class ErrorBase(object): def __init__(self, debuglevel=0, debugname='Error Base'): self.debuglevel = debuglevel self.debugname = debugname self._error_string = '' self.on_error_string_changed = [] # Error self._error_channel = ErrorSubscribe(debuglevel=debuglevel) self._error_channel.debugname = '%s - %s' % (self.debugname, 'error') self._error_channel.on_state_changed.append(self._error_channel_state_changed) self._error_channel.on_socket_message_received.append( self._error_channel_message_received ) # more efficient to reuse protobuf messages self._error_rx = Container() # callbacks self.on_error_message_received = [] self.on_state_changed = [] # fsm self._fsm = Fysom( { 'initial': 'down', 'events': [ {'name': 'connect', 'src': 'down', 'dst': 'trying'}, {'name': 'error_up', 'src': 'trying', 'dst': 'up'}, {'name': 'disconnect', 'src': 'trying', 'dst': 'down'}, {'name': 'error_trying', 'src': 'up', 'dst': 'trying'}, {'name': 'disconnect', 'src': 'up', 'dst': 'down'}, ], } ) self._fsm.ondown = self._on_fsm_down self._fsm.onafterconnect = self._on_fsm_connect self._fsm.ontrying = self._on_fsm_trying self._fsm.onaftererror_up = self._on_fsm_error_up self._fsm.onafterdisconnect = self._on_fsm_disconnect self._fsm.onup = self._on_fsm_up self._fsm.onaftererror_trying = self._on_fsm_error_trying self._fsm.onenterup = self._on_fsm_up_entry self._fsm.onleaveup = self._on_fsm_up_exit def _on_fsm_down(self, _): if self.debuglevel > 0: print('[%s]: state DOWN' % self.debugname) for cb in self.on_state_changed: cb('down') return True def _on_fsm_connect(self, _): if self.debuglevel > 0: print('[%s]: event CONNECT' % self.debugname) self.update_topics() self.start_error_channel() return True def _on_fsm_trying(self, _): if self.debuglevel > 0: print('[%s]: state TRYING' % self.debugname) for cb in self.on_state_changed: cb('trying') return True def _on_fsm_error_up(self, _): if self.debuglevel > 0: print('[%s]: event ERROR UP' % self.debugname) return True def _on_fsm_disconnect(self, _): if self.debuglevel > 0: print('[%s]: event DISCONNECT' % self.debugname) self.stop_error_channel() return True def _on_fsm_up(self, _): if self.debuglevel > 0: print('[%s]: state UP' % self.debugname) for cb in self.on_state_changed: cb('up') return True def _on_fsm_error_trying(self, _): if self.debuglevel > 0: print('[%s]: event ERROR TRYING' % self.debugname) return True def _on_fsm_up_entry(self, _): if self.debuglevel > 0: print('[%s]: state UP entry' % self.debugname) self.set_connected() return True def _on_fsm_up_exit(self, _): if self.debuglevel > 0: print('[%s]: state UP exit' % self.debugname) self.clear_connected() return True @property def error_string(self): return self._error_string @error_string.setter def error_string(self, string): if self._error_string is string: return self._error_string = string for cb in self.on_error_string_changed: cb(string) @property def error_uri(self): return self._error_channel.socket_uri @error_uri.setter def error_uri(self, value): self._error_channel.socket_uri = value def update_topics(self): print('WARNING: slot update topics unimplemented') def set_connected(self): print('WARNING: slot set connected unimplemented') def clear_connected(self): print('WARNING: slot clear connected unimplemented') def start(self): if self._fsm.isstate('down'): self._fsm.connect() def stop(self): if self._fsm.isstate('trying'): self._fsm.disconnect() elif self._fsm.isstate('up'): self._fsm.disconnect() def add_error_topic(self, name): self._error_channel.add_socket_topic(name) def remove_error_topic(self, name): self._error_channel.remove_socket_topic(name) def clear_error_topics(self): self._error_channel.clear_socket_topics() def start_error_channel(self): self._error_channel.start() def stop_error_channel(self): self._error_channel.stop() # process all messages received on error def _error_channel_message_received(self, identity, rx): # react to emc nml error message if rx.type == pb.MT_EMC_NML_ERROR: self.emc_nml_error_received(identity, rx) # react to emc nml text message elif rx.type == pb.MT_EMC_NML_TEXT: self.emc_nml_text_received(identity, rx) # react to emc nml display message elif rx.type == pb.MT_EMC_NML_DISPLAY: self.emc_nml_display_received(identity, rx) # react to emc operator text message elif rx.type == pb.MT_EMC_OPERATOR_TEXT: self.emc_operator_text_received(identity, rx) # react to emc operator error message elif rx.type == pb.MT_EMC_OPERATOR_ERROR: self.emc_operator_error_received(identity, rx) # react to emc operator display message elif rx.type == pb.MT_EMC_OPERATOR_DISPLAY: self.emc_operator_display_received(identity, rx) for cb in self.on_error_message_received: cb(identity, rx) def emc_nml_error_received(self, identity, rx): print('SLOT emc nml error unimplemented') def emc_nml_text_received(self, identity, rx): print('SLOT emc nml text unimplemented') def emc_nml_display_received(self, identity, rx): print('SLOT emc nml display unimplemented') def emc_operator_text_received(self, identity, rx): print('SLOT emc operator text unimplemented') def emc_operator_error_received(self, identity, rx): print('SLOT emc operator error unimplemented') def emc_operator_display_received(self, identity, rx): print('SLOT emc operator display unimplemented') def _error_channel_state_changed(self, state): if state == 'trying': if self._fsm.isstate('up'): self._fsm.error_trying() elif state == 'up': if self._fsm.isstate('trying'): self._fsm.error_up()
class LogServiceBase(object): def __init__(self, debuglevel=0, debugname='Log Service Base'): self.debuglevel = debuglevel self.debugname = debugname self._error_string = '' self.on_error_string_changed = [] # Log self._log_channel = Publish(debuglevel=debuglevel) self._log_channel.debugname = '%s - %s' % (self.debugname, 'log') # more efficient to reuse protobuf messages self._log_tx = Container() # callbacks self.on_state_changed = [] # fsm self._fsm = Fysom( { 'initial': 'down', 'events': [ {'name': 'connect', 'src': 'down', 'dst': 'up'}, {'name': 'disconnect', 'src': 'up', 'dst': 'down'}, ], } ) self._fsm.ondown = self._on_fsm_down self._fsm.onafterconnect = self._on_fsm_connect self._fsm.onup = self._on_fsm_up self._fsm.onafterdisconnect = self._on_fsm_disconnect def _on_fsm_down(self, _): if self.debuglevel > 0: print('[%s]: state DOWN' % self.debugname) for cb in self.on_state_changed: cb('down') return True def _on_fsm_connect(self, _): if self.debuglevel > 0: print('[%s]: event CONNECT' % self.debugname) self.start_log_channel() return True def _on_fsm_up(self, _): if self.debuglevel > 0: print('[%s]: state UP' % self.debugname) for cb in self.on_state_changed: cb('up') return True def _on_fsm_disconnect(self, _): if self.debuglevel > 0: print('[%s]: event DISCONNECT' % self.debugname) self.stop_log_channel() return True @property def error_string(self): return self._error_string @error_string.setter def error_string(self, string): if self._error_string is string: return self._error_string = string for cb in self.on_error_string_changed: cb(string) @property def log_uri(self): return self._log_channel.socket_uri @log_uri.setter def log_uri(self, value): self._log_channel.socket_uri = value @property def log_port(self): return self._log_channel.socket_port @property def log_dsn(self): return self._log_channel.socket_dsn def start(self): if self._fsm.isstate('down'): self._fsm.connect() def stop(self): if self._fsm.isstate('up'): self._fsm.disconnect() def add_log_topic(self, name): self._log_channel.add_socket_topic(name) def remove_log_topic(self, name): self._log_channel.remove_socket_topic(name) def clear_log_topics(self): self._log_channel.clear_socket_topics() def start_log_channel(self): self._log_channel.start() def stop_log_channel(self): self._log_channel.stop() def send_log_message(self, identity, msg_type, tx): self._log_channel.send_socket_message(identity.encode(), msg_type, tx) def send_log_message(self, identity, tx): ids = [identity.encode()] for receiver in ids: self.send_log_message(receiver, pb.MT_LOG_MESSAGE, tx)
class ErrorBase(object): def __init__(self, debuglevel=0, debugname='Error Base'): self.debuglevel = debuglevel self.debugname = debugname self._error_string = '' self.on_error_string_changed = [] # Error self._error_channel = ErrorSubscribe(debuglevel=debuglevel) self._error_channel.debugname = '%s - %s' % (self.debugname, 'error') self._error_channel.on_state_changed.append( self._error_channel_state_changed) self._error_channel.on_socket_message_received.append( self._error_channel_message_received) # more efficient to reuse protobuf messages self._error_rx = Container() # callbacks self.on_error_message_received = [] self.on_state_changed = [] # fsm self._fsm = Fysom({ 'initial': 'down', 'events': [ { 'name': 'connect', 'src': 'down', 'dst': 'trying' }, { 'name': 'error_up', 'src': 'trying', 'dst': 'up' }, { 'name': 'disconnect', 'src': 'trying', 'dst': 'down' }, { 'name': 'error_trying', 'src': 'up', 'dst': 'trying' }, { 'name': 'disconnect', 'src': 'up', 'dst': 'down' }, ], }) self._fsm.ondown = self._on_fsm_down self._fsm.onafterconnect = self._on_fsm_connect self._fsm.ontrying = self._on_fsm_trying self._fsm.onaftererror_up = self._on_fsm_error_up self._fsm.onafterdisconnect = self._on_fsm_disconnect self._fsm.onup = self._on_fsm_up self._fsm.onaftererror_trying = self._on_fsm_error_trying self._fsm.onleaveup = self._on_fsm_up_exit def _on_fsm_down(self, _): if self.debuglevel > 0: print('[%s]: state DOWN' % self.debugname) for cb in self.on_state_changed: cb('down') return True def _on_fsm_connect(self, _): if self.debuglevel > 0: print('[%s]: event CONNECT' % self.debugname) self.update_topics() self.start_error_channel() return True def _on_fsm_trying(self, _): if self.debuglevel > 0: print('[%s]: state TRYING' % self.debugname) for cb in self.on_state_changed: cb('trying') return True def _on_fsm_error_up(self, _): if self.debuglevel > 0: print('[%s]: event ERROR UP' % self.debugname) return True def _on_fsm_disconnect(self, _): if self.debuglevel > 0: print('[%s]: event DISCONNECT' % self.debugname) self.stop_error_channel() return True def _on_fsm_up(self, _): if self.debuglevel > 0: print('[%s]: state UP entry' % self.debugname) self.set_connected() if self.debuglevel > 0: print('[%s]: state UP' % self.debugname) for cb in self.on_state_changed: cb('up') return True def _on_fsm_error_trying(self, _): if self.debuglevel > 0: print('[%s]: event ERROR TRYING' % self.debugname) return True def _on_fsm_up_exit(self, _): if self.debuglevel > 0: print('[%s]: state UP exit' % self.debugname) self.clear_connected() return True @property def error_string(self): return self._error_string @error_string.setter def error_string(self, string): if self._error_string is string: return self._error_string = string for cb in self.on_error_string_changed: cb(string) @property def error_uri(self): return self._error_channel.socket_uri @error_uri.setter def error_uri(self, value): self._error_channel.socket_uri = value def update_topics(self): print('WARNING: slot update topics unimplemented') def set_connected(self): print('WARNING: slot set connected unimplemented') def clear_connected(self): print('WARNING: slot clear connected unimplemented') def start(self): if self._fsm.isstate('down'): self._fsm.connect() def stop(self): if self._fsm.isstate('trying'): self._fsm.disconnect() elif self._fsm.isstate('up'): self._fsm.disconnect() def add_error_topic(self, name): self._error_channel.add_socket_topic(name) def remove_error_topic(self, name): self._error_channel.remove_socket_topic(name) def clear_error_topics(self): self._error_channel.clear_socket_topics() def start_error_channel(self): self._error_channel.start() def stop_error_channel(self): self._error_channel.stop() # process all messages received on error def _error_channel_message_received(self, identity, rx): # react to emc nml error message if rx.type == pb.MT_EMC_NML_ERROR: self.emc_nml_error_received(identity, rx) # react to emc nml text message elif rx.type == pb.MT_EMC_NML_TEXT: self.emc_nml_text_received(identity, rx) # react to emc nml display message elif rx.type == pb.MT_EMC_NML_DISPLAY: self.emc_nml_display_received(identity, rx) # react to emc operator text message elif rx.type == pb.MT_EMC_OPERATOR_TEXT: self.emc_operator_text_received(identity, rx) # react to emc operator error message elif rx.type == pb.MT_EMC_OPERATOR_ERROR: self.emc_operator_error_received(identity, rx) # react to emc operator display message elif rx.type == pb.MT_EMC_OPERATOR_DISPLAY: self.emc_operator_display_received(identity, rx) for cb in self.on_error_message_received: cb(identity, rx) def emc_nml_error_received(self, identity, rx): print('SLOT emc nml error unimplemented') def emc_nml_text_received(self, identity, rx): print('SLOT emc nml text unimplemented') def emc_nml_display_received(self, identity, rx): print('SLOT emc nml display unimplemented') def emc_operator_text_received(self, identity, rx): print('SLOT emc operator text unimplemented') def emc_operator_error_received(self, identity, rx): print('SLOT emc operator error unimplemented') def emc_operator_display_received(self, identity, rx): print('SLOT emc operator display unimplemented') def _error_channel_state_changed(self, state): if state == 'trying': if self._fsm.isstate('up'): self._fsm.error_trying() elif state == 'up': if self._fsm.isstate('trying'): self._fsm.error_up()
class RemoteComponentBase(object): def __init__(self, debuglevel=0, debugname='Remote Component Base'): self.debuglevel = debuglevel self.debugname = debugname self._error_string = '' self.on_error_string_changed = [] # Halrcmd self._halrcmd_channel = RpcClient(debuglevel=debuglevel) self._halrcmd_channel.debugname = '%s - %s' % (self.debugname, 'halrcmd') self._halrcmd_channel.on_state_changed.append( self._halrcmd_channel_state_changed) self._halrcmd_channel.on_socket_message_received.append( self._halrcmd_channel_message_received) # more efficient to reuse protobuf messages self._halrcmd_rx = Container() self._halrcmd_tx = Container() # Halrcomp self._halrcomp_channel = HalrcompSubscribe(debuglevel=debuglevel) self._halrcomp_channel.debugname = '%s - %s' % (self.debugname, 'halrcomp') self._halrcomp_channel.on_state_changed.append( self._halrcomp_channel_state_changed) self._halrcomp_channel.on_socket_message_received.append( self._halrcomp_channel_message_received) # more efficient to reuse protobuf messages self._halrcomp_rx = Container() # callbacks self.on_halrcmd_message_received = [] self.on_halrcomp_message_received = [] self.on_state_changed = [] # fsm self._fsm = Fysom({ 'initial': 'down', 'events': [ { 'name': 'connect', 'src': 'down', 'dst': 'trying' }, { 'name': 'halrcmd_up', 'src': 'trying', 'dst': 'bind' }, { 'name': 'disconnect', 'src': 'trying', 'dst': 'down' }, { 'name': 'halrcomp_bind_msg_sent', 'src': 'bind', 'dst': 'binding' }, { 'name': 'no_bind', 'src': 'bind', 'dst': 'syncing' }, { 'name': 'bind_confirmed', 'src': 'binding', 'dst': 'syncing' }, { 'name': 'bind_rejected', 'src': 'binding', 'dst': 'error' }, { 'name': 'halrcmd_trying', 'src': 'binding', 'dst': 'trying' }, { 'name': 'disconnect', 'src': 'binding', 'dst': 'down' }, { 'name': 'halrcmd_trying', 'src': 'syncing', 'dst': 'trying' }, { 'name': 'halrcomp_up', 'src': 'syncing', 'dst': 'sync' }, { 'name': 'sync_failed', 'src': 'syncing', 'dst': 'error' }, { 'name': 'disconnect', 'src': 'syncing', 'dst': 'down' }, { 'name': 'pins_synced', 'src': 'sync', 'dst': 'synced' }, { 'name': 'halrcomp_trying', 'src': 'synced', 'dst': 'syncing' }, { 'name': 'halrcmd_trying', 'src': 'synced', 'dst': 'trying' }, { 'name': 'set_rejected', 'src': 'synced', 'dst': 'error' }, { 'name': 'halrcomp_set_msg_sent', 'src': 'synced', 'dst': 'synced' }, { 'name': 'disconnect', 'src': 'synced', 'dst': 'down' }, { 'name': 'disconnect', 'src': 'error', 'dst': 'down' }, ], }) self._fsm.ondown = self._on_fsm_down self._fsm.onafterconnect = self._on_fsm_connect self._fsm.onleavedown = self._on_fsm_down_exit self._fsm.ontrying = self._on_fsm_trying self._fsm.onafterhalrcmd_up = self._on_fsm_halrcmd_up self._fsm.onafterdisconnect = self._on_fsm_disconnect self._fsm.onbind = self._on_fsm_bind self._fsm.onafterhalrcomp_bind_msg_sent = self._on_fsm_halrcomp_bind_msg_sent self._fsm.onafterno_bind = self._on_fsm_no_bind self._fsm.onbinding = self._on_fsm_binding self._fsm.onafterbind_confirmed = self._on_fsm_bind_confirmed self._fsm.onafterbind_rejected = self._on_fsm_bind_rejected self._fsm.onafterhalrcmd_trying = self._on_fsm_halrcmd_trying self._fsm.onsyncing = self._on_fsm_syncing self._fsm.onafterhalrcomp_up = self._on_fsm_halrcomp_up self._fsm.onaftersync_failed = self._on_fsm_sync_failed self._fsm.onsync = self._on_fsm_sync self._fsm.onafterpins_synced = self._on_fsm_pins_synced self._fsm.onsynced = self._on_fsm_synced self._fsm.onafterhalrcomp_trying = self._on_fsm_halrcomp_trying self._fsm.onafterset_rejected = self._on_fsm_set_rejected self._fsm.onafterhalrcomp_set_msg_sent = self._on_fsm_halrcomp_set_msg_sent self._fsm.onerror = self._on_fsm_error def _on_fsm_down(self, _): if self.debuglevel > 0: print('[%s]: state DOWN entry' % self.debugname) self.set_disconnected() if self.debuglevel > 0: print('[%s]: state DOWN' % self.debugname) for cb in self.on_state_changed: cb('down') return True def _on_fsm_connect(self, _): if self.debuglevel > 0: print('[%s]: event CONNECT' % self.debugname) self.add_pins() self.start_halrcmd_channel() return True def _on_fsm_down_exit(self, _): if self.debuglevel > 0: print('[%s]: state DOWN exit' % self.debugname) self.set_connecting() return True def _on_fsm_trying(self, _): if self.debuglevel > 0: print('[%s]: state TRYING' % self.debugname) for cb in self.on_state_changed: cb('trying') return True def _on_fsm_halrcmd_up(self, _): if self.debuglevel > 0: print('[%s]: event HALRCMD UP' % self.debugname) self.bind_component() return True def _on_fsm_disconnect(self, _): if self.debuglevel > 0: print('[%s]: event DISCONNECT' % self.debugname) self.stop_halrcmd_channel() self.stop_halrcomp_channel() self.remove_pins() return True def _on_fsm_bind(self, _): if self.debuglevel > 0: print('[%s]: state BIND' % self.debugname) for cb in self.on_state_changed: cb('bind') return True def _on_fsm_halrcomp_bind_msg_sent(self, _): if self.debuglevel > 0: print('[%s]: event HALRCOMP BIND MSG SENT' % self.debugname) return True def _on_fsm_no_bind(self, _): if self.debuglevel > 0: print('[%s]: event NO BIND' % self.debugname) self.start_halrcomp_channel() return True def _on_fsm_binding(self, _): if self.debuglevel > 0: print('[%s]: state BINDING' % self.debugname) for cb in self.on_state_changed: cb('binding') return True def _on_fsm_bind_confirmed(self, _): if self.debuglevel > 0: print('[%s]: event BIND CONFIRMED' % self.debugname) self.start_halrcomp_channel() return True def _on_fsm_bind_rejected(self, _): if self.debuglevel > 0: print('[%s]: event BIND REJECTED' % self.debugname) self.stop_halrcmd_channel() return True def _on_fsm_halrcmd_trying(self, _): if self.debuglevel > 0: print('[%s]: event HALRCMD TRYING' % self.debugname) return True def _on_fsm_syncing(self, _): if self.debuglevel > 0: print('[%s]: state SYNCING' % self.debugname) for cb in self.on_state_changed: cb('syncing') return True def _on_fsm_halrcomp_up(self, _): if self.debuglevel > 0: print('[%s]: event HALRCOMP UP' % self.debugname) return True def _on_fsm_sync_failed(self, _): if self.debuglevel > 0: print('[%s]: event SYNC FAILED' % self.debugname) self.stop_halrcomp_channel() self.stop_halrcmd_channel() return True def _on_fsm_sync(self, _): if self.debuglevel > 0: print('[%s]: state SYNC' % self.debugname) for cb in self.on_state_changed: cb('sync') return True def _on_fsm_pins_synced(self, _): if self.debuglevel > 0: print('[%s]: event PINS SYNCED' % self.debugname) return True def _on_fsm_synced(self, _): if self.debuglevel > 0: print('[%s]: state SYNCED entry' % self.debugname) self.set_connected() if self.debuglevel > 0: print('[%s]: state SYNCED' % self.debugname) for cb in self.on_state_changed: cb('synced') return True def _on_fsm_halrcomp_trying(self, _): if self.debuglevel > 0: print('[%s]: event HALRCOMP TRYING' % self.debugname) self.unsync_pins() self.set_timeout() return True def _on_fsm_set_rejected(self, _): if self.debuglevel > 0: print('[%s]: event SET REJECTED' % self.debugname) self.stop_halrcomp_channel() self.stop_halrcmd_channel() return True def _on_fsm_halrcomp_set_msg_sent(self, _): if self.debuglevel > 0: print('[%s]: event HALRCOMP SET MSG SENT' % self.debugname) return True def _on_fsm_error(self, _): if self.debuglevel > 0: print('[%s]: state ERROR entry' % self.debugname) self.set_error() if self.debuglevel > 0: print('[%s]: state ERROR' % self.debugname) for cb in self.on_state_changed: cb('error') return True @property def error_string(self): return self._error_string @error_string.setter def error_string(self, string): if self._error_string is string: return self._error_string = string for cb in self.on_error_string_changed: cb(string) @property def halrcmd_uri(self): return self._halrcmd_channel.socket_uri @halrcmd_uri.setter def halrcmd_uri(self, value): self._halrcmd_channel.socket_uri = value @property def halrcomp_uri(self): return self._halrcomp_channel.socket_uri @halrcomp_uri.setter def halrcomp_uri(self, value): self._halrcomp_channel.socket_uri = value def bind_component(self): print('WARNING: slot bind component unimplemented') def add_pins(self): print('WARNING: slot add pins unimplemented') def remove_pins(self): print('WARNING: slot remove pins unimplemented') def unsync_pins(self): print('WARNING: slot unsync pins unimplemented') def set_connected(self): print('WARNING: slot set connected unimplemented') def set_error(self): print('WARNING: slot set error unimplemented') def set_disconnected(self): print('WARNING: slot set disconnected unimplemented') def set_connecting(self): print('WARNING: slot set connecting unimplemented') def set_timeout(self): print('WARNING: slot set timeout unimplemented') def no_bind(self): if self._fsm.isstate('bind'): self._fsm.no_bind() def pins_synced(self): if self._fsm.isstate('sync'): self._fsm.pins_synced() def start(self): if self._fsm.isstate('down'): self._fsm.connect() def stop(self): if self._fsm.isstate('trying'): self._fsm.disconnect() elif self._fsm.isstate('binding'): self._fsm.disconnect() elif self._fsm.isstate('syncing'): self._fsm.disconnect() elif self._fsm.isstate('synced'): self._fsm.disconnect() elif self._fsm.isstate('error'): self._fsm.disconnect() def add_halrcomp_topic(self, name): self._halrcomp_channel.add_socket_topic(name) def remove_halrcomp_topic(self, name): self._halrcomp_channel.remove_socket_topic(name) def clear_halrcomp_topics(self): self._halrcomp_channel.clear_socket_topics() def start_halrcmd_channel(self): self._halrcmd_channel.start() def stop_halrcmd_channel(self): self._halrcmd_channel.stop() def start_halrcomp_channel(self): self._halrcomp_channel.start() def stop_halrcomp_channel(self): self._halrcomp_channel.stop() # process all messages received on halrcmd def _halrcmd_channel_message_received(self, rx): # react to halrcomp bind confirm message if rx.type == pb.MT_HALRCOMP_BIND_CONFIRM: if self._fsm.isstate('binding'): self._fsm.bind_confirmed() # react to halrcomp bind reject message elif rx.type == pb.MT_HALRCOMP_BIND_REJECT: # update error string with note self.error_string = '' for note in rx.note: self.error_string += note + '\n' if self._fsm.isstate('binding'): self._fsm.bind_rejected() # react to halrcomp set reject message elif rx.type == pb.MT_HALRCOMP_SET_REJECT: # update error string with note self.error_string = '' for note in rx.note: self.error_string += note + '\n' if self._fsm.isstate('synced'): self._fsm.set_rejected() for cb in self.on_halrcmd_message_received: cb(rx) # process all messages received on halrcomp def _halrcomp_channel_message_received(self, identity, rx): # react to halrcomp full update message if rx.type == pb.MT_HALRCOMP_FULL_UPDATE: self.halrcomp_full_update_received(identity, rx) # react to halrcomp incremental update message elif rx.type == pb.MT_HALRCOMP_INCREMENTAL_UPDATE: self.halrcomp_incremental_update_received(identity, rx) # react to halrcomp error message elif rx.type == pb.MT_HALRCOMP_ERROR: # update error string with note self.error_string = '' for note in rx.note: self.error_string += note + '\n' if self._fsm.isstate('syncing'): self._fsm.sync_failed() self.halrcomp_error_received(identity, rx) for cb in self.on_halrcomp_message_received: cb(identity, rx) def halrcomp_full_update_received(self, identity, rx): print('SLOT halrcomp full update unimplemented') def halrcomp_incremental_update_received(self, identity, rx): print('SLOT halrcomp incremental update unimplemented') def halrcomp_error_received(self, identity, rx): print('SLOT halrcomp error unimplemented') def send_halrcmd_message(self, msg_type, tx): self._halrcmd_channel.send_socket_message(msg_type, tx) if msg_type == pb.MT_HALRCOMP_BIND: if self._fsm.isstate('bind'): self._fsm.halrcomp_bind_msg_sent() elif msg_type == pb.MT_HALRCOMP_SET: if self._fsm.isstate('synced'): self._fsm.halrcomp_set_msg_sent() def send_halrcomp_bind(self, tx): self.send_halrcmd_message(pb.MT_HALRCOMP_BIND, tx) def send_halrcomp_set(self, tx): self.send_halrcmd_message(pb.MT_HALRCOMP_SET, tx) def _halrcmd_channel_state_changed(self, state): if state == 'trying': if self._fsm.isstate('syncing'): self._fsm.halrcmd_trying() elif self._fsm.isstate('synced'): self._fsm.halrcmd_trying() elif self._fsm.isstate('binding'): self._fsm.halrcmd_trying() elif state == 'up': if self._fsm.isstate('trying'): self._fsm.halrcmd_up() def _halrcomp_channel_state_changed(self, state): if state == 'trying': if self._fsm.isstate('synced'): self._fsm.halrcomp_trying() elif state == 'up': if self._fsm.isstate('syncing'): self._fsm.halrcomp_up()
class StatusBase(object): def __init__(self, debuglevel=0, debugname='Status Base'): self.debuglevel = debuglevel self.debugname = debugname self._error_string = '' self.on_error_string_changed = [] # Status self._status_channel = StatusSubscribe(debuglevel=debuglevel) self._status_channel.debugname = '%s - %s' % (self.debugname, 'status') self._status_channel.on_state_changed.append( self._status_channel_state_changed) self._status_channel.on_socket_message_received.append( self._status_channel_message_received) # more efficient to reuse protobuf messages self._status_rx = Container() # callbacks self.on_status_message_received = [] self.on_state_changed = [] # fsm self._fsm = Fysom({ 'initial': 'down', 'events': [ { 'name': 'connect', 'src': 'down', 'dst': 'trying' }, { 'name': 'status_up', 'src': 'trying', 'dst': 'syncing' }, { 'name': 'disconnect', 'src': 'trying', 'dst': 'down' }, { 'name': 'channels_synced', 'src': 'syncing', 'dst': 'up' }, { 'name': 'status_trying', 'src': 'syncing', 'dst': 'trying' }, { 'name': 'disconnect', 'src': 'syncing', 'dst': 'down' }, { 'name': 'status_trying', 'src': 'up', 'dst': 'trying' }, { 'name': 'disconnect', 'src': 'up', 'dst': 'down' }, ], }) self._fsm.ondown = self._on_fsm_down self._fsm.onafterconnect = self._on_fsm_connect self._fsm.ontrying = self._on_fsm_trying self._fsm.onafterstatus_up = self._on_fsm_status_up self._fsm.onafterdisconnect = self._on_fsm_disconnect self._fsm.onsyncing = self._on_fsm_syncing self._fsm.onafterchannels_synced = self._on_fsm_channels_synced self._fsm.onafterstatus_trying = self._on_fsm_status_trying self._fsm.onup = self._on_fsm_up self._fsm.onleaveup = self._on_fsm_up_exit def _on_fsm_down(self, _): if self.debuglevel > 0: print('[%s]: state DOWN' % self.debugname) for cb in self.on_state_changed: cb('down') return True def _on_fsm_connect(self, _): if self.debuglevel > 0: print('[%s]: event CONNECT' % self.debugname) self.update_topics() self.start_status_channel() return True def _on_fsm_trying(self, _): if self.debuglevel > 0: print('[%s]: state TRYING' % self.debugname) for cb in self.on_state_changed: cb('trying') return True def _on_fsm_status_up(self, _): if self.debuglevel > 0: print('[%s]: event STATUS UP' % self.debugname) return True def _on_fsm_disconnect(self, _): if self.debuglevel > 0: print('[%s]: event DISCONNECT' % self.debugname) self.stop_status_channel() return True def _on_fsm_syncing(self, _): if self.debuglevel > 0: print('[%s]: state SYNCING' % self.debugname) for cb in self.on_state_changed: cb('syncing') return True def _on_fsm_channels_synced(self, _): if self.debuglevel > 0: print('[%s]: event CHANNELS SYNCED' % self.debugname) return True def _on_fsm_status_trying(self, _): if self.debuglevel > 0: print('[%s]: event STATUS TRYING' % self.debugname) return True def _on_fsm_up(self, _): if self.debuglevel > 0: print('[%s]: state UP entry' % self.debugname) self.sync_status() if self.debuglevel > 0: print('[%s]: state UP' % self.debugname) for cb in self.on_state_changed: cb('up') return True def _on_fsm_up_exit(self, _): if self.debuglevel > 0: print('[%s]: state UP exit' % self.debugname) self.unsync_status() return True @property def error_string(self): return self._error_string @error_string.setter def error_string(self, string): if self._error_string is string: return self._error_string = string for cb in self.on_error_string_changed: cb(string) @property def status_uri(self): return self._status_channel.socket_uri @status_uri.setter def status_uri(self, value): self._status_channel.socket_uri = value def sync_status(self): print('WARNING: slot sync status unimplemented') def unsync_status(self): print('WARNING: slot unsync status unimplemented') def update_topics(self): print('WARNING: slot update topics unimplemented') def start(self): if self._fsm.isstate('down'): self._fsm.connect() def stop(self): if self._fsm.isstate('trying'): self._fsm.disconnect() elif self._fsm.isstate('up'): self._fsm.disconnect() def channels_synced(self): if self._fsm.isstate('syncing'): self._fsm.channels_synced() def add_status_topic(self, name): self._status_channel.add_socket_topic(name) def remove_status_topic(self, name): self._status_channel.remove_socket_topic(name) def clear_status_topics(self): self._status_channel.clear_socket_topics() def start_status_channel(self): self._status_channel.start() def stop_status_channel(self): self._status_channel.stop() # process all messages received on status def _status_channel_message_received(self, identity, rx): # react to emcstat full update message if rx.type == pb.MT_EMCSTAT_FULL_UPDATE: self.emcstat_full_update_received(identity, rx) # react to emcstat incremental update message elif rx.type == pb.MT_EMCSTAT_INCREMENTAL_UPDATE: self.emcstat_incremental_update_received(identity, rx) for cb in self.on_status_message_received: cb(identity, rx) def emcstat_full_update_received(self, identity, rx): print('SLOT emcstat full update unimplemented') def emcstat_incremental_update_received(self, identity, rx): print('SLOT emcstat incremental update unimplemented') def _status_channel_state_changed(self, state): if state == 'trying': if self._fsm.isstate('up'): self._fsm.status_trying() elif state == 'trying': if self._fsm.isstate('syncing'): self._fsm.status_trying() elif state == 'up': if self._fsm.isstate('trying'): self._fsm.status_up()
class CommandBase(object): def __init__(self, debuglevel=0, debugname='Command Base'): self.debuglevel = debuglevel self.debugname = debugname self._error_string = '' self.on_error_string_changed = [] # Command self._command_channel = RpcClient(debuglevel=debuglevel) self._command_channel.debugname = '%s - %s' % (self.debugname, 'command') self._command_channel.on_state_changed.append( self._command_channel_state_changed) self._command_channel.on_socket_message_received.append( self._command_channel_message_received) # more efficient to reuse protobuf messages self._command_rx = Container() self._command_tx = Container() # callbacks self.on_command_message_received = [] self.on_state_changed = [] # fsm self._fsm = Fysom({ 'initial': 'down', 'events': [ { 'name': 'connect', 'src': 'down', 'dst': 'trying' }, { 'name': 'command_up', 'src': 'trying', 'dst': 'up' }, { 'name': 'disconnect', 'src': 'trying', 'dst': 'down' }, { 'name': 'command_trying', 'src': 'up', 'dst': 'trying' }, { 'name': 'disconnect', 'src': 'up', 'dst': 'down' }, ], }) self._fsm.ondown = self._on_fsm_down self._fsm.onafterconnect = self._on_fsm_connect self._fsm.ontrying = self._on_fsm_trying self._fsm.onaftercommand_up = self._on_fsm_command_up self._fsm.onafterdisconnect = self._on_fsm_disconnect self._fsm.onup = self._on_fsm_up self._fsm.onaftercommand_trying = self._on_fsm_command_trying self._fsm.onleaveup = self._on_fsm_up_exit def _on_fsm_down(self, _): if self.debuglevel > 0: print('[%s]: state DOWN' % self.debugname) for cb in self.on_state_changed: cb('down') return True def _on_fsm_connect(self, _): if self.debuglevel > 0: print('[%s]: event CONNECT' % self.debugname) self.start_command_channel() return True def _on_fsm_trying(self, _): if self.debuglevel > 0: print('[%s]: state TRYING' % self.debugname) for cb in self.on_state_changed: cb('trying') return True def _on_fsm_command_up(self, _): if self.debuglevel > 0: print('[%s]: event COMMAND UP' % self.debugname) return True def _on_fsm_disconnect(self, _): if self.debuglevel > 0: print('[%s]: event DISCONNECT' % self.debugname) self.stop_command_channel() self.clear_connected() return True def _on_fsm_up(self, _): if self.debuglevel > 0: print('[%s]: state UP entry' % self.debugname) self.set_connected() if self.debuglevel > 0: print('[%s]: state UP' % self.debugname) for cb in self.on_state_changed: cb('up') return True def _on_fsm_command_trying(self, _): if self.debuglevel > 0: print('[%s]: event COMMAND TRYING' % self.debugname) return True def _on_fsm_up_exit(self, _): if self.debuglevel > 0: print('[%s]: state UP exit' % self.debugname) self.clear_connected() return True @property def error_string(self): return self._error_string @error_string.setter def error_string(self, string): if self._error_string is string: return self._error_string = string for cb in self.on_error_string_changed: cb(string) @property def command_uri(self): return self._command_channel.socket_uri @command_uri.setter def command_uri(self, value): self._command_channel.socket_uri = value def set_connected(self): print('WARNING: slot set connected unimplemented') def clear_connected(self): print('WARNING: slot clear connected unimplemented') def start(self): if self._fsm.isstate('down'): self._fsm.connect() def stop(self): if self._fsm.isstate('trying'): self._fsm.disconnect() elif self._fsm.isstate('up'): self._fsm.disconnect() def start_command_channel(self): self._command_channel.start() def stop_command_channel(self): self._command_channel.stop() # process all messages received on command def _command_channel_message_received(self, rx): # react to emccmd executed message if rx.type == pb.MT_EMCCMD_EXECUTED: self.emccmd_executed_received(rx) # react to emccmd completed message elif rx.type == pb.MT_EMCCMD_COMPLETED: self.emccmd_completed_received(rx) # react to error message elif rx.type == pb.MT_ERROR: # update error string with note self.error_string = '' for note in rx.note: self.error_string += note + '\n' for cb in self.on_command_message_received: cb(rx) def emccmd_executed_received(self, rx): print('SLOT emccmd executed unimplemented') def emccmd_completed_received(self, rx): print('SLOT emccmd completed unimplemented') def send_command_message(self, msg_type, tx): self._command_channel.send_socket_message(msg_type, tx) def send_emc_task_abort(self, tx): self.send_command_message(pb.MT_EMC_TASK_ABORT, tx) def send_emc_task_plan_run(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_RUN, tx) def send_emc_task_plan_pause(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_PAUSE, tx) def send_emc_task_plan_step(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_STEP, tx) def send_emc_task_plan_resume(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_RESUME, tx) def send_emc_set_debug(self, tx): self.send_command_message(pb.MT_EMC_SET_DEBUG, tx) def send_emc_coolant_flood_on(self, tx): self.send_command_message(pb.MT_EMC_COOLANT_FLOOD_ON, tx) def send_emc_coolant_flood_off(self, tx): self.send_command_message(pb.MT_EMC_COOLANT_FLOOD_OFF, tx) def send_emc_axis_home(self, tx): self.send_command_message(pb.MT_EMC_AXIS_HOME, tx) def send_emc_axis_jog(self, tx): self.send_command_message(pb.MT_EMC_AXIS_JOG, tx) def send_emc_axis_abort(self, tx): self.send_command_message(pb.MT_EMC_AXIS_ABORT, tx) def send_emc_axis_incr_jog(self, tx): self.send_command_message(pb.MT_EMC_AXIS_INCR_JOG, tx) def send_emc_tool_load_tool_table(self, tx): self.send_command_message(pb.MT_EMC_TOOL_LOAD_TOOL_TABLE, tx) def send_emc_tool_update_tool_table(self, tx): self.send_command_message(pb.MT_EMC_TOOL_UPDATE_TOOL_TABLE, tx) def send_emc_task_plan_execute(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_EXECUTE, tx) def send_emc_coolant_mist_on(self, tx): self.send_command_message(pb.MT_EMC_COOLANT_MIST_ON, tx) def send_emc_coolant_mist_off(self, tx): self.send_command_message(pb.MT_EMC_COOLANT_MIST_OFF, tx) def send_emc_task_plan_init(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_INIT, tx) def send_emc_task_plan_open(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_OPEN, tx) def send_emc_task_plan_set_optional_stop(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_SET_OPTIONAL_STOP, tx) def send_emc_task_plan_set_block_delete(self, tx): self.send_command_message(pb.MT_EMC_TASK_PLAN_SET_BLOCK_DELETE, tx) def send_emc_task_set_mode(self, tx): self.send_command_message(pb.MT_EMC_TASK_SET_MODE, tx) def send_emc_task_set_state(self, tx): self.send_command_message(pb.MT_EMC_TASK_SET_STATE, tx) def send_emc_traj_set_so_enable(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_SO_ENABLE, tx) def send_emc_traj_set_fh_enable(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_FH_ENABLE, tx) def send_emc_traj_set_fo_enable(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_FO_ENABLE, tx) def send_emc_traj_set_max_velocity(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_MAX_VELOCITY, tx) def send_emc_traj_set_mode(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_MODE, tx) def send_emc_traj_set_scale(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_SCALE, tx) def send_emc_traj_set_rapid_scale(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_RAPID_SCALE, tx) def send_emc_traj_set_spindle_scale(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_SPINDLE_SCALE, tx) def send_emc_traj_set_teleop_enable(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_TELEOP_ENABLE, tx) def send_emc_traj_set_teleop_vector(self, tx): self.send_command_message(pb.MT_EMC_TRAJ_SET_TELEOP_VECTOR, tx) def send_emc_tool_set_offset(self, tx): self.send_command_message(pb.MT_EMC_TOOL_SET_OFFSET, tx) def send_emc_axis_override_limits(self, tx): self.send_command_message(pb.MT_EMC_AXIS_OVERRIDE_LIMITS, tx) def send_emc_spindle_constant(self, tx): self.send_command_message(pb.MT_EMC_SPINDLE_CONSTANT, tx) def send_emc_spindle_decrease(self, tx): self.send_command_message(pb.MT_EMC_SPINDLE_DECREASE, tx) def send_emc_spindle_increase(self, tx): self.send_command_message(pb.MT_EMC_SPINDLE_INCREASE, tx) def send_emc_spindle_off(self, tx): self.send_command_message(pb.MT_EMC_SPINDLE_OFF, tx) def send_emc_spindle_on(self, tx): self.send_command_message(pb.MT_EMC_SPINDLE_ON, tx) def send_emc_spindle_brake_engage(self, tx): self.send_command_message(pb.MT_EMC_SPINDLE_BRAKE_ENGAGE, tx) def send_emc_spindle_brake_release(self, tx): self.send_command_message(pb.MT_EMC_SPINDLE_BRAKE_RELEASE, tx) def send_emc_motion_set_aout(self, tx): self.send_command_message(pb.MT_EMC_MOTION_SET_AOUT, tx) def send_emc_motion_set_dout(self, tx): self.send_command_message(pb.MT_EMC_MOTION_SET_DOUT, tx) def send_emc_motion_adaptive(self, tx): self.send_command_message(pb.MT_EMC_MOTION_ADAPTIVE, tx) def send_emc_axis_set_max_position_limit(self, tx): self.send_command_message(pb.MT_EMC_AXIS_SET_MAX_POSITION_LIMIT, tx) def send_emc_axis_set_min_position_limit(self, tx): self.send_command_message(pb.MT_EMC_AXIS_SET_MIN_POSITION_LIMIT, tx) def send_emc_axis_unhome(self, tx): self.send_command_message(pb.MT_EMC_AXIS_UNHOME, tx) def send_shutdown(self, tx): self.send_command_message(pb.MT_SHUTDOWN, tx) def _command_channel_state_changed(self, state): if state == 'trying': if self._fsm.isstate('up'): self._fsm.command_trying() elif state == 'up': if self._fsm.isstate('trying'): self._fsm.command_up()
class LogBase(object): def __init__(self, debuglevel=0, debugname='Log Base'): self.debuglevel = debuglevel self.debugname = debugname self._error_string = '' self.on_error_string_changed = [] # Log self._log_channel = SimpleSubscribe(debuglevel=debuglevel) self._log_channel.debugname = '%s - %s' % (self.debugname, 'log') self._log_channel.on_state_changed.append( self._log_channel_state_changed) self._log_channel.on_socket_message_received.append( self._log_channel_message_received) # more efficient to reuse protobuf messages self._log_rx = Container() # callbacks self.on_log_message_received = [] self.on_state_changed = [] # fsm self._fsm = Fysom({ 'initial': 'down', 'events': [ { 'name': 'connect', 'src': 'down', 'dst': 'trying' }, { 'name': 'log_up', 'src': 'trying', 'dst': 'up' }, { 'name': 'disconnect', 'src': 'trying', 'dst': 'down' }, { 'name': 'disconnect', 'src': 'up', 'dst': 'down' }, ], }) self._fsm.ondown = self._on_fsm_down self._fsm.onafterconnect = self._on_fsm_connect self._fsm.ontrying = self._on_fsm_trying self._fsm.onafterlog_up = self._on_fsm_log_up self._fsm.onafterdisconnect = self._on_fsm_disconnect self._fsm.onup = self._on_fsm_up self._fsm.onleaveup = self._on_fsm_up_exit def _on_fsm_down(self, _): if self.debuglevel > 0: print('[%s]: state DOWN' % self.debugname) for cb in self.on_state_changed: cb('down') return True def _on_fsm_connect(self, _): if self.debuglevel > 0: print('[%s]: event CONNECT' % self.debugname) self.update_topics() self.start_log_channel() return True def _on_fsm_trying(self, _): if self.debuglevel > 0: print('[%s]: state TRYING' % self.debugname) for cb in self.on_state_changed: cb('trying') return True def _on_fsm_log_up(self, _): if self.debuglevel > 0: print('[%s]: event LOG UP' % self.debugname) return True def _on_fsm_disconnect(self, _): if self.debuglevel > 0: print('[%s]: event DISCONNECT' % self.debugname) self.stop_log_channel() return True def _on_fsm_up(self, _): if self.debuglevel > 0: print('[%s]: state UP entry' % self.debugname) self.set_connected() if self.debuglevel > 0: print('[%s]: state UP' % self.debugname) for cb in self.on_state_changed: cb('up') return True def _on_fsm_up_exit(self, _): if self.debuglevel > 0: print('[%s]: state UP exit' % self.debugname) self.clear_connected() return True @property def error_string(self): return self._error_string @error_string.setter def error_string(self, string): if self._error_string is string: return self._error_string = string for cb in self.on_error_string_changed: cb(string) @property def log_uri(self): return self._log_channel.socket_uri @log_uri.setter def log_uri(self, value): self._log_channel.socket_uri = value def update_topics(self): print('WARNING: slot update topics unimplemented') def set_connected(self): print('WARNING: slot set connected unimplemented') def clear_connected(self): print('WARNING: slot clear connected unimplemented') def start(self): if self._fsm.isstate('down'): self._fsm.connect() def stop(self): if self._fsm.isstate('trying'): self._fsm.disconnect() elif self._fsm.isstate('up'): self._fsm.disconnect() def add_log_topic(self, name): self._log_channel.add_socket_topic(name) def remove_log_topic(self, name): self._log_channel.remove_socket_topic(name) def clear_log_topics(self): self._log_channel.clear_socket_topics() def start_log_channel(self): self._log_channel.start() def stop_log_channel(self): self._log_channel.stop() # process all messages received on log def _log_channel_message_received(self, identity, rx): # react to log message message if rx.type == pb.MT_LOG_MESSAGE: self.log_message_received(identity, rx) for cb in self.on_log_message_received: cb(identity, rx) def log_message_received(self, identity, rx): print('SLOT log message unimplemented') def _log_channel_state_changed(self, state): if state == 'up': if self._fsm.isstate('trying'): self._fsm.log_up()
class hsmsHandler(EventProducer): """Baseclass for creating Host/Equipment models. This layer contains the HSMS functionality. Inherit from this class and override required functions. :param address: IP address of remote host :type address: string :param port: TCP port of remote host :type port: integer :param active: Is the connection active (*True*) or passive (*False*) :type active: boolean :param session_id: session / device ID to use for connection :type session_id: integer :param name: Name of the underlying configuration :type name: string :param event_handler: object for event handling :type event_handler: :class:`secsgem.common.EventHandler` :param custom_connection_handler: object for connection handling (ie multi server) :type custom_connection_handler: :class:`secsgem.hsmsConnections.HsmsMultiPassiveServer` **Example**:: import secsgem def S1F1Handler(connection, packet): print "S1F1 received" def onConnect(event, data): print "Connected" client = secsgem.hsmsHandler("10.211.55.33", 5000, True, 0, "test", eventHandler=secsgem.EventHandler(events={'RemoteConnected': onConnect})) client.registerCallback(1, 1, S1F1Handler) client.enable() time.sleep(3) client.disable() """ def __init__(self, address, port, active, session_id, name, event_handler=None, custom_connection_handler=None): EventProducer.__init__(self, event_handler) self.logger = logging.getLogger(self.__module__ + "." + self.__class__.__name__) self.address = address self.port = port self.active = active self.sessionID = session_id self.name = name self.connected = False # repeating linktest variables self.linktestTimer = None self.linktestTimeout = 30 # event and packet queues self.eventQueue = [] self.packetQueue = [] # hsms connection state fsm self.connectionState = Fysom({ 'initial': 'NOT_CONNECTED', 'events': [ {'name': 'connect', 'src': 'NOT_CONNECTED', 'dst': 'CONNECTED'}, {'name': 'disconnect', 'src': ['CONNECTED', 'NOT_SELECTED', 'SELECTED'], 'dst': 'NOT_CONNECTED'}, {'name': 'select', 'src': 'NOT_SELECTED', 'dst': 'SELECTED'}, {'name': 'deselect', 'src': 'SELECTED', 'dst': 'NOT_SELECTED'}, {'name': 'timeoutT7', 'src': 'NOT_SELECTED', 'dst': 'NOT_CONNECTED'}, ], 'callbacks': { 'onNOT_SELECTED': self._on_state_connect, 'onNOT_CONNECTED': self._on_state_disconnect, 'onSELECTED': self._on_state_select, }, 'autoforward': [ {'src': 'CONNECTED', 'dst': 'NOT_SELECTED'} ] }) # setup connection if self.active: if custom_connection_handler is None: self.connection = HsmsActiveConnection(self.address, self.port, self.sessionID, self) else: self.connection = custom_connection_handler.create_connection(self.address, self.port, self.sessionID, self) else: if custom_connection_handler is None: self.connection = HsmsPassiveConnection(self.address, self.port, self.sessionID, self) else: self.connection = custom_connection_handler.create_connection(self.address, self.port, self.sessionID, self) def _on_state_connect(self, data): """Connection state model got event connect :param data: event attributes :type data: object """ # start linktest timer self.linktestTimer = threading.Timer(self.linktestTimeout, self._on_linktest_timer) self.linktestTimer.start() # start select process if connection is active if self.active: system_id = self.sendSelectReq() self.waitforSelectRsp(system_id) def _on_state_disconnect(self, data): """Connection state model got event disconnect :param data: event attributes :type data: object """ # stop linktest timer if self.linktestTimer: self.linktestTimer.cancel() self.linktestTimer = None def _on_state_select(self, data): """Connection state model got event select :param data: event attributes :type data: object """ # send event self.fireEvent('HsmsSelected', {'connection': self}) # notify hsms handler of selection if hasattr(self, '_onHsmsSelect') and callable(getattr(self, '_onHsmsSelect')): self._onHsmsSelect() def _on_linktest_timer(self): """Linktest time timed out, so send linktest request""" # send linktest request and wait for response system_id = self.sendLinktestReq() self.waitforLinktestRsp(system_id) # restart the timer self.linktestTimer = threading.Timer(self.linktestTimeout, self._on_linktest_timer) self.linktestTimer.start() def on_connection_established(self): """Connection was established""" # update connection state self.connected = True self.connectionState.connect() self.fireEvent("HsmsConnected", {'connection': self}) def on_before_connection_closed(self): """Connection is about to be closed""" # send separate request self.sendSeparateReq() def on_connection_closed(self): """Connection was closed""" # update connection state self.connected = False self.connectionState.disconnect() self.fireEvent("HsmsDisconnected", {'connection': self}) def _queuePacket(self, packet): """Add packet to event queue :param packet: received data packet :type packet: :class:`secsgem.hsmsPackets.hsmsPacket` """ # add to event queue self.packetQueue.append(packet) # notify all that new event arrived for event in self.eventQueue: event.set() def on_connection_packet_received(self, packet): """Packet received by connection :param packet: received data packet :type packet: :class:`secsgem.hsmsPackets.hsmsPacket` """ if packet.header.sType > 0: self.logger.info("< %s\n %s", packet, hsmsSTypes[packet.header.sType]) # check if it is a select request if packet.header.sType == 0x01: # if we are disconnecting send reject else send response if self.connection.disconnecting: self.sendRejectRsp(packet.header.system, packet.header.sType, 4) else: self.sendSelectRsp(packet.header.system) # update connection state self.connectionState.select() # check if it is a select response elif packet.header.sType == 0x02: # update connection state self.connectionState.select() # queue packet to notify waiting threads self._queuePacket(packet) # check if it is a deselect request elif packet.header.sType == 0x03: # if we are disconnecting send reject else send response if self.connection.disconnecting: self.sendRejectRsp(packet.header.system, packet.header.sType, 4) else: self.sendDeselectRsp(packet.header.system) # update connection state self.connectionState.deselect() elif packet.header.sType == 0x04: # update connection state self.connectionState.deselect() # queue packet to notify waiting threads self._queuePacket(packet) # check if it is a linktest request elif packet.header.sType == 0x05: # if we are disconnecting send reject else send response if self.connection.disconnecting: self.sendRejectRsp(packet.header.system, packet.header.sType, 4) else: self.sendLinktestRsp(packet.header.system) else: # queue packet if not handeled self._queuePacket(packet) else: if not self.connectionState.isstate("SELECTED"): self.logger.info("< %s", packet) self.logger.warning("received message when not selected") self.connection.send_packet(hsmsPacket(hsmsRejectReqHeader(packet.header.system, packet.header.sType, 4))) return True # redirect packet to hsms handler if hasattr(self, '_onHsmsPacketReceived') and callable(getattr(self, '_onHsmsPacketReceived')): self._onHsmsPacketReceived(packet) else: self.logger.info("< %s", packet) def _serializeData(self): """Returns data for serialization :returns: data to serialize for this object :rtype: dict """ return {'address': self.address, 'port': self.port, 'active': self.active, 'sessionID': self.sessionID, 'name': self.name, 'connected': self.connected} def enable(self): """Enables the connection""" self.connection.enable() def disable(self): """Disables the connection""" self.connection.disable() def waitforStreamFunction(self, stream, function, is_control=False): """Wait for an incoming stream and function and return the receive data :param stream: number of stream to wait for :type stream: integer :param function: number of function to wait for :type function: integer :param is_control: is it a control packet :type is_control: bool :returns: Packet that was received :rtype: :class:`secsgem.hsmsPackets.hsmsPacket` """ if is_control: # setup timeout to T6 timeout = time.time() + self.connection.T6 else: # setup timeout to T3 timeout = time.time() + self.connection.T3 # setup event for new item in queue event = threading.Event() self.eventQueue.append(event) found_packet = None while found_packet is None: for packet in self.packetQueue: if (packet.header.stream == stream) and (packet.header.function == function): self.packetQueue.remove(packet) found_packet = packet break if found_packet is None: if event.wait(1): event.clear() elif not self.connected or self.connection.disconnecting or time.time() > timeout: return None self.eventQueue.remove(event) return found_packet def sendStreamFunction(self, packet): """Send the packet and wait for the response :param packet: packet to be sent :type packet: :class:`secsgem.secsFunctionBase.secsStreamFunction` """ out_packet = hsmsPacket(hsmsStreamFunctionHeader(self.connection.get_next_system_counter(), packet.stream, packet.function, True, self.sessionID), packet.encode()) self.connection.send_packet(out_packet) def waitforSystem(self, system, is_control=False): """Wait for an message with supplied system :param system: number of system to wait for :type system: integer :returns: Packet that was received :rtype: :class:`secsgem.hsmsPackets.hsmsPacket` """ if not self.connected: self.logger.warning("handler not connected waiting for response for system {0}".format(system)) return None if is_control: # setup timeout to T6 timeout = time.time() + self.connection.T6 else: # setup timeout to T3 timeout = time.time() + self.connection.T3 event = threading.Event() self.eventQueue.append(event) found_packet = None while found_packet is None: for packet in self.packetQueue: if packet.header.system == system: self.packetQueue.remove(packet) found_packet = packet break if found_packet is None: if event.wait(1): event.clear() elif not self.connected or self.connection.disconnecting or time.time() > timeout: self.logger.warning("response for system {0} not received within timeout".format(system)) return None self.eventQueue.remove(event) return found_packet def sendAndWaitForResponse(self, packet): """Send the packet and wait for the response :param packet: packet to be sent :type packet: :class:`secsgem.secsFunctionBase.secsStreamFunction` :returns: Packet that was received :rtype: :class:`secsgem.hsmsPackets.hsmsPacket` """ out_packet = hsmsPacket(hsmsStreamFunctionHeader(self.connection.get_next_system_counter(), packet.stream, packet.function, True, self.sessionID), packet.encode()) self.connection.send_packet(out_packet) return self.waitforSystem(out_packet.header.system, (packet.stream == 0)) def sendResponse(self, function, system): """Send response function for system :param function: function to be sent :type function: :class:`secsgem.secsFunctionBase.secsStreamFunction` :param system: system to reply to :type system: integer """ out_packet = hsmsPacket(hsmsStreamFunctionHeader(system, function.stream, function.function, False, self.sessionID), function.encode()) self.connection.send_packet(out_packet) def sendSelectReq(self): """Send a Select Request to the remote host :returns: System of the sent request :rtype: integer """ system_id = self.connection.get_next_system_counter() packet = hsmsPacket(hsmsSelectReqHeader(system_id)) self.connection.send_packet(packet) return system_id def sendSelectRsp(self, system_id): """Send a Select Response to the remote host :param system_id: System of the request to reply for :type system_id: integer """ packet = hsmsPacket(hsmsSelectRspHeader(system_id)) self.connection.send_packet(packet) def waitforSelectRsp(self, system_id): """Wait for an incoming Select Response :param system_id: System of the request to reply for :type system_id: integer :returns: Packet that was received :rtype: :class:`secsgem.hsmsPackets.hsmsPacket` """ result = self.waitforSystem(system_id, True) return result def sendLinktestReq(self): """Send a Linktest Request to the remote host :returns: System of the sent request :rtype: integer """ system_id = self.connection.get_next_system_counter() packet = hsmsPacket(hsmsLinktestReqHeader(system_id)) self.connection.send_packet(packet) return system_id def sendLinktestRsp(self, system_id): """Send a Linktest Response to the remote host :param system_id: System of the request to reply for :type system_id: integer """ packet = hsmsPacket(hsmsLinktestRspHeader(system_id)) self.connection.send_packet(packet) def waitforLinktestRsp(self, system_id): """Wait for an incoming Linktest Response :param system_id: System of the request to reply for :type system_id: integer :returns: Packet that was received :rtype: :class:`secsgem.hsmsPackets.hsmsPacket` """ return self.waitforSystem(system_id, True) def sendDeselectReq(self): """Send a Deselect Request to the remote host :returns: System of the sent request :rtype: integer """ system_id = self.connection.get_next_system_counter() packet = hsmsPacket(hsmsDeselectReqHeader(system_id)) self.connection.send_packet(packet) return system_id def sendDeselectRsp(self, system_id): """Send a Deselect Response to the remote host :param system_id: System of the request to reply for :type system_id: integer """ packet = hsmsPacket(hsmsDeselectRspHeader(system_id)) self.connection.send_packet(packet) def waitforDeselectRsp(self, system_id): """Wait for an incoming Deselect Response :param system_id: System of the request to reply for :type system_id: integer :returns: Packet that was received :rtype: :class:`secsgem.hsmsPackets.hsmsPacket` """ result = self.waitforSystem(system_id, True) return result def sendRejectRsp(self, system_id, s_type, reason): """Send a Reject Response to the remote host :param system_id: System of the request to reply for :type system_id: integer :param s_type: s_type of rejected message :type s_type: integer :param reason: reason for rejection :type reason: integer """ packet = hsmsPacket(hsmsRejectReqHeader(system_id, s_type, reason)) self.connection.send_packet(packet) def sendSeparateReq(self): """Send a Separate Request to the remote host""" system_id = self.connection.get_next_system_counter() packet = hsmsPacket(hsmsSeparateReqHeader(system_id)) self.connection.send_packet(packet) return system_id