Repository navigation
TinyG 450.01 (edge-next pre-release)
Pre-releaseTinyG 450.01 (edge-next)
Built from edge-next at 425fa92e. This is a pre-release for hosts that flash firmware from the release list; it carries every fix made on edge-next since edge-0.97 build 449.01. Expect follow-up builds (450.02, ...) as the bug hunt continues: each later release supersedes this one.
158 firmware fixes, 5 features, 15 harness/test merges, 3 documentation merges (196 merges, 833 commits).
Flashing
- Flash
tinyg-450.01.hexthrough the xboot bootloader: send{"boot":1}(or$boot=1), then
avrdude -p x192a3 -c avr109 -b 115200 -P <port> -U flash:w:tinyg-450.01.hex. Never use a chip erase (-e): it wipes the settings in EEPROM. - Back up settings first (
$$in text mode, or a JSON dump). A build with a new build number reloads defaults on its first boot. SHA256SUMSin the release lists the checksums of the hex and elf.
Highlights
Fast, position-keeping limit stop (E031)
- On a limit switch hit, the switch interrupt itself requests the stop. Edge used to wait for the main loop.
- The braking distance is computed on the fly: the hold's deceleration tail is rescaled to the homing jerk of the axes in motion, so the machine stops within sqrt(xjm/xjh) of the normal distance. It is never softer than a normal hold.
- Position is kept: no lost steps and no forced re-home of the coordinate system. The axes are marked unhomed, so the host knows homing should be repeated, and the machine enters ALARM.
- Verified on the bench by measuring the stop from the firmware's physical step count after a software limit switch trip. Real-time latency is still to be confirmed with a scope or logic analyzer.
Lost serial input can no longer run as a corrupted move (E162)
- When a host sends faster than the board can take (no flow control, or a host that keeps sending after XOFF), the 250-byte receive buffer overflows. Every TinyG release so far dropped the extra bytes silently. The next line read was then the front of one line joined to the back of a later one, and it ran if it parsed. A bench stream produced a 583 mm Y move this way.
- Now the board records where input was lost, and a line that lost bytes, or that starts right after lost bytes, does not run.
- The first such line raises ALARM 13 ("Buffer full non-fatal - input lost"), and every damaged line gets its own status-13 reply, so the host knows exactly when the stream went bad. This holds in character mode and in line (packet) mode, and across a '%' queue flush.
- In the bench streaming tests, hosts that pace correctly (line mode, RTS/CTS, character counting) did not trigger it.
Streaming files runs through in every recommended mode (E162, E163, E164)
- XON/XOFF is much more robust with USB-serial hosts. The board sends XOFF with 175 bytes of its receive buffer still free (it used to be 50), which covers the USB adapter's latency for hosts that wait for each line to go out, as terminal programs like CoolTerm do. A host that writes as fast as it can without waiting can still overrun the buffer. When that happens, E162 raises ALARM 13 instead of running damaged lines. Line mode or RTS/CTS remain the recommended methods. RTS/CTS uses the same thresholds and runs as fast as before.
- Character counting is exact. In character mode the reply's byte count (
f[2]) now includes bytes that get no reply of their own: the second byte of a CRLF line ending, and blank or whitespace-only lines. A Grbl-style host that streams by counting bytes no longer drifts on files with Windows line endings. After an alarm or a%flush,{rx:null}reports the free buffer bytes so a host can resync. - Every method was checked on the bench, each streaming four test programs (straight lines, arcs, 2252 dense segments, a mixed job): line mode, g2core's line-mode protocol, RTS/CTS, character counting (including CRLF files with blank lines) and application-paced XON/XOFF.
Smooth, faster motion on dense CAM files (E180)
- No more speed sawtooth on short segments. With a full planner queue of very short moves (0.04 mm here) at high jerk, the planned speed used to saw between near-stop and full speed. The E180 planner/exec hand-off rework (final version, including its short-block entry-speed change) removes it; which part of the change does it is not isolated yet. On the bench (perfbench section B, jerk 200), speed used to swing between 17 and 360 mm/min, and the section took 13.4 s. It now holds 235-299 mm/min and takes 7.3 s, about 45% faster. The 0.08 mm sections smooth out the same way. Measured from step captures on the Saleae (bench 2, 2026-11-01).
Stricter, safer G-code parsing (E150, E152, E154, E159, E160, E161)
Lines that used to run with a silently wrong meaning are now rejected with an error and nothing executed:
- Unimplemented dotted codes no longer run as their whole number (G59.1 was G59, M3.1 started the spindle, M30.1 ended the program).
- RS274NGC modal-group rules: two codes of one group on a line (G0 G1, G90 G91, M3 M5, G4 G92), a motion code with G28.x/G92/G10, axis words while G80 is in effect, and G53 outside G0/G1. CAM safety lines such as
G00 G17 G21 G40 G49 G80 G90still work (G80 beside one motion code), and a bareX10still runs under the current G0-G3. - Negative F/S, T outside 0-31 and malformed L words (G10 L258 used to act as L2) are errors.
- An
Eword is never read as an exponent (G1 X10 E5used to command X=1,000,000), and characters such as*,#,[no longer vanish and splice digits (a RepRap checksumY5*45used to run as Y545).
Host impact: sloppy or 3D-printer G-code that previously "worked" may now report errors; this is intentional.
Operator-facing fixes (E096, E153, E156, E157, E031)
^dkills the job (ALARM 207), as CNCjs "Stop (force)" expects.- A homing search that misses its switch now reports error 240 instead of stopping silently.
- A jog sent while a program runs is refused instead of silently discarding the rest of the job; jogging out of a feedhold works as before.
- Text-mode
$settings are rejected in SHUTDOWN and PANIC, like JSON.
Full speed through the first junction (E089)
- The first move after idle no longer plans to stop at its end before the next line is parsed. Planner startup waits briefly for lookahead, so two collinear moves sent together keep cruise speed through the junction. Measured on the Saleae: the minimum junction speed went from 0.012 to 8.33 mm/s at a 9.98 mm/s cruise.
- Trade-off: a lone command sent from idle may start up to about 50 ms later.
Standard tool length offset sign (E037)
- G43.1 now follows RS274NGC/LinuxCNC/g2core: a positive offset is a longer tool. G91, G53 and G92 handle the offset correctly. This is a behaviour change for hosts calibrated to the old edge sign.
Probing that can't lie (E070, E071)
- G38.2 with the probe already closed alarms instead of reporting success in the air.
- G91 G38.2 probes relative to the current position, and G38.2 is rejected in G93.
Homing safety (E132, E092, E055)
- An open or stuck switch (e.g. a broken NC wire) fails homing instead of homing anywhere.
- Homed means every homing axis is homed. G28.4 keeps machine coordinates.
Probing keeps your spindle and vacuum on (E061)
- G38.2 no longer silently switches the spindle output off. A pick-and-place vacuum keeps hold of its part through a probe, as in g2core. This is a behaviour change for anyone relying on the old implicit stop.
Arcs: soft limits, absolute centres, bare G2 (E040, E041, E074)
- Arcs are checked against soft limits at the endpoint and at every extreme they actually sweep through, computed from the arc's angles rather than a coarse bounding box.
- G90.1/G91.1 work, and absolute IJK honours work offsets. A bare
G2 F100just sets the mode.
Rotary homing (E075)
- A continuous rotary axis (tn = tm) homes within one full turn (g2core 0112c81, adapted to radius mode).
Robustness
- Overlong lines are rejected cleanly (E087), JSON lines up to 254 characters are accepted (E078), and
tidis echoed exactly, even on errors (E049). - SHUTDOWN can be cleared without a reset, and keeps position (E045, E046). Alarms stop dwells and queued moves even when idle (E044), and homing/probing abort on an alarm (E073).
- Settings survive firmware updates (E022).
Documented convention: probe reports (E028)
{prb:...}reports the probe position in work coordinates, in the current units (inches in G20). This is edge's convention, kept by maintainer decision on 2026-10-30. Master and g2core report machine millimetres, so hosts written for 440.x should convert.
G18 arcs follow the standard (E029) - BEHAVIOUR CHANGE
- G2/G3 in the XZ plane (G18) now turn the same way as RS274NGC, LinuxCNC and grbl: clockwise as seen from +Y. Edge and g2core used to run them reversed, so programs from standard CAM posts cut mirrored arcs. Existing G18 programs written for the old TinyG direction will now reverse; swap G2/G3 in them. Maintainer decision, 2026-10-30.
Spindle pauses on feedhold (E060) - BEHAVIOUR CHANGE, pending timing verification
- When a feedhold finishes stopping, the spindle (and optionally coolant) turns off. On resume it restarts and waits a spin-up dwell before motion continues, as in g2core. This is on by default (maintainer decision);
$spph=0restores the old behaviour.
Cycle start after a dwell finishes the cycle (E165)
- Resuming with
~from a pause (M0, or a feedhold) when the next queued block is a dwell or another non-motion command now starts the cycle before releasing the hold, so the cycle ends normally when the queue empties. Before, the cycle could stay "running" after the program finished, and hosts waiting for idle waited forever.
Status reports describe one moment (E166)
- A status report used to read each axis separately while the machine moved, so X could come from one segment and Y from the next, or from the end point once the move finished. On curves and diagonals, hosts plotted points up to about 0.1 mm off the programmed path. Saleae step captures showed the machine itself stayed on the path.
- Every position in one report (and in
pos/mpo/ofsgroup reads and M114), with its offsets and units, now comes from one instant. Measured on the bench: streamed circles stay within 0.011 mm of the path in every streaming mode, against 0.04-0.05 mm before.
Text-mode messages appear once (E167)
- A
(MSG ...)comment in text mode is printed on the reply to its own line. It used to vanish after a status report or a$query, and a blank line or CRLF ending could print the previous message again.
M0/M1/M60 really pause (E020)
- M0 and M60 pause until cycle start (
~); the next queued line no longer restarts motion on its own. M1 is an optional stop: it pauses only when$os=1(a session switch, off after reset), per RS274NGC 3.6.1.
'%' and '~' inside comments are text (E021, E058)
(50% feed)in a comment or a JSON string no longer flushes the queue, and a~there no longer resumes motion. Resume and flush act only at a line boundary, so hosts must finish a partial line before sending them. Feedhold!still acts immediately, anywhere. Output that contains%is printed correctly (E058).
Motor energize timeout (E093) - BEHAVIOUR CHANGE, awaiting board validation
{me:N}now holds all non-disabled motors energized for N seconds (integer 1–4294967), overriding$mt. It no longer selects motor N.$me,{me:null}, and{me:0}retain the configured idle timeout;$mdcancels the hold and{md:N}retains per-motor disable. Existing always-powered settings remain in force. Expiry does not cut torque during motion or feedhold. Deterministic host tests cover expiry and wraparound; physical timing has not been measured.
Combined configuration layout 2 — candidate 4652449b
The append-only EEPROM layout transition (1 -> 2) preserves existing machine settings from markers 10001 and legacy 449.01. It initializes only active appended settings and commits marker 10002 last. Erased/unknown layouts still use defaults. Back up settings before changing firmware; downgrading to older firmware can still reset or misinterpret newer contents. Candidate 4652449b replaces the earlier reset-on-upgrade implementation.
Independent prbp defaults to active-low/NO, preserving edge probe behavior. fstk is an observed stack watermark, not a worst-case bound. adc3 / M105 report signed raw PB3 samples using VCC/1.6 reference, not calibrated voltage or temperature. PB3 is reserved from SPI2. spph / spde / coph are nonpersistent placeholders at their final indexes: direct GETs and SETs return status 17 (function stubbed), group reports omit them, and loading defaults leaves their EEPROM slots untouched. They do not enable pause/dwell behavior. E060 must initialize its defaults when activated (spph=1, coph=0); unused EEPROM contents are not trusted. The combined candidate is not timing-pending; the separate E060 runtime change remains timing-pending. Host checks and both builds pass; board validation pending.
Edge defaults and host compatibility (E063)
The release keeps edge's default profile: st=1 (active-high / normally-closed homing and limit inputs), rxm=1 (line-mode receive), and si=250 ms (filtered status reports by default). Stored settings and a build-specific machine profile can override these values. Probe polarity is separate; prbp=0 preserves the historical active-low probe input.
For master-like operation, select st=0 only if the actual homing/limit wiring is normally open; select rxm=0 for character-mode receive and si=500 for master's default report interval. Edge jv=2 selects messages and footer without configuration echo, corresponding to master's default JV_MESSAGES behavior. Apply settings individually with EEPROM write pacing and verify readback. These are compatibility choices, not a request to reset a machine's saved configuration.
Hosts must decode the footer by its revision:
| Footer revision | Layout | Meaning of third element |
|---|---|---|
| 1 (master) | [1, status, line_length, checksum] |
Input line length; checksum is the fourth element |
| 2 (edge character mode) | [2, status, line_length] |
Input line length; no checksum |
| 3 (edge line mode) | [3, status, line_buffers_available] |
Free input line buffers, not planner slots or byte credits |
Changing rxm selects edge footer 2 or 3; it does not restore footer 1 or its checksum. Host software must handle the newer formats.
stat is the machine's combined state, distinct from the command-result status in a footer. Values 0–10 retain their master meanings, including alarm 2. Master uses 11 for shutdown. Edge uses 11 for interlock, 12 for shutdown and 13 for panic; hosts must update this mapping. No setting restores master's state numbering.
Source comparison: origin/master settings.h (SWITCH_TYPE, STATUS_REPORT_INTERVAL_MS, JSON_VERBOSITY), json_parser.h/c (footer 1), canonical_machine.h (cmCombinedState); edge settings_default.h, json_parser.c and canonical_machine.h. Documentation only; no firmware defaults changed.
Boot-output note: GPIO1 spindle/coolant pins intentionally remain inputs until configuration loads and spindle OFF is latched before enabling their drivers. External inactive bias is required during this interval; suitable board pull resistors and absence of startup glitches have not been verified.
CNCjs receive-line compatibility (E095, pending validation)
Line mode accepts up to 254 characters, within the unchanged 1000-byte receive pool. The larger minimum reservation leaves less room for queued long lines. Hosts must keep observing flow control and footer credits instead of assuming a fixed number of long lines fits. Footer f[2] reports free line headers (or zero when allocation fails), not pool size / reservation; idle credits therefore need not change. Candidate measurement: after the change, idle f[2] was 10 on bench 2; a matched pre-change observation is pending.
E099 legacy backup compatibility (pending validation)
Legacy net=0, fd=0 and nonnegative ma settings are accepted for 440.xx backup restoration. They do not enable networking, alter footer nesting, or change arc segmentation. GETs return zero; edge continues using chordal tolerance. Nonzero network/footer requests are rejected. These direct-only tokens are not persisted or included in group exports. Existing EEPROM indexes remain unchanged.
Pending validation: E100/E106/E107/E123
Rejected JSON value conversions echo null rather than uninitialized data (E100). Invalid switch types return the range error before persistence or reinitialization (E106). Unsigned JSON settings accept exact integral decimal/exponent values and booleans, reject negatives and overflow, and interpret leading zeroes as decimal; the test selector is integer-valued (E107/E125). Canned programs execute through line-mode input and stop cleanly at EOF; starting a program during a partial USB line or another program is rejected (E123). Peer review and board validation remain pending for these changes.
E095 idle-credit check: the E097 cleanup query {qr:null} returned qr:32 with f:[3,0,10] both before E095 (run20261030T145239Z) and after E095 (run20261030T151234Z). Idle header credit stays 10; increasing minimum line reservation reduces room for queued long lines, not the number of headers.
E123 source selection: while a canned program runs, ordinary USB command lines wait until file EOF, matching master; RX-ISR realtime characters still act. Code review approved 0bfc0662; board validation remains pending. The HIL test observes unsolicited output instead of issuing GETs during the file and uses realtime reset for cleanup.
E107 compatibility correction (pending review/board): status slots se00-se29 retain their signed -1 disabled sentinel; ordinary integer settings remain unsigned. Decimal-only JSON follows the documented interface; TYPE_DATA hexadecimal strings retain their separate path. Integrate together with E100 rejection handling.
Known behavior: jerk setting and dense paths (E015 — parked)
The current planner exceeds the configured $xjm by about 1.44x on resolved moves from rest, and can exceed it much more on short chained segments at nonzero speed. Both the quintic scale constant and the use of Vf-Vi instead of Vi+Vf in the ramp-distance formula contribute. Existing machine settings are tuned against this behavior. No E015 planner correction is being merged in this release: the tested correction substantially slows dense jobs and requires a deliberate planner redesign, including jerk-continuous junctions.
The corrected experimental sweep and baseline are preserved as research evidence, not released behavior. See parked findings and future gates. The independent motion-profile/evidence tooling is available for review on test/motion-profile at 53211e5e.
G93 inverse-time feed (E130, candidate)
G93 programs must carry F on every feed block (G1/G2/G3), as required by RS274NGC. The mode remains active until G94; F no longer leaks from a preceding block, and arc segments retain inverse-time interpretation. Code reviewed; board validation pending.
Reset and startup handshake (E128, candidate)
Control-X now invokes the watchdog reset from USB RX, including when the main loop is blocked transmitting or motion is active. It is an abrupt reset, not a controlled feedhold; it still waits for RX interrupts to be serviceable. Startup banners retain edge’s sr envelope and always use strict JSON without changing the selected syntax. Bootloader command policy and delay are unchanged. Code reviewed; board validation pending.
Text setting validation (E131, candidate)
Empty values remain display requests. Malformed, nonfinite and out-of-range numbers are rejected before changing or persisting a setting. Values previously truncated, such as $1mi=1.5 or $xvm=12oops, now produce an error. Text integer spelling remains stricter than the E107 JSON parser (8.0 is rejected in text). Code reviewed; board gate pending.
New features
- Live feed advisor, step 2:
{"rt":{"fi":N}}streams per-window feed-limit summaries (fs) and per-move limit reasons (fl) so a host can show why a job runs slower than programmed (feat/feed-limit-counters) - Live feed advisor, step 1: every planned move records which limit set its speed (axis velocity, jerk, junction, feed, feed override) (
feat/feed-limit-reasons) - Spindle status readouts (
spe,sps,spc) for hosts (feat/spindle-status) - Idle heartbeat
{"rt":{"hb":seconds}}: the board reports on its own while idle so hosts need not poll (feat/runtime-heartbeat) - Config layout v2: settings grouped and documented for hosts that build settings pages from the board (
feat/config-layout-v2-r2)
Fixes
Each line is one merged fix branch; the E-number is the finding in the edge-0.97 audit (docs/audit/edge-0.97/findings.json on the docs/edge-audit branch) and the test that guards it lives in tests/hil/tests/bugs/.
JSON and text parsing (28)
- E034 Add HIL test for E034: JSON-wrapped G-code ({gc:...}, {txt:'gcode'}, tid lines) — audit: JSON-wrapped G-code ({gc:...}, {txt:'gcode'}, tid lines) and '$' lines are dispatched before the planner-headroom check: planner overflow PANIC, reordering, and execution during homing/probing
- E043 Add HIL test for E043: In ALARM, JSON SETs (including {"gc":...}) are silently — audit: In ALARM, JSON SETs (including {"gc":...}) are silently skipped but answered with status 0
- E051 Test initialized defaults and nonfatal configuration recovery — audit: stepper_reset() on AVR zeroes the DDA downcount without stopping TIMER_DDA/TIMER_DWELL: runaway stepping after $shutd/panic/$clc or a $Nsa/$Ntr/$Nmi change during motion
- E051 Reproduce boot geometry rejection with a queued startup command — audit: stepper_reset() on AVR zeroes the DDA downcount without stopping TIMER_DDA/TIMER_DWELL: runaway stepping after $shutd/panic/$clc or a $Nsa/$Ntr/$Nmi change during motion
- E051 Add HIL test for E051: stepper_reset() on AVR zeroes the DDA downcount without — audit: stepper_reset() on AVR zeroes the DDA downcount without stopping TIMER_DDA/TIMER_DWELL: runaway stepping after $shutd/panic/$clc or a $Nsa/$Ntr/$Nmi change during motion
- E057 Add HIL test for E057: {"txt":""} prints a text-mode prompt into the — audit: {"txt":""} prints a text-mode prompt into the JSON stream
- E058 Exercise percent-bearing JSON, text and exception output on the host — audit: printf() with non-literal format strings in edge output paths (JSON responses, text messages, exception reports)
- E078 Add HIL test for E078: JSON input is capped at 128 characters (an arbitrary — audit: JSON input is capped at 128 characters (an arbitrary test value), so longer host setup lines are rejected with status 107
- E079 Add HIL test for E079: Changing $rxm at runtime drops or replays buffered lines — audit: Changing $rxm at runtime drops or replays buffered lines (char and line mode share one pool, nothing re-initialised)
- E082 Add HIL test for E082: JSON tokenizer defects: always-true safety-valve loop — audit: JSON tokenizer defects: always-true safety-valve loop test, NULL pointer return on trailing whitespace, escaped quotes dropped
- E092 Hil: mounted-switch geometry cached at mount time; ICE stack high-water diagnostic — audit: $home reports Homed after homing any single axis, and $homx/homy print as positions
- E093 Add HIL test for E093: Motor energize ($me/{me:N}) still times out after $mt; — audit: Motor energize ($me/{me:N}) still times out after $mt; no way to keep motors on longer
- E103 Add HIL test for E103: {"gc":"..."} (documented JSON-wrapped G-code) is
- E107 Add HIL test for E107: JSON SET of int- and bool-typed tokens rejects values
- E123 Add HIL test for E123: $test=N does nothing in the default line mode ($rxm=1)
- E124 Add HIL test for E124: Canned $test programs on 449.01, per test: none runs in
- E131 Add HIL test for E131: Text mode: an empty, non-numeric or trailing-space value
- E136 Add HIL test for E136: A lone '$' in line mode appends 'sys' past its 2-byte
- E139 Add HIL test for E139: Changing $ex (flow control mode) never resets XON/XOFF
- E151 E151 test: {"sys":n} lists every sys setting with intact keys; text $sys labels each one
- E152 E152 test: the parser rejects RS274NGC modal-group violations before executing
- E153 E153 test: a text-mode $ set is rejected in SHUTDOWN like a JSON set
- E172 Reject data after the root JSON object
- E173 Validate complete JSON literals
- E174 Reject whitespace inside JSON values
- E175 Bound partial smart-quote lookahead
- E176 Decode JSON control escapes
- E177 Require a delimiter after JSON strings
G-code interpretation (37)
- — End an arc cycle when no chord was queued (N06)
- — Deferred G10 write: build the offset token without sprintf
- — Deferred G10 write: format the offset token from a uint8_t
- E003 Add HIL test for E003: Port M201.3 (set per-axis jerk transiently from G-code) — audit: Port M201.3 (set per-axis jerk transiently from G-code)
- E004 Add HIL test for E004: G4 P0 (bare G4, or any dwell under 0.1 ms) hangs the — audit: G4 P0 (bare G4, or any dwell under 0.1 ms) hangs the machine in 'run' for ~5 days: port master's dwell tick floor
- E005 Add HIL test for E005: G/M word values truncated to uint8: M256..M265 alias to — audit: G/M word values truncated to uint8: M256..M265 alias to M0..M9 (M259 starts the spindle, M258 runs program end), M400 becomes 144, G256 runs G0
- E008 Add HIL test for E008: Every radius-format arc (G2/G3 ... R) raises ALARM 157 — audit: Every radius-format arc (G2/G3 ... R) raises ALARM 157 'arc offsets missing or zero': add g2core's radius-mode guard
- E023 Add HIL test for E023: G10 L20 ignores G92 origin offsets and the tool length — audit: G10 L20 ignores G92 origin offsets and the tool length offset; P0 is rejected
- E025 Add HIL test for E025: Probing cycle error paths: a failed probe move leaves — audit: Probing cycle error paths: a failed probe move leaves CYCLE_PROBE stuck, the cycle starts before earlier moves finish, and a modal F is rejected
- E029 Add HIL test for E029: G18 (XZ) arcs run in the reverse direction vs — audit: G18 (XZ) arcs run in the reverse direction vs NIST/LinuxCNC/grbl (the 448.02 fix was reverted the same day)
- E032 Add HIL test for E032: Tool support: T plus M6 records the previously selected — audit: Tool support: T plus M6 records the previously selected tool (T5 M6, or T and M6 on separate lines), M6 is a no-op, and G43 Hn / any H word raises ALARM
- E035 Add HIL test for E035: Line-mode RX buffer manager leaves a FREE hole at — audit: Line-mode RX buffer manager leaves a FREE hole at used_top when the newest line is a control line: overlapping buffers, corrupted, stalled or out-of-order G-code
- E037 Add HIL test for E037: G43.1 tool length offset (marked '+++++ TEST THIS'): — audit: G43.1 tool length offset (marked '+++++ TEST THIS'): re-applied on every G91 move, applied under G53/G28/homing, sign opposite to g2core/LinuxCNC, ignored by G92 and by the runtime DRO offset
- E039 Add HIL test for E039: G28/G30 feed the stored machine-mm position back through — audit: G28/G30 feed the stored machine-mm position back through cm_set_model_target (x25.4 in G20, relative in G91, minus TLO), take the intermediate point in machine coordinates, move all six axes, and busy-wait
- E040 Add HIL test for E040: G90.1/G91.1 (arc distance mode) are parsed but never — audit: G90.1/G91.1 (arc distance mode) are parsed but never executed; absolute IJK would also ignore work offsets
- E041 Add HIL test for E041: Arcs are never soft-limit checked (not even the endpoint) — audit: Arcs are never soft-limit checked (not even the endpoint)
- E042 Add HIL test for E042: Any unsupported G-code or unknown word (G43 Hn, G41, — audit: Any unsupported G-code or unknown word (G43 Hn, G41, G81-G89, G98, O-number, H/D/Q/E) and arc spec errors raise ALARM and stop the job; master only returned an error
- E044 Add HIL test for E044: An ALARM raised while nothing is moving (during a dwell — audit: An ALARM raised while nothing is moving (during a dwell or before queued moves start) neither holds nor flushes; queued moves then run in ALARM
- E048 Add HIL test for E048: an exact-length string overruns the shared nv string — audit: nv_copy_string off-by-one writes NUL into nvStr.magic_end, so an exact-length string causes a CONFIG_ASSERTION PANIC; every raw G-code line is now copied there and the return value is ignored
- E054 Add HIL test for E054: cm_set_model_target() does not seed gm.target from the — audit: cm_set_model_target() does not seed gm.target from the model position, so a rejected block (soft-limit alarm, arc error) leaves a stale target that the next move picks up
- E066 E066: pass --param=min-pagesize=0 to avr-gcc 12 and 13 — audit: avr-gcc 12/13 '--param=min-pagesize=0' workaround for newer toolchains
- E071 Add HIL test for the E071 follow-up: G20 minimum probe travel compared in inches — audit: G38.2 target is not converted at command time: G91 probes toward an absolute work coordinate, and the minimum-travel check sums unflagged axes
- E071 Add HIL test for E071: G38.2 target is not converted at command time: G91 — audit: G38.2 target is not converted at command time: G91 probes toward an absolute work coordinate, and the minimum-travel check sums unflagged axes
- E074 Add HIL test for E074: G2/G3 with only the motion word (e.g. 'G2' or 'G2 F100') — audit: G2/G3 with only the motion word (e.g. 'G2' or 'G2 F100') raises ALARM instead of being a no-op
- E075 Add HIL test for E075: cyclic rotary axis searches only the latch backoff — audit: Cyclic rotary axis (AXIS_RADIUS, tn==tm) homes with a near-zero search travel or errors out
- E088 Add HIL test for E088: A single G-code block that queues more than 4 commands — audit: A single G-code block that queues more than 4 commands (S/T/M6/M3/M7/M8/G4/G92/motion) can PANIC with 'Buffer full fatal'
- E090 Add HIL test for E090: Status report shows the arc endpoint (vel 0) before the — audit: Status report shows the arc endpoint (vel 0) before the arc starts moving
- E117 Add HIL test for E117: G80, and every non-motion block while the modal motion
- E154 E154 test: negative F/S and out-of-range T words are rejected with nothing executed
- E155 E155 test: G28.3 and G92 A values in G20 are degrees, not inches
- E156 E156 test: a homing search that misses its switch is reported with status 240
- E159 E159 test: an E word after a value is rejected, not read as an exponent
- E160 E160 tests: L word, qv range, B/C junction precision and status messages
- E165 E165 test: resuming a dwell queued behind M0 can leave the machine in RUN
- E168 Reject nonfinite G-code values before execution
- E169 Validate line numbers before unsigned conversion
- E170 Reject repeated non-G/M words before execution
Planner and motion (26)
- E001 Add HIL test for E001: Port M114 (get position) and M115 (firmware info) to — audit: Port M114 (get position) and M115 (firmware info) to edge, the queries OpenPnP relies on
- E002 Add HIL test for E002: Port M400 (wait for all motion to finish), adapted to — audit: Port M400 (wait for all motion to finish), adapted to edge's control-line processing during the block
- E018 Add HIL test for E018: 'Move time is NAN' PANIC when a body-only block from — audit: 'Move time is NAN' PANIC when a body-only block from rest gets cruise forced to entry velocity 0 (low-feed probing/homing freeze; tonyluken FixMoveTimeIsNan, PR #272)
- E020 Add HIL test for E020: M0/M1/M60 do not pause: the next queued line — audit: M0/M1/M60 do not pause: the next queued line auto-restarts motion without cycle start
- E030 Add HIL test for E030: Feedhold resume (
) re-runs the held block with its old — audit: Feedhold resume () re-runs the held block with its old trapezoid, so it overshoots the endpoint and shifts the rest of the job - E031 Add HIL test for E031: limit hit brakes at the move's jerk and leaves axes homed — audit: Limit switch hit: soft jerk-limited feedhold instead of a hard stop, no deglitch, alarm raised from the main loop, no LED indication, interlock/hard-limit settings unwired
- E038 Add HIL test for E038: G43.1 or G49 anywhere in a block returns early, silently — audit: G43.1 or G49 anywhere in a block returns early, silently dropping G54-G59, G61/G64, G90/G91, G28/G30/G10/G92, motion and M0/M2/M30 on that line
- E045 Add HIL test for E045: SHUTDOWN can never be cleared: _shutdown_handler blocks — audit: SHUTDOWN can never be cleared: _shutdown_handler blocks all command dispatch
- E046 Add HIL test for E046: SHUTDOWN and PANIC zero the machine position: — audit: SHUTDOWN and PANIC zero the machine position: planner_reset() memsets mr/mm, then the flush copies 0 into the model
- E055 Add HIL test for E055: G28.4 rewrites machine position from work position — audit: Homing edge cases: G28.4 rewrites machine position from work position, and the clear move reads sw.s[-1] when the opposite switch is disabled
- E069 Add HIL test for E069: M2/M30 program-end resets run at runtime in interrupt — audit: M2/M30 program-end resets run at runtime in interrupt context and queue new commands (G54/G92.1/M5/M9) behind later blocks
- E070 Add HIL test for E070: G38.2 with the probe already tripped reports success — audit: G38.2 with the probe already tripped reports success at the current position
- E073 Add HIL test for E073: Homing and probing callbacks keep queuing moves after an — audit: Homing and probing callbacks keep queuing moves after an ALARM (no abort path)
- E089 Add HIL test for E089: First move after idle decelerates to zero even when the — audit: First move after idle decelerates to zero even when the next move is queued right away (no planner start-up delay)
- E091 Add HIL test for E091: Queue-report qi/qo counts are reset at cycle start, so — audit: Queue-report qi/qo counts are reset at cycle start, so commands queued before the first move are lost
- E108 Add HIL test for E108: Tokens removed versus master: pwr1-pwr4 (the empty pwr
- E111 Add HIL test for E111: Microsteps getter reads 1 byte of a uint32_t:
- E135 Add HIL test for E135: M2/M30 clear an ALARM only when the normalized block is
- E145 Add HIL test for E145: an alarm's queue flush drops host input when motion comes to rest
- E158 E158 test: zero or negative step angle, travel, microsteps and jerk are refused unchanged
- E166 E166 test: status reports show positions the machine never occupied
- E180 E180 test: the exec can start a block the planner is rewriting, and the move is lost
- E181 E181 test: planning a short move rewrites the run buffer's flags behind the exec
- E184 E184 test: the motor power timeout disables a motor whose move has just started
- E196 E196 test: a previous block freed during the junction read limits the new block
- E197 E197 tests: a move after a runtime halt is planned to start at speed
Feedhold, homing, probing and jogging (14)
- E033 Add HIL test for E033: G0/G1 never call cm_cycle_start(): inverted status test — audit: G0/G1 never call cm_cycle_start(): inverted status test after mp_aline() keeps stat out of RUN, breaks cycle end/hold reporting, waypoint correction and the 'not while moving' guards
- E036 Add HIL test for E036: Queue flush (! then %, or alarm) keeps lines already in — audit: Queue flush (! then %, or alarm) keeps lines already in the line-mode buffers or the held char-mode line, then ends the hold, so the machine starts moving again after the abort
- E050 E050 test: a release during switch lockout leaves the input stuck active — audit: Switch lockout drops edges with no re-sample, leaving a stale 'hit' state so the next real limit or probe edge is ignored
- E061 Add HIL test for E061: G38.2 turns the spindle off and never restores it — audit: G38.2 probing silently turns the spindle off and never restores it (cuts PnP vacuum); g2core does not touch the spindle
- E072 Add HIL test for E072: Failed G38.2 (no contact) is not an error, and limit — audit: Failed G38.2 (no contact) is not an error, and limit switches during probing only cause a feedhold
- E114 Reproduce homing dispatch before feedhold completion
- E116 Add HIL test for E116: A feedhold request that arrives while the last queued
- E132 Add HIL test for E132: Homing accepts a switch that never changes state: with
- E144 Add HIL test for E144: alarm + flush + clear leaves cycle_state MACHINING
- E146 Add HIL test for E146: a host '%' flush cuts a line the host sent right after it
- E148 E148 test: value vectors passed to mp_queue_command() must hold AXES floats
- E157 E157 test: a jog is refused while a program runs; jogs from idle or a feedhold still work
- E191 E191 test: a flush accepted while a line is read does not stop that line
- E192 E192 test: a probe contact during the cycle's initial pin sample is lost
Serial input and flow control (22)
- E019 Add HIL test for E019: alarm/shutdown leave spindle and coolant on — audit: ALARM, SHUTDOWN and PANIC never stop the spindle or coolant (spindle_reset() is a no-op, immediate-off calls commented out), and the shutdown blinker toggles the spindle DIR pin
- E021 Add HIL test for E021: '%' (and '!' '
') are trapped in the RX ISR anywhere in — audit: '%' (and '!' '') are trapped in the RX ISR anywhere in the stream, including inside comments - E022 Add HIL test for E022: a firmware build-number change resets all settings — audit: Every firmware build-number change resets all settings to defaults
- E052 Add HIL test for E052: ENQ answered with printf inside the RX ISR — audit: RX ISR answers ENQ (0x05) with printf from inside the MED-level ISR
- E076 Add HIL test for E076: {mt:...} clamps the motor timeout but echoes the — audit: {mt:...} clamps the motor timeout but echoes the unclamped input value
- E077 Add HIL test for E077: rpt_exception() overflows a 128-byte stack buffer when — audit: rpt_exception() overflows a 128-byte stack buffer when the alarm message includes the user's input line (lines over ~60 chars)
- E080 Add HIL test for E080: Char-mode line reader uses an 8-bit length, so lines — audit: Char-mode line reader uses an 8-bit length, so lines over 255 chars silently wrap onto themselves instead of reporting overflow
- E085 E085: lint the PROGMEM format strings, and fix what it finds — audit: Compiler warnings with -Wall/-Wextra: few real issues, but GCC cannot check PROGMEM format strings (how the rpt_exception overflow got through)
- E087 Add HIL test for E087: A serial line of 200+ chars in line mode (the default) — audit: A serial line of 200+ chars in line mode (the default) raises ALARM 'Buffer full non-fatal', names the previous command, and runs the leftover text as a separate line
- E094 Reproduce wrapped receive-buffer overlap with the firmware allocator — audit: Line-mode RX buffer allocator ignores the wrapped used region, so new input overwrites queued lines that have not run yet (lines of roughly 75+ chars)
- E096 Add HIL test for E096: No ^D (0x04) job kill: CNCjs 'Stop (force)' and 'Kill
- E097 Add HIL test for E097: Text-mode automatic status reports are multi-line on
- E128 Add HIL test for E128: Reset and boot handshake on edge: ^X is serviced from
- E137 Add HIL test for E137: Text-mode output regressions: automatic status reports
- E142 Add HIL test for E142: XON from the host disables the USB TX interrupt
- E161 E161 test: characters the normaliser cannot keep make the line malformed instead of splicing digits
- E162 E162 test: an RX ring overrun splices lines and the result runs
- E163 E163 test: a host that honours XOFF still overruns the RX ring
- E164 E164 test: character-mode byte counts miss bytes that get no reply
- E167 E167 test: a text-mode (MSG ...) is lost after a status report and repeated after a message
- E182 E182 test: the main loop's buffer count update loses a free from the exec
- E190 E190 test: the system clock is read and written in parts across interrupts
Status reports and replies (7)
- E047 Add HIL test for E047: {srs:...} removal writes past sr.value_flt[30] (memory — audit: {srs:...} removal writes past sr.value_flt[30] (memory corruption)
- E049 Add HIL test for E049: Transaction id (tid) is dropped from error responses, — audit: Transaction id (tid) is dropped from error responses, stored as a float, and filtered at jv<3
- E053 Add HIL test for E053: A line starting with '?' plus more text is silently — audit: A line starting with '?' plus more text is silently dropped with no response (leftover '?' hack)
- E056 Add HIL test for E056: A filtered status-report request is never cleared when — audit: A filtered status-report request is never cleared when nothing changed, so it is re-evaluated every loop (CPU burn) while idle in READY or ALARM
- E100 Add HIL test for E100: A rejected numeric SET echoes 4294967295 (or a NULL
- E164 E164 follow-up test: the char-mode footer count goes negative above 32767
- E183 E183 test: a queue report loses a removal that lands while it is written
Settings and persistence (1)
- — Finish idle G10 persistence before acknowledging it (N01)
Switches, spindle, outputs (5)
- E024 Add HIL test for E024: Feed-rate and spindle-speed overrides: M48/M49/M50/M51 — audit: Feed-rate and spindle-speed overrides: M48/M49/M50/M51 are parsed and stored but never applied, and there are no mfo/sso tokens
- E102 Add HIL test for E102: Edge output layer: er, msg and err strings go out
- E106 Add HIL test for E106: {"st":2} answers OK and leaves the live switch type
- E130 Add HIL test for E130: G93 inverse time: the first G1 silently switches the
- E149 E149 test: a zero-width spindle speed range gives a finite duty; pwm_set_duty refuses NaN
Other firmware fixes (18)
- — Reject nonpositive axis rate caps before storage (N06)
- E012 Fixing Atmel disclaimer — audit: Atmel disclaimer text fixes (FART/SHOE typos, author line) apply cleanly to edge
- E017 Add HIL test for E017: Full circle with an explicit endpoint equal to the — audit: Full circle with an explicit endpoint equal to the start: G2 works, G3 raises an ALARM
- E095 Add HIL test for E095: CNCjs on edge 449: the connect sequence puts the board
- E099 Add HIL test for E099: Master-only tokens net, ma and fd are gone, so restoring
- E101 Add HIL test for E101: UGS works with the edge 449 connect sequence, with three
- E103 Accept boolean values for both alarm-clear aliases
- E104 Add HIL test for E104: hp/hv accessors still assume the old float fields:
- E110 Add HIL test for E110: Rotary-axis rows mix unit-converting and non-converting
- E112 Add HIL test for E112: Setters narrow value_int to uint8_t before the range
- E125 Add HIL test for E125: {test:N} is rejected for every N>=2 with status 110: the
- E126 Add HIL test for E126: At the end of a canned test, the char-mode reader
- E140 Add HIL test for E140: Writing se00-se29 stores the low 16 bits of the float's
- E141 Add HIL test for E141: (MSG ...) alone on a line is dropped
- E150 E150 test: unimplemented dotted G/M codes are rejected; implemented sub-codes still run
- E171 Bound text comma normalization
- E193 E193 test: a frame the USART loses must not leave an altered line that runs
- E195 Harness: look up edge-only states by name only where the dialect has them
Test harness
- 15 merges of hardware-in-the-loop test work (
tests/hil): a pytest harness that drives real boards over USB, the Atmel-ICE (PDI) and a Saleae logic analyser; strict-xfail bug tests for every fix above; streaming senders for line mode, XON/XOFF, RTS/CTS and character counting; overnight bug-hunt loops with a live scoreboard.
Known issues (open at release time)
- N02: on slow arcs (radius 5-15 mm at F100) a line-mode host can see 5 s without a line reply or status report; line replies pausing during an arc is by design, the missing status reports are under investigation.
- N04: with hardware flow control (
ex=2) a feedhold while the host keeps streaming could leave the board unable to receive the resume; a fix is in verification and will ship in the next build.
