// 20260212 ChatGPT // $Id$ // $HeadURL$ #include #include #include // --- Compile-time label --- #ifndef NODE_LABEL #define NODE_LABEL "?" #endif // --- Pins injected via platformio.ini build_flags --- #ifndef LORA_CS #error "LORA_CS not defined" #endif #ifndef LORA_DIO1 #error "LORA_DIO1 not defined" #endif #ifndef LORA_RESET #error "LORA_RESET not defined" #endif #ifndef LORA_BUSY #error "LORA_BUSY not defined" #endif // SX1262 on T-Beam Supreme (tbeam-s3-core pinout) SX1262 radio = new Module(LORA_CS, LORA_DIO1, LORA_RESET, LORA_BUSY); static volatile bool g_rx_flag = false; static void onDio1Rise() { g_rx_flag = true; } static void print_config() { Serial.printf("Node=%s\n", NODE_LABEL); Serial.printf("Pins: CS=%d DIO1=%d RST=%d BUSY=%d SCK=%d MISO=%d MOSI=%d\r\n", (int)LORA_CS, (int)LORA_DIO1, (int)LORA_RESET, (int)LORA_BUSY, (int)LORA_SCK, (int)LORA_MISO, (int)LORA_MOSI); Serial.printf("LoRa: freq=915.0 BW=125 SF=7 CR=5 txp=14\r\n"); } void setup() { Serial.begin(115200); delay(250); Serial.println(); Serial.println("Exercise 01: LoRa ASCII ping-pong (serial only)"); // Ensure SPI pins match the variant SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); int state = radio.begin(915.0 /* MHz */, 125.0 /* kHz */, 7 /* SF */, 5 /* CR */, 0x12 /* sync */, 14 /* dBm */); if (state != RADIOLIB_ERR_NONE) { Serial.printf("ERROR: radio.begin failed, code=%d\r\n", state); while (true) delay(1000); } // Match Meshtastic-like wiring assumptions for SX1262 modules: // - DIO2 used as RF switch // - TCXO at 1.8V //OLD radio.setDio2AsRfSwitch(true); //OLD radio.setTcxoVoltage((float)LORA_TCXO_VOLTAGE); // below is replacement for above 2 lines: //maybe_setDio2AsRfSwitch(radio, true); //maybe_setTcxoVoltage(radio, (float)LORA_TCXO_VOLTAGE); // end of replacement // Set up RX interrupt radio.setDio1Action(onDio1Rise); // Start receiving state = radio.startReceive(); if (state != RADIOLIB_ERR_NONE) { Serial.printf("ERROR: startReceive failed, code=%d\r\n", state); while (true) delay(1000); } print_config(); } void loop() { // Periodic TX (with a label-based offset to reduce collisions) static uint32_t next_tx_ms = 0; static uint32_t iter = 0; uint32_t now = millis(); if (next_tx_ms == 0) { // Offset A and B so they don't always collide uint32_t offset = (NODE_LABEL[0] == 'A') ? 500 : 1500; next_tx_ms = now + offset; } if ((int32_t)(now - next_tx_ms) >= 0) { next_tx_ms = now + 2000; // 2 seconds for this smoke test // String msg = String("I am ") + NODE_LABEL + " iter=" + String(iter++); String msg = String(" ") + NODE_LABEL + " sends greetings. iter=" + String(iter++); Serial.printf("TX: %s\r\n", msg.c_str()); //int tx = radio.transmit(msg); //if (tx != RADIOLIB_ERR_NONE) { // Serial.printf("TX ERROR code=%d\r\n", tx); // } // After transmit, resume RX //radio.startReceive(); // DIO1 triggers on TX-done as well as RX-done. // If left armed, TX completion looks like RX. g_rx_flag = false; radio.clearDio1Action(); int tx = radio.transmit(msg); if (tx != RADIOLIB_ERR_NONE) { Serial.printf("TX ERROR code=%d\r\n", tx); } // Re-arm RX interrupt and resume RX g_rx_flag = false; radio.setDio1Action(onDio1Rise); radio.startReceive(); } // RX handling if (g_rx_flag) { g_rx_flag = false; String rx; int state = radio.readData(rx); if (state == RADIOLIB_ERR_NONE) { Serial.printf("RX: %s | RSSI=%.1f SNR=%.1f\r\n", rx.c_str(), radio.getRSSI(), radio.getSNR()); } else { Serial.printf("RX ERROR code=%d\r\n", state); } // Keep receiving radio.startReceive(); } delay(5); }