Api of the device

device Package

_const Module

_device Module

API fine print

Device state chart

Power management

Note

If your device does not need to power itself up or down, please just ignore power_up() and power_down() methods.

Devices should be powered up when we start call power_up(), but needn`t do so, they must be powered up when after we exit from start(). So there are three methods in which devices should power up:

  • power_up(), this method is called relatively early in during the experiment, and should allow plenty of time to initialize everyhing
  • apply_settings(), use this method if your device powers up quickly.
  • start(), if your device is volatile and you want to minimize the time it is powered up use this.

You can power down the device when following methods are called:

  • power_down()
  • stop()

Threading considerations

Devices are accessed from single thread. All methods sould exit relatively fast, you should not use loops that are infinite (or can be infinite — for example if hardware will not respond).

Change device state

It is quite important to change state of your device after appropriate method calls.

How to test the devices according to the API

There are two ways in which you can test it: start ipython interpreter create device and manage it by hand:

Use DeviceWorkerWrapper from interpreter

Import classes:

>>> from silf.backend.commons_test.device.test_device import *
>>> from silf.backend.commons.device_manager import start_worker_interactive

Start the device:

>>> work = start_worker_interactive('foo', MockDevice,
... configure_logging=False, auto_pull_results=False)

>>> work.state
'off'

>>> work.power_up() 
UUID(...)

Let’s setup the device:

>>> work.apply_settings({"foo": 3, "bar": 2}) 
UUID(...)

>>> work.start() 
UUID(...)

This device will perform own acquisition in separete process, well wait for results to be acquired:

>>> time.sleep(1.2)

First pop_results() will return stale data, and schedule acquisition of new data:

>>> work.state
'running'
>>> work.pop_results() == []
True

Wait for results to get processed (will be faster on server!)

>>> time.sleep(0.5)
>>> results = work.pop_results()
>>> results == [{'foo_result': 3, 'bar_result': 2}]
True

Kill it without waiting;

>>> work.kill(wait_time=None)

Auto result pooling

You can configure this to auto poll for results:

>>> work = start_worker_interactive('foo', MockDevice,
... configure_logging=False, auto_pull_results=True)


>>> work.power_up() 
UUID(...)

As in last test:

>>> work.apply_settings({"foo": 3, "bar": 2}) 
UUID(...)
>>> work.start() 
UUID(...)

Wait for results to be gathered

>>> time.sleep(2)

Notice that results are avilable at once (no need to query)

>>> results = work.pop_results()
>>> results == [{'foo_result': 3, 'bar_result': 2}]
True

>>> work.kill(wait_time=None)
>>> results == [{'foo_result': 3, 'bar_result': 2}]
True

>>> work.kill(wait_time=None)

Device Api examples

This is pseudocode

Engine driver

This imaginary device implements an engine. This is not actual experiment code, sxperiment will not be doing any waiting!

engine = ImaginaryDriver()

assert engine.state == 'off'

engine.power_up() # Powers up the device

assert engine.state == 'stand-by'

engine.apply_settings({"position" : 512})

assert engine.state == 'ready'

engine.start() # Start the engine

assert engine.state == 'acquiring'

# Silnik ruszył i teraz jest w stanie `acquiring`

# .. wait

while engine.state != 'ready':
    time.sleep(0.1)

# Silnik doszedł do końca i jest w stanie `ready`

# Następny pukt

engine.apply_settings({"position" : 1024})

engine.start() # Start the engine

Engine driver

Imaginary voltimeter

volt = ImaginaryVoltimeter()

assert volt.state == 'off'

volt.power_up() # Powers up the device

assert volt.state == 'stand-by'

volt.apply_settings({'range' : 15})

assert volt.state == 'ready'

volt.start() # Start the volt

assert volt.state == 'acquiring'

while volt.state != 'ready':
    time.sleep(0.1)

assert volt.pop_results() == [{'voltage' : 243.11}]

Engine and voltimeter connected

It works that so voltimeter measures single point after position is set by the engine.

engine = ImaginaryDriver()
volt = ImaginaryVoltimeter()

engine.power_up() # Powers up the device
volt.power_up() # Powers up the device

engine.apply_settings({"position" : 512})

engine.start();

while engine.state != 'ready':
    time.sleep(0.1)

volt.apply_settings({'range' : 15})

volt.start() # Start the volt

while volt.state != 'ready':
    time.sleep(0.1)

assert volt.pop_results() == [{'voltage' : 243.11}]

engine.apply_settings({"position" : 1024})

engine.start();

while engine.state != 'ready':
    time.sleep(0.1)

while volt.state != 'ready':
    time.sleep(0.1)

assert volt.pop_results() == [{'voltage' : 123.123}]