Skip to content

Instantly share code, notes, and snippets.

@Tech500
Last active August 4, 2026 22:16
Show Gist options
  • Select an option

  • Save Tech500/73ff160249ff1eec437cc68712aa884c to your computer and use it in GitHub Desktop.

Select an option

Save Tech500/73ff160249ff1eec437cc68712aa884c to your computer and use it in GitHub Desktop.
SX1262 with Channel Activity Detection-Wake-on-Radio-Deep Sleep
#define EoRa_PI_V1
#include <RadioLib.h>
#include <boards.h>
#include <SPI.h>
#include "driver/rtc_io.h"
// --- Pin Definitions
//Using Ebyte's EoRa-S3-900TB Configuration files
#define WAKEUP_PIN GPIO_NUM_16
const float radioFreq = 915.0; // MHz
const float bandWidth = 125.0; // kHz
const uint8_t spreadingFactor = 7;
const uint8_t codingRate = 7;
const uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE;
SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
// flag to indicate that a packet was detected or CAD timed out
volatile bool scanFlag = false;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
#if defined(ESP8266) || defined(ESP32)
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// something happened, set the flag
scanFlag = true;
}
void setupLoRa() {
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN, RADIO_CS_PIN);
radio.standby();
delay(50);
radio.resetOnStartup = true;
delay(50);
radio.tcxoVoltage = 1.6; // Crucial 1.6V reference for Ebyte modules
int state = radio.begin(
radioFreq,
125.0,
7,
7,
RADIOLIB_SX126X_SYNC_WORD_PRIVATE,
2,
5000, // <--- SET PREAMBLE TO 5000 TO MATCH TRANSMITTER
1.6,
false
);
if (state == RADIOLIB_ERR_NONE) {
radio.setRegulatorDCDC();
// Force explicit 5000 symbol preamble configuration
radio.setPreambleLength(5000);
Serial.println(F("[SX1262] Battery Receiver Initialized with 5000-symbol Preamble."));
} else {
Serial.printf("[SX1262] Initialization failed, code %d\n", state);
}
}
// --- Your 10-Pass Diagnostic Logic repurposed as a Filter ---
bool verifySignalWithBusyLoop(int totalPasses = 10, int requiredHits = 3) {
Serial.println(F("\n--- [WAKE DIAGNOSTIC & MULTI-SCAN START] ---"));
// 1. Verify Sleep Wakeup Reason
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
Serial.printf(" Wakeup Cause Code: %d ", wakeup_reason);
if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) {
Serial.println(F("(ESP_SLEEP_WAKEUP_EXT0 - DIO1 High)"));
} else {
Serial.println(F("(Other Wakeup Reason / Cold Boot)"));
}
// 2. Read Physical Pins at Boot
int dio1State = digitalRead(WAKEUP_PIN);
int busyState = digitalRead(RADIO_BUSY_PIN);
Serial.printf(" Pin Levels at Boot -> DIO1 (GPIO %d): %d | BUSY (GPIO %d): %d\n",
RADIO_DIO1_PIN, dio1State, RADIO_BUSY_PIN, busyState);
// 3. Query Radio Internal IRQ Flags
uint16_t irqFlags = radio.getIrqFlags();
Serial.printf(" SX1262 Internal IRQ Register: 0x%04X\n", irqFlags);
if (irqFlags & RADIOLIB_SX126X_IRQ_CAD_DETECTED) {
Serial.println(F(" [IRQ CHECK] -> RADIOLIB_SX126X_IRQ_CAD_DETECTED is SET!"));
}
if (irqFlags & RADIOLIB_SX126X_IRQ_HEADER_VALID) {
Serial.println(F(" [IRQ CHECK] -> RADIOLIB_SX126X_IRQ_HEADER_VALID is SET!"));
}
//esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) {
Serial.println("Woke from hub WOR -- reading and sending BME280 data");
digitalWrite(BOARD_LED, LED_ON);
}
return false;
}
void enterLowPowerWOR() {
radio.clearIrqFlags(RADIOLIB_SX126X_IRQ_ALL);
int state = radio.startReceiveDutyCycleAuto(
5000,
0,
RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED |
RADIOLIB_SX126X_IRQ_HEADER_VALID |
RADIOLIB_SX126X_IRQ_RX_DONE,
RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED |
RADIOLIB_SX126X_IRQ_HEADER_VALID |
RADIOLIB_SX126X_IRQ_RX_DONE
);
if (state != RADIOLIB_ERR_NONE) {
Serial.printf("[SX1262] DutyCycleAuto failed, code: %d\n", state);
return;
}
// DIO1 = GPIO16, already defined by EoRa board file
pinMode(WAKEUP_PIN, INPUT);
// EXT0 is level triggered
// SX1262 DIO1 goes HIGH on interrupt
esp_sleep_enable_ext0_wakeup(WAKEUP_PIN, 1);
Serial.printf("DIO1 GPIO %d before sleep = %d\n",
WAKEUP_PIN,
digitalRead(WAKEUP_PIN));
Serial.println(F(
"=== SX1262 WOR armed - ESP32-S3 entering deep sleep ==="
));
Serial.flush();
esp_deep_sleep_start();
}
void setup() {
initBoard();
delay(1500);
Serial.begin(115200);
delay(1500); // Give CDC Serial monitor time to connect
Serial.println(F("\n=============================================="));
Serial.println(F("--- ESP32-S3 WOR NODE (BOOT DIAGNOSTIC) ---"));
// 1. Initialize Radio SPI & SX1262
setupLoRa();
// 2. ALWAYS run diagnostic on boot to verify pin states and test CAD
Serial.println(F("Executing mandatory boot-up radio diagnostic..."));
verifySignalWithBusyLoop(10, 3);
// 3. Enter WOR Sleep
enterLowPowerWOR();
}
void loop() {
// Unused
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment