diff --git a/artiq/coredevice/comm_generic.py b/artiq/coredevice/comm_generic.py index 3de7b40e1..a737dfb84 100644 --- a/artiq/coredevice/comm_generic.py +++ b/artiq/coredevice/comm_generic.py @@ -43,9 +43,8 @@ class _D2HMsgType(Enum): RPC_REQUEST = 10 FLASH_READ_REPLY = 11 - FLASH_WRITE_REPLY = 12 - FLASH_OK_REPLY = 13 - FLASH_ERROR_REPLY = 14 + FLASH_OK_REPLY = 12 + FLASH_ERROR_REPLY = 13 class UnsupportedDevice(Exception): @@ -148,14 +147,11 @@ class CommGeneric: self.write(b"\x00") self.write(value) _, ty = self._read_header() - if ty != _D2HMsgType.FLASH_WRITE_REPLY: + if ty != _D2HMsgType.FLASH_OK_REPLY: if ty == _D2HMsgType.FLASH_ERROR_REPLY: - raise IOError("Invalid key: not a null-terminated string") + raise IOError("Flash storage is full") else: raise IOError("Incorrect reply from device: {}".format(ty)) - ret = self.read(1) - if ret != b"\x01": - raise IOError("Flash storage is full") def flash_storage_erase(self): self._write_header(9, _H2DMsgType.FLASH_ERASE_REQUEST) diff --git a/artiq/test/scheduler.py b/artiq/test/scheduler.py index dd993d516..436f9316a 100644 --- a/artiq/test/scheduler.py +++ b/artiq/test/scheduler.py @@ -1,7 +1,7 @@ import unittest import asyncio import sys -from time import sleep +from time import time, sleep from artiq import * from artiq.master.scheduler import Scheduler @@ -27,11 +27,11 @@ def _get_expid(name): } -def _get_basic_steps(rid, expid): +def _get_basic_steps(rid, expid, priority=0, flush=False): return [ {"action": "setitem", "key": rid, "value": - {"pipeline": "main", "status": "pending", "priority": 0, - "expid": expid, "due_date": None, "flush": False}, + {"pipeline": "main", "status": "pending", "priority": priority, + "expid": expid, "due_date": None, "flush": flush}, "path": []}, {"action": "setitem", "key": "status", "value": "preparing", "path": [rid]}, @@ -59,7 +59,7 @@ class SchedulerCase(unittest.TestCase): scheduler = Scheduler(0, _handlers) expid = _get_expid("EmptyExperiment") - expect = _get_basic_steps(0, expid) + expect = _get_basic_steps(1, expid) done = asyncio.Event() expect_idx = 0 def notify(notifier, mod): @@ -72,8 +72,22 @@ class SchedulerCase(unittest.TestCase): loop = asyncio.get_event_loop() scheduler.start() + + # Verify that a timed experiment far in the future does not + # get run, even if it has high priority. + late = time() + 100000 + expect.insert(0, + {"action": "setitem", "key": 0, "value": + {"pipeline": "main", "status": "pending", "priority": 99, + "expid": expid, "due_date": late, "flush": False}, + "path": []}) + scheduler.submit("main", expid, 99, late, False) + + # This one (RID 1) gets run instead. scheduler.submit("main", expid, 0, None, False) + loop.run_until_complete(done.wait()) + scheduler.notifier.publish = None loop.run_until_complete(scheduler.stop()) def test_pause(self): @@ -106,3 +120,37 @@ class SchedulerCase(unittest.TestCase): scheduler.submit("main", expid, 0, None, False) loop.run_until_complete(done.wait()) loop.run_until_complete(scheduler.stop()) + + def test_flush(self): + scheduler = Scheduler(0, _handlers) + expid = _get_expid("EmptyExperiment") + + expect = _get_basic_steps(1, expid, 1, True) + expect.insert(1, {"key": "status", + "path": [1], + "value": "flushing", + "action": "setitem"}) + first_preparing = asyncio.Event() + done = asyncio.Event() + expect_idx = 0 + def notify(notifier, mod): + nonlocal expect_idx + if mod == {"path": [0], + "value": "preparing", + "key": "status", + "action": "setitem"}: + first_preparing.set() + if mod["path"] == [1] or (mod["path"] == [] and mod["key"] == 1): + self.assertEqual(mod, expect[expect_idx]) + expect_idx += 1 + if expect_idx >= len(expect): + done.set() + scheduler.notifier.publish = notify + + loop = asyncio.get_event_loop() + scheduler.start() + scheduler.submit("main", expid, 0, None, False) + loop.run_until_complete(first_preparing.wait()) + scheduler.submit("main", expid, 1, None, True) + loop.run_until_complete(done.wait()) + loop.run_until_complete(scheduler.stop()) diff --git a/doc/manual/getting_started.rst b/doc/manual/getting_started.rst index eb3166f6c..da2952fd3 100644 --- a/doc/manual/getting_started.rst +++ b/doc/manual/getting_started.rst @@ -1,6 +1,8 @@ Getting started =============== +.. _connecting-to-the-core-device: + Connecting to the core device ----------------------------- diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 92e54b55e..79ef78e66 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -128,7 +128,7 @@ The communication parameters are 115200 8-N-1. * You can either set it by generating a flash storage image and then flash it: :: - $ ~/artiq-dev/artiq/frontend/artiq_mkfs.py flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx + $ artiq_mkfs flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx $ ~/artiq-dev/artiq/frontend/artiq_flash.sh -f flash_storage.img * Or you can set it via the runtime test mode command line @@ -168,6 +168,26 @@ The communication parameters are 115200 8-N-1. .. note:: The reset button of the KC705 board is the "CPU_RST" labeled button. .. warning:: Both those instructions will result in the flash storage being wiped out. However you can use the test mode to change the IP/MAC without erasing everything if you skip the "fserase" command. +* (optional) Flash the ``idle`` kernel + +The ``idle`` kernel is the kernel (some piece of code running on the core device) which the core device runs whenever it is not connected to a PC via ethernet. +This kernel is therefore stored in the :ref:`core device configuration flash storage `. +To flash the ``idle`` kernel: + + * Compile the ``idle`` experiment: + The ``idle`` experiment's ``run()`` method must be a kernel: it must be decorated with the ``@kernel`` decorator (see :ref:`next topic ` for more information about kernels). + + Moreover, since the core device is not connected to the PC: RPC are forbidden in this ``idle`` experiment. + :: + + $ artiq_compile idle.py + + * Write it into the core device configuration flash storage: :: + + $ artiq_coreconfig -f idle_kernel idle.elf + +.. note:: You can find more information about how to use the ``artiq_coreconfig`` tool on the :ref:`Utilities ` page. + Installing the host-side software --------------------------------- @@ -197,31 +217,13 @@ Installing the host-side software .. note:: Compilation of LLVM can take more than 30 min on some machines. -* Install ARTIQ (without the GUI): :: +* Install ARTIQ: :: $ cd ~/artiq-dev $ git clone https://github.com/m-labs/artiq # if not already done $ cd artiq $ python3 setup.py develop --user -* Install ARTIQ (with the GUI): :: - - $ cd ~/artiq-dev - $ git clone https://github.com/m-labs/cairoplot3 - $ cd cairoplot3 - $ python3 setup.py install --user - $ cd - - $ git clone https://github.com/m-labs/gbulb - $ cd gbulb - $ python3 setup.py install --user - $ cd - - $ git clone https://github.com/m-labs/artiq # if not already done - $ cd artiq - $ ARTIQ_GUI=1 python3 setup.py develop --user - -.. note:: - Use ARTIQ_GUI=1 to install GUI dependencies which are only supported on Linux for now, to install ARTIQ on Windows do not set ARTIQ_GUI. - * Build the documentation: :: $ cd ~/artiq-dev/artiq/doc/manual diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index 740fa81b1..027d22470 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -117,12 +117,11 @@ To write the value ``test_value`` in the key ``my_key``:: $ artiq_coreconfig -r my_key b'test_value' -You can also write entire files in a record using the ``-f`` parameter:: +You can also write entire files in a record using the ``-f`` parameter. This is useful for instance to write the ``idle`` kernel in the flash storage:: - $ echo "this_is_a_test" > my_filename - $ artiq_coreconfig -f my_key my_filename - $ artiq_coreconfig -r my_key - b'this_is_a_test\n' + $ artiq_coreconfig -f idle_kernel idle.elf + $ artiq_coreconfig -r idle_kernel | head -c9 + b'\x7fELF You can write several records at once:: diff --git a/soc/runtime/flash_storage.c b/soc/runtime/flash_storage.c index 40f062884..547087fd0 100644 --- a/soc/runtime/flash_storage.c +++ b/soc/runtime/flash_storage.c @@ -284,7 +284,7 @@ unsigned int fs_read(char *key, void *buffer, unsigned int buf_len, unsigned int memcpy(buffer, record.value, min(record.value_len, buf_len)); read_length = min(record.value_len, buf_len); if(remain) - *remain = max(0, (int)(record.value_len) - (int)buf_len); + *remain = max(0, (int)record.value_len - (int)buf_len); } } diff --git a/soc/runtime/session.c b/soc/runtime/session.c index d8852f533..036978bf3 100644 --- a/soc/runtime/session.c +++ b/soc/runtime/session.c @@ -112,7 +112,6 @@ enum { REMOTEMSG_TYPE_RPC_REQUEST, REMOTEMSG_TYPE_FLASH_READ_REPLY, - REMOTEMSG_TYPE_FLASH_WRITE_REPLY, REMOTEMSG_TYPE_FLASH_OK_REPLY, REMOTEMSG_TYPE_FLASH_ERROR_REPLY }; @@ -259,9 +258,11 @@ static int process_input(void) value = key + key_len; ret = fs_write(key, value, value_len); - buffer_out[8] = REMOTEMSG_TYPE_FLASH_WRITE_REPLY; - buffer_out[9] = ret; - submit_output(10); + if(ret) + buffer_out[8] = REMOTEMSG_TYPE_FLASH_OK_REPLY; + else + buffer_out[8] = REMOTEMSG_TYPE_FLASH_ERROR_REPLY; + submit_output(9); break; } case REMOTEMSG_TYPE_FLASH_ERASE_REQUEST: {