First commit
This commit is contained in:
121
device.py
Normal file
121
device.py
Normal file
@@ -0,0 +1,121 @@
|
||||
"""
|
||||
NMEA2000-Gerät
|
||||
- auf dem Bus erkannte Geräte
|
||||
- für das eigene Gerät steht initUid() zur Verfügung
|
||||
|
||||
"""
|
||||
|
||||
import time
|
||||
import struct
|
||||
from . import lookup
|
||||
|
||||
class Device():
|
||||
|
||||
def __init__(self, address):
|
||||
# WIP: Felder können sich noch ändern!
|
||||
self.address = address # Kann sich zur Laufzeit ändern
|
||||
self.lastseen = time.time()
|
||||
self.lastpinfo = None # Wann letztes Mal Productinfo erhalten?
|
||||
self.lastcinfo = None # Wann letztes Mal Configurationinfo erhalten?
|
||||
self.has_cinfo = True # Weitere Abfragen können verhindert werden
|
||||
|
||||
# Device info
|
||||
self.NAME = 0 # Wird über getNAME (address claim) gefüllt, 64bit Integer
|
||||
self.uniqueid = None # Z.B. aus der Geräteseriennummer abgeleitet
|
||||
self.manufacturercode = 2046 # Open Boat Projects
|
||||
self.instance = 0 # default 0
|
||||
self.instlower = 0 # 3bit, ISO ECU Instance
|
||||
self.instupper = 0 # 5bit, ISO Function Instance
|
||||
self.sysinstance = 0 # used with bridged networks, default 0
|
||||
self.industrygroup = None
|
||||
self.devicefunction = None
|
||||
self.deviceclass = None
|
||||
|
||||
# Product info
|
||||
self.product = None # Product name
|
||||
self.productcode = None # Product code
|
||||
self.serial = None
|
||||
self.modelvers = None # Hardware Version
|
||||
self.softvers = None # Current Software Version
|
||||
self.n2kvers = None # NMEA2000 Network Message Database Version
|
||||
self.certlevel = None # NMEA2000 Certification Level
|
||||
self.loadequiv = None # NMEA2000 LEN
|
||||
|
||||
# Configuration info
|
||||
self.instdesc1 = None
|
||||
self.instdesc2 = None
|
||||
self.manufinfo = None
|
||||
|
||||
# Additional data
|
||||
self.customname = None # User defined device name
|
||||
|
||||
def _ISOtime(self, epoch):
|
||||
if not epoch:
|
||||
return "n/a"
|
||||
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(epoch))
|
||||
|
||||
def initUid(self):
|
||||
# Initialize unique id from raspi cpu id and return 21bit value
|
||||
with open("/sys/firmware/devicetree/base/serial-number", "r") as f:
|
||||
hexid = f.read().rstrip('\x00')
|
||||
return int(hexid, 16) & 0x001FFFFF # 21bit mask
|
||||
|
||||
def getNAME(self):
|
||||
"""
|
||||
NAME is unique on bus
|
||||
Returns bytearray and sets integer NAME for later easy and fast access
|
||||
"""
|
||||
data = bytearray()
|
||||
data.extend(struct.pack('<I', (self.uniqueid & 0x001fffff) | (self.manufacturercode << 21)))
|
||||
data.append((self.instlower & 0x07) | ((self.instupper & 0x1f) << 3))
|
||||
data.append(self.devicefunction)
|
||||
data.append((self.deviceclass & 0x7f) << 1)
|
||||
data.append(0x80 | ((self.industrygroup & 0x07) << 4) | (self.sysinstance & 0x0f))
|
||||
self.NAME = struct.unpack_from('<Q', data, 0)[0]
|
||||
return data
|
||||
|
||||
def __str__(self):
|
||||
out = f"Device: {self.address} : '{self.product}'\n"
|
||||
out += " NAME: {} ({})\n".format(self.getNAME(), self.NAME)
|
||||
out += " last seen: {}\n".format(self._ISOtime(self.lastseen))
|
||||
out += " Device info\n"
|
||||
out += f" Unique ID: {self.uniqueid}\n"
|
||||
out += f" Instance: {self.instance} ({self.instupper}/{self.instlower})\n"
|
||||
out += f" System instance: {self.sysinstance}\n"
|
||||
try:
|
||||
devfnname = lookup.devicefunction[self.deviceclass][self.devicefunction]
|
||||
except KeyError:
|
||||
devfnname = "*key error*"
|
||||
out += f" Device function: {devfnname} ({self.devicefunction})\n"
|
||||
try:
|
||||
devclassname = lookup.deviceclass[self.deviceclass]
|
||||
except KeyError:
|
||||
devclassname = "*key error*"
|
||||
out += f" Device class: {devclassname} ({self.deviceclass})\n"
|
||||
try:
|
||||
igrpname = lookup.industrygroup[self.industrygroup]
|
||||
except KeyError:
|
||||
igrpname = "*key error*"
|
||||
out += f" Industry group: {igrpname} ({self.industrygroup})\n"
|
||||
try:
|
||||
manufname = lookup.manufacturer[self.manufacturercode]
|
||||
except KeyError:
|
||||
manufname = "*key error*"
|
||||
out += f" Manufacturer code: {manufname} ({self.manufacturercode})\n"
|
||||
out += " Product info at {}\n".format(self._ISOtime(self.lastpinfo))
|
||||
out += f" Product Code: {self.productcode}\n"
|
||||
out += f" Product: {self.product}\n"
|
||||
out += f" Serial: {self.serial}\n"
|
||||
out += f" Model Version: {self.modelvers}\n"
|
||||
out += f" Software Version: {self.softvers}\n"
|
||||
out += f" NMEA2000 Version: {self.n2kvers}\n"
|
||||
out += f" Cert-Level: {lookup.certlevel[self.certlevel]} ({self.certlevel})\n"
|
||||
out += f" LEN: {self.loadequiv}\n"
|
||||
out += " Configuration info at {}\n".format(self._ISOtime(self.lastcinfo))
|
||||
if self.has_cinfo:
|
||||
out += f" Installation description 1: {self.instdesc1}\n"
|
||||
out += f" Installation description 2: {self.instdesc2}\n"
|
||||
out += f" Manufacturer info: {self.manufinfo}\n"
|
||||
else:
|
||||
out += " not available\n"
|
||||
return out
|
||||
Reference in New Issue
Block a user