def turn_off_port(self, port_id): try: oms_port_id = self.nodeCfgFile.GetOMSPortId(port_id) except Exception as e: raise PlatformConnectionException( msg="Cannot turn_off_platform_port: %s" % str(e)) log.debug("%r: turning off port: port_id=%s oms port_id = %s", self._platform_id, port_id, oms_port_id) if self._rsn_oms is None: raise PlatformConnectionException( "Cannot turn_off_platform_port: _rsn_oms object required (created via connect() call)" ) try: response = self._rsn_oms.port.turn_off_platform_port( self._platform_id, oms_port_id, 'CI - User') except Exception as e: raise PlatformConnectionException( msg="Cannot turn_off_platform_port: %s" % str(e)) log.debug("%r: turn_off_platform_port response: %s", self._platform_id, response) dic_plat = self._verify_platform_id_in_response(response) self._verify_port_id_in_response(oms_port_id, dic_plat) return dic_plat # note: return the dic for the platform
def _send_massp_direct_access(self, command): """ Handle a direct access command. Driver expects direct access commands to specify the target using the following format: target:command It then routes the command to the appropriate slave protocol. @param command: Direct access command received """ err_string = 'Invalid command. Command must be in the following format: "target:command' + NEWLINE + \ 'Valid targets are: %r' % self._slave_protocols.keys() try: target, command = command.split(DA_COMMAND_DELIMITER, 1) target = target.lower() except ValueError: target = None log.debug('_do_cmd_direct - target: %s command: %r', target, command) if target not in self._slave_protocols: self._driver_event(DriverAsyncEvent.DIRECT_ACCESS, err_string) else: self._slave_protocols[target]._protocol_fsm.on_event( ProtocolEvent.EXECUTE_DIRECT, command)
def set_overcurrent_limit(self,port_id, milliamps, microseconds,src): """ """ if self._rsn_oms is None: raise PlatformConnectionException("Cannot set_overcurrent_limit: _rsn_oms object required (created via connect() call)") if port_id not in self.nodeCfg.node_port_info : raise PlatformConnectionException("Cannot set_overcurrent_limit: Invalid Port ID") oms_port_cntl_id = self.nodeCfg.node_port_info[port_id]['port_oms_port_cntl_id'] # ok, now make the request to RSN OMS: try: retval = self._rsn_oms.port.set_over_current(self._platform_id,oms_port_cntl_id,int(milliamps),int(microseconds),src) except Exception as e: raise PlatformConnectionException(msg="Cannot set_overcurrent_limit: %s" % str(e)) log.debug("set_overcurrent_limit = %s", retval) dic_plat = self._verify_platform_id_in_response(response) self._verify_port_id_in_response(oms_port_id, dic_plat) return dic_plat # note: return the dic for the platform
def get_nms_eng_data(self): log.debug("%r: get_nms_eng_data...", self._platform_id) ntp_time = ntplib.system_to_ntp_time(time.time()) attrs=list(); for streamKey,stream in sorted(self.nodeCfg.node_streams.iteritems()): # log.debug("%r Stream(%s)", self._platform_id,streamKey) for streamAttrKey,streamAttr in sorted(stream.iteritems()): # log.debug("%r %r = %r", self._platform_id, streamAttrKey,streamAttr) if 'lastRcvSampleTime' not in streamAttr : # first time this is called set this to a reasonable value streamAttr['lastRcvSampleTime'] = ntp_time - streamAttr['monitor_cycle_seconds']*2 lastRcvSampleTime = streamAttr['lastRcvSampleTime'] if (lastRcvSampleTime+streamAttr['monitor_cycle_seconds'])<ntp_time : # if we think that the OMS will have data from us add it to the list if (ntp_time-lastRcvSampleTime)>(streamAttr['monitor_cycle_seconds']*10) : #make sure we dont reach too far back by accident or will lastRcvSampleTime=ntp_time-(streamAttr['monitor_cycle_seconds']*10) #clog up the OMS DB search attrs.append((streamAttrKey,lastRcvSampleTime+0.1)) # add a little bit of time to the last recieved so we don't get one we alread have again if len(attrs)>0 : returnDict = self.get_attribute_values_from_oms(attrs) #go get the data from the OMS for attr_id, attr_vals in returnDict.iteritems(): # go through the returned list of attributes for streamKey,stream in sorted(self.nodeCfg.node_streams.iteritems()): #go through all the streams for this platform if attr_id in stream : # see if this attribute is in this stream for v, ts in attr_vals: stream[attr_id]['lastRcvSampleTime']=ts ionAttrs = self.convertAttrsToIon(stream,[(attr_id,v)]) #scale the attrs and convert the names to ion pad_particle = Platform_Particle(ionAttrs,port_timestamp=ts) pad_particle.set_internal_timestamp(timestamp=ts) pad_particle._data_particle_type = streamKey # stream name json_message = pad_particle.generate() # this cals parse values above to go from raw to values dict event = { 'type': DriverAsyncEvent.SAMPLE, 'value': json_message, 'time': time.time() } self._send_event(event) return 1
def get_attribute_values_from_oms(self,attrs): """ """ if not isinstance(attrs, (list, tuple)): raise PlatformException('get_attribute_values: attrs argument must be a ' 'list [(attrName, from_time), ...]. Given: %s', attrs) if self._rsn_oms is None: raise PlatformConnectionException("Cannot get_platform_attribute_values: _rsn_oms object required (created via connect() call)") log.debug("get_attribute_values: attrs=%s", self._platform_id) log.debug("get_attribute_values: attrs=%s", attrs) try: retval = self._rsn_oms.attr.get_platform_attribute_values(self._platform_id, attrs) except Exception as e: raise PlatformConnectionException(msg="get_attribute_values_from_oms Cannot get_platform_attribute_values: %s" % str(e)) if not self._platform_id in retval: raise PlatformException("Unexpected: response get_attribute_values_from_oms does not include " "requested platform '%s'" % self._platform_id) attr_values = retval[self._platform_id] if isinstance(attr_values,str): raise PlatformException("Unexpected: response get_attribute_values_from_oms " "'%s'" % attr_values ) # reported timestamps are already in NTP. Just return the dict: return attr_values
def _set_params(self, *args, **kwargs): """ Issue commands to the instrument to set various parameters @param args: arglist, should contain a dictionary of parameters/values to be set """ try: params = args[0] except IndexError: raise InstrumentParameterException( 'Set command requires a parameter dict.') self._verify_set_values(params) self._verify_not_readonly(*args, **kwargs) # if setting the output rate, get the current rate from the instrument first... if Parameter.OUTPUT_RATE in params: self._update_params() old_config = self._param_dict.get_config() # all constraints met or no constraints exist, set the values for key, value in params.iteritems(): self._param_dict.set_value(key, value) new_config = self._param_dict.get_config() if not old_config == new_config: log.debug('Config change: %r %r', old_config, new_config) if old_config[Parameter.OUTPUT_RATE] is not None: if int(old_config[Parameter.OUTPUT_RATE]) != int( new_config[Parameter.OUTPUT_RATE]): self._do_cmd_no_resp( InstrumentCommand.NANO_SET_RATE, int(new_config[Parameter.OUTPUT_RATE])) self._driver_event(DriverAsyncEvent.CONFIG_CHANGE)
def _register_event_listener(self, url): """ Registers given url for all event types. """ self._verify_rsn_oms('_register_event_listener') try: already_registered = self._rsn_oms.event.get_registered_event_listeners( ) except Exception as e: raise PlatformConnectionException( msg="%r: Cannot get registered event listeners: %s" % (self._platform_id, e)) if url in already_registered: log.debug("listener %r was already registered", url) return try: result = self._rsn_oms.event.register_event_listener(url) except Exception as e: raise PlatformConnectionException( msg="%r: Cannot register_event_listener: %s" % (self._platform_id, e)) log.debug("%r: register_event_listener(%r) => %s", self._platform_id, url, result)
def start_profiler_mission(self, mission_name, src): def _verify_response(rsp): try: message = rsp[mission_name] if not message.startswith('OK'): raise PlatformException( msg="Error in starting mission %s: %s" % (mission_name, message)) except KeyError: raise PlatformException( msg="Error in starting mission response: %s" % rsp) self._verify_rsn_oms('start_profiler_mission') try: response = self._rsn_oms.profiler.start_mission( self._platform_id, mission_name, src) except Exception as e: raise PlatformConnectionException( msg="Cannot start_profiler_mission: %s" % str(e)) log.debug("%r: start_profiler_mission response: %s", self._platform_id, response) dic_plat = self._verify_platform_id_in_response(response) _verify_response(dic_plat) return dic_plat # note: return the dic for the platform
def turn_off_port(self, port_id,src): if self._rsn_oms is None: raise PlatformConnectionException("Cannot turn_off_port: _rsn_oms object required (created via connect() call)") if port_id not in self.nodeCfg.node_port_info : raise PlatformConnectionException("Cannot turn_off_port: Invalid Port ID") oms_port_cntl_id = self.nodeCfg.node_port_info[port_id]['port_oms_port_cntl_id'] log.debug("%r: turning off port: port_id=%s oms port_id = %s", self._platform_id, port_id,oms_port_cntl_id) if self._rsn_oms is None: raise PlatformConnectionException("Cannot turn_off_platform_port: _rsn_oms object required (created via connect() call)") try: response = self._rsn_oms.port.turn_off_platform_port(self._platform_id, oms_port_cntl_id,src) except Exception as e: raise PlatformConnectionException(msg="Cannot turn_off_platform_port: %s" % str(e)) log.debug("%r: turn_off_platform_port response: %s", self._platform_id, response) dic_plat = self._verify_platform_id_in_response(response) return dic_plat # note: return the dic for the platform
def _register_event_listener(self, url): """ Registers given url for all event types. """ if self._rsn_oms is None: raise PlatformConnectionException( "Cannot _register_event_listener: _rsn_oms object required (created via connect() call)" ) try: already_registered = self._rsn_oms.event.get_registered_event_listeners( ) except Exception as e: raise PlatformConnectionException( msg="%r: Cannot get registered event listeners: %s" % (self._platform_id, e)) if url in already_registered: log.debug("listener %r was already registered", url) return try: result = self._rsn_oms.event.register_event_listener(url) except Exception as e: raise PlatformConnectionException( msg="%r: Cannot register_event_listener: %s" % (self._platform_id, e)) log.debug("%r: register_event_listener(%r) => %s", self._platform_id, url, result)
def _construct_fsm(self, states=PlatformDriverState, events=PlatformDriverEvent, enter_event=PlatformDriverEvent.ENTER, exit_event=PlatformDriverEvent.EXIT): """ Constructs the FSM for the driver. The preparations here are mostly related with the UNCONFIGURED, DISCONNECTED, and CONNECTED state transitions, with some common handlers for the CONNECTED state. Subclasses can override to indicate specific parameters and add new handlers (typically for the CONNECTED state). """ log.debug("constructing base platform driver FSM") self._fsm = ThreadSafeFSM(states, events, enter_event, exit_event) for state in PlatformDriverState.list(): self._fsm.add_handler(state, enter_event, self._common_state_enter) self._fsm.add_handler(state, exit_event, self._common_state_exit) # UNCONFIGURED state event handlers: self._fsm.add_handler(PlatformDriverState.UNCONFIGURED, PlatformDriverEvent.CONFIGURE, self._handler_unconfigured_configure) # DISCONNECTED state event handlers: self._fsm.add_handler(PlatformDriverState.DISCONNECTED, PlatformDriverEvent.CONNECT, self._handler_disconnected_connect) self._fsm.add_handler(PlatformDriverState.DISCONNECTED, PlatformDriverEvent.DISCONNECT, self._handler_disconnected_disconnect) # CONNECTED state event handlers: self._fsm.add_handler(PlatformDriverState.CONNECTED, PlatformDriverEvent.DISCONNECT, self._handler_connected_disconnect) self._fsm.add_handler(PlatformDriverState.CONNECTED, PlatformDriverEvent.CONNECTION_LOST, self._handler_connected_connection_lost) self._fsm.add_handler(PlatformDriverState.CONNECTED, PlatformDriverEvent.PING, self._handler_connected_ping) self._fsm.add_handler(PlatformDriverState.CONNECTED, PlatformDriverEvent.GET, self._handler_connected_get) self._fsm.add_handler(PlatformDriverState.CONNECTED, PlatformDriverEvent.SET, self._handler_connected_set) self._fsm.add_handler(PlatformDriverState.CONNECTED, PlatformDriverEvent.EXECUTE, self._handler_connected_execute)
def _handler_disconnected_connect(self, *args, **kwargs): """ Establish communications with the device via port agent / logger and construct and initialize a protocol FSM for device interaction. @return (next_state, result) tuple, (DriverConnectionState.CONNECTED, None) if successful. @raises InstrumentConnectionException if the attempt to connect failed. """ self._build_protocol() try: for name, connection in self._connection.items(): connection.init_comms(self._slave_protocols[name].got_data, self._slave_protocols[name].got_raw, functools.partial(self._massp_got_config, name), self._got_exception, self._lost_connection_callback) self._slave_protocols[name]._connection = connection next_state = DriverConnectionState.CONNECTED except InstrumentConnectionException as e: log.error("Connection Exception: %s", e) log.error("Instrument Driver remaining in disconnected state.") if self._autoconnect: next_state = DriverConnectionState.CONNECT_FAILED else: next_state = DriverConnectionState.DISCONNECTED log.debug('_handler_disconnected_connect exit') return next_state, None
def turn_off_port(self, port_id, src): def _verify_response(rsp): try: message = rsp[port_id] if not message.startswith('OK'): raise PlatformException(msg="Error in turning off port %s: %s" % (port_id, message)) except KeyError: raise PlatformException(msg="Error in turn off port response: %s" % rsp) self._verify_rsn_oms('turn_off_port') oms_port_cntl_id = self._verify_and_return_oms_port(port_id, 'turn_off_port') log.debug("%r: turning off port: port_id=%s oms port_id = %s", self._platform_id, port_id, oms_port_cntl_id) try: response = self._rsn_oms.port.turn_off_platform_port(self._platform_id, oms_port_cntl_id, src) except Exception as e: raise PlatformConnectionException(msg="Cannot turn_off_platform_port: %s" % str(e)) response = self._convert_port_id_from_oms_to_ci(port_id, oms_port_cntl_id, response) log.debug("%r: turn_off_platform_port response: %s", self._platform_id, response) dic_plat = self._verify_platform_id_in_response(response) _verify_response(dic_plat) return dic_plat # note: return the dic for the platform
def _verify_set_values(self, params): """ Verify supplied values are in range, if applicable @param params: Dictionary of Parameter:value pairs to be verified @throws InstrumentParameterException """ constraints = ParameterConstraint.dict() parameters = Parameter.reverse_dict() # step through the list of parameters for key, val in params.iteritems(): # verify this parameter exists if not Parameter.has(key): raise InstrumentParameterException( 'Received invalid parameter in SET: %s' % key) # if constraint exists, verify we have not violated it constraint_key = parameters.get(key) if constraint_key in constraints: var_type, minimum, maximum = constraints[constraint_key] constraint_string = 'Parameter: %s Value: %s Type: %s Minimum: %s Maximum: %s' % \ (key, val, var_type, minimum, maximum) log.debug('SET CONSTRAINT: %s', constraint_string) # attempt to cast val to target type try: val = var_type(val) except ValueError: raise InstrumentParameterException('Type mismatch: %s' % constraint_string) # now, verify we are within min/max if not var_type == bool: if val < minimum or val > maximum: raise InstrumentParameterException('Out of range: %s' % constraint_string)
def _handler_disconnected_connect(self, *args, **kwargs): """ Establish communications with the device via port agent / logger and construct and initialize a protocol FSM for device interaction. @return (next_state, result) tuple, (DriverConnectionState.CONNECTED, None) if successful. @raises InstrumentConnectionException if the attempt to connect failed. """ self._build_protocol() try: for name, connection in self._connection.items(): connection.init_comms( self._slave_protocols[name].got_data, self._slave_protocols[name].got_raw, functools.partial(self._massp_got_config, name), self._got_exception, self._lost_connection_callback) self._slave_protocols[name]._connection = connection next_state = DriverConnectionState.CONNECTED except InstrumentConnectionException as e: log.error("Connection Exception: %s", e) log.error("Instrument Driver remaining in disconnected state.") if self._autoconnect: next_state = DriverConnectionState.CONNECT_FAILED else: next_state = DriverConnectionState.DISCONNECTED log.debug('_handler_disconnected_connect exit') return next_state, None
def _disconnect(self, recursion=None): CIOMSClientFactory.destroy_instance(self._rsn_oms) self._rsn_oms = None log.debug("%r: CIOMSClient instance destroyed", self._platform_id) self._delete_scheduler() self._scheduler = None
def _ping(self): """ Verifies communication with external platform returning "PONG" if this verification completes OK. @retval "PONG" iff all OK. @raise PlatformConnectionException Cannot ping external platform or got unexpected response. """ log.debug("%r: pinging OMS...", self._platform_id) if self._rsn_oms is None: raise PlatformConnectionException( "Cannot ping: _rsn_oms object required (created via connect() call)" ) try: retval = self._rsn_oms.hello.ping() except Exception as e: raise PlatformConnectionException(msg="Cannot ping: %s" % str(e)) if retval is None or retval.upper() != "PONG": raise PlatformConnectionException( msg="Unexpected ping response: %r" % retval) log.debug("%r: ping completed: response: %s", self._platform_id, retval) return "PONG"
def _build_scheduler(self): """ Remove any previously scheduled event, then generate an absolute trigger to schedule the next scan in case we lose some data and the next scan isn't triggered by got_chunk. """ try: self._remove_scheduler(ScheduledJob.TAKE_SCAN) log.debug('Successfully removed existing scheduled event TAKE_SCAN.') except KeyError as ke: log.debug('KeyError: %s', ke) # this formula was derived from testing, should yield a slightly higher time than the actual # time required to collect a single scan. delay = self._param_dict.get(Parameter.AP) / 9 / self._param_dict.get(Parameter.NF) + 5 if delay > 0: dt = datetime.datetime.now() + datetime.timedelta(seconds=delay) job_name = ScheduledJob.TAKE_SCAN config = { DriverConfigKey.SCHEDULER: { job_name: { DriverSchedulerConfigKey.TRIGGER: { DriverSchedulerConfigKey.TRIGGER_TYPE: TriggerType.ABSOLUTE, DriverSchedulerConfigKey.DATE: dt }, } } } self.set_init_params(config) self._add_scheduler_event(ScheduledJob.TAKE_SCAN, ProtocolEvent.TIMEOUT)
def _verify_set_values(self, params): """ Verify supplied values are in range, if applicable @param params: Dictionary of Parameter:value pairs to be verified @throws InstrumentParameterException """ constraints = ParameterConstraint.dict() parameters = Parameter.reverse_dict() # step through the list of parameters for key, val in params.iteritems(): # verify this parameter exists if not Parameter.has(key): raise InstrumentParameterException('Received invalid parameter in SET: %s' % key) # if constraint exists, verify we have not violated it constraint_key = parameters.get(key) if constraint_key in constraints: var_type, minimum, maximum = constraints[constraint_key] constraint_string = 'Parameter: %s Value: %s Type: %s Minimum: %s Maximum: %s' % \ (key, val, var_type, minimum, maximum) log.debug('SET CONSTRAINT: %s', constraint_string) # check bool values are actual booleans if var_type == bool: if val not in [True, False]: raise InstrumentParameterException('Non-boolean value!: %s' % constraint_string) # else, check if we can cast to the correct type else: try: var_type(val) except ValueError: raise InstrumentParameterException('Type mismatch: %s' % constraint_string) # now, verify we are within min/max if val < minimum or val > maximum: raise InstrumentParameterException('Out of range: %s' % constraint_string)
def set_overcurrent_limit(self, port_id, milliamps, microseconds, src): def _verify_response(rsp): try: message = rsp[port_id] if not message.startswith('OK'): raise PlatformException( msg="Error in setting overcurrent for port %s: %s" % (port_id, message)) except KeyError: raise PlatformException(msg="Error in response: %s" % rsp) self._verify_rsn_oms('set_overcurrent_limit') oms_port_cntl_id = self._verify_and_return_oms_port( port_id, 'set_overcurrent_limit') try: response = self._rsn_oms.port.set_over_current( self._platform_id, oms_port_cntl_id, int(milliamps), int(microseconds), src) except Exception as e: raise PlatformConnectionException( msg="Cannot set_overcurrent_limit: %s" % str(e)) response = self._convert_port_id_from_oms_to_ci( port_id, oms_port_cntl_id, response) log.debug("set_overcurrent_limit = %s", response) dic_plat = self._verify_platform_id_in_response(response) _verify_response(dic_plat) return dic_plat # note: return the dic for the platform
def set_init_params(self, config): """ Set initial parameters. Parameters are forwarded to the appropriate parameter dictionary based on name. @param config: Init param config to be handled """ temp_dict = {} self._startup_config = config config = config.get(DriverConfigKey.PARAMETERS, {}) for key in config: target, _ = key.split('_', 1) if target not in self._slave_protocols: # master driver parameter log.debug("Setting init value for %s to %s", key, config[key]) self._param_dict.set_init_value(key, config[key]) else: temp_dict.setdefault(target, {})[key] = config[key] for name in temp_dict: if name in self._slave_protocols: self._slave_protocols[name].set_init_params( {DriverConfigKey.PARAMETERS: temp_dict[name]}) else: # how did we get here? This should never happen, but raise an exception if it does. raise InstrumentParameterException( 'Invalid key(s) in INIT PARAMS action: %r' % temp_dict[name])
def disconnect_instrument(self, port_id, instrument_id): if self._rsn_oms is None: raise PlatformConnectionException( "Cannot disconnect_instrument: _rsn_oms object required (created via connect() call)" ) try: response = self._rsn_oms.instr.disconnect_instrument( self._platform_id, port_id, instrument_id) except Exception as e: raise PlatformConnectionException( msg="Cannot disconnect_instrument: %s" % str(e)) log.debug("%r: disconnect_instrument response: %s", self._platform_id, response) dic_plat = self._verify_platform_id_in_response(response) port_dic = self._verify_port_id_in_response(port_id, dic_plat) instr_res = self._verify_instrument_id_in_response( port_id, instrument_id, port_dic) # update local image if instrument was actually disconnected in this call: if instr_res == NormalResponse.INSTRUMENT_DISCONNECTED: # TODO(OOIION-1495) review. This line was commented out, but the # PortNode.add_instrument/remove_instrument functionality is # being used to keep track of the connected instruments in a port. self._pnode.ports[port_id].remove_instrument(instrument_id) log.debug( "%r: port_id=%s disconnect_instrument: local image updated: %s", self._platform_id, port_id, instrument_id) return dic_plat # note: return the dic for the platform
def _got_data(port_agent_packet): if isinstance(port_agent_packet, Exception): return self._got_exception(port_agent_packet) if isinstance(port_agent_packet, PortAgentPacket): packet_type = port_agent_packet.get_header_type() data = port_agent_packet.get_data() if packet_type == PortAgentPacket.PORT_AGENT_CONFIG: try: paconfig = json.loads(data) self._port_agent_config[name] = paconfig self._driver_event(DriverAsyncEvent.DRIVER_CONFIG, paconfig) except ValueError as e: log.exception('Unable to parse port agent config: %r %r', data, e) elif packet_type == PortAgentPacket.PORT_AGENT_STATUS: log.debug('Received PORT AGENT STATUS: %r', data) current_state = self._connection_fsm.get_current_state() if data == 'DISCONNECTED': self._slave_connection_status[name] = 0 self._async_raise_event(DriverEvent.PA_CONNECTION_LOST) elif data == 'CONNECTED': self._slave_connection_status[name] = 1 if all(self._slave_connection_status.values()): if current_state == DriverConnectionState.INST_DISCONNECTED: self._async_raise_event(DriverEvent.CONNECT) else: protocol = self._slave_protocols.get(name) if protocol: protocol.got_data(port_agent_packet)
def start_profiler_mission(self, mission_name, src): def _verify_response(rsp): try: message = rsp[mission_name] if not message.startswith('OK'): raise PlatformException(msg="Error in starting mission %s: %s" % (mission_name, message)) except KeyError: raise PlatformException(msg="Error in starting mission response: %s" % rsp) self._verify_rsn_oms('start_profiler_mission') try: response = self._rsn_oms.profiler.start_mission(self._platform_id, mission_name, src) except Exception as e: raise PlatformConnectionException(msg="Cannot start_profiler_mission: %s" % str(e)) log.debug("%r: start_profiler_mission response: %s", self._platform_id, response) dic_plat = self._verify_platform_id_in_response(response) _verify_response(dic_plat) return dic_plat # note: return the dic for the platform
def set_overcurrent_limit(self, port_id, milliamps, microseconds, src): def _verify_response(rsp): try: message = rsp[port_id] if not message.startswith('OK'): raise PlatformException(msg="Error in setting overcurrent for port %s: %s" % (port_id, message)) except KeyError: raise PlatformException(msg="Error in response: %s" % rsp) self._verify_rsn_oms('set_overcurrent_limit') oms_port_cntl_id = self._verify_and_return_oms_port(port_id, 'set_overcurrent_limit') try: response = self._rsn_oms.port.set_over_current(self._platform_id, oms_port_cntl_id, int(milliamps), int(microseconds), src) except Exception as e: raise PlatformConnectionException(msg="Cannot set_overcurrent_limit: %s" % str(e)) response = self._convert_port_id_from_oms_to_ci(port_id, oms_port_cntl_id, response) log.debug("set_overcurrent_limit = %s", response) dic_plat = self._verify_platform_id_in_response(response) _verify_response(dic_plat) return dic_plat # note: return the dic for the platform
def _got_data(port_agent_packet): if isinstance(port_agent_packet, Exception): return self._got_exception(port_agent_packet) if isinstance(port_agent_packet, PortAgentPacket): packet_type = port_agent_packet.get_header_type() data = port_agent_packet.get_data() if packet_type == PortAgentPacket.PORT_AGENT_CONFIG: try: paconfig = json.loads(data) self._port_agent_config[name] = paconfig self._driver_event(DriverAsyncEvent.DRIVER_CONFIG, paconfig) except ValueError as e: log.exception( 'Unable to parse port agent config: %r %r', data, e) elif packet_type == PortAgentPacket.PORT_AGENT_STATUS: log.debug('Received PORT AGENT STATUS: %r', data) current_state = self._connection_fsm.get_current_state() if data == 'DISCONNECTED': self._slave_connection_status[name] = 0 self._async_raise_event(DriverEvent.PA_CONNECTION_LOST) elif data == 'CONNECTED': self._slave_connection_status[name] = 1 if all(self._slave_connection_status.values()): if current_state == DriverConnectionState.INST_DISCONNECTED: self._async_raise_event(DriverEvent.CONNECT) else: protocol = self._slave_protocols.get(name) if protocol: protocol.got_data(port_agent_packet)
def disconnect_instrument(self, port_id, instrument_id): if self._rsn_oms is None: raise PlatformConnectionException("Cannot disconnect_instrument: _rsn_oms object required (created via connect() call)") try: response = self._rsn_oms.instr.disconnect_instrument(self._platform_id, port_id, instrument_id) except Exception as e: raise PlatformConnectionException(msg="Cannot disconnect_instrument: %s" % str(e)) log.debug("%r: disconnect_instrument response: %s", self._platform_id, response) dic_plat = self._verify_platform_id_in_response(response) port_dic = self._verify_port_id_in_response(port_id, dic_plat) instr_res = self._verify_instrument_id_in_response(port_id, instrument_id, port_dic) # update local image if instrument was actually disconnected in this call: if instr_res == NormalResponse.INSTRUMENT_DISCONNECTED: # TODO(OOIION-1495) review. This line was commented out, but the # PortNode.add_instrument/remove_instrument functionality is # being used to keep track of the connected instruments in a port. self._pnode.ports[port_id].remove_instrument(instrument_id) log.debug("%r: port_id=%s disconnect_instrument: local image updated: %s", self._platform_id, port_id, instrument_id) return dic_plat # note: return the dic for the platform
def turn_off_port(self, port_id): try: oms_port_id = self.nodeCfgFile.GetOMSPortId(port_id); except Exception as e: raise PlatformConnectionException(msg="Cannot turn_off_platform_port: %s" % str(e)) log.debug("%r: turning off port: port_id=%s oms port_id = %s", self._platform_id, port_id,oms_port_id) if self._rsn_oms is None: raise PlatformConnectionException("Cannot turn_off_platform_port: _rsn_oms object required (created via connect() call)") try: response = self._rsn_oms.port.turn_off_platform_port(self._platform_id, oms_port_id,'CI - User') except Exception as e: raise PlatformConnectionException(msg="Cannot turn_off_platform_port: %s" % str(e)) log.debug("%r: turn_off_platform_port response: %s", self._platform_id, response) dic_plat = self._verify_platform_id_in_response(response) self._verify_port_id_in_response(oms_port_id, dic_plat) return dic_plat # note: return the dic for the platform
def callback_for_alert(self, event, *args, **kwargs): log.debug("caught an OMSDeviceStatusEvent: %s", event) # self._notify_driver_event(OMSEventDriverEvent(event['description'])) log.info('Platform agent %r published OMSDeviceStatusEvent : %s, time: %s', self._platform_id, event, time.time())
def _connect(self, recursion=None): """ Creates an CIOMSClient instance, does a ping to verify connection, and starts event dispatch. """ # create CIOMSClient: oms_uri = self._driver_config['oms_uri'] log.debug("%r: creating CIOMSClient instance with oms_uri=%r", self._platform_id, oms_uri) self._rsn_oms = CIOMSClientFactory.create_instance(oms_uri) log.debug("%r: CIOMSClient instance created: %s", self._platform_id, self._rsn_oms) # ping to verify connection: self._ping() # start event dispatch: self._start_event_dispatch() # TODO - commented out # self.event_subscriber = EventSubscriber(event_type='OMSDeviceStatusEvent', # callback=self.callback_for_alert) # # self.event_subscriber.start() # TODO(OOIION-1495) review the following. Commented out for the moment. # Note, per the CI-OMS spec ports need to be turned OFF to then proceed # with connecting instruments. So we need to determine whether we # want to turn all ports ON in this "connect driver" operation, # and then add the logic to turn a port OFF before connecting # instruments, and then ON again; or, just do the OFF/ON logic in the # connect_instrument and disconnect_instrument operations, # but not here. """
def _set_params(self, *args, **kwargs): """ Issue commands to the instrument to set various parameters @param args: arglist, should contain a dictionary of parameters/values to be set """ try: params = args[0] except IndexError: raise InstrumentParameterException('Set command requires a parameter dict.') self._verify_set_values(params) self._verify_not_readonly(*args, **kwargs) # if setting the output rate, get the current rate from the instrument first... if Parameter.OUTPUT_RATE in params: self._update_params() old_config = self._param_dict.get_config() # all constraints met or no constraints exist, set the values for key, value in params.iteritems(): self._param_dict.set_value(key, value) new_config = self._param_dict.get_config() if not old_config == new_config: log.debug('Config change: %r %r', old_config, new_config) if old_config[Parameter.OUTPUT_RATE] is not None: if int(old_config[Parameter.OUTPUT_RATE]) != int(new_config[Parameter.OUTPUT_RATE]): self._do_cmd_no_resp(InstrumentCommand.NANO_SET_RATE, int(new_config[Parameter.OUTPUT_RATE])) self._driver_event(DriverAsyncEvent.CONFIG_CHANGE)
def _remove_heater_timeout(self): """ Clean up the heater timer """ try: self._remove_scheduler(ScheduledJob.HEATER_TIMEOUT) except KeyError: log.debug('Unable to remove HEATER_TIMEOUT scheduled job, job does not exist.')
def _remove_leveling_timeout(self): """ Clean up the leveling timer """ try: self._remove_scheduler(ScheduledJob.LEVELING_TIMEOUT) except KeyError: log.debug('Unable to remove LEVELING_TIMEOUT scheduled job, job does not exist.')
def callback_for_alert(self, event, *args, **kwargs): log.debug("caught an OMSDeviceStatusEvent: %s", event) # self._notify_driver_event(OMSEventDriverEvent(event['description'])) log.info( 'Platform agent %r published OMSDeviceStatusEvent : %s, time: %s', self._platform_id, event, time.time())
def _common_state_enter(self, *args, **kwargs): """ Common work upon every state entry. """ state = self.get_driver_state() log.debug('%r: driver entering state: %s', self._platform_id, state) self._driver_event(DriverAsyncEvent.STATE_CHANGE)
def _common_state_enter(self, *args, **kwargs): """ Common work upon every state entry. """ state = self.get_driver_state() log.debug('%r: driver entering state: %s', self._platform_id, state) self._notify_driver_event(StateChangeDriverEvent(state))
def _build_override_handler(self, slave, event): log.debug('Building event handler for protocol: %s event: %s', slave, event) def inner(): return None, self._slave_protocols[slave]._protocol_fsm.on_event( event) return inner
def _get_ports(self): ports = {} for port_id, port in self._pnode.ports.iteritems(): ports[port_id] = {'state': port.state} log.debug("%r: _get_ports: %s", self._platform_id, ports) return ports # TODO(OOIION-1495) review the following """
def _build_parsed_values(self): """ @throws SampleException If there is a problem with sample creation """ if self._parameters is None or self._streams is None: self._load_streams() if self.raw_data not in self._streams: raise SampleException('Unknown stream %r' % self.raw_data) self._data_particle_type = self.raw_data parameters = self._streams.get(self.raw_data, []) values = [] for param in parameters: if param in self._ignore: continue p = self._parameters.get(param) if p.parameter_type == 'function': continue log.trace('Generating random data for param: %s name: %s', param, p.name) val = None if p.value_encoding in ['str', 'string']: val = self.random_string(20) elif p.value_encoding == 'int8': val = random.choice(self.INT8_RANDOM) elif p.value_encoding == 'int16': val = random.choice(self.INT16_RANDOM) elif p.value_encoding == 'int32': val = random.choice(self.INT32_RANDOM) elif p.value_encoding == 'int64': val = random.choice(self.INT64_RANDOM) elif p.value_encoding == 'uint8': val = random.choice(self.UINT8_RANDOM) elif p.value_encoding == 'uint16': val = random.choice(self.UINT16_RANDOM) elif p.value_encoding == 'uint32': val = random.choice(self.UINT32_RANDOM) elif p.value_encoding == 'uint64': val = random.choice(self.UINT64_RANDOM) elif p.value_encoding in ['float32', 'float64']: val = random.choice(self.FLOAT_RANDOM) else: log.debug('Unhandled parameter value encoding: %s', p) if val is not None: if 'array' in p.parameter_type and p.value_encoding not in [ 'str', 'string' ]: val = [val] * 2 values.append({'value_id': p.name, 'value': val}) return values
def load_paramdicts(conn): log.debug('Loading Streams') c = conn.cursor() c.execute(STREAM_SELECT) stream_params = map(StreamParam._make, c.fetchall()) paramdict = {} for each in stream_params: paramdict.setdefault(each.name, []).append(each.parameter_id) return paramdict
def load_paramdicts(conn): log.debug("Loading Streams") c = conn.cursor() c.execute(STREAM_SELECT) stream_params = map(StreamParam._make, c.fetchall()) paramdict = {} for each in stream_params: paramdict.setdefault(each.name, []).append(each.parameter_id) return paramdict
def _delete_scheduler(self): """ Remove the autosample schedule. """ try: self._scheduler.unschedule_job(self._job) except KeyError: log.debug('Failed to remove scheduled job for ACQUIRE_SAMPLE') self._scheduler.shutdown()
def _remove_heater_timeout(self): """ Clean up the heater timer """ try: self._remove_scheduler(ScheduledJob.HEATER_TIMEOUT) except KeyError: log.debug( 'Unable to remove HEATER_TIMEOUT scheduled job, job does not exist.' )
def _unregister_event_listener(self, url): """ Unregisters given url for all event types. """ try: result = self._rsn_oms.event.unregister_event_listener(url) log.debug("%r: unregister_event_listener(%r) => %s", self._platform_id, url, result) except (Fault, ProtocolError, SocketError) as e: raise PlatformConnectionException(msg="%r: Cannot unregister_event_listener: %s" % (self._platform_id, e))
def _build_parsed_values(self): result = [] for key, value in self.raw_data.items(): if key == Parameter.ERROR_REASON: continue key = 'massp_%s' % key result.append({DataParticleKey.VALUE_ID: key, DataParticleKey.VALUE: value}) log.debug('STATUS PARTICLE: %r', result) return result
def get_node_eng_data(self): log.debug("%r: get_eng_data...", self._platform_id) ntp_time = ntplib.system_to_ntp_time(time.time()) for streamKey,stream in sorted(self.nodeCfg.node_streams.iteritems()): log.debug("%r Stream(%s)", self._platform_id,streamKey) attrs=list(); for streamAttrKey,streamAttr in sorted(stream.iteritems()): # log.debug("%r %r = %r", self._platform_id, streamAttrKey,streamAttr) if 'lastRcvSampleTime' not in streamAttr : # first time this is called set this to a reasonable value streamAttr['lastRcvSampleTime'] = ntp_time - streamAttr['monitor_cycle_seconds']*2 lastRcvSampleTime = streamAttr['lastRcvSampleTime'] if (lastRcvSampleTime+streamAttr['monitor_cycle_seconds'])<ntp_time : # if we think that the OMS will have data from us add it to the list if (ntp_time-lastRcvSampleTime)>(streamAttr['monitor_cycle_seconds']*10) : #make sure we don't reach too far back by accident or will lastRcvSampleTime=ntp_time-(streamAttr['monitor_cycle_seconds']*10) #clog up the OMS DB search attrs.append((streamAttrKey,lastRcvSampleTime+0.1)) # add a little bit of time to the last received so we don't get one we already have again if len(attrs)>0 : returnDictTemp = self.get_attribute_values_from_oms(attrs) #go get the data from the OMS returnDict = self.round_timestamps(returnDictTemp) ts_list = self.get_all_returned_timestamps(returnDict) #get the list of all unique returned timestamps for ts in ts_list: #for each timestamp create a particle and emit it oneTimestampAttrs = self.get_single_timestamp_list(stream,ts,returnDict) #go get the list at this timestamp ionOneTimestampAttrs = self.convertAttrsToIon(stream,oneTimestampAttrs) #scale the attrs and convert the names to ion pad_particle = Platform_Particle(ionOneTimestampAttrs,port_timestamp=ts) #need to review what port timetamp meaning is.. pad_particle.set_internal_timestamp(timestamp=ts) pad_particle._data_particle_type = streamKey # stream name json_message = pad_particle.generate() # this cals parse values above to go from raw to values dict event = { 'type': DriverAsyncEvent.SAMPLE, 'value': json_message, 'time': time.time() } self._send_event(event) return 1
def get_eng_data(self): log.debug("%r: get_eng_data...", self._platform_id) ntp_time = ntplib.system_to_ntp_time(time.time()) for streamKey, stream in sorted(self.nodeCfg.node_streams.iteritems()): log.debug("%r Stream(%s)", self._platform_id, streamKey) if not (streamKey in self._lastRcvSampleTime): self._lastRcvSampleTime[streamKey] = ntp_time - self.oms_sample_rate*10 if self._lastRcvSampleTime[streamKey]<ntp_time-self.oms_sample_rate*10 : #prevent the max lookback time getting to big self._lastRcvSampleTime[streamKey]=ntp_time-self.oms_sample_rate*10 #if we stop getting data for some reason attrs = list() for streamAttrKey, streamAttr in sorted(stream.iteritems()): # log.debug("%r %r = %r", self._platform_id, streamAttrKey,streamAttr) attrs.append((streamAttrKey,self._lastRcvSampleTime[streamKey]+0.1)) # add a little bit of time to the last received so we don't get one we already have again if len(attrs)>0 : # log.error("%r Request From OMS Stream(%s) Attrs(%s)", self._platform_id, streamKey,attrs) returnDict = self.get_attribute_values_from_oms(attrs) #go get the data from the OMS ts_list = self.get_all_returned_timestamps(returnDict) #get the list of all unique returned timestamps # log.error("%r Request From OMS Stream(%s) Return (%s)", self._platform_id, streamKey,returnDict) for ts in sorted(ts_list): #for each timestamp create a particle and emit it oneTimestampAttrs = self.get_single_timestamp_list(stream,ts,returnDict) #go get the list at this timestamp ionOneTimestampAttrs = self.convertAttrsToIon(stream,oneTimestampAttrs) #scale the attrs and convert the names to ion pad_particle = PlatformParticle(ionOneTimestampAttrs, preferred_timestamp=DataParticleKey.INTERNAL_TIMESTAMP) #need to review what port timetamp meaning is.. pad_particle.set_internal_timestamp(timestamp=ts) pad_particle._data_particle_type = streamKey # stream name json_message = pad_particle.generate() # this cals parse values above to go from raw to values dict event = { 'type': DriverAsyncEvent.SAMPLE, 'value': json_message, 'time': time.time() } self._send_event(event) self._lastRcvSampleTime[streamKey]=ts return 1
def _unregister_event_listener(self, url): """ Unregisters given url for all event types. """ try: result = self._rsn_oms.event.unregister_event_listener(url) log.debug("%r: unregister_event_listener(%r) => %s", self._platform_id, url, result) except (Fault, ProtocolError, SocketError) as e: raise PlatformConnectionException( msg="%r: Cannot unregister_event_listener: %s" % (self._platform_id, e))
def set_attribute_values(self, attrs): """ """ if self._rsn_oms is None: raise PlatformConnectionException( "Cannot set_platform_attribute_values: _rsn_oms object required (created via connect() call)" ) error_vals = self._validate_set_attribute_values(attrs) if len(error_vals) > 0: # remove offending attributes for the request below attrs_dict = dict(attrs) for bad_attr_name in error_vals: del attrs_dict[bad_attr_name] # no good attributes at all? if len(attrs_dict) == 0: # just immediately return with the errors: return error_vals # else: update attrs with the good attributes: attrs = attrs_dict.items() # ok, now make the request to RSN OMS: try: retval = self._rsn_oms.attr.set_platform_attribute_values( self._platform_id, attrs) except Exception as e: raise PlatformConnectionException( msg="Cannot set_platform_attribute_values: %s" % str(e)) log.debug("set_platform_attribute_values = %s", retval) if not self._platform_id in retval: raise PlatformException("Unexpected: response does not include " "requested platform '%s'" % self._platform_id) attr_values = retval[self._platform_id] # Note that the reported timestamps are in NTP. # (Timestamps indicate the time when the value was set for each attribute.) # ret_attr_values: dictionary to return, initialized with the error ones # determined above, if any: ret_attr_values = error_vals # add the info returned from RSN OMS: for attr_name, attr_val_ts in attr_values.iteritems(): ret_attr_values[attr_name] = attr_val_ts log.debug("set_attribute_values: returning %s", ret_attr_values) return ret_attr_values
def get_eng_data(self): ntp_time = ntplib.system_to_ntp_time(time.time()) max_time = ntp_time - self.oms_sample_rate * 10 for key, stream in self.nodeCfg.node_streams.iteritems(): log.debug("%r Stream(%s)", self._platform_id, key) # prevent the max lookback time getting to big if we stop getting data for some reason self._last_sample_time[key] = max(self._last_sample_time.get(key, max_time), max_time) for instance in stream: self.get_instance_particles(key, instance, stream[instance])