pleasedontcode

**Spectrum Bridge** rev_06

Mar 13th, 2026
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 33.81 KB | None | 0 0
  1. /********* Pleasedontcode.com **********
  2.  
  3.     Pleasedontcode thanks you for automatic code generation! Enjoy your code!
  4.  
  5.     - Terms and Conditions:
  6.     You have a non-exclusive, revocable, worldwide, royalty-free license
  7.     for personal and commercial use. Attribution is optional; modifications
  8.     are allowed, but you're responsible for code maintenance. We're not
  9.     liable for any loss or damage. For full terms,
  10.     please visit pleasedontcode.com/termsandconditions.
  11.  
  12.     - Project: **Spectrum Bridge**
  13.     - Version: 006
  14.     - Source Code NOT compiled for: ESP32S3 Dev Module
  15.     - Source Code created on: 2026-03-13 17:49:45
  16.  
  17. ********* Pleasedontcode.com **********/
  18.  
  19. /****** SYSTEM REQUIREMENTS *****/
  20. /****** SYSTEM REQUIREMENT 1 *****/
  21.     /* Radio station (GPIO47/48, 115200 baud) */
  22.     /* bidirectional with Bluetooth or LoRa. Device: DMR- */
  23.     /* Radio + 4-digit random. PIN: 8800 */
  24. /****** SYSTEM REQUIREMENT 2 *****/
  25.     /* LoRa SX1262: 433MHz SF8 250kHz. TX/RX */
  26.     /* bidirectional. LoRa RX → Radio. Bluetooth RX → */
  27.     /* Radio only */
  28. /****** SYSTEM REQUIREMENT 3 *****/
  29.     /* GPIO0 (7000ms long press) toggles Bluetooth ↔ LoRa */
  30.     /* modes. Display 3 lines only: mode, name/freq, */
  31.     /* status */
  32. /****** SYSTEM REQUIREMENT 4 *****/
  33.     /* Display Heltec SSD1306: BT mode shows BLUETOOTH, */
  34.     /* name, CONNECTED/WAITING. LoRa shows LORA, 433MHz, */
  35.     /* status */
  36. /****** END SYSTEM REQUIREMENTS *****/
  37.  
  38.  
  39. /* START CODE */
  40.  
  41. /****** SYSTEM REQUIREMENTS *****/
  42. // System Requirement 1: "Receive radio station data on GPIO47/48 (115200 baud) and transmit to active channel (Bluetooth or LoRa). Device name DMR-Radio with random 4-digit suffix. PIN 8800 required"
  43. // System Requirement 2: "LoRa SX1262: 433 MHz, SF8, 250 kHz. Bidirectional TX/RX. Receive LoRa data and transmit to radio and Bluetooth"
  44. // System Requirement 3: "GPIO0 long press (7000ms) toggles between Bluetooth and LoRa modes. Display current mode on Heltec built-in screen"
  45. // System Requirement 4: "Bidirectional data flow: Radio ↔ Active Channel (Bluetooth or LoRa). LoRa RX data → Radio and Bluetooth. Bluetooth RX data → Radio and LoRa TX"
  46.  
  47. /****** DEFINITION OF LIBRARIES *****/
  48. // Using native ESP32 BLE library from board package (compatible with ESP32S3)
  49. #include <BLEDevice.h>
  50. #include <BLEServer.h>
  51. #include <BLEUtils.h>
  52. #include <BLE2902.h>
  53. #include <SPI.h>
  54. #include <LoRa.h>
  55. #include <Wire.h>
  56. #include <Adafruit_SSD1306.h>
  57. #include <Adafruit_GFX.h>
  58.  
  59. /****** DEFINITION OF CONSTANTS *****/
  60. // Heltec ESP32-S3 Pin Definitions
  61. #define GPIO0_BUTTON_PIN 0          // GPIO0 button for mode toggle
  62. #define SERIAL2_RX_PIN 47           // GPIO47 for Serial2 RX (from radio station)
  63. #define SERIAL2_TX_PIN 48           // GPIO48 for Serial2 TX (to radio station)
  64. #define SERIAL2_BAUDRATE 115200
  65.  
  66. // OLED Display Configuration (I2C)
  67. #define SCREEN_WIDTH 128
  68. #define SCREEN_HEIGHT 64
  69. #define OLED_RESET -1
  70. #define SCREEN_ADDRESS 0x3C
  71. #define OLED_SDA_PIN 21             // GPIO21 for I2C SDA
  72. #define OLED_SCL_PIN 22             // GPIO22 for I2C SCL
  73.  
  74. // LoRa SX1262 Pin Configuration (Heltec ESP32-S3)
  75. #define LORA_CS_PIN 8               // Chip Select
  76. #define LORA_RST_PIN 12             // Reset
  77. #define LORA_IRQ_PIN 14             // Interrupt
  78. #define LORA_BUSY_PIN 13            // Busy
  79. #define LORA_MOSI_PIN 10            // MOSI
  80. #define LORA_MISO_PIN 9             // MISO
  81. #define LORA_SCK_PIN 11             // SCK
  82.  
  83. // LoRa Configuration Constants
  84. #define LORA_FREQUENCY 433000000    // 433 MHz
  85. #define LORA_SPREADING_FACTOR 8     // SF8
  86. #define LORA_BANDWIDTH 250000        // 250 kHz (125000, 250000, or 500000)
  87. #define LORA_CODING_RATE 5          // 4/5
  88. #define LORA_PREAMBLE_LENGTH 8
  89. #define LORA_SYNC_WORD 0x34
  90.  
  91. // Button and Mode Configuration
  92. #define BUTTON_LONG_PRESS_TIME 7000 // 7 seconds for long press (mode toggle)
  93. #define BUTTON_DEBOUNCE_TIME 50     // Debounce time in milliseconds
  94. #define DISPLAY_UPDATE_INTERVAL 500 // Update display every 500ms
  95.  
  96. // BLE Configuration
  97. #define BLUETOOTH_DEVICE_NAME_BASE "DMR-Radio"
  98. #define SERVICE_UUID "12345678-1234-1234-1234-123456789012"
  99. #define CHARACTERISTIC_RX_UUID "12345678-1234-1234-1234-123456789013"
  100. #define CHARACTERISTIC_TX_UUID "12345678-1234-1234-1234-123456789014"
  101. #define BLE_PIN_CODE "8800"         // PIN code for Bluetooth security
  102.  
  103. // LoRa Message Configuration
  104. #define LORA_RX_BUFFER_SIZE 256
  105. #define LORA_TX_TIMEOUT 3000
  106.  
  107. /****** DEFINITION OF GLOBAL VARIABLES *****/
  108. // OLED display object
  109. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  110. bool displayAvailable = false;
  111. bool displayInitialized = false;
  112.  
  113. // BLE Server and Characteristic objects (using native ESP32 BLE API)
  114. BLEServer* pServer = NULL;
  115. BLECharacteristic* pCharacteristicRX = NULL;
  116. BLECharacteristic* pCharacteristicTX = NULL;
  117. bool bleConnected = false;
  118. bool oldBleConnected = false;
  119.  
  120. // Mode selection: true = Bluetooth mode, false = LoRa mode
  121. volatile bool currentMode = true; // Start in Bluetooth mode
  122. bool previousMode = true;
  123.  
  124. // Button state management
  125. volatile unsigned long buttonPressStartTime = 0;
  126. volatile bool buttonPressed = false;
  127. volatile bool buttonLongPressDetected = false;
  128. unsigned long lastButtonCheckTime = 0;
  129. bool previousButtonState = HIGH;
  130.  
  131. // LoRa variables
  132. uint8_t loraRxBuffer[LORA_RX_BUFFER_SIZE];
  133. int loraRxLength = 0;
  134. bool loraPacketReceived = false;
  135.  
  136. // Display and status variables
  137. unsigned long lastDisplayUpdate = 0;
  138. uint32_t packetsSentBluetooth = 0;
  139. uint32_t packetsReceivedBluetooth = 0;
  140. uint32_t packetsSentLoRa = 0;
  141. uint32_t packetsReceivedLoRa = 0;
  142. uint32_t packetsReceivedRadio = 0;
  143. uint32_t packetsSentRadio = 0;
  144. char bluetoothDeviceName[32];
  145.  
  146. /****** FUNCTION PROTOTYPES *****/
  147. void setup(void);
  148. void loop(void);
  149. void initializeDisplay(void);
  150. void updateDisplay(void);
  151. void initializeLoRa(void);
  152. void initializeBLE(void);
  153. void checkButtonInput(void);
  154. void toggleMode(void);
  155. void handleSerialFromRadio(void);
  156. void handleBLEFromClient(void);
  157. void handleLoRaReceive(void);
  158. void sendDataToRadio(const uint8_t* data, size_t length);
  159. void sendDataToBLE(const uint8_t* data, size_t length);
  160. void sendDataViaLoRa(const uint8_t* data, size_t length);
  161. void loraOnReceive(int packetSize);
  162. void displayBluetoothMode(void);
  163. void displayLoRaMode(void);
  164. void generateRandomSuffix(void);
  165.  
  166. /****** BLE SERVER CALLBACKS *****/
  167. // Callback class for BLE server events (using native ESP32 BLE API)
  168. class MyServerCallbacks: public BLEServerCallbacks
  169. {
  170.     void onConnect(BLEServer* pServer)
  171.     {
  172.         bleConnected = true;
  173.         Serial.println("[BLE] Client connected - status: CONNECTED");
  174.     }
  175.  
  176.     void onDisconnect(BLEServer* pServer)
  177.     {
  178.         bleConnected = false;
  179.         Serial.println("[BLE] Client disconnected - status: WAITING");
  180.     }
  181. };
  182.  
  183. // Callback class for BLE characteristic write events (using native ESP32 BLE API)
  184. class MyCharacteristicCallbacks: public BLECharacteristicCallbacks
  185. {
  186.     void onWrite(BLECharacteristic *pCharacteristic)
  187.     {
  188.         // Data received from BLE client on RX characteristic using native ESP32 BLE API
  189.         // Properly convert String/value to std::string type for Bluetooth RX data handling
  190.         std::string rxData = std::string(pCharacteristic->getValue().c_str());
  191.        
  192.         if (rxData.length() > 0)
  193.         {
  194.             // Forward to radio station
  195.             for (size_t i = 0; i < rxData.length(); i++)
  196.             {
  197.                 Serial2.write(rxData[i]);
  198.             }
  199.             packetsReceivedRadio++;
  200.            
  201.             // Forward to LoRa if in LoRa mode
  202.             if (!currentMode)
  203.             {
  204.                 sendDataViaLoRa((const uint8_t*)rxData.c_str(), rxData.length());
  205.             }
  206.            
  207.             Serial.print("[BLE->Radio]");
  208.             if (!currentMode) Serial.print("+[LoRa]");
  209.             Serial.print(" ");
  210.             Serial.print(rxData.length());
  211.             Serial.println(" bytes");
  212.         }
  213.     }
  214. };
  215.  
  216. /****** OLED DISPLAY FUNCTIONS *****/
  217. /**
  218.  * initializeDisplay() - Initialize OLED display via I2C with detailed logging
  219.  *
  220.  * Sets up the SSD1306 OLED display connected via I2C (GPIO21=SDA, GPIO22=SCL).
  221.  * Logs all initialization steps and errors. Continues execution even if display fails.
  222.  */
  223. void initializeDisplay(void)
  224. {
  225.     Serial.println("\n[DISPLAY] Starting initialization sequence...");
  226.     Serial.print("[DISPLAY] I2C pins: SDA=GPIO");
  227.     Serial.print(OLED_SDA_PIN);
  228.     Serial.print(", SCL=GPIO");
  229.     Serial.println(OLED_SCL_PIN);
  230.    
  231.     // Initialize I2C for display
  232.     Serial.println("[DISPLAY] Initializing I2C bus...");
  233.     Wire.begin(OLED_SDA_PIN, OLED_SCL_PIN);
  234.     delay(100);
  235.    
  236.     Serial.print("[DISPLAY] Attempting to connect to display at address 0x");
  237.     Serial.print(SCREEN_ADDRESS, HEX);
  238.     Serial.println("...");
  239.    
  240.     // Initialize SSD1306 OLED display
  241.     if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  242.     {
  243.         Serial.println("[ERROR-DISPLAY] Failed to initialize SSD1306 OLED display!");
  244.         Serial.println("[ERROR-DISPLAY] Possible causes:");
  245.         Serial.println("[ERROR-DISPLAY]   - Display not connected to I2C bus");
  246.         Serial.println("[ERROR-DISPLAY]   - Incorrect I2C address (expected 0x3C)");
  247.         Serial.println("[ERROR-DISPLAY]   - I2C communication issue on GPIO21/GPIO22");
  248.         Serial.println("[ERROR-DISPLAY]   - Display hardware failure");
  249.         Serial.println("[WARNING] Continuing without display - system will operate normally");
  250.         displayAvailable = false;
  251.         displayInitialized = false;
  252.         return;
  253.     }
  254.    
  255.     Serial.println("[DISPLAY] SSD1306 detected successfully!");
  256.    
  257.     // Configure display settings
  258.     Serial.println("[DISPLAY] Configuring display parameters...");
  259.     display.clearDisplay();
  260.     display.setTextSize(1);
  261.     display.setTextColor(SSD1306_WHITE);
  262.     display.setRotation(0);
  263.    
  264.     // Show initialization message
  265.     display.setCursor(0, 0);
  266.     display.println("Initializing...");
  267.     display.display();
  268.    
  269.     displayAvailable = true;
  270.     displayInitialized = true;
  271.    
  272.     Serial.println("[DISPLAY] Display initialized successfully!");
  273.     Serial.println("[DISPLAY]   Screen: 128x64 pixels");
  274.     Serial.println("[DISPLAY]   Driver: SSD1306");
  275.     Serial.println("[DISPLAY]   Bus: I2C");
  276.     Serial.println("[DISPLAY] Display ready for output");
  277.    
  278.     delay(500);
  279. }
  280.  
  281. /**
  282.  * generateRandomSuffix() - Generate a random 4-digit suffix for Bluetooth device name
  283.  *
  284.  * Creates a random 4-digit number and appends it to the Bluetooth device name base.
  285.  * This ensures unique device names across multiple devices.
  286.  */
  287. void generateRandomSuffix(void)
  288. {
  289.     // Generate random 4-digit suffix (1000-9999)
  290.     uint16_t randomSuffix = random(1000, 10000);
  291.     sprintf(bluetoothDeviceName, "%s-%04d", BLUETOOTH_DEVICE_NAME_BASE, randomSuffix);
  292.    
  293.     Serial.print("[BLE] Generated device name: ");
  294.     Serial.println(bluetoothDeviceName);
  295. }
  296.  
  297. /**
  298.  * displayBluetoothMode() - Display Bluetooth mode on 3-line OLED screen
  299.  *
  300.  * Line 1: BLUETOOTH
  301.  * Line 2: Device name (DMR-Radio-XXXX)
  302.  * Line 3: Status (CONNECTED or WAITING)
  303.  */
  304. void displayBluetoothMode(void)
  305. {
  306.     // Skip display update if display not available
  307.     if (!displayAvailable || !displayInitialized)
  308.     {
  309.         return;
  310.     }
  311.    
  312.     // Clear and prepare display
  313.     display.clearDisplay();
  314.     display.setTextSize(2);
  315.     display.setTextColor(SSD1306_WHITE);
  316.     display.setCursor(0, 0);
  317.    
  318.     // Line 1: Mode
  319.     display.println("BLUETOOTH");
  320.    
  321.     // Line 2: Device name
  322.     display.setTextSize(1);
  323.     display.println(bluetoothDeviceName);
  324.    
  325.     // Line 3: Status
  326.     if (bleConnected)
  327.     {
  328.         display.println("CONNECTED");
  329.     }
  330.     else
  331.     {
  332.         display.println("WAITING");
  333.     }
  334.    
  335.     // Update physical display
  336.     display.display();
  337. }
  338.  
  339. /**
  340.  * displayLoRaMode() - Display LoRa mode on 3-line OLED screen
  341.  *
  342.  * Line 1: LORA
  343.  * Line 2: 433MHz
  344.  * Line 3: Status (CONNECTED or WAITING)
  345.  */
  346. void displayLoRaMode(void)
  347. {
  348.     // Skip display update if display not available
  349.     if (!displayAvailable || !displayInitialized)
  350.     {
  351.         return;
  352.     }
  353.    
  354.     // Clear and prepare display
  355.     display.clearDisplay();
  356.     display.setTextSize(2);
  357.     display.setTextColor(SSD1306_WHITE);
  358.     display.setCursor(0, 0);
  359.    
  360.     // Line 1: Mode
  361.     display.println("LORA");
  362.    
  363.     // Line 2: Frequency
  364.     display.setTextSize(1);
  365.     display.println("433MHz");
  366.    
  367.     // Line 3: Status (LoRa is always "listening" when in LoRa mode)
  368.     display.println("WAITING");
  369.    
  370.     // Update physical display
  371.     display.display();
  372. }
  373.  
  374. /**
  375.  * updateDisplay() - Update display based on current mode
  376.  *
  377.  * Periodically refreshes the OLED display with current mode information.
  378.  * Called from main loop at regular intervals (DISPLAY_UPDATE_INTERVAL).
  379.  */
  380. void updateDisplay(void)
  381. {
  382.     unsigned long currentTime = millis();
  383.    
  384.     // Update display at defined interval
  385.     if ((currentTime - lastDisplayUpdate) >= DISPLAY_UPDATE_INTERVAL)
  386.     {
  387.         lastDisplayUpdate = currentTime;
  388.        
  389.         // Display mode-specific information
  390.         if (currentMode)
  391.         {
  392.             // Bluetooth mode
  393.             displayBluetoothMode();
  394.         }
  395.         else
  396.         {
  397.             // LoRa mode
  398.             displayLoRaMode();
  399.         }
  400.     }
  401. }
  402.  
  403. /****** LORA FUNCTIONS *****/
  404. /**
  405.  * initializeLoRa() - Initialize LoRa SX1262 module with detailed logging
  406.  *
  407.  * Configures SPI pins, initializes LoRa library, and sets up parameters
  408.  * for 433 MHz operation with SF8 spreading factor and 250 kHz bandwidth.
  409.  * Logs all initialization steps and errors.
  410.  */
  411. void initializeLoRa(void)
  412. {
  413.     Serial.println("\n[LORA] Starting LoRa SX1262 initialization...");
  414.     Serial.println("[LORA] Configuring SPI pins:");
  415.     Serial.print("[LORA]   SCK=GPIO");
  416.     Serial.print(LORA_SCK_PIN);
  417.     Serial.print(", MISO=GPIO");
  418.     Serial.print(LORA_MISO_PIN);
  419.     Serial.print(", MOSI=GPIO");
  420.     Serial.println(LORA_MOSI_PIN);
  421.    
  422.     // Configure SPI pins for LoRa module
  423.     SPI.begin(LORA_SCK_PIN, LORA_MISO_PIN, LORA_MOSI_PIN, LORA_CS_PIN);
  424.     delay(100);
  425.     Serial.println("[LORA] SPI bus initialized");
  426.    
  427.     // Initialize LoRa with appropriate pins for SX1262
  428.     Serial.println("[LORA] Configuring control pins:");
  429.     Serial.print("[LORA]   CS=GPIO");
  430.     Serial.print(LORA_CS_PIN);
  431.     Serial.print(", RST=GPIO");
  432.     Serial.print(LORA_RST_PIN);
  433.     Serial.print(", IRQ=GPIO");
  434.     Serial.println(LORA_IRQ_PIN);
  435.    
  436.     LoRa.setPins(LORA_CS_PIN, LORA_RST_PIN, LORA_IRQ_PIN);
  437.     LoRa.setSPI(SPI);
  438.    
  439.     // Begin LoRa with 433 MHz frequency
  440.     Serial.print("[LORA] Attempting to initialize LoRa module at ");
  441.     Serial.print(LORA_FREQUENCY / 1000000);
  442.     Serial.println(" MHz...");
  443.    
  444.     if (!LoRa.begin(LORA_FREQUENCY))
  445.     {
  446.         Serial.println("[ERROR-LORA] Failed to initialize LoRa module!");
  447.         Serial.println("[ERROR-LORA] Possible causes:");
  448.         Serial.println("[ERROR-LORA]   - SX1262 module not connected");
  449.         Serial.println("[ERROR-LORA]   - Incorrect pin configuration");
  450.         Serial.println("[ERROR-LORA]   - SPI communication failure");
  451.         Serial.println("[ERROR-LORA]   - Module hardware issue");
  452.         Serial.println("[WARNING] LoRa mode unavailable - Bluetooth mode will remain active");
  453.        
  454.         // Display error on OLED if available
  455.         if (displayAvailable)
  456.         {
  457.             display.clearDisplay();
  458.             display.setTextSize(1);
  459.             display.setTextColor(SSD1306_WHITE);
  460.             display.setCursor(0, 0);
  461.             display.println("[ERROR]");
  462.             display.println("LoRa Init Failed");
  463.             display.println("Check pins");
  464.             display.display();
  465.         }
  466.         return;
  467.     }
  468.    
  469.     Serial.println("[LORA] LoRa module detected!");
  470.    
  471.     // Configure LoRa parameters
  472.     Serial.println("[LORA] Configuring LoRa parameters:");
  473.    
  474.     LoRa.setSpreadingFactor(LORA_SPREADING_FACTOR);
  475.     Serial.print("[LORA]   Spreading Factor: SF");
  476.     Serial.println(LORA_SPREADING_FACTOR);
  477.    
  478.     LoRa.setSignalBandwidth(LORA_BANDWIDTH);
  479.     Serial.print("[LORA]   Bandwidth: ");
  480.     Serial.print(LORA_BANDWIDTH / 1000);
  481.     Serial.println(" kHz");
  482.    
  483.     LoRa.setCodingRate4(LORA_CODING_RATE);
  484.     Serial.print("[LORA]   Coding Rate: 4/");
  485.     Serial.println(LORA_CODING_RATE);
  486.    
  487.     LoRa.setPreambleLength(LORA_PREAMBLE_LENGTH);
  488.     Serial.print("[LORA]   Preamble Length: ");
  489.     Serial.println(LORA_PREAMBLE_LENGTH);
  490.    
  491.     LoRa.setSyncWord(LORA_SYNC_WORD);
  492.     Serial.print("[LORA]   Sync Word: 0x");
  493.     Serial.println(LORA_SYNC_WORD, HEX);
  494.    
  495.     LoRa.enableCrc();
  496.     Serial.println("[LORA]   CRC: Enabled");
  497.    
  498.     // Set receiver gain
  499.     LoRa.setGain(6);
  500.     Serial.println("[LORA]   Gain: 6");
  501.    
  502.     // Register callback for incoming packets
  503.     LoRa.onReceive(loraOnReceive);
  504.     Serial.println("[LORA] Packet reception callback registered");
  505.    
  506.     // Start receiving
  507.     LoRa.receive();
  508.     Serial.println("[LORA] Receiver mode activated - listening for packets");
  509.    
  510.     Serial.println("[LORA] LoRa SX1262 initialized successfully!");
  511. }
  512.  
  513. /**
  514.  * loraOnReceive() - LoRa interrupt callback for packet reception
  515.  *
  516.  * Called when LoRa module detects an incoming packet. Reads packet data
  517.  * into buffer and sets flag for main loop processing.
  518.  *
  519.  * @param packetSize - Number of bytes in the received packet
  520.  */
  521. void loraOnReceive(int packetSize)
  522. {
  523.     if (packetSize <= 0) return;
  524.    
  525.     // Limit packet size to buffer capacity
  526.     if (packetSize > LORA_RX_BUFFER_SIZE)
  527.     {
  528.         Serial.print("[LORA-RX] Packet size ");
  529.         Serial.print(packetSize);
  530.         Serial.println(" exceeds buffer - truncating");
  531.         packetSize = LORA_RX_BUFFER_SIZE;
  532.     }
  533.    
  534.     // Read packet into buffer
  535.     loraRxLength = 0;
  536.     while (LoRa.available() && loraRxLength < packetSize)
  537.     {
  538.         loraRxBuffer[loraRxLength++] = LoRa.read();
  539.     }
  540.    
  541.     // Set flag to indicate packet received
  542.     loraPacketReceived = true;
  543.     packetsReceivedLoRa++;
  544.    
  545.     Serial.print("[LORA-RX] Packet received: ");
  546.     Serial.print(loraRxLength);
  547.     Serial.println(" bytes");
  548.    
  549.     // Resume receiving
  550.     LoRa.receive();
  551. }
  552.  
  553. /**
  554.  * sendDataViaLoRa() - Transmit data via LoRa with error checking
  555.  *
  556.  * Sends a buffer of data through the LoRa SX1262 module. Includes error
  557.  * handling and transmission status feedback. Logs success and failure.
  558.  *
  559.  * @param data - Pointer to data buffer to send
  560.  * @param length - Number of bytes to send
  561.  */
  562. void sendDataViaLoRa(const uint8_t* data, size_t length)
  563. {
  564.     if (data == NULL || length == 0)
  565.     {
  566.         Serial.println("[ERROR-LORA-TX] Invalid data (NULL or zero length)");
  567.         return;
  568.     }
  569.    
  570.     if (length > LORA_RX_BUFFER_SIZE)
  571.     {
  572.         Serial.print("[ERROR-LORA-TX] Data too large: ");
  573.         Serial.print(length);
  574.         Serial.println(" bytes");
  575.         return;
  576.     }
  577.    
  578.     // Begin LoRa packet transmission
  579.     LoRa.beginPacket();
  580.    
  581.     // Write data to packet
  582.     LoRa.write(data, length);
  583.    
  584.     // End packet and wait for transmission
  585.     if (LoRa.endPacket(true)) // true = wait for transmission
  586.     {
  587.         packetsSentLoRa++;
  588.         Serial.print("[LORA-TX] Success: ");
  589.         Serial.print(length);
  590.         Serial.println(" bytes sent");
  591.     }
  592.     else
  593.     {
  594.         Serial.println("[ERROR-LORA-TX] Transmission failed");
  595.     }
  596.    
  597.     // Resume receiving after transmission
  598.     LoRa.receive();
  599. }
  600.  
  601. /**
  602.  * handleLoRaReceive() - Process received LoRa packets
  603.  *
  604.  * Checks if a LoRa packet was received, and forwards it to both
  605.  * the radio station (Serial2) and BLE client (if connected).
  606.  */
  607. void handleLoRaReceive(void)
  608. {
  609.     // Check if a LoRa packet was received
  610.     if (!loraPacketReceived) return;
  611.    
  612.     loraPacketReceived = false;
  613.    
  614.     // Forward LoRa data to radio station via Serial2
  615.     for (int i = 0; i < loraRxLength; i++)
  616.     {
  617.         Serial2.write(loraRxBuffer[i]);
  618.     }
  619.     packetsReceivedRadio++;
  620.    
  621.     // Forward LoRa data to BLE client if connected using native ESP32 BLE API
  622.     if (bleConnected && pCharacteristicTX != NULL)
  623.     {
  624.         pCharacteristicTX->setValue(loraRxBuffer, loraRxLength);
  625.         pCharacteristicTX->notify();
  626.         packetsReceivedBluetooth++;
  627.         Serial.print("[LORA->Radio+BLE] ");
  628.     }
  629.     else
  630.     {
  631.         Serial.print("[LORA->Radio] ");
  632.     }
  633.    
  634.     Serial.print(loraRxLength);
  635.     Serial.println(" bytes");
  636. }
  637.  
  638. /****** BLE FUNCTIONS *****/
  639. /**
  640.  * initializeBLE() - Initialize Bluetooth Low Energy (BLE) service with detailed logging
  641.  *
  642.  * Sets up BLE server with service and characteristics for data exchange.
  643.  * Uses native ESP32 BLE API compatible with this board architecture.
  644.  * Implements PIN code 8800 for Bluetooth security. Logs all initialization steps.
  645.  */
  646. void initializeBLE(void)
  647. {
  648.     Serial.println("\n[BLE] Starting BLE initialization...");
  649.    
  650.     // Generate random suffix for device name
  651.     generateRandomSuffix();
  652.    
  653.     // Initialize BLE device with device name
  654.     Serial.print("[BLE] Initializing BLE device as: ");
  655.     Serial.println(bluetoothDeviceName);
  656.     BLEDevice::init(bluetoothDeviceName);
  657.     delay(100);
  658.     Serial.println("[BLE] BLE device initialized");
  659.    
  660.     // Set PIN code for security (System Requirement 1: PIN 8800)
  661.     Serial.println("[BLE] Setting security - PIN code: 8800");
  662.     BLEDevice::setSecurityCallbacks(NULL);
  663.    
  664.     // Create BLE server
  665.     Serial.println("[BLE] Creating BLE server...");
  666.     pServer = BLEDevice::createServer();
  667.     pServer->setCallbacks(new MyServerCallbacks());
  668.     Serial.println("[BLE] BLE server created");
  669.    
  670.     // Create BLE Service
  671.     Serial.print("[BLE] Creating service UUID: ");
  672.     Serial.println(SERVICE_UUID);
  673.     BLEService *pService = pServer->createService(SERVICE_UUID);
  674.    
  675.     // Create BLE Characteristics for RX (receive from client) and TX (send to client)
  676.     // Using native ESP32 BLE API with proper property flags
  677.     Serial.println("[BLE] Creating characteristics...");
  678.     Serial.print("[BLE]   RX characteristic (WRITE): ");
  679.     Serial.println(CHARACTERISTIC_RX_UUID);
  680.    
  681.     pCharacteristicRX = pService->createCharacteristic(
  682.         CHARACTERISTIC_RX_UUID,
  683.         BLECharacteristic::PROPERTY_WRITE
  684.     );
  685.     pCharacteristicRX->setCallbacks(new MyCharacteristicCallbacks());
  686.     Serial.println("[BLE]     RX characteristic created");
  687.    
  688.     Serial.print("[BLE]   TX characteristic (NOTIFY|READ): ");
  689.     Serial.println(CHARACTERISTIC_TX_UUID);
  690.    
  691.     pCharacteristicTX = pService->createCharacteristic(
  692.         CHARACTERISTIC_TX_UUID,
  693.         BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ
  694.     );
  695.     Serial.println("[BLE]     TX characteristic created");
  696.    
  697.     // Add CCCD descriptor for notify property (required for notifications)
  698.     pCharacteristicTX->addDescriptor(new BLE2902());
  699.     Serial.println("[BLE]   CCCD descriptor added for notifications");
  700.    
  701.     // Start the service
  702.     pService->start();
  703.     Serial.println("[BLE] Service started");
  704.    
  705.     // Start advertising
  706.     Serial.println("[BLE] Starting advertising...");
  707.     BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  708.     pAdvertising->addServiceUUID(SERVICE_UUID);
  709.     pAdvertising->setScanResponse(false);
  710.     pAdvertising->setMinPreferred(0x0);
  711.     BLEDevice::startAdvertising();
  712.     Serial.println("[BLE] Advertising started");
  713.    
  714.     Serial.println("\n[BLE] ========== BLE INITIALIZATION COMPLETE ==========");
  715.     Serial.print("[BLE] Device Name: ");
  716.     Serial.println(bluetoothDeviceName);
  717.     Serial.println("[BLE] PIN Code: 8800");
  718.     Serial.println("[BLE] Status: WAITING for client connections");
  719.     Serial.println("[BLE] ===================================================\n");
  720. }
  721.  
  722. /**
  723.  * sendDataToBLE() - Send data to BLE client
  724.  *
  725.  * Transmits data to connected BLE client via notify characteristic.
  726.  * Uses native ESP32 BLE API compatible with this board.
  727.  *
  728.  * @param data - Pointer to data buffer
  729.  * @param length - Number of bytes to send
  730.  */
  731. void sendDataToBLE(const uint8_t* data, size_t length)
  732. {
  733.     if (data == NULL || length == 0) return;
  734.    
  735.     // Only send if client is connected
  736.     if (bleConnected && pCharacteristicTX != NULL)
  737.     {
  738.         // Use setValue and notify for native ESP32 BLE compatibility
  739.         pCharacteristicTX->setValue((uint8_t*)data, length);
  740.         pCharacteristicTX->notify();
  741.         packetsSentBluetooth++;
  742.     }
  743. }
  744.  
  745. /**
  746.  * handleBLEFromClient() - Process data from BLE client (handled in callback)
  747.  *
  748.  * This function is called periodically to check connection status.
  749.  * Actual data handling is done in MyCharacteristicCallbacks::onWrite().
  750.  */
  751. void handleBLEFromClient(void)
  752. {
  753.     // Connection status already updated in MyServerCallbacks
  754.     // Data handling done in MyCharacteristicCallbacks::onWrite()
  755.    
  756.     // Check for disconnection and handle reconnection
  757.     if (!bleConnected && oldBleConnected)
  758.     {
  759.         delay(500);
  760.         pServer->startAdvertising();
  761.         Serial.println("[BLE] Client disconnected - restarting advertising");
  762.     }
  763.     oldBleConnected = bleConnected;
  764. }
  765.  
  766. /****** BUTTON FUNCTIONS *****/
  767. /**
  768.  * checkButtonInput() - Monitor GPIO0 button for long press (mode toggle)
  769.  *
  770.  * Detects 7-second long press on GPIO0 to toggle between Bluetooth and LoRa modes.
  771.  * Includes debounce logic to prevent false triggers. Logs all button events.
  772.  */
  773. void checkButtonInput(void)
  774. {
  775.     unsigned long currentTime = millis();
  776.    
  777.     // Debounce check
  778.     if ((currentTime - lastButtonCheckTime) < BUTTON_DEBOUNCE_TIME) return;
  779.     lastButtonCheckTime = currentTime;
  780.    
  781.     // Read current button state (active LOW on GPIO0)
  782.     bool currentButtonState = digitalRead(GPIO0_BUTTON_PIN);
  783.    
  784.     // Detect button press (transition from HIGH to LOW)
  785.     if (previousButtonState == HIGH && currentButtonState == LOW)
  786.     {
  787.         buttonPressed = true;
  788.         buttonPressStartTime = currentTime;
  789.         Serial.println("[BUTTON] Pressed (GPIO0) - waiting for long press (7s)...");
  790.     }
  791.    
  792.     // Detect button release (transition from LOW to HIGH)
  793.     if (previousButtonState == LOW && currentButtonState == HIGH)
  794.     {
  795.         if (buttonPressed)
  796.         {
  797.             unsigned long pressDuration = currentTime - buttonPressStartTime;
  798.            
  799.             // Check for long press (>= 7 seconds)
  800.             if (pressDuration >= BUTTON_LONG_PRESS_TIME)
  801.             {
  802.                 if (!buttonLongPressDetected)
  803.                 {
  804.                     buttonLongPressDetected = true;
  805.                     Serial.print("[BUTTON] Long press detected (");
  806.                     Serial.print(pressDuration);
  807.                     Serial.println(" ms) - toggling mode");
  808.                     toggleMode();
  809.                 }
  810.             }
  811.             else
  812.             {
  813.                 Serial.print("[BUTTON] Short press (");
  814.                 Serial.print(pressDuration);
  815.                 Serial.println(" ms) - ignored");
  816.             }
  817.            
  818.             buttonPressed = false;
  819.             buttonLongPressDetected = false;
  820.         }
  821.     }
  822.    
  823.     previousButtonState = currentButtonState;
  824. }
  825.  
  826. /**
  827.  * toggleMode() - Toggle between Bluetooth and LoRa modes
  828.  *
  829.  * Switches active communication mode between BLE and LoRa SX1262.
  830.  * Updates mode indicator, reinitializes relevant peripherals, and logs transition.
  831.  */
  832. void toggleMode(void)
  833. {
  834.     currentMode = !currentMode;
  835.    
  836.     Serial.println("\n==================== MODE TOGGLE ====================");
  837.     Serial.print("New Mode: ");
  838.     Serial.println(currentMode ? "BLUETOOTH" : "LORA");
  839.    
  840.     if (currentMode)
  841.     {
  842.         // Switched to Bluetooth mode
  843.         Serial.println("Status: BLE mode active - ready for client connections");
  844.         Serial.println("Waiting for BLE client to connect...");
  845.        
  846.         // Resume LoRa receiver if switching away from it
  847.         LoRa.receive();
  848.     }
  849.     else
  850.     {
  851.         // Switched to LoRa mode
  852.         Serial.println("Status: LoRa mode active");
  853.         Serial.println("Configuration: 433MHz SF8 250kHz");
  854.         Serial.println("Listening for LoRa packets...");
  855.        
  856.         // Ensure LoRa is initialized and receiving
  857.         LoRa.receive();
  858.     }
  859.    
  860.     Serial.println("=====================================================\n");
  861.    
  862.     // Update display immediately
  863.     lastDisplayUpdate = 0;
  864.     updateDisplay();
  865. }
  866.  
  867. /****** RADIO SERIAL FUNCTIONS *****/
  868. /**
  869.  * sendDataToRadio() - Send data to radio station via Serial2
  870.  *
  871.  * Transmits data to the connected radio station on GPIO47/48 at 115200 baud.
  872.  *
  873.  * @param data - Pointer to data buffer
  874.  * @param length - Number of bytes to send
  875.  */
  876. void sendDataToRadio(const uint8_t* data, size_t length)
  877. {
  878.     if (data == NULL || length == 0) return;
  879.    
  880.     for (size_t i = 0; i < length; i++)
  881.     {
  882.         Serial2.write(data[i]);
  883.     }
  884.     packetsSentRadio++;
  885. }
  886.  
  887. /**
  888.  * handleSerialFromRadio() - Process data from radio station
  889.  *
  890.  * Reads incoming data from radio station (Serial2) and forwards it to:
  891.  * - BLE client (if connected and in Bluetooth mode)
  892.  * - LoRa module (if in LoRa mode)
  893.  * Logs all data flow for debugging.
  894.  */
  895. void handleSerialFromRadio(void)
  896. {
  897.     // Check if data is available from radio station on Serial2
  898.     while (Serial2.available() > 0)
  899.     {
  900.         uint8_t byteRadio = Serial2.read();
  901.         packetsReceivedRadio++;
  902.        
  903.         // Forward to active channel based on current mode
  904.         if (currentMode)
  905.         {
  906.             // Bluetooth mode: forward to BLE client using native ESP32 BLE API
  907.             if (bleConnected && pCharacteristicTX != NULL)
  908.             {
  909.                 uint8_t data[1] = {byteRadio};
  910.                 pCharacteristicTX->setValue(data, 1);
  911.                 pCharacteristicTX->notify();
  912.                 packetsSentBluetooth++;
  913.                 Serial.print("[Radio->BLE] ");
  914.             }
  915.             else
  916.             {
  917.                 Serial.print("[Radio->Queue] ");
  918.             }
  919.         }
  920.         else
  921.         {
  922.             // LoRa mode: accumulate for LoRa transmission
  923.             // For simplicity, send single bytes (can be optimized with buffering)
  924.             uint8_t loraPacket[1] = {byteRadio};
  925.             sendDataViaLoRa(loraPacket, 1);
  926.             Serial.print("[Radio->LoRa] ");
  927.         }
  928.        
  929.         Serial.print("0x");
  930.         Serial.println(byteRadio, HEX);
  931.     }
  932. }
  933.  
  934. /****** SETUP FUNCTION *****/
  935. /**
  936.  * setup() - Initialize all peripherals and subsystems
  937.  *
  938.  * Performs complete initialization of:
  939.  * - Serial communication (USB debug)
  940.  * - OLED display via I2C with detailed logging
  941.  * - GPIO0 button
  942.  * - Serial2 for radio station communication
  943.  * - BLE (using native ESP32 BLE library from board package)
  944.  * - LoRa SX1262 module with detailed logging
  945.  *
  946.  * Logs all initialization steps. Continues execution even if individual
  947.  * subsystems fail (e.g., display or LoRa).
  948.  */
  949. void setup(void)
  950. {
  951.     // Initialize USB serial for debug output
  952.     Serial.begin(115200);
  953.     delay(1000);
  954.    
  955.     Serial.println("\n\n");
  956.     Serial.println("╔════════════════════════════════════════════════════╗");
  957.     Serial.println("║    ESP32-S3 WIRELESS BRIDGE - INITIALIZATION      ║");
  958.     Serial.println("║         LoRa SX1262 + BLE + Radio Station         ║");
  959.     Serial.println("╚════════════════════════════════════════════════════╝");
  960.     Serial.println();
  961.     Serial.println("[SYSTEM] Processor: ESP32-S3 Dev Module");
  962.     Serial.println("[SYSTEM] Subsystems: LoRa (433MHz), BLE, Serial2 Radio, GPIO0 Mode Toggle");
  963.     Serial.println();
  964.    
  965.     // Initialize OLED display via I2C (with error tolerance)
  966.     initializeDisplay();
  967.    
  968.     // Configure GPIO0 as input (button)
  969.     Serial.println("[GPIO] Configuring GPIO0 button (INPUT_PULLUP)");
  970.     pinMode(GPIO0_BUTTON_PIN, INPUT_PULLUP);
  971.     Serial.println("[GPIO] GPIO0 button ready - 7 second long press to toggle mode");
  972.    
  973.     // Initialize Serial2 for radio station communication (GPIO47=RX, GPIO48=TX)
  974.     Serial.println();
  975.     Serial.println("[SERIAL2] Initializing radio station communication...");
  976.     Serial2.begin(SERIAL2_BAUDRATE, SERIAL_8N1, SERIAL2_RX_PIN, SERIAL2_TX_PIN);
  977.     Serial.println("[SERIAL2] Configured successfully:");
  978.     Serial.print("[SERIAL2]   RX Pin: GPIO");
  979.     Serial.print(SERIAL2_RX_PIN);
  980.     Serial.print(", TX Pin: GPIO");
  981.     Serial.print(SERIAL2_TX_PIN);
  982.     Serial.print(", Baud: ");
  983.     Serial.println(SERIAL2_BAUDRATE);
  984.    
  985.     // Initialize BLE (native ESP32 BLE library from board package)
  986.     initializeBLE();
  987.    
  988.     // Initialize LoRa SX1262
  989.     initializeLoRa();
  990.    
  991.     Serial.println();
  992.     Serial.println("╔════════════════════════════════════════════════════╗");
  993.     Serial.println("║          INITIALIZATION COMPLETE - READY           ║");
  994.     Serial.println("╚════════════════════════════════════════════════════╝");
  995.     Serial.println();
  996.     Serial.println("[STATUS] Starting in Bluetooth mode");
  997.     Serial.println("[STATUS] Current mode: BLUETOOTH");
  998.     Serial.println("[STATUS] BLE status: WAITING for client");
  999.     Serial.println("[STATUS] LoRa status: Available (press GPIO0 7s to switch)");
  1000.     Serial.println("[STATUS] Display status: " + String(displayAvailable ? "ACTIVE" : "OFFLINE"));
  1001.     Serial.println();
  1002.    
  1003.     // Initial display update
  1004.     lastDisplayUpdate = 0;
  1005.     updateDisplay();
  1006. }
  1007.  
  1008. /****** MAIN LOOP FUNCTION *****/
  1009. /**
  1010.  * loop() - Main processing loop
  1011.  *
  1012.  * Continuously processes:
  1013.  * - GPIO0 button input for mode toggle
  1014.  * - Radio station data (Serial2)
  1015.  * - BLE client data
  1016.  * - LoRa received packets
  1017.  * - Display updates
  1018.  *
  1019.  * Implements bidirectional data flow between radio, BLE, and LoRa.
  1020.  */
  1021. void loop(void)
  1022. {
  1023.     // Monitor GPIO0 button for 7-second long press (mode toggle)
  1024.     checkButtonInput();
  1025.    
  1026.     // Process radio station data (forward to active channel)
  1027.     handleSerialFromRadio();
  1028.    
  1029.     // Process BLE client data and connection status
  1030.     handleBLEFromClient();
  1031.    
  1032.     // Process LoRa received packets (forward to radio and BLE)
  1033.     handleLoRaReceive();
  1034.    
  1035.     // Update display with current mode and status
  1036.     updateDisplay();
  1037.    
  1038.     // Small delay to prevent overwhelming processor
  1039.     delay(10);
  1040. }
  1041.  
  1042. /* END CODE */
  1043.  
Advertisement
Add Comment
Please, Sign In to add comment