Implementierung Protokoll (Gps-Empfänger)
Verfasst: Donnerstag 1. März 2012, 09:22
Hallo @ all,
ich bin gerade dabei das binary Protokoll eines GPS-Empfängers zu implementieren. Oder besser gesagt mache ich mir gerade Gedanken dazu wie es am gescheitesten zu implementieren ist.
Das Protokoll:
Es gibt folgende Typen von Nachrichten: POLL, GET/SET, PERIODIC und CMD (command)
Die Implementierung einer Nachricht würde ich wie folgt vornehmen:
Die Definition des Payloads beinhaltet die Typen für unpack/pack des struct Moduls und die Namen der Attribute.
Die Attributnamen habe gemäß des Protokolls der Übersicht halber so gelassen. Normalerweise hätte ich sie durch einen Unterstrich getrennt.
Die Benutzung sehe dann wie folgt aus:
Das Problem ist die Benutzung der Nachrichten mit einem sich wiederholendem Block. Oben in 3. dargestellt.
Ich habe diesen "repeated block" einfach erstmal aus Übersichtsgründen in die payload Liste geschrieben.
Aber genau hier liegt der Haken. Dieser Block kann sich N'mal wiederholen bzw. auch mehrere Felder enthalten.
Die Frage ist wie ich diesen am gescheitesten zerlege und die Daten in der Klasse kapsel. Bzw. wie kann ich am besten über einen solchen wiederholten Block iterieren.
Hat jemand eine Idee? Oder bin ich komplett auf dem Holzweg.
Ich freue mich auf Feedback.
Gr. Chris
ich bin gerade dabei das binary Protokoll eines GPS-Empfängers zu implementieren. Oder besser gesagt mache ich mir gerade Gedanken dazu wie es am gescheitesten zu implementieren ist.
Das Protokoll:
Code: Alles auswählen
'''
0 1 2 3
|0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7|8|9|0|1|
+-------+-------+-------+-------+---------------+---------------+
| | | | | LENGTH | |
| SYNC1 | SYNC2 | CLASS | ID | Little Endian | Payload Data :
| | | | | (2 Byte) | |
+-------+-------+-------+-------+---------------+ - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+-------+-------+-----------------------------------------------+
| CK_A | CK_B | |
+-------+-------+-----------------------------------------------+
'''
Es gibt folgende Typen von Nachrichten: POLL, GET/SET, PERIODIC und CMD (command)
Die Implementierung einer Nachricht würde ich wie folgt vornehmen:
Code: Alles auswählen
U1 = "B" # XXX
I1 = "b"
X1 = I1
X2 = 'h'
X4 = "i"
R4 = "f"
R8 = "d"
U4 = 'L'
I4 = 'l'
I2 = X2
U2 = 'H'
XX = 's'
RAW = '%i'+XX
class Raw(object):
__metaclass__ = _MyMetaClass # meta msg
__payload__ = ((RAW, 'payload', ''),)
def __init__(self, file, *args, **kwds): pass
def wait(self, timeout=None, exception=None): pass
def send(self): pass
# Beispiel Navigationslösung
class NavSol(Raw):
__whoiam__ = 0x0106
__payload__ = ((U4, 'iTOW', 0), (I4, 'fTOW', 0), (I2, 'week', 0),
(U1, 'gpsFix', 0), # range 0..5; see at gps fix constants
(X1, 'flags', 0x00), # see at status flags
(I4, 'ecefX', 0),
(I4, 'ecefY', 0),
(I4, 'ecefZ', 0), # ECEF X,Y,Z coordinate (cm)
(U4, 'pAcc', 0), # 3D Position Accuracy Estimate
(I4, 'ecefVX', 0),
(I4, 'ecefVY', 0),
(I4, 'ecefVZ', 0), # ECEF X,Y,Z velocity (cm/s)
(U4, 'sAcc', 0), # Speed Accuracy Estimate
(U2, 'pDOP', 0), # Position DOP
(U1, 'res1', 0),
(U1, 'numSV', 0), # Number of SV's used in Nav.-Solution
(U4, 'res2', 0))
Die Attributnamen habe gemäß des Protokolls der Übersicht halber so gelassen. Normalerweise hätte ich sie durch einen Unterstrich getrennt.
Die Benutzung sehe dann wie folgt aus:
Code: Alles auswählen
# open tty com2usb
ttyACMx = open('tty/ttyACM0', 'r')
##########################
# 1: when we got the solution permanently:
##########################
# init the navigation solution:
navi = NavSol(file=ttyACMx)
while 1:
navi.wait(timeout=1)
print navi.ecefX, navi.ecefY, navi.ecefZ
##########################
# 2: send a message and wait for acknowledge
##########################
# kill a config, for exampl. clear the navigation config on the battery bracket rack
cfg = CfgCfg(file=ttyACMx, clearMask=CfgCfg.NAV_CFG, devMask=CfgCfg.BBR)
cfg.send()
# wait for acknowledge in view of sent message:
ack = AckAck(file=ttyACMx)
try:
# if the time is over then raise the given exception ...
ack.wait(timeout=1, exception=Timeout)
except Timeout:
pass # no acknowledge returned ...
# #########################
# 3: get a message with repeated blocks (get the current receiver version):
##########################
message = MonVer(file=ttyACMx)
message.send()
# wait for answering:
message.wait(timeout=1)
print message.swVersion, message.hwVersion, message.romVersion
for block in message.repeated_blocks:
print block.extension
Code: Alles auswählen
class MonVer(Raw):
__whoiam__ = 0x050A
__payload__ = (('30'+XX, 'swVersion', ''), ('10'+XX, 'hwVersion', ''),
('30'+XX, 'romVersion', ''),
('30'+XX, 'extension', '') # <--- REPEATED BLOCK !!!
)
Ich habe diesen "repeated block" einfach erstmal aus Übersichtsgründen in die payload Liste geschrieben.
Aber genau hier liegt der Haken. Dieser Block kann sich N'mal wiederholen bzw. auch mehrere Felder enthalten.
Code: Alles auswählen
__payload__ = (('30'+XX, 'swVersion', ''), ('10'+XX, 'hwVersion', ''),
('30'+XX, 'romVersion', ''),
# START REPEATED BLOCK > :
(U1, 'field1', ''), (U1, 'field2', '') ...
# < END REPEATED BLOCK
)
Code: Alles auswählen
for block in my_message.XXXX:
print block.MyFieldx
Hat jemand eine Idee? Oder bin ich komplett auf dem Holzweg.
Ich freue mich auf Feedback.
Gr. Chris