Beispiel #1
0
    def _validate_GetCD_response(self, response, prompt):
        """
        validation handler for GetCD command
        @param response command response string.
        @param prompt prompt following command response.
        @throws InstrumentProtocolException if command misunderstood.
        """
        error = self._find_error(response)

        if error:
            log.error("GetCD command encountered error; type='%s' msg='%s'",
                      error[0], error[1])
            raise InstrumentProtocolException(
                'GetCD command failure: type="%s" msg="%s"' %
                (error[0], error[1]))

        if not SBE43ConfigurationParticle.resp_regex_compiled().search(
                response):
            log.error(
                '_validate_GetCD_response: GetCD command not recognized: %s.' %
                response)
            raise InstrumentProtocolException(
                'GetCD command not recognized: %s.' % response)

        self._param_dict.update_many(response)

        return response
Beispiel #2
0
    def _do_cmd_no_resp(self, cmd, *args, **kwargs):
        """
        Overridden to handle multiple port agent connections
        """
        connection = kwargs.get('connection')
        if connection is None:
            raise InstrumentProtocolException(
                '_do_cmd_no_resp: no connection supplied! %r %r %r' %
                (cmd, args, kwargs))

        timeout = kwargs.get('timeout', DEFAULT_CMD_TIMEOUT)
        write_delay = kwargs.get('write_delay', DEFAULT_WRITE_DELAY)

        build_handler = self._build_handlers.get(cmd, None)
        if not callable(build_handler):
            log.error('_do_cmd_no_resp: no handler for command: %s' % cmd)
            raise InstrumentProtocolException(
                error_code=InstErrorCode.BAD_DRIVER_COMMAND)
        cmd_line = build_handler(cmd, *args)

        # Wakeup the device, timeout exception as needed
        self._wakeup(timeout, connection=connection)

        # Clear line and prompt buffers for result, then send command.
        self._linebuf[connection] = ''
        self._promptbuf[connection] = ''
        self._send_data(cmd_line, write_delay, connection=connection)
Beispiel #3
0
    def _do_cmd_resp(self, cmd, *args, **kwargs):
        """
        Perform a command-response on the device. Overrides the base class so it will
        return the regular expression groups without concatenating them into a string.
        @param cmd The command to execute.
        @param args positional arguments to pass to the build handler.
        @param write_delay kwarg for the amount of delay in seconds to pause
        between each character. If none supplied, the DEFAULT_WRITE_DELAY
        value will be used.
        @param timeout optional wakeup and command timeout via kwargs.
        @param response_regex kwarg with a compiled regex for the response to
        match. Groups that match will be returned as a tuple.
        @retval response The parsed response result.
        @raises InstrumentTimeoutException if the response did not occur in time.
        @raises InstrumentProtocolException if command could not be built or if response
        was not recognized.
        """

        # Get timeout and initialize response.
        timeout = kwargs.get('timeout', DEFAULT_CMD_TIMEOUT)
        response_regex = kwargs.get('response_regex',
                                    None)  # required argument
        write_delay = INTER_CHARACTER_DELAY
        retval = None

        if not response_regex:
            raise InstrumentProtocolException(
                'missing required keyword argument "response_regex"')

        if response_regex and not isinstance(response_regex, RE_PATTERN):
            raise InstrumentProtocolException(
                'Response regex is not a compiled pattern!')

        # Get the build handler.
        build_handler = self._build_handlers.get(cmd, None)
        if not build_handler:
            raise InstrumentProtocolException('Cannot build command: %s' % cmd)

        cmd_line = build_handler(cmd, *args)
        # Wakeup the device, pass up exception if timeout

        prompt = self._wakeup(timeout)

        # Clear line and prompt buffers for result.
        self._linebuf = ''
        self._promptbuf = ''

        # Send command.
        log.debug(
            '_do_cmd_resp: %s, timeout=%s, write_delay=%s, response_regex=%s',
            repr(cmd_line), timeout, write_delay, response_regex)

        for char in cmd_line:
            self._connection.send(char)
            time.sleep(write_delay)

        # Wait for the prompt, prepare result and return, timeout exception
        return self._get_response(timeout, response_regex=response_regex)
Beispiel #4
0
    def _get_response(self,
                      timeout=10,
                      expected_prompt=None,
                      response_regex=None,
                      connection=None):
        """
        Overridden to handle multiple port agent connections
        """
        if connection is None:
            raise InstrumentProtocolException(
                '_get_response: no connection supplied!')
        # Grab time for timeout and wait for prompt.
        end_time = time.time() + timeout

        if response_regex and not isinstance(response_regex, RE_PATTERN):
            raise InstrumentProtocolException(
                'Response regex is not a compiled pattern!')

        if expected_prompt and response_regex:
            raise InstrumentProtocolException(
                'Cannot supply both regex and expected prompt!')

        if expected_prompt is None:
            prompt_list = self._get_prompts()
        else:
            if isinstance(expected_prompt, str):
                prompt_list = [expected_prompt]
            else:
                prompt_list = expected_prompt

        if response_regex is None:
            pattern = None
        else:
            pattern = response_regex.pattern

        log.debug(
            '_get_response: timeout=%s, prompt_list=%s, expected_prompt=%r, response_regex=%r, promptbuf=%r',
            timeout, prompt_list, expected_prompt, pattern, self._promptbuf)
        while time.time() < end_time:
            if response_regex:
                # noinspection PyArgumentList
                match = response_regex.search(self._linebuf[connection])
                if match:
                    return match.groups()
            else:
                for item in prompt_list:
                    index = self._promptbuf[connection].find(item)
                    if index >= 0:
                        result = self._promptbuf[connection][0:index +
                                                             len(item)]
                        return item, result

            time.sleep(.1)

        raise InstrumentTimeoutException(
            "in InstrumentProtocol._get_response()")
Beispiel #5
0
 def _check_command(self, resp, prompt):
     """
     Perform a checksum calculation on provided data. The checksum used for comparison is the last two characters of
     the line.
     @param resp - response from the instrument to the command
     @param prompt - expected prompt (or the joined groups from a regex match)
     @retval
     """
     for line in resp.split(NEWLINE):
         if line.startswith('?'):
             raise InstrumentProtocolException('error processing command (%r)', resp[1:])
         if line.startswith('*'):  # response
             if not valid_response(line):
                 raise InstrumentProtocolException('checksum failed (%r)', line)
Beispiel #6
0
    def _parse_clock_response(self, response, prompt):
        """
        Parse handler for clock command.
        @param response command response string.
        @param prompt prompt following command response.        
        @throws InstrumentProtocolException if clock command misunderstood.
        """
        log.debug("_parse_clock_response: response=%s, prompt=%s" % (response, prompt))
        if prompt not in [Prompt.CR_NL]:
            raise InstrumentProtocolException('CLOCK command not recognized: %s.' % response)

        if not self._param_dict.update(response):
            raise InstrumentProtocolException('CLOCK command not parsed: %s.' % response)

        return
 def create(self, net, location, station, channel, start, end, rate, calib,
            calper, refdes):
     self.header = PacketLogHeader(net, location, station, channel, start,
                                   end, rate, calib, calper, refdes)
     if not os.path.exists(self.abspath):
         try:
             os.makedirs(self.abspath)
         except OSError:
             raise InstrumentProtocolException(
                 'OSError occurred while creating file path: ' +
                 self.abspath)
     elif os.path.isfile(self.abspath):
         raise InstrumentProtocolException(
             'Error creating file path: File exists with same name: ' +
             self.abspath)
Beispiel #8
0
    def got_data(self, port_agent_packet, connection=None):
        """
        Called by the instrument connection when data is available.
        Append line and prompt buffers.

        Also add data to the chunker and when received call got_chunk
        to publish results.
        :param connection: connection which produced this packet
        :param port_agent_packet: packet of data
        """
        if connection is None:
            raise InstrumentProtocolException(
                'got_data: no connection supplied!')

        data_length = port_agent_packet.get_data_length()
        data = port_agent_packet.get_data()
        timestamp = port_agent_packet.get_timestamp()

        log.debug("Got Data: %r %r", connection, data)
        log.debug("Add Port Agent Timestamp: %r %s", connection, timestamp)

        if data_length > 0:
            if self.get_current_state() == DriverProtocolState.DIRECT_ACCESS:
                self._driver_event(DriverAsyncEvent.DIRECT_ACCESS, data)

            self.add_to_buffer(data, connection=connection)

            self.chunkers[connection].add_chunk(data, timestamp)
            (timestamp, chunk) = self.chunkers[connection].get_next_data()
            while chunk:
                self._got_chunk(chunk, timestamp, connection=connection)
                (timestamp, chunk) = self.chunkers[connection].get_next_data()
Beispiel #9
0
    def _got_chunk(self, chunk, ts):
        """
        Process chunk output by the chunker.  Generate samples and (possibly) react
        @param chunk: data
        @param ts: ntp timestamp
        @return sample
        @throws InstrumentProtocolException
        """
        possible_particles = [
            (particles.LilySampleParticle, self._check_for_autolevel),
            (particles.LilyLevelingParticle, self._check_completed_leveling),
            (particles.HeatSampleParticle, None),
            (particles.IrisSampleParticle, None),
            (particles.NanoSampleParticle, self._check_pps_sync),
        ]

        for particle_type, func in possible_particles:
            sample = self._extract_sample(particle_type,
                                          particle_type.regex_compiled(),
                                          chunk, ts)
            if sample:
                if func:
                    func(sample)
                return sample

        raise InstrumentProtocolException(
            u'unhandled chunk received by _got_chunk: [{0!r:s}]'.format(chunk))
Beispiel #10
0
    def _handler_acquire_status(self, *args, **kwargs):
        """
        We generate these particles here to avoid the chunker.  This allows us to process status
        messages with embedded messages from the other parts of the instrument.
        @return next_state, (next_agent_state, result)
        """
        ts = ntplib.system_to_ntp_time(time.time())
        parts = []

        for command, particle_class in [
            (InstrumentCommand.SYST_DUMP1, particles.SystStatusParticle),
            (InstrumentCommand.LILY_DUMP1, particles.LilyStatusParticle1),
            (InstrumentCommand.LILY_DUMP2, particles.LilyStatusParticle2),
            (InstrumentCommand.IRIS_DUMP1, particles.IrisStatusParticle1),
            (InstrumentCommand.IRIS_DUMP2, particles.IrisStatusParticle2),
            (InstrumentCommand.NANO_DUMP1, particles.NanoStatusParticle),
        ]:
            result, _ = self._do_cmd_resp(
                command, response_regex=particle_class.regex_compiled())
            parts.append(result)
        sample = self._extract_sample(
            particles.BotptStatusParticle,
            particles.BotptStatusParticle.regex_compiled(),
            NEWLINE.join(parts), ts)

        if self.get_current_state() == ProtocolState.AUTOSAMPLE:
            # acquiring status stops NANO output, restart it
            self._do_cmd_resp(InstrumentCommand.NANO_ON,
                              expected_prompt=NANO_STRING)

        if not sample:
            raise InstrumentProtocolException(
                'Failed to generate status particle')
        return None, (None, sample)
Beispiel #11
0
    def _wait_for_sync(self):
        """
        When the instrument is syncing internal parameters we can't stop
        logging.  So we will watch the logging status and when it is not
        synchronizing we will return.  Basically we will just block
        until we are no longer syncing.
        @raise InstrumentProtocolException when we timeout waiting for a
        transition.
        """
        timeout = time.time() + SYNC_TIMEOUT

        while (time.time() < timeout):
            result = self._do_cmd_resp(
                Command.STAT,
                expected_prompt=[Prompt.STOPPED, Prompt.SYNC, Prompt.GO])

            match = LOGGING_SYNC_COMPILED.match(result)

            if (match):
                log.debug("We are still in sync mode.  Wait a bit and retry")
                time.sleep(2)
            else:
                log.debug("Transitioned out of sync.")
                return True

        # We timed out
        raise InstrumentProtocolException(
            "failed to transition out of sync mode")
Beispiel #12
0
    def _handler_autosample_enter(self, *args, **kwargs):
        """
        Handle SatlanticProtocolState.AUTOSAMPLE SatlanticProtocolEvent.ENTER

        @param params Parameters to pass to the state
        @retval return (next state, result)
        @throw InstrumentProtocolException For hardware error
        """
        next_state = None
        result = None

        # Command device to update parameters only on initialization.
        if self._init_type != InitializationType.NONE:
            self._send_break()
            self._update_params()
            self._init_params()
            self._do_cmd_resp(Command.EXIT,
                              response_regex=SAMPLE_REGEX,
                              timeout=30)
            time.sleep(0.115)
            self._do_cmd_resp(Command.SWITCH_TO_AUTOSAMPLE,
                              response_regex=SAMPLE_REGEX,
                              timeout=30)

        if not self._confirm_autosample_mode:
            raise InstrumentProtocolException(
                error_code=InstErrorCode.HARDWARE_ERROR,
                msg="Not in the correct mode!")

        self._driver_event(DriverAsyncEvent.STATE_CHANGE)
        return next_state, result
 def _got_chunk(self, chunk, timestamp):
     """
     The base class got_data has gotten a chunk from the chunker.  Pass it to extract_sample
     with the appropriate particle objects and REGEXes.
     """
     if not self._extract_sample(THSPHParticle, THSPHParticle.regex_compiled(), chunk, timestamp):
         raise InstrumentProtocolException("Unhandled chunk")
Beispiel #14
0
    def __init__(self, prompts, newline, driver_event, connections=None):
        """
        Constructor.
        @param prompts Enum class containing possible device prompts used for
        command response logic.
        @param newline The device newline.
        @driver_event The callback for asynchronous driver events.
        """
        if not type(connections) is list:
            raise InstrumentProtocolException(
                'Unable to instantiate multi connection protocol without connection list'
            )
        self._param_dict2 = ProtocolParameterDict()

        # Construct superclass.
        WorkhorseProtocol.__init__(self, prompts, newline, driver_event)

        # Create multiple connection versions of the pieces of protocol involving data to/from the instrument
        self._linebuf = {connection: '' for connection in connections}
        self._promptbuf = {connection: '' for connection in connections}
        self._last_data_timestamp = {
            connection: None
            for connection in connections
        }
        self.connections = {connection: None for connection in connections}
        self.chunkers = {
            connection: StringChunker(self.sieve_function)
            for connection in connections
        }
Beispiel #15
0
    def apply_startup_params(self):
        """
        Apply all startup parameters.  First we check the instrument to see
        if we need to set the parameters.  If they are they are set
        correctly then we don't do anything.

        If we need to set parameters then we might need to transition to
        command first.  Then we will transition back when complete.

        @todo: This feels odd.  It feels like some of this logic should
               be handled by the state machine.  It's a pattern that we
               may want to review.  I say this because this command
               needs to be run from autosample or command mode.
        @raise: InstrumentProtocolException if not in command or streaming
        """
        # Let's give it a try in unknown state
        log.debug("CURRENT STATE: %s", self.get_current_state())
        if (self.get_current_state() != DriverProtocolState.COMMAND and
                self.get_current_state() != DriverProtocolState.AUTOSAMPLE):
            raise InstrumentProtocolException(
                "Not in command or autosample state. Unable to apply startup params"
            )

        log.debug("sbe apply_startup_params, logging?")
        logging = self._is_logging()
        log.debug("sbe apply_startup_params, logging == %s", logging)

        # If we are in streaming mode and our configuration on the
        # instrument matches what we think it should be then we
        # don't need to do anything.
        if (not self._instrument_config_dirty()):
            log.debug("configuration not dirty.  Nothing to do here")
            return True

        error = None

        try:
            if (logging):
                # Switch to command mode,
                log.debug("stop logging")
                self._stop_logging()

            log.debug("sbe apply_startup_params now")
            self._apply_params()

        # Catch all error so we can put ourself back into
        # streaming.  Then rethrow the error
        except Exception as e:
            error = e

        finally:
            # Switch back to streaming
            if (logging):
                log.debug("sbe apply_startup_params start logging again")
                self._start_logging()

        if (error):
            log.error("Error in apply_startup_params: %s", error)
            raise error
Beispiel #16
0
    def _do_cmd_resp(self, cmd, *args, **kwargs):
        """
        Overridden to handle multiple port agent connections
        """
        connection = kwargs.get('connection')
        if connection is None:
            raise InstrumentProtocolException(
                '_do_cmd_resp: no connection supplied!')

        # Get timeout and initialize response.
        timeout = kwargs.get('timeout', DEFAULT_CMD_TIMEOUT)
        expected_prompt = kwargs.get('expected_prompt', None)
        response_regex = kwargs.get('response_regex', None)

        if response_regex and not isinstance(response_regex, RE_PATTERN):
            raise InstrumentProtocolException(
                'Response regex is not a compiled pattern!')

        if expected_prompt and response_regex:
            raise InstrumentProtocolException(
                'Cannot supply both regex and expected prompt!')

        self._do_cmd_no_resp(cmd, *args, **kwargs)

        # Wait for the prompt, prepare result and return, timeout exception
        if response_regex:
            prompt = ""
            result_tuple = self._get_response(timeout,
                                              connection=connection,
                                              response_regex=response_regex,
                                              expected_prompt=expected_prompt)
            result = "".join(result_tuple)
        else:
            (prompt,
             result) = self._get_response(timeout,
                                          connection=connection,
                                          expected_prompt=expected_prompt)

        resp_handler = self._response_handlers.get(
            (self.get_current_state(), cmd),
            self._response_handlers.get(cmd, None))
        resp_result = None
        if callable(resp_handler):
            resp_result = resp_handler(result, prompt)

        return resp_result
Beispiel #17
0
 def _to_seconds(value, unit):
     """
     Converts a number and a unit into seconds. Ie if "4" and "1"
     comes in, it spits out 240
     @param value The int value for some number of minutes or seconds
     @param unit int of 0 or 1 where 0 is seconds, 1 is minutes
     @return Number of seconds.
     """
     if (not isinstance(value, int)) or (not isinstance(unit, int)):
         raise InstrumentProtocolException("Invalid second arguments!")
     
     if unit == 1:
         return value * 60
     elif unit == 0:
         return value
     else:
         raise InstrumentProtocolException("Invalid Units!")
Beispiel #18
0
    def _parse_battery_response(self, response, prompt):
        """
        Parse handler for battery command.
        @param response command response string.
        @param prompt prompt following command response.        
        @throws InstrumentProtocolException if clock command misunderstood.
        """
        log.debug("_parse_battery_response: response=%s, prompt=%s" %
                  (response, prompt))
        if prompt == Prompt.UNRECOGNIZED_COMMAND:
            raise InstrumentProtocolException(
                'battery command not recognized: %s.' % response)

        if not self._param_dict.update(response):
            raise InstrumentProtocolException(
                'battery command not parsed: %s.' % response)

        return
Beispiel #19
0
 def _handler_leveling_timeout(self):
     """
     Leveling has timed out, disable auto-relevel and mark leveling as failed.
     handler_stop_leveling will raise the config change event.
     @throws InstrumentProtocolException
     """
     self._param_dict.set_value(Parameter.AUTO_RELEVEL, False)
     self._param_dict.set_value(Parameter.LEVELING_FAILED, True)
     self._handler_stop_leveling()
     raise InstrumentProtocolException('Leveling failed to complete within timeout, disabling auto-relevel')
Beispiel #20
0
 def _got_chunk(self, chunk, timestamp):
     """
     extract samples from a chunk of data
     @param chunk: bytes to parse into a sample.
     """
     sample = self._extract_sample(self._data_particle_type, self._data_particle_regex, chunk, timestamp) or \
              self._extract_sample(self._config_particle_type, self._config_particle_regex, chunk, timestamp)
     if not sample:
         raise InstrumentProtocolException(u'unhandled chunk received by _got_chunk: [{0!r:s}]'.format(chunk))
     return sample
Beispiel #21
0
    def _send_data(self, data, write_delay=0, connection=None):
        if connection is None:
            raise InstrumentProtocolException('_send_data: no connection supplied!')

        if write_delay == 0:
            self.connections[connection].send(data)
        else:
            for char in data:
                self.connections[connection].send(char)
                time.sleep(write_delay)
Beispiel #22
0
 def _send_event_to_slave(self, name, event):
     """
     Send an event to a specific protocol
     @param name: Name of slave protocol
     @param event: Event to be sent
     """
     slave_protocol = self._slave_protocols.get(name)
     if slave_protocol is None:
         raise InstrumentProtocolException(
             'Attempted to send event to non-existent protocol: %s' % name)
     slave_protocol._async_raise_fsm_event(event)
Beispiel #23
0
    def _parse_fs_response(self, response, prompt):
        """
        Parse handler for FS command.
        @param response command response string.
        @param prompt prompt following command response.
        @throws InstrumentProtocolException if FS command misunderstood.
        """
        log.debug("_parse_fs_response: response=%s, prompt=%s" % (response, prompt))
        if prompt not in [Prompt.FS]:
            raise InstrumentProtocolException('FS command not recognized: %s.' % response)

        return response
Beispiel #24
0
    def got_data(self, port_agent_packet):
        data_length = port_agent_packet.get_data_length()
        data_type = port_agent_packet.get_header_type()

        if data_type == PortAgentPacket.PICKLED_FROM_INSTRUMENT:
            self._pickle_cache.append(port_agent_packet.get_data())
            if data_length != 65519:
                data = pickle.loads(''.join(self._pickle_cache))
                self._pickle_cache = []
                self._bin_data(data)
        else:
            raise InstrumentProtocolException('Received unpickled data from port agent')
Beispiel #25
0
    def _got_chunk(self, chunk, timestamp):
        """
        Over-ride sieve function to handle additional particles.
        The base class got_data has gotten a chunk from the chunker.  Pass it to extract_sample
        with the appropriate particle objects and REGEXes.
        """
        for particle_class in SBE43HardwareParticle, SBE43DataParticle, SBE43CalibrationParticle, \
                              SBE43ConfigurationParticle, SBE43StatusParticle:
            if self._extract_sample(particle_class, particle_class.regex_compiled(), chunk, timestamp):
                return

        raise InstrumentProtocolException("Unhandled chunk %s" % chunk)
Beispiel #26
0
 def _handler_autosample_stop_autosample(self):
     """
     Handle PARProtocolState.AUTOSAMPLE stop
     @retval return (next state, result)
     @throw InstrumentProtocolException For hardware error
     """
     try:
         self._send_break()
     except InstrumentException, e:
         log.debug("_handler_autosample_stop_autosample error: %s", e)
         raise InstrumentProtocolException(error_code=InstErrorCode.HARDWARE_ERROR,
                                           msg="Couldn't break from autosample!")
Beispiel #27
0
    def filename(self):
        # Get the year, month and day for the directory structure of the data file from the packet start time
        packet_start_time = datetime.utcfromtimestamp(self.header.starttime)
        year = str(packet_start_time.year)
        month = '%02d' % packet_start_time.month
        day = '%02d' % packet_start_time.day

        # Generate the data file path and create it on the disk
        file_path = os.path.join(PacketLog.base_dir, year, month, day)
        if not os.path.exists(file_path):
            try:
                os.makedirs(file_path)
            except OSError:
                raise InstrumentProtocolException(
                    'OSError occurred while creating file path: ' + file_path)
        elif os.path.isfile(file_path):
            raise InstrumentProtocolException(
                'Error creating file path: File exists with same name: ' +
                file_path)

        return os.path.join(
            file_path, self.header.name + '.' + self.header.time + '.mseed')
Beispiel #28
0
 def _handler_autosample_stop_autosample(self):
     """
     Handle PARProtocolState.AUTOSAMPLE stop
     @throw InstrumentProtocolException For hardware error
     """
     next_state = PARProtocolState.COMMAND
     try:
         self._send_break()
         result = ['Autosample break successful, returning to command mode']
     except InstrumentException, e:
         log.debug("_handler_autosample_stop_autosample error: %s", e)
         raise InstrumentProtocolException(error_code=InstErrorCode.HARDWARE_ERROR,
                                           msg="Couldn't break from autosample!")
Beispiel #29
0
    def _validate_GetEC_response(self, response, prompt):
        """
        validation handler for GetEC command
        @param response command response string.
        @throws InstrumentProtocolException if command misunderstood.
        """
        error = self._find_error(response)

        if error:
            log.error("GetEC command encountered error; type='%s' msg='%s'", error[0], error[1])
            raise InstrumentProtocolException('GetEC command failure: type="%s" msg="%s"' % (error[0], error[1]))

        return response
Beispiel #30
0
 def _handler_autosample_acquire_sample(self):
     """
     Fire off a sample sequence while in the autosample state.
     @return None, None
     @throws InstrumentProtocolException
     """
     slave_states = self._get_slave_states()
     # verify the MCU is not already in a sequence
     if slave_states[0] == ProtocolState.COMMAND:
         result = self._send_event_to_slave(MCU, mcu.Capability.START1)
     else:
         raise InstrumentProtocolException(
             "Attempted to acquire sample while sampling")
     return None, None