#!/usr/bin/env python3 import socket import struct import time import os import sys import signal import argparse from datetime import datetime, timezone # Parameters toutSaveInterval = 60 paramMulticastAddr = "239.0.0.1" paramMulticastPort = 23901 paramMulticastIfAddr = "10.0.0.28" PKT_HEADER = 0x5dac PKT_TYPE_IMU_FLOAT = 0x12 PKT_TYPE_GNSS_PPS = 0x20 PKT_TYPE_GNSS_PVT = 0x21 PKT_TYPE_XXX = 0xf0 dirRoot = 't4-xxxCapture' dirSubDateText = '' dirDataDate = '' datePrev = '' fnameImu = 't4-xxx_imu.txt' fnameGnss = 't4-xxx_gnss.txt' optionQuiet = False optionNoSave = False optionVerbose = False sizeStrageMax = 384 * 1024 * 1024 * 1024 # Global state multicastRecvBuf = b"" strImu = "" strGnss = "" parsePacketTypeImuDataNsec = 0 # UDP socket udps = None def GetStreamLen(sock, n): global multicastRecvBuf while len(multicastRecvBuf) < n: data = sock.recv(65536) multicastRecvBuf += data out = multicastRecvBuf[:n] multicastRecvBuf = multicastRecvBuf[n:] return out def CalcSum(data, sumv): for b in data: sumv += b return sumv & 0xff def ParsePacketTypeImuDataFloat(data): global parsePacketTypeImuDataNsec header, length, sumv, ptype, rsv1 = struct.unpack_from(" ts_nsec: update = True parsePacketTypeImuDataNsec = ts_nsec return s, update def ParsePacketTypeGnssDataPps(data): global parsePacketTypeImuDataNsec update = False header, length, sumv, ptype, rsv1 = struct.unpack_from(" ts_nsec: update = True parsePacketTypeImuDataNsec = ts_nsec return s, update def NetworkInit(): global udps udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) udps.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) udps.bind(("0.0.0.0", paramMulticastPort)) mreq = socket.inet_aton(paramMulticastAddr) + socket.inet_aton(paramMulticastIfAddr) udps.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) def StoreRecvData(s, ddir, fname): if not optionNoSave: if len(s) > 0: os.makedirs(ddir, exist_ok=True) path = os.path.join(ddir, fname) with open(path, "a+") as fd: fd.write(s) def SaveImu(): global strImu if len(strImu) > 0: StoreRecvData(strImu, dirDataDate, fnameImu) strImu = "" def SaveGnss(): global strGnss if len(strGnss) > 0: StoreRecvData(strGnss, dirDataDate, fnameGnss) strGnss = "" def SaveAll(): SaveImu() SaveGnss() def ExitRoutine(sig=None, frame=None): SaveAll() SaveGnss() sys.exit(0) def handle_signals(): for s in [signal.SIGINT, signal.SIGTERM, signal.SIGHUP, signal.SIGQUIT, signal.SIGUSR1, signal.SIGUSR2]: signal.signal(s, ExitRoutine) def parse_options(): global dirDataDate, optionNoSave, optionQuiet, optionVerbose parser = argparse.ArgumentParser() parser.add_argument("--datadir", dest="datadir", type=str) parser.add_argument("--nosave", action="store_true") parser.add_argument("-q", action="store_true") parser.add_argument("--verbose", action="store_true") args = parser.parse_args() if args.datadir: dirDataDate = args.datadir if args.nosave: optionNoSave = True if args.q: optionQuiet = True if args.verbose: optionVerbose = True def main(): global dirSubDateText, dirDataDate, datePrev, strImu, strGnss handle_signals() os.makedirs(dirRoot, exist_ok=True) # dirSubDateText = datetime.utcnow().strftime("%Y%m%d_%H%M") dirSubDateText = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M") dirDataDate = os.path.join(dirRoot, dirSubDateText) datePrevDigit = 8 datePrev = dirSubDateText[0:datePrevDigit] parse_options() NetworkInit() if not optionQuiet: print(f' the data store directory is "{dirDataDate}"', file=sys.stderr) tUpdate = int(time.time()) try: while True: udps.settimeout(0.1) try: c = GetStreamLen(udps, 1) except socket.timeout: c = None if c: if c[0] != (PKT_HEADER & 0xff): continue c2 = GetStreamLen(udps, 1) if c2[0] != (PKT_HEADER >> 8): continue data = struct.pack("= 60: tUpdate = int(time.time()) except KeyboardInterrupt: udps.close() if __name__ == "__main__": main()