// 20260212 ChatGPT
// $Id$
// $HeadURL$

/*
  Exercise 01: LoRa ASCII ping-pong (serial only)

  This is a simple "ping-pong" test of LoRa communication between two nodes, using the Serial console for output.
  The nodes will periodically transmit a message containing their label and an iteration count, and print any received messages along with RSSI and SNR.

  To run this test, set up two devices with the same code but different NODE_LABELs (e.g., "A" and "B"), and ensure they are within range of each other. You should see them exchanging messages in the Serial console.

  Note: This exercise assumes you have already set up the hardware and wiring correctly, as per the instructions in the README. Make sure to adjust the pins in platformio.ini if needed.
    
  
*/
#include <Arduino.h>
#include <SPI.h>
#include <RadioLib.h>

// --- Compile-time label ---
#ifndef NODE_LABEL
#define NODE_LABEL "?"
#endif
#ifndef UNIT_NAME
  #define UNIT_NAME "UNNAMED"
#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 + " says hi. 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);
}

