348 lines
9.8 KiB
C++
348 lines
9.8 KiB
C++
BLEScan* pBLEScan = nullptr;
|
|
BLEClient* pClient = nullptr;
|
|
BLEAdvertisedDevice* pRemoteDevice = nullptr;
|
|
BLERemoteService* pRemoteService = nullptr;
|
|
BLERemoteCharacteristic* pRemoteCharacteristic_rx = nullptr;
|
|
BLERemoteCharacteristic* pRemoteCharacteristic_tx = nullptr;
|
|
|
|
// 0000ff01-0000-1000-8000-00805f9b34fb
|
|
// Notifications from this characteristic is received data from BMS
|
|
// NOTIFY, READ
|
|
|
|
// 0000ff02-0000-1000-8000-00805f9b34fb
|
|
// Write this characteristic to send data to BMS
|
|
// READ, WRITE, WRITE NO RESPONSE
|
|
|
|
boolean doScan = false; // becomes true when BLE is initialized and scanning is allowed
|
|
boolean doConnect = false; // becomes true when correct ID is found during scanning
|
|
|
|
boolean ble_client_connected = false; // true when fully connected
|
|
|
|
unsigned int ble_packets_requested = 0b00; // keeps track of requested packets
|
|
unsigned int ble_packets_received = 0b00; // keeps track of received packets
|
|
|
|
|
|
// ======= CALLBACKS =========
|
|
|
|
void MyEndOfScanCallback(BLEScanResults pBLEScanResult){
|
|
bms_status=false; // BMS not found
|
|
|
|
if(BLE_CALLBACK_DEBUG){
|
|
debug("BLE: scan finished");
|
|
Serial.println("Scan finished.");
|
|
}
|
|
}
|
|
|
|
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks{
|
|
// called for each advertising BLE server
|
|
|
|
void onResult(BLEAdvertisedDevice advertisedDevice){
|
|
// found a device
|
|
|
|
|
|
if(BLE_CALLBACK_DEBUG){
|
|
debug(
|
|
String("BLE: found ") +
|
|
String(advertisedDevice.getName().c_str()) +
|
|
String(" with address ") +
|
|
String(advertisedDevice.getAddress().toString().c_str()) +
|
|
String(" and RSSI ") +
|
|
String(advertisedDevice.getRSSI())
|
|
);
|
|
|
|
Serial.print("BLE: found ");
|
|
Serial.println(advertisedDevice.toString().c_str());
|
|
}
|
|
|
|
// Check if device is advertising the specific service UUID
|
|
if (!advertisedDevice.isAdvertisingService(serviceUUID)) {
|
|
debug("Device does not advertise the specified service UUID.");
|
|
return;
|
|
}
|
|
|
|
if(BLE_CALLBACK_DEBUG){
|
|
debug("BLE: target device found");
|
|
}
|
|
|
|
pBLEScan->stop();
|
|
|
|
// delete old remote device, create new one
|
|
if(pRemoteDevice != nullptr){
|
|
delete pRemoteDevice;
|
|
}
|
|
pRemoteDevice = new BLEAdvertisedDevice(advertisedDevice);
|
|
|
|
doConnect = true;
|
|
}
|
|
};
|
|
|
|
class MyClientCallback : public BLEClientCallbacks{
|
|
// called on connect/disconnect
|
|
void onConnect(BLEClient* pclient){
|
|
|
|
if(BLE_CALLBACK_DEBUG){
|
|
debug(String("BLE: connecting to ") + String(pclient->getPeerAddress().toString().c_str()));
|
|
}
|
|
}
|
|
|
|
void onDisconnect(BLEClient* pclient){
|
|
ble_client_connected = false;
|
|
doConnect = false;
|
|
|
|
if(BLE_CALLBACK_DEBUG){
|
|
debug(String("BLE: disconnected from ") + String(pclient->getPeerAddress().toString().c_str()));
|
|
}
|
|
|
|
}
|
|
};
|
|
|
|
static void MyNotifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify){
|
|
//this is called when BLE server sents data via notification
|
|
//hexDump((char*)pData, length);
|
|
if(!bleCollectPacket((char *)pData, length)){
|
|
debug("ERROR: packet could not be collected.");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ======= OTHERS =========
|
|
|
|
void handleBLE(){
|
|
static unsigned long prev_millis_standby = 0;
|
|
|
|
prev_millis_standby = millis();
|
|
|
|
while(true){ // loop until we hit a timeout or gathered all packets
|
|
|
|
if((ble_packets_received == BLE_PACKETSRECEIVED_BEFORE_STANDBY) || (millis()>prev_millis_standby+BLE_TIMEOUT)){
|
|
if(ble_packets_received == BLE_PACKETSRECEIVED_BEFORE_STANDBY){
|
|
debug("BLE: all packets received");
|
|
bms_status=true; // BMS was connected, data up-to-date
|
|
printBasicInfo();
|
|
printCellInfo();
|
|
}else{
|
|
debug("BLE: connection timeout");
|
|
bms_status=false; // BMS not (fully) connected
|
|
}
|
|
|
|
break; // we're done with BLE, exit while loop
|
|
}
|
|
else if (doConnect){
|
|
|
|
// found the desired BLE server, now connect to it
|
|
if (connectToServer()){
|
|
ble_client_connected = true;
|
|
ble_packets_received=0;
|
|
ble_packets_requested=0;
|
|
|
|
}else{
|
|
ble_client_connected = false;
|
|
debug("BLE: failed to connect");
|
|
}
|
|
|
|
doConnect = false;
|
|
}
|
|
|
|
if (ble_client_connected){
|
|
// if connected to BLE server, request all data
|
|
if((ble_packets_requested & 0b01)!=0b01){
|
|
// request packet 0b01
|
|
debug("BLE: requesting packet 0b01");
|
|
delay(50);
|
|
if(bmsRequestBasicInfo()){
|
|
ble_packets_requested |= 0b01;
|
|
}
|
|
|
|
}else if(((ble_packets_received & 0b01)==0b01) && ((ble_packets_requested & 0b10)!=0b10)){
|
|
// request packet 0b10 after 0b01 has been received
|
|
debug("BLE: requesting packet 0b10");
|
|
delay(50);
|
|
if(bmsRequestCellInfo()){
|
|
ble_packets_requested |= 0b10;
|
|
}
|
|
}
|
|
|
|
}else if ((!doConnect)&&(doScan)){
|
|
// we are not connected, so we can scan for devices
|
|
debug("BLE: not connected, starting scan");
|
|
Serial.print("BLE is not connected, starting scan");
|
|
|
|
// Disconnect client
|
|
if((pClient != nullptr)&&(pClient->isConnected())){
|
|
pClient->disconnect();
|
|
}
|
|
|
|
// stop scan (if running) and start a new one
|
|
pBLEScan->setActiveScan(true);
|
|
pBLEScan->setInterval(1 << 8); // 160 ms
|
|
pBLEScan->setWindow(1 << 7); // 80 ms
|
|
pBLEScan->start(BLE_SCAN_DURATION, MyEndOfScanCallback, false); // non-blocking, use a callback
|
|
|
|
doScan=false;
|
|
|
|
debug("BLE: scan started");
|
|
}
|
|
}
|
|
}
|
|
|
|
void bleGatherPackets(){
|
|
bleStart();
|
|
handleBLE();
|
|
blePause();
|
|
BLEDevice::deinit(false);
|
|
}
|
|
|
|
void bleStart(){
|
|
Serial.print("Starting BLE... ");
|
|
|
|
BLEDevice::init("");
|
|
//esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); // release some unused memory
|
|
|
|
// Retrieve a BLE client
|
|
pClient = BLEDevice::createClient();
|
|
pClient->setClientCallbacks(new MyClientCallback());
|
|
|
|
// Retrieve a BLE scanner
|
|
pBLEScan = BLEDevice::getScan();
|
|
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
|
|
|
bleContinue();
|
|
Serial.println("done");
|
|
}
|
|
|
|
void blePause(){
|
|
// stop scanning and disconnect from all devices
|
|
doScan=false;
|
|
|
|
// Disconnect client
|
|
if((pClient != nullptr)&&(pClient->isConnected())){
|
|
pClient->disconnect();
|
|
}
|
|
|
|
delay(50);
|
|
|
|
pBLEScan->stop();
|
|
|
|
ble_client_connected=false;
|
|
doConnect=false;
|
|
ble_packets_received=0;
|
|
ble_packets_requested=0;
|
|
|
|
}
|
|
|
|
|
|
void bleContinue(){
|
|
// Prepare for scanning
|
|
ble_client_connected=false;
|
|
doConnect=false;
|
|
ble_packets_received=0;
|
|
|
|
doScan=true; // start scanning for new devices
|
|
}
|
|
|
|
bool connectToServer(){
|
|
if(pRemoteDevice==nullptr){
|
|
Serial.println("Invalid remote device, can't connect");
|
|
return false;
|
|
}
|
|
|
|
// Disconnect client
|
|
if((pClient != nullptr)&&(pClient->isConnected())){
|
|
pClient->disconnect();
|
|
}
|
|
|
|
Serial.print("Forming a connection to ");
|
|
Serial.println(pRemoteDevice->getAddress().toString().c_str());
|
|
|
|
delay(100);
|
|
|
|
// Connect to the remote BLE Server.
|
|
pClient->connect(pRemoteDevice);
|
|
if(!(pClient->isConnected())){
|
|
debug(String("BLE: failed to connect"));
|
|
Serial.println("Failed to connect to server");
|
|
pClient->disconnect();
|
|
return false;
|
|
}
|
|
|
|
Serial.println(" - Connected to server");
|
|
|
|
|
|
// Get remote service
|
|
pRemoteService = pClient->getService(serviceUUID);
|
|
if (pRemoteService == nullptr){
|
|
debug(String("BLE: failed to find service UUID"));
|
|
Serial.print("Failed to find our service UUID: ");
|
|
Serial.println(serviceUUID.toString().c_str());
|
|
pClient->disconnect();
|
|
return false;
|
|
}
|
|
Serial.println(" - Found our service");
|
|
|
|
|
|
// Get BMS receive characteristic
|
|
pRemoteCharacteristic_rx = pRemoteService->getCharacteristic(charUUID_rx);
|
|
if (pRemoteCharacteristic_rx == nullptr){
|
|
debug(String("BLE: failed to find RX UUID"));
|
|
Serial.print("Failed to find rx UUID: ");
|
|
Serial.println(charUUID_rx.toString().c_str());
|
|
pClient->disconnect();
|
|
return false;
|
|
}
|
|
Serial.println(" - Found RX characteristic");
|
|
|
|
|
|
// Register callback for remote characteristic (receive channel)
|
|
if (pRemoteCharacteristic_rx->canNotify()){
|
|
pRemoteCharacteristic_rx->registerForNotify(MyNotifyCallback);
|
|
}else{
|
|
debug(String("BLE: failed to register notification of remote characteristic"));
|
|
Serial.println("Failed to register notification of remote characteristic");
|
|
pClient->disconnect();
|
|
return false;
|
|
}
|
|
Serial.println(" - Registered remote characteristic for notification");
|
|
|
|
|
|
// Get BMS transmit characteristic
|
|
pRemoteCharacteristic_tx = pRemoteService->getCharacteristic(charUUID_tx);
|
|
if (pRemoteCharacteristic_tx == nullptr){
|
|
debug(String("BLE: failed to find TX UUID"));
|
|
Serial.print("Failed to find tx UUID: ");
|
|
Serial.println(charUUID_tx.toString().c_str());
|
|
pClient->disconnect();
|
|
return false;
|
|
}
|
|
Serial.println(" - Found TX characteristic");
|
|
|
|
|
|
// Check whether tx is writeable
|
|
if (!(pRemoteCharacteristic_tx->canWriteNoResponse())){
|
|
debug(String("BLE: failed TX remote characteristic is not writable"));
|
|
Serial.println("Failed TX remote characteristic is not writable");
|
|
pClient->disconnect();
|
|
return false;
|
|
}
|
|
Serial.println(" - TX is writable");
|
|
|
|
|
|
delay(BLE_REQUEST_DELAY); // wait, otherwise writeValue doesn't work for some reason
|
|
// to do: fix this ugly hack
|
|
|
|
debug(String("BLE: connected"));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool sendCommand(uint8_t *data, uint32_t dataLen){
|
|
if((pClient!=nullptr)&&(pClient->isConnected())){
|
|
pRemoteCharacteristic_tx->writeValue(data, dataLen, false);
|
|
return true;
|
|
}else{
|
|
return false;
|
|
}
|
|
}
|