microReticulumTbeam/exercises/01_lora_ascii_pingpong/src/main.cpp

148 lines
3.8 KiB
C++

// 20260212 ChatGPT
// $Id$
// $HeadURL$
#include <Arduino.h>
#include <SPI.h>
#include <RadioLib.h>
// --- 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);
}