forked from M-Labs/artiq
refactor device/parameter management, immediate parameter updates, start introducing results
This commit is contained in:
parent
c938e3f4f0
commit
891c0d12f2
|
@ -1,5 +1,5 @@
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language.context import *
|
from artiq.language.db import *
|
||||||
from artiq.language.units import check_unit
|
from artiq.language.units import check_unit
|
||||||
from artiq.language.units import ps, ns, us, ms, s
|
from artiq.language.units import ps, ns, us, ms, s
|
||||||
from artiq.language.units import Hz, kHz, MHz, GHz
|
from artiq.language.units import Hz, kHz, MHz, GHz
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from artiq.language.context import AutoContext
|
from artiq.language.db import AutoDB
|
||||||
from artiq.language.units import ms, ns
|
from artiq.language.units import ms, ns
|
||||||
from artiq.coredevice.runtime import LinkInterface
|
from artiq.coredevice.runtime import LinkInterface
|
||||||
|
|
||||||
|
@ -14,8 +14,9 @@ class _RuntimeEnvironment(LinkInterface):
|
||||||
return str(self.llvm_module)
|
return str(self.llvm_module)
|
||||||
|
|
||||||
|
|
||||||
class Comm(AutoContext):
|
class Comm(AutoDB):
|
||||||
implicit_core = False
|
class DBKeys:
|
||||||
|
implicit_core = False
|
||||||
|
|
||||||
def get_runtime_env(self):
|
def get_runtime_env(self):
|
||||||
return _RuntimeEnvironment(1*ns)
|
return _RuntimeEnvironment(1*ns)
|
||||||
|
|
|
@ -7,7 +7,7 @@ import logging
|
||||||
|
|
||||||
from artiq.language import core as core_language
|
from artiq.language import core as core_language
|
||||||
from artiq.language import units
|
from artiq.language import units
|
||||||
from artiq.language.context import *
|
from artiq.language.db import *
|
||||||
from artiq.coredevice.runtime import Environment
|
from artiq.coredevice.runtime import Environment
|
||||||
from artiq.coredevice import runtime_exceptions
|
from artiq.coredevice import runtime_exceptions
|
||||||
from artiq.coredevice.rpc_wrapper import RPCWrapper
|
from artiq.coredevice.rpc_wrapper import RPCWrapper
|
||||||
|
@ -60,10 +60,11 @@ def _read_exactly(f, n):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
class Comm(AutoContext):
|
class Comm(AutoDB):
|
||||||
serial_dev = Parameter("/dev/ttyUSB1")
|
class DBKeys:
|
||||||
baud_rate = Parameter(115200)
|
serial_dev = Parameter("/dev/ttyUSB1")
|
||||||
implicit_core = False
|
baud_rate = Parameter(115200)
|
||||||
|
implicit_core = False
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.port = serial.Serial(self.serial_dev, baudrate=115200)
|
self.port = serial.Serial(self.serial_dev, baudrate=115200)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language.context import *
|
from artiq.language.db import *
|
||||||
|
|
||||||
from artiq.transforms.inline import inline
|
from artiq.transforms.inline import inline
|
||||||
from artiq.transforms.lower_units import lower_units
|
from artiq.transforms.lower_units import lower_units
|
||||||
|
@ -44,10 +44,11 @@ def _no_debug_unparse(label, node):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Core(AutoContext):
|
class Core(AutoDB):
|
||||||
comm = Device("comm")
|
class DBKeys:
|
||||||
external_clock = Parameter(None)
|
comm = Device()
|
||||||
implicit_core = False
|
external_clock = Parameter(None)
|
||||||
|
implicit_core = False
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.runtime_env = self.comm.get_runtime_env()
|
self.runtime_env = self.comm.get_runtime_env()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language.context import *
|
from artiq.language.db import *
|
||||||
from artiq.language.units import *
|
from artiq.language.units import *
|
||||||
from artiq.coredevice import rtio
|
from artiq.coredevice import rtio
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ PHASE_MODE_ABSOLUTE = 1
|
||||||
PHASE_MODE_TRACKING = 2
|
PHASE_MODE_TRACKING = 2
|
||||||
|
|
||||||
|
|
||||||
class DDS(AutoContext):
|
class DDS(AutoDB):
|
||||||
"""Core device Direct Digital Synthesis (DDS) driver.
|
"""Core device Direct Digital Synthesis (DDS) driver.
|
||||||
|
|
||||||
Controls DDS devices managed directly by the core device's runtime. It also
|
Controls DDS devices managed directly by the core device's runtime. It also
|
||||||
|
@ -24,15 +24,16 @@ class DDS(AutoContext):
|
||||||
the DDS device.
|
the DDS device.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
dds_sysclk = Parameter(1*GHz)
|
class DBKeys:
|
||||||
reg_channel = Parameter()
|
dds_sysclk = Parameter(1*GHz)
|
||||||
rtio_switch = Parameter()
|
reg_channel = Argument()
|
||||||
|
rtio_switch = Argument()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.previous_on = False
|
self.previous_on = False
|
||||||
self.previous_frequency = 0*MHz
|
self.previous_frequency = 0*MHz
|
||||||
self.set_phase_mode(PHASE_MODE_CONTINUOUS)
|
self.set_phase_mode(PHASE_MODE_CONTINUOUS)
|
||||||
self.sw = rtio.RTIOOut(self, channel=self.rtio_switch)
|
self.sw = rtio.RTIOOut(core=self.core, channel=self.rtio_switch)
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def frequency_to_ftw(self, frequency):
|
def frequency_to_ftw(self, frequency):
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language.context import *
|
from artiq.language.db import *
|
||||||
|
|
||||||
|
|
||||||
class GPIOOut(AutoContext):
|
class GPIOOut(AutoDB):
|
||||||
channel = Parameter()
|
class DBKeys:
|
||||||
|
channel = Argument()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def on(self):
|
def on(self):
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language.context import *
|
from artiq.language.db import *
|
||||||
|
|
||||||
|
|
||||||
class LLRTIOOut(AutoContext):
|
class LLRTIOOut(AutoDB):
|
||||||
"""Low-level RTIO output driver.
|
"""Low-level RTIO output driver.
|
||||||
|
|
||||||
Allows setting RTIO outputs at arbitrary times, without time unit
|
Allows setting RTIO outputs at arbitrary times, without time unit
|
||||||
|
@ -12,7 +12,8 @@ class LLRTIOOut(AutoContext):
|
||||||
``RTIOOut`` instead.
|
``RTIOOut`` instead.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
channel = Parameter()
|
class DBKeys:
|
||||||
|
channel = Argument()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self._set_oe()
|
self._set_oe()
|
||||||
|
@ -50,8 +51,9 @@ class LLRTIOOut(AutoContext):
|
||||||
self.set_value(t, 0)
|
self.set_value(t, 0)
|
||||||
|
|
||||||
|
|
||||||
class _RTIOBase(AutoContext):
|
class _RTIOBase(AutoDB):
|
||||||
channel = Parameter()
|
class DBKeys:
|
||||||
|
channel = Argument()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.previous_timestamp = int64(0) # in RTIO cycles
|
self.previous_timestamp = int64(0) # in RTIO cycles
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language.context import *
|
from artiq.language.db import *
|
||||||
from artiq.language.units import *
|
from artiq.language.units import *
|
||||||
from artiq.coredevice import rtio
|
from artiq.coredevice import rtio
|
||||||
|
|
||||||
|
@ -111,16 +111,17 @@ class _Frame:
|
||||||
del self.fn
|
del self.fn
|
||||||
|
|
||||||
|
|
||||||
class CompoundPDQ2(AutoContext):
|
class CompoundPDQ2(AutoDB):
|
||||||
ids = Parameter()
|
class DBKeys:
|
||||||
rtio_trigger = Parameter()
|
ids = Argument()
|
||||||
rtio_frame = Parameter()
|
rtio_trigger = Argument()
|
||||||
|
rtio_frame = Argument()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.trigger = rtio.LLRTIOOut(self, channel=self.rtio_trigger)
|
self.trigger = rtio.LLRTIOOut(core=self.core, channel=self.rtio_trigger)
|
||||||
self.frame0 = rtio.LLRTIOOut(self, channel=self.rtio_frame[0])
|
self.frame0 = rtio.LLRTIOOut(core=self.core, channel=self.rtio_frame[0])
|
||||||
self.frame1 = rtio.LLRTIOOut(self, channel=self.rtio_frame[1])
|
self.frame1 = rtio.LLRTIOOut(core=self.core, channel=self.rtio_frame[1])
|
||||||
self.frame2 = rtio.LLRTIOOut(self, channel=self.rtio_frame[2])
|
self.frame2 = rtio.LLRTIOOut(core=self.core, channel=self.rtio_frame[2])
|
||||||
|
|
||||||
self.frames = []
|
self.frames = []
|
||||||
self.current_frame = -1
|
self.current_frame = -1
|
||||||
|
|
|
@ -1,179 +0,0 @@
|
||||||
"""
|
|
||||||
Device and parameter attributes.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
class _AttributeKind:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Device(_AttributeKind):
|
|
||||||
"""Represents a device for ``AutoContext`` to process.
|
|
||||||
|
|
||||||
:param type_hint: An optional string giving a hint about the type of the
|
|
||||||
device.
|
|
||||||
|
|
||||||
"""
|
|
||||||
def __init__(self, type_hint=None):
|
|
||||||
self.type_hint = type_hint
|
|
||||||
|
|
||||||
|
|
||||||
class NoDefault:
|
|
||||||
"""Represents the absence of a default value for ``Parameter``.
|
|
||||||
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Parameter(_AttributeKind):
|
|
||||||
"""Represents a parameter (from the database) for ``AutoContext``
|
|
||||||
to process.
|
|
||||||
|
|
||||||
:param default: Default value of the parameter to be used if not found
|
|
||||||
in the database.
|
|
||||||
:param write_db: Writes any modification of the parameter back to the
|
|
||||||
database.
|
|
||||||
|
|
||||||
"""
|
|
||||||
def __init__(self, default=NoDefault, write_db=False):
|
|
||||||
self.default = default
|
|
||||||
self.write_db = write_db
|
|
||||||
|
|
||||||
|
|
||||||
class Argument(_AttributeKind):
|
|
||||||
"""Represents an argument (specifiable at instance creation) for
|
|
||||||
``AutoContext`` to process.
|
|
||||||
|
|
||||||
:param default: Default value of the argument to be used if not specified
|
|
||||||
at instance creation.
|
|
||||||
|
|
||||||
"""
|
|
||||||
def __init__(self, default=NoDefault):
|
|
||||||
self.default = default
|
|
||||||
|
|
||||||
|
|
||||||
class AutoContext:
|
|
||||||
"""Base class to automate device and parameter discovery.
|
|
||||||
|
|
||||||
Drivers and experiments should in most cases overload this class to
|
|
||||||
obtain the parameters and devices (including the core device) that they
|
|
||||||
need.
|
|
||||||
|
|
||||||
This class sets all its ``__init__`` keyword arguments as attributes. It
|
|
||||||
then iterates over each element in the attribute dictionary of the class,
|
|
||||||
and when they are abtract attributes (e.g. ``Device``, ``Parameter``),
|
|
||||||
requests them from the ``mvs`` (Missing Value Supplier) object.
|
|
||||||
|
|
||||||
A ``AutoContext`` instance can be used as MVS. If the requested parameter
|
|
||||||
is within its attributes, the value of that attribute is returned.
|
|
||||||
Otherwise, the request is forwarded to the parent MVS.
|
|
||||||
|
|
||||||
All keyword arguments are set as object attributes. This enables setting
|
|
||||||
parameters of a lower-level ``AutoContext`` object using keyword arguments
|
|
||||||
without having those explicitly listed in the upper-level ``AutoContext``
|
|
||||||
parameter list.
|
|
||||||
|
|
||||||
At the top-level, it is possible to have a MVS that issues requests to a
|
|
||||||
database and hardware management system.
|
|
||||||
|
|
||||||
:var implicit_core: Automatically adds a ``core`` device to the attributes.
|
|
||||||
Default: True.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
>>> class SubExperiment(AutoContext):
|
|
||||||
... foo = Parameter()
|
|
||||||
... bar = Parameter()
|
|
||||||
...
|
|
||||||
... def run(self):
|
|
||||||
... do_something(self.foo, self.bar)
|
|
||||||
...
|
|
||||||
>>> class MainExperiment(AutoContext):
|
|
||||||
... bar1 = Parameter()
|
|
||||||
... bar2 = Parameter()
|
|
||||||
... offset = Parameter()
|
|
||||||
...
|
|
||||||
... def build(self):
|
|
||||||
... self.exp1 = SubExperiment(self, bar=self.bar1)
|
|
||||||
... self.exp2 = SubExperiment(self, bar=self.bar2)
|
|
||||||
... self.exp3 = SubExperiment(self, bar=self.bar2 + self.offset)
|
|
||||||
...
|
|
||||||
... def run(self):
|
|
||||||
... self.exp1.run()
|
|
||||||
... self.exp2.run()
|
|
||||||
... self.exp3.run()
|
|
||||||
...
|
|
||||||
>>> # does not require a database.
|
|
||||||
>>> a = MainExperiment(foo=1, bar1=2, bar2=3, offset=0)
|
|
||||||
>>> # "foo" and "offset" are automatically retrieved from the database.
|
|
||||||
>>> b = MainExperiment(db_mvs, bar1=2, bar2=3)
|
|
||||||
|
|
||||||
"""
|
|
||||||
implicit_core = True
|
|
||||||
|
|
||||||
def __init__(self, mvs=None, **kwargs):
|
|
||||||
if self.implicit_core:
|
|
||||||
if hasattr(self, "core"):
|
|
||||||
raise ValueError(
|
|
||||||
"Set implicit_core to False when"
|
|
||||||
" core is explicitly specified")
|
|
||||||
self.core = Device("core")
|
|
||||||
|
|
||||||
self.mvs = mvs
|
|
||||||
for k, v in kwargs.items():
|
|
||||||
if hasattr(self, k):
|
|
||||||
p = getattr(self, k)
|
|
||||||
if isinstance(p, Parameter) and p.write_db:
|
|
||||||
self.mvs.register_parameter_wb(self, k)
|
|
||||||
if (not hasattr(self, k)
|
|
||||||
or not isinstance(getattr(self, k), _AttributeKind)):
|
|
||||||
raise ValueError(
|
|
||||||
"Got unexpected keyword argument: '{}'".format(k))
|
|
||||||
setattr(self, k, v)
|
|
||||||
|
|
||||||
for k in dir(self):
|
|
||||||
v = getattr(self, k)
|
|
||||||
if isinstance(v, _AttributeKind):
|
|
||||||
if isinstance(v, Argument):
|
|
||||||
# never goes through MVS
|
|
||||||
if v.default is NoDefault:
|
|
||||||
raise AttributeError(
|
|
||||||
"No value specified for argument '{}'".format(k))
|
|
||||||
value = v.default
|
|
||||||
else:
|
|
||||||
if self.mvs is None:
|
|
||||||
if (isinstance(v, Parameter)
|
|
||||||
and v.default is not NoDefault):
|
|
||||||
value = v.default
|
|
||||||
else:
|
|
||||||
raise AttributeError("Attribute '{}' not specified"
|
|
||||||
" and no MVS present".format(k))
|
|
||||||
else:
|
|
||||||
value = self.mvs.get_missing_value(k, v, self)
|
|
||||||
if isinstance(v, Parameter) and v.write_db:
|
|
||||||
self.mvs.register_parameter_wb(self, k)
|
|
||||||
setattr(self, k, value)
|
|
||||||
|
|
||||||
self.build()
|
|
||||||
|
|
||||||
def get_missing_value(self, name, kind, requester):
|
|
||||||
"""Attempts to retrieve ``name`` from the object's attributes.
|
|
||||||
If not present, forwards the request to the parent MVS.
|
|
||||||
|
|
||||||
The presence of this method makes ``AutoContext`` act as a MVS.
|
|
||||||
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return getattr(self, name)
|
|
||||||
except AttributeError:
|
|
||||||
return self.mvs.get_missing_value(name, kind, requester)
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
"""This is called by ``__init__`` after the parameter initialization
|
|
||||||
is done.
|
|
||||||
|
|
||||||
The user may overload this method to complete the object's
|
|
||||||
initialization with all parameters available.
|
|
||||||
|
|
||||||
"""
|
|
||||||
pass
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
"""
|
||||||
|
Connection to device, parameter and result database.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
class _AttributeKind:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Device(_AttributeKind):
|
||||||
|
"""Represents a device for ``AutoDB`` to process.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NoDefault:
|
||||||
|
"""Represents the absence of a default value for ``Parameter``
|
||||||
|
and ``Argument``.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Parameter(_AttributeKind):
|
||||||
|
"""Represents a parameter (from the database) for ``AutoDB``
|
||||||
|
to process.
|
||||||
|
|
||||||
|
:param default: Default value of the parameter to be used if not found
|
||||||
|
in the database.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, default=NoDefault):
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
|
||||||
|
class Argument(_AttributeKind):
|
||||||
|
"""Represents an argument (specifiable at instance creation) for
|
||||||
|
``AutoDB`` to process.
|
||||||
|
|
||||||
|
:param default: Default value of the argument to be used if not specified
|
||||||
|
at instance creation.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, default=NoDefault):
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
|
||||||
|
class Result(_AttributeKind):
|
||||||
|
"""Represents a result for ``AutoDB`` to process.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AutoDB:
|
||||||
|
"""Base class to automate device, parameter and result database access.
|
||||||
|
|
||||||
|
Drivers and experiments should in most cases overload this class to
|
||||||
|
obtain the parameters and devices (including the core device) that they
|
||||||
|
need, report results, and modify parameters.
|
||||||
|
|
||||||
|
:param dbh: database hub to use. If ``None``, all devices and parameters
|
||||||
|
must be supplied as keyword arguments, and reporting results and
|
||||||
|
modifying parameters is not supported.
|
||||||
|
|
||||||
|
"""
|
||||||
|
class DBKeys:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(self, dbh=None, **kwargs):
|
||||||
|
self.dbh = dbh
|
||||||
|
|
||||||
|
dbkeys = self.DBKeys()
|
||||||
|
if getattr(dbkeys, "implicit_core", True):
|
||||||
|
if hasattr(dbkeys, "core"):
|
||||||
|
raise ValueError(
|
||||||
|
"Set implicit_core to False when"
|
||||||
|
" core is explicitly specified")
|
||||||
|
dbkeys.core = Device()
|
||||||
|
|
||||||
|
for k, v in kwargs.items():
|
||||||
|
object.__setattr__(self, k, v)
|
||||||
|
|
||||||
|
for k in dir(dbkeys):
|
||||||
|
if k not in self.__dict__:
|
||||||
|
ak = getattr(dbkeys, k)
|
||||||
|
if isinstance(ak, Argument):
|
||||||
|
if ak.default is NoDefault:
|
||||||
|
raise AttributeError(
|
||||||
|
"No value specified for argument '{}'".format(k))
|
||||||
|
object.__setattr__(self, k, ak.default)
|
||||||
|
elif isinstance(ak, Device):
|
||||||
|
try:
|
||||||
|
dev = self.dbh.get_device(k)
|
||||||
|
except KeyError:
|
||||||
|
raise KeyError("Device '{}' not found".format(k))
|
||||||
|
object.__setattr__(self, k, dev)
|
||||||
|
|
||||||
|
self.build()
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
ak = getattr(self.DBKeys, name)
|
||||||
|
if isinstance(ak, Parameter):
|
||||||
|
try:
|
||||||
|
if self.dbh is None:
|
||||||
|
raise KeyError
|
||||||
|
return self.dbh.get_parameter(name)
|
||||||
|
except KeyError:
|
||||||
|
if ak.default is not NoDefault:
|
||||||
|
return ak.default
|
||||||
|
else:
|
||||||
|
raise AttributeError("Parameter '{}' not in database"
|
||||||
|
" and without default value"
|
||||||
|
.format(name))
|
||||||
|
elif isinstance(ak, Result):
|
||||||
|
try:
|
||||||
|
return self.dbh.get_result(name)
|
||||||
|
except KeyError:
|
||||||
|
raise AttributeError("Result '{}' not found".format(name))
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
try:
|
||||||
|
ak = getattr(self.DBKeys, name)
|
||||||
|
except AttributeError:
|
||||||
|
object.__setattr__(self, name, value)
|
||||||
|
else:
|
||||||
|
if isinstance(ak, Parameter):
|
||||||
|
self.dbh.set_parameter(name, value)
|
||||||
|
elif isinstance(ak, Result):
|
||||||
|
self.dbh.set_result(name, value)
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
"""This is called by ``__init__`` after the parameter initialization
|
||||||
|
is done.
|
||||||
|
|
||||||
|
The user may overload this method to complete the object's
|
||||||
|
initialization with all parameters available.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
|
@ -0,0 +1,106 @@
|
||||||
|
from collections import OrderedDict, defaultdict
|
||||||
|
import importlib
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
from artiq.language.db import *
|
||||||
|
from artiq.management import pyon
|
||||||
|
from artiq.management.sync_struct import Notifier
|
||||||
|
|
||||||
|
|
||||||
|
class FlatFileDB:
|
||||||
|
def __init__(self, filename):
|
||||||
|
self.filename = filename
|
||||||
|
self.data = Notifier(pyon.load_file(self.filename))
|
||||||
|
self.hooks = []
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
pyon.store_file(self.filename, self.data.backing_struct)
|
||||||
|
|
||||||
|
def request(self, name):
|
||||||
|
return self.data.backing_struct[name]
|
||||||
|
|
||||||
|
def set(self, name, value):
|
||||||
|
self.data[name] = value
|
||||||
|
self.save()
|
||||||
|
timestamp = time()
|
||||||
|
for hook in self.hooks:
|
||||||
|
hook.set(timestamp, name, value)
|
||||||
|
|
||||||
|
def delete(self, name):
|
||||||
|
del self.data[name]
|
||||||
|
self.save()
|
||||||
|
timestamp = time()
|
||||||
|
for hook in self.hooks:
|
||||||
|
hook.delete(timestamp, name)
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleHistory:
|
||||||
|
def __init__(self, depth):
|
||||||
|
self.depth = depth
|
||||||
|
self.history = Notifier([])
|
||||||
|
|
||||||
|
def set(self, timestamp, name, value):
|
||||||
|
if len(self.history.backing_struct) >= self.depth:
|
||||||
|
del self.history[0]
|
||||||
|
self.history.append((timestamp, name, value))
|
||||||
|
|
||||||
|
def delete(self, timestamp, name):
|
||||||
|
if len(self.history.backing_struct) >= self.depth:
|
||||||
|
del self.history[0]
|
||||||
|
self.history.append((timestamp, name))
|
||||||
|
|
||||||
|
|
||||||
|
class ResultDB:
|
||||||
|
def __init__(self):
|
||||||
|
self.data = defaultdict(list)
|
||||||
|
|
||||||
|
def request(self, name):
|
||||||
|
return self.data[name]
|
||||||
|
|
||||||
|
def set(self, name, value):
|
||||||
|
self.data[name] = value
|
||||||
|
|
||||||
|
|
||||||
|
def _create_device(desc, dbh):
|
||||||
|
module = importlib.import_module(desc["module"])
|
||||||
|
device_class = getattr(module, desc["class"])
|
||||||
|
return device_class(dbh, **desc["arguments"])
|
||||||
|
|
||||||
|
|
||||||
|
class DBHub:
|
||||||
|
"""Connects device, parameter and result databases to experiment.
|
||||||
|
Handle device driver creation and destruction.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, ddb, pdb, rdb):
|
||||||
|
self.ddb = ddb
|
||||||
|
self.active_devices = OrderedDict()
|
||||||
|
|
||||||
|
self.get_parameter = pdb.request
|
||||||
|
self.set_parameter = pdb.set
|
||||||
|
self.get_result = rdb.request
|
||||||
|
self.set_result = rdb.set
|
||||||
|
|
||||||
|
def get_device(self, name):
|
||||||
|
if name in self.active_devices:
|
||||||
|
return self.active_devices[name]
|
||||||
|
else:
|
||||||
|
desc = self.ddb.request(name)
|
||||||
|
while isinstance(desc, str):
|
||||||
|
# alias
|
||||||
|
desc = self.ddb.request(desc)
|
||||||
|
dev = _create_device(desc, self)
|
||||||
|
self.active_devices[name] = dev
|
||||||
|
return dev
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Closes all active devices, in the opposite order as they were
|
||||||
|
requested.
|
||||||
|
|
||||||
|
Do not use the same ``DBHub`` again after calling
|
||||||
|
this function.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for dev in reversed(list(self.active_devices.values())):
|
||||||
|
if hasattr(dev, "close"):
|
||||||
|
dev.close()
|
|
@ -1,133 +0,0 @@
|
||||||
from collections import OrderedDict
|
|
||||||
import importlib
|
|
||||||
from time import time
|
|
||||||
|
|
||||||
from artiq.language.context import *
|
|
||||||
from artiq.management import pyon
|
|
||||||
from artiq.management.sync_struct import Notifier
|
|
||||||
|
|
||||||
|
|
||||||
def create_device(desc, mvs):
|
|
||||||
module = importlib.import_module(desc["module"])
|
|
||||||
device_class = getattr(module, desc["class"])
|
|
||||||
return device_class(mvs, **desc["parameters"])
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceParamSupplier:
|
|
||||||
"""Supplies devices and parameters to AutoContext objects.
|
|
||||||
|
|
||||||
"""
|
|
||||||
def __init__(self, req_device, req_parameter):
|
|
||||||
self.req_device = req_device
|
|
||||||
self.req_parameter = req_parameter
|
|
||||||
self.active_devices = OrderedDict()
|
|
||||||
# list of (requester, name)
|
|
||||||
self.parameter_wb = []
|
|
||||||
|
|
||||||
def get_missing_value(self, name, kind, requester):
|
|
||||||
if isinstance(kind, Device):
|
|
||||||
if name in self.active_devices:
|
|
||||||
return self.active_devices[name]
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
desc = self.req_device(name)
|
|
||||||
except KeyError:
|
|
||||||
raise KeyError(
|
|
||||||
"Unknown device '{}' of type '{}' requested by {}"
|
|
||||||
.format(name, kind.type_hint, requester))
|
|
||||||
try:
|
|
||||||
while isinstance(desc, str):
|
|
||||||
# alias
|
|
||||||
desc = self.req_device(desc)
|
|
||||||
except KeyError:
|
|
||||||
raise KeyError(
|
|
||||||
"Unknown alias '{}' for device '{}' of type '{}'"
|
|
||||||
" requested by {}"
|
|
||||||
.format(desc, name, kind.type_hint, requester))
|
|
||||||
dev = create_device(desc, self)
|
|
||||||
self.active_devices[name] = dev
|
|
||||||
return dev
|
|
||||||
elif isinstance(kind, Parameter):
|
|
||||||
try:
|
|
||||||
return self.req_parameter(name)
|
|
||||||
except KeyError:
|
|
||||||
if kind.default is not NoDefault:
|
|
||||||
return kind.default
|
|
||||||
else:
|
|
||||||
raise KeyError("Unknown parameter: " + name)
|
|
||||||
else:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def register_parameter_wb(self, requester, name):
|
|
||||||
self.parameter_wb.append((requester, name))
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
"""Closes all active devices, in the opposite order as they were
|
|
||||||
requested.
|
|
||||||
|
|
||||||
Do not use the same ``DeviceParamSupplier`` again after calling
|
|
||||||
this function.
|
|
||||||
|
|
||||||
"""
|
|
||||||
for dev in reversed(list(self.active_devices.values())):
|
|
||||||
if hasattr(dev, "close"):
|
|
||||||
dev.close()
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceParamDB:
|
|
||||||
def __init__(self, ddb_file, pdb_file):
|
|
||||||
self.ddb_file = ddb_file
|
|
||||||
self.pdb_file = pdb_file
|
|
||||||
self.ddb = Notifier(pyon.load_file(self.ddb_file))
|
|
||||||
self.pdb = Notifier(pyon.load_file(self.pdb_file))
|
|
||||||
self.parameter_hooks = []
|
|
||||||
|
|
||||||
def save_ddb(self):
|
|
||||||
pyon.store_file(self.ddb_file, self.ddb.backing_struct)
|
|
||||||
|
|
||||||
def save_pdb(self):
|
|
||||||
pyon.store_file(self.pdb_file, self.pdb.backing_struct)
|
|
||||||
|
|
||||||
def req_device(self, name):
|
|
||||||
return self.ddb.backing_struct[name]
|
|
||||||
|
|
||||||
def set_device(self, name, description):
|
|
||||||
self.ddb[name] = description
|
|
||||||
self.save_ddb()
|
|
||||||
|
|
||||||
def del_device(self, name):
|
|
||||||
del self.ddb[name]
|
|
||||||
self.save_ddb()
|
|
||||||
|
|
||||||
def req_parameter(self, name):
|
|
||||||
return self.pdb.backing_struct[name]
|
|
||||||
|
|
||||||
def set_parameter(self, name, value):
|
|
||||||
self.pdb[name] = value
|
|
||||||
self.save_pdb()
|
|
||||||
timestamp = time()
|
|
||||||
for hook in self.parameter_hooks:
|
|
||||||
hook.set_parameter(timestamp, name, value)
|
|
||||||
|
|
||||||
def del_parameter(self, name):
|
|
||||||
del self.pdb[name]
|
|
||||||
self.save_pdb()
|
|
||||||
timestamp = time()
|
|
||||||
for hook in self.parameter_hooks:
|
|
||||||
hook.del_parameter(timestamp, name)
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleParameterHistory:
|
|
||||||
def __init__(self, depth):
|
|
||||||
self.depth = depth
|
|
||||||
self.history = Notifier([])
|
|
||||||
|
|
||||||
def set_parameter(self, timestamp, name, value):
|
|
||||||
if len(self.history.backing_struct) >= self.depth:
|
|
||||||
del self.history[0]
|
|
||||||
self.history.append((timestamp, name, value))
|
|
||||||
|
|
||||||
def del_parameter(self, timestamp, name):
|
|
||||||
if len(self.history.backing_struct) >= self.depth:
|
|
||||||
del self.history[0]
|
|
||||||
self.history.append((timestamp, name))
|
|
|
@ -4,24 +4,24 @@ import traceback
|
||||||
|
|
||||||
from artiq.management import pyon
|
from artiq.management import pyon
|
||||||
from artiq.management.file_import import file_import
|
from artiq.management.file_import import file_import
|
||||||
from artiq.language.context import AutoContext
|
from artiq.language.db import AutoDB
|
||||||
from artiq.management.dpdb import DeviceParamSupplier
|
from artiq.management.db import DBHub, ResultDB
|
||||||
|
|
||||||
|
|
||||||
def run(dps, file, unit, arguments):
|
def run(dbh, file, unit, arguments):
|
||||||
module = file_import(file)
|
module = file_import(file)
|
||||||
if unit is None:
|
if unit is None:
|
||||||
units = [v for k, v in module.__dict__.items()
|
units = [v for k, v in module.__dict__.items()
|
||||||
if k[0] != "_"
|
if k[0] != "_"
|
||||||
and isclass(v)
|
and isclass(v)
|
||||||
and issubclass(v, AutoContext)
|
and issubclass(v, AutoDB)
|
||||||
and v is not AutoContext]
|
and v is not AutoDB]
|
||||||
if len(units) != 1:
|
if len(units) != 1:
|
||||||
raise ValueError("Found {} units in module".format(len(units)))
|
raise ValueError("Found {} units in module".format(len(units)))
|
||||||
unit = units[0]
|
unit = units[0]
|
||||||
else:
|
else:
|
||||||
unit = getattr(module, unit)
|
unit = getattr(module, unit)
|
||||||
unit_inst = unit(dps, **arguments)
|
unit_inst = unit(dbh, **arguments)
|
||||||
unit_inst.run()
|
unit_inst.run()
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,9 +56,13 @@ def make_parent_action(action, argnames, exception=ParentActionError):
|
||||||
return parent_action
|
return parent_action
|
||||||
|
|
||||||
|
|
||||||
req_device = make_parent_action("req_device", "name", KeyError)
|
class ParentDDB:
|
||||||
req_parameter = make_parent_action("req_parameter", "name", KeyError)
|
request = make_parent_action("req_device", "name", KeyError)
|
||||||
set_parameter = make_parent_action("set_parameter", "name value")
|
|
||||||
|
|
||||||
|
class ParentPDB:
|
||||||
|
request = make_parent_action("req_parameter", "name", KeyError)
|
||||||
|
set = make_parent_action("set_parameter", "name value")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -68,12 +72,11 @@ def main():
|
||||||
obj = get_object()
|
obj = get_object()
|
||||||
put_object("ack")
|
put_object("ack")
|
||||||
|
|
||||||
dps = DeviceParamSupplier(req_device, req_parameter)
|
rdb = ResultDB()
|
||||||
|
dbh = DBHub(ParentDDB, ParentPDB, rdb)
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
run(dps, **obj)
|
run(dbh, **obj)
|
||||||
for requester, name in dps.parameter_wb:
|
|
||||||
set_parameter(name, getattr(requester, name))
|
|
||||||
except Exception:
|
except Exception:
|
||||||
put_object({"action": "report_completed",
|
put_object({"action": "report_completed",
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
|
@ -82,7 +85,7 @@ def main():
|
||||||
put_object({"action": "report_completed",
|
put_object({"action": "report_completed",
|
||||||
"status": "ok"})
|
"status": "ok"})
|
||||||
finally:
|
finally:
|
||||||
dps.close()
|
dbh.close()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
from random import Random
|
from random import Random
|
||||||
|
|
||||||
from artiq.language.core import delay, kernel
|
from artiq.language.core import delay, kernel
|
||||||
from artiq.language.context import AutoContext, Parameter
|
from artiq.language.db import AutoDB, Argument
|
||||||
from artiq.language import units
|
from artiq.language import units
|
||||||
from artiq.sim import time
|
from artiq.sim import time
|
||||||
|
|
||||||
|
|
||||||
class Core(AutoContext):
|
class Core(AutoDB):
|
||||||
implicit_core = False
|
class DBKeys:
|
||||||
|
implicit_core = False
|
||||||
|
|
||||||
_level = 0
|
_level = 0
|
||||||
|
|
||||||
|
@ -20,8 +21,9 @@ class Core(AutoContext):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
class Input(AutoContext):
|
class Input(AutoDB):
|
||||||
name = Parameter()
|
class DBKeys:
|
||||||
|
name = Argument()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.prng = Random()
|
self.prng = Random()
|
||||||
|
@ -40,8 +42,9 @@ class Input(AutoContext):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class WaveOutput(AutoContext):
|
class WaveOutput(AutoDB):
|
||||||
name = Parameter()
|
class DBKeys:
|
||||||
|
name = Argument()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def pulse(self, frequency, duration):
|
def pulse(self, frequency, duration):
|
||||||
|
@ -49,8 +52,9 @@ class WaveOutput(AutoContext):
|
||||||
delay(duration)
|
delay(duration)
|
||||||
|
|
||||||
|
|
||||||
class VoltageOutput(AutoContext):
|
class VoltageOutput(AutoDB):
|
||||||
name = Parameter()
|
class DBKeys:
|
||||||
|
name = Argument()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set(self, value):
|
def set(self, value):
|
||||||
|
|
|
@ -28,9 +28,10 @@ def _run_on_host(k_class, **parameters):
|
||||||
k_inst.run()
|
k_inst.run()
|
||||||
|
|
||||||
|
|
||||||
class _Primes(AutoContext):
|
class _Primes(AutoDB):
|
||||||
output_list = Parameter()
|
class DBKeys:
|
||||||
maximum = Parameter()
|
output_list = Argument()
|
||||||
|
maximum = Argument()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -46,7 +47,7 @@ class _Primes(AutoContext):
|
||||||
self.output_list.append(x)
|
self.output_list.append(x)
|
||||||
|
|
||||||
|
|
||||||
class _Misc(AutoContext):
|
class _Misc(AutoDB):
|
||||||
def build(self):
|
def build(self):
|
||||||
self.input = 84
|
self.input = 84
|
||||||
self.inhomogeneous_units = []
|
self.inhomogeneous_units = []
|
||||||
|
@ -82,9 +83,10 @@ class _Misc(AutoContext):
|
||||||
delay(10*Hz)
|
delay(10*Hz)
|
||||||
|
|
||||||
|
|
||||||
class _PulseLogger(AutoContext):
|
class _PulseLogger(AutoDB):
|
||||||
output_list = Parameter()
|
class DBKeys:
|
||||||
name = Parameter()
|
output_list = Argument()
|
||||||
|
name = Argument()
|
||||||
|
|
||||||
def _append(self, t, l, f):
|
def _append(self, t, l, f):
|
||||||
if not hasattr(self, "first_timestamp"):
|
if not hasattr(self, "first_timestamp"):
|
||||||
|
@ -104,12 +106,15 @@ class _PulseLogger(AutoContext):
|
||||||
self.off(int(now().amount*1000000000))
|
self.off(int(now().amount*1000000000))
|
||||||
|
|
||||||
|
|
||||||
class _Pulses(AutoContext):
|
class _Pulses(AutoDB):
|
||||||
output_list = Parameter()
|
class DBKeys:
|
||||||
|
output_list = Argument()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
for name in "a", "b", "c", "d":
|
for name in "a", "b", "c", "d":
|
||||||
pl = _PulseLogger(self, name=name)
|
pl = _PulseLogger(core=self.core,
|
||||||
|
output_list=self.output_list,
|
||||||
|
name=name)
|
||||||
setattr(self, name, pl)
|
setattr(self, name, pl)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
|
@ -128,8 +133,9 @@ class _MyException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class _Exceptions(AutoContext):
|
class _Exceptions(AutoDB):
|
||||||
trace = Parameter()
|
class DBKeys:
|
||||||
|
trace = Argument()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -170,7 +176,7 @@ class _Exceptions(AutoContext):
|
||||||
self.trace.append(104)
|
self.trace.append(104)
|
||||||
|
|
||||||
|
|
||||||
class _RPCExceptions(AutoContext):
|
class _RPCExceptions(AutoDB):
|
||||||
def build(self):
|
def build(self):
|
||||||
self.success = False
|
self.success = False
|
||||||
|
|
||||||
|
@ -250,10 +256,11 @@ class ExecutionCase(unittest.TestCase):
|
||||||
comm.close()
|
comm.close()
|
||||||
|
|
||||||
|
|
||||||
class _RTIOLoopback(AutoContext):
|
class _RTIOLoopback(AutoDB):
|
||||||
i = Device("ttl_in")
|
class DBKeys:
|
||||||
o = Device("ttl_out")
|
i = Device()
|
||||||
npulses = Parameter()
|
o = Device()
|
||||||
|
npulses = Argument()
|
||||||
|
|
||||||
def report(self, n):
|
def report(self, n):
|
||||||
self.result = n
|
self.result = n
|
||||||
|
@ -269,8 +276,9 @@ class _RTIOLoopback(AutoContext):
|
||||||
self.report(self.i.count())
|
self.report(self.i.count())
|
||||||
|
|
||||||
|
|
||||||
class _RTIOUnderflow(AutoContext):
|
class _RTIOUnderflow(AutoDB):
|
||||||
o = Device("ttl_out")
|
class DBKeys:
|
||||||
|
o = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -279,8 +287,9 @@ class _RTIOUnderflow(AutoContext):
|
||||||
self.o.pulse(25*ns)
|
self.o.pulse(25*ns)
|
||||||
|
|
||||||
|
|
||||||
class _RTIOSequenceError(AutoContext):
|
class _RTIOSequenceError(AutoDB):
|
||||||
o = Device("ttl_out")
|
class DBKeys:
|
||||||
|
o = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -9,15 +9,16 @@ As a very first step, we will turn on a LED on the core device. Create a file ``
|
||||||
from artiq import *
|
from artiq import *
|
||||||
|
|
||||||
|
|
||||||
class LED(AutoContext):
|
class LED(AutoDB):
|
||||||
led = Device("gpio_out")
|
class DBKeys:
|
||||||
|
led = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
self.led.on()
|
self.led.on()
|
||||||
|
|
||||||
|
|
||||||
The central part of our code is our ``LED`` class, that derives from :class:`artiq.language.core.AutoContext`. ``AutoContext`` is part of the mechanism that attaches device drivers and retrieves parameters according to a database. Abstract attributes such as ``Device("gpio_out")`` list the devices (and parameters) that our class needs in order to operate, and the names of the attributes (e.g. ``led``) are used to search the database. ``AutoContext`` replaces them with the actual device drivers (and parameter values). Finally, the ``@kernel`` decorator tells the system that the ``run`` method must be executed on the core device (instead of the host).
|
The central part of our code is our ``LED`` class, that derives from :class:`artiq.language.db.AutoDB`. ``AutoDB`` is part of the mechanism that attaches device drivers and retrieves parameters according to a database. Our ``DBKeys`` class lists the devices (and parameters) that ``LED`` needs in order to operate, and the names of the attributes (e.g. ``led``) are used to search the database. ``AutoDB`` replaces them with the actual device drivers (and parameter values). Finally, the ``@kernel`` decorator tells the system that the ``run`` method must be executed on the core device (instead of the host).
|
||||||
|
|
||||||
Copy the files ``ddb.pyon`` and ``pdb.pyon`` (containing the device and parameter databases) from the ``examples`` folder of ARTIQ into the same directory as ``led.py`` (alternatively, you can use the ``-d`` and ``-p`` options of ``artiq_run.py``). You can open the database files using a text editor - their contents are in a human-readable format.
|
Copy the files ``ddb.pyon`` and ``pdb.pyon`` (containing the device and parameter databases) from the ``examples`` folder of ARTIQ into the same directory as ``led.py`` (alternatively, you can use the ``-d`` and ``-p`` options of ``artiq_run.py``). You can open the database files using a text editor - their contents are in a human-readable format.
|
||||||
|
|
||||||
|
@ -37,8 +38,9 @@ Modify the code as follows: ::
|
||||||
def input_led_state():
|
def input_led_state():
|
||||||
return int(input("Enter desired LED state: "))
|
return int(input("Enter desired LED state: "))
|
||||||
|
|
||||||
class LED(AutoContext):
|
class LED(AutoDB):
|
||||||
led = Device("gpio_out")
|
class DBKeys:
|
||||||
|
led = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -79,8 +81,9 @@ Create a new file ``rtio.py`` containing the following: ::
|
||||||
|
|
||||||
from artiq import *
|
from artiq import *
|
||||||
|
|
||||||
class Tutorial(AutoContext):
|
class Tutorial(AutoDB):
|
||||||
ttl0 = Device("ttl_out")
|
class DBKeys:
|
||||||
|
ttl0 = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -100,9 +103,10 @@ Try reducing the period of the generated waveform until the CPU cannot keep up w
|
||||||
def print_underflow():
|
def print_underflow():
|
||||||
print("RTIO underflow occured")
|
print("RTIO underflow occured")
|
||||||
|
|
||||||
class Tutorial(AutoContext):
|
class Tutorial(AutoDB):
|
||||||
led = Device("gpio_out")
|
class DBKeys:
|
||||||
ttl0 = Device("ttl_out")
|
led = Device()
|
||||||
|
ttl0 = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -81,7 +81,7 @@ Run it as before, while the controller is running. You should see the message ap
|
||||||
$ ./hello_controller.py
|
$ ./hello_controller.py
|
||||||
message: Hello World!
|
message: Hello World!
|
||||||
|
|
||||||
When using the driver in an experiment, for simple cases the ``Client`` instance can be returned by the :class:`artiq.language.core.AutoContext` mechanism and used normally as a device.
|
When using the driver in an experiment, for simple cases the ``Client`` instance can be returned by the :class:`artiq.language.db.AutoDB` mechanism and used normally as a device.
|
||||||
|
|
||||||
:warning: RPC servers operate on copies of objects provided by the client, and modifications to mutable types are not written back. For example, if the client passes a list as a parameter of an RPC method, and that method ``append()s`` an element to the list, the element is not appended to the client's list.
|
:warning: RPC servers operate on copies of objects provided by the client, and modifications to mutable types are not written back. For example, if the client passes a list as a parameter of an RPC method, and that method ``append()s`` an element to the list, the element is not appended to the client's list.
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ with parallel:
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{\fontseries{l}\selectfont Object orientation and code reuse}
|
\frametitle{\fontseries{l}\selectfont Object orientation and code reuse}
|
||||||
\begin{verbatimtab}
|
\begin{verbatimtab}
|
||||||
class Main(AutoContext):
|
class Main(AutoDB):
|
||||||
def build(self):
|
def build(self):
|
||||||
self.ion1 = Ion(...)
|
self.ion1 = Ion(...)
|
||||||
self.ion2 = Ion(...)
|
self.ion2 = Ion(...)
|
||||||
|
@ -130,9 +130,9 @@ class Main(AutoContext):
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{\fontseries{l}\selectfont Channels and parameters}
|
\frametitle{\fontseries{l}\selectfont Channels and parameters}
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item A kernel is a method of a class that derives from the \verb!AutoContext! class
|
\item A kernel is a method of a class
|
||||||
\item The entry point for an experiment is called \verb!run! --- may or may not be a kernel
|
\item The entry point for an experiment is called \verb!run! --- may or may not be a kernel
|
||||||
\item The \verb!AutoContext! class manages channels and parameters, and sets them as attributes
|
\item The \verb!AutoDB! class manages channels and parameters
|
||||||
\item If channels/parameters are passed as constructor arguments, those are used
|
\item If channels/parameters are passed as constructor arguments, those are used
|
||||||
\item Otherwise, they are looked up in the device and parameter databases
|
\item Otherwise, they are looked up in the device and parameter databases
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
from artiq import *
|
from artiq import *
|
||||||
|
|
||||||
|
|
||||||
class AluminumSpectroscopy(AutoContext):
|
class AluminumSpectroscopy(AutoDB):
|
||||||
mains_sync = Device("ttl_in")
|
class DBKeys:
|
||||||
laser_cooling = Device("dds")
|
mains_sync = Device()
|
||||||
spectroscopy = Device("dds")
|
laser_cooling = Device()
|
||||||
spectroscopy_b = Device("dac")
|
spectroscopy = Device()
|
||||||
state_detection = Device("dds")
|
spectroscopy_b = Device()
|
||||||
pmt = Device("ttl_in")
|
state_detection = Device()
|
||||||
spectroscopy_freq = Parameter(432*MHz)
|
pmt = Device()
|
||||||
photon_limit_low = Parameter(10)
|
spectroscopy_freq = Parameter(432*MHz)
|
||||||
photon_limit_high = Parameter(15)
|
photon_limit_low = Argument(10)
|
||||||
|
photon_limit_high = Argument(15)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -2,67 +2,67 @@
|
||||||
"comm": {
|
"comm": {
|
||||||
"module": "artiq.coredevice.comm_serial",
|
"module": "artiq.coredevice.comm_serial",
|
||||||
"class": "Comm",
|
"class": "Comm",
|
||||||
"parameters": {}
|
"arguments": {}
|
||||||
},
|
},
|
||||||
"core": {
|
"core": {
|
||||||
"module": "artiq.coredevice.core",
|
"module": "artiq.coredevice.core",
|
||||||
"class": "Core",
|
"class": "Core",
|
||||||
"parameters": {}
|
"arguments": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
"led": {
|
"led": {
|
||||||
"module": "artiq.coredevice.gpio",
|
"module": "artiq.coredevice.gpio",
|
||||||
"class": "GPIOOut",
|
"class": "GPIOOut",
|
||||||
"parameters": {"channel": 0}
|
"arguments": {"channel": 0}
|
||||||
},
|
},
|
||||||
|
|
||||||
"pmt0": {
|
"pmt0": {
|
||||||
"module": "artiq.coredevice.rtio",
|
"module": "artiq.coredevice.rtio",
|
||||||
"class": "RTIOIn",
|
"class": "RTIOIn",
|
||||||
"parameters": {"channel": 0}
|
"arguments": {"channel": 0}
|
||||||
},
|
},
|
||||||
"pmt1": {
|
"pmt1": {
|
||||||
"module": "artiq.coredevice.rtio",
|
"module": "artiq.coredevice.rtio",
|
||||||
"class": "RTIOIn",
|
"class": "RTIOIn",
|
||||||
"parameters": {"channel": 1}
|
"arguments": {"channel": 1}
|
||||||
},
|
},
|
||||||
|
|
||||||
"ttl0": {
|
"ttl0": {
|
||||||
"module": "artiq.coredevice.rtio",
|
"module": "artiq.coredevice.rtio",
|
||||||
"class": "RTIOOut",
|
"class": "RTIOOut",
|
||||||
"parameters": {"channel": 2}
|
"arguments": {"channel": 2}
|
||||||
},
|
},
|
||||||
"ttl1": {
|
"ttl1": {
|
||||||
"module": "artiq.coredevice.rtio",
|
"module": "artiq.coredevice.rtio",
|
||||||
"class": "RTIOOut",
|
"class": "RTIOOut",
|
||||||
"parameters": {"channel": 3}
|
"arguments": {"channel": 3}
|
||||||
},
|
},
|
||||||
"ttl2": {
|
"ttl2": {
|
||||||
"module": "artiq.coredevice.rtio",
|
"module": "artiq.coredevice.rtio",
|
||||||
"class": "RTIOOut",
|
"class": "RTIOOut",
|
||||||
"parameters": {"channel": 4}
|
"arguments": {"channel": 4}
|
||||||
},
|
},
|
||||||
|
|
||||||
"dds0": {
|
"dds0": {
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "DDS",
|
||||||
"parameters": {"reg_channel": 0, "rtio_switch": 5}
|
"arguments": {"reg_channel": 0, "rtio_switch": 5}
|
||||||
},
|
},
|
||||||
"dds1": {
|
"dds1": {
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "DDS",
|
||||||
"parameters": {"reg_channel": 1, "rtio_switch": 6}
|
"arguments": {"reg_channel": 1, "rtio_switch": 6}
|
||||||
},
|
},
|
||||||
"dds2": {
|
"dds2": {
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "DDS",
|
||||||
"parameters": {"reg_channel": 2, "rtio_switch": 7}
|
"arguments": {"reg_channel": 2, "rtio_switch": 7}
|
||||||
},
|
},
|
||||||
|
|
||||||
"electrodes": {
|
"electrodes": {
|
||||||
"module": "artiq.devices.pdq2",
|
"module": "artiq.devices.pdq2",
|
||||||
"class": "CompoundPDQ2",
|
"class": "CompoundPDQ2",
|
||||||
"parameters": {
|
"arguments": {
|
||||||
"ids": ["qc_q1_0", "qc_q1_1", "qc_q1_2", "qc_q1_3"],
|
"ids": ["qc_q1_0", "qc_q1_1", "qc_q1_2", "qc_q1_3"],
|
||||||
"rtio_trigger": 7,
|
"rtio_trigger": 7,
|
||||||
"rtio_frame": (2, 3, 4)
|
"rtio_frame": (2, 3, 4)
|
||||||
|
|
|
@ -2,36 +2,36 @@
|
||||||
"core": {
|
"core": {
|
||||||
"module": "artiq.sim.devices",
|
"module": "artiq.sim.devices",
|
||||||
"class": "Core",
|
"class": "Core",
|
||||||
"parameters": {}
|
"arguments": {}
|
||||||
},
|
},
|
||||||
"mains_sync": {
|
"mains_sync": {
|
||||||
"module": "artiq.sim.devices",
|
"module": "artiq.sim.devices",
|
||||||
"class": "Input",
|
"class": "Input",
|
||||||
"parameters": {"name": "mains_sync"}
|
"arguments": {"name": "mains_sync"}
|
||||||
},
|
},
|
||||||
"pmt": {
|
"pmt": {
|
||||||
"module": "artiq.sim.devices",
|
"module": "artiq.sim.devices",
|
||||||
"class": "Input",
|
"class": "Input",
|
||||||
"parameters": {"name": "pmt"}
|
"arguments": {"name": "pmt"}
|
||||||
},
|
},
|
||||||
"laser_cooling": {
|
"laser_cooling": {
|
||||||
"module": "artiq.sim.devices",
|
"module": "artiq.sim.devices",
|
||||||
"class": "WaveOutput",
|
"class": "WaveOutput",
|
||||||
"parameters": {"name": "laser_cooling"}
|
"arguments": {"name": "laser_cooling"}
|
||||||
},
|
},
|
||||||
"spectroscopy": {
|
"spectroscopy": {
|
||||||
"module": "artiq.sim.devices",
|
"module": "artiq.sim.devices",
|
||||||
"class": "WaveOutput",
|
"class": "WaveOutput",
|
||||||
"parameters": {"name": "spectroscopy"}
|
"arguments": {"name": "spectroscopy"}
|
||||||
},
|
},
|
||||||
"spectroscopy_b": {
|
"spectroscopy_b": {
|
||||||
"module": "artiq.sim.devices",
|
"module": "artiq.sim.devices",
|
||||||
"class": "VoltageOutput",
|
"class": "VoltageOutput",
|
||||||
"parameters": {"name": "spectroscopy_b"}
|
"arguments": {"name": "spectroscopy_b"}
|
||||||
},
|
},
|
||||||
"state_detection": {
|
"state_detection": {
|
||||||
"module": "artiq.sim.devices",
|
"module": "artiq.sim.devices",
|
||||||
"class": "WaveOutput",
|
"class": "WaveOutput",
|
||||||
"parameters": {"name": "state_detection"}
|
"arguments": {"name": "state_detection"}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
from artiq import *
|
from artiq import *
|
||||||
|
|
||||||
|
|
||||||
class DDSTest(AutoContext):
|
class DDSTest(AutoDB):
|
||||||
dds0 = Device("dds")
|
class DBKeys:
|
||||||
dds1 = Device("dds")
|
dds0 = Device()
|
||||||
dds2 = Device("dds")
|
dds1 = Device()
|
||||||
led = Device("gpio_out")
|
dds2 = Device()
|
||||||
|
led = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -3,7 +3,7 @@ import sys
|
||||||
from artiq import *
|
from artiq import *
|
||||||
|
|
||||||
|
|
||||||
class Mandelbrot(AutoContext):
|
class Mandelbrot(AutoDB):
|
||||||
def col(self, i):
|
def col(self, i):
|
||||||
sys.stdout.write(" .,-:;i+hHM$*#@ "[i])
|
sys.stdout.write(" .,-:;i+hHM$*#@ "[i])
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
from artiq import *
|
from artiq import *
|
||||||
|
|
||||||
|
|
||||||
class PhotonHistogram(AutoContext):
|
class PhotonHistogram(AutoDB):
|
||||||
bd = Device("dds")
|
class DBKeys:
|
||||||
bdd = Device("dds")
|
bd = Device()
|
||||||
pmt = Device("ttl_in")
|
bdd = Device()
|
||||||
|
pmt = Device()
|
||||||
|
|
||||||
nbins = Argument(100)
|
nbins = Argument(100)
|
||||||
repeats = Argument(100)
|
repeats = Argument(100)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def cool_detect(self):
|
def cool_detect(self):
|
||||||
|
|
|
@ -6,8 +6,9 @@ def print_min_period(p):
|
||||||
print("Minimum square wave output period: {} ns".format(p))
|
print("Minimum square wave output period: {} ns".format(p))
|
||||||
|
|
||||||
|
|
||||||
class PulsePerformance(AutoContext):
|
class PulsePerformance(AutoDB):
|
||||||
ttl0 = Device("ttl_out")
|
class DBKeys:
|
||||||
|
ttl0 = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -9,9 +9,10 @@ def print_failed():
|
||||||
print("Pulse was not received back")
|
print("Pulse was not received back")
|
||||||
|
|
||||||
|
|
||||||
class RTIOSkew(AutoContext):
|
class RTIOSkew(AutoDB):
|
||||||
pmt0 = Device("ttl_in")
|
class DBKeys:
|
||||||
ttl0 = Device("ttl_out")
|
pmt0 = Device()
|
||||||
|
ttl0 = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
from artiq import *
|
from artiq import *
|
||||||
|
|
||||||
|
|
||||||
class SimpleSimulation(AutoContext):
|
class SimpleSimulation(AutoDB):
|
||||||
a = Device("dds")
|
class DBKeys:
|
||||||
b = Device("dds")
|
a = Device()
|
||||||
c = Device("dds")
|
b = Device()
|
||||||
d = Device("dds")
|
c = Device()
|
||||||
|
d = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -20,17 +21,16 @@ class SimpleSimulation(AutoContext):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
from artiq.sim import devices as sd
|
from artiq.sim import devices as sd
|
||||||
from artiq.sim import time
|
|
||||||
|
|
||||||
|
core = sd.Core()
|
||||||
exp = SimpleSimulation(
|
exp = SimpleSimulation(
|
||||||
core=sd.Core(),
|
core=core,
|
||||||
a=sd.WaveOutput(name="a"),
|
a=sd.WaveOutput(core=core, name="a"),
|
||||||
b=sd.WaveOutput(name="b"),
|
b=sd.WaveOutput(core=core, name="b"),
|
||||||
c=sd.WaveOutput(name="c"),
|
c=sd.WaveOutput(core=core, name="c"),
|
||||||
d=sd.WaveOutput(name="d"),
|
d=sd.WaveOutput(core=core, name="d"),
|
||||||
)
|
)
|
||||||
exp.run()
|
exp.run()
|
||||||
print(time.manager.format_timeline())
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -10,17 +10,18 @@ transport_data = dict(
|
||||||
# 4 devices, 3 board each, 3 dacs each
|
# 4 devices, 3 board each, 3 dacs each
|
||||||
)
|
)
|
||||||
|
|
||||||
class Transport(AutoContext):
|
class Transport(AutoDB):
|
||||||
bd = Device("dds")
|
class DBKeys:
|
||||||
bdd = Device("dds")
|
bd = Device()
|
||||||
pmt = Device("ttl_in")
|
bdd = Device()
|
||||||
electrodes = Device("pdq")
|
pmt = Device()
|
||||||
|
electrodes = Device()
|
||||||
|
|
||||||
wait_at_stop = Parameter(100*us)
|
wait_at_stop = Parameter(100*us)
|
||||||
speed = Parameter(1.5)
|
speed = Parameter(1.5)
|
||||||
|
|
||||||
repeats = Argument(100)
|
repeats = Argument(100)
|
||||||
nbins = Argument(100)
|
nbins = Argument(100)
|
||||||
|
|
||||||
def prepare(self, stop):
|
def prepare(self, stop):
|
||||||
t = transport_data["t"][:stop]*self.speed
|
t = transport_data["t"][:stop]*self.speed
|
||||||
|
|
|
@ -113,19 +113,19 @@ def _action_cancel(remote, args):
|
||||||
|
|
||||||
|
|
||||||
def _action_set_device(remote, args):
|
def _action_set_device(remote, args):
|
||||||
remote.set_device(args.name, pyon.decode(args.description))
|
remote.set(args.name, pyon.decode(args.description))
|
||||||
|
|
||||||
|
|
||||||
def _action_del_device(remote, args):
|
def _action_del_device(remote, args):
|
||||||
remote.del_device(args.name)
|
remote.delete(args.name)
|
||||||
|
|
||||||
|
|
||||||
def _action_set_parameter(remote, args):
|
def _action_set_parameter(remote, args):
|
||||||
remote.set_parameter(args.name, pyon.decode(args.value))
|
remote.set(args.name, pyon.decode(args.value))
|
||||||
|
|
||||||
|
|
||||||
def _action_del_parameter(remote, args):
|
def _action_del_parameter(remote, args):
|
||||||
remote.del_parameter(args.name)
|
remote.delete(args.name)
|
||||||
|
|
||||||
|
|
||||||
def _show_queue(queue):
|
def _show_queue(queue):
|
||||||
|
@ -233,10 +233,14 @@ def main():
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
port = 8888 if args.port is None else args.port
|
port = 8888 if args.port is None else args.port
|
||||||
if action in ("submit", "cancel"):
|
target_name = {
|
||||||
target_name = "master_schedule"
|
"submit": "master_schedule",
|
||||||
else:
|
"cancel": "master_schedule",
|
||||||
target_name = "master_dpdb"
|
"set_device": "master_ddb",
|
||||||
|
"del_device": "master_ddb",
|
||||||
|
"set_parameter": "master_pdb",
|
||||||
|
"del_parameter": "master_pdb",
|
||||||
|
}[action]
|
||||||
remote = Client(args.server, port, target_name)
|
remote = Client(args.server, port, target_name)
|
||||||
try:
|
try:
|
||||||
globals()["_action_" + action](remote, args)
|
globals()["_action_" + action](remote, args)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import atexit
|
||||||
|
|
||||||
from artiq.management.pc_rpc import Server
|
from artiq.management.pc_rpc import Server
|
||||||
from artiq.management.sync_struct import Publisher
|
from artiq.management.sync_struct import Publisher
|
||||||
from artiq.management.dpdb import DeviceParamDB, SimpleParameterHistory
|
from artiq.management.db import FlatFileDB, SimpleHistory
|
||||||
from artiq.management.scheduler import Scheduler
|
from artiq.management.scheduler import Scheduler
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,24 +27,26 @@ def _get_args():
|
||||||
def main():
|
def main():
|
||||||
args = _get_args()
|
args = _get_args()
|
||||||
|
|
||||||
dpdb = DeviceParamDB("ddb.pyon", "pdb.pyon")
|
ddb = FlatFileDB("ddb.pyon")
|
||||||
simplephist = SimpleParameterHistory(30)
|
pdb = FlatFileDB("pdb.pyon")
|
||||||
dpdb.parameter_hooks.append(simplephist)
|
simplephist = SimpleHistory(30)
|
||||||
|
pdb.hooks.append(simplephist)
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
atexit.register(lambda: loop.close())
|
atexit.register(lambda: loop.close())
|
||||||
|
|
||||||
scheduler = Scheduler({
|
scheduler = Scheduler({
|
||||||
"req_device": dpdb.req_device,
|
"req_device": ddb.request,
|
||||||
"req_parameter": dpdb.req_parameter,
|
"req_parameter": pdb.request,
|
||||||
"set_parameter": dpdb.set_parameter
|
"set_parameter": pdb.set
|
||||||
})
|
})
|
||||||
loop.run_until_complete(scheduler.start())
|
loop.run_until_complete(scheduler.start())
|
||||||
atexit.register(lambda: loop.run_until_complete(scheduler.stop()))
|
atexit.register(lambda: loop.run_until_complete(scheduler.stop()))
|
||||||
|
|
||||||
server_control = Server({
|
server_control = Server({
|
||||||
"master_schedule": scheduler,
|
"master_schedule": scheduler,
|
||||||
"master_dpdb": dpdb
|
"master_ddb": ddb,
|
||||||
|
"master_pdb": pdb
|
||||||
})
|
})
|
||||||
loop.run_until_complete(server_control.start(
|
loop.run_until_complete(server_control.start(
|
||||||
args.bind, args.port_control))
|
args.bind, args.port_control))
|
||||||
|
@ -53,8 +55,8 @@ def main():
|
||||||
server_notify = Publisher({
|
server_notify = Publisher({
|
||||||
"queue": scheduler.queue,
|
"queue": scheduler.queue,
|
||||||
"periodic": scheduler.periodic,
|
"periodic": scheduler.periodic,
|
||||||
"devices": dpdb.ddb,
|
"devices": ddb.data,
|
||||||
"parameters": dpdb.pdb,
|
"parameters": pdb.data,
|
||||||
"parameters_simplehist": simplephist.history
|
"parameters_simplehist": simplephist.history
|
||||||
})
|
})
|
||||||
loop.run_until_complete(server_notify.start(
|
loop.run_until_complete(server_notify.start(
|
||||||
|
|
|
@ -6,14 +6,15 @@ from inspect import isclass
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from artiq.management.file_import import file_import
|
from artiq.management.file_import import file_import
|
||||||
from artiq.language.context import *
|
from artiq.language.db import *
|
||||||
from artiq.management import pyon
|
from artiq.management import pyon
|
||||||
from artiq.management.dpdb import DeviceParamDB, DeviceParamSupplier
|
from artiq.management.db import *
|
||||||
|
|
||||||
|
|
||||||
class ELFRunner(AutoContext):
|
class ELFRunner(AutoDB):
|
||||||
comm = Device("comm")
|
class DBKeys:
|
||||||
implicit_core = False
|
comm = Device()
|
||||||
|
implicit_core = False
|
||||||
|
|
||||||
def run(self, filename):
|
def run(self, filename):
|
||||||
with open(filename, "rb") as f:
|
with open(filename, "rb") as f:
|
||||||
|
@ -23,8 +24,14 @@ class ELFRunner(AutoContext):
|
||||||
comm.serve(dict(), dict())
|
comm.serve(dict(), dict())
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleParamLogger:
|
||||||
|
def set(self, timestamp, name, value):
|
||||||
|
print("Parameter change: {} -> {}".format(name, value))
|
||||||
|
|
||||||
|
|
||||||
def _get_args():
|
def _get_args():
|
||||||
parser = argparse.ArgumentParser(description="Local running tool")
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Local experiment running tool")
|
||||||
|
|
||||||
parser.add_argument("-d", "--ddb", default="ddb.pyon",
|
parser.add_argument("-d", "--ddb", default="ddb.pyon",
|
||||||
help="device database file")
|
help="device database file")
|
||||||
|
@ -54,8 +61,11 @@ def _parse_arguments(arguments):
|
||||||
def main():
|
def main():
|
||||||
args = _get_args()
|
args = _get_args()
|
||||||
|
|
||||||
dpdb = DeviceParamDB(args.ddb, args.pdb)
|
ddb = FlatFileDB(args.ddb)
|
||||||
dps = DeviceParamSupplier(dpdb.req_device, dpdb.req_parameter)
|
pdb = FlatFileDB(args.pdb)
|
||||||
|
pdb.hooks.append(SimpleParamLogger())
|
||||||
|
rdb = ResultDB()
|
||||||
|
dbh = DBHub(ddb, pdb, rdb)
|
||||||
try:
|
try:
|
||||||
if args.elf:
|
if args.elf:
|
||||||
if args.arguments:
|
if args.arguments:
|
||||||
|
@ -69,8 +79,8 @@ def main():
|
||||||
units = [(k, v) for k, v in module.__dict__.items()
|
units = [(k, v) for k, v in module.__dict__.items()
|
||||||
if k[0] != "_"
|
if k[0] != "_"
|
||||||
and isclass(v)
|
and isclass(v)
|
||||||
and issubclass(v, AutoContext)
|
and issubclass(v, AutoDB)
|
||||||
and v is not AutoContext]
|
and v is not AutoDB]
|
||||||
l = len(units)
|
l = len(units)
|
||||||
if l == 0:
|
if l == 0:
|
||||||
print("No units found in module")
|
print("No units found in module")
|
||||||
|
@ -92,15 +102,15 @@ def main():
|
||||||
print("Failed to parse run arguments")
|
print("Failed to parse run arguments")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
unit_inst = unit(dps, **arguments)
|
unit_inst = unit(dbh, **arguments)
|
||||||
unit_inst.run()
|
unit_inst.run()
|
||||||
|
|
||||||
if dps.parameter_wb:
|
if rdb.data:
|
||||||
print("Modified parameters:")
|
print("Results:")
|
||||||
for requester, name in dps.parameter_wb:
|
for k, v in rdb.data.items():
|
||||||
print("{}: {}".format(name, getattr(requester, name)))
|
print("{}: {}".format(k, v))
|
||||||
finally:
|
finally:
|
||||||
dps.close()
|
dbh.close()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in New Issue