Skip to content

Commit

Permalink
Merge pull request #37 from mookerji/table-and-log
Browse files Browse the repository at this point in the history
Moves JSON and pickle iterators into libsbp.
  • Loading branch information
mfine committed Mar 19, 2015
2 parents a187f0e + 7038d98 commit ed835a4
Show file tree
Hide file tree
Showing 15 changed files with 3,031 additions and 31 deletions.
Binary file not shown.
2,650 changes: 2,650 additions & 0 deletions python/data/serial_link_log_20150310-115522-test.log.dat

Large diffs are not rendered by default.

16 changes: 9 additions & 7 deletions python/sbp/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

def crc16(s, crc=0):
"""CRC16 implementation acording to CCITT standards.
"""
for ch in s:
crc = ((crc<<8)&0xFFFF) ^ crc16_tab[ ((crc>>8)&0xFF) ^ (ord(ch)&0xFF) ]
Expand All @@ -60,9 +60,9 @@ def crc16(s, crc=0):

class SBP(object):
"""Swift Binary Protocol container.
"""

def __init__(self, msg_type=None, sender=None,
length=None, payload=None, crc=None):
self.preamble = SBP_PREAMBLE
Expand All @@ -71,11 +71,13 @@ def __init__(self, msg_type=None, sender=None,
self.length = length
self.payload = payload
self.crc = crc


def __eq__(self, other):
return self.__dict__ == other.__dict__

def pack(self):
"""Pack to framed binary message.
"""
framed_msg = struct.pack('<BHHB',
self.preamble,
Expand All @@ -92,7 +94,7 @@ def __repr__(self):
self.payload, self.crc)
fmt = "<SBP (preamble=0x%X, msg_type=0x%X, sender=%s, length=%d, payload=%s, crc=0x%X)>"
return fmt % p

@staticmethod
def from_json_dict(data):
msg_type = data['msg_type']
Expand Down
39 changes: 38 additions & 1 deletion python/sbp/client/drivers/file_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

from base_driver import BaseDriver
from .base_driver import BaseDriver

class FileDriver(BaseDriver):
"""
Expand All @@ -24,3 +24,40 @@ class FileDriver(BaseDriver):
def __init__(self, filename):
handle = open(filename, "r")
super(FileDriver, self).__init__(handle)

def __iter__(self):
return self

def seek(self, pos, whence=0):
"""
Wrapper around file seek.
Parameters
----------
pos : int
Position of the read/write pointer within the file.
whence : int
Optional and defaults to 0 which means absolute file
positioning, other values are 1 which means seek relative to the
current position and 2 means seek relative to the file's end
"""
self.handle.seek(pos, whence)

def next(self):
"""
Call handle's iterator.
"""
line = self.handle.readline()
if not line:
raise StopIteration
return line

def readline(self):
"""
Readline wrapper: read a line which is terminated with end-of-line
(EOL) character ('\n' by default), or until timeout.
"""
return self.handle.readline()
4 changes: 2 additions & 2 deletions python/sbp/client/drivers/pyftdi_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

from base_driver import BaseDriver
from .base_driver import BaseDriver

class PyFTDIDriver(BaseDriver):
"""
PyFTDIDriver
PyFTDIDriver
The :class:`PyFTDIDriver` class reads SBP messages from a serial port
using the pyftdi driver.
Expand Down
2 changes: 1 addition & 1 deletion python/sbp/client/drivers/pyserial_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

from base_driver import BaseDriver
from .base_driver import BaseDriver

class PySerialDriver(BaseDriver):
"""
Expand Down
41 changes: 41 additions & 0 deletions python/sbp/client/loggers/base_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

from ...table import dispatch
import calendar
import time

Expand All @@ -21,6 +22,7 @@ class BaseLogger(object):
----------
filename : string
File to log to.
"""
def __init__(self, filename):
self.handle = open(filename, "w+")
Expand All @@ -47,3 +49,42 @@ def delta(self):
"""
return int((time.time() - self.base_time) * 1000)


class LogIterator(object):
"""
LogIterator
The :class: `LogIterator` provides an abstract interface for reading
serialized logs of SBP data.
Parameters
----------
handle : File-like handle
Any file-like handle providing SBP messages.
"""
def __init__(self, handle, dispatcher=dispatch):
self.handle = handle
self.dispatcher = dispatcher

def __enter__(self):
return self

def __exit__(self, *args):
self.handle.close()

def __iter__(self):
return self

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 EOF, throws
exception and then returns to start of file.
Returns
-------
(float, float, object)
(elapsed msec since beginning of log, UTC timestamp, msg)
"""
raise NotImplementedError("next() not implemented!")
4 changes: 2 additions & 2 deletions python/sbp/client/loggers/byte_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@

import struct

from base_logger import BaseLogger
from .base_logger import BaseLogger

class ByteLogger(BaseLogger):
"""
ByteLogger
The :class:`ByteLogger` logs SBP messages to bytes.
"""
def __call__(self, msg):
Expand Down
52 changes: 47 additions & 5 deletions python/sbp/client/loggers/json_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,63 @@
# 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 json

from base_logger import BaseLogger

class JSONLogger(BaseLogger):
"""
JSONLogger
The :class:`JSONLogger` logs JSON records.
"""
def __call__(self, msg):
self.call(msg)

def fmt_msg(self, msg):
return {"delta": self.delta(), "timestamp": self.timestamp(), "data": msg.to_json_dict()}

return {"delta": self.delta(),
"timestamp": self.timestamp(),
"data": msg.to_json_dict()}

def call(self, msg):
self.handle.write(json.dumps(self.fmt_msg(msg)) + "\n")


class JSONLogIterator(LogIterator):
"""
JSONLogIterator
The :class:`JSONLogIterator` is an iterator for reading JSON logs
of SBP data.
Parameters
----------
handle : File-like handle
Any file-like handle providing SBP messages.
"""

def next(self):
"""
Return the next record tuple from log file containing
JSON-serialized SBP. If an unknown SBP message type is found,
it'll return the raw SBP. If EOF, throws exception and then
returns to start of file.
Returns
-------
(float, float, object)
(elapsed msec since beginning of log, UTC timestamp, msg)
"""
for line in self.handle:
data = json.loads(line)
delta = data['delta']
timestamp = data['timestamp']
item = SBP.from_json_dict(data['data'])
try:
yield (delta, timestamp, self.dispatcher(item))
except KeyError:
yield (delta, timestamp, item)
self.handle.seek(0, 0)
raise StopIteration
44 changes: 41 additions & 3 deletions python/sbp/client/loggers/pickle_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
# 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 BaseLogger, LogIterator
import cPickle as pickle

from base_logger import BaseLogger

class PickleLogger(BaseLogger):
"""
PickleLogger
The :class:`PickleLogger` logs pickled structures.
"""
def __call__(self, msg):
Expand All @@ -26,3 +25,42 @@ def fmt_msg(self, msg):

def call(self, msg):
pickle.dump(self.fmt_msg(msg), self.handle, 2)


class PickleLogIterator(LogIterator):
"""
PickleLogIterator
The :class:`PickleLogIterator` is an iterator for reading pickled logs
of SBP data.
Parameters
----------
handle : File-like handle
Any file-like handle providing SBP messages.
"""

def next(self):
"""
Return the next record tuple from log file containing
Pickle SBP. If an unknown SBP message type is found,
it'll return the raw SBP. If EOF, throws exception and then
returns to start of file.
Returns
-------
(float, float, object)
(elapsed msec since beginning of log, UTC timestamp, msg)
"""
try:
while True:
delta, timestamp, item = pickle.load(self.handle)
try:
yield (delta, timestamp, self.dispatcher(item))
except KeyError:
yield (delta, timestamp, item)
except EOFError:
self.handle.seek(0, 0)
raise StopIteration
18 changes: 9 additions & 9 deletions python/sbp/client/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
import sys
import time

from ..piksi import SBP_MSG_PRINT
from drivers.file_driver import FileDriver
from drivers.pyserial_driver import PySerialDriver
from drivers.pyftdi_driver import PyFTDIDriver
from loggers.byte_logger import ByteLogger
from loggers.json_logger import JSONLogger
from loggers.null_logger import NullLogger
from loggers.pickle_logger import PickleLogger
from handler import Handler
from ..piksi import SBP_MSG_PRINT
from .drivers.file_driver import FileDriver
from .drivers.pyserial_driver import PySerialDriver
from .drivers.pyftdi_driver import PyFTDIDriver
from .loggers.byte_logger import ByteLogger
from .loggers.json_logger import JSONLogger
from .loggers.null_logger import NullLogger
from .loggers.pickle_logger import PickleLogger
from .handler import Handler

DEFAULT_PORT = "/dev/ttyUSB0"
DEFAULT_BAUD = 1000000
Expand Down
Loading

0 comments on commit ed835a4

Please sign in to comment.