289 lines
9.1 KiB
Python
289 lines
9.1 KiB
Python
"""
|
|
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
|