device and parameter database

This commit is contained in:
Sebastien Bourdeauducq 2014-12-03 18:20:30 +08:00
parent a41009f92a
commit 2a95d27770
23 changed files with 385 additions and 261 deletions

View File

@ -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)

View File

@ -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))

View File

@ -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)

View File

@ -24,7 +24,7 @@ class DDS(AutoContext):
the DDS device.
"""
dds_sysclk = Parameter()
dds_sysclk = Parameter(1*GHz)
reg_channel = Parameter()
rtio_switch = Parameter()

View File

@ -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
View 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()

View File

@ -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))

View File

@ -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::

View File

@ -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

View File

@ -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
View 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
View 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"}
},
}

View File

@ -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()

View File

@ -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
View File

@ -0,0 +1 @@
{}

View File

@ -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])

View File

@ -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()

View File

@ -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()

View File

@ -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
View 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()

View File

@ -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()

View File

@ -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()

View File

@ -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)