diff --git a/python/data/one_msg.bin b/python/data/one_msg.bin new file mode 100644 index 0000000000..f7b985a883 Binary files /dev/null and b/python/data/one_msg.bin differ diff --git a/python/sbp/client/handler.py b/python/sbp/client/handler.py index c8bda8ec35..0f5d8ddc7d 100644 --- a/python/sbp/client/handler.py +++ b/python/sbp/client/handler.py @@ -138,6 +138,8 @@ def run(self): if msg is not None: if msg.msg_type: self.call(msg) + except SystemExit: + break except: import traceback traceback.print_exc() diff --git a/python/sbp/client/loggers/device_iterator.py b/python/sbp/client/loggers/device_iterator.py new file mode 100644 index 0000000000..b2b9eded73 --- /dev/null +++ b/python/sbp/client/loggers/device_iterator.py @@ -0,0 +1,88 @@ +# Copyright (C) 2015 Swift Navigation Inc. +# Contact: Mark Fine +# +# This source is subject to the license found in the file 'LICENSE' which must +# be be distributed together with this source. All other rights reserved. +# +# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +from base_logger import LogIterator +from ...client.handler import Handler +from ...table import dispatch +import calendar +import time +from Queue import Queue, Empty + +class DeviceIterator(LogIterator): + """ + LogIterator + + The :class: `DeviceIterator` provides an abstract interface for reading + from a handle and appending messages to a queue, and reading the queue + in an iterable fashion + + Parameters + ---------- + handler : Handler + SBP handler + timeout : float + number of seconds to block when reading queue before + raising stop iteration + + """ + + def _enqueue(self, msg): + """ + Called with each receipt of the message + Note: dispatch is necessary but perhaps should be handled in handler + """ + try: + data = self.dispatcher(msg) + except KeyError: + data = msg + self.queue.put(data, True) + + def __init__(self, handler, timeout=0, maxsize=0, dispatcher=dispatch): + + self.handler = handler + self.queue = Queue(maxsize) + self.handler.add_callback(self._enqueue) + self.timeout = timeout + self.base_time = time.time() + self.dispatcher = dispatcher + + def __iter__(self): + return self + + def delta(self): + return time.time() - self.base_time + + def timestamp(self): + """ + Timestamp generator. + """ + return calendar.timegm(time.gmtime()) + + def next(self): + """Return the next record tuple from the log file. If an unknown SBP + message type is found, it'll return the raw SBP. If the queue is empty, + It throws the StopIteration exception + + Returns + ------- + (float, float, object) + (elapsed msec since beginning of log, UTC timestamp, msg) + + """ + try: + msg = self.queue.get(True, self.timeout) + return (self.delta(), self.timestamp(), msg) + except Empty: + raise StopIteration + + + + + diff --git a/python/sbp/client/loggers/pickle_logger.py b/python/sbp/client/loggers/pickle_logger.py index a0fa5d50c4..e9b075736b 100644 --- a/python/sbp/client/loggers/pickle_logger.py +++ b/python/sbp/client/loggers/pickle_logger.py @@ -7,7 +7,7 @@ # THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, # EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. - +from ... import SBP from .base_logger import BaseLogger, LogIterator import cPickle as pickle diff --git a/python/tests/sbp/client/test_logger.py b/python/tests/sbp/client/test_logger.py index 6db7536732..52e7c030ab 100755 --- a/python/tests/sbp/client/test_logger.py +++ b/python/tests/sbp/client/test_logger.py @@ -13,9 +13,12 @@ from sbp.client.loggers.base_logger import LogIterator from sbp.client.loggers.json_logger import JSONLogIterator, MultiJSONLogIterator from sbp.client.loggers.pickle_logger import PickleLogIterator +from sbp.client.loggers.device_iterator import DeviceIterator from sbp.logging import SBP_MSG_PRINT +from sbp.acquisition import SBP_MSG_ACQ_RESULT, MsgAcqResult from sbp.table import _SBP_TABLE, dispatch from sbp.table import InvalidSBPMessageType +from sbp.client.handler import Handler import pytest import warnings @@ -151,3 +154,17 @@ def test_msg_print(): assert len(w) == 1 assert issubclass(w[0].category, RuntimeWarning) assert str(w[0].message).startswith('Bad message parsing for line') + +def test_device_iterator(): + """ + device iterator sanity tests. + """ + log_datafile = "data/one_msg.bin" + handle = open(log_datafile, 'r') + myhandler = Handler(handle.read, None, verbose=True) + mydevice_iterator = DeviceIterator(myhandler, 0.5) + myhandler.start() + for delta, timestamp, msg in mydevice_iterator: + assert delta > 0 + assert timestamp >0 + assert type(msg) == MsgAcqResult