*_GET-message types confuse parseUBXPayload
I wrote a simple script trying to query some settings of a receiver. However, after sending (for example) a UBX.CFG.PRT_GET message, the UBXManager fails to parse the response correctly.
I traced this error down already to some extent: The root cause is that both UBX.CFG.PRT_GET and UBX.CFG.PRT have the same _id. When initMessageClass initially fills the _lookup-dictionary of UBX.CFG, duplicate keys are partially discarded, only the last key-value is stored, leaving only UBX.CFG.PRT_GET in there.
When parseUBXPayload then tries to look up the subclass from the _lookup-dictionary with .get(msgid), only UBX.CFG.PRT_GET is present.
The issue can be worked around by changing the order of PRT and PRT_GET in the source code (same applies for TP5 and TP5_GET, but explicitly excluding _GET-messages from the list of parseable messages might be a better idea.
Interesting side effect: The Exception message wrongly states "Message not fully consumed while parsing a UBX.CFG.TP5_GET!", even though this should read UBX.CFG.PRT_GET. I did not track down what causes this, but it threw me off first while looking for the root cause of the problem.
Test code:
import serial
import time
import UBX
from UBXManager import UBXManager
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=None)
manager = UBXManager(ser, debug=True)
manager.start()
# query port settings - response triggers bug
time.sleep(1)
prt = UBX.CFG.PRT_GET(b'\x01')
manager.send(prt.serialize())
@thasti If I understand correctly the "addGet" decorator creates a "Get" version of UBXMessage with given _class and _id, so the best way is to pass payload to the UBXMessage init. I managed to do it with:
- extended version of addGet decorator, that inits Get class with payload
def addGetExt(cls):
"""Decorator that adds a Get function to the subclass."""
class Get(UBXMessage):
def __init__(self,payload=b''):
# this only works because class and module have the same name!
_class = eval(cls.__module__)._class
UBXMessage.__init__(self, _class, cls._id, payload)
setattr(cls, "Get", Get)
return cls
#usage
msg = UBX.CFG.PRT.Get(payload=b'\x03')
- modified decorator to accept payload - this is rather static solution, but works for specific configuration
def addGetPayload(payload):
def addGet(cls):
"""Decorator that adds a Get function to the subclass."""
class Get(UBXMessage):
def __init__(self):
# this only works because class and module have the same name!
_class = eval(cls.__module__)._class
UBXMessage.__init__(self, _class, cls._id, payload)
setattr(cls, "Get", Get)
return cls
return addGet
this decorator then is used:
@addGetPayload(payload=b'\x03')
class PRT:
In both cases you'd need to modify decorators for classes in UBX, remove _GET subclasses and import new decorator functions in UBX/CFG (see import lines). Please see if it works for you.