class TestSiamCiAdapterProxyAsync(SiamCiTestCase): @defer.inlineCallbacks def setUp(self): yield self._start_container(sysname="siamci") self.siamci = SiamCiAdapterProxy(SiamCiTestCase.pid, SiamCiTestCase.port) yield self.siamci.start() self.receiver_client = yield self._start_receiver_service( receiver_service_name) @defer.inlineCallbacks def tearDown(self): yield self.siamci.stop() yield self._stop_container() @defer.inlineCallbacks def test_list_ports_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "list_ports;" # prepare to receive result: yield self.receiver_client.expect(publish_id) # make request: ret = yield self.siamci.list_ports(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_get_status_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "get_status;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) # make request: ret = yield self.siamci.get_status(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_get_last_sample_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "get_last_sample;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) # make request: ret = yield self.siamci.get_last_sample(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_get_channels_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "get_channels;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) # make request: ret = yield self.siamci.get_channels(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_fetch_params_some_good_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "fetch_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.fetch_params(['startDelayMsec'], publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_fetch_params_some_wrong_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "fetch_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.fetch_params(['startDelayMsec', 'WRONG_PARAM'], publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # NOTE the immediate reply should be OK ... # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # ... but the actual response should indicate ERROR: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, ERROR) @defer.inlineCallbacks def test_fetch_params_all_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "fetch_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.fetch_params(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_set_params_good_async_timeout_30(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "set_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.set_params({'startDelayMsec': '1000'}, publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected(timeout=30) self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_set_params_wrong_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "set_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.set_params( { 'startDelayMsec': '1000', 'WRONG_PARAM': 'fooVal' }, publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate ERROR: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, ERROR)
class TestSiamCiAdapterProxyAsync(SiamCiTestCase): @defer.inlineCallbacks def setUp(self): yield self._start_container(sysname="siamci") self.siamci = SiamCiAdapterProxy(SiamCiTestCase.pid, SiamCiTestCase.port) yield self.siamci.start() self.receiver_client = yield self._start_receiver_service(receiver_service_name) @defer.inlineCallbacks def tearDown(self): yield self.siamci.stop() yield self._stop_container() @defer.inlineCallbacks def test_list_ports_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "list_ports;" # prepare to receive result: yield self.receiver_client.expect(publish_id) # make request: ret = yield self.siamci.list_ports(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_get_status_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "get_status;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) # make request: ret = yield self.siamci.get_status(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_get_last_sample_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "get_last_sample;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) # make request: ret = yield self.siamci.get_last_sample(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_get_channels_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "get_channels;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) # make request: ret = yield self.siamci.get_channels(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_fetch_params_some_good_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "fetch_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.fetch_params(["startDelayMsec"], publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_fetch_params_some_wrong_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "fetch_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.fetch_params( ["startDelayMsec", "WRONG_PARAM"], publish_stream="siamci." + receiver_service_name ) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # NOTE the immediate reply should be OK ... # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # ... but the actual response should indicate ERROR: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, ERROR) @defer.inlineCallbacks def test_fetch_params_all_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "fetch_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.fetch_params(publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_set_params_good_async_timeout_30(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "set_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.set_params({"startDelayMsec": "1000"}, publish_stream="siamci." + receiver_service_name) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected(timeout=30) self.assertEquals(len(expected), 0) # actual response should indicate OK: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, OK) @defer.inlineCallbacks def test_set_params_wrong_async(self): self._check_skip() # # @todo: more robust assignment of publish IDs # publish_id = "set_params;port=" + SiamCiTestCase.port # prepare to receive result: yield self.receiver_client.expect(publish_id) ret = yield self.siamci.set_params( {"startDelayMsec": "1000", "WRONG_PARAM": "fooVal"}, publish_stream="siamci." + receiver_service_name ) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) # check that all expected were received expected = yield self.receiver_client.getExpected() self.assertEquals(len(expected), 0) # actual response should indicate ERROR: response = yield self.receiver_client.getAccepted(publish_id) self.assertIsSuccessFail(response) self.assertEquals(response.result, ERROR)
class TestSiamCiAdapterProxy(SiamCiTestCase): @defer.inlineCallbacks def setUp(self): yield self._start_container() self.siamci = SiamCiAdapterProxy(SiamCiTestCase.pid, SiamCiTestCase.port) yield self.siamci.start() @defer.inlineCallbacks def tearDown(self): yield self.siamci.stop() yield self._stop_container() @defer.inlineCallbacks def test_ping(self): self._check_skip() ret = yield self.siamci.ping() self.assertTrue(ret) @defer.inlineCallbacks def test_list_ports(self): self._check_skip() ret = yield self.siamci.list_ports() self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_get_channels(self): self._check_skip() ret = yield self.siamci.get_channels() self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_get_status(self): self._check_skip() ret = yield self.siamci.get_status() @defer.inlineCallbacks def test_get_last_sample(self): self._check_skip() ret = yield self.siamci.get_last_sample() self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_fetch_params_some_good(self): """fetch specific list of parameters""" self._check_skip() ret = yield self.siamci.fetch_params(['startDelayMsec']) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_fetch_params_some_wrong(self): """fetch specific list of parameters""" self._check_skip() ret = yield self.siamci.fetch_params(['startDelayMsec', 'WRONG_PARAM']) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, ERROR) @defer.inlineCallbacks def test_fetch_params_all(self): """fetch all parameters""" self._check_skip() ret = yield self.siamci.fetch_params() self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_set_params_good(self): self._check_skip() ret = yield self.siamci.set_params({'startDelayMsec': '1000'}) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_set_params_wrong(self): self._check_skip() ret = yield self.siamci.set_params({ 'startDelayMsec': '1000', 'WRONG_PARAM': 'fooVal' }) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, ERROR)
class TestSiamCiAdapterProxy(SiamCiTestCase): @defer.inlineCallbacks def setUp(self): yield self._start_container() self.siamci = SiamCiAdapterProxy(SiamCiTestCase.pid, SiamCiTestCase.port) yield self.siamci.start() @defer.inlineCallbacks def tearDown(self): yield self.siamci.stop() yield self._stop_container() @defer.inlineCallbacks def test_ping(self): self._check_skip() ret = yield self.siamci.ping() self.assertTrue(ret) @defer.inlineCallbacks def test_list_ports(self): self._check_skip() ret = yield self.siamci.list_ports() self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_get_channels(self): self._check_skip() ret = yield self.siamci.get_channels() self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_get_status(self): self._check_skip() ret = yield self.siamci.get_status() @defer.inlineCallbacks def test_get_last_sample(self): self._check_skip() ret = yield self.siamci.get_last_sample() self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_fetch_params_some_good(self): """fetch specific list of parameters""" self._check_skip() ret = yield self.siamci.fetch_params(['startDelayMsec']) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_fetch_params_some_wrong(self): """fetch specific list of parameters""" self._check_skip() ret = yield self.siamci.fetch_params(['startDelayMsec', 'WRONG_PARAM']) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, ERROR) @defer.inlineCallbacks def test_fetch_params_all(self): """fetch all parameters""" self._check_skip() ret = yield self.siamci.fetch_params() self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_set_params_good(self): self._check_skip() ret = yield self.siamci.set_params({'startDelayMsec' : '1000' }) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, OK) @defer.inlineCallbacks def test_set_params_wrong(self): self._check_skip() ret = yield self.siamci.set_params({'startDelayMsec' : '1000' , 'WRONG_PARAM' : 'fooVal' }) self.assertIsSuccessFail(ret) self.assertEquals(ret.result, ERROR)
class SiamInstrumentDriver(InstrumentDriver): """ Instrument driver interface to a SIAM enabled instrument. Main operations are supported by the core class SiamCiAdapterProxy. """ def __init__(self, *args, **kwargs): """ Creates an instance of the driver. This instance will be initially unconfigured (ie., with no specific instrument associated) until the configure operation is called and completed. """ InstrumentDriver.__init__(self, *args, **kwargs) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("\nSiamDriver __init__: spawn_args = " + str(self.spawn_args)) """ A flag indicating whether notifications to self.proc_supid should be sent when entering states. It is assigned the value returned by self.spawn_args.get('notify_agent', False). @NOTE: This is to avoid "ERROR:Process does not define op=driver_event_occurred" messages when self.proc_supid does not correspond to an instrument agent. There might be a more appropriate way to accomplish this behavior. I'm using this mechanism in test_siam_agent.py to include the corresponding spawn arg. """ self.notify_agent = self.spawn_args.get('notify_agent', False) """ Used to connect to the SIAM-CI adapter service. More specifically, this is the routing key (queue) where the SIAM-CI adapter service (java) is listening for requests. """ self.pid = None """ Instrument port. A concrete instrument in the SIAM node is identified by its corresponding port. """ self.port = None """ Will be a SiamCiAdapterProxy(pid, port) instance upon configuration """ self.siamci = None """ Used in certain operations to enable handling of notifications from the SIAM-CI adapter service in lieu of InstrumentAgent """ self.publish_stream = None """ Instrument state handlers. Note, I have followed SBE37_driver to some extent here but this is very preliminary in general. """ self.state_handlers = { SiamDriverState.UNCONFIGURED: self.state_handler_unconfigured, SiamDriverState.DISCONNECTED: self.state_handler_disconnected, SiamDriverState.CONNECTING: self.state_handler_connecting, SiamDriverState.DISCONNECTING: self.state_handler_disconnecting, SiamDriverState.CONNECTED: self.state_handler_connected, # SiamDriverState.ACQUIRE_SAMPLE : self.state_handler_acquire_sample, # SiamDriverState.UPDATE_PARAMS : self.state_handler_update_params, # SiamDriverState.SET : self.state_handler_set, # SiamDriverState.AUTOSAMPLE : self.state_handler_autosample } """ Instrument state machine. """ self.fsm = InstrumentFSM(SiamDriverState, SiamDriverEvent, self.state_handlers, SiamDriverEvent.ENTER, SiamDriverEvent.EXIT) ########################################################################### # <state handlers> def state_handler_unconfigured(self, event, params): """ Event handler for STATE_UNCONFIGURED. Events handled: EVENT_ENTER: Reset communication parameters to null values. EVENT_EXIT: Pass. EVENT_CONFIGURE: Set communication parameters and switch to STATE_DISCONNECTED if successful. EVENT_INITIALIZE: Reset communication parameters to null values. """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug("state_handler_unconfigured: event = " + str(event) + "\n\t\t params = " + str(params)) success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = { 'type': SiamDriverAnnouncement.STATE_CHANGE, 'transducer': SiamDriverChannel.INSTRUMENT, 'value': SiamDriverState.UNCONFIGURED } self.send(self.proc_supid, 'driver_event_occurred', content) self._initialize() elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.INITIALIZE: self._initialize() elif event == SiamDriverEvent.CONFIGURE: if self._configure(params): next_state = SiamDriverState.DISCONNECTED else: success = InstErrorCode.INCORRECT_STATE return (success, next_state) def state_handler_disconnected(self, event, params): """ Event handler for STATE_DISCONNECTED. Events handled: EVENT_ENTER: Pass. EVENT_EXIT: Pass. EVENT_INITIALIZE: Switch to STATE_UNCONFIGURED. EVENT_CONNECT: Switch to STATE_CONNECTING. """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug("state_handler_disconnected: event = " + str(event) + "\n\t\t params = " + str(params)) success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = { 'type': SiamDriverAnnouncement.STATE_CHANGE, 'transducer': SiamDriverChannel.INSTRUMENT, 'value': SiamDriverState.DISCONNECTED } self.send(self.proc_supid, 'driver_event_occurred', content) elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.INITIALIZE: next_state = SiamDriverState.UNCONFIGURED elif event == SiamDriverEvent.CONNECT: next_state = SiamDriverState.CONNECTING # not in sbe37 elif event == SiamDriverEvent.DISCONNECT_COMPLETE: pass else: success = InstErrorCode.INCORRECT_STATE return (success, next_state) def state_handler_connecting(self, event, params): """ Event handler for STATE_CONNECTING. Events handled: EVENT_ENTER: Attemmpt to establish connection. EVENT_EXIT: Pass. EVENT_CONNECTION_COMPLETE: Switch to SiamDriverState.CONNECTED (STATE_UPDATE_PARAMS in SBE37) EVENT_CONNECTION_FAILED: Switch to STATE_DISCONNECTED. """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug("state_handler_connecting: event = " + str(event) + "\n\t\t params = " + str(params)) success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = { 'type': SiamDriverAnnouncement.STATE_CHANGE, 'transducer': SiamDriverChannel.INSTRUMENT, 'value': SiamDriverState.CONNECTING } self.send(self.proc_supid, 'driver_event_occurred', content) elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.CONNECTION_COMPLETE: # next_state = SiamDriverState.UPDATE_PARAMS next_state = SiamDriverState.CONNECTED elif event == SiamDriverEvent.CONNECTION_FAILED: # Error message to agent here. next_state = SiamDriverState.DISCONNECTED else: success = InstErrorCode.INCORRECT_STATE return (success, next_state) def state_handler_connected(self, event, params): """ Event handler for STATE_CONNECTED. EVENT_ENTER: Notifies agent if instructed so CONNECTION_COMPLETE: pass EVENT_EXIT: Pass. EVENT_DISCONNECT: Switch to STATE_DISCONNECTING. EVENT_COMMAND_RECEIVED: If a command is queued, switch to command specific state for handling. EVENT_DATA_RECEIVED: Pass. """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug("state_handler_connected: event = " + str(event) + "\n\t\t params = " + str(params)) success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = { 'type': SiamDriverAnnouncement.STATE_CHANGE, 'transducer': SiamDriverChannel.INSTRUMENT, 'value': SiamDriverState.CONNECTED } self.send(self.proc_supid, 'driver_event_occurred', content) elif event == SiamDriverEvent.CONNECTION_COMPLETE: pass elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.DISCONNECT: next_state = SiamDriverState.DISCONNECTING elif event == SiamDriverEvent.SET: next_state = SiamDriverState.SET elif event == SiamDriverEvent.ACQUIRE_SAMPLE: next_state = SiamDriverState.ACQUIRE_SAMPLE elif event == SiamDriverEvent.START_AUTOSAMPLE: next_state = SiamDriverState.AUTOSAMPLE elif event == SiamDriverEvent.TEST: next_state = SiamDriverState.TEST elif event == SiamDriverEvent.CALIBRATE: next_state = SiamDriverState.CALIBRATE elif event == SiamDriverEvent.RESET: next_state = SiamDriverState.RESET elif event == SiamDriverEvent.DATA_RECEIVED: pass else: success = InstErrorCode.INCORRECT_STATE return (success, next_state) def state_handler_disconnecting(self, event, params): """ Event handler for STATE_DISCONNECTING. Events handled: EVENT_ENTER: Attempt to close connection to instrument. EVENT_EXIT: Pass. EVENT_DISCONNECT_COMPLETE: Switch to STATE_DISCONNECTED. """ success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = { 'type': SiamDriverAnnouncement.STATE_CHANGE, 'transducer': SiamDriverChannel.INSTRUMENT, 'value': SiamDriverState.DISCONNECTED } self.send(self.proc_supid, 'driver_event_occurred', content) elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.DISCONNECT_COMPLETE: next_state = SiamDriverState.DISCONNECTED else: success = InstErrorCode.INCORRECT_STATE return (success, next_state) # </state handlers> ########################################################################### def _initialize(self): """ Set the configuration to an initialized, unconfigured state. """ self.pid = None self.port = None ########################################################################### # <Process lifecycle methods> @defer.inlineCallbacks def plc_init(self): """ Process lifecycle initialization. """ yield # Set initial state. self.fsm.start(SiamDriverState.UNCONFIGURED) log.debug("SiamDriver plc_init: FSM started with state UNCONFIGURED") @defer.inlineCallbacks def plc_terminate(self): log.debug("SiamDriver plc_terminate") """ Process lifecycle termination. """ yield # </Process lifecycle methods> ########################################################################### @defer.inlineCallbacks def op_get_state(self, content, headers, msg): cur_state = self.fsm.current_state yield self.reply_ok(msg, cur_state) @defer.inlineCallbacks def op_initialize(self, content, headers, msg): """ Restore driver to a default, unconfigured state. @param content A dict with optional timeout: {'timeout':timeout}. @retval A reply message with a dict {'success':success,'result':None}. """ # Timeout not implemented for this op. timeout = content.get('timeout', None) if timeout != None: assert (isinstance(timeout, int)), 'Expected integer timeout' assert (timeout > 0), 'Expected positive timeout' pass # Set up the reply and fire an EVENT_INITIALIZE. reply = {'success': None, 'result': None} success = self.fsm.on_event(SiamDriverEvent.INITIALIZE) # Set success and send reply. Unsuccessful initialize means the # event is not handled in the current state. if not success: reply['success'] = InstErrorCode.INCORRECT_STATE else: reply['success'] = InstErrorCode.OK yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_configure(self, content, headers, msg): assert (isinstance(content, dict)), 'Expected dict content.' params = content.get('params', None) assert (isinstance(params, dict)), 'Expected dict params.' # Timeout not implemented for this op. timeout = content.get('timeout', None) if timeout != None: assert (isinstance(timeout, int)), 'Expected integer timeout' assert (timeout > 0), 'Expected positive timeout' pass # Set up the reply message and validate the configuration parameters. # Reply with the error message if the parameters not valid. reply = {'success': None, 'result': params} reply['success'] = self._validate_configuration(params) if InstErrorCode.is_error(reply['success']): yield self.reply_ok(msg, reply) return # Fire EVENT_CONFIGURE with the validated configuration parameters. # Set the error message if the event is not handled in the current # state. reply['success'] = self.fsm.on_event(SiamDriverEvent.CONFIGURE, params) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('op_configure: complete. success = %s' % (reply['success'])) yield self.reply_ok(msg, reply) def _configure(self, params): # Validate configuration. success = self._validate_configuration(params) if InstErrorCode.is_error(success): return False # Set configuration parameters. self.pid = params['pid'] self.port = params['port'] if log.getEffectiveLevel() <= logging.DEBUG: log.debug("_configure: pid = '" + \ str(self.pid) + "' port = '" + str(self.port) + "'") self.siamci = SiamCiAdapterProxy(self.pid, self.port) return True def _validate_configuration(self, params): # Get required parameters. pid = params.get('pid', None) port = params.get('port', None) # fail if missing a required parameter. if not pid or not port: return InstErrorCode.REQUIRED_PARAMETER return InstErrorCode.OK @defer.inlineCallbacks def op_connect(self, content, headers, msg): # Timeout not implemented for this op. timeout = content.get('timeout', None) if timeout != None: assert (isinstance(timeout, int)), 'Expected integer timeout' assert (timeout > 0), 'Expected positive timeout' pass success = self.fsm.on_event(SiamDriverEvent.CONNECT) reply = {'success': success, 'result': None} if InstErrorCode.is_error(reply['success']): yield self.reply_ok(msg, reply) return success = self.fsm.on_event(SiamDriverEvent.CONNECTION_COMPLETE) reply['success'] = success """ There is no actual "connect"/"disconnect" as the driver interacts via messaging with the SIAM-CI adapter service. We just start our proxy: """ yield self.siamci.start() if log.getEffectiveLevel() <= logging.DEBUG: log.debug('op_connect: SiamCiProxy started') yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_disconnect(self, content, headers, msg): # Timeout not implemented for this op. timeout = content.get('timeout', None) if timeout != None: assert (isinstance(timeout, int)), 'Expected integer timeout' assert (timeout > 0), 'Expected positive timeout' pass success = self.fsm.on_event(SiamDriverEvent.DISCONNECT) reply = {'success': success, 'result': None} if InstErrorCode.is_error(reply['success']): yield self.reply_ok(msg, reply) return success = self.fsm.on_event(SiamDriverEvent.DISCONNECT_COMPLETE) reply['success'] = success """ @TODO: why calling ''yield self.siamci.stop()'' to stop (terminate) the SiamCiProxy process causes errors? Here are some of the errors if this call is included when running test_siam_driver.py: [process :780] WARNING:Process bootstrap RPC conv-id=carueda_46740.7#29 timed out! [state_object :113] ERROR:ERROR in StateObject process(event=deactivate) [receiver :169] ERROR:Receiver error: Illegal state change [state_object :132] ERROR:Subsequent ERROR in StateObject error(), ND-ND """ # yield self.siamci.stop() if log.getEffectiveLevel() <= logging.DEBUG: log.debug('op_disconnect: complete. success = %s' % (reply['success'])) yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_get_status(self, content, headers, msg): log.debug('In SiamDriver op_get_status') assert (isinstance(content, dict)), 'Expected dict content.' params = content.get('params', None) """ For 'params', how is that a list, eg., [('all','all)], passed from the client gets converted to a tuple here, eg., (('all', 'all'),) ? """ assert(isinstance(params,(list,tuple))), \ 'Expected list or tuple params in op_get_status' assert(all(map(lambda x:isinstance(x,tuple),params))), \ 'Expected tuple elements in params list' # Timeout not implemented for this op. timeout = content.get('timeout', None) if timeout != None: assert (isinstance(timeout, int)), 'Expected integer timeout' assert (timeout > 0), 'Expected positive timeout' pass # @todo: Do something with the new possible argument 'timeout' response = yield self.siamci.get_status(params=params) result = response.result reply = {'success': InstErrorCode.OK, 'result': result} yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_get(self, content, headers, msg): assert (isinstance(content, dict)), 'Expected dict content.' params = content.get('params', None) assert (isinstance(params, (list, tuple))), 'Expected list or tuple params.' # Timeout not implemented for this op. timeout = content.get('timeout', None) if timeout != None: assert (isinstance(timeout, int)), 'Expected integer timeout' assert (timeout > 0), 'Expected positive timeout' pass if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver op_get: params = ' +\ str(params)+ " publish_stream=" +str(self.publish_stream)) if self.publish_stream is None: successFail = yield self.siamci.fetch_params(params) else: successFail = yield self.siamci.fetch_params( params, publish_stream=self.publish_stream) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver op_get successFail --> ' + str(successFail)) # initialize reply assuming OK reply = {'success': InstErrorCode.OK, 'result': None} if successFail.result != OK: reply['success'] = InstErrorCode.GET_DEVICE_ERR yield self.reply_ok(msg, reply) return result = {} for it in successFail.item: # logging does not have a TRACE level! # if log.getEffectiveLevel() <= logging.TRACE: # log.trace('In SiamDriver op_get item --> ' + str(it)) chName = it.pair.first value = it.pair.second key = (SiamDriverChannel.INSTRUMENT, chName) result[key] = (InstErrorCode.OK, value) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver op_get result --> ' + str(result)) reply['result'] = result yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_set(self, content, headers, msg): log.debug('In SiamDriver op_set') assert (isinstance(content, dict)), 'Expected dict content.' # # params should be of the form: # {(chan_arg,param_arg):value,...,(chan_arg,param_arg):value} # params = content.get('params', None) assert (isinstance(params, dict)), 'Expected dict params.' assert (all(map(lambda x: isinstance(x, (list, tuple)), params.keys()))), 'Expected list or tuple dict keys.' assert (all(map(lambda x: isinstance(x, str), params.values()))), 'Expected string dict values.' # Timeout not implemented for this op. timeout = content.get('timeout', None) if timeout != None: assert (isinstance(timeout, int)), 'Expected integer timeout' assert (timeout > 0), 'Expected positive timeout' pass reply = {'success': None, 'result': None} # # TODO accept the format of the params as indicated above. For the # moment, we convert the input: # {(chan_arg,param_arg):value,...,(chan_arg,param_arg):value} # into # {param_arg:value,..., param_arg:value} # while checking that all chan_arg in the input are equal to # SiamDriverChannel.INSTRUMENT. params_for_proxy = {} for (chan, param) in params.keys(): if SiamDriverChannel.INSTRUMENT != chan: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Only " +str(SiamDriverChannel.INSTRUMENT) + \ " accepted for channel; given: " + chan reply['result'] = errmsg log.warning("op_set: " + errmsg) yield self.reply_ok(msg, reply) return val = params[(chan, param)] params_for_proxy[param] = val if log.getEffectiveLevel() <= logging.DEBUG: log.debug("params_for_proxy = " + str(params_for_proxy) + \ " **** siamci = " + str(self.siamci)) response = yield self.siamci.set_params(params_for_proxy) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver op_set_params --> ' + str(response)) if response.result == OK: reply['success'] = InstErrorCode.OK reply['result'] = params_for_proxy # just informative else: reply['success'] = InstErrorCode.SET_DEVICE_ERR yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_set_publish_stream(self, content, headers, msg): self.publish_stream = content.get('publish_stream', None) reply = {'success': InstErrorCode.OK, 'result': self.publish_stream} if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_set_publish_stream = " + str(self.publish_stream)) yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_execute(self, content, headers, msg): """ Execute a driver command. Commands may be common or specific to the device, with specific commands known through knowledge of the device or a previous get_capabilities query. @param content A dict with channels and command lists and optional timeout: {'channels':[chan_arg,...,chan_arg], 'command':[command,arg,...,argN]), 'timeout':timeout}. @retval A reply message with a dict {'success':success, 'result':{chan_arg:(success,command_specific_values),..., chan_arg:(success,command_specific_values)}}. """ assert (isinstance(content, dict)), 'Expected dict content.' # Set up reply dict, get required parameters from message content. reply = {'success': None, 'result': None} command = content.get('command', None) channels = content.get('channels', None) timeout = content.get('timeout', None) # Fail if required parameters absent. if not command: reply['success'] = InstErrorCode.REQUIRED_PARAMETER yield self.reply_ok(msg, reply) return if not channels: reply['success'] = InstErrorCode.REQUIRED_PARAMETER yield self.reply_ok(msg, reply) return assert (isinstance(command, (list, tuple))) assert (all(map(lambda x: isinstance(x, str), command))) assert (isinstance(channels, (list, tuple))) assert (all(map(lambda x: isinstance(x, str), channels))) if timeout != None: assert (isinstance(timeout, int)), 'Expected integer timeout' assert (timeout > 0), 'Expected positive timeout' pass # Fail if command or channels not valid for siam driver. if not SiamDriverCommand.has(command[0]): reply['success'] = InstErrorCode.UNKNOWN_COMMAND yield self.reply_ok(msg, reply) return # get the actual instrument channels: successFail = yield self.siamci.get_channels() if successFail.result != OK: reply['success'] = InstErrorCode.EXE_DEVICE_ERR errmsg = "Error retrieving channels" reply['result'] = errmsg log.warning("op_execute: " + errmsg) yield self.reply_ok(msg, reply) return instrument_channels = [it.str for it in successFail.item] # # NOTE: special channel name SiamDriverChannel.INSTRUMENT only # accepted in a singleton channels list. # if len(channels) == 0 or (len(channels) == 1 and SiamDriverChannel.INSTRUMENT == channels[0]): # ok, this means all channels for various operations. pass else: # verify the explicit requested channels are valid for chan in channels: if SiamDriverChannel.INSTRUMENT == chan: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Can only use '" + \ str(SiamDriverChannel.INSTRUMENT) + \ "' for a singleton channels list" reply['result'] = errmsg log.warning("op_execute: " + errmsg) yield self.reply_ok(msg, reply) return if not chan in instrument_channels: reply['success'] = InstErrorCode.UNKNOWN_CHANNEL errmsg = "instrument does not have channel named '" + str( chan) + "'" reply['result'] = errmsg log.warning("op_execute: " + errmsg) yield self.reply_ok(msg, reply) return drv_cmd = command[0] ############################# # dispatch the given command: ############################# # GET_CHANNELS ############################################## if drv_cmd == SiamDriverCommand.GET_CHANNELS: # # we already have the channels from the general preparation above # reply['success'] = InstErrorCode.OK reply['result'] = instrument_channels if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute GET_CHANNELS to reply: " + str(reply)) yield self.reply_ok(msg, reply) return # GET_LAST_SAMPLE ############################################## if drv_cmd == SiamDriverCommand.GET_LAST_SAMPLE: yield self.__get_last_sample(channels, reply) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute GET_LAST_SAMPLE to reply: " + str(reply)) yield self.reply_ok(msg, reply) return # START_AUTO_SAMPLING ############################################## if drv_cmd == SiamDriverCommand.START_AUTO_SAMPLING: yield self.__start_sampling(channels, reply) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute START_AUTO_SAMPLING to reply: " + str(reply)) yield self.reply_ok(msg, reply) return # STOP_AUTO_SAMPLING ############################################## if drv_cmd == SiamDriverCommand.STOP_AUTO_SAMPLING: yield self.__stop_sampling(channels, reply) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute STOP_AUTO_SAMPLING to reply: " + str(reply)) yield self.reply_ok(msg, reply) return # # Else: INVALID_COMMAND # reply['success'] = InstErrorCode.INVALID_COMMAND if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute INVALID_COMMAND to reply: " + str(reply)) yield self.reply_ok(msg, reply) return @defer.inlineCallbacks def __get_last_sample(self, channels, reply): log.debug('In SiamDriver __get_last_sample') response = yield self.siamci.get_last_sample() if response.result != OK: # TODO: some more appropriate error code reply['success'] = InstErrorCode.EXE_DEVICE_ERR return result = {} for it in response.item: ch = it.pair.first val = it.pair.second result[ch] = val reply['success'] = InstErrorCode.OK reply['result'] = result @defer.inlineCallbacks def __start_sampling(self, channels, reply): """ If successful, reply['success'] = InstErrorCode.OK reply['result'] = {'channel':channel, 'publish_stream':self.publish_stream } where channel is the channel in the singleton channels list """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug('__start_sampling channels = ' +str(channels) + \ " notify_agent = " + str(self.notify_agent) + \ " publish_stream = " + str(self.publish_stream)) if len(channels) != 1: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Can only be one channel for the START_AUTO_SAMPLING operation" reply['result'] = errmsg log.warning("__start_sampling: " + errmsg) return # the actual channel we will be sampling on channel = channels[0] if SiamDriverChannel.INSTRUMENT == channel: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Has to be a specific channel, not '" + \ str(SiamDriverChannel.INSTRUMENT) + "'" reply['result'] = errmsg log.warning("__start_sampling: " + errmsg) return # # either publish_stream is given OR notify_agent is True, with # publish_stream having precedence just because this was the first # implemented functionality (but in general, not both properties # would be indicated at the same time). # if self.publish_stream is not None: response = yield self.siamci.execute_StartAcquisition( channel, self.publish_stream) if response.result != OK: log.warning("execute_StartAcquisition failed: " + str(response)) # TODO: some more appropriate error code reply['success'] = InstErrorCode.EXE_DEVICE_ERR return reply['success'] = InstErrorCode.OK reply['result'] = { 'channel': channel, 'publish_stream': self.publish_stream } return # # if we are interacting with an Instrument Agent, we need to notify it # whenever we get data from the instrument. # if self.notify_agent: """ @TODO: implement. This could probably be done as follows: use a customized receiver service; set the publish_stream accordingly; and call self.siamci.execute_StartAcquisition(channel, publish_stream) as above. The customized receiver would send the notifications to the agent. Alternatively, do the execute_StartAcquisition thing as above but providing more information such that the java side does the notifications directly to the agent (however, by looking at instrument_agent.py, seems like the operation (op_publish in this case, I think) requires the sender to be a child process, which wouldn't be the case for the external SIAM-CI adapter service...) """ reply['success'] = InstErrorCode.NOT_IMPLEMENTED errmsg = "Notification of data to the agent not implemented yet" reply['result'] = errmsg log.warning("__start_sampling: " + errmsg) return # TODO: perhaps a more appropriate error code for this situation reply['success'] = InstErrorCode.EXE_DEVICE_ERR errmsg = "associated agent or publish_stream required for this operation" reply['result'] = errmsg log.warning("__start_sampling: " + errmsg) @defer.inlineCallbacks def __stop_sampling(self, channels, reply): """ Request to stop sampling """ if len(channels) != 1: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Can only be one channel for the START_AUTO_SAMPLING operation" reply['result'] = errmsg log.warning("__stop_sampling: " + errmsg) return # the actual channel we will be sampling on channel = channels[0] if SiamDriverChannel.INSTRUMENT == channel: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Has to be a specific channel, not '" + \ str(SiamDriverChannel.INSTRUMENT) + "'" reply['result'] = errmsg log.warning("__stop_sampling: " + errmsg) return # # either publish_stream is given OR notify_agent is True, with # publish_stream having precedence just because this was the first # implemented functionality (but in general, not both properties # would be indicated at the same time). # if self.publish_stream is not None: response = yield self.siamci.execute_StopAcquisition( channel, self.publish_stream) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver __stop_sampling --> ' + str(response)) if response.result != OK: # TODO: some more appropriate error code reply['success'] = InstErrorCode.EXE_DEVICE_ERR return reply['success'] = InstErrorCode.OK reply['result'] = { 'channel': channel, 'publish_stream': self.publish_stream } return # # if we are interacting with an Instrument Agent, we need to notify it # that data acqusition is to stop. # if self.notify_agent: """ @TODO: implement. See __start_sampling. """ reply['success'] = InstErrorCode.NOT_IMPLEMENTED errmsg = "Notification of data to the agent not implemented yet" reply['result'] = errmsg log.warning("__stop_sampling: " + errmsg) return # TODO: perhaps a more appropriate error code for this situation reply['success'] = InstErrorCode.EXE_DEVICE_ERR errmsg = "associated agent or publish_stream required for this operation" reply['result'] = errmsg log.warning("__stop_sampling: " + errmsg)
class SiamInstrumentDriver(InstrumentDriver): """ Instrument driver interface to a SIAM enabled instrument. Main operations are supported by the core class SiamCiAdapterProxy. """ def __init__(self, *args, **kwargs): """ Creates an instance of the driver. This instance will be initially unconfigured (ie., with no specific instrument associated) until the configure operation is called and completed. """ InstrumentDriver.__init__(self, *args, **kwargs) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("\nSiamDriver __init__: spawn_args = " +str(self.spawn_args)) """ A flag indicating whether notifications to self.proc_supid should be sent when entering states. It is assigned the value returned by self.spawn_args.get('notify_agent', False). @NOTE: This is to avoid "ERROR:Process does not define op=driver_event_occurred" messages when self.proc_supid does not correspond to an instrument agent. There might be a more appropriate way to accomplish this behavior. I'm using this mechanism in test_siam_agent.py to include the corresponding spawn arg. """ self.notify_agent = self.spawn_args.get('notify_agent', False) """ Used to connect to the SIAM-CI adapter service. More specifically, this is the routing key (queue) where the SIAM-CI adapter service (java) is listening for requests. """ self.pid = None """ Instrument port. A concrete instrument in the SIAM node is identified by its corresponding port. """ self.port = None """ Will be a SiamCiAdapterProxy(pid, port) instance upon configuration """ self.siamci = None """ Used in certain operations to enable handling of notifications from the SIAM-CI adapter service in lieu of InstrumentAgent """ self.publish_stream = None """ Instrument state handlers. Note, I have followed SBE37_driver to some extent here but this is very preliminary in general. """ self.state_handlers = { SiamDriverState.UNCONFIGURED : self.state_handler_unconfigured, SiamDriverState.DISCONNECTED : self.state_handler_disconnected, SiamDriverState.CONNECTING : self.state_handler_connecting, SiamDriverState.DISCONNECTING : self.state_handler_disconnecting, SiamDriverState.CONNECTED : self.state_handler_connected, # SiamDriverState.ACQUIRE_SAMPLE : self.state_handler_acquire_sample, # SiamDriverState.UPDATE_PARAMS : self.state_handler_update_params, # SiamDriverState.SET : self.state_handler_set, # SiamDriverState.AUTOSAMPLE : self.state_handler_autosample } """ Instrument state machine. """ self.fsm = InstrumentFSM(SiamDriverState, SiamDriverEvent, self.state_handlers, SiamDriverEvent.ENTER, SiamDriverEvent.EXIT) ########################################################################### # <state handlers> def state_handler_unconfigured(self,event,params): """ Event handler for STATE_UNCONFIGURED. Events handled: EVENT_ENTER: Reset communication parameters to null values. EVENT_EXIT: Pass. EVENT_CONFIGURE: Set communication parameters and switch to STATE_DISCONNECTED if successful. EVENT_INITIALIZE: Reset communication parameters to null values. """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug("state_handler_unconfigured: event = " +str(event) + "\n\t\t params = " + str(params)) success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = {'type':SiamDriverAnnouncement.STATE_CHANGE,'transducer':SiamDriverChannel.INSTRUMENT, 'value':SiamDriverState.UNCONFIGURED} self.send(self.proc_supid,'driver_event_occurred',content) self._initialize() elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.INITIALIZE: self._initialize() elif event == SiamDriverEvent.CONFIGURE: if self._configure(params): next_state = SiamDriverState.DISCONNECTED else: success = InstErrorCode.INCORRECT_STATE return (success,next_state) def state_handler_disconnected(self,event,params): """ Event handler for STATE_DISCONNECTED. Events handled: EVENT_ENTER: Pass. EVENT_EXIT: Pass. EVENT_INITIALIZE: Switch to STATE_UNCONFIGURED. EVENT_CONNECT: Switch to STATE_CONNECTING. """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug("state_handler_disconnected: event = " +str(event) + "\n\t\t params = " + str(params)) success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = {'type':SiamDriverAnnouncement.STATE_CHANGE,'transducer':SiamDriverChannel.INSTRUMENT, 'value':SiamDriverState.DISCONNECTED} self.send(self.proc_supid,'driver_event_occurred',content) elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.INITIALIZE: next_state = SiamDriverState.UNCONFIGURED elif event == SiamDriverEvent.CONNECT: next_state = SiamDriverState.CONNECTING # not in sbe37 elif event == SiamDriverEvent.DISCONNECT_COMPLETE: pass else: success = InstErrorCode.INCORRECT_STATE return (success,next_state) def state_handler_connecting(self,event,params): """ Event handler for STATE_CONNECTING. Events handled: EVENT_ENTER: Attemmpt to establish connection. EVENT_EXIT: Pass. EVENT_CONNECTION_COMPLETE: Switch to SiamDriverState.CONNECTED (STATE_UPDATE_PARAMS in SBE37) EVENT_CONNECTION_FAILED: Switch to STATE_DISCONNECTED. """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug("state_handler_connecting: event = " +str(event) + "\n\t\t params = " + str(params)) success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = {'type':SiamDriverAnnouncement.STATE_CHANGE,'transducer':SiamDriverChannel.INSTRUMENT, 'value':SiamDriverState.CONNECTING} self.send(self.proc_supid,'driver_event_occurred',content) elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.CONNECTION_COMPLETE: # next_state = SiamDriverState.UPDATE_PARAMS next_state = SiamDriverState.CONNECTED elif event == SiamDriverEvent.CONNECTION_FAILED: # Error message to agent here. next_state = SiamDriverState.DISCONNECTED else: success = InstErrorCode.INCORRECT_STATE return (success,next_state) def state_handler_connected(self,event,params): """ Event handler for STATE_CONNECTED. EVENT_ENTER: Notifies agent if instructed so CONNECTION_COMPLETE: pass EVENT_EXIT: Pass. EVENT_DISCONNECT: Switch to STATE_DISCONNECTING. EVENT_COMMAND_RECEIVED: If a command is queued, switch to command specific state for handling. EVENT_DATA_RECEIVED: Pass. """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug("state_handler_connected: event = " +str(event) + "\n\t\t params = " + str(params)) success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = {'type':SiamDriverAnnouncement.STATE_CHANGE,'transducer':SiamDriverChannel.INSTRUMENT, 'value':SiamDriverState.CONNECTED} self.send(self.proc_supid,'driver_event_occurred',content) elif event == SiamDriverEvent.CONNECTION_COMPLETE: pass elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.DISCONNECT: next_state = SiamDriverState.DISCONNECTING elif event == SiamDriverEvent.SET: next_state = SiamDriverState.SET elif event == SiamDriverEvent.ACQUIRE_SAMPLE: next_state = SiamDriverState.ACQUIRE_SAMPLE elif event == SiamDriverEvent.START_AUTOSAMPLE: next_state = SiamDriverState.AUTOSAMPLE elif event == SiamDriverEvent.TEST: next_state = SiamDriverState.TEST elif event == SiamDriverEvent.CALIBRATE: next_state = SiamDriverState.CALIBRATE elif event == SiamDriverEvent.RESET: next_state = SiamDriverState.RESET elif event == SiamDriverEvent.DATA_RECEIVED: pass else: success = InstErrorCode.INCORRECT_STATE return (success,next_state) def state_handler_disconnecting(self,event,params): """ Event handler for STATE_DISCONNECTING. Events handled: EVENT_ENTER: Attempt to close connection to instrument. EVENT_EXIT: Pass. EVENT_DISCONNECT_COMPLETE: Switch to STATE_DISCONNECTED. """ success = InstErrorCode.OK next_state = None if event == SiamDriverEvent.ENTER: if self.notify_agent: # Announce the state change to agent. content = {'type':SiamDriverAnnouncement.STATE_CHANGE,'transducer':SiamDriverChannel.INSTRUMENT, 'value':SiamDriverState.DISCONNECTED} self.send(self.proc_supid,'driver_event_occurred',content) elif event == SiamDriverEvent.EXIT: pass elif event == SiamDriverEvent.DISCONNECT_COMPLETE: next_state = SiamDriverState.DISCONNECTED else: success = InstErrorCode.INCORRECT_STATE return (success,next_state) # </state handlers> ########################################################################### def _initialize(self): """ Set the configuration to an initialized, unconfigured state. """ self.pid = None self.port = None ########################################################################### # <Process lifecycle methods> @defer.inlineCallbacks def plc_init(self): """ Process lifecycle initialization. """ yield # Set initial state. self.fsm.start(SiamDriverState.UNCONFIGURED) log.debug("SiamDriver plc_init: FSM started with state UNCONFIGURED") @defer.inlineCallbacks def plc_terminate(self): log.debug("SiamDriver plc_terminate") """ Process lifecycle termination. """ yield # </Process lifecycle methods> ########################################################################### @defer.inlineCallbacks def op_get_state(self, content, headers, msg): cur_state = self.fsm.current_state yield self.reply_ok(msg, cur_state) @defer.inlineCallbacks def op_initialize(self, content, headers, msg): """ Restore driver to a default, unconfigured state. @param content A dict with optional timeout: {'timeout':timeout}. @retval A reply message with a dict {'success':success,'result':None}. """ # Timeout not implemented for this op. timeout = content.get('timeout',None) if timeout != None: assert(isinstance(timeout,int)), 'Expected integer timeout' assert(timeout>0), 'Expected positive timeout' pass # Set up the reply and fire an EVENT_INITIALIZE. reply = {'success':None,'result':None} success = self.fsm.on_event(SiamDriverEvent.INITIALIZE) # Set success and send reply. Unsuccessful initialize means the # event is not handled in the current state. if not success: reply['success'] = InstErrorCode.INCORRECT_STATE else: reply['success'] = InstErrorCode.OK yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_configure(self, content, headers, msg): assert(isinstance(content, dict)), 'Expected dict content.' params = content.get('params', None) assert(isinstance(params, dict)), 'Expected dict params.' # Timeout not implemented for this op. timeout = content.get('timeout', None) if timeout != None: assert(isinstance(timeout, int)), 'Expected integer timeout' assert(timeout > 0), 'Expected positive timeout' pass # Set up the reply message and validate the configuration parameters. # Reply with the error message if the parameters not valid. reply = {'success':None, 'result':params} reply['success'] = self._validate_configuration(params) if InstErrorCode.is_error(reply['success']): yield self.reply_ok(msg, reply) return # Fire EVENT_CONFIGURE with the validated configuration parameters. # Set the error message if the event is not handled in the current # state. reply['success'] = self.fsm.on_event(SiamDriverEvent.CONFIGURE,params) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('op_configure: complete. success = %s' % (reply['success'])) yield self.reply_ok(msg, reply) def _configure(self, params): # Validate configuration. success = self._validate_configuration(params) if InstErrorCode.is_error(success): return False # Set configuration parameters. self.pid = params['pid'] self.port = params['port'] if log.getEffectiveLevel() <= logging.DEBUG: log.debug("_configure: pid = '" + \ str(self.pid) + "' port = '" + str(self.port) + "'") self.siamci = SiamCiAdapterProxy(self.pid, self.port) return True def _validate_configuration(self, params): # Get required parameters. pid = params.get('pid', None) port = params.get('port', None) # fail if missing a required parameter. if not pid or not port: return InstErrorCode.REQUIRED_PARAMETER return InstErrorCode.OK @defer.inlineCallbacks def op_connect(self, content, headers, msg): # Timeout not implemented for this op. timeout = content.get('timeout',None) if timeout != None: assert(isinstance(timeout,int)), 'Expected integer timeout' assert(timeout>0), 'Expected positive timeout' pass success = self.fsm.on_event(SiamDriverEvent.CONNECT) reply = {'success':success,'result':None} if InstErrorCode.is_error(reply['success']): yield self.reply_ok(msg, reply) return success = self.fsm.on_event(SiamDriverEvent.CONNECTION_COMPLETE) reply['success'] = success """ There is no actual "connect"/"disconnect" as the driver interacts via messaging with the SIAM-CI adapter service. We just start our proxy: """ yield self.siamci.start() if log.getEffectiveLevel() <= logging.DEBUG: log.debug('op_connect: SiamCiProxy started') yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_disconnect(self, content, headers, msg): # Timeout not implemented for this op. timeout = content.get('timeout',None) if timeout != None: assert(isinstance(timeout,int)), 'Expected integer timeout' assert(timeout>0), 'Expected positive timeout' pass success = self.fsm.on_event(SiamDriverEvent.DISCONNECT) reply = {'success':success,'result':None} if InstErrorCode.is_error(reply['success']): yield self.reply_ok(msg, reply) return success = self.fsm.on_event(SiamDriverEvent.DISCONNECT_COMPLETE) reply['success'] = success """ @TODO: why calling ''yield self.siamci.stop()'' to stop (terminate) the SiamCiProxy process causes errors? Here are some of the errors if this call is included when running test_siam_driver.py: [process :780] WARNING:Process bootstrap RPC conv-id=carueda_46740.7#29 timed out! [state_object :113] ERROR:ERROR in StateObject process(event=deactivate) [receiver :169] ERROR:Receiver error: Illegal state change [state_object :132] ERROR:Subsequent ERROR in StateObject error(), ND-ND """ # yield self.siamci.stop() if log.getEffectiveLevel() <= logging.DEBUG: log.debug('op_disconnect: complete. success = %s' % (reply['success'])) yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_get_status(self, content, headers, msg): log.debug('In SiamDriver op_get_status') assert(isinstance(content,dict)), 'Expected dict content.' params = content.get('params',None) """ For 'params', how is that a list, eg., [('all','all)], passed from the client gets converted to a tuple here, eg., (('all', 'all'),) ? """ assert(isinstance(params,(list,tuple))), \ 'Expected list or tuple params in op_get_status' assert(all(map(lambda x:isinstance(x,tuple),params))), \ 'Expected tuple elements in params list' # Timeout not implemented for this op. timeout = content.get('timeout',None) if timeout != None: assert(isinstance(timeout,int)), 'Expected integer timeout' assert(timeout>0), 'Expected positive timeout' pass # @todo: Do something with the new possible argument 'timeout' response = yield self.siamci.get_status(params=params) result = response.result reply = {'success':InstErrorCode.OK,'result':result} yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_get(self, content, headers, msg): assert(isinstance(content,dict)),'Expected dict content.' params = content.get('params',None) assert(isinstance(params,(list,tuple))),'Expected list or tuple params.' # Timeout not implemented for this op. timeout = content.get('timeout',None) if timeout != None: assert(isinstance(timeout,int)), 'Expected integer timeout' assert(timeout>0), 'Expected positive timeout' pass if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver op_get: params = ' +\ str(params)+ " publish_stream=" +str(self.publish_stream)) if self.publish_stream is None: successFail = yield self.siamci.fetch_params(params) else: successFail = yield self.siamci.fetch_params(params, publish_stream=self.publish_stream) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver op_get successFail --> ' + str(successFail)) # initialize reply assuming OK reply = {'success':InstErrorCode.OK, 'result':None} if successFail.result != OK: reply['success'] = InstErrorCode.GET_DEVICE_ERR yield self.reply_ok(msg,reply) return result = {} for it in successFail.item: # logging does not have a TRACE level! # if log.getEffectiveLevel() <= logging.TRACE: # log.trace('In SiamDriver op_get item --> ' + str(it)) chName = it.pair.first value = it.pair.second key = (SiamDriverChannel.INSTRUMENT, chName) result[key] = (InstErrorCode.OK, value) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver op_get result --> ' + str(result)) reply['result'] = result yield self.reply_ok(msg,reply) @defer.inlineCallbacks def op_set(self, content, headers, msg): log.debug('In SiamDriver op_set') assert(isinstance(content,dict)), 'Expected dict content.' # # params should be of the form: # {(chan_arg,param_arg):value,...,(chan_arg,param_arg):value} # params = content.get('params',None) assert(isinstance(params,dict)), 'Expected dict params.' assert(all(map(lambda x: isinstance(x,(list,tuple)), params.keys()))), 'Expected list or tuple dict keys.' assert(all(map(lambda x: isinstance(x,str), params.values()))), 'Expected string dict values.' # Timeout not implemented for this op. timeout = content.get('timeout',None) if timeout != None: assert(isinstance(timeout,int)), 'Expected integer timeout' assert(timeout>0), 'Expected positive timeout' pass reply = {'success':None,'result':None} # # TODO accept the format of the params as indicated above. For the # moment, we convert the input: # {(chan_arg,param_arg):value,...,(chan_arg,param_arg):value} # into # {param_arg:value,..., param_arg:value} # while checking that all chan_arg in the input are equal to # SiamDriverChannel.INSTRUMENT. params_for_proxy = {} for (chan,param) in params.keys(): if SiamDriverChannel.INSTRUMENT != chan: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Only " +str(SiamDriverChannel.INSTRUMENT) + \ " accepted for channel; given: " + chan reply['result'] = errmsg log.warning("op_set: " +errmsg) yield self.reply_ok(msg,reply) return val = params[(chan,param)] params_for_proxy[param] = val if log.getEffectiveLevel() <= logging.DEBUG: log.debug("params_for_proxy = " + str(params_for_proxy) + \ " **** siamci = " + str(self.siamci)) response = yield self.siamci.set_params(params_for_proxy) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver op_set_params --> ' + str(response)) if response.result == OK: reply['success'] = InstErrorCode.OK reply['result'] = params_for_proxy # just informative else: reply['success'] = InstErrorCode.SET_DEVICE_ERR yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_set_publish_stream(self, content, headers, msg): self.publish_stream = content.get('publish_stream', None) reply = {'success':InstErrorCode.OK, 'result':self.publish_stream} if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_set_publish_stream = " + str(self.publish_stream)) yield self.reply_ok(msg, reply) @defer.inlineCallbacks def op_execute(self, content, headers, msg): """ Execute a driver command. Commands may be common or specific to the device, with specific commands known through knowledge of the device or a previous get_capabilities query. @param content A dict with channels and command lists and optional timeout: {'channels':[chan_arg,...,chan_arg], 'command':[command,arg,...,argN]), 'timeout':timeout}. @retval A reply message with a dict {'success':success, 'result':{chan_arg:(success,command_specific_values),..., chan_arg:(success,command_specific_values)}}. """ assert(isinstance(content,dict)), 'Expected dict content.' # Set up reply dict, get required parameters from message content. reply = {'success':None,'result':None} command = content.get('command',None) channels = content.get('channels',None) timeout = content.get('timeout',None) # Fail if required parameters absent. if not command: reply['success'] = InstErrorCode.REQUIRED_PARAMETER yield self.reply_ok(msg,reply) return if not channels: reply['success'] = InstErrorCode.REQUIRED_PARAMETER yield self.reply_ok(msg,reply) return assert(isinstance(command,(list,tuple))) assert(all(map(lambda x:isinstance(x,str),command))) assert(isinstance(channels,(list,tuple))) assert(all(map(lambda x:isinstance(x,str),channels))) if timeout != None: assert(isinstance(timeout,int)), 'Expected integer timeout' assert(timeout>0), 'Expected positive timeout' pass # Fail if command or channels not valid for siam driver. if not SiamDriverCommand.has(command[0]): reply['success'] = InstErrorCode.UNKNOWN_COMMAND yield self.reply_ok(msg,reply) return # get the actual instrument channels: successFail = yield self.siamci.get_channels() if successFail.result != OK: reply['success'] = InstErrorCode.EXE_DEVICE_ERR errmsg = "Error retrieving channels" reply['result'] = errmsg log.warning("op_execute: " +errmsg) yield self.reply_ok(msg,reply) return instrument_channels = [it.str for it in successFail.item] # # NOTE: special channel name SiamDriverChannel.INSTRUMENT only # accepted in a singleton channels list. # if len(channels) == 0 or (len(channels) == 1 and SiamDriverChannel.INSTRUMENT == channels[0]): # ok, this means all channels for various operations. pass else: # verify the explicit requested channels are valid for chan in channels: if SiamDriverChannel.INSTRUMENT == chan: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Can only use '" + \ str(SiamDriverChannel.INSTRUMENT) + \ "' for a singleton channels list" reply['result'] = errmsg log.warning("op_execute: " +errmsg) yield self.reply_ok(msg,reply) return if not chan in instrument_channels: reply['success'] = InstErrorCode.UNKNOWN_CHANNEL errmsg = "instrument does not have channel named '" +str(chan)+ "'" reply['result'] = errmsg log.warning("op_execute: " +errmsg) yield self.reply_ok(msg,reply) return drv_cmd = command[0] ############################# # dispatch the given command: ############################# # GET_CHANNELS ############################################## if drv_cmd == SiamDriverCommand.GET_CHANNELS: # # we already have the channels from the general preparation above # reply['success'] = InstErrorCode.OK reply['result'] = instrument_channels if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute GET_CHANNELS to reply: " + str(reply)) yield self.reply_ok(msg,reply) return # GET_LAST_SAMPLE ############################################## if drv_cmd == SiamDriverCommand.GET_LAST_SAMPLE: yield self.__get_last_sample(channels, reply) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute GET_LAST_SAMPLE to reply: " + str(reply)) yield self.reply_ok(msg,reply) return # START_AUTO_SAMPLING ############################################## if drv_cmd == SiamDriverCommand.START_AUTO_SAMPLING: yield self.__start_sampling(channels, reply) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute START_AUTO_SAMPLING to reply: " + str(reply)) yield self.reply_ok(msg,reply) return # STOP_AUTO_SAMPLING ############################################## if drv_cmd == SiamDriverCommand.STOP_AUTO_SAMPLING: yield self.__stop_sampling(channels, reply) if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute STOP_AUTO_SAMPLING to reply: " + str(reply)) yield self.reply_ok(msg,reply) return # # Else: INVALID_COMMAND # reply['success'] = InstErrorCode.INVALID_COMMAND if log.getEffectiveLevel() <= logging.DEBUG: log.debug("op_execute INVALID_COMMAND to reply: " + str(reply)) yield self.reply_ok(msg,reply) return @defer.inlineCallbacks def __get_last_sample(self, channels, reply): log.debug('In SiamDriver __get_last_sample') response = yield self.siamci.get_last_sample() if response.result != OK: # TODO: some more appropriate error code reply['success'] = InstErrorCode.EXE_DEVICE_ERR return result = {} for it in response.item: ch = it.pair.first val = it.pair.second result[ch] = val reply['success'] = InstErrorCode.OK reply['result'] = result @defer.inlineCallbacks def __start_sampling(self, channels, reply): """ If successful, reply['success'] = InstErrorCode.OK reply['result'] = {'channel':channel, 'publish_stream':self.publish_stream } where channel is the channel in the singleton channels list """ if log.getEffectiveLevel() <= logging.DEBUG: log.debug('__start_sampling channels = ' +str(channels) + \ " notify_agent = " + str(self.notify_agent) + \ " publish_stream = " + str(self.publish_stream)) if len(channels) != 1: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Can only be one channel for the START_AUTO_SAMPLING operation" reply['result'] = errmsg log.warning("__start_sampling: " +errmsg) return # the actual channel we will be sampling on channel = channels[0] if SiamDriverChannel.INSTRUMENT == channel: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Has to be a specific channel, not '" + \ str(SiamDriverChannel.INSTRUMENT) + "'" reply['result'] = errmsg log.warning("__start_sampling: " +errmsg) return # # either publish_stream is given OR notify_agent is True, with # publish_stream having precedence just because this was the first # implemented functionality (but in general, not both properties # would be indicated at the same time). # if self.publish_stream is not None: response = yield self.siamci.execute_StartAcquisition(channel, self.publish_stream) if response.result != OK: log.warning("execute_StartAcquisition failed: " +str(response)) # TODO: some more appropriate error code reply['success'] = InstErrorCode.EXE_DEVICE_ERR return reply['success'] = InstErrorCode.OK reply['result'] = {'channel':channel, 'publish_stream':self.publish_stream } return # # if we are interacting with an Instrument Agent, we need to notify it # whenever we get data from the instrument. # if self.notify_agent: """ @TODO: implement. This could probably be done as follows: use a customized receiver service; set the publish_stream accordingly; and call self.siamci.execute_StartAcquisition(channel, publish_stream) as above. The customized receiver would send the notifications to the agent. Alternatively, do the execute_StartAcquisition thing as above but providing more information such that the java side does the notifications directly to the agent (however, by looking at instrument_agent.py, seems like the operation (op_publish in this case, I think) requires the sender to be a child process, which wouldn't be the case for the external SIAM-CI adapter service...) """ reply['success'] = InstErrorCode.NOT_IMPLEMENTED errmsg = "Notification of data to the agent not implemented yet" reply['result'] = errmsg log.warning("__start_sampling: " +errmsg) return # TODO: perhaps a more appropriate error code for this situation reply['success'] = InstErrorCode.EXE_DEVICE_ERR errmsg = "associated agent or publish_stream required for this operation" reply['result'] = errmsg log.warning("__start_sampling: " +errmsg) @defer.inlineCallbacks def __stop_sampling(self, channels, reply): """ Request to stop sampling """ if len(channels) != 1: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Can only be one channel for the START_AUTO_SAMPLING operation" reply['result'] = errmsg log.warning("__stop_sampling: " +errmsg) return # the actual channel we will be sampling on channel = channels[0] if SiamDriverChannel.INSTRUMENT == channel: reply['success'] = InstErrorCode.INVALID_CHANNEL errmsg = "Has to be a specific channel, not '" + \ str(SiamDriverChannel.INSTRUMENT) + "'" reply['result'] = errmsg log.warning("__stop_sampling: " +errmsg) return # # either publish_stream is given OR notify_agent is True, with # publish_stream having precedence just because this was the first # implemented functionality (but in general, not both properties # would be indicated at the same time). # if self.publish_stream is not None: response = yield self.siamci.execute_StopAcquisition(channel, self.publish_stream) if log.getEffectiveLevel() <= logging.DEBUG: log.debug('In SiamDriver __stop_sampling --> ' + str(response)) if response.result != OK: # TODO: some more appropriate error code reply['success'] = InstErrorCode.EXE_DEVICE_ERR return reply['success'] = InstErrorCode.OK reply['result'] = {'channel':channel, 'publish_stream':self.publish_stream } return # # if we are interacting with an Instrument Agent, we need to notify it # that data acqusition is to stop. # if self.notify_agent: """ @TODO: implement. See __start_sampling. """ reply['success'] = InstErrorCode.NOT_IMPLEMENTED errmsg = "Notification of data to the agent not implemented yet" reply['result'] = errmsg log.warning("__stop_sampling: " +errmsg) return # TODO: perhaps a more appropriate error code for this situation reply['success'] = InstErrorCode.EXE_DEVICE_ERR errmsg = "associated agent or publish_stream required for this operation" reply['result'] = errmsg log.warning("__stop_sampling: " +errmsg)