Last active
February 23, 2026 21:38
-
-
Save Tech500/e3db24ef063edc78dacc3542c1d71fcf to your computer and use it in GitHub Desktop.
EoRa-S3-900TB---FreeRTOS--WOR--Dual-Core LoRa Project
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define EoRa_PI_V1 | |
| #include <Arduino.h> | |
| #include <RadioLib.h> | |
| #include "boards.h" | |
| #include "packet_struct.h" | |
| #include "utilities.h" | |
| #include "radio_eora.h" | |
| #include "driver/rtc_io.h" | |
| #include "esp_sleep.h" | |
| // -------------------- Camera Power Pins -------------------- | |
| #define KY002S_TRIGGER 10 // Camera ON/OFF control | |
| #define KY002S_STATUS 11 // Optional status input | |
| // -------------------- Flags -------------------- | |
| extern SX1262 radio; | |
| extern volatile bool enableInterrupt; | |
| extern volatile bool receivedFlag; // already defined in your ISR file | |
| extern void setFlag(); // ISR from radio_eora | |
| // -------------------- Forward Declarations -------------------- | |
| void handleWorWake(); | |
| void handleTimerWake(); | |
| void enterWorSleep(); | |
| // -------------------- Setup -------------------- | |
| void setup() { | |
| pinMode(KY002S_TRIGGER, OUTPUT); | |
| digitalWrite(KY002S_TRIGGER, LOW); // camera OFF by default | |
| pinMode(KY002S_STATUS, INPUT_PULLDOWN); | |
| Serial.begin(115200); | |
| delay(300); | |
| esp_sleep_wakeup_cause_t wake = esp_sleep_get_wakeup_cause(); | |
| Serial.print("Wake reason: "); | |
| Serial.println((int)wake); | |
| if (wake == ESP_SLEEP_WAKEUP_EXT0) { | |
| handleWorWake(); | |
| } | |
| else if (wake == ESP_SLEEP_WAKEUP_TIMER) { | |
| handleTimerWake(); | |
| } | |
| else { | |
| // First boot or reset → go straight into WOR mode | |
| initRadio(); | |
| enterWorSleep(); | |
| } | |
| } | |
| void loop() { | |
| delay(1000); // should never run | |
| } | |
| // -------------------- WOR Mode Entry -------------------- | |
| void enterWorSleep() { | |
| Serial.println("Entering WOR mode..."); | |
| radio.setDio1Action(setFlag); | |
| int state = radio.startReceiveDutyCycleAuto(); | |
| if (state != RADIOLIB_ERR_NONE) { | |
| Serial.print("WOR start failed: "); | |
| Serial.println(state); | |
| } | |
| esp_sleep_enable_ext0_wakeup((gpio_num_t)RADIO_DIO1_PIN, 1); | |
| Serial.println("Deep sleeping (WOR)..."); | |
| delay(50); | |
| esp_deep_sleep_start(); | |
| } | |
| // -------------------- WOR Wake Handler -------------------- | |
| void handleWorWake() { | |
| Serial.println("WOR wake: waiting for packet..."); | |
| uint32_t start = millis(); | |
| while (!receivedFlag && (millis() - start) < 5000) { | |
| delay(1); | |
| } | |
| if (!receivedFlag) { | |
| Serial.println("No packet after WOR wake. Re-arming WOR."); | |
| initRadio(); | |
| enterWorSleep(); | |
| } | |
| receivedFlag = false; | |
| LoraPacket pkt; | |
| int state = radio.readData((uint8_t*)&pkt, sizeof(pkt)); | |
| if (state != RADIOLIB_ERR_NONE) { | |
| Serial.print("readData failed: "); | |
| Serial.println(state); | |
| initRadio(); | |
| enterWorSleep(); | |
| } | |
| Serial.print("Packet: type="); | |
| Serial.print(pkt.type); | |
| Serial.print(" cmd="); | |
| Serial.print(pkt.cmd); | |
| Serial.print(" ts="); | |
| Serial.println(pkt.timestamp); | |
| if (pkt.cmd == 1) { | |
| Serial.println("Turning camera ON..."); | |
| digitalWrite(KY002S_TRIGGER, HIGH); | |
| Serial.println("Putting radio to sleep..."); | |
| radio.sleep(); // eliminates 8mA WOR spikes | |
| const uint64_t ON_DURATION_US = 2ULL * 60ULL * 1000000ULL; // 2 minutes | |
| esp_sleep_enable_timer_wakeup(ON_DURATION_US); | |
| Serial.println("Deep sleeping (camera ON timer)..."); | |
| delay(50); | |
| esp_deep_sleep_start(); | |
| } | |
| // Unknown command → re-arm WOR | |
| initRadio(); | |
| enterWorSleep(); | |
| } | |
| // -------------------- Timer Wake Handler -------------------- | |
| void handleTimerWake() { | |
| Serial.println("Timer wake: turning camera OFF."); | |
| digitalWrite(KY002S_TRIGGER, LOW); | |
| initRadio(); | |
| enterWorSleep(); | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define EoRa_PI_V1 | |
| #include <Arduino.h> | |
| #include "radiolib.h" | |
| #include "boards.h" | |
| #include <WiFi.h> | |
| #include <AsyncTCP.h> | |
| #include <ESPAsyncWebServer.h> | |
| #include "radio_eora.h" // your SX1262 wrapper | |
| #include "structs.h" // your LoraPacket struct | |
| #include "index7.h" // HTML7 + processor7 | |
| // -------------------- WiFi Credentials -------------------- | |
| const char* ssid = "YOUR_SSID"; | |
| const char* password = "YOUR_PASSWORD"; | |
| // -------------------- Web Server -------------------- | |
| AsyncWebServer server(80); | |
| // -------------------- TX Flags -------------------- | |
| volatile bool sendRequested = false; | |
| // -------------------- Forward Declarations -------------------- | |
| void txTask(void* parameter); | |
| void sendLoRaPacket(); | |
| // -------------------- Setup -------------------- | |
| void setup() { | |
| Serial.begin(115200); | |
| delay(300); | |
| // WiFi | |
| WiFi.mode(WIFI_STA); | |
| WiFi.begin(ssid, password); | |
| Serial.print("Connecting to WiFi"); | |
| while (WiFi.status() != WL_CONNECTED) { | |
| delay(300); | |
| Serial.print("."); | |
| } | |
| Serial.println(); | |
| Serial.print("TX IP: "); | |
| Serial.println(WiFi.localIP()); | |
| // Radio init | |
| initRadio(); | |
| // -------------------- Web Route -------------------- | |
| server.on("/relay", HTTP_GET, [](AsyncWebServerRequest *request) { | |
| // 1. Serve HTML page from PROGMEM | |
| request->send_P(200, PSTR("text/html"), HTML7, processor7); | |
| // 2. Trigger LoRa send | |
| sendRequested = true; | |
| }); | |
| server.begin(); | |
| // -------------------- TX Task (Core 1) -------------------- | |
| xTaskCreatePinnedToCore( | |
| txTask, | |
| "txTask", | |
| 4096, | |
| NULL, | |
| 1, | |
| NULL, | |
| 1 | |
| ); | |
| } | |
| void loop() { | |
| // Nothing here — TX is event-driven | |
| } | |
| // -------------------- TX Task -------------------- | |
| void txTask(void* parameter) { | |
| for (;;) { | |
| if (sendRequested) { | |
| sendRequested = false; | |
| sendLoRaPacket(); | |
| } | |
| vTaskDelay(10 / portTICK_PERIOD_MS); | |
| } | |
| } | |
| // -------------------- Send WOR + Payload -------------------- | |
| void sendLoRaPacket() { | |
| Serial.println("TX: Sending WOR preamble..."); | |
| // 1. WOR preamble | |
| radio.transmitWORPreamble(); | |
| // 2. Short delay (RX needs this) | |
| delay(30); | |
| // 3. Build packet | |
| LoraPacket pkt; | |
| pkt.type = 1; | |
| pkt.cmd = 1; | |
| pkt.timestamp = (uint32_t)millis(); // or your NTP timestamp | |
| Serial.println("TX: Sending payload struct..."); | |
| // 4. Send struct | |
| int state = radio.transmit((uint8_t*)&pkt, sizeof(pkt)); | |
| if (state == RADIOLIB_ERR_NONE) { | |
| Serial.println("TX: Packet sent OK."); | |
| } else { | |
| Serial.print("TX: Packet send failed, code "); | |
| Serial.println(state); | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment