From e65dbd7f747c219ee58db17e3bba1549f037627f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 02:51:12 +0000 Subject: [PATCH 1/4] Initial plan From 9a486009217e1cb04661d33caab09fc6cf6abe18 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 02:56:11 +0000 Subject: [PATCH 2/4] Add raw pulse train callback API --- src/rtl_433_ESP.cpp | 4 ++++ src/rtl_433_ESP.h | 9 +++++++++ src/signalDecoder.cpp | 9 +++++++++ src/signalDecoder.h | 1 + 4 files changed, 23 insertions(+) diff --git a/src/rtl_433_ESP.cpp b/src/rtl_433_ESP.cpp index d7792682..f6b1b5b3 100644 --- a/src/rtl_433_ESP.cpp +++ b/src/rtl_433_ESP.cpp @@ -681,6 +681,10 @@ void rtl_433_ESP::setCallback(rtl_433_ESPCallBack callback, char* messageBuffer, _setCallback(callback, messageBuffer, bufferSize); } +void rtl_433_ESP::setRawPulsesCallback(rtl_433_raw_pulse_cb callback) { + _setRawPulsesCallback(callback); +} + /** * @brief Set delta applied to average RSSI level for determining start and end of signal * diff --git a/src/rtl_433_ESP.h b/src/rtl_433_ESP.h index 5c2f909b..35021821 100644 --- a/src/rtl_433_ESP.h +++ b/src/rtl_433_ESP.h @@ -226,6 +226,9 @@ * message - JSON formatted message from device */ typedef void (*rtl_433_ESPCallBack)(char* message); +typedef void (*rtl_433_raw_pulse_cb)(const int* pulse_us, const int* gap_us, + unsigned int num_pulses, + unsigned long duration_us, int rssi); typedef std::function PulseTrainCallBack; @@ -257,6 +260,12 @@ class rtl_433_ESP { void setCallback(rtl_433_ESPCallBack callback, char* messageBuffer, int bufferSize); + /** + * Set callback to receive raw pulse train data for each captured signal. + * Pointers are valid only during callback execution. + */ + void setRawPulsesCallback(rtl_433_raw_pulse_cb callback); + /** * Set minimum RSSI value for receiver */ diff --git a/src/signalDecoder.cpp b/src/signalDecoder.cpp index 85451915..86ce591c 100644 --- a/src/signalDecoder.cpp +++ b/src/signalDecoder.cpp @@ -52,6 +52,7 @@ r_cfg_t g_cfg; // Global config object TaskHandle_t rtl_433_DecoderHandle; static QueueHandle_t rtl_433_Queue; +static rtl_433_raw_pulse_cb rawPulsesCallback = nullptr; void rtlSetup() { r_cfg_t* cfg = &g_cfg; @@ -482,6 +483,10 @@ void _setCallback(rtl_433_ESPCallBack callback, char* messageBuffer, cfg->bufferSize = bufferSize; } +void _setRawPulsesCallback(rtl_433_raw_pulse_cb callback) { + rawPulsesCallback = callback; +} + void _setDebug(int debug) { rtlVerbose = debug; logprintfLn(LOG_INFO, "Setting rtl_433 debug to: %d", rtlVerbose); @@ -523,6 +528,10 @@ void rtl_433_DecoderTask(void* pvParameters) { } else { events = run_fsk_demods(&cfg->demod->r_devs, rtl_pulses); } + if (rawPulsesCallback != nullptr) { + rawPulsesCallback(rtl_pulses->pulse, rtl_pulses->gap, rtl_pulses->num_pulses, + rtl_pulses->signalDuration, rtl_pulses->signalRssi); + } if (events == 0) { #ifdef RTL_ANALYZER pulse_analyzer(rtl_pulses, rtl_433_ESP::ookModulation ? 1 : 2); diff --git a/src/signalDecoder.h b/src/signalDecoder.h index 03ba6c64..d34f5cef 100644 --- a/src/signalDecoder.h +++ b/src/signalDecoder.h @@ -48,6 +48,7 @@ extern "C" { void rtlSetup(); void _setCallback(rtl_433_ESPCallBack callback, char* messageBuffer, int bufferSize); +void _setRawPulsesCallback(rtl_433_raw_pulse_cb callback); void _setDebug(int debug); void processSignal(pulse_data_t* rtl_pulses); void rtl_433_DecoderTask(void* pvParameters); From 121afa51e8813b3bb1d29eb7a5a0ad8d112d3b57 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 03:00:24 +0000 Subject: [PATCH 3/4] Harden raw pulse callback registration race --- src/signalDecoder.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/signalDecoder.cpp b/src/signalDecoder.cpp index 86ce591c..ac5017cd 100644 --- a/src/signalDecoder.cpp +++ b/src/signalDecoder.cpp @@ -25,6 +25,8 @@ #include "signalDecoder.h" +#include + /*----------------------------- rtl_433_ESP Internals -----------------------------*/ #ifndef rtl_433_Decoder_Stack @@ -52,7 +54,7 @@ r_cfg_t g_cfg; // Global config object TaskHandle_t rtl_433_DecoderHandle; static QueueHandle_t rtl_433_Queue; -static rtl_433_raw_pulse_cb rawPulsesCallback = nullptr; +static std::atomic rawPulsesCallback{nullptr}; void rtlSetup() { r_cfg_t* cfg = &g_cfg; @@ -484,7 +486,7 @@ void _setCallback(rtl_433_ESPCallBack callback, char* messageBuffer, } void _setRawPulsesCallback(rtl_433_raw_pulse_cb callback) { - rawPulsesCallback = callback; + rawPulsesCallback.store(callback, std::memory_order_release); } void _setDebug(int debug) { @@ -528,9 +530,11 @@ void rtl_433_DecoderTask(void* pvParameters) { } else { events = run_fsk_demods(&cfg->demod->r_devs, rtl_pulses); } - if (rawPulsesCallback != nullptr) { - rawPulsesCallback(rtl_pulses->pulse, rtl_pulses->gap, rtl_pulses->num_pulses, - rtl_pulses->signalDuration, rtl_pulses->signalRssi); + rtl_433_raw_pulse_cb rawCallback = + rawPulsesCallback.load(std::memory_order_acquire); + if (rawCallback != nullptr) { + rawCallback(rtl_pulses->pulse, rtl_pulses->gap, rtl_pulses->num_pulses, + rtl_pulses->signalDuration, rtl_pulses->signalRssi); } if (events == 0) { #ifdef RTL_ANALYZER From 22777dce862e2dd1db2840fd888e22dd803fe130 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 12:20:24 +0000 Subject: [PATCH 4/4] Document and demonstrate raw pulse callback --- README.md | 26 ++++++++++++++++++++++++++ example/OOK_Receiver/OOK_Receiver.ino | 16 ++++++++++++++++ example/OOK_Receiver/README.md | 4 ++++ 3 files changed, 46 insertions(+) diff --git a/README.md b/README.md index 52336681..9beb4b03 100644 --- a/README.md +++ b/README.md @@ -365,6 +365,32 @@ build_flags = For a complete example, see the `esp32_heltec_915` environment in [example/OOK_Receiver/platformio.ini](example/OOK_Receiver/platformio.ini#L163). +## Callbacks + +The library supports two callback interfaces: + +* `setCallback(...)` - receives JSON payloads for successfully decoded signals. +* `setRawPulsesCallback(...)` - receives raw pulse/gap timing for every captured signal, including signals that do not match a built-in decoder. + +```cpp +typedef void (*rtl_433_raw_pulse_cb)( + const int* pulse_us, + const int* gap_us, + unsigned int num_pulses, + unsigned long duration_us, + int rssi +); +``` + +Registering callbacks: + +```cpp +rf.setCallback(rtl_433_Callback, messageBuffer, JSON_MSG_BUFFER); +rf.setRawPulsesCallback(rtl_433_RawCallback); +``` + +Raw pulse pointers are valid only during the callback. Copy any data you need to keep. + ## Wiring and Building the Example Details are [here](example/OOK_Receiver/README.md) diff --git a/example/OOK_Receiver/OOK_Receiver.ino b/example/OOK_Receiver/OOK_Receiver.ino index 7f780293..188a2bc7 100644 --- a/example/OOK_Receiver/OOK_Receiver.ino +++ b/example/OOK_Receiver/OOK_Receiver.ino @@ -12,6 +12,7 @@ #endif #define JSON_MSG_BUFFER 512 +#define RAW_CALLBACK_SAMPLE_PULSES 8 char messageBuffer[JSON_MSG_BUFFER]; @@ -26,6 +27,20 @@ void rtl_433_Callback(char* message) { count++; } +void rtl_433_RawCallback(const int* pulse_us, const int* gap_us, + unsigned int num_pulses, unsigned long duration_us, + int rssi) { + Log.notice(F("Raw signal: duration=%luus pulses=%u rssi=%d" CR), duration_us, + num_pulses, rssi); + unsigned int sampleCount = num_pulses; + if (sampleCount > RAW_CALLBACK_SAMPLE_PULSES) { + sampleCount = RAW_CALLBACK_SAMPLE_PULSES; + } + for (unsigned int i = 0; i < sampleCount; i++) { + Log.notice(F(" pulse[%u]=+%dus -%dus" CR), i, pulse_us[i], gap_us[i]); + } +} + void logJson(JsonDocument jsondata) { #if defined(ESP8266) || defined(ESP32) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) char JSONmessageBuffer[measureJson(jsondata) + 1]; @@ -54,6 +69,7 @@ void setup() { Log.notice(F("****** setup ******" CR)); rf.initReceiver(RF_MODULE_RECEIVER_GPIO, RF_MODULE_FREQUENCY); rf.setCallback(rtl_433_Callback, messageBuffer, JSON_MSG_BUFFER); + rf.setRawPulsesCallback(rtl_433_RawCallback); rf.enableReceiver(); Log.notice(F("****** setup complete ******" CR)); rf.getModuleStatus(); diff --git a/example/OOK_Receiver/README.md b/example/OOK_Receiver/README.md index 38f7551f..799e028c 100644 --- a/example/OOK_Receiver/README.md +++ b/example/OOK_Receiver/README.md @@ -1,5 +1,9 @@ This is a sample implementation of the rtl_433_ESP library with the CC1101 or the SX127X (Heltec) Transceiver Module. +The sample registers both callback types: +* JSON decode callback (`setCallback`) +* Raw pulse callback (`setRawPulsesCallback`) for pulse/gap timing on every captured signal + # Building and implementing the sample To build and deploy the sample I used Visual Studio Code and PlatformIO. This development environment will pull in all the required libraries as part of the build.