semuconsulting / pyspartn Goto Github PK
View Code? Open in Web Editor NEWPython library for parsing SPARTN protocol messages.
License: BSD 3-Clause "New" or "Revised" License
Python library for parsing SPARTN protocol messages.
License: BSD 3-Clause "New" or "Revised" License
Main page specify that OCB payload decode is failing where nData < 35 (this is probably due to a misinterpretation of the payload specification).
This is true.
The reason the wrong place of IODE field in OCB messages.
Example for SPARTN-1X-OCB-GPS
:
SF018 should be in the ORBCLK_BLOCK block (that is optionally read if orbit/clock/delay are set) while it is currently read every time because it's after the OCB_SAT_FLAGS block
groupSat": ( # Satellite Block table 6.4
NB + "SF011", # repeating group * num bits set in SF011
{
"SF013": "Do not use (DNU)",
"optSat": (
("SF013", 0), # if SF013 = 0
{
**OCB_SAT_FLAGS,
Remove --------------> "SF018": "GPS IODE",
**ORBCLK_BLOCK,
"optBias": (
...
...
ORBCLK_BLOCK = { # tables 6.5 & 6.6 Orbit and Clock Blocks
"optOrbit": (
("SF014O", 1), # if SF014O = 1
{
Add -----> "SF018": "GPS IODE",
"SF020R": "Orbit radial correction",
"SF020A": "Orbit along-track correction",
"SF020C": "Orbit cross-track correction",
...
...
However as it's type depend on the OCB message (IODE of GPS/GLO/GAL/BDS) I'm not sure the best way to parse it. Either copy-paste the block for each constellation type, or do it differently ?
How to reproduce :
import datetime
from pyspartn import SPARTNReader, SPARTNMessage
msgs = []
key = "930d847b779b126863c8b3b2766ae7cc"
msgs.append(b's\x00\x12\xe2\x08\xd6\xde\x07\xe8[\x11\x88CO\xe7Z\x9e\x91\x85\xd1\x9a\x14t\x7f,\xe1\x0e\xaa\xc9OX\xa5\xf1\x12\xb3\x02\xc0`F\xf8H\xba\xfa\x0c\xda\xee=q\xcd\x00\x057')
msgs.append(b's\x00\x10\xe3\x18\xd6\xdfX\xd8[\x10H\xa8\xff;\xec\xe7>;\x91\xbe\xa4\xa0p0\x1b~\xf3\x8a;N\xb6\xc5b\x9eQ\xbb.>\x98O\x0f\x18\xd7\xc6\xa6\xa0~')
msgs.append(b's\x00\x16i(\xd6\xde\x07\xe8[\x12\xc8\xa8\x94)\xa6)7\xd2\xe5\xdb\x06\xe0\xfaQ\xd0\xc958 \xacw\x14I\x92q\x98\xe2\xe2\xa2\xe0-X\x01Xe\xd1\x14\x18Z8\xae<\xad\x83\xdd\xbe`\xeb')
for msg in msgs:
parsed = SPARTNReader.parse(msg, decode=True, key="930d847b779b126863c8b3b2766ae7cc", basedate=datetime.datetime(2024, 4, 12, 9, 17, 0))
print(parsed)
print(parsed._decode)
parsed_typed: SPARTNMessage = parsed
print()
Manual parsing :
SPARTN-1X-OCB-GPS,
00010100100000000000001000011000001000000110010110010111111101000101101000010010111111011101110011110010010111111011100011011010100010011011011100100101100010010111111101000111101010010010111111100100110110010010010111111011101111101010010010111111011011001011000010010111111100010010000000110000
000101001 SF005 -> 51 -> name of solution
0 SF010 -> 0 -> still more messages to follow
0 SF069 -> 0 -> reserved
0 SF008 -> 0 -> No Yaw (SF021) in all orbits
0 SF009 -> 0 -> Time is normal
00 SF016 -> 0 -> GPS L1C/A band used
00 SF011_A -> 0 -> 32 bits to follow
00000100001100000100000011001011 -> SF011_B -> There will be 9 sat to follow
0010111111011101110011110010010111111011100011011010100010011011011100100101100010010111111101000111101010010010111111100100110110010010010111111011101111101010010010111111011011001011000010010111111100010010000000110000
Sat 6 :
0 SF013 -> 0 -> satellites fields are present
010 SF014 -> 0 1 0 -> Orbit NO, Clock YES, Bias NO
111 SF015 -> 7 -> There has been no discontinuity in the last 320 seconds
Orbit : No orbit (because of flag)
Clock :
111 SF022 -> The data has been using the same IODE since 320 seconds
10100010110100 SF020 -> 10420 == -4.456m of correction
001 SF024 -> 1 == 0.001m of error expected
Bias : No bias (because of flag)
Sat 11
Sat 12
Sat 18
Sat 25
Sat 26
Sat 29
Sat 31
Sat 32
SPARTN-1X-OCB-GAL
0001010011000001000010100111010000000000011100001010000010111111100000100011000010010111110100000000110000010010101101011100001010110010010111111011110101100110110010111110011111101011100010010111110011110110010010010010111110100010010110100010010111110100011011111010010010111110100000010101010010010111111101001000011100010010111110100011110001010010
000101001 -> SF0005 -> 41 -> name of solution
1 -> SF010 -> 1 -> all OCB messages for the epoch were sent
0 -> SF069 -> 0 -> reserved
0 -> SF008 -> 0 -> YAW is not present for any of orbit block
0 -> SF009 -> 0 -> normal date reference
001 -> SF096 -> 1 -> Ephem of type Galileo I/NAV
00 -> SF093_A -> 0 -> 36 bits to follow
001010011101000000000001110000101000 -> SF093_B
sat 3
sat 5
0 -> SF013 -> 0 -> sat fields present
010 -> SF014 -> orbit = 0, clock = 1, bias = 0
111 -> SF015 -> 7 -> Maximum continuity
Orbit : No orbit
Clock :
111 -> SF022 -> 7 -> IODE maximum continuity
10000010001100 -> SF020 -> -140 == -0.28m of correction
001 -> SF024 -> 1 == 0.001m of error expected
Bias : No bias
sat 8
sat 9
sat 10
sat 12
sat 24
sat 25
sat 26
sat 31
sat 33
Decryption of SPARTN-1X-OCB-GLO doesn't seem to be correct. The output result looks random (not a single field looks correct)
It looks to be related to the ambiguity resolution as SPARTN-1X-OCB-GLO are the only messages with 16 bits GNSS time tag defined in GLONASS epoch (rather than being 32 bits with no ambiguity or defined in GPS epoch)
Ideally a parameter of one of the function in the chain should specify if GPS time needs to be used or GLONASS
I'm not sure how to solve it cleanly for now but I'll think about it and try to come with a proposal (or maybe @semuadmin has an idea on how to do that properly)
def convert_timetag(timetag16: int, basedate: datetime = datetime.now()) -> int:
...
...
base16 = datetime(basedate.year, basedate.month, basedate.day, 0, 0, 0)
secs = timetag16
if basedate.hour >= 12:
secs += 43200
time16 = base16 + timedelta(seconds=secs)
return date2timetag(time16)
Code to reproduce :
import datetime
from pyspartn import SPARTNReader, SPARTNMessage
msgs = []
key = "930d847b779b126863c8b3b2766ae7cc"
# msgs.append(b's\x00\x14h\x04\x120[\x11\x08(\x18\x14&\x98\x9e|\xdaz\x14\x01\xc0\xa5HS\xbc\xdb\xba\xc7\xcd\x83VuQ\xa5O\xc6\xc8]G\xe8\xc6t\xbcX\xd79\xe1*6\xa9\xfe\xc2')
# msgs.append(b's\x00\x0e\xec\x10\x1d [\x1e\xc8\xd6_\xf6q\xb8\x94\xdfja\x7fLh\x94\x89#G9\xbd%\xdfi\x15B\xc6\xe6y\xb3V\t\x04D)')
msgs.append(
b's\x02\xb8j\x18\xd7)+p[\x10\x88\x04\xcf\xe7\xb3\xec\xf2l\xc1\xd9J\xd2qj\xc4\x8fW[\\\x08\x87\xe4\xa0\xb1\x1c\xb3\x96\xfc\xdci\x07\xf2\xf5\'5\t\x7f\xd0.\xe42\x0c\x0b\xb8\xd9r|\x8b\xcf\xd8c\x02\xe8t~\xfayqJHVU\xb9D\x1b\x02\xe1\xedK\xb6%p\xf1Z\xc2y+$M\xf9\xad\xa1?\xcb\xde6\xc0\x99\x02)\x7f\xde\xb1\xc85\xc7\xab\xc0x\x9f(\xc3K\xe66\xa0c\\4d\xf6\xb0\xaf-\x10x\x06\xa7\xadGl4\xec\xe6_\xa5;\xde\x12\xb4_\xdd\x10\x83J\xfb\xf6!\xf5]\xeaR\x08\x06)\x9fg\x03${\x10\xefVR+\xa7d=\x8d\x97U\xe7\x88\xc7\x01&\xccD#j\x19d\x87\x92">\xcb\xdaOET\xbfL\xfc\x8bQ{\xca\xb9\x89\xae\xe0\xd6\x7f\xcf\x154\n\xe7\x87Bau\xb5\xf3&\xcb\x8dp\xbbi\xcck\x99\xf4\xdfq\xd5\xa4\x85U\xb8\xb0NE\x8eO\x1a\xc9\xf6\xf3\x95\xcc\xc7\xe0\xa5~\x97\r\xca\x954.\x0e\x0c5\xfc\x011\xdbc\x8d\x1e\x8d\x84>\x07\x0cL\x87\xc9\xec\xa5\xecBo\xce\xc13:\xcd\x83\x824~\xd05\xa3\xcaL\xb1M\xc3d\xba\xe0ob\xceC\xf3\xa8Vw\xaakJ\xd8dT\x83D\x03g\xad\x04\xb0s\x90!BJ\xa8zh!\xa5\xe1\xffiYb\xf3\x16\x18\xbd\xca,\xe8v\xff\xf6gLq\xeb\xbf\xe0\x02c\xf0\xa8\xf9\xd3\x11\x07\x9f\x1a\xc3\xd4\x867\x89\xf1\x0e\xe6\x99\xf3\x06\x87\x1e-m\xd4\x9a\xf1\xec\r\xf2\xb4P8')
msgs.append(
b's\x02\x9d\xeb\x18\xd7)+p[\x11\x08P\xe3T\xd7\xbe5\xd9Q\x86\x95\xc2\xe3x\xbdK\x8aF)\xdf\xe7\xe3\xf7H\x076G\xab\xa9:\xa1\xc0\xd5;\xd2}t\xbc\x80\xe5\x88\xc0\xa7\xba7\xb93\xc0\xc7\xab\xfd,@\xe5\x9f\xff6\xae\xac\xe8-,U(\xdf[\xe4\x0c\xa3d%l\x8a\xdb\xfd\xa2e\xc1\xbeR\x1c\xa2\x10\x01\rNJ\xd4-Z\x17}\xf2O\xf6\xb4\x1fH\xf3\xd2T\x12\xe2W\x13\x12@\xdf\x8a\x16\x85S\x10{{\x97\xbej$\xb5@\x98\xd3\xaf\x90\xee\xe2.\xef\x82\x1c\xca\x9f\xf80\x9a(\xbe\xe2\x97\xcf\x85\xa8\x98\xccy{R.\xe1\x0fa\xdcX\x02\x80\x18\xe0\xc7\xd6\xd9s\xf6\t\x1b.T\xb0z\xaa\x82\x1d\xb2\x0bu\x1b\xd5\x04E\xb6\xaa\xe3\x1b\xbc\xc91\x9c\xa9\xd8\xefA\xa2Z\xf8\xe9T\xc1{\xa6\xf2Rz|1/;\xbd\xf2+\xf6Y\x10\xa6O\xcd\x8b\xe7\x13\xabO\xf4d\x05\x8e&\xe8\xdaQ\xd9\xban:p\xb8\xe9\x12\xe5":\x82\xf6v4\x8e\xf6?\x05\xd6\\Hf\x9d\x85\x04\x93L\x07\xde)\xa0\xaf\x06\'\xae*1\xc7\xbb\xdcoWL\x02\xed&\xf7\x94v\xcdZ\xa4>\xf5\x90%3\xdf\x13\xe8y\x14y\x9d\x7f\xe3G\x95\x84R\x0fa\xb6\xbeP\xe4U,\xd8A+\xef-\xa0A>\xea\xb5\xdaM')
msgs.append(
b's\x02\x97\xee\x18\xd7)+p[\x11H\xef\x15K\xc1\\\x10\rQ\xaa@\x12\xea\xb59=\t\x03\xca\xf5\xd7\t\xae\n\xae\x9a.|<\x8b\xf3r"N\x18I\xc98\x01\x15\xfa\x0f\xb5\x91\xe7%Ph\t\x93\xb41\xe3\xcc\x89\xf6\xcb\x9a\xe2\xb9|\x82?%$\x06\xe6\xfc\xfd\n\xd7\xdd\\\xdapV\xf5\xc8\x8a\x8a-0\xb4\xf5\x8d;\xbd\xcf7\xa8.3\x1aTe\xdc\xf9\xa9\xee!3Z\xe8X\x106\xebw\\J;\xf1\xdd;\x9c\x14"\xf1mj\xf9\xc4Nkpb&\x1f\x15\xb9\x1a|\xd3u\xf9\x1e\xa0\x8cq\x0c/\xe4\xa8\xfd\x10\xa8DQ\xfcTOU8j\xeeq\x15\xf6\x84w\x1c\x9f\xa2H\x84:\x88c#~p\xf03&\x0e\xdd5$\x98\xce&(\xd4\xd1@M\x83i\xe9\xd9\x9a\xaf\xca;K\xbe\xc5ZDAO\xe3\x02Q)\xd2/\xff\x06\xe2v!\x17\x9a\x00\xffW\x03\xcaV\xfe\x03kCA`\x05\xf1"\xb3X/%\xc6\x8cI\xbd\x91:\xd3ht1\x00^\x1d6}\xd1\x8e\xcbE\xb4\xce\xf1\xdeq,\x97<fT\xe25n\xce@\t\xd1\xd5m>I\x82xU\x82\x1b\xa6\xc3\x07\x82jm\x80p_\x10\x06\xc4EupT\x86cIk\x0b\x16\xf3h\xc6\xc0\xb6\xe0D')
msgs.append(
b's\x02\xabj8\xd7\'\xda\x10[\x1f\xc8\xd1\x07\xfb\xde\x1a\x08\x90\\{\x7f;\xa1\xe5+2@y{\x89\xca\xad\x8a\x9f\x8fu\x8ahrCm\xae\xdb\xbdh\xac\x9a/\xfcb\x8eH\xcdE\xf1\x17#\xd1E&\x17\x87\xb5\x06\xcb\xddW\xea(\xbe\x19c\x0f`\xf7%\x82\xdf\x84\x8f\xbb<\xdb\xf1\xbeV\x86)\r\x95\x08\xe6\x12|\x83_\xea\xe7\x04$\x18\x86\x0f\x83\xef\x1f\xcc`V\x8a-\xe8\xdd\xf9\xceW\x1f\xc2\xc4"\x8c;\xf6;\xb5\xbf\xe3G(\xd4\xc5kT\x8f\xdb\xb1\xfap\xa0\xd3\xe3\xb2[ \x8a\x7f*\r\xc3\x05\xa4\x80)A\x05\xd1^\xd6\x87\x9e\x86\xfcH\xce\xa5\xd5\xbe{4\xa9\xaa?G\xdc\xc8\x89c2s\xccR\x90\xc2<\xf3\xf2\x13\xb0\xdc%>q\xc38\xf3 \xd4}\xfcST\xb8\xa9\xbb\xd2\x0fw\x156-5\x11#\xc3\xac\xf9\xe4\xf4\xe4\xdbU\x13\xb7\xc5\xdc\x9b\xca\xf3\xee\x0b!\x9aI\x1bP}\xc2\xcd+\x9b\x96{\x91\xcbL\x84T\xdb\t,\xcf\xa7\x9f\x93\x9b\x8d\x93\xb99\xbb\xd2\\;\xb5x\xc7\x9f%F\x95wzX\x01\x1d\x80\x15\xe0|Ix%\xe8\x90\xe3ps\x1f\x8e\x90+\xa5\xbfXB(\x85\xde\xb1\xffY\xe0N\xc2~\xb1\x01\xed\xd2\xe6\x00\x9c]\x9f%\x84\xcbB\xbf\x89\xb4\xda\x8b\xf6/\xaa\t\xc5\xb5\xe2&\x1e\xcdk\xe2r\x11\xf0\x0cz\x9b\xa9v\x99\xe0~\x8d\xf5W\xde\xcf\n\xac{\x88\x0e')
msgs.append(
b's\x02\xc8\xee8\xd7\'\xda\x10[\x10\x08<uA)]O\xe24\x95\xbd)\x05\x9e)\x02M\x16\xb2\xdd\xbe\x1c\xce\x15\x0b\x03\xc2\xb1\x8e"\xcd\xd1\xce0\x8di}\xc5$\x8ezd\xc6\x83]QO\xbf\xf44\x95\nv\xb0\x16\xec\xc1\xc3\xc0\x9d\x95\xdc\x9cR\x07l\xda\xc8\x05{\x18|\x11\x81\xdc\x1c\x84\x14\x91\x87\xba\xbc\x05L\xa4\xaa\xed\x8d\rsfqOh\xd7\x17b\x92w\x13\x959\x9cT\x8d\xd7\x0f\xd4\xb0/\x8a\xcfH\xe9\xce\xd0\xd3\x0e\x85R\xb9N7\x18Q\xddK\xb2z\xe5\xc5\xef\x82\x06\x9b\x94\x0c\xa8Sl\xe6\xb0QN\xe7\xd0Y\xab\x8f\x03\xa9n \r\x0f`\xe3\xfd*\xcbN\xe3\x08\x08\x0c\xb5\xb7h:\x06\xe1\x98\xc6At\xdah\xcd\xd7JC\xe9\x0f\xca\xd8\x96\xcc\xd08\xdb\xabw\xa4\xa7+c\xff\x8b\x056\x98\xf1\xca\x19l\x04V!p\xe2\xf3K\xaf\xe2b\xae\x9f\xd3@\xcc\x8fM"n\xc6_9\xdf\x01\ta\xba3\xf1G\x17?\xbd\x8d\xc0\xf6\xb4#\xccRe\x8e<\x1c\xa8\xcc\x02\x11\x89\x18Z\xdd\xca\xdcms\x82\xbak\xf3P\x08y\x12a\xd2$\x9cn\xc2*6/\xc6(Ksc\xaf1\xb8k\xb9\'\xd0\x84\xee\x1b\x82^\xcdG\x10\xf1\xe8\xe5\xb8\x88\x81\xe7y\xbfZ\xa9\xb9"\xf1LpL\xb2\x06\xf9\x95O\xef\xf63\xe19\xb9\xe9\xa2\xe5\xba\xa7\xd7j\xbd\xdf1y_\xbe\xcc+\x936\x94;U"\x81\xac\x83_\xd7\x8b\xb9\xdb\x1e\x06\xbd\xcf\xd5pz\x8cS\xcb\xcb\xf1\x96\x04\xf5jUJ\xc9G\x83\xf6\xces\xc7\xad\xf1=\x00\xbe\x91\x134\xa9\xf3\x07M\x1d@aUPJ5z\x06\x9e\xcdv%')
msgs.append(
b"s\x02\xce\xed8\xd7'\xda\x10[\x10\x88'\xe1\t\x8b\xdbq\x0c/\xc7\x88`\xd5\xe3\xb5\x90(C\xc3\xd9\xc2/:\xaa\x81\xd187i\xa5}\x03\xfe\x1e\xb6'\x15{c\xbdLr\x8b)\x1d[\xf4\x1fu\xce\xf3\xdc\xe3%\x00v\xc7\xc5\x986\xc9l\xd6\xe7\xec\x8e\xa5\x8f=\x89\xf1[C\xa9,B\x12\x97\xe7\xc4\xady\x13M\xc5XI\x8fV\xf3\x7f\xee:u\x1d}ORN\x97\x80\xb7\xcap\tgr\x06\xa7\xfc/NE6\x816\xd5\xb74.\r\x92\xb1\x8e\xf1n\xca\xa3$\xab\xee\x11\xec\n\xcc\x1d\x8f\xe6\x1d\x1b\xbe\xd97CQ\xca\xf7\xf78\xa0\xb5\x91\xfe\xa0\xdbv(@\x15A\x88\xe6\x92\xc3\xd4\x80\xbc\xd0sv\xf2P\x8a*:'\xc1\xa0'\xde\xed\xdb\nl\xcdm\x0f\x97\x15Z\xd3X[\xdd\x05\xe8Q\x96\x01q\xdb\xd1\x8cgI\xe1~5Y\xd8\x82\x9b#\xaa\xe6\xe9\x01\xf9\x0f\x15f)\xee\x03_s\xdb\xdeWh\xa9;\xbeC\xf4\xa2\xb5U\xe9\xf5\r\x1f,q\x8co\x9a\xef\x7f\xc9\x8e\xf7\xbe\xb6Rg\xe3\x99\xa3J\xf8.\x94]U\x9d\x1f\xa9F:\x93\xca\xce)\x92hF\xa9[!\x08\xf6\xce\xdfO`\xfe'\xad5\xa33\xda\x8aq\x80\x92\xdb\x06r\xc4S:\r\x13d$\xa8\x1e\xc8b\xbb\xed\xd9\xfaC\xb3\xee\xc0~<\xaa\x044Q\xca!>\xfe>\x84E\x8a\xf4*\x19\xb9X\xe9\x9c\x1b{\x95\x13\x1b$v\x045hy21\xa8D\x06\x9f7\x7f\xbf\x1b\x95\xd8\xea]-\xc7mM[\x85*\x10\xfc\xff\x1d\x87s\x82k\x92\xf02\xb6\xd0\xb7\xe5\xe4*\x92\xb1R\x90\xb4\xc3\x07\r\xda-$\xe2\xd4:\xe7\x95\x03\x02\x16/\x82o\x8ag\xc6\xdbz\xe8")
msgs.append(b"s\x02'`8\xd7'\xda\x10[\x10\xc8\xb8\xf0\x1b\xe6\xba\xc9:\x1a\xb6{\xae$cf\\k3\xed\xec\xac\xc4T\xad{\xbe:/7\x0b\x89zHa\x14\x91\xdfJ\xc3(\\\xad\x14\xc5I\x9d|\x8c\xc6\xd1\x97\x0fW\xd34\xa7\xf8\xcb\x1a\x1c\x0c6wT7:g\xfdineJ\x18\xb0\x8c\xb3\x96\x92u$\xf3\xd9")
msgs.append(
b's\x02\xeb\xe5(\xd7\'\xda\x80[\x10\x08\x84\xc4\xf4\xb5r\x17\xb9e\x82\x9c#J\xe7|;\xce;NZ\x93\xf3\x80\x9c\xc7s\x1dG\xdc\xde\xfc\x92j\xe4-R\xb7\xcb\xac\x14\xff\x04`_xI\xdd\xb72\x06SC{c\x9e_R\x8e\x17\xfa\xf3r\x0b.\x9aC\xffr\x8dJ)\xeb\xb0Ik\x8d\xe5:\x8dU\xb7\x8f\xe4\x99\xeeD*\xc4\xf5\xbd\xb7-\xa4B\x11TV\x93%\xf3\xd9\xecLw\xca\xb7f\x8e\xe5\x1dq\xd8\xaeIY\xde\xeeRO\xd4\xb5\x86\xa7\x18\xe6 \xee\x9c\xb5&\xeee\xbb\xeb1\xa5\xadJ\x93\xbah \xbe\x92\xfc\xfa\xeb\xa0X\xa7\x89\x81\xe9\xbeJ\x91\xfa8j\xa4\xb6\xc2\xb0\xed\xban)L\xd3\x96\xe9 2?&\xe9w\x11\x8e;\xeb]<FX*\xc5D{\xb4\xc1p\xaf\tE\xbd\x19\xa4) \x9d[\t6\xc1`\xfa=T\xeeo\xd3Q\xdet\xecs\x9c|e\xa5\xdc\xe7Qx\xb4S\xb9\x0fU\xfaS\xb3\x0c\xdf\xe0\x04\xf7\x89<"\xd2\xb8\xcc\x0b\xa5\xbb\xa0\xa21T\x88\x1d\x07h\x01\x15\xbb\xe7<\xee{F\xb3t\xed\x06\xd1\xe5\x9c\xb8\xba_\xb0uZ\xca\xd3\x91"\xc0mB-\xff\x18\xde\xda$\xe7\xc1LX*\xe0.\xf6\x91@\xfd\x8cCx\xed\x87\x0e\xa7{\xf5[g\x15<\xd8\xd9j\xfd\x967\xf0\x83\xe7Y#C2\xde\xb4\xe1\x06\x16\xf3\x94!\xf9:\x12S\xb0\xae\xdf-\x01U\x0e\xf8\xc8\xae\xae\xec\xeaT\xc4\xf3[\x11\x00l\x1e\x95\xaf\x00\x81\x7f\xda\xee\x08\xcdLw[\xe6TLe\xa2\xff\x08\r\x91(\xfcf\x9d\xc6<\xc29\xc6\x83\xb3tB\x95R\xf3\xe5\x89\xc4\x9d\x8e\x99\x1cj^\xa8\xc1\xe0x1=\x01\x14\xf1\x88\xcaOr\x05e\xb1\xc2\xd3\x0em\x7f\xc2\x15\xeb\x05\r\xc5\xa8\xff\xa9W~\xf1q\x1f\xe7\n\x1aB\xc1\xeb\xfd\x98xF=\xe9\xde\xdd\xd9\xc0\xdf\'\xd3\x03\x81\xbc\x97\xf4` \x03KQ\xaa\xe2\xc2\xb5^\xa3')
msgs.append(
b's\x02\xee\xee(\xd7\'\xda\x80[\x10H{\x1e$z\x86\xee\xae\xfd\x97f\xef\xefa\xbeX\xb0\x0f\xde\xfa\x97\x1d\xe8$\x8c\x08\xe6\xf1m\x14\xd6#S\x19\xea\x1b\xd9\xee/\x15\xa1^\xc4t\x8c\x1d\xcca\x18Zq,\xb8\x0e\x90\xe1[\x96\x1b\xd1\x16\x87\xb7\x9f(\xf28\x83\x17x<\x16\xf8\x13T\xda\xa1\xec\xde"\xfe~\'\x1ap\xbb\x1c{\xf0\x88\xe8\xe1V\xf5\xfd\xc1\x8a|\xc4\x0e\xf3s\x17z\xa7\xbd\xd8w\x9f\xca\xce\xbc\xb3\x97w\xa0\xd0+\x0e9J&/~9\x9f\xdeT\x9d\xcf\x17\x99]\x177L\xf2\xadO\xd6\xf1M\xf7Wv\xcc\xdfK\tX\xaf\xe0X\xff\xa1\xb5y\xd9/4\xde8\xe4\x90}\x08Z\xa4\x0cAr\xa8\xd5\x82G#7\x85\x83V\xbd\x8f\xef]\\\xb6&6\xeer\xc8{h\xea<\x9e\xaaFc\xa6\xcdx\x84\xbfU\xa1l\x7f-n\xcf\x10P2H^\xba?\x97S\xd3LT\xfc\xb0\x05\xae[\xf9\x9d\x17\x0b\xa5\xe6E?2_fr\x14\xc22\xe2?I\x18\xbc\x92\x9c\xc1\xe8\x93i\xef\xb4\x95%U\x1d:9\xb5\xd5\xb4U\xd2\x1b\xb5\x89\x9e\xd2\xe8\x1d\x05\xaaa\x84\xc5\x12\xd5\x04\xf9\xb4\xbe\xe1g\xe1a\xc8\x96}\x89x\x00\xc2\x90u\x0b\xe4\x02\xc9\x0110\xf6\x08\xf0\x8bw3\xb1\x8ckU\x82&)"p")l\tZLci\xae\x08\xd0\x12\xe0\xe1#W^P8\xa0\xf4\x84\x06lbH\x07bX1\xf0\xcda1/\xc0?\xa2\xb0-\xe3\xfd\xed\x01\xb15Z\\\x97\xea\x1f\x8a\x9d\x08\xa8wO"\x95\xfdJ\xbb}EC\x0c\x99\xf1\xf3\xfa\xbe,1\xf2\xd8\x01Rf/\xa2\xf5x\x8e\x90\xc8B?\x15\xe7\x95\xe6\x1b?\x10\xc4\xdb\x01f\xf6t\x03\xc2\x1a\xb5\xf6CX\xfa\xc0A\xfe\xc47-\xe86\xeb\x9b\xe1\xb9\xa7\xf4\xf0\xcd\x91\x86\xf3\x1c\xb9\x9a\xde\x0b<\xce\x02\x12\x13\x8e\xddV\xa1_\xe4\xcc\xb9\t\xb6\x7f\x01\x83|\xf4\xc6\xb8uso\xa8\x05K\x08')
msgs.append(b"s\x02+\xef(\xd7'\xda\x80[\x11\x08N(pwa\x85\xab\x9a90y\xf6+3\x88C\xb8\x97^|\xba\xdb5\xa1\xba\x81\xb6$Z\x94\xd6\xdfE\r>8\xc7\xd2U:\x1b}z\xb9|$\xd7\x8bs>I\x01i\xe4\x8eL}\x06\xe8\x99\xff\xc0h\xd5\xee\xc6\xb7\xeaAb{\x13\x8dc\xa0N\x1c\x05\x8f\x08a?\xa9g9i(\t\xc5&")
msgs.append(
b"s\x00}\xe9\x08\xd7'\xda\x80[\x11\x88\x97\xfa%m\xeb\r\x9evnH<\xe0\xca\xa9a@\xef\xb8\xd9E\xd4\xban\xd5\xd5\x9b\xce\xe8\x11\xf0&2\x83A\x0e\x8aR\x14)\x14\xe8R\xa8+\xa4\xe3\x05B+\xc5\xe3\xd6/\x13\x84\xb7!\x98\xaecu\xb2j!kq\x82\xb6\xf2I\xec\xfc\xca\x9b\xb1\x8e\xf8\xc6\xbeC`\xe0\xa8p`Qg\xa2\x01Q\xfb\xbb\x8d\xdf\xa6\x9e\xa2i1m\x15XD\xbd\xb7\x87\x0en\xa8\xaa|\t\ro\xe6\x18 \x8a\xafQ\xd1\xeb\x9erJ\x98\x07#\x11\xa1\xec\xdd\x10\x00#^\xb3WRz\x86\x9c`IL\xaa(\x1b\x9c;Z\xa4\xb4P\x9f\x0c\xe5\xb2\xa4\xb4\x9c\xce\xb2@\x9aO\xf7OM\xc4&>&-5\xf3:\xcf\xbbuA\x044\x98\xeb\x85\xd7\x95\xcb\x1di\x9ci]\xb3K\xbd\xc5\xfb\x9fLQ\x1a~\xe9^\xf5{\xf3\xb2\xa39'\x96!\xachE\xdd\xfa!\xea\xea)z\xd4p_\xed\xa8k\xf3L\x1b\xc8\x8fZ,\x91\x86\xaa\x18f\xd4U\x8cLD\x8a\xa7-\xaa\xbc")
msgs.append(b's\x00B\xec\x18\xd7)+p[\x1fH0\xb6\xb6`j\xef\xa5\x03\xb3\x1a\x1cd\xbc\x17\xa7\xf5\xb3\x95K\xfa)\xb2F\xc4\x9a:y\x867\xf5\x7fW\x96o\xbb|\x97\x81#\x8c\xef\x8ey\xd2\xfb\x89\xffF)1\xd3RA]\xe2\xe1\x17>\xf9\xfe\xf9\xa7XJ\xab[\xa6,\xb59\xd0W\xa1\x93\xa7H\x83Zb\xc3\x0b\xb5Y\xebtF5E:\xc6P\xd8\xccP\xfd\xfe:om\x9c\xf6p\x8a\xeb\x10]*/\xe7KU\xb76b\x97$\xf4\x8f^\xfb\xe8\xe4\xb2\xbdF\xf1\xbeH~\xa8\x9e\x1c\x81\xb1\x1d\xd7')
msgs.append(b's\x00Fg8\xd7\'\xda\x10[\x17HX\xfe\x1b|\xae\xf2\x18f\xd9\xaa\xfb\xaf0\xec\xf9\xabq\xcf*F\xed\x1e!\xd0^"(\xd3i<\xbbt\x1aU\xe0\xfez\xd4d\xfes\x00\x0eg#\x07\xed\x1f\xe2%\x9bb,B7&}\x98=F\xb4S\xb2\xccd\\\xe0Q\xd8Uc\xa29\x83K{\xaa%\xf4"\x00\x13U\xf6\xe3h\x10\xc2\xb7\xa0\t\x87\x9e\xce\x12\xf7\x1d}0d+4\x88\xaf;\x17\x95;\xd9\x8e\x94\xca\xf99\x898M,\xa2\xc9h\xd1\xa5\xf5spN\x1cc\x8aZx}\xa9X\x8c\xe4S\xe0\xe2f7\x97')
msgs.append(
b"s\x00_\xeb(\xd7'\xda\x80[\x1fH\xa9\x81\xe5>2`~E\xa3O\xf7\x9b\x08R)Z\x96\xccI\xb0\xd0\xb4\xd4C\x8d\xcb\xcb\xadDx\x18\xcc\x94\xdbG\xce\x95\x8e\xef\xd9\xff\x1c\xef\xdd\xcf\xe8\xe7\x8fT\x80\xb5\x99\xc3\x10\x07=\x93\x82\xc9\xa4\x82\xbe)\xbc\xe6,\x16\x9e\xa5\xb4`N\x92\r2x1\x85\x82\x99M\xdd\x83\xec\xf3\xe8ov\x0c\xe5!\xcb\x85d\x8di\xe4Q\x1d\xcaE))\x871\x81\xc5\xbd\xbfc<\x0f\x82\xe0\x8b\x81\xd2\xc8T0\xfaz'\xdb\xf0\xc0\xa8\x8c\x13x\x93\x88$\x9c\xe7;\xfd\xa8\xe5t\xeb~Mc\x1aY\x80d\xcd_\xf1y\x94\xbd\xe5\xc6\xb6\xfd\x14i\xb6\x1e\xc0\x14\x96$]\xe1(\xe1\xb7v\x02$?\x9bd\xef\x8d\xc9\x12\xff\x99j3\x95U\xf5\x8e1p$\xa9\xd9")
msgs.append(b's\x00\x14h\x04\x12\xa8[\x11\xc8V\xf4^R\xac\xaf\xc7.Q\t\x82\x9c\xa3\xc2\x02H\xca\xb1J\xc4\x18\xc6A:\x90qZ-\x08\xee\xf8\xa8\x93\xc3\xfa\xcb\xdf\x9a\xa9\x0e\xaa\x9e\xf1')
msgs.append(b's\x00\x0e\xec\x10\x1d\x98[\x1f\x88r^\\\xff\xf6\x1a\xf8\x97\xf0)u"\xb1\x04\xe0\xb8\x1b\xbeu\x8d\xcao{\x01sUn\xc1\xc1b\x05I')
msgs.append(b"s\x00\x14h\x04\x12\xd0[\x12\x08&\x9b\nOi\x90\xe3\xccKp\x99\xc7w9\xd4\x8cY\xed'\xd2\xcb\x97`\xa4mT\xb5S\xbe&\xac-\x00u\x19\x1d\xcch\x96\x87\xcat\xcc")
msgs.append(b"s\x00\x0e\xec\x10\x1d\xc0[\x1f\xc8'e\x0f\xfc\xc4\x14z\x96\xc4h\x14\xe1\xec=\x05\x03\xc9\xa1h\xab\xc9\x99w\xbfN\x1fh\xee\xad\xb4\xf7\x1d")
msgs.append(b's\x00\x0c\xed4\x12`[\x17\xc8\x1c\\\x8d}\xf2\xafp=\xc9\x02\xf2J\xab\xa2\xd2Pc\x11\x00\r\xac\x16\xec\xd6\xd4j\x95?')
msgs.append(b"s\x00\x11c$\x12\xd0[\x1f\xc8\xd8O\x9e\x0f\x04X\xe7N7!\x9c\xa6g\x8c7\xbf[\t\x1c'\x99k\x954\xb8\xe8jR\x9dmBG\xd8\x07\x05\xd5K")
for msg in msgs:
try:
parsed = SPARTNReader.parse(msg, decode=True, key=key, basedate=datetime.datetime.utcfromtimestamp(1713519000))
# print(parsed._decode)
parsed_typed: SPARTNMessage = parsed
print(f"{parsed_typed.identity}")
except Exception as e:
print(e)
TypeError: can't subtract offset-naive and offset-aware datetimes
when processing basedates without timezone information.
Exception in thread paho-mqtt-client-<<redacted>>:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/threading.py", line 1010, in run
self._target(*self._args, **self._kwargs)
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/paho/mqtt/client.py", line 4523, in _thread_main
self.loop_forever(retry_first_connection=True)
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/paho/mqtt/client.py", line 2297, in loop_forever
rc = self._loop(timeout)
^^^^^^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/paho/mqtt/client.py", line 1686, in _loop
rc = self.loop_read()
^^^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/paho/mqtt/client.py", line 2100, in loop_read
rc = self._packet_read()
^^^^^^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/paho/mqtt/client.py", line 3142, in _packet_read
rc = self._packet_handle()
^^^^^^^^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/paho/mqtt/client.py", line 3808, in _packet_handle
return self._handle_publish()
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/paho/mqtt/client.py", line 4145, in _handle_publish
self._handle_on_message(message)
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/paho/mqtt/client.py", line 4501, in _handle_on_message
on_message(self, self._userdata, message)
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pygnssutils/gnssmqttclient.py", line 411, in on_message
for raw, parsed in spr:
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnreader.py", line 135, in __next__
(raw_data, parsed_data) = self.read()
^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnreader.py", line 165, in read
(raw_data, parsed_data) = self._parse_spartn(byte1)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnreader.py", line 251, in _parse_spartn
parsed_data = self.parse(
^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnreader.py", line 328, in parse
return SPARTNMessage(
^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnmessage.py", line 98, in __init__
self._do_attributes()
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnmessage.py", line 167, in _do_attributes
iv = self._get_iv()
^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnmessage.py", line 203, in _get_iv
timeTag = convert_timetag(self.gnssTimeTag, self._basedate)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnhelpers.py", line 282, in convert_timetag
basedate_seconds = date2timetag(basedate)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/steve/Library/Python/3.12/lib/python/site-packages/pyspartn/spartnhelpers.py", line 245, in date2timetag
return int((date - TIMEBASE).total_seconds())
~~~~~^~~~~~~~~~
TypeError: can't subtract offset-naive and offset-aware datetimes
To Reproduce
Steps to reproduce the behaviour:
spartn_mqtt_client.py
example with decryption enabled.Expected Behaviour
Desktop (please complete the following information):
SPARTN data source (please complete the following information as best you can):
(NB: Please redact any current SPARTN decryption keys)
Additional context
Add any other context about the problem here.
Hi, I have been playing with pyspartn a bit more and am now close to result I hope, thus my ability to now find errors deep in the parsing.
When using version 1.0.2 (latest at the time of writing), the parsing of SPARTN-1X-HPAC-GPS satellite mask looks wrong. Too many bits are read.
Field of interest is SF011. Definition is :
Leftmost 2 bits indicate bitmask size to follow
0 : 32 bits
1 : 44 bits
2 : 56 bits
3 : 64 bits
So typically, with first 2 bits as "01", 44 bits should be read. However 46 bits are read. 46 is the total field size, however 2 bits are already read.
To Reproduce
payload = bytes.fromhex("7302dfec38db7b1fa05b14c8abf0841e136d0e55dcda5cf7440c399537f66ee9add1b9fb0ebc1c10e09d790ff561d3763b3e1287ac1384dbcdec28b968ab77aac1da6cae785cbaa21d9a50a8ac8385e7b605bbcacb0e954f1c1d53815ab69553770f25cb912a7dfabfe590374371fc07def2da832f82697af5815bdc5a21dbe0f655fe85e8b0fc319f94d4366c0f8b7da564d952b5b0654af600ab39cb0bab35411c2c85046464a999e6510c23a3f3617ad49a868627e9eae5d3ca6400b9f2ce2067d6bdeaa9924fe8a0b4823b0ad1ea447238f8659292ea928feb3733f51a795dd3858ef4e340eb8e40dd454b011756ee506e1e9c74a59f1c50546baba4da9e739e91ae8582f01edb2bdfdf98c7163a664205223f8c9b70c77c4e63184260cd4f9486e3fd8fbd7b954766e89d5dc3d6b8b59ddc6804103e86912aff1524b1202a52d7c0e8406ba5ecefdf0c2c093c8e984e67dc62f3508bd07ac44bdf30ae8df66de478019405aa373d422b2e069eeb4eff4c14edcb7881a939f8a8cdfbf8752e28fc375c3bfc4ab70ec1802c1cab04feecbd5cb4d97966cdfb5d1a76baf8432402da5d6ba3808e42d0cdc3f952c3993a9f71716abdcc7e53c30e8a5542f5f5d1a1f95ef0a22564fecedd6335407302d1eb38db7b1fa05b1508fe82ed5f6427ac94ee8c1869b413cf5212489c83c8247e503c8291d261fdaa401f80b95d5f6a45b2b32730be3a3b8ab5a82ef1fb8df71fb663e5d494933c053ad2ab6bb43889375c3f67c382121e44d46b0d6d1fe516a35032af3a30e914250f49238c6e3367ca6a1acb60c476d4e6662f31f914b8e9e65fa9c5c9350c7951a6cefdb66acb3fe6dfb82fce760a7707179e59b85a8adb51841019c542921fc58a532de2529fd4a548fea7bf4c3ebf14e7616ae5b138beeb217bb251f3aebfd2d6b63253912174c604879b9b7fa0a1ec430c3528122b690f2fb800d9c3c2848f97eaa5740968abb79e865bb61899c99e2c50483af7d281f339f089f61bd35c031ddde5bf2b129372e8d840f0a6f5dfd9d96da54ebdfd5109176c10570bd996f464e26cb49475127f67ce870dc8c8e0513c3c9a359cc6ad3377de6600c1d6e32bebbeb5ca55bebab885d716c3b2b14b8f0112180cd918e0bb87f07d4a5a6149bb752ead5a4f00938323b59b1fe40d71b2286917383e6dc0330b89f23b70f6e6eedf18c01e8161e3af45595889c07eec100ee59fe5a8b859a6f6ab94595180a5937740ed24cfa0af7302ceed38db7b1fa05b154834bc1fd26efa4642733718086ba2724db1aeca8921e51513ce28e1c2b63e8aaeb07ecc79b0124b72c32ce7abdafceb9a845e7041824d96b80aa285a4b9d1f157acf31a958258770083e69ccd79ad6db549371357715881f9003aeac8af2ed085a95c402c9004dad4659bd207d007e2477ff308714bc4b06274402939d6a6aeffa7ac7636807db23feb6985b87b9eec42294d1d14c30ca37c50f7f8ccb590bd61c916bc7acc55dbccfcac6ad3678dd3ee98c3091ad9d9f4ee8b6180f4994f0cad0cbc2dddde8eeffa6e71bf47487a6ba54e0291d284230603c01b73b73f545ab3c8a0a1a3d2c93b3615d48ff7ac4e07bc6395214cfd5eb5a20d70f98b00e685b312a7a2046c37f5670787fe23303496ff807c6f7cb94a6b453cdcde901db537cc315a794c2189ec376db92a09721e9f7c20878cb959b9e7864e4d1c4af2434db467459e46223c300abc55a56b355f6474f3ba0e2c2b4db4db0a1856e5958be1e2ea4ec7fea6577300ed9383293503b286d4ea49b2f9f3aeed828b9aad3b920b38ed024497244e906356072eb4710602863b8fdd5f8146eed2120a5b8d02e84f217302c06338db7b1fa05b1588567a097223f7f09dc90c3c1c0d85ad8299c8ad4d0aa969d01a6f482dafb86e676c90dbde180f51313ee8a38745d3e6f33fecaf50f438f651a0b42ee93549f02d8910899b4e4bf5fb0514560b8fce55f7f95756158ec80ba47413613201ba66da52d8fab96ec9c25becb6b170269830f76483e2d9fdcc01dca9f7f28336197149f55dc9cc5d5a4d82681792fc3a0aaaf700759470a4035b55090423951a0c8bea009e7bdd1daa21ca528aba7e621417d416115735c6002a4a92dd520c1c3c416b4efbd1175423cd9a77b35197f39556dbca2d8e41529b541b63d450e3bf94565bf6255e9e71eeaf3e69c495604a34e5c0490766c2f57aa8d33631b468af6c2e56a9b325bbe6988f277aa20f332880331da79e810c56463e5f8cf7aeb0292a0ea17c6f748113070d04bf8fc4a735ce5f577180f5be82381a0985f8769c76b086cd192c799a4cee4f0e3bbb59112e81e12169b1523d019236d5e7c9f413531f6093c44e460866b4534ff4033385aee4561eaf7ecc85b29285129c332fc9ab457a0478b8f273022d6538db7b1fa05b15c87006e3601505d12cb65f9b43a400a3d13bd4aef0647d4691533ac61450bdc06c811202376ec73454437e7ead5e103947caed003125cc47bbd2cace0c0465274d4f1458164bf98db035280c08884769654c9a0ffa16dac70cf8b67b84b7")
key = "930d847b779b126863c8b3b2766ae7cc"
date_str = "2024-08-02 08:55:17.221124"
base_date = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S.%f")
spr = SPARTNReader(BytesIO(payload), decode=True, key=key, basedate=base_date)
With debug enabled, this produces (look offset 85) :
Offset:0 read_length:9 key:SF005 val:281
Offset:9 read_length:4 key:SF068 val:1
Offset:13 read_length:1 key:SF069 val:0
Offset:14 read_length:5 key:SF030 val:9
Offset:19 read_length:8 key:SF031_01 val:0
Offset:27 read_length:7 key:SF039_01 val:0
Offset:34 read_length:2 key:SF040T_01 val:1
Offset:36 read_length:2 key:SF040I_01 val:1
Offset:38 read_length:3 key:SF041_01 val:1
Offset:41 read_length:3 key:SF042_01 val:1
Offset:44 read_length:8 key:SF043_01 val:0.0
Offset:52 read_length:1 key:SF044_01 val:1
Offset:53 read_length:9 key:SF048_01 val:-0.06000000000000005
Offset:62 read_length:9 key:SF049a_01 val:0.013000000000000012
Offset:71 read_length:9 key:SF049b_01 val:-0.0020000000000000018
Offset:80 read_length:3 key:SF054_01 val:1
Offset:83 read_length:2 key:SatBitmaskLen_01 val:1
Offset:85 read_length:46 key:SF094_01 val:34350104 <--- Here the problem start
Offset:131 read_length:0 key:PRN_01_01 val:21 <--- now we can see the problem
Offset:131 read_length:4 key:SF055_01_01 val:2 <-- everything is off by 2 bits now
...
And here is how I log the parsing :
@@ -385,6 +385,7 @@ class SPARTNMessage:
except SPARTNMessageError as err:
raise err
+ print(f"Offset:{offset} \t read_length:{str(attlen).ljust(4, ' ')} \t key:{anami.ljust(20, ' ')} val:{val}")
setattr(self, anami, val)
Expected Behaviour
Manual parsing gives :
...
011110000 -> Tropo coeff T00 (I agree with 1.0.2)
100001100 -> Tropo coeff T0 (I agree with 1.0.2)
011111101 -> Tropo coeff T10 (I agree with 1.0.2)
001 -> Iono equation type (I agree with 1.0.2)
01 -> 44 bits to follow (I agree with 1.0.2)
00000000000000000000100000110000100100000110 -> GPS sat mask (error) : I read 44 bits but 1.0.2 reads 46 bits
0000 -> Iono quality (error) : Now we read 2 bits too much and everything is off. Iono quality should be 0, but is read as 2 (see the next 2 bits of the stream)
1011000110... -> ... next bits of the stream
Additional context
SATBITMASKLEN = {
"SF011": [32, 44, 56, 64],
"SF012": [24, 36, 48, 63],
"SF093": [36, 45, 54, 64],
"SF094": [37, 46, 55, 64],
"SF095": [10, 40, 48, 64],
}
Looks correct, so it's probably in the logic of the SATBITMASKLEN.
I'll take a look and see if I can find the responsible line, and also if OCB messages are affected, as they are using the same parsing logic.
Have a good day
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.