forked from M-Labs/artiq
device and parameter database
This commit is contained in:
parent
a41009f92a
commit
2a95d27770
@ -1,5 +1,6 @@
|
||||
from operator import itemgetter
|
||||
|
||||
from artiq.language.context import AutoContext
|
||||
from artiq.language.units import ms, ns
|
||||
from artiq.coredevice.runtime import LinkInterface
|
||||
|
||||
@ -13,7 +14,9 @@ class _RuntimeEnvironment(LinkInterface):
|
||||
return str(self.llvm_module)
|
||||
|
||||
|
||||
class Comm:
|
||||
class Comm(AutoContext):
|
||||
implicit_core = False
|
||||
|
||||
def get_runtime_env(self):
|
||||
return _RuntimeEnvironment(1*ns)
|
||||
|
||||
|
@ -8,6 +8,7 @@ import logging
|
||||
|
||||
from artiq.language import core as core_language
|
||||
from artiq.language import units
|
||||
from artiq.language.context import *
|
||||
from artiq.coredevice.runtime import Environment
|
||||
from artiq.coredevice import runtime_exceptions
|
||||
|
||||
@ -59,13 +60,17 @@ def _read_exactly(f, n):
|
||||
return r
|
||||
|
||||
|
||||
class Comm:
|
||||
def __init__(self, dev="/dev/ttyUSB1", baud=115200):
|
||||
self._fd = os.open(dev, os.O_RDWR | os.O_NOCTTY)
|
||||
class Comm(AutoContext):
|
||||
serial_dev = Parameter("/dev/ttyUSB1")
|
||||
baud_rate = Parameter(115200)
|
||||
implicit_core = False
|
||||
|
||||
def build(self):
|
||||
self._fd = os.open(self.serial_dev, os.O_RDWR | os.O_NOCTTY)
|
||||
self.port = os.fdopen(self._fd, "r+b", buffering=0)
|
||||
self.set_baud(115200)
|
||||
self.set_remote_baud(baud)
|
||||
self.set_baud(baud)
|
||||
self.set_remote_baud(self.baud_rate)
|
||||
self.set_baud(self.baud_rate)
|
||||
|
||||
def set_baud(self, baud):
|
||||
iflag, oflag, cflag, lflag, ispeed, ospeed, cc = \
|
||||
@ -109,12 +114,6 @@ class Comm:
|
||||
self.set_remote_baud(115200)
|
||||
self.port.close()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close()
|
||||
|
||||
def _get_device_msg(self):
|
||||
while True:
|
||||
(reply, ) = struct.unpack("B", _read_exactly(self.port, 1))
|
||||
|
@ -1,5 +1,8 @@
|
||||
import os
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.context import *
|
||||
|
||||
from artiq.transforms.inline import inline
|
||||
from artiq.transforms.lower_units import lower_units
|
||||
from artiq.transforms.quantize_time import quantize_time
|
||||
@ -10,8 +13,8 @@ from artiq.transforms.unroll_loops import unroll_loops
|
||||
from artiq.transforms.interleave import interleave
|
||||
from artiq.transforms.lower_time import lower_time
|
||||
from artiq.transforms.unparse import unparse
|
||||
|
||||
from artiq.py2llvm import get_runtime_binary
|
||||
from artiq.language.core import *
|
||||
|
||||
|
||||
def _announce_unparse(label, node):
|
||||
@ -41,19 +44,20 @@ def _no_debug_unparse(label, node):
|
||||
pass
|
||||
|
||||
|
||||
class Core:
|
||||
def __init__(self, comm, external_clock=None, runtime_env=None):
|
||||
if runtime_env is None:
|
||||
runtime_env = comm.get_runtime_env()
|
||||
self.runtime_env = runtime_env
|
||||
self.comm = comm
|
||||
class Core(AutoContext):
|
||||
comm = Device("comm")
|
||||
external_clock = Parameter(None)
|
||||
implicit_core = False
|
||||
|
||||
def build(self):
|
||||
self.runtime_env = self.comm.get_runtime_env()
|
||||
self.core = self
|
||||
|
||||
if external_clock is None:
|
||||
if self.external_clock is None:
|
||||
self.ref_period = self.runtime_env.internal_ref_period
|
||||
self.comm.switch_clock(False)
|
||||
else:
|
||||
self.ref_period = external_clock
|
||||
self.ref_period = self.external_clock
|
||||
self.comm.switch_clock(True)
|
||||
self.initial_time = int64(self.runtime_env.warmup_time/self.ref_period)
|
||||
|
||||
|
@ -24,7 +24,7 @@ class DDS(AutoContext):
|
||||
the DDS device.
|
||||
|
||||
"""
|
||||
dds_sysclk = Parameter()
|
||||
dds_sysclk = Parameter(1*GHz)
|
||||
reg_channel = Parameter()
|
||||
rtio_switch = Parameter()
|
||||
|
||||
|
@ -110,13 +110,21 @@ class AutoContext:
|
||||
for k in dir(self):
|
||||
v = getattr(self, k)
|
||||
if isinstance(v, _AttributeKind):
|
||||
value = self.mvs.get_missing_value(k, v)
|
||||
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)
|
||||
setattr(self, k, value)
|
||||
|
||||
self.build()
|
||||
|
||||
def get_missing_value(self, name, kind):
|
||||
"""Attempts to retrieve ``parameter`` from the object's attributes.
|
||||
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.
|
||||
@ -125,7 +133,7 @@ class AutoContext:
|
||||
try:
|
||||
return getattr(self, name)
|
||||
except AttributeError:
|
||||
return self.mvs.get_missing_value(name, kind)
|
||||
return self.mvs.get_missing_value(name, kind, requester)
|
||||
|
||||
def build(self):
|
||||
"""This is called by ``__init__`` after the parameter initialization
|
||||
|
49
artiq/management/dpdb.py
Normal file
49
artiq/management/dpdb.py
Normal file
@ -0,0 +1,49 @@
|
||||
from collections import OrderedDict
|
||||
import importlib
|
||||
|
||||
from artiq.language.context import *
|
||||
|
||||
|
||||
def create_device(desc, mvs):
|
||||
module = importlib.import_module(desc["module"])
|
||||
device_class = getattr(module, desc["class"])
|
||||
return device_class(mvs, **desc["parameters"])
|
||||
|
||||
|
||||
class DeviceParamDB:
|
||||
def __init__(self, devices, parameters):
|
||||
self.devices = devices
|
||||
self.parameters = parameters
|
||||
self.active_devices = OrderedDict()
|
||||
|
||||
def get_missing_value(self, name, kind, requester):
|
||||
if isinstance(kind, Device):
|
||||
if name in self.active_devices:
|
||||
return self.active_devices[name]
|
||||
elif name in self.devices:
|
||||
desc = self.devices[name]
|
||||
while isinstance(desc, str):
|
||||
# alias
|
||||
desc = self.devices[desc]
|
||||
dev = create_device(desc, self)
|
||||
self.active_devices[name] = dev
|
||||
return dev
|
||||
else:
|
||||
raise KeyError("Unknown device '{}' of type '{}'"
|
||||
" requested by {}"
|
||||
.format(name, kind.type_hint, requester))
|
||||
elif isinstance(kind, Parameter):
|
||||
if name in self.parameters:
|
||||
return self.parameters[name]
|
||||
elif kind.default is not NoDefault:
|
||||
return kind.default
|
||||
else:
|
||||
raise KeyError("Unknown parameter: " + name)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
def close(self):
|
||||
for dev in reversed(list(self.active_devices.values())):
|
||||
if hasattr(dev, "close"):
|
||||
dev.close()
|
||||
self.active_devices = OrderedDict()
|
@ -1,28 +1,38 @@
|
||||
from random import Random
|
||||
|
||||
from artiq.language.core import delay
|
||||
from artiq.language.core import delay, kernel
|
||||
from artiq.language.context import AutoContext, Parameter
|
||||
from artiq.language import units
|
||||
from artiq.sim import time
|
||||
|
||||
|
||||
class Core:
|
||||
class Core(AutoContext):
|
||||
implicit_core = False
|
||||
|
||||
_level = 0
|
||||
|
||||
def run(self, k_function, k_args, k_kwargs):
|
||||
return k_function(*k_args, **k_kwargs)
|
||||
Core._level += 1
|
||||
r = k_function(*k_args, **k_kwargs)
|
||||
Core._level -= 1
|
||||
if Core._level == 0:
|
||||
print(time.manager.format_timeline())
|
||||
return r
|
||||
|
||||
|
||||
class Input(AutoContext):
|
||||
name = Parameter()
|
||||
implicit_core = False
|
||||
|
||||
def build(self):
|
||||
self.prng = Random()
|
||||
|
||||
@kernel
|
||||
def wait_edge(self):
|
||||
duration = self.prng.randrange(0, 20)*units.ms
|
||||
time.manager.event(("wait_edge", self.name, duration))
|
||||
delay(duration)
|
||||
|
||||
@kernel
|
||||
def count_gate(self, duration):
|
||||
result = self.prng.randrange(0, 100)
|
||||
time.manager.event(("count_gate", self.name, duration, result))
|
||||
@ -32,8 +42,8 @@ class Input(AutoContext):
|
||||
|
||||
class WaveOutput(AutoContext):
|
||||
name = Parameter()
|
||||
implicit_core = False
|
||||
|
||||
@kernel
|
||||
def pulse(self, frequency, duration):
|
||||
time.manager.event(("pulse", self.name, frequency, duration))
|
||||
delay(duration)
|
||||
@ -41,7 +51,7 @@ class WaveOutput(AutoContext):
|
||||
|
||||
class VoltageOutput(AutoContext):
|
||||
name = Parameter()
|
||||
implicit_core = False
|
||||
|
||||
@kernel
|
||||
def set(self, value):
|
||||
time.manager.event(("set_voltage", self.name, value))
|
||||
|
@ -7,7 +7,7 @@ Connecting to the core device
|
||||
As a very first step, we will turn on a LED on the core device. Create a file ``led.py`` containing the following: ::
|
||||
|
||||
from artiq import *
|
||||
from artiq.coredevice import comm_serial, core, gpio
|
||||
|
||||
|
||||
class LED(AutoContext):
|
||||
led = Device("gpio_out")
|
||||
@ -16,18 +16,14 @@ As a very first step, we will turn on a LED on the core device. Create a file ``
|
||||
def run(self):
|
||||
self.led.on()
|
||||
|
||||
if __name__ == "__main__":
|
||||
with comm_serial.Comm() as comm:
|
||||
core_driver = core.Core(comm)
|
||||
led_driver = gpio.GPIOOut(core=core_driver, channel=0)
|
||||
exp = LED(core=core_driver, led=led_driver)
|
||||
exp.run()
|
||||
|
||||
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. We are not using the database yet; instead, we import and create the device drivers and establish communication with the core device manually. Abstract attributes such as ``Device("gpio_out")`` list the devices (and parameters) that our class needs in order to operate. ``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.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).
|
||||
|
||||
Run this example with: ::
|
||||
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.
|
||||
|
||||
python3 led.py
|
||||
Run your code using ``artiq_run.py``, which is part of the ARTIQ front-end tools: ::
|
||||
|
||||
$ artiq_run.py led
|
||||
|
||||
The LED of the device should turn on. Congratulations! You have a basic ARTIQ system up and running.
|
||||
|
||||
@ -53,9 +49,9 @@ Modify the code as follows: ::
|
||||
|
||||
You can then turn the LED off and on by entering 0 or 1 at the prompt that appears: ::
|
||||
|
||||
$ python3 led.py
|
||||
$ artiq_run.py led
|
||||
Enter desired LED state: 1
|
||||
$ python3 led.py
|
||||
$ artiq_run.py led
|
||||
Enter desired LED state: 0
|
||||
|
||||
What happens is the ARTIQ compiler notices that the ``input_led_state`` function does not have a ``@kernel`` decorator and thus must be executed on the host. When the core device calls it, it sends a request to the host to execute it. The host displays the prompt, collects user input, and sends the result back to the core device, which sets the LED state accordingly.
|
||||
@ -82,25 +78,18 @@ The point of running code on the core device is the ability to meet demanding re
|
||||
Create a new file ``rtio.py`` containing the following: ::
|
||||
|
||||
from artiq import *
|
||||
from artiq.coredevice import comm_serial, core, rtio
|
||||
|
||||
class Tutorial(AutoContext):
|
||||
o = Device("ttl_out")
|
||||
ttl0 = Device("ttl_out")
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
for i in range(1000000):
|
||||
self.o.pulse(2*us)
|
||||
self.ttl0.pulse(2*us)
|
||||
delay(2*us)
|
||||
|
||||
if __name__ == "__main__":
|
||||
with comm_serial.Comm() as comm:
|
||||
core_driver = core.Core(comm)
|
||||
out_driver = rtio.RTIOOut(core=core_driver, channel=2)
|
||||
exp = Tutorial(core=core_driver, o=out_driver)
|
||||
exp.run()
|
||||
|
||||
Connect an oscilloscope or logic analyzer to the RTIO channel 2 (pin C11 on the Papilio Pro, TTL0) and run ``python3 rtio.py``. Notice that the generated signal's period is precisely 4 microseconds, and that it has a duty cycle of precisely 50%. This is not what you would expect if the delay and the pulse were implemented with CPU-controlled GPIO: overhead from the loop management, function calls, etc. would increase the signal's period, and asymmetry in the overhead would cause duty cycle distortion.
|
||||
Connect an oscilloscope or logic analyzer to TTL0 (pin C11 on the Papilio Pro) and run ``artiq_run.py led``. Notice that the generated signal's period is precisely 4 microseconds, and that it has a duty cycle of precisely 50%. This is not what you would expect if the delay and the pulse were implemented with CPU-controlled GPIO: overhead from the loop management, function calls, etc. would increase the signal's period, and asymmetry in the overhead would cause duty cycle distortion.
|
||||
|
||||
Instead, inside the core device, output timing is generated by the gateware and the CPU only programs switching commands with certain timestamps that the CPU computes. This guarantees precise timing as long as the CPU can keep generating timestamps that are increasing fast enough. In case it fails to do that (and attempts to program an event with a timestamp in the past), the :class:`artiq.coredevice.runtime_exceptions.RTIOUnderflow` exception is raised. The kernel causing it may catch it (using a regular ``try... except...`` construct), or it will be propagated to the host.
|
||||
|
||||
@ -113,14 +102,14 @@ Try reducing the period of the generated waveform until the CPU cannot keep up w
|
||||
|
||||
class Tutorial(AutoContext):
|
||||
led = Device("gpio_out")
|
||||
o = Device("ttl_out")
|
||||
ttl0 = Device("ttl_out")
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
self.led.off()
|
||||
try:
|
||||
for i in range(1000000):
|
||||
self.o.pulse(...)
|
||||
self.ttl0.pulse(...)
|
||||
delay(...)
|
||||
except RTIOUnderflow:
|
||||
self.led.on()
|
||||
@ -135,21 +124,21 @@ Try the following code and observe the generated pulses on a 2-channel oscillosc
|
||||
|
||||
for i in range(1000000):
|
||||
with parallel:
|
||||
self.o1.pulse(2*us)
|
||||
self.o2.pulse(4*us)
|
||||
self.ttl0.pulse(2*us)
|
||||
self.ttl1.pulse(4*us)
|
||||
delay(4*us)
|
||||
|
||||
If you assign ``o2`` to the RTIO channel 3, the signal will be generated on the pin C10 (TTL1) of the Papilio Pro.
|
||||
TTL1 is assigned to the pin C10 of the Papilio Pro. The name of the attributes (``ttl0`` and ``ttl1``) is used to look up hardware in the device database.
|
||||
|
||||
Within a parallel block, some statements can be made sequential again using a ``with sequential`` construct. Observe the pulses generated by this code: ::
|
||||
|
||||
for i in range(1000000):
|
||||
with parallel:
|
||||
with sequential:
|
||||
self.o1.pulse(2*us)
|
||||
self.ttl0.pulse(2*us)
|
||||
delay(1*us)
|
||||
self.o1.pulse(1*us)
|
||||
self.o2.pulse(4*us)
|
||||
self.ttl0.pulse(1*us)
|
||||
self.ttl1.pulse(4*us)
|
||||
delay(4*us)
|
||||
|
||||
.. warning::
|
||||
|
@ -49,7 +49,7 @@ and verify that you can connect to the TCP port: ::
|
||||
|
||||
:tip: Use the key combination Ctrl-AltGr-9 to get the ``telnet>`` prompt, and enter ``close`` to quit Telnet. Quit the controller with Ctrl-C.
|
||||
|
||||
Also verify that you can get the type of the server (the "hello" string passed to ``simple_server_loop``) using the ``identify-controller.py`` program from the ARTIQ front-end tools: ::
|
||||
Also verify that you can get the type of the server (the "hello" string passed to ``simple_server_loop``) using the ``identify_controller.py`` program from the ARTIQ front-end tools: ::
|
||||
|
||||
$ identify_controller.py ::1 7777
|
||||
Type: hello
|
||||
|
@ -8,9 +8,9 @@ class AluminumSpectroscopy(AutoContext):
|
||||
spectroscopy_b = Device("dac")
|
||||
state_detection = Device("dds")
|
||||
pmt = Device("ttl_in")
|
||||
spectroscopy_freq = Parameter()
|
||||
photon_limit_low = Parameter()
|
||||
photon_limit_high = Parameter()
|
||||
spectroscopy_freq = Parameter(432*MHz)
|
||||
photon_limit_low = Parameter(10)
|
||||
photon_limit_high = Parameter(15)
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
@ -37,27 +37,3 @@ class AluminumSpectroscopy(AutoContext):
|
||||
if photon_count < self.photon_limit_low:
|
||||
state_0_count += 1
|
||||
return state_0_count
|
||||
|
||||
|
||||
def main():
|
||||
from artiq.sim import devices as sd
|
||||
from artiq.sim import time
|
||||
|
||||
exp = AluminumSpectroscopy(
|
||||
core=sd.Core(),
|
||||
mains_sync=sd.Input(name="mains_sync"),
|
||||
laser_cooling=sd.WaveOutput(name="laser_cooling"),
|
||||
spectroscopy=sd.WaveOutput(name="spectroscopy"),
|
||||
spectroscopy_b=sd.VoltageOutput(name="spectroscopy_b"),
|
||||
state_detection=sd.WaveOutput(name="state_detection"),
|
||||
pmt=sd.Input(name="pmt"),
|
||||
|
||||
spectroscopy_freq=432*MHz,
|
||||
photon_limit_low=10,
|
||||
photon_limit_high=15
|
||||
)
|
||||
exp.run()
|
||||
print(time.manager.format_timeline())
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
76
examples/ddb.pyon
Normal file
76
examples/ddb.pyon
Normal file
@ -0,0 +1,76 @@
|
||||
{
|
||||
"comm": {
|
||||
"module": "artiq.coredevice.comm_serial",
|
||||
"class": "Comm",
|
||||
"parameters": {}
|
||||
},
|
||||
"core": {
|
||||
"module": "artiq.coredevice.core",
|
||||
"class": "Core",
|
||||
"parameters": {}
|
||||
},
|
||||
|
||||
"led": {
|
||||
"module": "artiq.coredevice.gpio",
|
||||
"class": "GPIOOut",
|
||||
"parameters": {"channel": 0}
|
||||
},
|
||||
|
||||
"pmt0": {
|
||||
"module": "artiq.coredevice.rtio",
|
||||
"class": "RTIOIn",
|
||||
"parameters": {"channel": 0}
|
||||
},
|
||||
"pmt1": {
|
||||
"module": "artiq.coredevice.rtio",
|
||||
"class": "RTIOIn",
|
||||
"parameters": {"channel": 1}
|
||||
},
|
||||
|
||||
"ttl0": {
|
||||
"module": "artiq.coredevice.rtio",
|
||||
"class": "RTIOOut",
|
||||
"parameters": {"channel": 2}
|
||||
},
|
||||
"ttl1": {
|
||||
"module": "artiq.coredevice.rtio",
|
||||
"class": "RTIOOut",
|
||||
"parameters": {"channel": 3}
|
||||
},
|
||||
"ttl2": {
|
||||
"module": "artiq.coredevice.rtio",
|
||||
"class": "RTIOOut",
|
||||
"parameters": {"channel": 4}
|
||||
},
|
||||
|
||||
"dds0": {
|
||||
"module": "artiq.coredevice.dds",
|
||||
"class": "DDS",
|
||||
"parameters": {"reg_channel": 0, "rtio_switch": 5}
|
||||
},
|
||||
"dds1": {
|
||||
"module": "artiq.coredevice.dds",
|
||||
"class": "DDS",
|
||||
"parameters": {"reg_channel": 1, "rtio_switch": 6}
|
||||
},
|
||||
"dds2": {
|
||||
"module": "artiq.coredevice.dds",
|
||||
"class": "DDS",
|
||||
"parameters": {"reg_channel": 2, "rtio_switch": 7}
|
||||
},
|
||||
|
||||
"electrodes": {
|
||||
"module": "artiq.devices.pdq2",
|
||||
"class": "CompoundPDQ2",
|
||||
"parameters": {
|
||||
"ids": ["qc_q1_0", "qc_q1_1", "qc_q1_2", "qc_q1_3"],
|
||||
"rtio_trigger": 7,
|
||||
"rtio_frame": (2, 3, 4)
|
||||
},
|
||||
"comment": "Conflicts with dds2 and ttl0-2"
|
||||
},
|
||||
|
||||
"pmt": "pmt0",
|
||||
"bd": "dds0",
|
||||
"bdd": "dds1"
|
||||
}
|
37
examples/ddb_sim.pyon
Normal file
37
examples/ddb_sim.pyon
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"core": {
|
||||
"module": "artiq.sim.devices",
|
||||
"class": "Core",
|
||||
"parameters": {}
|
||||
},
|
||||
"mains_sync": {
|
||||
"module": "artiq.sim.devices",
|
||||
"class": "Input",
|
||||
"parameters": {"name": "mains_sync"}
|
||||
},
|
||||
"pmt": {
|
||||
"module": "artiq.sim.devices",
|
||||
"class": "Input",
|
||||
"parameters": {"name": "pmt"}
|
||||
},
|
||||
"laser_cooling": {
|
||||
"module": "artiq.sim.devices",
|
||||
"class": "WaveOutput",
|
||||
"parameters": {"name": "laser_cooling"}
|
||||
},
|
||||
"spectroscopy": {
|
||||
"module": "artiq.sim.devices",
|
||||
"class": "WaveOutput",
|
||||
"parameters": {"name": "spectroscopy"}
|
||||
},
|
||||
"spectroscopy_b": {
|
||||
"module": "artiq.sim.devices",
|
||||
"class": "VoltageOutput",
|
||||
"parameters": {"name": "spectroscopy_b"}
|
||||
},
|
||||
"state_detection": {
|
||||
"module": "artiq.sim.devices",
|
||||
"class": "WaveOutput",
|
||||
"parameters": {"name": "state_detection"}
|
||||
},
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
from artiq import *
|
||||
from artiq.coredevice import comm_serial, core, dds, gpio
|
||||
|
||||
|
||||
class DDSTest(AutoContext):
|
||||
a = Device("dds")
|
||||
b = Device("dds")
|
||||
c = Device("dds")
|
||||
d = Device("dds")
|
||||
dds0 = Device("dds")
|
||||
dds1 = Device("dds")
|
||||
dds2 = Device("dds")
|
||||
led = Device("gpio_out")
|
||||
|
||||
@kernel
|
||||
@ -18,30 +16,7 @@ class DDSTest(AutoContext):
|
||||
self.led.off()
|
||||
with parallel:
|
||||
with sequential:
|
||||
self.a.pulse(100*MHz + 4*i*kHz, 500*us)
|
||||
self.b.pulse(120*MHz, 500*us)
|
||||
with sequential:
|
||||
self.c.pulse(200*MHz, 100*us)
|
||||
self.d.pulse(250*MHz, 200*us)
|
||||
self.dds0.pulse(100*MHz + 4*i*kHz, 500*us)
|
||||
self.dds1.pulse(120*MHz, 500*us)
|
||||
self.dds2.pulse(200*MHz, 100*us)
|
||||
self.led.off()
|
||||
|
||||
|
||||
def main():
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
exp = DDSTest(
|
||||
core=coredev,
|
||||
a=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||
reg_channel=0, rtio_switch=2),
|
||||
b=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||
reg_channel=1, rtio_switch=3),
|
||||
c=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||
reg_channel=2, rtio_switch=4),
|
||||
d=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||
reg_channel=3, rtio_switch=5),
|
||||
led=gpio.GPIOOut(core=coredev, channel=0)
|
||||
)
|
||||
exp.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,7 +1,6 @@
|
||||
import sys
|
||||
|
||||
from artiq import *
|
||||
from artiq.coredevice import comm_serial, core
|
||||
|
||||
|
||||
class Mandelbrot(AutoContext):
|
||||
@ -36,12 +35,3 @@ class Mandelbrot(AutoContext):
|
||||
z_r = new_z_r
|
||||
self.col(i)
|
||||
self.row()
|
||||
|
||||
|
||||
def main():
|
||||
with comm_serial.Comm() as comm:
|
||||
exp = Mandelbrot(core=core.Core(comm))
|
||||
exp.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
1
examples/pdb.pyon
Normal file
1
examples/pdb.pyon
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -1,16 +1,12 @@
|
||||
from artiq import *
|
||||
from artiq.coredevice import comm_serial, core, dds, rtio
|
||||
|
||||
|
||||
class PhotonHistogram(AutoContext):
|
||||
bd = Device("dds")
|
||||
bdd = Device("dds")
|
||||
pmt = Device("ttl_in")
|
||||
repeats = Parameter()
|
||||
nbins = Parameter()
|
||||
|
||||
def report(self, i, n):
|
||||
print(i, n)
|
||||
repeats = Parameter(100)
|
||||
nbins = Parameter(100)
|
||||
|
||||
@kernel
|
||||
def cool_detect(self):
|
||||
@ -36,23 +32,4 @@ class PhotonHistogram(AutoContext):
|
||||
hist[n] += 1
|
||||
|
||||
for i in range(self.nbins):
|
||||
self.report(i, hist[i])
|
||||
|
||||
|
||||
def main():
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
exp = PhotonHistogram(
|
||||
core=coredev,
|
||||
bd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||
reg_channel=0, rtio_switch=2),
|
||||
bdd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||
reg_channel=1, rtio_switch=3),
|
||||
pmt=rtio.RTIOIn(core=coredev, channel=0),
|
||||
repeats=100,
|
||||
nbins=100
|
||||
)
|
||||
exp.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
print(i, hist[i])
|
||||
|
@ -1,5 +1,4 @@
|
||||
from artiq import *
|
||||
from artiq.coredevice import comm_serial, core, rtio
|
||||
from artiq.coredevice.runtime_exceptions import RTIOUnderflow
|
||||
|
||||
|
||||
@ -8,7 +7,7 @@ def print_min_period(p):
|
||||
|
||||
|
||||
class PulsePerformance(AutoContext):
|
||||
o = Device("ttl_out")
|
||||
ttl0 = Device("ttl_out")
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
@ -16,7 +15,7 @@ class PulsePerformance(AutoContext):
|
||||
while True:
|
||||
try:
|
||||
for i in range(1000):
|
||||
self.o.pulse(cycles_to_time(T))
|
||||
self.ttl0.pulse(cycles_to_time(T))
|
||||
delay(cycles_to_time(T))
|
||||
except RTIOUnderflow:
|
||||
T += 1
|
||||
@ -25,10 +24,3 @@ class PulsePerformance(AutoContext):
|
||||
print_min_period(int(cycles_to_time(2*T)/(1*ns)))
|
||||
break
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
exp = PulsePerformance(core=coredev,
|
||||
o=rtio.RTIOOut(core=coredev, channel=2))
|
||||
exp.run()
|
||||
|
@ -1,5 +1,4 @@
|
||||
from artiq import *
|
||||
from artiq.coredevice import comm_serial, core, rtio
|
||||
|
||||
|
||||
def print_skew(p):
|
||||
@ -11,27 +10,19 @@ def print_failed():
|
||||
|
||||
|
||||
class RTIOSkew(AutoContext):
|
||||
i = Device("ttl_in")
|
||||
o = Device("ttl_out")
|
||||
pmt0 = Device("ttl_in")
|
||||
ttl0 = Device("ttl_out")
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
with parallel:
|
||||
self.i.gate_rising(10*us)
|
||||
self.pmt0.gate_rising(10*us)
|
||||
with sequential:
|
||||
delay(5*us)
|
||||
out_t = now()
|
||||
self.o.pulse(5*us)
|
||||
in_t = self.i.timestamp()
|
||||
self.ttl0.pulse(5*us)
|
||||
in_t = self.pmt0.timestamp()
|
||||
if in_t < 0*s:
|
||||
print_failed()
|
||||
else:
|
||||
print_skew(int((out_t - in_t)/(1*ns)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
exp = RTIOSkew(core=coredev,
|
||||
i=rtio.RTIOIn(core=coredev, channel=0),
|
||||
o=rtio.RTIOOut(core=coredev, channel=2))
|
||||
exp.run()
|
||||
|
@ -1,23 +1,29 @@
|
||||
import numpy as np
|
||||
|
||||
from artiq import *
|
||||
from artiq.coredevice import comm_serial, core, dds, rtio
|
||||
from artiq.devices import pdq2
|
||||
|
||||
|
||||
# data is usually precomputed offline
|
||||
transport_data = dict(
|
||||
t=np.linspace(0, 10, 101), # waveform time
|
||||
u=np.random.randn(101, 4*3*3), # waveform data,
|
||||
# 4 devices, 3 board each, 3 dacs each
|
||||
)
|
||||
|
||||
class Transport(AutoContext):
|
||||
bd = Device("dds")
|
||||
bdd = Device("dds")
|
||||
pmt = Device("ttl_in")
|
||||
repeats = Parameter()
|
||||
nbins = Parameter()
|
||||
electrodes = Device("pdq")
|
||||
transport_data = Parameter()
|
||||
wait_at_stop = Parameter()
|
||||
speed = Parameter()
|
||||
|
||||
repeats = Parameter(100)
|
||||
nbins = Parameter(100)
|
||||
wait_at_stop = Parameter(100*us)
|
||||
speed = Parameter(1.5)
|
||||
|
||||
def prepare(self, stop):
|
||||
t = self.transport_data["t"][:stop]*self.speed
|
||||
u = self.transport_data["u"][:stop]
|
||||
t = transport_data["t"][:stop]*self.speed
|
||||
u = transport_data["u"][:stop]
|
||||
# start a new frame
|
||||
self.tf = self.electrodes.create_frame()
|
||||
# interpolates t and u and appends the (t, u) segment to the frame
|
||||
@ -110,36 +116,7 @@ class Transport(AutoContext):
|
||||
# live update 2d plot with current self.histogram
|
||||
# broadcast(s, self.histogram)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# data is usually precomputed offline
|
||||
data = dict(
|
||||
t=np.linspace(0, 10, 101), # waveform time
|
||||
u=np.random.randn(101, 4*3*3), # waveform data,
|
||||
# 4 devices, 3 board each, 3 dacs each
|
||||
)
|
||||
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
exp = Transport(
|
||||
core=coredev,
|
||||
bd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||
reg_channel=0, rtio_switch=2),
|
||||
bdd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||
reg_channel=1, rtio_switch=3),
|
||||
pmt=rtio.RTIOIn(core=coredev, channel=0),
|
||||
# a compound pdq device that wraps multiple usb devices (looked up
|
||||
# by usb "serial number"/id) into one
|
||||
electrodes=pdq2.CompoundPDQ2(
|
||||
core=coredev,
|
||||
ids=["qc_q1_{}".format(i) for i in range(4)],
|
||||
rtio_trigger=4, rtio_frame=(5, 6, 7)),
|
||||
transport_data=data, # or: json.load
|
||||
wait_at_stop=100*us,
|
||||
speed=1.5,
|
||||
repeats=100,
|
||||
nbins=100
|
||||
)
|
||||
def run(self):
|
||||
# scan transport endpoint
|
||||
stop = range(10, len(exp.transport_data["t"]), 10)
|
||||
exp.scan(stop)
|
||||
stops = range(10, len(transport_data["t"]), 10)
|
||||
self.scan(stops)
|
||||
|
83
frontend/artiq_run.py
Executable file
83
frontend/artiq_run.py
Executable file
@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import importlib
|
||||
import sys
|
||||
from inspect import isclass
|
||||
from operator import itemgetter
|
||||
|
||||
from artiq.language.context import *
|
||||
from artiq.management import pyon
|
||||
from artiq.management.dpdb import DeviceParamDB
|
||||
|
||||
|
||||
class ELFRunner(AutoContext):
|
||||
comm = Device("comm")
|
||||
implicit_core = False
|
||||
|
||||
def run(self, filename, function):
|
||||
with open(filename, "rb") as f:
|
||||
binary = f.read()
|
||||
comm.load(binary)
|
||||
comm.run(function)
|
||||
comm.serve(dict(), dict())
|
||||
|
||||
|
||||
def _get_args():
|
||||
parser = argparse.ArgumentParser(description="Experiment running tool")
|
||||
|
||||
parser.add_argument("-d", "--ddb", default="ddb.pyon",
|
||||
help="device database file")
|
||||
parser.add_argument("-p", "--pdb", default="pdb.pyon",
|
||||
help="parameter database file")
|
||||
|
||||
parser.add_argument("-e", "--elf", default=False, action="store_true",
|
||||
help="run ELF binary")
|
||||
parser.add_argument("-f", "--function", default="run",
|
||||
help="function to run")
|
||||
parser.add_argument("-u", "--unit", default=None,
|
||||
help="unit to run")
|
||||
parser.add_argument("module",
|
||||
help="module containing the unit to run")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = _get_args()
|
||||
|
||||
devices = pyon.load_file(args.ddb)
|
||||
parameters = pyon.load_file(args.pdb)
|
||||
dpdb = DeviceParamDB(devices, parameters)
|
||||
try:
|
||||
if args.elf:
|
||||
unit_inst = ELFRunner(dpdb)
|
||||
unit_inst.run(args.file, args.function)
|
||||
else:
|
||||
sys.path.append(".")
|
||||
module = importlib.import_module(args.module)
|
||||
if args.unit is None:
|
||||
units = [(k, v) for k, v in module.__dict__.items()
|
||||
if k[0] != "_" and isclass(v) and issubclass(v, AutoContext) and v is not AutoContext]
|
||||
l = len(units)
|
||||
if l == 0:
|
||||
print("No units found in module")
|
||||
sys.exit(1)
|
||||
elif l > 1:
|
||||
print("More than one unit found in module:")
|
||||
for k, v in sorted(units, key=itemgetter(0)):
|
||||
print(" " + k)
|
||||
print("Use -u to specify which unit to use.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
unit = units[0][1]
|
||||
else:
|
||||
unit = getattr(module, args.unit)
|
||||
unit_inst = unit(dpdb)
|
||||
f = getattr(unit_inst, args.function)
|
||||
f()
|
||||
finally:
|
||||
dpdb.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from artiq.coredevice import comm_serial
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Core device ELF loading tool")
|
||||
parser.add_argument("-e", default=False, action="store_true",
|
||||
help="show environment")
|
||||
parser.add_argument("-f", default="run",
|
||||
help="function to run")
|
||||
parser.add_argument("file",
|
||||
help="ELF binary to load")
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.file, "rb") as f:
|
||||
binary = f.read()
|
||||
with comm_serial.Comm() as comm:
|
||||
runtime_env = comm.get_runtime_env()
|
||||
if args.e:
|
||||
print(runtime_env)
|
||||
comm.load(binary)
|
||||
comm.run(args.f)
|
||||
comm.serve(dict(), dict())
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -13,10 +13,13 @@ no_hardware = bool(os.getenv("ARTIQ_NO_HARDWARE"))
|
||||
|
||||
|
||||
def _run_on_device(k_class, **parameters):
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
comm = comm_serial.Comm()
|
||||
try:
|
||||
coredev = core.Core(comm=comm)
|
||||
k_inst = k_class(core=coredev, **parameters)
|
||||
k_inst.run()
|
||||
finally:
|
||||
comm.close()
|
||||
|
||||
|
||||
def _run_on_host(k_class, **parameters):
|
||||
@ -171,8 +174,9 @@ class ExecutionCase(unittest.TestCase):
|
||||
self.assertEqual(l_device, l_host)
|
||||
|
||||
def test_misc(self):
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
comm = comm_serial.Comm()
|
||||
try:
|
||||
coredev = core.Core(comm=comm)
|
||||
uut = _Misc(core=coredev)
|
||||
uut.run()
|
||||
self.assertEqual(uut.half_input, 42)
|
||||
@ -189,6 +193,8 @@ class ExecutionCase(unittest.TestCase):
|
||||
uut.dimension_error3()
|
||||
with self.assertRaises(DimensionError):
|
||||
uut.dimension_error4()
|
||||
finally:
|
||||
comm.close()
|
||||
|
||||
def test_pulses(self):
|
||||
l_device, l_host = [], []
|
||||
@ -255,8 +261,9 @@ class RTIOCase(unittest.TestCase):
|
||||
# (C11 and C13 on Papilio Pro)
|
||||
def test_loopback(self):
|
||||
npulses = 4
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
comm = comm_serial.Comm()
|
||||
try:
|
||||
coredev = core.Core(comm=comm)
|
||||
uut = _RTIOLoopback(
|
||||
core=coredev,
|
||||
i=rtio.RTIOIn(core=coredev, channel=0),
|
||||
@ -265,23 +272,31 @@ class RTIOCase(unittest.TestCase):
|
||||
)
|
||||
uut.run()
|
||||
self.assertEqual(uut.result, npulses)
|
||||
finally:
|
||||
comm.close()
|
||||
|
||||
def test_underflow(self):
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
comm = comm_serial.Comm()
|
||||
try:
|
||||
coredev = core.Core(comm=comm)
|
||||
uut = _RTIOUnderflow(
|
||||
core=coredev,
|
||||
o=rtio.RTIOOut(core=coredev, channel=2)
|
||||
)
|
||||
with self.assertRaises(runtime_exceptions.RTIOUnderflow):
|
||||
uut.run()
|
||||
finally:
|
||||
comm.close()
|
||||
|
||||
def test_sequence_error(self):
|
||||
with comm_serial.Comm() as comm:
|
||||
coredev = core.Core(comm)
|
||||
comm = comm_serial.Comm()
|
||||
try:
|
||||
coredev = core.Core(comm=comm)
|
||||
uut = _RTIOSequenceError(
|
||||
core=coredev,
|
||||
o=rtio.RTIOOut(core=coredev, channel=2)
|
||||
)
|
||||
with self.assertRaises(runtime_exceptions.RTIOSequenceError):
|
||||
uut.run()
|
||||
finally:
|
||||
comm.close()
|
||||
|
@ -39,7 +39,7 @@ def run():
|
||||
|
||||
class OptimizeCase(unittest.TestCase):
|
||||
def test_optimize(self):
|
||||
coredev = core.Core(comm_dummy.Comm())
|
||||
coredev = core.Core(comm=comm_dummy.Comm())
|
||||
func_def = ast.parse(optimize_in).body[0]
|
||||
coredev.transform_stack(func_def, dict(), dict())
|
||||
self.assertEqual(unparse(func_def), optimize_out)
|
||||
|
Loading…
Reference in New Issue
Block a user