Android Question BLE from External GPS

sigster

Active Member
Licensed User
Longtime User
Hi

I am try to read GPS data from ESP32 using the BLEExample





I can not get the raw NMEA data

*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create (first time) **
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
** Activity (main) Resume **
Starting scan...
Target device found: ESP32_BLE_GPS (1C:C3:AB:D1:45:9E)
Connecting to: 1C:C3:AB:D1:45:9E
Discovering services.
Connected. Waiting for GATT table to stabilize...
--- Starting Read Data ---
Total services to read: 3
Requesting data for Service UUID: 00001801-0000-1000-8000-00805f9b34fb
Requesting data for Service UUID: 00001800-0000-1000-8000-00805f9b34fb
Requesting data for Service UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
--- Read Request Completed ---
RAW DATA RECEIVED: ESP32_BLE_GPS
Buffer contents: ESP32_BLE_GPS
RAW DATA RECEIVED: ����
Buffer contents: ESP32_BLE_GPS����
RAW DATA RECEIVED: ��
Buffer contents: ESP32_BLE_GPS������





This is the Arduino code
B4X:
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

// UART configuration for ESP32-WROOM-32
#define RX1_PIN 16  // GPS TX -> ESP32 RX
#define TX1_PIN 17  // GPS RX <- ESP32 TX

// Device name
const char* bleName = "ESP32_BLE_GPS";
const int ledPin = 2;

// BLE UUIDs for Nordic UART Service
#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

BLEServer* pServer = NULL;
BLECharacteristic* pTxCharacteristic = NULL;
BLECharacteristic* pRxCharacteristic = NULL;
bool bleDeviceConnected = false;
bool oldBleDeviceConnected = false;
unsigned long uartBaudrate = 460800;  // ✅ CORRECT BAUD RATE!

void blinkLED(uint32_t millis) {
    digitalWrite(ledPin, HIGH);
    delay(millis);
    digitalWrite(ledPin, LOW);
}

class MyServerCallbacks : public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      bleDeviceConnected = true;
      Serial.println("🔵 BLE device connected.");
    };
    
    void onDisconnect(BLEServer* pServer) {
      bleDeviceConnected = false;
      Serial.println("🔴 BLE device disconnected.");
      pServer->startAdvertising();
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic* pCharacteristic) override {
        String value = pCharacteristic->getValue();
        if (value.length() > 0) {
            Serial.println("\n📱 BLE -> ESP32:");
            Serial1.write((uint8_t*)value.c_str(), value.length());
            blinkLED(10);
        }
    }
};

void uartTask(void *pvParameters) {
  static char line[256];
  static int pos = 0;

  while (1) {
    // 1. FAST READ: Pull every single byte out of the hardware buffer
    while (Serial1.available()) {
      char c = Serial1.read();
      
      if (c == '$') {
        pos = 0;
      }

      if (pos < 255) {
        line[pos++] = c;
      } else {
        pos = 0;
      }

      // 2. PARSE: Only when we hit the end of a line
      if (c == '\n') {
        line[pos] = '\0';
        
        // --- SEND TO BLE ---
        if (bleDeviceConnected) {
          pTxCharacteristic->setValue((uint8_t*)line, pos);
          pTxCharacteristic->notify();
        }

        // --- EFFICIENT PARSING (Zero String Objects) ---
        // Check for GNGGA or GPGGA using strncmp
        if (line[0] == '$' && (strncmp(line, "$GNGGA", 6) == 0 || strncmp(line, "$GPGGA", 6) == 0)) {
            
            // Pointer arithmetic to find the 6th comma (Fix Quality)
            int commaCount = 0;
            char* ptr = line;
            char* fixPtr = NULL;
            
            while (*ptr && commaCount < 6) {
                if (*ptr == ',') commaCount++;
                ptr++;
            }
            
            if (commaCount == 6) {
                fixPtr = ptr;
                int fixQuality = *fixPtr - '0'; // Convert char to int
                
                Serial.println("--- GPS STATUS ---");
                Serial.print("Fix Quality: ");
                switch(fixQuality) {
                    case 4: Serial.println("RTK FIX"); break;
                    case 5: Serial.println("RTK FLOAT"); break;
                    case 1: Serial.println("GPS FIX"); break;
                    default: Serial.println("NO FIX / INVALID");
                }
                
                // For other fields like satellites, you could continue using
                // similar pointer arithmetic if needed.
                Serial.println("------------------");
            }
        }
        
        pos = 0; // Reset buffer
      }
    }
    
    // Minimal delay to allow other tasks to run
    vTaskDelay(1 / portTICK_PERIOD_MS);
  }
}
void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("\n--- BLE Bridge Starting ---");

  // Initialize GPS Serial at 460800 baud
  Serial1.begin(uartBaudrate, SERIAL_8N1, RX1_PIN, TX1_PIN);
  Serial.println("✅ UART initialized at 460800 baud!");

  pinMode(ledPin, OUTPUT);

  BLEDevice::init(bleName);
  Serial.println("✅ BLE initialized");

  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService* pService = pServer->createService(SERVICE_UUID);
 
  pTxCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID_TX,
    BLECharacteristic::PROPERTY_NOTIFY
  );
  pTxCharacteristic->addDescriptor(new BLE2902());
 
  pRxCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID_RX,
    BLECharacteristic::PROPERTY_WRITE
  );
  pRxCharacteristic->setCallbacks(new MyCallbacks());

  pService->start();

  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinInterval(160);
  pAdvertising->setMaxInterval(160);
  pAdvertising->start();
 
  Serial.println("✅ BLE advertising started!");
  Serial.println("📱 Device: " + String(bleName));

  xTaskCreatePinnedToCore(uartTask, "UART Task", 8192, NULL, 1, NULL, 1);
}

void loop() {
  if (bleDeviceConnected && !oldBleDeviceConnected) {
    oldBleDeviceConnected = bleDeviceConnected;
    Serial.println("\n🎉 BLE CONNECTED! 🎉");
    blinkLED(200);
  }
  if (!bleDeviceConnected && oldBleDeviceConnected) {
    oldBleDeviceConnected = bleDeviceConnected;
    pServer->startAdvertising();
    Serial.println("\n⚠️ BLE disconnected, advertising restarted...");
  }
  delay(10);
}
 

Attachments

  • BLEExample.zip
    12.8 KB · Views: 2

drgottjr

Expert
Licensed User
Longtime User
i apologize for not reading your posted BLEExample.zip, but your posted code snippet jumps out to me with what i would tell you: characteristic 6E400003-B5A3-F393-E0A9-E50E24DCCA9E is not read(able) directly. with it you subscribe to notifications. when notifications are ready, they will be available by listening to the notifications listener for that characteristic.
 
Upvote 0
Top