Skip to content

Debugging and Testing

Relevant source files

This page provides practical guidance for debugging and testing the PiBot CNC Pendant firmware. It covers the centralized logging system, message queue inspection, value subscription validation, screen transition debugging, and communication protocol troubleshooting. These tools are essential for maintaining the stability of the LVGL-based UI and the real-time communication with FluidNC/grblHAL controllers.


The firmware uses a specialized logging component, esp3d_log, which supports multiline output, timestamps, and pluggable backends.

Log levels are defined in esp3d_log.h and configured globally via cmake/dev_tools.cmake.

LevelMacroDescription
0N/ALogging disabled
1esp3d_log_eError messages only
2esp3d_log_wWarnings and errors
3esp3d_log_dDebug, warnings, and errors
4esp3d_logAll messages (Verbose)

Sources:components/esp3d_log/esp3d_log.h#28-32cmake/dev_tools.cmake#37-44

The core output function esp3d_log_output handles multiline splitting and assembly into a final buffer. It prepends a header containing the filename, line number, and function name components/esp3d_log/esp3d_log.c#200-201 Access to internal static formatting buffers is protected by s_log_mutex to ensure thread-safety across UI and communication tasks components/esp3d_log/esp3d_log.c#49-50

// Example usage in code
esp3d_log_d("Initializing %s at baud %d", client_name, baud);
esp3d_log_e("Failed to allocate message buffer");

The system includes a utility esp3d_log_u64_to_str (aliased as U64_STR(x)) because some standard library printf implementations on ESP32 lack %llu support components/esp3d_log/esp3d_log.h#108-111 It uses 4 rotating buffers to allow multiple calls within a single log line components/esp3d_log/esp3d_log.c#100-102

Sources:components/esp3d_log/esp3d_log.c#49-129components/esp3d_log/esp3d_log.h#108-118

Developers can tune the logging behavior in cmake/dev_tools.cmake:

The firmware supports five backends selected at compile-time via ESP3D_LOG_BACKENDcomponents/esp3d_log/esp3d_log.h#37-41:

  1. Serial (0): Standard UART output via esp_log_writecomponents/esp3d_log/CMakeLists.txt#25-26
  2. SD Card (1): Writes logs to the SD card main/modules/log/sd/esp3d_log_sd_backend.cpp#1-10
  3. UART2 (2): Output to a secondary UART port main/modules/log/uart2/esp3d_log_uart2_backend.cpp#1-10
  4. Telnet (3): Streams logs over a Telnet connection main/modules/log/telnet/esp3d_log_telnet_backend.cpp#1-10
  5. WebSocket (4): Broadcasts logs to connected WebSocket clients main/modules/log/websocket/esp3d_log_websocket_backend.cpp#1-10

Sources:cmake/dev_tools.cmake#59-69components/esp3d_log/CMakeLists.txt#3-10docs/guides/esp3d_log_guide.md#101-110


The communication system relies on a dual-queue architecture (RX and TX) implemented in the ESP3DClient base class.

Title: Message Queue Code Entities

Transport Implementations

ESP3DClient Base Class

Consumer

GcodeHandler

_rx_queue (std::deque)

_tx_queue (std::deque)

_rx_mutex

_tx_mutex

addRxData()

popRx()

ESP3DSerialClient

ESP3DUsbSerialClient

ESP3DBTSerialClient

ESP3DBTBleClient

Sources:main/core/esp3d_client.cpp#34-247docs/architecture/connection_management.md#52-58

To debug communication lag or “stuck” commands, developers can inspect the queue sizes and memory usage using getRxMsgsCount() and getTxMsgsCount()main/core/esp3d_client.cpp#114-147


The esp3dTftValues service is a pub/sub system for real-time CNC data (positions, overrides, status).

Title: Value Subscription Data Flow

Data Source

Registry: ESP3DValues

UI Subscribers

JogScreen::on_value_changed

StatusScreen::on_value_changed

set_value(ESP3DValuesIndex, value)

_values_map

GcodeHandler::processStatus()

  1. Trace Subscriptions: Log every time a callback is triggered to ensure the parser is extracting data correctly.
  2. Verify Unsubscription: Ensure unsubscribe() is called in prepareForDestruction(). Failure to do so causes crashes when the pub/sub system attempts to call a method on a deleted screen object main/display/cnc/screens/jog_screen.cpp#1123-1161

Sources:main/display/cnc/screens/jog_screen.cpp#1123-1161docs/architecture/connection_management.md#52-58


The PanelComponent manages interactive elements with rotary encoder navigation. A common issue is “phantom navigation” where encoder pulses from a previous screen affect the new one. The constructor explicitly calls VirtualButtonsComponent::resetEncoderSteps() to prevent this main/display/components/panel_component.cpp#41-45

PanelComponent operates in two modes: PANEL_NAVIGATION_MODE and PANEL_EDITING_MODEmain/display/components/panel_component.h#34-35 If an item is not responding to the encoder, check if enableEncoderFor() was called with the correct mode main/display/components/panel_component.cpp#333-356

Sources:main/display/components/panel_component.cpp#29-62main/display/components/panel_component.h#34-53


The tools/fw_simulator/ directory contains Python scripts to simulate CNC controllers (Marlin, Grbl, FluidNC). This allows testing the pendant without physical CNC hardware tools/fw_simulator/fw_simulator.py#1-11

  • fw_simulator.py: The main entry point. It detects serial ports and routes G-code to specific firmware logic tools/fw_simulator/fw_simulator.py#12-32
  • fluidnc.py: Simulates FluidNC status reports and Jog commands.

Sources:tools/fw_simulator/fw_simulator.py#1-75

The cmake/dev_tools.cmake file provides several flags to aid development:

Sources:cmake/dev_tools.cmake#1-90


SymptomPotential CauseDebug Step
UI FreezeMutex DeadlockCheck s_log_mutex usage in esp3d_log output components/esp3d_log/esp3d_log.c#49-50
Crash on Screen ChangeMissing UnsubscribeVerify esp3dTftValues.unsubscribe is called in prepareForDestruction.
Stale Position DataParser FailureUse fw_simulator.py to send known status strings and check log output.
No Serial CommBaud MismatchVerify ESP3D_LOG for “Serial initialized” and check NVS settings.
Phantom Encoder ClicksBuffer Not ClearedEnsure PanelComponent constructor clears the encoder buffer main/display/components/panel_component.cpp#41-45

Sources:main/core/esp3d_client.cpp#42-80main/display/components/panel_component.cpp#41-45cmake/dev_tools.cmake#83-88components/esp3d_log/esp3d_log.c#49-50