Skip to content

None Target — Null CNC Firmware Stub

The none_target module is the null firmware target for the CNC Firmware Integration layer. It provides compile-safe, no-op stub implementations of every interface that the GCode host service and its flow-control layer require, allowing the firmware to build and run without any active CNC firmware backend (no FluidNC, Grbl, or GrblHAL).

Read these first:


none_target satisfies the two link-time interfaces that every firmware build must provide:

  1. ESP3DGCodeHandlerService — the handler singleton that the host task calls for command classification, ACK detection, startup strings, and firmware session lifecycle.
  2. gcodeHostFlow* functions — the flow-gate hooks the host task calls on every send, ACK, NACK, and reset event.

All implementations are pure no-ops or safe constant returns. No transport is opened, no GCode is sent, and no firmware responses are parsed.


Core GCode Host (shared)

Handler selection - CMake

Build-time selection - CMake

gcodeHostFlow*()

esp3dGcodeHandler.*

target/cnc/modules/gcode_host/

esp3d_gcode_host_flow.cpp

(real flow: ok credit + planner/RX gates)

target/none/modules/gcode_host/

esp3d_gcode_host_flow.cpp

(permissive stubs ← this module)

target/3dprinter/modules/gcode_host/

esp3d_gcode_host_flow.cpp

(stub - Marlin future ⬜)

target/cnc/{fluidnc|grbl|grblhal}/

esp3d_gcode_handler_service.h/.cpp

target/none/

esp3d_gcode_handler_service.h

(inline stub ← this module)

ESP3DGCodeHostService

main/modules/gcode_host/

CMake links exactly one flow implementation and exactly one handler per build:

TARGET_FW_NONE → target/none/modules/gcode_host/ (flow stubs)
target/none/ (handler stub)
TARGET_FW_GRBL / GRBLHAL / FLUIDNC
→ target/cnc/modules/gcode_host/ (real flow)
target/cnc/{grbl|grblhal|fluidnc}/ (real handler)

main/target/none/
├── esp3d_gcode_handler_service.h ← stub handler class + enums (header-only)
└── modules/gcode_host/
└── esp3d_gcode_host_flow.cpp ← no-op flow-control functions

esp3d_gcode_handler_service.h — Handler stub

Section titled “esp3d_gcode_handler_service.h — Handler stub”

Both enums are declared here and must also exist in every real handler header so call sites compile identically regardless of the selected target.

enum class FW_GCodeCommand : uint8_t {
reset_stream_numbering = 0,
};

Identifies firmware-level injected commands. getFwCommandString() returns "" for every value in the none target.

enum class ESP3DCommandType : int8_t {
unknown = -1,
normal = 0,
realtime = 1
};

Classifies a GCode line as queued or real-time. The none target treats every command as unknown and never routes realtime traffic.


A final class with no member state. Every method is defined inline in the header. A global instance is declared at file scope:

extern ESP3DGCodeHandlerService esp3dGcodeHandler;
MethodReturnBehaviour
begin()trueAlways reports success; no real initialisation.
handle()—No-op; called periodically by the host task.
end()—No-op; called on shutdown.
started()falseSignals that no firmware session is active. The host task uses this to skip the active-streaming loop.
MethodReturnBehaviour
getType(const char *)ESP3DDataType::unknownNo parsing; every line is opaque.
isRealTimeCommand(const char *) (static)falseNo realtime commands recognised.
hasMultiLineReport(const char *)falseNo multi-line responses expected.
processCommand(const char *)falseCommand is dropped silently.

These are called by the host task and by the flow-control layer. The none-target values are chosen so the host never deadlocks waiting for events that will never arrive.

MethodReturnWhy this value
isAckNeeded()falseNo pending ACK → host never enters wait_for_ack.
hasAck(const char *)trueEvery received line is treated as an implicit ACK; no credit is held indefinitely.
getLineResend()0No line resend ever requested.
getStreamMaxInFlight() const1Conservative window; keeps the host flow loop trivially correct if ever called.
canAcceptStreamLine(size_t) consttrueAlways ready; no transport backpressure.
MethodReturnBehaviour
sendGcode(const char *, ...)falseGCode is silently dropped; no transport attached.
forwardToScreen(const char *)falseNothing to forward; no firmware responses arrive.
getLastError()""No error state tracked.
MethodReturnBehaviour
getInitCommand()""No firmware-specific initialisation string.
sendStartupCommands()falseNo commands sent.
resetStartupCommandsSent()—No-op.
sendPingCommand()falseNo keepalive sent.
updateReportingInterval(uint32_t)falseNo reporting configured.
getFwCommandString(FW_GCodeCommand)""No firmware command strings defined.

esp3d_gcode_host_flow.cpp — Flow-control stubs

Section titled “esp3d_gcode_host_flow.cpp — Flow-control stubs”

Provides the no-op implementations of the flow-gate hook functions declared in esp3d_gcode_host_flow.h. The cnc_gcode_host_flow module provides the real implementations for CNC builds; the none target replaces them at link time.

FunctionReturnsBehaviour vs. real implementation
gcodeHostFlowReset()—No-op. Real: atomically zeroes pending_ok, empties the in-flight ring, resets inflight_bytes.
gcodeHostFlowCanSendLine(size_t line_len)trueAlways permits sending; line_len ignored. Real: checks four concurrent gates (ok credit, planner blocks, RX window, RX bytes snapshot).
gcodeHostFlowOnLineSent(const char *cmd)—No-op; cmd discarded. Real: increments pending_ok and pushes wire byte length into the in-flight ring when hasAck(cmd) is true.
gcodeHostFlowOnAck()—No-op. Real: decrements pending_ok, pops the oldest ring entry, reduces inflight_bytes.
gcodeHostFlowOnNack()—No-op. Real: same accounting as OnAck; error:N releases one credit.
gcodeHostFlowOnError()—No-op. Real: calls gcodeHostFlowReset().
gcodeHostFlowAtInFlightCap()falseReports window always open. Real: returns true when pending_ok >= getStreamMaxInFlight().
gcodeHostFlowPendingOk()0No in-flight lines tracked. Real: returns s_pending_ok under mutex; host uses this to decide whether to enter wait_for_ack.

Note: gcodeHostFlowReset() is present in this none-target stub. The function is also called in the real cnc_gcode_host_flow but is listed there as an internal reset triggered by gcodeHostFlowOnError() — both the none stub and the real implementation share the same public declaration in esp3d_gcode_host_flow.h.


The stub return values are chosen to keep the GCode host task in a safe idle state regardless of how many times it ticks:

Stub valueEffect
started() → falseHost skips the active-streaming loop entirely.
gcodeHostFlowCanSendLine() → trueNo deadlock if the host does iterate; no saved pending line, no livelock.
gcodeHostFlowAtInFlightCap() → falseHost never enters wait_for_ack after a no-op send.
hasAck() → true, gcodeHostFlowPendingOk() → 0No line is ever retried or held waiting for an ACK that will never arrive.
isAckNeeded() → falseConsistent redundant guard at the host level.
getStreamMaxInFlight() → 1Trivially satisfies any pending_ok < max_in_flight check.

All ESP3DGCodeHandlerService methods are inline in the header; no translation unit is generated for the class itself. esp3d_gcode_host_flow.cpp compiles to eight trivial functions, several of which reduce to a single ret instruction.

No dynamic allocation, no FreeRTOS objects, no mutex, no static state. The none target adds negligible code size to the firmware image.


DocumentRelation
gcode_host.mdFull gcode_host module: scheduler, dual queues, state machine, how flow hooks are called
cnc_gcode_host_flow.mdReal flow implementation — linked instead of this file for CNC targets; describes all four gates and the in-flight ring
gcode_host_architecture.mdLayer table, CMake selection, performance rules, future 3D-printer path
CNC_Firmware_Integration.mdParent module overview
cnc_fluidnc.mdFluidNC handler — processStatus(), hasAck(), buffer cache
cnc_grblhal.mdGrblHAL handler
cnc_grbl.mdGRBL handler