Skip to content

[modem]: Add support for DTE-Tx hooks#1042

Open
david-cermak wants to merge 1 commit intoespressif:masterfrom
david-cermak:fix/modem_expose
Open

[modem]: Add support for DTE-Tx hooks#1042
david-cermak wants to merge 1 commit intoespressif:masterfrom
david-cermak:fix/modem_expose

Conversation

@david-cermak
Copy link
Copy Markdown
Collaborator

@david-cermak david-cermak commented Apr 2, 2026

Add before/after transmit hooks to DTE so users can toggle a GPIO (DTR / sleep pin) around every UART write; including internal PPP frames, LCP echo-replies, and other traffic that applications cannot wrap today. This enables UART power-save modes (Quectel QSCLK, u-blox UPSV, SIMCom CSCLK, etc.) without silent data loss.

  • C++ API: DTE::set_transmit_hooks(before_tx, after_tx) hooks fire in all four DTE write paths (write(uint8_t*,size_t), write(DTE_Command), send(...), and inside command(...))

  • *C API : esp_modem_set_transmit_hooks(dce, before_tx, after_tx, user_ctx) wraps the C++ hooks with an opaque context pointer

  • Public terminal factory: create_uart_terminal() moved from private to public header, enabling C++ users to build custom DTE subclasses without private-include workarounds

  • Fully additive, no breaking changes. When no hooks are registered, overhead is a single null-check per write.

Notes

  • In CMUX mode, hooks may be called concurrently from PPP and AT-command threads. Users needing DTR gating under CMUX should use an atomic refcount.
  • The hooks wrap only the actual terminal->write() call, not the full command-wait cycle, so DTR stays asserted only while bytes are in flight.

Note

Medium Risk
Touches core DTE transmit paths and adds callback execution around every write, which could impact timing/concurrency (especially under CMUX) if hooks misbehave, though behavior is additive when hooks are unset.

Overview
Adds before/after transmit hooks to DTE (set_transmit_hooks) and wraps all DTE transmit paths (command(), write(), write(DTE_Command), send()) so callers can toggle GPIOs around every terminal write, including PPP/data traffic.

Exposes create_uart_terminal() as a public C++ API for building custom DTE subclasses, and adds a C API entrypoint esp_modem_set_transmit_hooks() (with opaque user_ctx) plus host tests validating hook firing, ordering, and clearing.

Reviewed by Cursor Bugbot for commit 3ec901e. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7f0732c. Configure here.

Comment thread components/esp_modem/src/esp_modem_dte.cpp
Comment thread components/esp_modem/src/esp_modem_dte.cpp Fixed
Comment thread components/esp_modem/src/esp_modem_dte.cpp Fixed
Comment on lines +274 to +278
#if defined(__cpp_lib_atomic_shared_ptr)
std::atomic<std::shared_ptr<const TransmitHooks>> transmit_hooks_ {}; /*!< Immutable hook pair */
#else
std::shared_ptr<const TransmitHooks> transmit_hooks_; /*!< Immutable hook pair; use std::atomic_{load,store} */
#endif
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@euripedesrocha Here's my workaround to get atomic load/store with shared_prt<> work across all IDF versions. (atomic_load/store_explicit vs. shared_ptr<>.load is either deprecated or not present)

Perhaps you have a better idea/suggestion how to address this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants