docs(series4): the schedule file is DECODED -- two records, five confirmations
The operator supplied the ground truth: entry 1 is "start monitoring TEST1" at
07:30, entry 2 is "Auto Call Home" at 19:30. That decodes the file completely.
The body is two 260-byte records plus four zero bytes = 524 exactly, and every
non-zero byte falls inside them:
[0] Action (0 = Auto Call Home, 3 = start monitoring with setup)
[1:4] padding
[4] 1/2h half-hour slot, 0-47
[5] Day
[6] ?? the one unidentified field
[7] name length
[8:260] setup name, null-padded
record @ 0: Action=3 1/2h=15 -> 07:30 Day=3 [6]=2 namelen=9 "TEST1.mmb"
record @260: Action=0 1/2h=39 -> 19:30 Day=3 [6]=16 namelen=0 (no setup)
Five independent confirmations, no fitting:
1. Slots 15 and 39 match the stated 07:30 and 19:30 on a 30-minute grid, and
39-15 = 24 slots = exactly 12 hours.
2. The length byte reads 9 for TEST1.mmb, 40 for the long name in the read
capture, and 0 for the Auto Call Home entry.
3. Auto Call Home carries NO setup name -- direct proof that a schedule entry
can exist with no setup attached, which is what the earlier
DUTYCYCLE_START_MONITOR finding predicted from the firmware side.
4. The 260-byte stride lands record 2's 1/2h exactly at [264].
5. 2 x 260 + 4 = 524, the whole body, nothing left over.
CORRECTION: `27 03 10` at [264] was recorded in the previous commit as a possible
trailer. It is record 2's 1/2h, Day and [6] fields. I had assumed the file held
one record and read the second one as padding -- the non-zero bytes were sitting
there the whole time.
Still open: [6] (2 on the start entry, 16 on the ACH entry -- a Repeat or Day/Week
capture would isolate it), the four remaining action codes, and whether the file
can hold unused record slots.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
This commit is contained in:
@@ -1011,10 +1011,10 @@ the record mode" works: an entry says *at this time, load this setup*. It also
|
|||||||
means the scheduler and the setup list are coupled — deleting a setup that a
|
means the scheduler and the setup list are coupled — deleting a setup that a
|
||||||
schedule references is a foot-gun worth checking before we ever expose either.
|
schedule references is a foot-gun worth checking before we ever expose either.
|
||||||
|
|
||||||
⚠ **The entry internals are NOT decoded.** One entry, one capture, no
|
✅ **The entry internals ARE decoded** — see *The schedule record format* below.
|
||||||
variation to diff against. `03 00 00 00 0f 03 02` and `27 03 10` are recorded
|
The file turned out to hold **two** 260-byte records, not one: `27 03 10` is the
|
||||||
as observed bytes, nothing more. Decoding needs schedules that differ in a
|
second record's time/day fields, not a trailer. `1/2h` is a half-hour slot and
|
||||||
known way — two entries, or one entry at a different time of day.
|
both times check out against what the operator entered.
|
||||||
|
|
||||||
### `SUB 0x47` — the scheduler enable, probably
|
### `SUB 0x47` — the scheduler enable, probably
|
||||||
|
|
||||||
@@ -1490,42 +1490,69 @@ other schedules — or the operator's own saved work — depend on. Nothing in
|
|||||||
protocol or the ack reports that this happened. Validating the reference
|
protocol or the ack reports that this happened. Validating the reference
|
||||||
instead of rewriting the referent avoids the whole class of problem.
|
instead of rewriting the referent avoids the whole class of problem.
|
||||||
|
|
||||||
### The schedule record format, from the firmware's own debug printf
|
### ✅ The schedule record format — DECODED (2026-09-24)
|
||||||
|
|
||||||
|
A debug printf in the scheduler names the fields outright:
|
||||||
|
|
||||||
```
|
```
|
||||||
SCHEDULER : _ReadRecord(%d) -> %s (Action=%u, 1/2h=%u, Day=%u, Setup="%s") [WDAY=%d]
|
SCHEDULER : _ReadRecord(%d) -> %s (Action=%u, 1/2h=%u, Day=%u, Setup="%s") [WDAY=%d]
|
||||||
```
|
```
|
||||||
|
|
||||||
That names the fields outright, and they fit the captured record:
|
The captured file is **two 260-byte records plus four zero bytes** — 524 bytes
|
||||||
|
exactly. Every non-zero byte in the file falls inside those two records.
|
||||||
|
|
||||||
| offset | field | read capture | write capture |
|
```
|
||||||
|---|---|---|---|
|
offset field size notes
|
||||||
| `[0]` | **Action** | `03` | `03` |
|
[0] Action 1 (or uint32 LE at [0:4] — both are zero-extended here)
|
||||||
| `[1:4]` | zero — padding, or `Action` is a uint32 | `00 00 00` | `00 00 00` |
|
[1:4] padding 3 zero in both records
|
||||||
| `[4]` | **1/2h** — half-hour slot | `0f` = 15 | `0f` = 15 |
|
[4] 1/2h 1 half-hour slot, 0–47
|
||||||
| `[5]` | **Day** | `03` | `03` |
|
[5] Day 1 3 in both records
|
||||||
| `[6]` | unidentified (`WDAY`?) | `02` | `02` |
|
[6] ?? 1 the one unidentified field
|
||||||
| `[7]` | **name length** | `0x28` = **40** | `0x09` = **9** |
|
[7] name length 1
|
||||||
| `[8:]` | **Setup** name | 40-char name | `TEST1.mmb` |
|
[8:260] Setup name 252 null-padded
|
||||||
| `[264]` | trailer | `27 03 10` | `27 03 10` |
|
```
|
||||||
|
|
||||||
**The length byte is what anchors this** — it reads 40 for the 40-character name
|
Decoded against the operator's own description of what they entered —
|
||||||
and 9 for `TEST1.mmb`, in the same position, in both directions. The layout is
|
*"start monitoring TEST1 at 7:30 AM, Auto Call Home at 7:30 PM"*:
|
||||||
not a guess.
|
|
||||||
|
|
||||||
`1/2h` implies **30-minute resolution, 48 slots per day**. Slot 15 would be
|
| | record @0 | record @260 |
|
||||||
07:30 if counted from midnight — plausible but ⚠ **unconfirmed**, since the
|
|---|---|---|
|
||||||
schedule's actual time was not recorded alongside the capture. One question to
|
| `Action` | **3** | **0** |
|
||||||
the operator settles it.
|
| `1/2h` | 15 → **07:30** ✅ | 39 → **19:30** ✅ |
|
||||||
|
| `Day` | 3 | 3 |
|
||||||
|
| `[6]` | 2 | 16 |
|
||||||
|
| name length | 9 | **0** |
|
||||||
|
| Setup | `TEST1.mmb` | *(none)* ✅ |
|
||||||
|
|
||||||
⚠ Still unknown, and all answerable with **one schedule containing two entries**:
|
**Five independent confirmations**, no fitting required:
|
||||||
|
|
||||||
- the **record stride** and how many records the file holds (one record was
|
1. Slot 15 = 07:30 and slot 39 = 19:30, both matching the operator's stated
|
||||||
captured; `27 03 10` at `[264]` may be a trailer or a second record's head)
|
times, on a 30-minute grid — and 39 − 15 = 24 slots = exactly 12 hours.
|
||||||
- whether `Action` is one byte or a uint32
|
2. The name-length byte reads 9 for `TEST1.mmb`, 40 for the 40-character name in
|
||||||
- the **action code values** — `03` is presumably
|
the read capture, and **0** for the Auto Call Home entry.
|
||||||
`DUTYCYCLE_START_MONITOR_WITH_SETUP` but the enum's base is unknown
|
3. **Auto Call Home carries no setup name** — which is what it should do, and
|
||||||
- `[6]`, and how `Day` and `WDAY` divide the work
|
direct proof that a schedule entry can exist with no setup attached.
|
||||||
|
4. The 260-byte stride lands the second record's `1/2h` exactly at `[264]`.
|
||||||
|
5. `2 × 260 + 4 = 524`, the whole body, with nothing left over.
|
||||||
|
|
||||||
|
⚠ **Correction:** the `27 03 10` bytes at `[264]` were previously recorded here as
|
||||||
|
a possible trailer. They are **record 2's `1/2h`, `Day` and `[6]` fields**. Not
|
||||||
|
a trailer — a second record hiding behind an assumption that the file held one.
|
||||||
|
|
||||||
|
Action codes, so far:
|
||||||
|
|
||||||
|
| value | action |
|
||||||
|
|---|---|
|
||||||
|
| `0` | **Auto Call Home** |
|
||||||
|
| `3` | **Start monitoring, with setup** |
|
||||||
|
|
||||||
|
⚠ `[6]` is the one field still unidentified — `2` on the start entry, `16` on the
|
||||||
|
Auto Call Home entry. It is not the name length and not the time. A capture
|
||||||
|
that changes only the **Repeat** checkbox, or switches Day↔Week, would isolate it.
|
||||||
|
|
||||||
|
⚠ Also still unknown: whether the file can hold more than the records in use
|
||||||
|
(both captures had every used record contiguous from offset 0), and the remaining
|
||||||
|
four action codes.
|
||||||
|
|
||||||
### Six duty-cycle actions, not five
|
### Six duty-cycle actions, not five
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user