fix: parser no v0.2.2, uses proper frame handling, checksum for large frames still unknown.
This commit is contained in:
98
parsers/bw_frames.jsonl
Normal file
98
parsers/bw_frames.jsonl
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
{"index": 0, "start_offset": 0, "end_offset": 21, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 1, "start_offset": 21, "end_offset": 42, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 2, "start_offset": 42, "end_offset": 63, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 3, "start_offset": 63, "end_offset": 84, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 4, "start_offset": 84, "end_offset": 105, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 5, "start_offset": 105, "end_offset": 126, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 6, "start_offset": 126, "end_offset": 147, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 7, "start_offset": 147, "end_offset": 168, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 8, "start_offset": 168, "end_offset": 189, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 9, "start_offset": 189, "end_offset": 210, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 10, "start_offset": 210, "end_offset": 231, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 11, "start_offset": 231, "end_offset": 252, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 12, "start_offset": 252, "end_offset": 273, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 13, "start_offset": 273, "end_offset": 294, "payload_len": 17, "payload_hex": "1000150000000000000000000000000025", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 14, "start_offset": 294, "end_offset": 315, "payload_len": 17, "payload_hex": "10001500000a000000000000000000002f", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 15, "start_offset": 315, "end_offset": 427, "payload_len": 108, "payload_hex": "10006800005a00000000000000000000005809000000010107cb00061e00010107cb00140000000000173b00000000000000000000000000000100000000000100000000000000010001000000000000000000000000000000000064000000000000001effdc0000100200c8", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 16, "start_offset": 427, "end_offset": 448, "payload_len": 17, "payload_hex": "1000730000000000000000000000000083", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 17, "start_offset": 448, "end_offset": 1497, "payload_len": 1045, "payload_hex": "1000710010040000000000000000000000082a6400001004100400003c0000be800000000040400000001003000f000000073dbb457a3db956e1000100015374616e64617264205265636f7264696e672053657475702e7365740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050726f6a6563743a0000000000000000000000000000544553542000000000000000000000000000000000000000000000000000000000000000000000000000436c69656e743a000000000000000000000000000000436c6175646520746573743200000000000000000000000000000000000000000000000000000000000055736572204e616d653a00000000000000000000000054657272612d4d656368616e69637320496e632e202d20422e204861727269736f6e000000000000000053656973204c6f633a000000000000000000000000004c6f636174696f6e202331202d20427269616e7320486f75736500000000000000000000000000000000457874656e646564204e6f74657300000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 18, "start_offset": 1497, "end_offset": 2574, "payload_len": 1073, "payload_hex": "1000710010040000001004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015472616e000000010050000f0028001510021003011004001003000040c697fd00003f19999a696e2e00400000002f730000000156657274000000010050000f0028001510021003011004001003000040c697fd00003f19999a696e2e00400000002f73000000014c6f6e67000000010050000f0028001510021003011004001003000040c697fd00003f19999a696e2e00400000002f73000000004d69634c000000100200c80032000a000a1002d501db000500003d38560800003c1374bc707369003cac0831284c29000010025472616e320000010050000f0028001510021003011004001003000040c697fd00003f000000696e2e00400000002f73000000100256657274320000010050000f0028001510021003011004001003000040c697fd00003f000000696e2e00400000002f7300000010024c6f6e67320000010050000f0028001510021003011004001003000040c697fd00003f000000696e2e00400000002f73000000004d69634c1002", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 19, "start_offset": 2574, "end_offset": 2641, "payload_len": 63, "payload_hex": "10007100002c00000800000000000000320000100200c80032000a000a1002d501db000500003d38560800003c23d70a707369003cac0831284c29007cea32", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 20, "start_offset": 2641, "end_offset": 2662, "payload_len": 17, "payload_hex": "1000720000000000000000000000000082", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 21, "start_offset": 2662, "end_offset": 2711, "payload_len": 45, "payload_hex": "10008200001c00000000000000000000001ad5000001080affffffffffffffffffffffffffffffffffff00009e", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 22, "start_offset": 2711, "end_offset": 2732, "payload_len": 17, "payload_hex": "1000830000000000000000000000000093", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 23, "start_offset": 2732, "end_offset": 2957, "payload_len": 221, "payload_hex": "1000690000ca0000000000000000000000c8080000010001000100010001000100010010020001001e0010020001000a000a4576656e742053756d6d617279205265706f7274000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002580000801018c76af", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 24, "start_offset": 2957, "end_offset": 2978, "payload_len": 17, "payload_hex": "1000740000000000000000000000000084", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 25, "start_offset": 2978, "end_offset": 2999, "payload_len": 17, "payload_hex": "1000720000000000000000000000000082", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 26, "start_offset": 2999, "end_offset": 3020, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 27, "start_offset": 3020, "end_offset": 3041, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 28, "start_offset": 3041, "end_offset": 3062, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 29, "start_offset": 3062, "end_offset": 3083, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 30, "start_offset": 3083, "end_offset": 3104, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 31, "start_offset": 3104, "end_offset": 3125, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 32, "start_offset": 3125, "end_offset": 3146, "payload_len": 17, "payload_hex": "1000150000000000000000000000000025", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 33, "start_offset": 3146, "end_offset": 3167, "payload_len": 17, "payload_hex": "10001500000a000000000000000000002f", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 34, "start_offset": 3167, "end_offset": 3188, "payload_len": 17, "payload_hex": "1000010000000000000000000000000011", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 35, "start_offset": 3188, "end_offset": 3209, "payload_len": 17, "payload_hex": "10000100009800000000000000000000a9", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 36, "start_offset": 3209, "end_offset": 3230, "payload_len": 17, "payload_hex": "1000080000000000000000000000000018", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 37, "start_offset": 3230, "end_offset": 3251, "payload_len": 17, "payload_hex": "1000080000580000000000000000000070", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 38, "start_offset": 3251, "end_offset": 3272, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 39, "start_offset": 3272, "end_offset": 3293, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 40, "start_offset": 3293, "end_offset": 3314, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 41, "start_offset": 3314, "end_offset": 3335, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 42, "start_offset": 3335, "end_offset": 3356, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 43, "start_offset": 3356, "end_offset": 3377, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 44, "start_offset": 3377, "end_offset": 3398, "payload_len": 17, "payload_hex": "1000010000000000000000000000000011", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 45, "start_offset": 3398, "end_offset": 3419, "payload_len": 17, "payload_hex": "10000100009800000000000000000000a9", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 46, "start_offset": 3419, "end_offset": 3440, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 47, "start_offset": 3440, "end_offset": 3461, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 48, "start_offset": 3461, "end_offset": 3482, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 49, "start_offset": 3482, "end_offset": 3503, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 50, "start_offset": 3503, "end_offset": 3524, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 51, "start_offset": 3524, "end_offset": 3545, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 52, "start_offset": 3545, "end_offset": 3566, "payload_len": 17, "payload_hex": "1000150000000000000000000000000025", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 53, "start_offset": 3566, "end_offset": 3587, "payload_len": 17, "payload_hex": "10001500000a000000000000000000002f", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 54, "start_offset": 3587, "end_offset": 3608, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 55, "start_offset": 3608, "end_offset": 3629, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 56, "start_offset": 3629, "end_offset": 3650, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 57, "start_offset": 3650, "end_offset": 3671, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 58, "start_offset": 3671, "end_offset": 3692, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 59, "start_offset": 3692, "end_offset": 3713, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 60, "start_offset": 3713, "end_offset": 3734, "payload_len": 17, "payload_hex": "1000150000000000000000000000000025", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 61, "start_offset": 3734, "end_offset": 3755, "payload_len": 17, "payload_hex": "10001500000a000000000000000000002f", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 62, "start_offset": 3755, "end_offset": 3776, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 63, "start_offset": 3776, "end_offset": 3797, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 64, "start_offset": 3797, "end_offset": 3818, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 65, "start_offset": 3818, "end_offset": 3839, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 66, "start_offset": 3839, "end_offset": 3860, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 67, "start_offset": 3860, "end_offset": 3881, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 68, "start_offset": 3881, "end_offset": 3902, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 69, "start_offset": 3902, "end_offset": 3923, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 70, "start_offset": 3923, "end_offset": 3944, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 71, "start_offset": 3944, "end_offset": 3965, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 72, "start_offset": 3965, "end_offset": 3986, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 73, "start_offset": 3986, "end_offset": 4007, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 74, "start_offset": 4007, "end_offset": 4028, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 75, "start_offset": 4028, "end_offset": 4049, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 76, "start_offset": 4049, "end_offset": 4070, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 77, "start_offset": 4070, "end_offset": 4091, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 78, "start_offset": 4091, "end_offset": 4112, "payload_len": 17, "payload_hex": "10005b000000000000000000000000006b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 79, "start_offset": 4112, "end_offset": 4133, "payload_len": 17, "payload_hex": "10005b000030000000000000000000009b", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 80, "start_offset": 4133, "end_offset": 4154, "payload_len": 17, "payload_hex": "1000010000000000000000000000000011", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 81, "start_offset": 4154, "end_offset": 4175, "payload_len": 17, "payload_hex": "10000100009800000000000000000000a9", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 82, "start_offset": 4175, "end_offset": 4196, "payload_len": 17, "payload_hex": "10002e000000000000000000000000003e", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 83, "start_offset": 4196, "end_offset": 4217, "payload_len": 17, "payload_hex": "10002e00001a0000000000000000000058", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 84, "start_offset": 4217, "end_offset": 4238, "payload_len": 17, "payload_hex": "1000010000000000000000000000000011", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 85, "start_offset": 4238, "end_offset": 4259, "payload_len": 17, "payload_hex": "10000100009800000000000000000000a9", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 86, "start_offset": 4259, "end_offset": 4280, "payload_len": 17, "payload_hex": "10001a000000000000000000006400008e", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 87, "start_offset": 4280, "end_offset": 4302, "payload_len": 18, "payload_hex": "10001a001004000000000000000064000092", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 88, "start_offset": 4302, "end_offset": 4325, "payload_len": 19, "payload_hex": "10001a00100400000010040000000064000096", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 89, "start_offset": 4325, "end_offset": 4346, "payload_len": 17, "payload_hex": "10001a00002a00000800000000640000c0", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 90, "start_offset": 4346, "end_offset": 4367, "payload_len": 17, "payload_hex": "1000090000000000000000000000000019", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 91, "start_offset": 4367, "end_offset": 4388, "payload_len": 17, "payload_hex": "1000090000ca00000000000000000000e3", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 92, "start_offset": 4388, "end_offset": 4409, "payload_len": 17, "payload_hex": "1000080000000000000000000000000018", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 93, "start_offset": 4409, "end_offset": 4430, "payload_len": 17, "payload_hex": "1000080000580000000000000000000070", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 94, "start_offset": 4430, "end_offset": 4451, "payload_len": 17, "payload_hex": "1000010000000000000000000000000011", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 95, "start_offset": 4451, "end_offset": 4472, "payload_len": 17, "payload_hex": "10000100009800000000000000000000a9", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 96, "start_offset": 4472, "end_offset": 4493, "payload_len": 17, "payload_hex": "1000080000000000000000000000000018", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
|
{"index": 97, "start_offset": 4493, "end_offset": 4514, "payload_len": 17, "payload_hex": "1000080000580000000000000000000070", "trailer_hex": "", "checksum_valid": null, "checksum_type": null, "checksum_hex": null}
|
||||||
BIN
parsers/raw_bw.bin
Normal file
BIN
parsers/raw_bw.bin
Normal file
Binary file not shown.
BIN
parsers/raw_s3.bin
Normal file
BIN
parsers/raw_s3.bin
Normal file
Binary file not shown.
@@ -1,232 +1,364 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
s3_parse.py — parse Instantel/Series3-like DLE-framed serial captures from a raw .bin logger.
|
s3_parser.py — Unified Instantel frame parser (S3 + BW).
|
||||||
|
|
||||||
Assumptions (based on your HxD patterns):
|
Modes:
|
||||||
- Frames are delimited by DLE STX (0x10 0x02) ... DLE ETX (0x10 0x03)
|
- s3: DLE STX (10 02) ... DLE ETX (10 03)
|
||||||
- Inside payload, a literal 0x10 is escaped as 0x10 0x10
|
- bw: ACK+STX (41 02) ... ETX (03)
|
||||||
- After ETX, there may be a trailer (often CRC16, maybe + seq/flags)
|
|
||||||
|
Stuffing:
|
||||||
|
- Literal 0x10 in payload is stuffed as 10 10 in both directions.
|
||||||
|
|
||||||
|
Checksums:
|
||||||
|
- BW frames appear to use more than one checksum style depending on message type.
|
||||||
|
Small frames often validate with 1-byte SUM8.
|
||||||
|
Large config/write frames appear to use a 2-byte CRC16 variant.
|
||||||
|
|
||||||
|
In BW mode we therefore validate candidate ETX positions using AUTO checksum matching:
|
||||||
|
- SUM8 (1 byte)
|
||||||
|
- CRC16 variants (2 bytes), both little/big endian
|
||||||
|
If any match, we accept the ETX as a real frame terminator.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Tuple
|
from typing import Callable, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
DLE = 0x10
|
DLE = 0x10
|
||||||
STX = 0x02
|
STX = 0x02
|
||||||
ETX = 0x03
|
ETX = 0x03
|
||||||
EOT = 0x04
|
ACK = 0x41
|
||||||
|
|
||||||
|
__version__ = "0.2.2"
|
||||||
|
|
||||||
# How the capture was produced:
|
|
||||||
# - Raw serial captures include DLE+ETX (`0x10 0x03`).
|
|
||||||
# - The s3_bridge `.bin` logger strips the DLE byte from ETX, so frames end with a
|
|
||||||
# bare `0x03`. See docs/instantel_protocol_reference.md §Appendix A.
|
|
||||||
ETX_MODE_AUTO = "auto"
|
|
||||||
ETX_MODE_RAW = "raw" # expect DLE+ETX
|
|
||||||
ETX_MODE_STRIPPED = "stripped" # expect bare ETX
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Frame:
|
class Frame:
|
||||||
index: int
|
index: int
|
||||||
start_offset: int
|
start_offset: int
|
||||||
end_offset: int
|
end_offset: int
|
||||||
payload_raw: bytes # as captured between STX..ETX, still escaped
|
payload_raw: bytes # de-stuffed bytes between STX..ETX (includes checksum bytes at end)
|
||||||
payload: bytes # unescaped
|
payload: bytes # payload without checksum bytes
|
||||||
trailer: bytes # bytes immediately after ETX (length chosen by user)
|
trailer: bytes
|
||||||
crc_match: Optional[str] # best-guess CRC type if verified, else None
|
checksum_valid: Optional[bool]
|
||||||
|
checksum_type: Optional[str]
|
||||||
|
checksum_hex: Optional[str]
|
||||||
|
|
||||||
def unescape_dle(payload_escaped: bytes) -> bytes:
|
|
||||||
"""Convert DLE-stuffing: 0x10 0x10 => 0x10 (literal DLE)."""
|
|
||||||
out = bytearray()
|
|
||||||
i = 0
|
|
||||||
n = len(payload_escaped)
|
|
||||||
while i < n:
|
|
||||||
b = payload_escaped[i]
|
|
||||||
if b == DLE:
|
|
||||||
if i + 1 < n and payload_escaped[i + 1] == DLE:
|
|
||||||
out.append(DLE)
|
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
# If we see a single DLE not followed by DLE inside payload,
|
|
||||||
# keep it as-is (conservative) — could be real data or malformed capture.
|
|
||||||
out.append(b)
|
|
||||||
i += 1
|
|
||||||
return bytes(out)
|
|
||||||
|
|
||||||
# ---- CRC helpers (we don't know which one yet, so we try a few) ----
|
# ------------------------
|
||||||
|
# Checksum / CRC helpers
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
|
def checksum8_sum(data: bytes) -> int:
|
||||||
|
"""SUM8: sum(payload) & 0xFF"""
|
||||||
|
return sum(data) & 0xFF
|
||||||
|
|
||||||
|
|
||||||
def crc16_ibm(data: bytes) -> int:
|
def crc16_ibm(data: bytes) -> int:
|
||||||
# CRC-16/IBM (aka ARC) poly=0xA001 (reflected 0x8005), init=0x0000
|
# CRC-16/IBM (aka ARC) poly=0xA001, init=0x0000, refin/refout true
|
||||||
crc = 0x0000
|
crc = 0x0000
|
||||||
for b in data:
|
for b in data:
|
||||||
crc ^= b
|
crc ^= b
|
||||||
for _ in range(8):
|
for _ in range(8):
|
||||||
if crc & 1:
|
crc = (crc >> 1) ^ 0xA001 if (crc & 1) else (crc >> 1)
|
||||||
crc = (crc >> 1) ^ 0xA001
|
|
||||||
else:
|
|
||||||
crc >>= 1
|
|
||||||
return crc & 0xFFFF
|
return crc & 0xFFFF
|
||||||
|
|
||||||
|
|
||||||
def crc16_ccitt_false(data: bytes) -> int:
|
def crc16_ccitt_false(data: bytes) -> int:
|
||||||
# CRC-16/CCITT-FALSE poly=0x1021, init=0xFFFF, no reflection
|
# CRC-16/CCITT-FALSE poly=0x1021, init=0xFFFF, refin/refout false
|
||||||
crc = 0xFFFF
|
crc = 0xFFFF
|
||||||
for b in data:
|
for b in data:
|
||||||
crc ^= (b << 8)
|
crc ^= (b << 8)
|
||||||
for _ in range(8):
|
for _ in range(8):
|
||||||
if crc & 0x8000:
|
crc = ((crc << 1) ^ 0x1021) & 0xFFFF if (crc & 0x8000) else (crc << 1) & 0xFFFF
|
||||||
crc = ((crc << 1) ^ 0x1021) & 0xFFFF
|
|
||||||
else:
|
|
||||||
crc = (crc << 1) & 0xFFFF
|
|
||||||
return crc
|
return crc
|
||||||
|
|
||||||
|
|
||||||
def crc16_x25(data: bytes) -> int:
|
def crc16_x25(data: bytes) -> int:
|
||||||
# CRC-16/X-25 poly=0x1021, init=0xFFFF, refin/refout true, xorout=0xFFFF
|
# CRC-16/X-25 poly=0x8408 (reflected), init=0xFFFF, xorout=0xFFFF
|
||||||
crc = 0xFFFF
|
crc = 0xFFFF
|
||||||
for b in data:
|
for b in data:
|
||||||
crc ^= b
|
crc ^= b
|
||||||
for _ in range(8):
|
for _ in range(8):
|
||||||
if crc & 1:
|
crc = (crc >> 1) ^ 0x8408 if (crc & 1) else (crc >> 1)
|
||||||
crc = (crc >> 1) ^ 0x8408
|
|
||||||
else:
|
|
||||||
crc >>= 1
|
|
||||||
return (crc ^ 0xFFFF) & 0xFFFF
|
return (crc ^ 0xFFFF) & 0xFFFF
|
||||||
|
|
||||||
CRC_FUNCS = {
|
|
||||||
"CRC-16/IBM": crc16_ibm,
|
CRC16_FUNCS: Dict[str, Callable[[bytes], int]] = {
|
||||||
"CRC-16/CCITT-FALSE": crc16_ccitt_false,
|
"CRC16_IBM": crc16_ibm,
|
||||||
"CRC-16/X-25": crc16_x25,
|
"CRC16_CCITT_FALSE": crc16_ccitt_false,
|
||||||
|
"CRC16_X25": crc16_x25,
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse_frames(blob: bytes, trailer_len: int) -> List[Frame]:
|
|
||||||
|
def _try_validate_sum8(body: bytes) -> Optional[Tuple[bytes, bytes, str]]:
|
||||||
|
"""
|
||||||
|
body = payload + chk8
|
||||||
|
Returns (payload, chk_bytes, type) if valid, else None
|
||||||
|
"""
|
||||||
|
if len(body) < 1:
|
||||||
|
return None
|
||||||
|
payload = body[:-1]
|
||||||
|
chk = body[-1]
|
||||||
|
if checksum8_sum(payload) == chk:
|
||||||
|
return payload, bytes([chk]), "SUM8"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _try_validate_crc16(body: bytes) -> Optional[Tuple[bytes, bytes, str]]:
|
||||||
|
"""
|
||||||
|
body = payload + crc16(2 bytes)
|
||||||
|
Try multiple CRC16 types and both endian interpretations.
|
||||||
|
Returns (payload, chk_bytes, type) if valid, else None
|
||||||
|
"""
|
||||||
|
if len(body) < 2:
|
||||||
|
return None
|
||||||
|
payload = body[:-2]
|
||||||
|
chk_bytes = body[-2:]
|
||||||
|
|
||||||
|
given_le = int.from_bytes(chk_bytes, "little", signed=False)
|
||||||
|
given_be = int.from_bytes(chk_bytes, "big", signed=False)
|
||||||
|
|
||||||
|
for name, fn in CRC16_FUNCS.items():
|
||||||
|
calc = fn(payload)
|
||||||
|
if calc == given_le:
|
||||||
|
return payload, chk_bytes, f"{name}_LE"
|
||||||
|
if calc == given_be:
|
||||||
|
return payload, chk_bytes, f"{name}_BE"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def validate_bw_body_auto(body: bytes) -> Optional[Tuple[bytes, bytes, str]]:
|
||||||
|
"""
|
||||||
|
Try to interpret the tail of body as a checksum in several ways.
|
||||||
|
Return (payload, checksum_bytes, checksum_type) if any match; else None.
|
||||||
|
"""
|
||||||
|
# Prefer SUM8 first (it fits small frames and is cheap)
|
||||||
|
hit = _try_validate_sum8(body)
|
||||||
|
if hit:
|
||||||
|
return hit
|
||||||
|
|
||||||
|
# Then CRC16 variants
|
||||||
|
hit = _try_validate_crc16(body)
|
||||||
|
if hit:
|
||||||
|
return hit
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# S3 MODE (DLE framed)
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
|
def parse_s3(blob: bytes, trailer_len: int) -> List[Frame]:
|
||||||
frames: List[Frame] = []
|
frames: List[Frame] = []
|
||||||
|
|
||||||
STATE_IDLE = 0
|
IDLE = 0
|
||||||
STATE_IN_FRAME = 1
|
IN_FRAME = 1
|
||||||
STATE_AFTER_DLE = 2
|
AFTER_DLE = 2
|
||||||
|
|
||||||
state = STATE_IDLE
|
state = IDLE
|
||||||
payload_raw = bytearray()
|
body = bytearray()
|
||||||
start_offset = 0
|
start_offset = 0
|
||||||
idx = 0
|
idx = 0
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
n = len(blob)
|
n = len(blob)
|
||||||
|
|
||||||
print(">>> CLEAN RAW STATE MACHINE ACTIVE <<<")
|
|
||||||
|
|
||||||
while i < n:
|
while i < n:
|
||||||
b = blob[i]
|
b = blob[i]
|
||||||
|
|
||||||
if state == STATE_IDLE:
|
if state == IDLE:
|
||||||
# look for DLE STX
|
|
||||||
if b == DLE and i + 1 < n and blob[i + 1] == STX:
|
if b == DLE and i + 1 < n and blob[i + 1] == STX:
|
||||||
print("FRAME START at", i)
|
|
||||||
start_offset = i
|
start_offset = i
|
||||||
payload_raw = bytearray()
|
body.clear()
|
||||||
state = STATE_IN_FRAME
|
state = IN_FRAME
|
||||||
i += 2
|
i += 2
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif state == STATE_IN_FRAME:
|
elif state == IN_FRAME:
|
||||||
if b == DLE:
|
if b == DLE:
|
||||||
state = STATE_AFTER_DLE
|
state = AFTER_DLE
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
else:
|
body.append(b)
|
||||||
payload_raw.append(b)
|
|
||||||
|
|
||||||
elif state == STATE_AFTER_DLE:
|
else: # AFTER_DLE
|
||||||
if b == DLE:
|
if b == DLE:
|
||||||
# escaped literal DLE
|
body.append(DLE)
|
||||||
payload_raw.append(DLE)
|
state = IN_FRAME
|
||||||
state = STATE_IN_FRAME
|
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif b == ETX:
|
if b == ETX:
|
||||||
print("FRAME END at", i)
|
|
||||||
# end of frame
|
|
||||||
end_offset = i + 1
|
end_offset = i + 1
|
||||||
|
|
||||||
# capture trailer
|
|
||||||
trailer_start = i + 1
|
trailer_start = i + 1
|
||||||
trailer_end = trailer_start + trailer_len
|
trailer_end = trailer_start + trailer_len
|
||||||
trailer = blob[trailer_start:trailer_end]
|
trailer = blob[trailer_start:trailer_end]
|
||||||
|
|
||||||
|
# For S3 mode we don't assume checksum type here yet.
|
||||||
frames.append(Frame(
|
frames.append(Frame(
|
||||||
index=idx,
|
index=idx,
|
||||||
start_offset=start_offset,
|
start_offset=start_offset,
|
||||||
end_offset=end_offset,
|
end_offset=end_offset,
|
||||||
payload_raw=bytes(payload_raw),
|
payload_raw=bytes(body),
|
||||||
payload=bytes(payload_raw),
|
payload=bytes(body),
|
||||||
trailer=trailer,
|
trailer=trailer,
|
||||||
crc_match=None
|
checksum_valid=None,
|
||||||
|
checksum_type=None,
|
||||||
|
checksum_hex=None
|
||||||
))
|
))
|
||||||
|
|
||||||
idx += 1
|
idx += 1
|
||||||
state = STATE_IDLE
|
state = IDLE
|
||||||
i = trailer_end
|
i = trailer_end
|
||||||
continue
|
continue
|
||||||
|
|
||||||
else:
|
# Unexpected DLE + byte → treat as literal data
|
||||||
# unexpected sequence: DLE followed by non-DLE/non-ETX
|
body.append(DLE)
|
||||||
# treat both bytes as data (robust recovery)
|
body.append(b)
|
||||||
payload_raw.append(DLE)
|
state = IN_FRAME
|
||||||
payload_raw.append(b)
|
|
||||||
state = STATE_IN_FRAME
|
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
print("Frames parsed:", len(frames))
|
|
||||||
return frames
|
return frames
|
||||||
|
|
||||||
def best_crc_match(payload: bytes, trailer: bytes, little_endian: bool) -> Optional[str]:
|
|
||||||
"""Try to interpret first 2 trailer bytes as CRC16 and see which algorithm matches."""
|
# ------------------------
|
||||||
if len(trailer) < 2:
|
# BW MODE (ACK+STX framed, bare ETX)
|
||||||
return None
|
# ------------------------
|
||||||
given = int.from_bytes(trailer[:2], byteorder="little" if little_endian else "big", signed=False)
|
|
||||||
matches = []
|
def parse_bw(blob: bytes, trailer_len: int, validate_checksum: bool) -> List[Frame]:
|
||||||
for name, fn in CRC_FUNCS.items():
|
frames: List[Frame] = []
|
||||||
calc = fn(payload)
|
|
||||||
if calc == given:
|
IDLE = 0
|
||||||
matches.append(name)
|
IN_FRAME = 1
|
||||||
if len(matches) == 1:
|
AFTER_DLE = 2
|
||||||
return matches[0]
|
|
||||||
if len(matches) > 1:
|
state = IDLE
|
||||||
return " / ".join(matches)
|
body = bytearray()
|
||||||
return None
|
start_offset = 0
|
||||||
|
idx = 0
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
n = len(blob)
|
||||||
|
|
||||||
|
while i < n:
|
||||||
|
b = blob[i]
|
||||||
|
|
||||||
|
if state == IDLE:
|
||||||
|
# Frame start signature: ACK + STX
|
||||||
|
if b == ACK and i + 1 < n and blob[i + 1] == STX:
|
||||||
|
start_offset = i
|
||||||
|
body.clear()
|
||||||
|
state = IN_FRAME
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if state == IN_FRAME:
|
||||||
|
if b == DLE:
|
||||||
|
state = AFTER_DLE
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if b == ETX:
|
||||||
|
# Candidate end-of-frame.
|
||||||
|
# Accept ETX if the next bytes look like a real next-frame start (ACK+STX),
|
||||||
|
# or we're at EOF. This prevents chopping on in-payload 0x03.
|
||||||
|
next_is_start = (i + 2 < n and blob[i + 1] == ACK and blob[i + 2] == STX)
|
||||||
|
at_eof = (i == n - 1)
|
||||||
|
|
||||||
|
if not (next_is_start or at_eof):
|
||||||
|
# Not a real boundary -> payload byte
|
||||||
|
body.append(ETX)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
trailer_start = i + 1
|
||||||
|
trailer_end = trailer_start + trailer_len
|
||||||
|
trailer = blob[trailer_start:trailer_end]
|
||||||
|
|
||||||
|
chk_valid = None
|
||||||
|
chk_type = None
|
||||||
|
chk_hex = None
|
||||||
|
payload = bytes(body)
|
||||||
|
|
||||||
|
if validate_checksum:
|
||||||
|
hit = validate_bw_body_auto(payload)
|
||||||
|
if hit:
|
||||||
|
payload, chk_bytes, chk_type = hit
|
||||||
|
chk_valid = True
|
||||||
|
chk_hex = chk_bytes.hex()
|
||||||
|
else:
|
||||||
|
chk_valid = False
|
||||||
|
|
||||||
|
frames.append(Frame(
|
||||||
|
index=idx,
|
||||||
|
start_offset=start_offset,
|
||||||
|
end_offset=i + 1,
|
||||||
|
payload_raw=bytes(body),
|
||||||
|
payload=payload,
|
||||||
|
trailer=trailer,
|
||||||
|
checksum_valid=chk_valid,
|
||||||
|
checksum_type=chk_type,
|
||||||
|
checksum_hex=chk_hex
|
||||||
|
))
|
||||||
|
idx += 1
|
||||||
|
state = IDLE
|
||||||
|
i = trailer_end
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Normal byte
|
||||||
|
body.append(b)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# AFTER_DLE
|
||||||
|
if b == DLE:
|
||||||
|
body.append(DLE) # 10 10 => literal 10
|
||||||
|
else:
|
||||||
|
# Robust recovery: treat as literal DLE + byte
|
||||||
|
body.append(DLE)
|
||||||
|
body.append(b)
|
||||||
|
state = IN_FRAME
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return frames
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# CLI
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
ap = argparse.ArgumentParser(description="Parse DLE-framed serial capture .bin into frames (and guess CRC).")
|
ap = argparse.ArgumentParser(description="Parse Instantel S3/BW binary captures.")
|
||||||
ap.add_argument("binfile", type=Path, help="Path to capture .bin file")
|
ap.add_argument("binfile", type=Path)
|
||||||
ap.add_argument("--trailer-len", type=int, default=2, help="Bytes to capture after DLE ETX (default: 2)")
|
ap.add_argument("--mode", choices=["s3", "bw"], default="s3")
|
||||||
ap.add_argument("--crc", action="store_true", help="Attempt CRC match using first 2 trailer bytes")
|
ap.add_argument("--trailer-len", type=int, default=0)
|
||||||
ap.add_argument("--crc-endian", choices=["little", "big"], default="little", help="CRC endian when reading trailer")
|
ap.add_argument("--no-checksum", action="store_true")
|
||||||
|
ap.add_argument("--out", type=Path, default=None)
|
||||||
|
|
||||||
ap.add_argument("--out", type=Path, default=None, help="Write JSONL output to this file")
|
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
print(f"s3_parser v{__version__}")
|
||||||
|
|
||||||
blob = args.binfile.read_bytes()
|
blob = args.binfile.read_bytes()
|
||||||
frames = parse_frames(blob, trailer_len=args.trailer_len)
|
|
||||||
|
|
||||||
little = (args.crc_endian == "little")
|
if args.mode == "s3":
|
||||||
if args.crc:
|
frames = parse_s3(blob, args.trailer_len)
|
||||||
for f in frames:
|
else:
|
||||||
f.crc_match = best_crc_match(f.payload, f.trailer, little_endian=little)
|
frames = parse_bw(blob, args.trailer_len, validate_checksum=not args.no_checksum)
|
||||||
|
|
||||||
# Summary
|
print("Frames found:", len(frames))
|
||||||
total = len(frames)
|
|
||||||
crc_hits = sum(1 for f in frames if f.crc_match) if args.crc else 0
|
|
||||||
print(f"Frames found: {total}")
|
|
||||||
if args.crc:
|
|
||||||
print(f"CRC matches: {crc_hits} ({(crc_hits/total*100.0):.1f}%)" if total else "CRC matches: 0")
|
|
||||||
|
|
||||||
# Emit JSONL
|
|
||||||
def to_hex(b: bytes) -> str:
|
def to_hex(b: bytes) -> str:
|
||||||
return b.hex()
|
return b.hex()
|
||||||
|
|
||||||
@@ -239,7 +371,9 @@ def main() -> None:
|
|||||||
"payload_len": len(f.payload),
|
"payload_len": len(f.payload),
|
||||||
"payload_hex": to_hex(f.payload),
|
"payload_hex": to_hex(f.payload),
|
||||||
"trailer_hex": to_hex(f.trailer),
|
"trailer_hex": to_hex(f.trailer),
|
||||||
"crc_match": f.crc_match,
|
"checksum_valid": f.checksum_valid,
|
||||||
|
"checksum_type": f.checksum_type,
|
||||||
|
"checksum_hex": f.checksum_hex,
|
||||||
}
|
}
|
||||||
lines.append(json.dumps(obj))
|
lines.append(json.dumps(obj))
|
||||||
|
|
||||||
@@ -247,11 +381,11 @@ def main() -> None:
|
|||||||
args.out.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
args.out.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||||
print(f"Wrote: {args.out}")
|
print(f"Wrote: {args.out}")
|
||||||
else:
|
else:
|
||||||
# Print first few only (avoid spewing your terminal)
|
|
||||||
for line in lines[:10]:
|
for line in lines[:10]:
|
||||||
print(line)
|
print(line)
|
||||||
if len(lines) > 10:
|
if len(lines) > 10:
|
||||||
print(f"... ({len(lines) - 10} more)")
|
print(f"... ({len(lines) - 10} more)")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user