First commit
This commit is contained in:
288
parser.py
Normal file
288
parser.py
Normal file
@@ -0,0 +1,288 @@
|
||||
"""
|
||||
PGNs verarbeiten
|
||||
"""
|
||||
|
||||
import struct
|
||||
import time
|
||||
from datetime import timedelta, date
|
||||
from . import lookup
|
||||
|
||||
def parse_60928(buf, device):
|
||||
"""
|
||||
Sets data in device and returns the 64bit NAME of device
|
||||
"""
|
||||
device.lastseen = time.time()
|
||||
# 21 bits Unique-ID und 11 bits Manuf.-Code
|
||||
device.uniqueid = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> 3
|
||||
device.manufacturercode = (buf[3] * 256 + buf[2]) >> 5
|
||||
device.instance = buf[4]
|
||||
device.instlower = buf[4] & 0x07
|
||||
device.instupper = buf[4] >> 3
|
||||
device.devicefunction = buf[5]
|
||||
device.deviceclass = (buf[6] & 0x7f) >> 1
|
||||
device.industrygroup = (buf[7] >> 4) & 0x07 # 3bit
|
||||
device.sysinstance = buf[7] & 0x0f # 4bit
|
||||
return struct.unpack_from('>Q', buf, 0)[0]
|
||||
|
||||
def parse_126992(buf, source):
|
||||
# System time
|
||||
print(f"PGN 126992 System time from {source}")
|
||||
sid = buf[0]
|
||||
src = buf[1] & 0x0f
|
||||
dval = date(1970,1,1) + timedelta(days=(buf[3] << 8) + buf[2])
|
||||
secs = struct.unpack_from('<L', buf, 4)[0] * 0.0001
|
||||
print(f" source={source}, date={dval}, secs={secs}, ts={lookup.timesource[src]}")
|
||||
|
||||
def parse_126993(buf, device):
|
||||
# Heartbeat
|
||||
print(f"Heartbeat from {device.address}")
|
||||
print(buf)
|
||||
|
||||
def parse_126996(buf, device):
|
||||
# Product information
|
||||
n2kvers = (buf[0] + buf[1] * 256) / 1000
|
||||
prodcode = buf[2] + buf[3] * 256
|
||||
modelid = buf[4:36] # 256bit modelid ascii text
|
||||
softvers = buf[36:68] # 256bit software version code ascii text
|
||||
modelvers = buf[68:100] # 256bit model version ascii text
|
||||
serial = buf[100:132] # 256bit model serial code ascii text
|
||||
# Füllzeichen entfernen. 0x20, 0xff, '@' für AIS
|
||||
# Die N2K-Bibliothek von ttlappalainen liefert 0xff
|
||||
modelid = modelid.rstrip(b'\xff')
|
||||
softvers = softvers.rstrip(b'\xff')
|
||||
modelvers = modelvers.rstrip(b'\xff')
|
||||
serial = serial.rstrip(b'\xff')
|
||||
# Übertragen in die Gerätedaten
|
||||
device.n2kvers = n2kvers
|
||||
device.productcode = prodcode
|
||||
device.modelvers = modelvers.decode('ascii').rstrip()
|
||||
device.softvers = softvers.decode('ascii').rstrip()
|
||||
device.product = modelid.decode('ascii').rstrip()
|
||||
device.serial = serial.decode('ascii').rstrip()
|
||||
device.certlevel = buf[132]
|
||||
device.loadequiv = buf[133]
|
||||
|
||||
def parse_126998(buf, source, device):
|
||||
# Configuration information
|
||||
# Installation Description 1
|
||||
txtlen = buf[0]
|
||||
if txtlen > 2:
|
||||
device.instdesc1 = buf[2:txtlen].decode('ascii')
|
||||
p = txtlen
|
||||
else:
|
||||
device.instdesc1 = ""
|
||||
p = 2
|
||||
# Installation Description 2
|
||||
txtlen = buf[p]
|
||||
if txtlen > 2:
|
||||
device.instdesc2 = buf[p+2:p+txtlen].decode('ascii')
|
||||
p += txtlen
|
||||
else:
|
||||
device.instdesc2 = ""
|
||||
p += 2
|
||||
# Manufacturer Info
|
||||
txtlen = buf[p]
|
||||
if txtlen > 2:
|
||||
device.manufinfo = buf[p+2:p+txtlen].decode('ascii')
|
||||
else:
|
||||
device.manufinfo = ""
|
||||
|
||||
def parse_127257(buf, boatdata):
|
||||
# Attitude
|
||||
sid = buf[0]
|
||||
yaw = struct.unpack_from('<h', buf, 1)[0] * 0.0001
|
||||
pitch = struct.unpack_from('<h', buf, 3)[0] * 0.0001
|
||||
roll = struct.unpack_from('<h', buf, 5)[0] * 0.0001
|
||||
boatdata.setValue("YAW", yaw)
|
||||
boatdata.setValue("PTCH", pitch)
|
||||
boatdata.setValue("ROLL", roll)
|
||||
|
||||
def parse_127501(buf):
|
||||
# Switch control status
|
||||
# 7 byte for switches every switch takes 2 bits
|
||||
# 0 = Off, 1=On, 2 and 3 unknown
|
||||
instance = buf[0]
|
||||
switch = [0] * 28
|
||||
ix = 0
|
||||
for b in range(1, 8):
|
||||
val = buf[b]
|
||||
for x in range(4):
|
||||
switch[ix] = val & 0x03
|
||||
val = val >> 2
|
||||
ix += 1
|
||||
|
||||
def parse_127502(buf):
|
||||
# Switch control
|
||||
# 7 byte for switches every switch takes 2 bits
|
||||
# 0 = Off, 1=On, 2 and 3 unknown
|
||||
instance = buf[0]
|
||||
switch = [0] * 28
|
||||
ix = 0
|
||||
for b in range(1, 8):
|
||||
val = buf[b]
|
||||
for x in range(4):
|
||||
switch[ix] = val & 0x03
|
||||
val = val >> 2
|
||||
ix += 1
|
||||
|
||||
def parse_127505(buf, boatdata):
|
||||
# Fluid Level
|
||||
instance = buf[0] & 0x0f
|
||||
if instance in boatdata.tank:
|
||||
boatdata.tank[instance].fluidtype = buf[0] >> 4
|
||||
boatdata.tank[instance].level = struct.unpack_from('<H', buf, 1)[0] * 0.004
|
||||
boatdata.tank[instance].capacity = struct.unpack_from('<L', buf, 3)[0] * 0.1
|
||||
print(boatdata.tank[instance])
|
||||
else:
|
||||
print(f"Tank {instance} not defined!")
|
||||
|
||||
def parse_127508(buf, boatdata):
|
||||
# Battery status
|
||||
instance = buf[0]
|
||||
voltage = (buf[2] * 256 + buf[1]) * 0.01
|
||||
current = (buf[4] * 256 + buf[3]) * 0.1
|
||||
temp = (buf[6] * 256 + buf[5]) * 0.01 - 273.15
|
||||
sid = buf[7]
|
||||
|
||||
def parse_129025(buf, boatdata):
|
||||
# Position, Rapid Update
|
||||
lat = struct.unpack_from('<l', buf, 0)[0] * 1e-07
|
||||
lon = struct.unpack_from('<l', buf, 4)[0] * 1e-07
|
||||
boatdata.setValue("LAT", lat)
|
||||
boatdata.setValue("LON", lon)
|
||||
|
||||
def parse_129026(buf, boatdata):
|
||||
# COG & SOG, Rapid Update
|
||||
sid = buf[0]
|
||||
cogref = buf[1] >> 6 # 0: true, 1: magnetic, 2: error
|
||||
cog = struct.unpack_from('<H', buf, 2)[0] * 0.0001 # rad
|
||||
sog = struct.unpack_from('<H', buf, 4)[0] * 0.01 # m/s
|
||||
# 2 Byte reserved
|
||||
boatdata.setValue("COG", cog)
|
||||
boatdata.setValue("SOG", sog)
|
||||
|
||||
def parse_129027(buf, boatdata):
|
||||
# TODO
|
||||
# Position Delta Rapid Update
|
||||
sid = buf[0]
|
||||
dt = struct.unpack_from('<H', buf, 1)[0],
|
||||
dlat = struct.unpack_from('<h', buf, 3)[0]
|
||||
dlon = struct.unpack_from('<h', buf, 5)[0]
|
||||
# 1 Byte reserved
|
||||
|
||||
def parse_129029(buf, boatdata):
|
||||
# GNSS Position Data
|
||||
'''
|
||||
1 sid
|
||||
2 date
|
||||
4 time seconds since midn
|
||||
8 lat
|
||||
8 lon
|
||||
8 alt
|
||||
4 bit gnss type
|
||||
{"name": "GPS", "value": 0},
|
||||
{"name": "GLONASS", "value": 1},
|
||||
{"name": "GPS+GLONASS", "value": 2},
|
||||
{"name": "GPS+SBAS/WAAS", "value": 3},
|
||||
{"name": "GPS+SBAS/WAAS+GLONASS", "value": 4},
|
||||
{"name": "Chayka", "value": 5},
|
||||
{"name": "integrated", "value": 6},
|
||||
{"name": "surveyed", "value": 7},
|
||||
{"name": "Galileo", "value": 8}]},
|
||||
4bit method
|
||||
{"name": "no GNSS", "value": 0},
|
||||
{"name": "GNSS fix", "value": 1},
|
||||
{"name": "DGNSS fix", "value": 2},
|
||||
{"name": "Precise GNSS", "value": 3},
|
||||
{"name": "RTK Fixed Integer", "value": 4},
|
||||
{"name": "RTK float", "value": 5},
|
||||
{"name": "Estimated (DR) mode", "value": 6},
|
||||
{"name": "Manual Input", "value": 7},
|
||||
{"name": "Simulate mode", "value": 8}]},
|
||||
|
||||
2bit integrity
|
||||
{"name": "No integrity checking", "value": 0},
|
||||
{"name": "Safe", "value": 1},
|
||||
{"name": "Caution", "value": 2}]},
|
||||
bit reserved
|
||||
|
||||
1 byte uint numberOfSvs Number of satellites used in solution
|
||||
2byte hdop
|
||||
2 byte tdop
|
||||
4 byte geoidalSeparation
|
||||
1 byte Number of reference stations
|
||||
|
||||
4bit referenceStationType
|
||||
12bit referenceStationId
|
||||
2byte sageOfDgnssCorrections
|
||||
|
||||
|
||||
'''
|
||||
|
||||
def parse_129033(buf, boatdata):
|
||||
# Time & Date
|
||||
gpsdate = struct.unpack_from('<H', buf, 0)[0] # days
|
||||
gpstime = struct.unpack_from('<L', buf, 2)[0] # seconds since midnight
|
||||
offset = struct.unpack_from('<h', buf, 6)[0] # local offset
|
||||
# TODO
|
||||
|
||||
def parse_129283(buf, boatdata):
|
||||
# TODO Cross Track Error XTE
|
||||
sid = buf[0]
|
||||
mode = buf[1] >> 4
|
||||
navterm = buf[1] & 0x03
|
||||
xte = struct.unpack_from('<l', buf, 2)[0] * 0.01 # m
|
||||
# 2 Byte reserved
|
||||
boatdata.setValue("XTE", xte)
|
||||
|
||||
def parse_129540(buf, boatdata):
|
||||
#sid = buf[0]
|
||||
#rrmode = buf[1]
|
||||
nsats = buf[2]
|
||||
# Datensatz je Sat Länge: 12 Byte
|
||||
smax = nsats * 12
|
||||
for s in range(0, smax, 12):
|
||||
prn = buf[3 + s]
|
||||
elevation = struct.unpack_from('<h', buf, s+4)[0] * 0.0001
|
||||
azimuth = struct.unpack_from('<H', buf, s+6)[0] * 0.0001
|
||||
snr = struct.unpack_from('<H', buf, s+8)[0] * 0.01
|
||||
rres = struct.unpack_from('<l', buf, s+10)[0]
|
||||
status = buf[s+14] & 0x0f
|
||||
boatdata.updateSatellite(prn, elevation, azimuth, snr, rres, status)
|
||||
|
||||
def parse_130312(buf, boatdata):
|
||||
# Temperature
|
||||
src = buf[2] # lookup "temperature" (0 .. 15)
|
||||
val = (buf[4] * 256 + buf[3]) * 0.01 # Kelvin
|
||||
if instance == 0 and src == 1:
|
||||
boatdata.setValue("xdrTemp", val)
|
||||
elif instance in boatdata.temp:
|
||||
boatdata.temp[instance].value = val
|
||||
|
||||
def parse_130314(buf, boatdata):
|
||||
# Pressure
|
||||
sid = buf[0]
|
||||
instance = buf[1]
|
||||
src = buf[2] # lookup "pressure"
|
||||
pressure = struct.unpack_from('<L', buf, 3)[0] * 0.1 # Pa
|
||||
if instance == 0 and src == 0:
|
||||
# Generischer Luftdruckwert
|
||||
boatdata.setValue("xdrPress", pressure)
|
||||
if instance in boatdata.press:
|
||||
# Verschiedene weitere Drücke
|
||||
# TODO sensortype "src"
|
||||
boatdata.press[instance].value = pressure
|
||||
|
||||
def parse_130316(buf, boatdata):
|
||||
# Temperature, extended range
|
||||
sid = buf[0]
|
||||
instance = buf[1]
|
||||
src = buf[2] # lookup "temperature" (0 .. 15)
|
||||
val = ((buf[5] << 16) | (buf[4] << 8) | buf[3]) * 0.001
|
||||
# TODO save in global temp data
|
||||
# Konflikt mit 130312?
|
||||
#if instance == 0 and src == 2:
|
||||
# boatdata.setValue("xdrTemp", val)
|
||||
# save in engine data
|
||||
if src == 14 and instance in boatdata.engine:
|
||||
boatdata.engine[instance].exhaust_temp = val
|
||||
Reference in New Issue
Block a user