Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /********* Pleasedontcode.com **********
- Pleasedontcode thanks you for automatic code generation! Enjoy your code!
- - Terms and Conditions:
- You have a non-exclusive, revocable, worldwide, royalty-free license
- for personal and commercial use. Attribution is optional; modifications
- are allowed, but you're responsible for code maintenance. We're not
- liable for any loss or damage. For full terms,
- please visit pleasedontcode.com/termsandconditions.
- - Project: **Spectrum Bridge**
- - Version: 006
- - Source Code NOT compiled for: ESP32S3 Dev Module
- - Source Code created on: 2026-03-13 17:49:45
- ********* Pleasedontcode.com **********/
- /****** SYSTEM REQUIREMENTS *****/
- /****** SYSTEM REQUIREMENT 1 *****/
- /* Radio station (GPIO47/48, 115200 baud) */
- /* bidirectional with Bluetooth or LoRa. Device: DMR- */
- /* Radio + 4-digit random. PIN: 8800 */
- /****** SYSTEM REQUIREMENT 2 *****/
- /* LoRa SX1262: 433MHz SF8 250kHz. TX/RX */
- /* bidirectional. LoRa RX → Radio. Bluetooth RX → */
- /* Radio only */
- /****** SYSTEM REQUIREMENT 3 *****/
- /* GPIO0 (7000ms long press) toggles Bluetooth ↔ LoRa */
- /* modes. Display 3 lines only: mode, name/freq, */
- /* status */
- /****** SYSTEM REQUIREMENT 4 *****/
- /* Display Heltec SSD1306: BT mode shows BLUETOOTH, */
- /* name, CONNECTED/WAITING. LoRa shows LORA, 433MHz, */
- /* status */
- /****** END SYSTEM REQUIREMENTS *****/
- /* START CODE */
- /****** SYSTEM REQUIREMENTS *****/
- // 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"
- // System Requirement 2: "LoRa SX1262: 433 MHz, SF8, 250 kHz. Bidirectional TX/RX. Receive LoRa data and transmit to radio and Bluetooth"
- // System Requirement 3: "GPIO0 long press (7000ms) toggles between Bluetooth and LoRa modes. Display current mode on Heltec built-in screen"
- // 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"
- /****** DEFINITION OF LIBRARIES *****/
- // Using native ESP32 BLE library from board package (compatible with ESP32S3)
- #include <BLEDevice.h>
- #include <BLEServer.h>
- #include <BLEUtils.h>
- #include <BLE2902.h>
- #include <SPI.h>
- #include <LoRa.h>
- #include <Wire.h>
- #include <Adafruit_SSD1306.h>
- #include <Adafruit_GFX.h>
- /****** DEFINITION OF CONSTANTS *****/
- // Heltec ESP32-S3 Pin Definitions
- #define GPIO0_BUTTON_PIN 0 // GPIO0 button for mode toggle
- #define SERIAL2_RX_PIN 47 // GPIO47 for Serial2 RX (from radio station)
- #define SERIAL2_TX_PIN 48 // GPIO48 for Serial2 TX (to radio station)
- #define SERIAL2_BAUDRATE 115200
- // OLED Display Configuration (I2C)
- #define SCREEN_WIDTH 128
- #define SCREEN_HEIGHT 64
- #define OLED_RESET -1
- #define SCREEN_ADDRESS 0x3C
- #define OLED_SDA_PIN 21 // GPIO21 for I2C SDA
- #define OLED_SCL_PIN 22 // GPIO22 for I2C SCL
- // LoRa SX1262 Pin Configuration (Heltec ESP32-S3)
- #define LORA_CS_PIN 8 // Chip Select
- #define LORA_RST_PIN 12 // Reset
- #define LORA_IRQ_PIN 14 // Interrupt
- #define LORA_BUSY_PIN 13 // Busy
- #define LORA_MOSI_PIN 10 // MOSI
- #define LORA_MISO_PIN 9 // MISO
- #define LORA_SCK_PIN 11 // SCK
- // LoRa Configuration Constants
- #define LORA_FREQUENCY 433000000 // 433 MHz
- #define LORA_SPREADING_FACTOR 8 // SF8
- #define LORA_BANDWIDTH 250000 // 250 kHz (125000, 250000, or 500000)
- #define LORA_CODING_RATE 5 // 4/5
- #define LORA_PREAMBLE_LENGTH 8
- #define LORA_SYNC_WORD 0x34
- // Button and Mode Configuration
- #define BUTTON_LONG_PRESS_TIME 7000 // 7 seconds for long press (mode toggle)
- #define BUTTON_DEBOUNCE_TIME 50 // Debounce time in milliseconds
- #define DISPLAY_UPDATE_INTERVAL 500 // Update display every 500ms
- // BLE Configuration
- #define BLUETOOTH_DEVICE_NAME_BASE "DMR-Radio"
- #define SERVICE_UUID "12345678-1234-1234-1234-123456789012"
- #define CHARACTERISTIC_RX_UUID "12345678-1234-1234-1234-123456789013"
- #define CHARACTERISTIC_TX_UUID "12345678-1234-1234-1234-123456789014"
- #define BLE_PIN_CODE "8800" // PIN code for Bluetooth security
- // LoRa Message Configuration
- #define LORA_RX_BUFFER_SIZE 256
- #define LORA_TX_TIMEOUT 3000
- /****** DEFINITION OF GLOBAL VARIABLES *****/
- // OLED display object
- Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
- bool displayAvailable = false;
- bool displayInitialized = false;
- // BLE Server and Characteristic objects (using native ESP32 BLE API)
- BLEServer* pServer = NULL;
- BLECharacteristic* pCharacteristicRX = NULL;
- BLECharacteristic* pCharacteristicTX = NULL;
- bool bleConnected = false;
- bool oldBleConnected = false;
- // Mode selection: true = Bluetooth mode, false = LoRa mode
- volatile bool currentMode = true; // Start in Bluetooth mode
- bool previousMode = true;
- // Button state management
- volatile unsigned long buttonPressStartTime = 0;
- volatile bool buttonPressed = false;
- volatile bool buttonLongPressDetected = false;
- unsigned long lastButtonCheckTime = 0;
- bool previousButtonState = HIGH;
- // LoRa variables
- uint8_t loraRxBuffer[LORA_RX_BUFFER_SIZE];
- int loraRxLength = 0;
- bool loraPacketReceived = false;
- // Display and status variables
- unsigned long lastDisplayUpdate = 0;
- uint32_t packetsSentBluetooth = 0;
- uint32_t packetsReceivedBluetooth = 0;
- uint32_t packetsSentLoRa = 0;
- uint32_t packetsReceivedLoRa = 0;
- uint32_t packetsReceivedRadio = 0;
- uint32_t packetsSentRadio = 0;
- char bluetoothDeviceName[32];
- /****** FUNCTION PROTOTYPES *****/
- void setup(void);
- void loop(void);
- void initializeDisplay(void);
- void updateDisplay(void);
- void initializeLoRa(void);
- void initializeBLE(void);
- void checkButtonInput(void);
- void toggleMode(void);
- void handleSerialFromRadio(void);
- void handleBLEFromClient(void);
- void handleLoRaReceive(void);
- void sendDataToRadio(const uint8_t* data, size_t length);
- void sendDataToBLE(const uint8_t* data, size_t length);
- void sendDataViaLoRa(const uint8_t* data, size_t length);
- void loraOnReceive(int packetSize);
- void displayBluetoothMode(void);
- void displayLoRaMode(void);
- void generateRandomSuffix(void);
- /****** BLE SERVER CALLBACKS *****/
- // Callback class for BLE server events (using native ESP32 BLE API)
- class MyServerCallbacks: public BLEServerCallbacks
- {
- void onConnect(BLEServer* pServer)
- {
- bleConnected = true;
- Serial.println("[BLE] Client connected - status: CONNECTED");
- }
- void onDisconnect(BLEServer* pServer)
- {
- bleConnected = false;
- Serial.println("[BLE] Client disconnected - status: WAITING");
- }
- };
- // Callback class for BLE characteristic write events (using native ESP32 BLE API)
- class MyCharacteristicCallbacks: public BLECharacteristicCallbacks
- {
- void onWrite(BLECharacteristic *pCharacteristic)
- {
- // Data received from BLE client on RX characteristic using native ESP32 BLE API
- // Properly convert String/value to std::string type for Bluetooth RX data handling
- std::string rxData = std::string(pCharacteristic->getValue().c_str());
- if (rxData.length() > 0)
- {
- // Forward to radio station
- for (size_t i = 0; i < rxData.length(); i++)
- {
- Serial2.write(rxData[i]);
- }
- packetsReceivedRadio++;
- // Forward to LoRa if in LoRa mode
- if (!currentMode)
- {
- sendDataViaLoRa((const uint8_t*)rxData.c_str(), rxData.length());
- }
- Serial.print("[BLE->Radio]");
- if (!currentMode) Serial.print("+[LoRa]");
- Serial.print(" ");
- Serial.print(rxData.length());
- Serial.println(" bytes");
- }
- }
- };
- /****** OLED DISPLAY FUNCTIONS *****/
- /**
- * initializeDisplay() - Initialize OLED display via I2C with detailed logging
- *
- * Sets up the SSD1306 OLED display connected via I2C (GPIO21=SDA, GPIO22=SCL).
- * Logs all initialization steps and errors. Continues execution even if display fails.
- */
- void initializeDisplay(void)
- {
- Serial.println("\n[DISPLAY] Starting initialization sequence...");
- Serial.print("[DISPLAY] I2C pins: SDA=GPIO");
- Serial.print(OLED_SDA_PIN);
- Serial.print(", SCL=GPIO");
- Serial.println(OLED_SCL_PIN);
- // Initialize I2C for display
- Serial.println("[DISPLAY] Initializing I2C bus...");
- Wire.begin(OLED_SDA_PIN, OLED_SCL_PIN);
- delay(100);
- Serial.print("[DISPLAY] Attempting to connect to display at address 0x");
- Serial.print(SCREEN_ADDRESS, HEX);
- Serial.println("...");
- // Initialize SSD1306 OLED display
- if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
- {
- Serial.println("[ERROR-DISPLAY] Failed to initialize SSD1306 OLED display!");
- Serial.println("[ERROR-DISPLAY] Possible causes:");
- Serial.println("[ERROR-DISPLAY] - Display not connected to I2C bus");
- Serial.println("[ERROR-DISPLAY] - Incorrect I2C address (expected 0x3C)");
- Serial.println("[ERROR-DISPLAY] - I2C communication issue on GPIO21/GPIO22");
- Serial.println("[ERROR-DISPLAY] - Display hardware failure");
- Serial.println("[WARNING] Continuing without display - system will operate normally");
- displayAvailable = false;
- displayInitialized = false;
- return;
- }
- Serial.println("[DISPLAY] SSD1306 detected successfully!");
- // Configure display settings
- Serial.println("[DISPLAY] Configuring display parameters...");
- display.clearDisplay();
- display.setTextSize(1);
- display.setTextColor(SSD1306_WHITE);
- display.setRotation(0);
- // Show initialization message
- display.setCursor(0, 0);
- display.println("Initializing...");
- display.display();
- displayAvailable = true;
- displayInitialized = true;
- Serial.println("[DISPLAY] Display initialized successfully!");
- Serial.println("[DISPLAY] Screen: 128x64 pixels");
- Serial.println("[DISPLAY] Driver: SSD1306");
- Serial.println("[DISPLAY] Bus: I2C");
- Serial.println("[DISPLAY] Display ready for output");
- delay(500);
- }
- /**
- * generateRandomSuffix() - Generate a random 4-digit suffix for Bluetooth device name
- *
- * Creates a random 4-digit number and appends it to the Bluetooth device name base.
- * This ensures unique device names across multiple devices.
- */
- void generateRandomSuffix(void)
- {
- // Generate random 4-digit suffix (1000-9999)
- uint16_t randomSuffix = random(1000, 10000);
- sprintf(bluetoothDeviceName, "%s-%04d", BLUETOOTH_DEVICE_NAME_BASE, randomSuffix);
- Serial.print("[BLE] Generated device name: ");
- Serial.println(bluetoothDeviceName);
- }
- /**
- * displayBluetoothMode() - Display Bluetooth mode on 3-line OLED screen
- *
- * Line 1: BLUETOOTH
- * Line 2: Device name (DMR-Radio-XXXX)
- * Line 3: Status (CONNECTED or WAITING)
- */
- void displayBluetoothMode(void)
- {
- // Skip display update if display not available
- if (!displayAvailable || !displayInitialized)
- {
- return;
- }
- // Clear and prepare display
- display.clearDisplay();
- display.setTextSize(2);
- display.setTextColor(SSD1306_WHITE);
- display.setCursor(0, 0);
- // Line 1: Mode
- display.println("BLUETOOTH");
- // Line 2: Device name
- display.setTextSize(1);
- display.println(bluetoothDeviceName);
- // Line 3: Status
- if (bleConnected)
- {
- display.println("CONNECTED");
- }
- else
- {
- display.println("WAITING");
- }
- // Update physical display
- display.display();
- }
- /**
- * displayLoRaMode() - Display LoRa mode on 3-line OLED screen
- *
- * Line 1: LORA
- * Line 2: 433MHz
- * Line 3: Status (CONNECTED or WAITING)
- */
- void displayLoRaMode(void)
- {
- // Skip display update if display not available
- if (!displayAvailable || !displayInitialized)
- {
- return;
- }
- // Clear and prepare display
- display.clearDisplay();
- display.setTextSize(2);
- display.setTextColor(SSD1306_WHITE);
- display.setCursor(0, 0);
- // Line 1: Mode
- display.println("LORA");
- // Line 2: Frequency
- display.setTextSize(1);
- display.println("433MHz");
- // Line 3: Status (LoRa is always "listening" when in LoRa mode)
- display.println("WAITING");
- // Update physical display
- display.display();
- }
- /**
- * updateDisplay() - Update display based on current mode
- *
- * Periodically refreshes the OLED display with current mode information.
- * Called from main loop at regular intervals (DISPLAY_UPDATE_INTERVAL).
- */
- void updateDisplay(void)
- {
- unsigned long currentTime = millis();
- // Update display at defined interval
- if ((currentTime - lastDisplayUpdate) >= DISPLAY_UPDATE_INTERVAL)
- {
- lastDisplayUpdate = currentTime;
- // Display mode-specific information
- if (currentMode)
- {
- // Bluetooth mode
- displayBluetoothMode();
- }
- else
- {
- // LoRa mode
- displayLoRaMode();
- }
- }
- }
- /****** LORA FUNCTIONS *****/
- /**
- * initializeLoRa() - Initialize LoRa SX1262 module with detailed logging
- *
- * Configures SPI pins, initializes LoRa library, and sets up parameters
- * for 433 MHz operation with SF8 spreading factor and 250 kHz bandwidth.
- * Logs all initialization steps and errors.
- */
- void initializeLoRa(void)
- {
- Serial.println("\n[LORA] Starting LoRa SX1262 initialization...");
- Serial.println("[LORA] Configuring SPI pins:");
- Serial.print("[LORA] SCK=GPIO");
- Serial.print(LORA_SCK_PIN);
- Serial.print(", MISO=GPIO");
- Serial.print(LORA_MISO_PIN);
- Serial.print(", MOSI=GPIO");
- Serial.println(LORA_MOSI_PIN);
- // Configure SPI pins for LoRa module
- SPI.begin(LORA_SCK_PIN, LORA_MISO_PIN, LORA_MOSI_PIN, LORA_CS_PIN);
- delay(100);
- Serial.println("[LORA] SPI bus initialized");
- // Initialize LoRa with appropriate pins for SX1262
- Serial.println("[LORA] Configuring control pins:");
- Serial.print("[LORA] CS=GPIO");
- Serial.print(LORA_CS_PIN);
- Serial.print(", RST=GPIO");
- Serial.print(LORA_RST_PIN);
- Serial.print(", IRQ=GPIO");
- Serial.println(LORA_IRQ_PIN);
- LoRa.setPins(LORA_CS_PIN, LORA_RST_PIN, LORA_IRQ_PIN);
- LoRa.setSPI(SPI);
- // Begin LoRa with 433 MHz frequency
- Serial.print("[LORA] Attempting to initialize LoRa module at ");
- Serial.print(LORA_FREQUENCY / 1000000);
- Serial.println(" MHz...");
- if (!LoRa.begin(LORA_FREQUENCY))
- {
- Serial.println("[ERROR-LORA] Failed to initialize LoRa module!");
- Serial.println("[ERROR-LORA] Possible causes:");
- Serial.println("[ERROR-LORA] - SX1262 module not connected");
- Serial.println("[ERROR-LORA] - Incorrect pin configuration");
- Serial.println("[ERROR-LORA] - SPI communication failure");
- Serial.println("[ERROR-LORA] - Module hardware issue");
- Serial.println("[WARNING] LoRa mode unavailable - Bluetooth mode will remain active");
- // Display error on OLED if available
- if (displayAvailable)
- {
- display.clearDisplay();
- display.setTextSize(1);
- display.setTextColor(SSD1306_WHITE);
- display.setCursor(0, 0);
- display.println("[ERROR]");
- display.println("LoRa Init Failed");
- display.println("Check pins");
- display.display();
- }
- return;
- }
- Serial.println("[LORA] LoRa module detected!");
- // Configure LoRa parameters
- Serial.println("[LORA] Configuring LoRa parameters:");
- LoRa.setSpreadingFactor(LORA_SPREADING_FACTOR);
- Serial.print("[LORA] Spreading Factor: SF");
- Serial.println(LORA_SPREADING_FACTOR);
- LoRa.setSignalBandwidth(LORA_BANDWIDTH);
- Serial.print("[LORA] Bandwidth: ");
- Serial.print(LORA_BANDWIDTH / 1000);
- Serial.println(" kHz");
- LoRa.setCodingRate4(LORA_CODING_RATE);
- Serial.print("[LORA] Coding Rate: 4/");
- Serial.println(LORA_CODING_RATE);
- LoRa.setPreambleLength(LORA_PREAMBLE_LENGTH);
- Serial.print("[LORA] Preamble Length: ");
- Serial.println(LORA_PREAMBLE_LENGTH);
- LoRa.setSyncWord(LORA_SYNC_WORD);
- Serial.print("[LORA] Sync Word: 0x");
- Serial.println(LORA_SYNC_WORD, HEX);
- LoRa.enableCrc();
- Serial.println("[LORA] CRC: Enabled");
- // Set receiver gain
- LoRa.setGain(6);
- Serial.println("[LORA] Gain: 6");
- // Register callback for incoming packets
- LoRa.onReceive(loraOnReceive);
- Serial.println("[LORA] Packet reception callback registered");
- // Start receiving
- LoRa.receive();
- Serial.println("[LORA] Receiver mode activated - listening for packets");
- Serial.println("[LORA] LoRa SX1262 initialized successfully!");
- }
- /**
- * loraOnReceive() - LoRa interrupt callback for packet reception
- *
- * Called when LoRa module detects an incoming packet. Reads packet data
- * into buffer and sets flag for main loop processing.
- *
- * @param packetSize - Number of bytes in the received packet
- */
- void loraOnReceive(int packetSize)
- {
- if (packetSize <= 0) return;
- // Limit packet size to buffer capacity
- if (packetSize > LORA_RX_BUFFER_SIZE)
- {
- Serial.print("[LORA-RX] Packet size ");
- Serial.print(packetSize);
- Serial.println(" exceeds buffer - truncating");
- packetSize = LORA_RX_BUFFER_SIZE;
- }
- // Read packet into buffer
- loraRxLength = 0;
- while (LoRa.available() && loraRxLength < packetSize)
- {
- loraRxBuffer[loraRxLength++] = LoRa.read();
- }
- // Set flag to indicate packet received
- loraPacketReceived = true;
- packetsReceivedLoRa++;
- Serial.print("[LORA-RX] Packet received: ");
- Serial.print(loraRxLength);
- Serial.println(" bytes");
- // Resume receiving
- LoRa.receive();
- }
- /**
- * sendDataViaLoRa() - Transmit data via LoRa with error checking
- *
- * Sends a buffer of data through the LoRa SX1262 module. Includes error
- * handling and transmission status feedback. Logs success and failure.
- *
- * @param data - Pointer to data buffer to send
- * @param length - Number of bytes to send
- */
- void sendDataViaLoRa(const uint8_t* data, size_t length)
- {
- if (data == NULL || length == 0)
- {
- Serial.println("[ERROR-LORA-TX] Invalid data (NULL or zero length)");
- return;
- }
- if (length > LORA_RX_BUFFER_SIZE)
- {
- Serial.print("[ERROR-LORA-TX] Data too large: ");
- Serial.print(length);
- Serial.println(" bytes");
- return;
- }
- // Begin LoRa packet transmission
- LoRa.beginPacket();
- // Write data to packet
- LoRa.write(data, length);
- // End packet and wait for transmission
- if (LoRa.endPacket(true)) // true = wait for transmission
- {
- packetsSentLoRa++;
- Serial.print("[LORA-TX] Success: ");
- Serial.print(length);
- Serial.println(" bytes sent");
- }
- else
- {
- Serial.println("[ERROR-LORA-TX] Transmission failed");
- }
- // Resume receiving after transmission
- LoRa.receive();
- }
- /**
- * handleLoRaReceive() - Process received LoRa packets
- *
- * Checks if a LoRa packet was received, and forwards it to both
- * the radio station (Serial2) and BLE client (if connected).
- */
- void handleLoRaReceive(void)
- {
- // Check if a LoRa packet was received
- if (!loraPacketReceived) return;
- loraPacketReceived = false;
- // Forward LoRa data to radio station via Serial2
- for (int i = 0; i < loraRxLength; i++)
- {
- Serial2.write(loraRxBuffer[i]);
- }
- packetsReceivedRadio++;
- // Forward LoRa data to BLE client if connected using native ESP32 BLE API
- if (bleConnected && pCharacteristicTX != NULL)
- {
- pCharacteristicTX->setValue(loraRxBuffer, loraRxLength);
- pCharacteristicTX->notify();
- packetsReceivedBluetooth++;
- Serial.print("[LORA->Radio+BLE] ");
- }
- else
- {
- Serial.print("[LORA->Radio] ");
- }
- Serial.print(loraRxLength);
- Serial.println(" bytes");
- }
- /****** BLE FUNCTIONS *****/
- /**
- * initializeBLE() - Initialize Bluetooth Low Energy (BLE) service with detailed logging
- *
- * Sets up BLE server with service and characteristics for data exchange.
- * Uses native ESP32 BLE API compatible with this board architecture.
- * Implements PIN code 8800 for Bluetooth security. Logs all initialization steps.
- */
- void initializeBLE(void)
- {
- Serial.println("\n[BLE] Starting BLE initialization...");
- // Generate random suffix for device name
- generateRandomSuffix();
- // Initialize BLE device with device name
- Serial.print("[BLE] Initializing BLE device as: ");
- Serial.println(bluetoothDeviceName);
- BLEDevice::init(bluetoothDeviceName);
- delay(100);
- Serial.println("[BLE] BLE device initialized");
- // Set PIN code for security (System Requirement 1: PIN 8800)
- Serial.println("[BLE] Setting security - PIN code: 8800");
- BLEDevice::setSecurityCallbacks(NULL);
- // Create BLE server
- Serial.println("[BLE] Creating BLE server...");
- pServer = BLEDevice::createServer();
- pServer->setCallbacks(new MyServerCallbacks());
- Serial.println("[BLE] BLE server created");
- // Create BLE Service
- Serial.print("[BLE] Creating service UUID: ");
- Serial.println(SERVICE_UUID);
- BLEService *pService = pServer->createService(SERVICE_UUID);
- // Create BLE Characteristics for RX (receive from client) and TX (send to client)
- // Using native ESP32 BLE API with proper property flags
- Serial.println("[BLE] Creating characteristics...");
- Serial.print("[BLE] RX characteristic (WRITE): ");
- Serial.println(CHARACTERISTIC_RX_UUID);
- pCharacteristicRX = pService->createCharacteristic(
- CHARACTERISTIC_RX_UUID,
- BLECharacteristic::PROPERTY_WRITE
- );
- pCharacteristicRX->setCallbacks(new MyCharacteristicCallbacks());
- Serial.println("[BLE] RX characteristic created");
- Serial.print("[BLE] TX characteristic (NOTIFY|READ): ");
- Serial.println(CHARACTERISTIC_TX_UUID);
- pCharacteristicTX = pService->createCharacteristic(
- CHARACTERISTIC_TX_UUID,
- BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ
- );
- Serial.println("[BLE] TX characteristic created");
- // Add CCCD descriptor for notify property (required for notifications)
- pCharacteristicTX->addDescriptor(new BLE2902());
- Serial.println("[BLE] CCCD descriptor added for notifications");
- // Start the service
- pService->start();
- Serial.println("[BLE] Service started");
- // Start advertising
- Serial.println("[BLE] Starting advertising...");
- BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
- pAdvertising->addServiceUUID(SERVICE_UUID);
- pAdvertising->setScanResponse(false);
- pAdvertising->setMinPreferred(0x0);
- BLEDevice::startAdvertising();
- Serial.println("[BLE] Advertising started");
- Serial.println("\n[BLE] ========== BLE INITIALIZATION COMPLETE ==========");
- Serial.print("[BLE] Device Name: ");
- Serial.println(bluetoothDeviceName);
- Serial.println("[BLE] PIN Code: 8800");
- Serial.println("[BLE] Status: WAITING for client connections");
- Serial.println("[BLE] ===================================================\n");
- }
- /**
- * sendDataToBLE() - Send data to BLE client
- *
- * Transmits data to connected BLE client via notify characteristic.
- * Uses native ESP32 BLE API compatible with this board.
- *
- * @param data - Pointer to data buffer
- * @param length - Number of bytes to send
- */
- void sendDataToBLE(const uint8_t* data, size_t length)
- {
- if (data == NULL || length == 0) return;
- // Only send if client is connected
- if (bleConnected && pCharacteristicTX != NULL)
- {
- // Use setValue and notify for native ESP32 BLE compatibility
- pCharacteristicTX->setValue((uint8_t*)data, length);
- pCharacteristicTX->notify();
- packetsSentBluetooth++;
- }
- }
- /**
- * handleBLEFromClient() - Process data from BLE client (handled in callback)
- *
- * This function is called periodically to check connection status.
- * Actual data handling is done in MyCharacteristicCallbacks::onWrite().
- */
- void handleBLEFromClient(void)
- {
- // Connection status already updated in MyServerCallbacks
- // Data handling done in MyCharacteristicCallbacks::onWrite()
- // Check for disconnection and handle reconnection
- if (!bleConnected && oldBleConnected)
- {
- delay(500);
- pServer->startAdvertising();
- Serial.println("[BLE] Client disconnected - restarting advertising");
- }
- oldBleConnected = bleConnected;
- }
- /****** BUTTON FUNCTIONS *****/
- /**
- * checkButtonInput() - Monitor GPIO0 button for long press (mode toggle)
- *
- * Detects 7-second long press on GPIO0 to toggle between Bluetooth and LoRa modes.
- * Includes debounce logic to prevent false triggers. Logs all button events.
- */
- void checkButtonInput(void)
- {
- unsigned long currentTime = millis();
- // Debounce check
- if ((currentTime - lastButtonCheckTime) < BUTTON_DEBOUNCE_TIME) return;
- lastButtonCheckTime = currentTime;
- // Read current button state (active LOW on GPIO0)
- bool currentButtonState = digitalRead(GPIO0_BUTTON_PIN);
- // Detect button press (transition from HIGH to LOW)
- if (previousButtonState == HIGH && currentButtonState == LOW)
- {
- buttonPressed = true;
- buttonPressStartTime = currentTime;
- Serial.println("[BUTTON] Pressed (GPIO0) - waiting for long press (7s)...");
- }
- // Detect button release (transition from LOW to HIGH)
- if (previousButtonState == LOW && currentButtonState == HIGH)
- {
- if (buttonPressed)
- {
- unsigned long pressDuration = currentTime - buttonPressStartTime;
- // Check for long press (>= 7 seconds)
- if (pressDuration >= BUTTON_LONG_PRESS_TIME)
- {
- if (!buttonLongPressDetected)
- {
- buttonLongPressDetected = true;
- Serial.print("[BUTTON] Long press detected (");
- Serial.print(pressDuration);
- Serial.println(" ms) - toggling mode");
- toggleMode();
- }
- }
- else
- {
- Serial.print("[BUTTON] Short press (");
- Serial.print(pressDuration);
- Serial.println(" ms) - ignored");
- }
- buttonPressed = false;
- buttonLongPressDetected = false;
- }
- }
- previousButtonState = currentButtonState;
- }
- /**
- * toggleMode() - Toggle between Bluetooth and LoRa modes
- *
- * Switches active communication mode between BLE and LoRa SX1262.
- * Updates mode indicator, reinitializes relevant peripherals, and logs transition.
- */
- void toggleMode(void)
- {
- currentMode = !currentMode;
- Serial.println("\n==================== MODE TOGGLE ====================");
- Serial.print("New Mode: ");
- Serial.println(currentMode ? "BLUETOOTH" : "LORA");
- if (currentMode)
- {
- // Switched to Bluetooth mode
- Serial.println("Status: BLE mode active - ready for client connections");
- Serial.println("Waiting for BLE client to connect...");
- // Resume LoRa receiver if switching away from it
- LoRa.receive();
- }
- else
- {
- // Switched to LoRa mode
- Serial.println("Status: LoRa mode active");
- Serial.println("Configuration: 433MHz SF8 250kHz");
- Serial.println("Listening for LoRa packets...");
- // Ensure LoRa is initialized and receiving
- LoRa.receive();
- }
- Serial.println("=====================================================\n");
- // Update display immediately
- lastDisplayUpdate = 0;
- updateDisplay();
- }
- /****** RADIO SERIAL FUNCTIONS *****/
- /**
- * sendDataToRadio() - Send data to radio station via Serial2
- *
- * Transmits data to the connected radio station on GPIO47/48 at 115200 baud.
- *
- * @param data - Pointer to data buffer
- * @param length - Number of bytes to send
- */
- void sendDataToRadio(const uint8_t* data, size_t length)
- {
- if (data == NULL || length == 0) return;
- for (size_t i = 0; i < length; i++)
- {
- Serial2.write(data[i]);
- }
- packetsSentRadio++;
- }
- /**
- * handleSerialFromRadio() - Process data from radio station
- *
- * Reads incoming data from radio station (Serial2) and forwards it to:
- * - BLE client (if connected and in Bluetooth mode)
- * - LoRa module (if in LoRa mode)
- * Logs all data flow for debugging.
- */
- void handleSerialFromRadio(void)
- {
- // Check if data is available from radio station on Serial2
- while (Serial2.available() > 0)
- {
- uint8_t byteRadio = Serial2.read();
- packetsReceivedRadio++;
- // Forward to active channel based on current mode
- if (currentMode)
- {
- // Bluetooth mode: forward to BLE client using native ESP32 BLE API
- if (bleConnected && pCharacteristicTX != NULL)
- {
- uint8_t data[1] = {byteRadio};
- pCharacteristicTX->setValue(data, 1);
- pCharacteristicTX->notify();
- packetsSentBluetooth++;
- Serial.print("[Radio->BLE] ");
- }
- else
- {
- Serial.print("[Radio->Queue] ");
- }
- }
- else
- {
- // LoRa mode: accumulate for LoRa transmission
- // For simplicity, send single bytes (can be optimized with buffering)
- uint8_t loraPacket[1] = {byteRadio};
- sendDataViaLoRa(loraPacket, 1);
- Serial.print("[Radio->LoRa] ");
- }
- Serial.print("0x");
- Serial.println(byteRadio, HEX);
- }
- }
- /****** SETUP FUNCTION *****/
- /**
- * setup() - Initialize all peripherals and subsystems
- *
- * Performs complete initialization of:
- * - Serial communication (USB debug)
- * - OLED display via I2C with detailed logging
- * - GPIO0 button
- * - Serial2 for radio station communication
- * - BLE (using native ESP32 BLE library from board package)
- * - LoRa SX1262 module with detailed logging
- *
- * Logs all initialization steps. Continues execution even if individual
- * subsystems fail (e.g., display or LoRa).
- */
- void setup(void)
- {
- // Initialize USB serial for debug output
- Serial.begin(115200);
- delay(1000);
- Serial.println("\n\n");
- Serial.println("╔════════════════════════════════════════════════════╗");
- Serial.println("║ ESP32-S3 WIRELESS BRIDGE - INITIALIZATION ║");
- Serial.println("║ LoRa SX1262 + BLE + Radio Station ║");
- Serial.println("╚════════════════════════════════════════════════════╝");
- Serial.println();
- Serial.println("[SYSTEM] Processor: ESP32-S3 Dev Module");
- Serial.println("[SYSTEM] Subsystems: LoRa (433MHz), BLE, Serial2 Radio, GPIO0 Mode Toggle");
- Serial.println();
- // Initialize OLED display via I2C (with error tolerance)
- initializeDisplay();
- // Configure GPIO0 as input (button)
- Serial.println("[GPIO] Configuring GPIO0 button (INPUT_PULLUP)");
- pinMode(GPIO0_BUTTON_PIN, INPUT_PULLUP);
- Serial.println("[GPIO] GPIO0 button ready - 7 second long press to toggle mode");
- // Initialize Serial2 for radio station communication (GPIO47=RX, GPIO48=TX)
- Serial.println();
- Serial.println("[SERIAL2] Initializing radio station communication...");
- Serial2.begin(SERIAL2_BAUDRATE, SERIAL_8N1, SERIAL2_RX_PIN, SERIAL2_TX_PIN);
- Serial.println("[SERIAL2] Configured successfully:");
- Serial.print("[SERIAL2] RX Pin: GPIO");
- Serial.print(SERIAL2_RX_PIN);
- Serial.print(", TX Pin: GPIO");
- Serial.print(SERIAL2_TX_PIN);
- Serial.print(", Baud: ");
- Serial.println(SERIAL2_BAUDRATE);
- // Initialize BLE (native ESP32 BLE library from board package)
- initializeBLE();
- // Initialize LoRa SX1262
- initializeLoRa();
- Serial.println();
- Serial.println("╔════════════════════════════════════════════════════╗");
- Serial.println("║ INITIALIZATION COMPLETE - READY ║");
- Serial.println("╚════════════════════════════════════════════════════╝");
- Serial.println();
- Serial.println("[STATUS] Starting in Bluetooth mode");
- Serial.println("[STATUS] Current mode: BLUETOOTH");
- Serial.println("[STATUS] BLE status: WAITING for client");
- Serial.println("[STATUS] LoRa status: Available (press GPIO0 7s to switch)");
- Serial.println("[STATUS] Display status: " + String(displayAvailable ? "ACTIVE" : "OFFLINE"));
- Serial.println();
- // Initial display update
- lastDisplayUpdate = 0;
- updateDisplay();
- }
- /****** MAIN LOOP FUNCTION *****/
- /**
- * loop() - Main processing loop
- *
- * Continuously processes:
- * - GPIO0 button input for mode toggle
- * - Radio station data (Serial2)
- * - BLE client data
- * - LoRa received packets
- * - Display updates
- *
- * Implements bidirectional data flow between radio, BLE, and LoRa.
- */
- void loop(void)
- {
- // Monitor GPIO0 button for 7-second long press (mode toggle)
- checkButtonInput();
- // Process radio station data (forward to active channel)
- handleSerialFromRadio();
- // Process BLE client data and connection status
- handleBLEFromClient();
- // Process LoRa received packets (forward to radio and BLE)
- handleLoRaReceive();
- // Update display with current mode and status
- updateDisplay();
- // Small delay to prevent overwhelming processor
- delay(10);
- }
- /* END CODE */
Advertisement
Add Comment
Please, Sign In to add comment