#!/usr/bin/python3 """ SmartSource parsing functions. """ import mmap import struct from collections import namedtuple def _str (v): return str(v, 'ascii').strip() def _tstamp (v): return str(v) # TODO def _f10 (v): return float(v)/10 def _ignore (v): return None st_smartsource_header = struct.Struct(">6s 4s 30s 10s 2s 1s 17s 1s 1s 2s 2s 2s 2s 2s 4s 6s 5s 5s 6s 4s 88s") fn_smartsource_header = ( _str, int, _str, int, int, _str, _tstamp, int, int, int, int, int, int, int, int, int, float, float, float, int, _str ) SmartsourceHeader = namedtuple("SmartsourceHeader", "header blk_siz line shot mask trg_mode time src_number num_subarray num_guns num_active num_delta num_auto num_nofire spread volume avg_delta std_delta baro_press manifold spare") st_smartsource_gun = struct.Struct(">1s 2s 1s 1s 1s 1s 1s 6s 6s 4s 4s 4s 4s 4s") fn_smartsource_gun = ( int, int, int, _str, _str, lambda v: v=="Y", _str, _f10, _f10, _f10, _f10, int, int, int ) SmartsourceGun = namedtuple("SmartsourceGun", "string gun source mode detect autofire spare aim_point firetime delay depth pressure volume filltime") SmartSourceRecord = namedtuple("SmartSourceRecord", "header guns") def safe_apply (iter): def safe_fn (fn, v): try: return fn(v) except ValueError: return None return [safe_fn(v[0], v[1]) for v in iter] def _check_chunk_size(chunk, size): return len(chunk) == size def from_file(path): records = [] with open(path, "rb") as fd: with mmap.mmap(fd.fileno(), length=0, access=mmap.ACCESS_READ) as buffer: while True: offset = buffer.find(b"*SMSRC") if offset == -1: break buffer = buffer[offset:] record, length = read_smartsource(buffer) if record is not None: records.append(record) if length != 0: buffer = buffer[length:] else: buffer = buffer[1:] return records def read_smartsource(buffer): length = 0 header = st_smartsource_header.unpack_from(buffer, 0) length += st_smartsource_header.size header = SmartsourceHeader(*safe_apply(zip(fn_smartsource_header, header))) record = dict(header._asdict()) record["guns"] = [] for _ in range(header.num_guns): gun = st_smartsource_gun.unpack_from(buffer, length) record["guns"].append(SmartsourceGun(*safe_apply(zip(fn_smartsource_gun, gun)))) length += st_smartsource_gun.size return (record, length)