Skip to content

fix: support Excellon routing/milling commands (G00, G01, M15, M16, M17)#283

Merged
spe-ciellt merged 2 commits intogerbv:developfrom
SourceParts:fix/excellon-route-milling
Feb 27, 2026
Merged

fix: support Excellon routing/milling commands (G00, G01, M15, M16, M17)#283
spe-ciellt merged 2 commits intogerbv:developfrom
SourceParts:fix/excellon-route-milling

Conversation

@rampageservices
Copy link
Copy Markdown
Contributor

@rampageservices rampageservices commented Feb 26, 2026

Summary

Fixes #271

Excellon files with routing/milling commands (G00, G01, M15, M16, M17) are rendered as a single drill hole instead of milled paths. These commands are standard Excellon (used by Mentor Graphics, understood by GcPrevue, ViewMate, and Ucamco's online viewer), but gerbv's drill parser creates a FLASH net for every X/Y coordinate regardless of routing mode.

This PR adds a routing state machine to the drill parser in drill.c:

  • Route mode tracking: route_mode field in drill_state_t tracks whether the parser is in drill mode (G05, default), rapid positioning (G00), or linear routing (G01)
  • Tool down tracking: tool_down field tracks plunge (M14/M15) vs retract (M16/M17) state
  • Mode-aware coordinate handling: When routing with tool down, X/Y coordinates produce line segments (APERTURE_STATE_ON + LINEARx1) instead of flash drill holes. When tool is up, coordinates reposition without creating geometry
  • State resets: Routing state resets on tool change (T-code) and drill mode (G05)
  • M-code recognition: M14, M15, M16, M17 are now recognized in drill_parse_M_code() instead of falling to DRILL_M_UNKNOWN

No changes to drill.h, draw.c, or gerbv.h — the renderer already handles APERTURE_STATE_ON + LINEARx1 for drill layers (proven by existing G85 slot support). The existing enums in drill.h (DRILL_G_ROUT, DRILL_G_LINEARMOVE, DRILL_M_ZAXISROUTEPOSITION, etc.) already had the correct values.

Before (single drill hole)

before

After (milled Y-shape paths)

after

Scope

  • G02/G03 arc routing: NOT implemented — still logged as unsupported. Can be added later with gerbv_cirseg_t.
  • No stats fields added: M14-M17 don't get dedicated counters (would require gerbv.h changes).

Test plan

  • New test file test-drill-route-milling.exc (exact file from Excellon milling data are rendered as a hole #271) registered in tests.list and run_drill_tests.sh
  • Golden PNG generated for regression testing
  • All existing drill tests pass (no regressions)
  • Builds cleanly with cmake — no warnings
  • Export to PNG produces correct Y-shaped milled paths with no error messages

Excellon files with routing/milling commands were rendered as a single
drill hole instead of milled paths. The drill parser only knew how to
create FLASH nets for every X/Y coordinate, regardless of routing mode.

Add a routing state machine to the drill parser:
- Track route_mode (G00 rapid/G01 linear vs G05 drill) and tool_down
  state (M15 plunge / M16,M17 retract) in drill_state_t
- When routing with tool down, X/Y coordinates produce line segments
  (APERTURE_STATE_ON + LINEARx1) instead of flash drill holes
- When routing with tool up, X/Y coordinates reposition without geometry
- Reset routing state on tool change (T-code) and drill mode (G05)

The renderer already handles APERTURE_STATE_ON + LINEARx1 for drill
layers (proven by G85 slot support), so no draw.c changes are needed.

G02/G03 arc routing is not yet implemented and still logs as unsupported.

Fixes gerbv#271
@spe-ciellt spe-ciellt self-assigned this Feb 27, 2026
@spe-ciellt
Copy link
Copy Markdown
Contributor

Thank you for this patch. If this is good enough I apply it else I will leave comments.

@spe-ciellt
Copy link
Copy Markdown
Contributor

Tested on the branch. Build clean, feature works correctly.

Code: The two-field state machine (route_mode, tool_down) is clean and well-integrated. drill_add_route_segment() correctly uses MIN/MAX over both endpoints for the bounding box — an improvement over drill_add_drill_hole() which only considers a single point. M14 and M15 both setting tool_down = TRUE is correct per spec. State resets on tool change and G05 are correct. G02/G03 arc routing properly falls to the existing error path. No changes to draw.c, gerbv.h, or drill.h — the renderer already handles APERTURE_STATE_ON + LINEARx1 via existing G85 slot support.

Before fix: 12 CRITICAL error messages on the test file (G00, G01, M15, M16, M17 all logged as unsupported).
After fix: clean output, no messages. 115,788 pixel difference vs develop confirms the rendering changed from a single drill hole to correct milled paths.

Tests: New test test-drill-route-milling passes. 92/102 overall; the 10 failures are the same Cairo-baseline mismatches as the develop baseline — no regressions.

One minor note: run_drill_tests.sh defaults to ../build/src/gerbv but the CMake Debug build places the binary at ../build/src/Debug/gerbv, so the script won't work out-of-the-box without setting GERBV. Not a CI issue since the new test is covered via tests.list, but worth fixing in a follow-up.

@spe-ciellt spe-ciellt merged commit 8074f82 into gerbv:develop Feb 27, 2026
1 check passed
@rampageservices rampageservices deleted the fix/excellon-route-milling branch February 27, 2026 17:20
@spe-ciellt spe-ciellt added the enhancement New feature or request label Feb 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Excellon milling data are rendered as a hole

2 participants