From 39e9e73ff34dbd1b81cfb47c7ac64c9e242363c2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 26 Jun 2015 12:37:15 -0600 Subject: [PATCH 01/17] language: allow experiments to import from artiq.language this way the import stanza shows what is imported: just experiment language related components keep the imports also at top level until experiments have transitioned the top level __init__.py should build and expose the entire namespace of artiq related things, like hdf5 analysis tools, frontend components (like experiment running api), deployment tools etc. --- artiq/__init__.py | 6 ++---- artiq/language/__init__.py | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/__init__.py b/artiq/__init__.py index ebdb62601..7e6404c1e 100644 --- a/artiq/__init__.py +++ b/artiq/__init__.py @@ -1,4 +1,2 @@ -from artiq.language.core import * -from artiq.language.experiment import Experiment -from artiq.language.db import * -from artiq.language.units import * +from artiq import language +from artiq.language import * diff --git a/artiq/language/__init__.py b/artiq/language/__init__.py index e69de29bb..ebdb62601 100644 --- a/artiq/language/__init__.py +++ b/artiq/language/__init__.py @@ -0,0 +1,4 @@ +from artiq.language.core import * +from artiq.language.experiment import Experiment +from artiq.language.db import * +from artiq.language.units import * From 593dafc118c64e23d1e73f22352a789916094271 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 25 Jun 2015 22:19:11 -0600 Subject: [PATCH 02/17] test: hardware testbench --- artiq/test/coredevice.py | 56 ++++++++++++++++++++++++++++++++ artiq/test/hardware_testbench.py | 42 ++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 artiq/test/coredevice.py create mode 100644 artiq/test/hardware_testbench.py diff --git a/artiq/test/coredevice.py b/artiq/test/coredevice.py new file mode 100644 index 000000000..78d30142a --- /dev/null +++ b/artiq/test/coredevice.py @@ -0,0 +1,56 @@ +from artiq import * +from artiq.test.hardware_testbench import * +from artiq.coredevice.runtime_exceptions import RTIOUnderflow + + +class RTTTest(ExperimentCase): + class RTT(Experiment, AutoDB): + class DBKeys: + core = Device() + ttl_inout = Device() + rtt = Result() + + @kernel + def run(self): + self.ttl_inout.output() + delay(1*us) + t0 = now() + with parallel: + self.ttl_inout.gate_falling(2*us) + self.ttl_inout.pulse(1*us) + self.rtt = self.ttl_inout.timestamp() - t0 + + def test_rtt(self): + rtt = self.execute(self.RTT)["rtt"] + self.assertGreater(rtt, 0*ns) + self.assertLess(rtt, 40*ns) + + +class PulseRateTest(ExperimentCase): + class PulseRate(Experiment, AutoDB): + class DBKeys: + core = Device() + loop_out = Device() + pulse_rate = Result() + + @kernel + def run(self): + dt = time_to_cycles(1000*ns) + while True: + try: + for i in range(1000): + self.loop_out.pulse(cycles_to_time(dt)) + delay(cycles_to_time(dt)) + except RTIOUnderflow: + dt += 1 + self.core.break_realtime() + else: + self.pulse_rate = cycles_to_time(2*dt) + break + + def test_rate(self): + rate = self.execute(self.PulseRate)["pulse_rate"] + self.assertGreater(rate, 100*ns) + self.assertLess(rate, 2000*ns) + + diff --git a/artiq/test/hardware_testbench.py b/artiq/test/hardware_testbench.py new file mode 100644 index 000000000..35bb100e9 --- /dev/null +++ b/artiq/test/hardware_testbench.py @@ -0,0 +1,42 @@ +import os +import sys +import unittest +import logging + +from artiq import * +from artiq.protocols.file_db import FlatFileDB +from artiq.master.worker_db import DBHub, ResultDB +from artiq.frontend.artiq_run import ( + DummyScheduler, DummyWatchdog, SimpleParamLogger) + + +artiq_root = os.getenv("ARTIQ_ROOT") +logger = logging.getLogger(__name__) + + +@unittest.skipUnless(artiq_root, "no ARTIQ_ROOT") +class ExperimentCase(unittest.TestCase): + def setUp(self): + self.ddb = FlatFileDB(os.path.join(artiq_root, "ddb.pyon")) + self.pdb = FlatFileDB(os.path.join(artiq_root, "pdb.pyon")) + self.rdb = ResultDB(lambda description: None, lambda mod: None) + self.dbh = DBHub(self.ddb, self.pdb, self.rdb) + + def execute(self, cls, **kwargs): + expid = { + "file": sys.modules[cls.__module__].__file__, + "experiment": cls.__name__, + "arguments": kwargs + } + sched = DummyScheduler(expid) + try: + try: + exp = cls(self.dbh, scheduler=sched, **kwargs) + except KeyError as e: + raise unittest.SkipTest(*e.args) + self.rdb.build() + exp.run() + exp.analyze() + return self.rdb.data.read + finally: + self.dbh.close_devices() From f7427dda395d85c19f2c28ce0aa01534eb506f92 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 28 Jun 2015 20:08:39 -0600 Subject: [PATCH 03/17] test: make benchmarks unittest --- artiq/test/coredevice.py | 150 ++++++++++++++++++++++--------- artiq/test/hardware_testbench.py | 3 +- 2 files changed, 109 insertions(+), 44 deletions(-) diff --git a/artiq/test/coredevice.py b/artiq/test/coredevice.py index 78d30142a..552fc26e1 100644 --- a/artiq/test/coredevice.py +++ b/artiq/test/coredevice.py @@ -1,56 +1,120 @@ -from artiq import * -from artiq.test.hardware_testbench import * +from math import sqrt + +from artiq.language import * +from artiq.test.hardware_testbench import ExperimentCase from artiq.coredevice.runtime_exceptions import RTIOUnderflow -class RTTTest(ExperimentCase): - class RTT(Experiment, AutoDB): - class DBKeys: - core = Device() - ttl_inout = Device() - rtt = Result() +class RTT(Experiment, AutoDB): + class DBKeys: + core = Device() + ttl_inout = Device() + rtt = Result() - @kernel - def run(self): - self.ttl_inout.output() - delay(1*us) - t0 = now() - with parallel: - self.ttl_inout.gate_falling(2*us) + @kernel + def run(self): + self.ttl_inout.output() + delay(1*us) + with parallel: + self.ttl_inout.gate_rising(2*us) + with sequential: + delay(1*us) + t0 = now() self.ttl_inout.pulse(1*us) - self.rtt = self.ttl_inout.timestamp() - t0 + self.rtt = self.ttl_inout.timestamp() - t0 + +class Loopback(Experiment, AutoDB): + class DBKeys: + core = Device() + loop_in = Device() + loop_out = Device() + rtt = Result() + + @kernel + def run(self): + with parallel: + self.loop_in.gate_rising(2*us) + with sequential: + delay(1*us) + t0 = now() + self.loop_out.pulse(1*us) + self.rtt = self.loop_in.timestamp() - t0 + + +class PulseRate(Experiment, AutoDB): + class DBKeys: + core = Device() + loop_out = Device() + pulse_rate = Result() + + @kernel + def run(self): + dt = time_to_cycles(1000*ns) + while True: + try: + for i in range(1000): + self.loop_out.pulse(cycles_to_time(dt)) + delay(cycles_to_time(dt)) + except RTIOUnderflow: + dt += 1 + self.core.break_realtime() + else: + self.pulse_rate = cycles_to_time(2*dt) + break + + +class CoredeviceTest(ExperimentCase): def test_rtt(self): - rtt = self.execute(self.RTT)["rtt"] + rtt = self.execute(RTT)["rtt"] + print(rtt) + self.assertGreater(rtt, 0*ns) + self.assertLess(rtt, 100*ns) + + def test_loopback(self): + rtt = self.execute(Loopback)["rtt"] + print(rtt) self.assertGreater(rtt, 0*ns) self.assertLess(rtt, 40*ns) - -class PulseRateTest(ExperimentCase): - class PulseRate(Experiment, AutoDB): - class DBKeys: - core = Device() - loop_out = Device() - pulse_rate = Result() - - @kernel - def run(self): - dt = time_to_cycles(1000*ns) - while True: - try: - for i in range(1000): - self.loop_out.pulse(cycles_to_time(dt)) - delay(cycles_to_time(dt)) - except RTIOUnderflow: - dt += 1 - self.core.break_realtime() - else: - self.pulse_rate = cycles_to_time(2*dt) - break - - def test_rate(self): - rate = self.execute(self.PulseRate)["pulse_rate"] + def test_pulse_rate(self): + rate = self.execute(PulseRate)["pulse_rate"] + print(rate) self.assertGreater(rate, 100*ns) - self.assertLess(rate, 2000*ns) + self.assertLess(rate, 2500*ns) +class RPCTiming(Experiment, AutoDB): + class DBKeys: + core = Device() + repeats = Argument(100) + rpc_time_mean = Result() + rpc_time_stddev = Result() + + def nop(self, x): + pass + + @kernel + def bench(self): + self.ts = [0. for _ in range(self.repeats)] + for i in range(self.repeats): + t1 = self.core.get_rtio_time() + self.nop(1) + t2 = self.core.get_rtio_time() + self.ts[i] = t2 - t1 + + def run(self): + self.bench() + mean = sum(self.ts)/self.repeats + self.rpc_time_stddev = sqrt( + sum([(t - mean)**2 for t in self.ts])/self.repeats)*s + self.rpc_time_mean = mean*s + + +class RPCTest(ExperimentCase): + def test_rpc_timing(self): + res = self.execute(RPCTiming) + print(res) + self.assertGreater(res["rpc_time_mean"], 100*ns) + self.assertLess(res["rpc_time_mean"], 10*ms) + self.assertLess(res["rpc_time_stddev"], 1*ms) diff --git a/artiq/test/hardware_testbench.py b/artiq/test/hardware_testbench.py index 35bb100e9..bdb1e2e82 100644 --- a/artiq/test/hardware_testbench.py +++ b/artiq/test/hardware_testbench.py @@ -3,7 +3,7 @@ import sys import unittest import logging -from artiq import * +from artiq.language import * from artiq.protocols.file_db import FlatFileDB from artiq.master.worker_db import DBHub, ResultDB from artiq.frontend.artiq_run import ( @@ -33,6 +33,7 @@ class ExperimentCase(unittest.TestCase): try: exp = cls(self.dbh, scheduler=sched, **kwargs) except KeyError as e: + # skip if ddb does not match requirements raise unittest.SkipTest(*e.args) self.rdb.build() exp.run() From 5442ae312f5d2677620ac220941f14908dbfce6f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 28 Jun 2015 20:09:38 -0600 Subject: [PATCH 04/17] benchmarks/*: remove Benchmarks should be shaped as unittests and run as part of CI. --- benchmarks/all.py | 18 ------------------ benchmarks/ddb.pyon | 28 ---------------------------- benchmarks/pdb.pyon | 1 - benchmarks/pulse_rate.py | 26 -------------------------- benchmarks/rpc_timing.py | 32 -------------------------------- benchmarks/rtio_skew.py | 29 ----------------------------- 6 files changed, 134 deletions(-) delete mode 100644 benchmarks/all.py delete mode 100644 benchmarks/ddb.pyon delete mode 100644 benchmarks/pdb.pyon delete mode 100644 benchmarks/pulse_rate.py delete mode 100644 benchmarks/rpc_timing.py delete mode 100644 benchmarks/rtio_skew.py diff --git a/benchmarks/all.py b/benchmarks/all.py deleted file mode 100644 index d0a34263b..000000000 --- a/benchmarks/all.py +++ /dev/null @@ -1,18 +0,0 @@ -from artiq import * - -import pulse_rate, rtio_skew, rpc_timing - - -_exps = [pulse_rate.PulseRate, rtio_skew.RTIOSkew, rpc_timing.RPCTiming] - -class AllBenchmarks(Experiment, AutoDB): - """All benchmarks""" - - def build(self): - self.se = [] - for exp in _exps: - self.se.append(exp(self.dbh)) - - def run(self): - for se in self.se: - se.run() diff --git a/benchmarks/ddb.pyon b/benchmarks/ddb.pyon deleted file mode 100644 index 8dd20362c..000000000 --- a/benchmarks/ddb.pyon +++ /dev/null @@ -1,28 +0,0 @@ -{ - "comm": { - "type": "local", - "module": "artiq.coredevice.comm_tcp", - "class": "Comm", - "arguments": {"host": "192.168.0.42"} - }, - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {} - }, - - "pmt0": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": 0} - }, - - "ttl0": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 2} - }, -} diff --git a/benchmarks/pdb.pyon b/benchmarks/pdb.pyon deleted file mode 100644 index 0967ef424..000000000 --- a/benchmarks/pdb.pyon +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/benchmarks/pulse_rate.py b/benchmarks/pulse_rate.py deleted file mode 100644 index 4de78fa06..000000000 --- a/benchmarks/pulse_rate.py +++ /dev/null @@ -1,26 +0,0 @@ -from artiq import * -from artiq.coredevice.runtime_exceptions import RTIOUnderflow - - -class PulseRate(Experiment, AutoDB): - """Sustained pulse rate""" - - class DBKeys: - core = Device() - ttl0 = Device() - pulse_rate = Result() - - @kernel - def run(self): - T = time_to_cycles(100*ns) - while True: - try: - for i in range(1000): - self.ttl0.pulse(cycles_to_time(T)) - delay(cycles_to_time(T)) - except RTIOUnderflow: - T += 1 - self.core.break_realtime() - else: - self.pulse_rate = cycles_to_time(2*T) - break diff --git a/benchmarks/rpc_timing.py b/benchmarks/rpc_timing.py deleted file mode 100644 index 33e8152d9..000000000 --- a/benchmarks/rpc_timing.py +++ /dev/null @@ -1,32 +0,0 @@ -from math import sqrt - -from artiq import * - - -class RPCTiming(Experiment, AutoDB): - """RPC timing""" - - class DBKeys: - core = Device() - repeats = Argument(100) - rpc_time_mean = Result() - rpc_time_stddev = Result() - - def nop(self, x): - pass - - @kernel - def bench(self): - self.ts = [0.0 for _ in range(self.repeats)] - for i in range(self.repeats): - t1 = self.core.get_rtio_time() - self.nop(10) - t2 = self.core.get_rtio_time() - self.ts[i] = t2 - t1 - - def run(self): - self.bench() - mean = sum(self.ts)/self.repeats - self.rpc_time_stddev = sqrt( - sum([(t - mean)**2 for t in self.ts])/self.repeats)*s - self.rpc_time_mean = mean*s diff --git a/benchmarks/rtio_skew.py b/benchmarks/rtio_skew.py deleted file mode 100644 index a5770864b..000000000 --- a/benchmarks/rtio_skew.py +++ /dev/null @@ -1,29 +0,0 @@ -from artiq import * - - -class PulseNotReceived(Exception): - pass - - -class RTIOSkew(Experiment, AutoDB): - """RTIO skew""" - - class DBKeys: - core = Device() - pmt0 = Device() - rtio_skew = Result() - - @kernel - def run(self): - self.pmt0.output() - delay(1*us) - with parallel: - self.pmt0.gate_rising(10*us) - with sequential: - delay(5*us) - out_t = now() - self.pmt0.pulse(5*us) - in_t = self.pmt0.timestamp() - if in_t < 0*s: - raise PulseNotReceived - self.rtio_skew = out_t - in_t From 23eee9445833d90e8bef1757914e8f0b5e1ba9ca Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 28 Jun 2015 20:33:50 -0600 Subject: [PATCH 05/17] pipistrello: add notes to nist_qc1 about dds_clock * remove xtrig from the target as it is not usually connected (used for dds_clock) and ignore PMT2/BTN2 as C:15 is used for dds_clock. * this also aligns the ttl channel numbers with kc705/nist_qc1 (two pmt inputs followed by 16 ttl outputs followed by leds) --- artiq/gateware/nist_qc1.py | 16 ++++++++++++++-- soc/targets/artiq_pipistrello.py | 10 ++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/nist_qc1.py b/artiq/gateware/nist_qc1.py index a2d68e44f..f75f52371 100644 --- a/artiq/gateware/nist_qc1.py +++ b/artiq/gateware/nist_qc1.py @@ -4,10 +4,22 @@ from mibuild.generic_platform import * papilio_adapter_io = [ ("ext_led", 0, Pins("B:7"), IOStandard("LVTTL")), + # to feed the 125 MHz clock (preferrably from DDS SYNC_CLK) + # to the FPGA, use the xtrig pair. + # + # on papiliopro-adapter, xtrig (C:12) is connected to a GCLK + # + # on pipistrello, C:15 is the only GCLK in proximity, used as a button + # input, BTN2/PMT2 in papiliopro-adapter + # either improve the DDS box to feed 125MHz into the PMT2 pair, or: + # + # * disconnect C:15 from its periphery on the adapter board + # * bridge C:15 to the xtrig output of the transciever + # * optionally, disconnect C:12 from its periphery + ("xtrig", 0, Pins("C:12"), IOStandard("LVTTL")), ("pmt", 0, Pins("C:13"), IOStandard("LVTTL")), ("pmt", 1, Pins("C:14"), IOStandard("LVTTL")), - ("xtrig", 0, Pins("C:12"), IOStandard("LVTTL")), - ("dds_clock", 0, Pins("C:15"), IOStandard("LVTTL")), # PMT2 + ("pmt", 2, Pins("C:15"), IOStandard("LVTTL")), # rarely equipped ("ttl", 0, Pins("C:11"), IOStandard("LVTTL")), ("ttl", 1, Pins("C:10"), IOStandard("LVTTL")), diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index 6f5e6f632..65b6e4cea 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -34,7 +34,7 @@ class _RTIOCRG(Module, AutoCSR): i_FREEZEDCM=0, i_RST=ResetSignal()) - rtio_external_clk = platform.request("dds_clock") + rtio_external_clk = platform.request("pmt", 2) platform.add_period_constraint(rtio_external_clk, 8.0) self.specials += Instance("BUFGMUX", i_I0=rtio_internal_clk, @@ -95,11 +95,13 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd for i in range(2): phy = ttl_simple.Inout(platform.request("pmt", i)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512, + ofifo_depth=4)) - phy = ttl_simple.Inout(platform.request("xtrig", 0)) + phy = ttl_simple.Inout(platform.request("xtrig")) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4, + ofifo_depth=4)) for i in range(16): phy = ttl_simple.Output(platform.request("ttl", i)) From e2cb0e107f5e3636459517659266c50ff2674844 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 28 Jun 2015 21:11:41 -0600 Subject: [PATCH 06/17] pipistrello: really do not request xtrig --- soc/targets/artiq_pipistrello.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index 65b6e4cea..ddc42a8dd 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -98,11 +98,6 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512, ofifo_depth=4)) - phy = ttl_simple.Inout(platform.request("xtrig")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4, - ofifo_depth=4)) - for i in range(16): phy = ttl_simple.Output(platform.request("ttl", i)) self.submodules += phy From 165ef20ffa88829e7b9b9a4410eb33818ebce6e1 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 28 Jun 2015 21:24:57 -0600 Subject: [PATCH 07/17] pipistrello: drop rtio fifos for invisible leds the main board leds are all under the adapter board also tweak fifo depths a bit in a feeble attempt to circumvent a ISE hang (par phase 4) --- soc/targets/artiq_pipistrello.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index ddc42a8dd..be7ba6312 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -105,12 +105,8 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd phy = ttl_simple.Output(platform.request("ext_led", 0)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) + rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256)) - for i in range(2, 5): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) self.add_constant("RTIO_TTL_COUNT", len(rtio_channels)) self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels)) From d39382eca0623697e46714c82bff1e1e967fd903 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 28 Jun 2015 22:06:33 -0600 Subject: [PATCH 08/17] pipistrello: ext_led fifo depth 4 --- soc/targets/artiq_pipistrello.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index be7ba6312..36d57f2e4 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -105,7 +105,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd phy = ttl_simple.Output(platform.request("ext_led", 0)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256)) + rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) self.add_constant("RTIO_TTL_COUNT", len(rtio_channels)) From 515aa968194f7e7578ebec518d5a41371cef341e Mon Sep 17 00:00:00 2001 From: Yann Sionneau Date: Mon, 29 Jun 2015 12:59:52 +0200 Subject: [PATCH 09/17] controllers: use --simulation for simulation --- artiq/frontend/lda_controller.py | 7 ++++--- artiq/frontend/novatech409b_controller.py | 7 +++++-- artiq/frontend/pdq2_controller.py | 7 +++++-- artiq/frontend/pxi6733_controller.py | 7 ++++--- artiq/frontend/thorlabs_tcube_controller.py | 7 ++++--- doc/manual/developing_a_ndsp.rst | 2 +- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/artiq/frontend/lda_controller.py b/artiq/frontend/lda_controller.py index cc70038e9..0f3a0ab32 100755 --- a/artiq/frontend/lda_controller.py +++ b/artiq/frontend/lda_controller.py @@ -19,8 +19,9 @@ def get_argparser(): "The serial number is written on a sticker under " "the device, you should write for example " "-d \"SN:03461\". You must prepend enough 0 for it " - "to be 5 digits." - " Omit for simulation mode.") + "to be 5 digits.") + parser.add_argument("--simulation", action="store_true", + help="Put the driver in simulation mode.") verbosity_args(parser) return parser @@ -28,7 +29,7 @@ def get_argparser(): def main(): args = get_argparser().parse_args() init_logger(args) - if args.device is None: + if args.simulation: lda = Ldasim() else: lda = Lda(args.device, args.product) diff --git a/artiq/frontend/novatech409b_controller.py b/artiq/frontend/novatech409b_controller.py index 30dcd75f7..8eb6b280a 100755 --- a/artiq/frontend/novatech409b_controller.py +++ b/artiq/frontend/novatech409b_controller.py @@ -19,7 +19,10 @@ def get_argparser(): simple_network_args(parser, 3254) parser.add_argument( "-d", "--device", default=None, - help="serial port. Omit for simulation mode.") + help="serial port.") + parser.add_argument( + "--simulation", action="store_true", + help="Put the driver in simulation mode.") verbosity_args(parser) return parser @@ -28,7 +31,7 @@ def main(): args = get_argparser().parse_args() init_logger(args) - dev = Novatech409B(args.device) + dev = Novatech409B(args.device if not args.simulation else None) try: simple_server_loop( {"novatech409b": dev}, args.bind, args.port) diff --git a/artiq/frontend/pdq2_controller.py b/artiq/frontend/pdq2_controller.py index 6404d7d7f..9a9885565 100755 --- a/artiq/frontend/pdq2_controller.py +++ b/artiq/frontend/pdq2_controller.py @@ -12,7 +12,10 @@ def get_argparser(): simple_network_args(parser, 3252) parser.add_argument( "-d", "--device", default=None, - help="serial port. Omit for simulation mode.") + help="serial port.") + parser.add_argument( + "--simulation", action="store_true", + help="Put the driver in simulation mode.") parser.add_argument( "--dump", default="pdq2_dump.bin", help="file to dump pdq2 data into, for later simulation") @@ -24,7 +27,7 @@ def main(): args = get_argparser().parse_args() init_logger(args) port = None - if args.device is None: + if args.simulation: port = open(args.dump, "wb") dev = Pdq2(url=args.device, dev=port) try: diff --git a/artiq/frontend/pxi6733_controller.py b/artiq/frontend/pxi6733_controller.py index 33948d02d..1c4a5ce64 100755 --- a/artiq/frontend/pxi6733_controller.py +++ b/artiq/frontend/pxi6733_controller.py @@ -12,10 +12,11 @@ def get_argparser(): parser = argparse.ArgumentParser(description="NI PXI 6733 controller") simple_network_args(parser, 3256) parser.add_argument("-C", "--channels", default=None, - help="List of channels (e.g. Dev1/ao0, Dev1/ao1:3)." - " Omit for simulation mode.") + help="List of channels (e.g. Dev1/ao0, Dev1/ao1:3).") parser.add_argument("-c", "--clock", default="PFI5", help="Input clock pin name (default: PFI5)") + parser.add_argument("--simulation", action='store_true', + help="Put the driver in simulation mode.") verbosity_args(parser) return parser @@ -24,7 +25,7 @@ def main(): args = get_argparser().parse_args() init_logger(args) - if args.channels is None: + if args.simulation: daq = DAQmxSim() else: daq = DAQmx(args.channels, diff --git a/artiq/frontend/thorlabs_tcube_controller.py b/artiq/frontend/thorlabs_tcube_controller.py index d6aea8cbf..c8766dd6c 100755 --- a/artiq/frontend/thorlabs_tcube_controller.py +++ b/artiq/frontend/thorlabs_tcube_controller.py @@ -14,8 +14,9 @@ def get_argparser(): choices=["TDC001", "TPZ001"]) parser.add_argument("-d", "--device", default=None, help="serial device. See documentation for how to " - "specify a USB Serial Number. Omit for simulation " - "mode.") + "specify a USB Serial Number.") + parser.add_argument("--simulation", action="store_true", + help="Put the driver in simulation mode.") simple_network_args(parser, 3255) verbosity_args(parser) return parser @@ -25,7 +26,7 @@ def main(): args = get_argparser().parse_args() init_logger(args) - if args.device is None: + if args.simulation: if args.product == "TDC001": dev = TdcSim() elif args.product == "TPZ001": diff --git a/doc/manual/developing_a_ndsp.rst b/doc/manual/developing_a_ndsp.rst index 98e24e15e..0bc867892 100644 --- a/doc/manual/developing_a_ndsp.rst +++ b/doc/manual/developing_a_ndsp.rst @@ -177,7 +177,7 @@ General guidelines * Use new-style formatting (``str.format``) except for logging where it is not well supported, and double quotes for strings. * The device identification (e.g. serial number, or entry in ``/dev``) to attach to must be passed as a command-line parameter to the controller. We suggest using ``-d`` and ``--device`` as parameter name. * Controllers must be able to operate in "simulation" mode, where they behave properly even if the associated hardware is not connected. For example, they can print the data to the console instead of sending it to the device, or dump it into a file. -* We suggest that the simulation mode is entered whenever the ``-d/--device`` option is omitted. +* The simulation mode is entered whenever the ``--simulation`` option is specified. * Keep command line parameters consistent across clients/controllers. When adding new command line options, look for a client/controller that does a similar thing and follow its use of ``argparse``. If the original client/controller could use ``argparse`` in a better way, improve it. * Use docstrings for all public methods of the driver (note that those will be retrieved by ``artiq_rpctool``). * Choose a free default TCP port and add it to the default port list in this manual. From a73776bd7297cb8caf467be6ad28a3ec5c7b38f7 Mon Sep 17 00:00:00 2001 From: Yann Sionneau Date: Mon, 29 Jun 2015 19:21:32 +0200 Subject: [PATCH 10/17] controllers: enforce the usage of either --simulation or --device --- artiq/frontend/novatech409b_controller.py | 5 +++++ artiq/frontend/pdq2_controller.py | 6 ++++++ artiq/frontend/pxi6733_controller.py | 5 +++++ artiq/frontend/thorlabs_tcube_controller.py | 5 +++++ 4 files changed, 21 insertions(+) diff --git a/artiq/frontend/novatech409b_controller.py b/artiq/frontend/novatech409b_controller.py index 8eb6b280a..d3c5ddf75 100755 --- a/artiq/frontend/novatech409b_controller.py +++ b/artiq/frontend/novatech409b_controller.py @@ -31,6 +31,11 @@ def main(): args = get_argparser().parse_args() init_logger(args) + if not args.simulation and args.device is None: + raise ValueError("You need to specify either --simulation or " + "-d/--device argument. Use --help for more " + "information.") + dev = Novatech409B(args.device if not args.simulation else None) try: simple_server_loop( diff --git a/artiq/frontend/pdq2_controller.py b/artiq/frontend/pdq2_controller.py index 9a9885565..95b86caa5 100755 --- a/artiq/frontend/pdq2_controller.py +++ b/artiq/frontend/pdq2_controller.py @@ -27,6 +27,12 @@ def main(): args = get_argparser().parse_args() init_logger(args) port = None + + if not args.simulation and args.device is None: + raise ValueError("You need to specify either --simulation or " + "-d/--device argument. Use --help for more " + "information.") + if args.simulation: port = open(args.dump, "wb") dev = Pdq2(url=args.device, dev=port) diff --git a/artiq/frontend/pxi6733_controller.py b/artiq/frontend/pxi6733_controller.py index 1c4a5ce64..1307bede2 100755 --- a/artiq/frontend/pxi6733_controller.py +++ b/artiq/frontend/pxi6733_controller.py @@ -25,6 +25,11 @@ def main(): args = get_argparser().parse_args() init_logger(args) + if not args.simulation and args.channels is None: + raise ValueError("You need to specify either --simulation or " + "-C/--channels argument. Use --help for more " + "information.") + if args.simulation: daq = DAQmxSim() else: diff --git a/artiq/frontend/thorlabs_tcube_controller.py b/artiq/frontend/thorlabs_tcube_controller.py index c8766dd6c..fd879d0a5 100755 --- a/artiq/frontend/thorlabs_tcube_controller.py +++ b/artiq/frontend/thorlabs_tcube_controller.py @@ -26,6 +26,11 @@ def main(): args = get_argparser().parse_args() init_logger(args) + if not args.simulation and args.device is None: + raise ValueError("You need to specify either --simulation or " + "-d/--device argument. Use --help for more " + "information.") + if args.simulation: if args.product == "TDC001": dev = TdcSim() From ffe1355b1aac88e669f162cd63134d87dc3aba60 Mon Sep 17 00:00:00 2001 From: Yann Sionneau Date: Mon, 29 Jun 2015 19:24:55 +0200 Subject: [PATCH 11/17] lda_controller: improve help message for --device argument --- artiq/frontend/lda_controller.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/lda_controller.py b/artiq/frontend/lda_controller.py index 0f3a0ab32..5753af44e 100755 --- a/artiq/frontend/lda_controller.py +++ b/artiq/frontend/lda_controller.py @@ -18,8 +18,9 @@ def get_argparser(): help="USB serial number of the device. " "The serial number is written on a sticker under " "the device, you should write for example " - "-d \"SN:03461\". You must prepend enough 0 for it " - "to be 5 digits.") + "-d \"SN:03461\". You must prepend enough 0 for " + "it to be 5 digits. If omitted, the first " + "available device will be used.") parser.add_argument("--simulation", action="store_true", help="Put the driver in simulation mode.") verbosity_args(parser) From f0ac8cb3543b0a496b76d604a49d35b4e23de9ab Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 29 Jun 2015 11:26:38 -0600 Subject: [PATCH 12/17] pipistrello: add user_led:2 for debugging w/o adapter --- soc/targets/artiq_pipistrello.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index 36d57f2e4..80b647785 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -107,6 +107,10 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) + phy = ttl_simple.Output(platform.request("user_led", 2)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) + self.add_constant("RTIO_TTL_COUNT", len(rtio_channels)) self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels)) From d1c4cf0b78e78e335f3509344404b1b9bd1f25c2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 29 Jun 2015 12:21:54 -0600 Subject: [PATCH 13/17] pipistrello: update rtio channel doc --- doc/manual/fpga_board_ports.rst | 32 ++++++++++++++++++-------------- soc/targets/artiq_pipistrello.py | 4 +++- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/doc/manual/fpga_board_ports.rst b/doc/manual/fpga_board_ports.rst index 13ba6b54a..442c3e691 100644 --- a/doc/manual/fpga_board_ports.rst +++ b/doc/manual/fpga_board_ports.rst @@ -13,20 +13,24 @@ The low-cost Pipistrello FPGA board can be used as a lower-cost but slower alter When plugged to an adapter, the NIST QC1 hardware can be used. The TTL lines are mapped to RTIO channels as follows: -+--------------+----------+-----------------+ -| RTIO channel | TTL line | Capability | -+==============+==========+=================+ -| 0 | PMT0 | Input only | -+--------------+----------+-----------------+ -| 1 | PMT1 | Input only | -+--------------+----------+-----------------+ -| 2-18 | TTL0-16 | Output only | -+--------------+----------+-----------------+ -| 19-21 | LEDs | Output only | -+--------------+----------+-----------------+ -| 22 | TTL2 | Output only | -+--------------+----------+-----------------+ ++--------------+----------+------------+ +| RTIO channel | TTL line | Capability | ++==============+==========+============+ +| 0 | PMT0 | Input | ++--------------+----------+------------+ +| 1 | PMT1 | Input | ++--------------+----------+------------+ +| 2-17 | TTL0-15 | Output | ++--------------+----------+------------+ +| 18 | EXT_LED | Output | ++--------------+----------+------------+ +| 19 | USER_LED | Output | ++--------------+----------+------------+ +| 20 | DDS | Output | ++--------------+----------+------------+ The input only limitation on channels 0 and 1 comes from the QC-DAQ adapter. When the adapter is not used (and physically unplugged from the Pipistrello board), the corresponding pins on the Pipistrello can be used as outputs. Do not configure these channels as outputs when the adapter is plugged, as this would cause electrical contention. -The board can accept an external RTIO clock connected to PMT2. +The board can accept an external RTIO clock connected to PMT2. If the DDS box +does not drive the PMT2 pair, use XTRIG and patch the XTRIG transciever output +on the adapter board onto C:15 disconnecting PMT2. diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index 80b647785..fbbb8d270 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -83,6 +83,8 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd self.submodules.leds = gpio.GPIOOut(Cat( platform.request("user_led", 0), platform.request("user_led", 1), + platform.request("user_led", 2), + platform.request("user_led", 3), )) self.comb += [ @@ -107,7 +109,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) - phy = ttl_simple.Output(platform.request("user_led", 2)) + phy = ttl_simple.Output(platform.request("user_led", 4)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) From 3ee2bd5fa8cf56c5bc6aec9f0097b922508b798b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 29 Jun 2015 12:59:59 -0600 Subject: [PATCH 14/17] pipistrello: set CLKFX_MD_MAX from MD ratio --- soc/targets/artiq_pipistrello.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index fbbb8d270..b3bc058c3 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -24,7 +24,7 @@ class _RTIOCRG(Module, AutoCSR): self.specials += Instance("DCM_CLKGEN", p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=f.denominator, - p_CLKFX_MD_MAX=1.6, + p_CLKFX_MD_MAX=float(f), p_CLKFX_MULTIPLY=f.numerator, p_CLKIN_PERIOD=1e9/clk_freq, p_SPREAD_SPECTRUM="NONE", From 0f06bac701de7f5a123d73b5efbf7575b822391d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 29 Jun 2015 14:18:38 -0600 Subject: [PATCH 15/17] travis: use "use-local" for conda install http://conda.pydata.org/docs/build_tutorials/pkgs.html --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1bee784bc..5e9c750b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ before_install: - pip install coveralls install: - conda build conda/artiq - - conda install $HOME/miniconda/conda-bld/linux-64/artiq-*.tar.bz2 + - conda install artiq --use-local script: - coverage run --source=artiq setup.py test - make -C doc/manual html From 652f3359a2cf38213afc91f30e1c0bd10f8ac4ba Mon Sep 17 00:00:00 2001 From: Yann Sionneau Date: Wed, 1 Jul 2015 11:40:48 +0200 Subject: [PATCH 16/17] lda_controller: fix typo --- artiq/frontend/lda_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/lda_controller.py b/artiq/frontend/lda_controller.py index 5753af44e..8286bc143 100755 --- a/artiq/frontend/lda_controller.py +++ b/artiq/frontend/lda_controller.py @@ -18,7 +18,7 @@ def get_argparser(): help="USB serial number of the device. " "The serial number is written on a sticker under " "the device, you should write for example " - "-d \"SN:03461\". You must prepend enough 0 for " + "-d \"SN:03461\". You must prepend enough 0s for " "it to be 5 digits. If omitted, the first " "available device will be used.") parser.add_argument("--simulation", action="store_true", From d7ef885d9e8eb3f54b4adf256e6514e8ebd1cb3e Mon Sep 17 00:00:00 2001 From: Yann Sionneau Date: Wed, 1 Jul 2015 11:54:15 +0200 Subject: [PATCH 17/17] controllers: print+exit instead of raising exception for argparse error, better doc for --simulation As long as you use --simulation, the driver will be in simulation mode. Even if you specify a --device or --channels. That can allow you to just switch to simulation mode by adding --simulation in the device database without having to remove the serial number or device path/name. --- artiq/frontend/novatech409b_controller.py | 9 +++++---- artiq/frontend/pdq2_controller.py | 9 +++++---- artiq/frontend/pxi6733_controller.py | 10 ++++++---- artiq/frontend/thorlabs_tcube_controller.py | 10 ++++++---- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/artiq/frontend/novatech409b_controller.py b/artiq/frontend/novatech409b_controller.py index d3c5ddf75..57846ae95 100755 --- a/artiq/frontend/novatech409b_controller.py +++ b/artiq/frontend/novatech409b_controller.py @@ -4,6 +4,7 @@ import argparse import logging +import sys from artiq.devices.novatech409b.driver import Novatech409B from artiq.protocols.pc_rpc import simple_server_loop @@ -22,7 +23,7 @@ def get_argparser(): help="serial port.") parser.add_argument( "--simulation", action="store_true", - help="Put the driver in simulation mode.") + help="Put the driver in simulation mode, even if --device is used.") verbosity_args(parser) return parser @@ -32,9 +33,9 @@ def main(): init_logger(args) if not args.simulation and args.device is None: - raise ValueError("You need to specify either --simulation or " - "-d/--device argument. Use --help for more " - "information.") + print("You need to specify either --simulation or -d/--device " + "argument. Use --help for more information.") + sys.exit(1) dev = Novatech409B(args.device if not args.simulation else None) try: diff --git a/artiq/frontend/pdq2_controller.py b/artiq/frontend/pdq2_controller.py index 95b86caa5..577cdce2b 100755 --- a/artiq/frontend/pdq2_controller.py +++ b/artiq/frontend/pdq2_controller.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import argparse +import sys from artiq.devices.pdq2.driver import Pdq2 from artiq.protocols.pc_rpc import simple_server_loop @@ -15,7 +16,7 @@ def get_argparser(): help="serial port.") parser.add_argument( "--simulation", action="store_true", - help="Put the driver in simulation mode.") + help="Put the driver in simulation mode, even if --device is used.") parser.add_argument( "--dump", default="pdq2_dump.bin", help="file to dump pdq2 data into, for later simulation") @@ -29,9 +30,9 @@ def main(): port = None if not args.simulation and args.device is None: - raise ValueError("You need to specify either --simulation or " - "-d/--device argument. Use --help for more " - "information.") + print("You need to specify either --simulation or -d/--device " + "argument. Use --help for more information.") + sys.exit(1) if args.simulation: port = open(args.dump, "wb") diff --git a/artiq/frontend/pxi6733_controller.py b/artiq/frontend/pxi6733_controller.py index 1307bede2..9658dc6bb 100755 --- a/artiq/frontend/pxi6733_controller.py +++ b/artiq/frontend/pxi6733_controller.py @@ -2,6 +2,7 @@ # Yann Sionneau , 2015 import argparse +import sys from artiq.protocols.pc_rpc import simple_server_loop from artiq.devices.pxi6733.driver import DAQmx, DAQmxSim @@ -16,7 +17,8 @@ def get_argparser(): parser.add_argument("-c", "--clock", default="PFI5", help="Input clock pin name (default: PFI5)") parser.add_argument("--simulation", action='store_true', - help="Put the driver in simulation mode.") + help="Put the driver in simulation mode, even if " + "--channels is used.") verbosity_args(parser) return parser @@ -26,9 +28,9 @@ def main(): init_logger(args) if not args.simulation and args.channels is None: - raise ValueError("You need to specify either --simulation or " - "-C/--channels argument. Use --help for more " - "information.") + print("You need to specify either --simulation or -C/--channels " + "argument. Use --help for more information.") + sys.exit(1) if args.simulation: daq = DAQmxSim() diff --git a/artiq/frontend/thorlabs_tcube_controller.py b/artiq/frontend/thorlabs_tcube_controller.py index fd879d0a5..85ccc6ebc 100755 --- a/artiq/frontend/thorlabs_tcube_controller.py +++ b/artiq/frontend/thorlabs_tcube_controller.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import argparse +import sys from artiq.devices.thorlabs_tcube.driver import Tdc, Tpz, TdcSim, TpzSim from artiq.protocols.pc_rpc import simple_server_loop @@ -16,7 +17,8 @@ def get_argparser(): help="serial device. See documentation for how to " "specify a USB Serial Number.") parser.add_argument("--simulation", action="store_true", - help="Put the driver in simulation mode.") + help="Put the driver in simulation mode, even if " + "--device is used.") simple_network_args(parser, 3255) verbosity_args(parser) return parser @@ -27,9 +29,9 @@ def main(): init_logger(args) if not args.simulation and args.device is None: - raise ValueError("You need to specify either --simulation or " - "-d/--device argument. Use --help for more " - "information.") + print("You need to specify either --simulation or -d/--device " + "argument. Use --help for more information.") + sys.exit(1) if args.simulation: if args.product == "TDC001":