This commit is contained in:
Aiden
2026-05-13 18:12:41 +10:00
parent 890a70f2cc
commit a33fea718d
20 changed files with 763 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.pyc

View File

@@ -0,0 +1,11 @@
Sequence probe: 2 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
17:59:32.142 TX group=1 frame=1 len=006 00 00 00 00 80 DA
17:59:32.142 RX group=1 frame=1 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
17:59:33.412 TX group=1 frame=2 len=006 00 00 A0 00 80 7A
17:59:33.412 RX group=1 frame=2 ANOMALY 36 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 3 expected 00
17:59:33.412 RX group=1 frame=2 raw 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5
Anomalies: 1

View File

@@ -0,0 +1,11 @@
Sequence probe: 2 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 A0 20 D0 0A
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
17:59:47.538 TX group=1 frame=1 len=006 00 00 00 00 80 DA
17:59:47.538 RX group=1 frame=1 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
17:59:48.803 TX group=1 frame=2 len=006 00 00 A0 20 D0 0A
17:59:48.803 RX group=1 frame=2 ANOMALY 36 RX bytes; first mismatch at byte 1: got 00, heartbeat offset 3 expected 80
17:59:48.803 RX group=1 frame=2 raw 00 00 00 00 80 DA 07 80 E8 48 3A 47 07 80 E8 48 3A 47 07 80 E8 48 3A 47 07 80 E8 48 3A 47 07 80 E8 48 3A 47
Anomalies: 1

View File

@@ -0,0 +1,11 @@
Sequence probe: 2 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 A0 40 30 8A
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
18:00:05.990 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:00:05.990 RX group=1 frame=1 heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
18:00:07.259 TX group=1 frame=2 len=006 00 00 A0 40 30 8A
18:00:07.259 RX group=1 frame=2 ANOMALY 36 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 3 expected 00
18:00:07.259 RX group=1 frame=2 raw 07 80 68 58 26 CB 07 80 68 58 26 CB 07 80 68 58 26 CB 07 80 68 58 26 CB 07 80 68 58 26 CB 07 80 68 58 26 CB
Anomalies: 1

View File

@@ -0,0 +1,11 @@
Sequence probe: 2 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 A0 60 30 AA
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
18:00:30.467 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:00:30.467 RX group=1 frame=1 heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
18:00:31.737 TX group=1 frame=2 len=006 00 00 A0 60 30 AA
18:00:31.737 RX group=1 frame=2 ANOMALY 36 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 3 expected 00
18:00:31.737 RX group=1 frame=2 raw 07 80 68 58 26 CB 07 80 68 58 26 CB 07 80 68 58 26 CB 07 80 68 58 26 CB 07 80 68 58 26 CB 07 80 68 58 26 CB
Anomalies: 1

View File

@@ -0,0 +1,15 @@
Sequence probe: 3 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 90 00 80 4A
FRAME 3: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
18:00:45.254 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:00:45.254 RX group=1 frame=1 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:00:46.313 TX group=1 frame=2 len=006 00 00 90 00 80 4A
18:00:46.313 RX group=1 frame=2 ANOMALY 30 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 3 expected 00
18:00:46.313 RX group=1 frame=2 raw 07 80 64 40 30 C9 07 80 64 40 30 C9 07 80 64 40 30 C9 07 80 64 40 30 C9 07 80 64 40 30 C9
18:00:47.371 TX group=1 frame=3 len=006 00 00 A0 00 80 7A
18:00:47.371 RX group=1 frame=3 ANOMALY 30 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 0 expected 00
18:00:47.371 RX group=1 frame=3 raw 07 80 64 40 30 C9 00 00 00 00 80 DA 00 00 00 00 80 DA 00 00 00 00 80 DA 00 00 00 00 80 DA
Anomalies: 2

View File

@@ -0,0 +1,14 @@
Sequence probe: 3 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 9F 00 80 45
FRAME 3: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
BEGIN group 1/1
18:01:04.213 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:01:04.213 RX group=1 frame=1 ANOMALY 18 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 0 expected 00
18:01:04.213 RX group=1 frame=1 raw 07 80 40 40 30 ED 00 00 00 00 80 DA 00 00 00 00 80 DA
18:01:05.268 TX group=1 frame=2 len=006 00 00 9F 00 80 45
18:01:05.268 RX group=1 frame=2 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:01:06.328 TX group=1 frame=3 len=006 00 00 A0 00 80 7A
18:01:06.328 RX group=1 frame=3 heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
Anomalies: 1

View File

@@ -0,0 +1,14 @@
Sequence probe: 3 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 AF 00 80 75
FRAME 3: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
18:01:22.379 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:01:22.379 RX group=1 frame=1 heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
18:01:23.438 TX group=1 frame=2 len=006 00 00 AF 00 80 75
18:01:23.438 RX group=1 frame=2 ANOMALY 32 RX bytes; first mismatch at byte 0: got 00, heartbeat offset 4 expected 80
18:01:23.438 RX group=1 frame=2 raw 00 00 07 80 0D 04 AB 7F 00 00 00 00 80 DA 00 00 00 00 80 DA 00 00 00 00 80 DA 00 00 00 00 80 DA
18:01:24.493 TX group=1 frame=3 len=006 00 00 A0 00 80 7A
18:01:24.493 RX group=1 frame=3 heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
Anomalies: 1

View File

@@ -0,0 +1,14 @@
Sequence probe: 3 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 B7 00 80 6D
FRAME 3: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
18:01:39.295 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:01:39.295 RX group=1 frame=1 heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
18:01:40.351 TX group=1 frame=2 len=006 00 00 B7 00 80 6D
18:01:40.351 RX group=1 frame=2 ANOMALY 36 RX bytes; first mismatch at byte 1: got 00, heartbeat offset 3 expected 80
18:01:40.351 RX group=1 frame=2 raw 00 00 00 00 80 DA 07 80 1B 08 D6 18 07 80 1B 08 D6 18 07 80 1B 08 D6 18 07 80 1B 08 D6 18 07 80 1B 08 D6 18
18:01:41.409 TX group=1 frame=3 len=006 00 00 A0 00 80 7A
18:01:41.409 RX group=1 frame=3 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
Anomalies: 1

View File

@@ -0,0 +1,15 @@
Sequence probe: 3 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 BB 00 80 61
FRAME 3: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
BEGIN group 1/1
18:01:53.451 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:01:53.451 RX group=1 frame=1 heartbeat-compatible RX: 12 bytes, offset 0, 2 frames + 0 bytes
18:01:54.508 TX group=1 frame=2 len=006 00 00 BB 00 80 61
18:01:54.508 RX group=1 frame=2 ANOMALY 30 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 3 expected 00
18:01:54.508 RX group=1 frame=2 raw 07 80 37 10 2C D6 07 80 37 10 2C D6 07 80 37 10 2C D6 07 80 37 10 2C D6 07 80 37 10 2C D6
18:01:55.566 TX group=1 frame=3 len=006 00 00 A0 00 80 7A
18:01:55.566 RX group=1 frame=3 ANOMALY 30 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 0 expected 00
18:01:55.566 RX group=1 frame=3 raw 07 80 37 10 2C D6 00 00 00 00 80 DA 00 00 00 00 80 DA 00 00 00 00 80 DA 00 00 00 00 80 DA
Anomalies: 2

View File

@@ -0,0 +1,13 @@
Sequence probe: 3 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 FF 00 80 25
FRAME 3: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
BEGIN group 1/1
18:02:08.775 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:02:08.775 RX group=1 frame=1 heartbeat-compatible RX: 12 bytes, offset 0, 2 frames + 0 bytes
18:02:09.829 TX group=1 frame=2 len=006 00 00 FF 00 80 25
18:02:09.829 RX group=1 frame=2 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:02:10.885 TX group=1 frame=3 len=006 00 00 A0 00 80 7A
18:02:10.885 RX group=1 frame=3 heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
Anomalies: 0

View File

@@ -0,0 +1,20 @@
Sequence probe: 5 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 A0 00 80 7A
FRAME 3: 00 00 A1 00 80 7B
FRAME 4: 00 00 A4 00 80 7E
FRAME 5: 00 00 A5 00 80 7F
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
18:02:32.900 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:02:32.900 RX group=1 frame=1 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:02:33.775 TX group=1 frame=2 len=006 00 00 A0 00 80 7A
18:02:33.775 RX group=1 frame=2 ANOMALY 24 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 3 expected 00
18:02:33.775 RX group=1 frame=2 raw 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5
18:02:34.650 TX group=1 frame=3 len=006 00 00 A1 00 80 7B
18:02:34.650 RX group=1 frame=3 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:02:35.525 TX group=1 frame=4 len=006 00 00 A4 00 80 7E
18:02:35.525 RX group=1 frame=4 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:02:36.399 TX group=1 frame=5 len=006 00 00 A5 00 80 7F
18:02:36.399 RX group=1 frame=5 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
Anomalies: 1

View File

@@ -0,0 +1,20 @@
Sequence probe: 5 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 B0 00 80 6A
FRAME 3: 00 00 B1 00 80 6B
FRAME 4: 00 00 B8 00 80 62
FRAME 5: 00 00 BC 00 80 66
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
18:02:48.308 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:02:48.308 RX group=1 frame=1 heartbeat-compatible RX: 12 bytes, offset 0, 2 frames + 0 bytes
18:02:49.181 TX group=1 frame=2 len=006 00 00 B0 00 80 6A
18:02:49.181 RX group=1 frame=2 ANOMALY 30 RX bytes; first mismatch at byte 6: got 07, heartbeat offset 0 expected 00
18:02:49.181 RX group=1 frame=2 raw 00 00 00 00 80 DA 07 80 EC 40 30 41 07 80 EC 40 30 41 07 80 EC 40 30 41 07 80 EC 40 30 41
18:02:50.055 TX group=1 frame=3 len=006 00 00 B1 00 80 6B
18:02:50.055 RX group=1 frame=3 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:02:50.925 TX group=1 frame=4 len=006 00 00 B8 00 80 62
18:02:50.925 RX group=1 frame=4 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:02:51.800 TX group=1 frame=5 len=006 00 00 BC 00 80 66
18:02:51.800 RX group=1 frame=5 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
Anomalies: 1

View File

@@ -0,0 +1,11 @@
Sequence probe: 2 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
17:58:03.154 TX group=1 frame=1 len=006 00 00 00 00 80 DA
17:58:03.154 RX group=1 frame=1 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
17:58:04.426 TX group=1 frame=2 len=006 00 00 A0 00 80 7A
17:58:04.426 RX group=1 frame=2 ANOMALY 36 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 3 expected 00
17:58:04.426 RX group=1 frame=2 raw 07 80 E8 40 30 45 07 80 E8 40 30 45 07 80 E8 40 30 45 07 80 E8 40 30 45 07 80 E8 40 30 45 07 80 E8 40 30 45
Anomalies: 1

View File

@@ -0,0 +1,10 @@
Sequence probe: 2 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 80 A0 00 80 FA
BASELINE heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
BEGIN group 1/1
17:58:30.063 TX group=1 frame=1 len=006 00 00 00 00 80 DA
17:58:30.063 RX group=1 frame=1 heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
17:58:31.333 TX group=1 frame=2 len=006 00 80 A0 00 80 FA
17:58:31.333 RX group=1 frame=2 heartbeat-compatible RX: 19 bytes, offset 0, 3 frames + 1 bytes
Anomalies: 0

View File

@@ -0,0 +1,10 @@
Sequence probe: 2 frames x 1 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 80 00 A0 00 80 FA
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/1
17:58:56.577 TX group=1 frame=1 len=006 00 00 00 00 80 DA
17:58:56.577 RX group=1 frame=1 heartbeat-compatible RX: 19 bytes, offset 0, 3 frames + 1 bytes
17:58:57.850 TX group=1 frame=2 len=006 80 00 A0 00 80 FA
17:58:57.850 RX group=1 frame=2 heartbeat-compatible RX: 23 bytes, offset 1, 3 frames + 5 bytes
Anomalies: 0

View File

@@ -0,0 +1,25 @@
Sequence probe: 2 frames x 3 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 A0 00 80 7A
BASELINE heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
BEGIN group 1/3
18:03:49.510 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:03:49.510 RX group=1 frame=1 heartbeat-compatible RX: 13 bytes, offset 0, 2 frames + 1 bytes
18:03:50.564 TX group=1 frame=2 len=006 00 00 A0 00 80 7A
18:03:50.564 RX group=1 frame=2 ANOMALY 35 RX bytes; first mismatch at byte 0: got 00, heartbeat offset 4 expected 80
18:03:50.564 RX group=1 frame=2 raw 00 00 00 80 DA 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5
GROUP 1 TAIL ANOMALY 18 RX bytes; first mismatch at byte 0: got 07, heartbeat offset 3 expected 00
GROUP 1 TAIL raw 07 80 68 40 30 C5 07 80 68 40 30 C5 07 80 68 40 30 C5
BEGIN group 2/3
18:03:53.892 TX group=2 frame=1 len=006 00 00 00 00 80 DA
18:03:53.892 RX group=2 frame=1 heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
18:03:54.952 TX group=2 frame=2 len=006 00 00 A0 00 80 7A
18:03:54.952 RX group=2 frame=2 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
GROUP 2 TAIL heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 3/3
18:03:58.282 TX group=3 frame=1 len=006 00 00 00 00 80 DA
18:03:58.282 RX group=3 frame=1 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:03:59.339 TX group=3 frame=2 len=006 00 00 A0 00 80 7A
18:03:59.339 RX group=3 frame=2 heartbeat-compatible RX: 30 bytes, offset 0, 5 frames + 0 bytes
GROUP 3 TAIL heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
Anomalies: 2

View File

@@ -0,0 +1,31 @@
Sequence probe: 3 frames x 3 group(s) on COM5 at 38400 8N1
FRAME 1: 00 00 00 00 80 DA
FRAME 2: 00 00 B0 00 80 6A
FRAME 3: 00 00 B1 00 80 6B
BASELINE heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
BEGIN group 1/3
18:03:14.221 TX group=1 frame=1 len=006 00 00 00 00 80 DA
18:03:14.221 RX group=1 frame=1 heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
18:03:15.095 TX group=1 frame=2 len=006 00 00 B0 00 80 6A
18:03:15.095 RX group=1 frame=2 ANOMALY 32 RX bytes; first mismatch at byte 0: got 00, heartbeat offset 4 expected 80
18:03:15.095 RX group=1 frame=2 raw 00 00 07 80 6C 40 30 C1 00 00 00 00 80 DA 00 00 00 00 80 DA 00 00 00 00 80 DA 00 00 00 00 80 DA
18:03:15.972 TX group=1 frame=3 len=006 00 00 B1 00 80 6B
18:03:15.972 RX group=1 frame=3 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
GROUP 1 TAIL heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
BEGIN group 2/3
18:03:19.123 TX group=2 frame=1 len=006 00 00 00 00 80 DA
18:03:19.123 RX group=2 frame=1 heartbeat-compatible RX: 36 bytes, offset 0, 6 frames + 0 bytes
18:03:19.995 TX group=2 frame=2 len=006 00 00 B0 00 80 6A
18:03:19.995 RX group=2 frame=2 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:03:20.868 TX group=2 frame=3 len=006 00 00 B1 00 80 6B
18:03:20.868 RX group=2 frame=3 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
GROUP 2 TAIL heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
BEGIN group 3/3
18:03:24.018 TX group=3 frame=1 len=006 00 00 00 00 80 DA
18:03:24.018 RX group=3 frame=1 heartbeat-compatible RX: 36 bytes, offset 0, 6 frames + 0 bytes
18:03:24.891 TX group=3 frame=2 len=006 00 00 B0 00 80 6A
18:03:24.891 RX group=3 frame=2 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
18:03:25.767 TX group=3 frame=3 len=006 00 00 B1 00 80 6B
18:03:25.767 RX group=3 frame=3 heartbeat-compatible RX: 24 bytes, offset 0, 4 frames + 0 bytes
GROUP 3 TAIL heartbeat-compatible RX: 18 bytes, offset 0, 3 frames + 0 bytes
Anomalies: 1

View File

@@ -3609,3 +3609,271 @@ Interpretation:
- Best current model: these are legitimate outer-table queries whose returned
payload can still depend on selector context, prior sequence, or exactly when
in the panel's internal state machine they are sampled.
## Host Identity / Capability Exchange Lead Ladder
Goal:
- Test whether the CCU is expected to identify itself before asking for
capability/state blocks.
- Separate "query selector/page" behavior from "host identity/session setup"
behavior.
- Check whether a short query burst behaves more like a capability poll than a
single one-shot request.
Tooling:
- Use `scripts/serial_sequence_probe.py` for fixed multi-frame sequences where
the canonical primer stays constant and only later frames vary.
- Use `scripts/serial_primer_candidate_sweep.py` when only a simple
`primer -> candidate` pair is needed.
### Test HI1: Prefix Variation On A Stable Query
Keep the known-good primer fixed and vary only the prefix bytes of the `A0`
query frame. If the response changes, the host prefix bytes may carry CCU
identity, addressing, or mode information rather than being ignored padding.
Power-cycle before each run.
```powershell
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 A0 00 80 7A" --read-after-frame 1.2 --log captures/rcp-hostid-prefix-0000-a0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 80 A0 00 80 FA" --read-after-frame 1.2 --log captures/rcp-hostid-prefix-0080-a0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "80 00 A0 00 80 FA" --read-after-frame 1.2 --log captures/rcp-hostid-prefix-8000-a0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "07 80 A0 00 80 FD" --read-after-frame 1.2 --log captures/rcp-hostid-prefix-0780-a0.txt
```
What to watch for:
- Same `A0` block as baseline: prefix bytes probably are not the missing host
identity on their own.
- Different structured block: prefix bytes likely select host identity, page,
or role.
- Heartbeat only: that prefix pair may be invalid or reserved.
### Test HI2: State/Value Variation On A Stable Query
Keep the canonical prefix and command byte, but vary the state/value fields on
the `A0` query. This checks whether the host is supposed to present status or
capability bits in fields that we have mostly left at `00 80`.
Power-cycle before each run.
```powershell
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 A0 00 80 7A" --read-after-frame 1.2 --log captures/rcp-hostid-a0-0080.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 A0 20 D0 0A" --read-after-frame 1.2 --log captures/rcp-hostid-a0-20d0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 A0 40 30 8A" --read-after-frame 1.2 --log captures/rcp-hostid-a0-4030.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 A0 60 30 AA" --read-after-frame 1.2 --log captures/rcp-hostid-a0-6030.txt
```
What to watch for:
- Same `A0` block every time: host state/value fields may be ignored here.
- Different block family or different returned value bytes: these fields may be
host-presented capability/status bits.
- LCD/LED changes without a different serial block: possible session-state side
effect rather than a simple table read.
### Test HI3: Primer -> Host-Announce -> Query
Try likely selector/identity-looking bytes as a middle frame before the stable
`A0` query. This is the direct "CCU says who it is first" test.
Power-cycle before each run.
```powershell
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 90 00 80 4A" --frame "00 00 A0 00 80 7A" --read-after-frame 1.0 --log captures/rcp-hostid-announce-90-then-a0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 9F 00 80 45" --frame "00 00 A0 00 80 7A" --read-after-frame 1.0 --log captures/rcp-hostid-announce-9f-then-a0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 AF 00 80 75" --frame "00 00 A0 00 80 7A" --read-after-frame 1.0 --log captures/rcp-hostid-announce-af-then-a0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 B7 00 80 6D" --frame "00 00 A0 00 80 7A" --read-after-frame 1.0 --log captures/rcp-hostid-announce-b7-then-a0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 BB 00 80 61" --frame "00 00 A0 00 80 7A" --read-after-frame 1.0 --log captures/rcp-hostid-announce-bb-then-a0.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 FF 00 80 25" --frame "00 00 A0 00 80 7A" --read-after-frame 1.0 --log captures/rcp-hostid-announce-ff-then-a0.txt
```
What to watch for:
- Middle frame gets heartbeat only, third frame still returns plain `A0` block:
the announce byte probably is not sufficient.
- Middle frame changes the later `A0` response: strong evidence for a
host-identity/selector stage.
- Middle frame alone produces a new block: it may itself be a readable
capability/identity query rather than a pure host announce.
### Test HI4: Capability-Poll Block
Send a short family of related queries as if a CCU is polling multiple
capability blocks in one startup pass. This checks whether the panel expects a
cluster of reads instead of one isolated query.
Power-cycle before each run.
```powershell
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 A0 00 80 7A" --frame "00 00 A1 00 80 7B" --frame "00 00 A4 00 80 7E" --frame "00 00 A5 00 80 7F" --read-after-frame 0.8 --log captures/rcp-hostid-capblock-a-family.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 B0 00 80 6A" --frame "00 00 B1 00 80 6B" --frame "00 00 B8 00 80 62" --frame "00 00 BC 00 80 66" --read-after-frame 0.8 --log captures/rcp-hostid-capblock-b-family.txt
```
What to watch for:
- Only the first query in the block responds: the one-shot model still dominates.
- Later queries also respond once the family is polled as a burst: this would be
a major new lead toward CCU-style startup behavior.
- A later query changes the LCD or LEDs even if the first one looks ordinary:
still worth treating as a lead.
### Test HI5: Repeated Poll Group
Repeat the same short poll group with a gap, to test whether the panel wants
periodic polling or whether only the first startup block matters.
Power-cycle before each run.
```powershell
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 B0 00 80 6A" --frame "00 00 B1 00 80 6B" --repeat 3 --repeat-interval 1.5 --read-after-frame 0.8 --read-after-group 0.8 --log captures/rcp-hostid-repeat-b0-b1.txt
python scripts/serial_sequence_probe.py --port COM5 --prompt --frame "00 00 00 00 80 DA" --frame "00 00 A0 00 80 7A" --repeat 3 --repeat-interval 1.5 --read-after-frame 1.0 --read-after-group 0.8 --log captures/rcp-hostid-repeat-a0.txt
```
What to watch for:
- Only group 1 responds: startup window or latch behavior still dominates.
- Later groups begin to respond too: periodic polling may be part of the
expected CCU session.
- A later group changes visible state even with similar serial output: possible
session-timer or keepalive behavior.
Recommended order:
1. `HI3` because it most directly tests the "CCU identifies itself first"
hypothesis.
2. `HI4` because a capability-poll burst is a plausible Sony startup pattern.
3. `HI1` and `HI2` if the first two stay flat and we need to isolate which host
fields matter.
### 2026-05-13 Host Identity / Capability Result
Captures:
- `captures/rcp-hostid-prefix-0000-a0.txt`
- `captures/rcp-hostid-prefix-0080-a0.txt`
- `captures/rcp-hostid-prefix-8000-a0.txt`
- `captures/rcp-hostid-a0-0080.txt`
- `captures/rcp-hostid-a0-20d0.txt`
- `captures/rcp-hostid-a0-4030.txt`
- `captures/rcp-hostid-a0-6030.txt`
- `captures/rcp-hostid-announce-90-then-a0.txt`
- `captures/rcp-hostid-announce-9f-then-a0.txt`
- `captures/rcp-hostid-announce-af-then-a0.txt`
- `captures/rcp-hostid-announce-b7-then-a0.txt`
- `captures/rcp-hostid-announce-bb-then-a0.txt`
- `captures/rcp-hostid-announce-ff-then-a0.txt`
- `captures/rcp-hostid-capblock-a-family.txt`
- `captures/rcp-hostid-capblock-b-family.txt`
- `captures/rcp-hostid-repeat-a0.txt`
- `captures/rcp-hostid-repeat-b0-b1.txt`
Not run / no capture present:
- `captures/rcp-hostid-prefix-0780-a0.txt`
#### HI1: Prefix Variation On `A0`
Observed result:
| Query frame after primer | Result |
| --- | --- |
| `00 00 A0 00 80 7A` | conflicting captures: one run returned `07 80 E8 40 30 45`, another returned `07 80 68 40 30 C5` |
| `00 80 A0 00 80 FA` | heartbeat only |
| `80 00 A0 00 80 FA` | heartbeat only |
| `07 80 A0 00 80 FD` | not run |
Read:
- Nonzero host prefix bytes did not help. The tested `00 80` and `80 00`
prefixes suppressed the `A0` response entirely.
- The plain `00 00` prefix remains the only confirmed working host prefix for
`A0`, although the returned block still varies across runs.
#### HI2: State/Value Variation On `A0`
Observed result:
| Query frame after primer | Observed RCP response |
| --- | --- |
| `00 00 A0 00 80 7A` | `07 80 68 40 30 C5` repeated |
| `00 00 A0 20 D0 0A` | `07 80 E8 48 3A 47` repeated |
| `00 00 A0 40 30 8A` | `07 80 68 58 26 CB` repeated |
| `00 00 A0 60 30 AA` | `07 80 68 58 26 CB` repeated |
Read:
- This is the strongest new lead in the set.
- The `A0` response is not fixed: the host `state/value` fields clearly affect
the returned block.
- That strongly supports the idea that these fields are carrying host-presented
status, selector, or capability information, not just filler.
#### HI3: Primer -> Host-Announce -> `A0`
Observed result:
| Sequence | Middle-frame result | Later `A0` result |
| --- | --- | --- |
| `00 -> 90 -> A0` | `07 80 64 40 30 C9` repeated | no clean `A0`; only one more `07 80 64 40 30 C9` then heartbeat |
| `00 -> 9F -> A0` | heartbeat only after `9F` | heartbeat only after `A0`; a prior anomaly `07 80 40 40 30 ED` appeared immediately after the primer |
| `00 -> AF -> A0` | `07 80 0D 04 AB 7F` visible with a leading heartbeat fragment | heartbeat only after `A0` |
| `00 -> B7 -> A0` | `07 80 1B 08 D6 18` repeated | heartbeat only after `A0` |
| `00 -> BB -> A0` | `07 80 37 10 2C D6` repeated | no clean `A0`; only one more `07 80 37 10 2C D6` then heartbeat |
| `00 -> FF -> A0` | heartbeat only | heartbeat only |
Read:
- The "announce" bytes behaved more like readable/query commands than like a
host identity banner the panel accepts and then builds on.
- In most runs, the middle frame consumed the one-shot response opportunity and
the following `A0` did not produce its own block.
- So far this argues against a simple three-step handshake of
`primer -> host identity -> query`.
#### HI4: Capability-Poll Block
Observed result:
| Block | Result |
| --- | --- |
| `00 -> A0 -> A1 -> A4 -> A5` | only `A0` responded (`07 80 68 40 30 C5`); `A1`, `A4`, and `A5` were heartbeat only |
| `00 -> B0 -> B1 -> B8 -> BC` | only `B0` responded (`07 80 EC 40 30 41` with a leading heartbeat fragment); `B1`, `B8`, and `BC` were heartbeat only |
Read:
- A burst of related readable queries did not unlock later responses in the same
startup pass.
- The one-shot model still dominates: first successful readable query responds,
later ones in the burst are suppressed.
#### HI5: Repeated Poll Group
Observed result:
| Repeated group | Result |
| --- | --- |
| `00 -> A0`, repeated 3 times | only group 1 produced `07 80 68 40 30 C5`; groups 2 and 3 were heartbeat only |
| `00 -> B0 -> B1`, repeated 3 times | only group 1 `B0` produced a response; later groups were heartbeat only and `B1` never responded |
Read:
- Periodic polling without a power cycle did not open a sustained session.
- The panel still behaves like it offers one early readable response block, then
falls back to heartbeat-only behavior.
Overall interpretation:
- The cleanest new evidence is that host `state/value` fields matter a lot for
at least the `A0` family.
- The tested nonzero prefixes do not look like a missing CCU identity by
themselves.
- Candidate "announce" bytes mostly act like ordinary readable/query selectors,
not like a reusable host identity stage.
- Capability-poll bursts and repeated poll groups did not create a multi-query
session.
- Best current model: the startup exchange probably does involve host-presented
status or selector bits, but the currently tested sequences still land in a
one-shot query regime rather than an active maintained session.

View File

@@ -0,0 +1,238 @@
#!/usr/bin/env python3
"""Send arbitrary RCP-TX7 host frame sequences and classify RX windows.
This helper is meant for exploratory multi-frame tests such as:
primer -> announce/selector -> query
primer -> short query block
repeated pseudo-keepalive groups
Each transmitted frame can be followed by a small read window so responses can
be attributed to a specific host frame more easily than in a long raw capture.
"""
from __future__ import annotations
import argparse
import datetime as dt
import sys
import time
try:
import serial
except ImportError:
print(
"Missing dependency: pyserial\n"
"Install it with: python -m pip install pyserial",
file=sys.stderr,
)
raise SystemExit(2)
HEARTBEAT = bytes.fromhex("00 00 00 00 80 DA")
def parse_hex_bytes(text: str) -> bytes:
normalized = text.replace(",", " ").replace("0x", "").replace("0X", "")
parts = normalized.split()
if not parts:
raise argparse.ArgumentTypeError("hex frame cannot be empty")
try:
values = [int(part, 16) for part in parts]
except ValueError as exc:
raise argparse.ArgumentTypeError(f"invalid hex byte list: {text}") from exc
if any(value < 0 or value > 0xFF for value in values):
raise argparse.ArgumentTypeError("hex values must be bytes")
return bytes(values)
def hex_preview(data: bytes) -> str:
return " ".join(f"{byte:02X}" for byte in data)
def ascii_preview(data: bytes) -> str:
return "".join(chr(byte) if 32 <= byte <= 126 else "." for byte in data)
def make_logger(path: str | None):
log_file = open(path, "a", encoding="utf-8") if path else None
def emit(line: str) -> None:
print(line)
if log_file:
log_file.write(line + "\n")
log_file.flush()
return emit, log_file
def heartbeat_offset(data: bytes) -> int | None:
if not data:
return 0
for offset in range(len(HEARTBEAT)):
if all(byte == HEARTBEAT[(offset + index) % len(HEARTBEAT)] for index, byte in enumerate(data)):
return offset
return None
def first_mismatch(data: bytes, offset: int) -> tuple[int, int, int] | None:
for index, byte in enumerate(data):
expected = HEARTBEAT[(offset + index) % len(HEARTBEAT)]
if byte != expected:
return index, byte, expected
return None
def classify_rx(data: bytes) -> tuple[bool, str]:
if not data:
return False, "no RX bytes"
offset = heartbeat_offset(data)
if offset is not None:
full = len(data) // len(HEARTBEAT)
extra = len(data) % len(HEARTBEAT)
return False, f"heartbeat-compatible RX: {len(data)} bytes, offset {offset}, {full} frames + {extra} bytes"
best_offset = min(
range(len(HEARTBEAT)),
key=lambda candidate: sum(
byte != HEARTBEAT[(candidate + index) % len(HEARTBEAT)]
for index, byte in enumerate(data)
),
)
mismatch = first_mismatch(data, best_offset)
if mismatch is None:
return False, "heartbeat-compatible RX"
index, byte, expected = mismatch
return (
True,
f"ANOMALY {len(data)} RX bytes; first mismatch at byte {index}: "
f"got {byte:02X}, heartbeat offset {best_offset} expected {expected:02X}",
)
def read_window(ser: serial.Serial, duration: float) -> bytes:
stop_at = time.monotonic() + duration
data = bytearray()
while time.monotonic() < stop_at:
chunk = ser.read(128)
if chunk:
data.extend(chunk)
return bytes(data)
def emit_rx(emit, label: str, data: bytes, ascii_mode: bool) -> bool:
is_anomaly, note = classify_rx(data)
emit(f"{label} {note}")
if data and ascii_mode:
emit(f"{'':14} ASCII {ascii_preview(data)}")
if is_anomaly:
emit(f"{label} raw {hex_preview(data)}")
return is_anomaly
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Send an arbitrary host frame sequence and classify RX after each step."
)
parser.add_argument("--port", required=True, help="serial port, for example COM5")
parser.add_argument("--baud", type=int, default=38400)
parser.add_argument("--timeout", type=float, default=0.03)
parser.add_argument("--log", help="append probe log to this file")
parser.add_argument("--ascii", action="store_true")
parser.add_argument("--prompt", action="store_true", help="pause before starting so you can power-cycle or prepare the panel")
parser.add_argument("--pre-read", type=float, default=3.0, help="seconds to observe baseline heartbeat before the first frame")
parser.add_argument("--delay", type=float, default=0.0, help="extra delay after prompt/baseline before the first frame")
parser.add_argument(
"--frame",
type=parse_hex_bytes,
action="append",
required=True,
help="hex frame to send; repeat the flag to build a sequence",
)
parser.add_argument("--frame-interval", type=float, default=0.05, help="delay between consecutive frames in the same group")
parser.add_argument("--read-after-frame", type=float, default=0.8, help="seconds to read/classify after each frame")
parser.add_argument("--repeat", type=int, default=1, help="how many times to send the full frame group")
parser.add_argument("--repeat-interval", type=float, default=0.0, help="delay between repeated frame groups")
parser.add_argument("--read-after-group", type=float, default=0.0, help="extra seconds to read/classify after each full group")
return parser.parse_args()
def main() -> int:
args = parse_args()
emit, log_file = make_logger(args.log)
try:
with serial.Serial(
port=args.port,
baudrate=args.baud,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=args.timeout,
write_timeout=1.0,
rtscts=False,
dsrdtr=False,
xonxoff=False,
) as ser:
emit(
f"Sequence probe: {len(args.frame)} frames x {args.repeat} group(s) "
f"on {ser.port} at {ser.baudrate} 8N1"
)
for index, frame in enumerate(args.frame, start=1):
emit(f"FRAME {index}: {hex_preview(frame)}")
if args.prompt:
input("Prepare/power-cycle RCP, wait for heartbeat, then press Enter: ")
ser.reset_input_buffer()
emit_rx(emit, "BASELINE", read_window(ser, args.pre_read), args.ascii)
if args.delay > 0:
time.sleep(args.delay)
anomaly_count = 0
for group_index in range(1, args.repeat + 1):
if group_index > 1 and args.repeat_interval > 0:
time.sleep(args.repeat_interval)
emit(f"BEGIN group {group_index}/{args.repeat}")
for frame_index, frame in enumerate(args.frame, start=1):
stamp = dt.datetime.now().strftime("%H:%M:%S.%f")[:-3]
emit(
f"{stamp} TX group={group_index} frame={frame_index} "
f"len={len(frame):03d} {hex_preview(frame)}"
)
ser.write(frame)
ser.flush()
if args.read_after_frame > 0:
label = f"{stamp} RX group={group_index} frame={frame_index}"
if emit_rx(emit, label, read_window(ser, args.read_after_frame), args.ascii):
anomaly_count += 1
if frame_index < len(args.frame) and args.frame_interval > 0:
time.sleep(args.frame_interval)
if args.read_after_group > 0:
label = f"GROUP {group_index} TAIL"
if emit_rx(emit, label, read_window(ser, args.read_after_group), args.ascii):
anomaly_count += 1
emit(f"Anomalies: {anomaly_count}")
except KeyboardInterrupt:
emit("Stopped.")
return 0
except serial.SerialException as exc:
print(f"Serial error: {exc}", file=sys.stderr)
return 1
finally:
if log_file:
log_file.close()
return 0
if __name__ == "__main__":
raise SystemExit(main())