Hi! Now im reaching out here to see if someone has an solution on my issue. I have searched the Forum for answer but not found any that match my issue. I have tried the different BLE connections found here on the forum but still no success.
I have made a DIY GPS module with an Adafruit ESP32-S3 feather. It has built in Wifi and BT.
I got it working good with Wifi but cant figure out the BLE connection.
When i connect my phone to the DIY BLE it connects and stays connected. In the nRF app i can see it was pushing the NMEA msg. (GGA, RMC) but when connecting to it in the Racechrono app (Android) under "Other Devices - BLE - GPS" its constantly saying Connected, Connecting..., Connected in a never ending loop. If i set it up as a "monitor" it stays connected.
Here is my code now, I have fiddle alot and gave up alittle as i got it working with the Wifi connection, so the GPS MSG is maybe not structed correct right now.
// ESP32-S3 BLE GPS Adapter for RaceChrono+
// Hardware: Adafruit Feather ESP32-S3 + NMEA GPS module on Serial1
// GPS TX -> GPIO 16 (RX), GPS RX -> GPIO 17 (TX)
#include
#include
#include
// Setup GPS
HardwareSerial gpsSerial(1);
Adafruit_GPS GPS(&gpsSerial);
#define GPS_BAUD 115200
#define PMTK_SET_NMEA_UPDATE_8HZ "$PMTK220,125*2C" // 125ms = 8Hz
// UUIDs (aollin compatible)
#define SERVICE_UUID "00000001-0000-00fd-8933-990d6f411ff8"
#define CHAR_UUID_GPS_MAIN "00000003-0000-00fd-8933-990d6f411ff8"
#define CHAR_UUID_GPS_TIME "00000004-0000-00fd-8933-990d6f411ff8"
NimBLEServer* pServer = nullptr;
NimBLECharacteristic* gpsMainChar = nullptr;
NimBLECharacteristic* gpsTimeChar = nullptr;
bool isConnected = false;
uint8_t syncBits = 0;
int lastDateAndHour = -1;
class ServerCallbacks : public NimBLEServerCallbacks {
void onConnect(NimBLEServer* pServer) override {
isConnected = true;
Serial.println("BLE connected");
}
void onDisconnect(NimBLEServer* pServer) override {
isConnected = false;
Serial.println("BLE disconnected");
NimBLEDevice::startAdvertising();
}
};
void setupBLE() {
NimBLEDevice::init("RC-DIY-GPS");
pServer = NimBLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());
NimBLEService* service = pServer->createService(SERVICE_UUID);
gpsMainChar = service->createCharacteristic(
CHAR_UUID_GPS_MAIN,
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ
);
gpsTimeChar = service->createCharacteristic(
CHAR_UUID_GPS_TIME,
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ
);
service->start();
NimBLEAdvertising* advertising = NimBLEDevice::getAdvertising();
advertising->addServiceUUID(SERVICE_UUID);
advertising->start();
Serial.println("BLE advertising started");
}
void setupGPS() {
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, 16, 17);
GPS.begin(GPS_BAUD);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); // Only RMC and GGA
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_8HZ); // 8Hz
delay(1000);
GPS.println("$PMTK220,125*2C"); // Force 8Hz update rate
}
void setup() {
Serial.begin(115200);
setupBLE();
setupGPS();
}
void loop() {
GPS.read();
if (!GPS.newNMEAreceived()) return;
if (!GPS.parse(GPS.lastNMEA())) return;
if (!isConnected) return;
if (!GPS.fix) {
uint8_t dummy[20] = {0};
gpsMainChar->setValue(dummy, 20);
gpsMainChar->notify();
return;
}
int dateHour = (GPS.year * 8928) + ((GPS.month - 1) * 744) + ((GPS.day - 1) * 24) + GPS.hour;
if (dateHour != lastDateAndHour) {
syncBits++;
lastDateAndHour = dateHour;
}
int ms = GPS.milliseconds;
int timeSinceHour = (GPS.minute * 60000) + (GPS.seconds * 1000) + ms;
int32_t lat = GPS.latitude_fixed;
int32_t lon = GPS.longitude_fixed;
int altitude = (int)(GPS.altitude * 10.0f);
int speed = (int)(GPS.speed * 100.0f);
int bearing = (int)(GPS.angle * 100.0f);
int hdop = (int)(GPS.HDOP * 10.0f);
// Main packet
uint8_t mainData[20];
mainData[0] = ((syncBits & 0x7) << 5) | ((timeSinceHour >> 16) & 0x1F);
mainData[1] = (timeSinceHour >> 8);
mainData[2] = (timeSinceHour);
mainData[3] = ((std::min(3, (int)GPS.fixquality) << 6) | std::min(63, (int)GPS.satellites));
mainData[4] = (lat >> 24); mainData[5] = (lat >> 16); mainData[6] = (lat >> 8); mainData[7] = lat;
mainData[8] = (lon >> 24); mainData[9] = (lon >> 16); mainData[10] = (lon >> 8); mainData[11] = lon;
mainData[12] = (altitude >> 8); mainData[13] = altitude;
mainData[14] = (speed >> 8); mainData[15] = speed;
mainData[16] = (bearing >> 8); mainData[17] = bearing;
mainData[18] = hdop;
mainData[19] = 0xFF; // unused
gpsMainChar->setValue(mainData, 20);
gpsMainChar->notify();
// Time packet
uint8_t timeData[3];
timeData[0] = ((syncBits & 0x7) << 5) | ((dateHour >> 16) & 0x1F);
timeData[1] = dateHour >> 8;
timeData[2] = dateHour;
gpsTimeChar->setValue(timeData, 3);
gpsTimeChar->notify();
delay(1);
}
Comments
Thanks. I will have a look at that.
I just got confused when it connected fine to nRF and also if I set it up as a monitor instead in rc it also connected fine. 🙂