-
Notifications
You must be signed in to change notification settings - Fork 15
Feat ble prototype example #331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
c77404f
8a055f2
2f41662
2244162
80d7099
01990cd
9d4ba9c
d7acd3b
0a735a5
e58e169
a70b0c9
3339bf0
5687d78
2db7d38
a473162
2849d46
bbfd66b
38f7c97
69bf798
6e919d3
0ed979a
1450c29
176cb58
7d6574e
c1e58c1
47f981c
8300982
b270aee
eab8f6f
e25f04c
dab6c44
ce42cd5
abdec15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,7 +21,6 @@ | |
| #ifdef ARDUINO_FEATHER_ESP32 | ||
| #include <SD.h> | ||
| #include "driver/adc.h" | ||
| #include <esp_bt.h> | ||
| #else | ||
| #include <SdFat.h> | ||
| #include <ArduinoLowPower.h> | ||
|
|
@@ -39,6 +38,9 @@ | |
| #include "FileTransferManager.h" | ||
| #endif | ||
| #include "EmotiBitConfigManager.h" | ||
| #ifdef ARDUINO_FEATHER_ESP32 | ||
| #include "EmotiBitBluetooth.h" | ||
| #endif | ||
|
|
||
| class EmotiBit { | ||
|
|
||
|
|
@@ -266,6 +268,7 @@ class EmotiBit { | |
| MAX_LOW_POWER, // data not sent, time-syncing accuracy low | ||
| LOW_POWER, // data not sent, time-syncing accuracy high | ||
| NORMAL_POWER, // data sending, time-syncing accuracy high | ||
| BLUETOOTH, | ||
| length | ||
| }; | ||
|
|
||
|
|
@@ -280,6 +283,9 @@ class EmotiBit { | |
| EmotiBitEda emotibitEda; | ||
| EmotiBitNvmController _emotibitNvmController; | ||
| #ifdef ARDUINO_FEATHER_ESP32 | ||
| EmotiBitBluetooth _emotiBitBluetooth; | ||
| #endif //ARDUINO_FEATHER_ESP32 | ||
| #ifdef ARDUINO_FEATHER_ESP32 | ||
| FileTransferManager _fileTransferManager; | ||
| #endif | ||
| EmotiBitConfigManager _emotibitConfigManager; | ||
|
|
@@ -429,6 +435,7 @@ class EmotiBit { | |
| DataType _serialData = DataType::length; | ||
| volatile bool buttonPressed = false; | ||
| bool startBufferOverflowTest = false; | ||
| bool _bluetoothEnabled = false; | ||
|
|
||
| void setupFailed(const String failureMode, int buttonPin = -1, bool configFileError = false); | ||
| bool setupSdCard(bool loadConfig = true); | ||
|
|
@@ -444,7 +451,8 @@ class EmotiBit { | |
| void attachShortButtonPress(void(*shortButtonPressFunction)(void)); | ||
| void attachLongButtonPress(void(*longButtonPressFunction)(void)); | ||
| PowerMode getPowerMode(); | ||
| void setPowerMode(PowerMode mode); | ||
| //void setPowerMode(PowerMode mode); | ||
| bool setPowerMode(PowerMode mode); | ||
|
Comment on lines
+454
to
+455
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Remove the stale commented-out signature. The old |
||
| bool writeSdCardMessage(const String &s); | ||
| int freeMemory(); | ||
| bool loadConfigFile(const String &filename); | ||
|
|
@@ -459,7 +467,6 @@ class EmotiBit { | |
| bool processThermopileData(); // placeholder until separate EmotiBitThermopile controller is implemented | ||
| void writeSerialData(EmotiBit::DataType t); | ||
| void printEmotiBitInfo(); | ||
|
|
||
|
|
||
| /** | ||
| * Copies data buffer of the specified DataType into the passed array | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,234 @@ | ||
| #ifdef ARDUINO_FEATHER_ESP32 | ||
| #include "EmotiBitBluetooth.h" | ||
| #include <esp_bt.h> | ||
|
|
||
| uint8_t EmotiBitBluetooth::begin(const String& emotibitDeviceId) | ||
| { | ||
| if (pServer) | ||
| { | ||
| EmotiBitBluetooth::reconnect(); | ||
| Serial.println("Bluetooth already initialized, reconnecting..."); | ||
| return 0; // Success | ||
| } | ||
|
|
||
| _emotibitDeviceId = emotibitDeviceId; | ||
|
|
||
| Serial.println("Bluetooth tag detected, turning on bluetooth."); | ||
| BLEDevice::init(("EmotiBit: " + _emotibitDeviceId).c_str()); | ||
|
|
||
| pServer = BLEDevice::createServer(); | ||
|
|
||
| if (!pServer) | ||
| { | ||
| Serial.println("ERROR: Failed to create BLE server"); | ||
| return 1; | ||
| } | ||
|
|
||
| pServer->setCallbacks(new MyServerCallbacks(this)); | ||
| BLEService* pService = pServer->createService(EMOTIBIT_SERVICE_UUID); | ||
|
|
||
| pDataTxCharacteristic = pService->createCharacteristic(EMOTIBIT_DATA_TX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY); | ||
| if (!pDataTxCharacteristic) | ||
| { | ||
| Serial.println("ERROR: Failed to create TX characteristic"); | ||
| return 1; | ||
| } | ||
| pDataTxCharacteristic->addDescriptor(new BLE2902()); | ||
|
|
||
| pDataRxCharacteristic = pService->createCharacteristic(EMOTIBIT_DATA_RX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_WRITE); | ||
| if (!pDataRxCharacteristic) | ||
| { | ||
| Serial.println("ERROR: Failed to create RX characteristic"); | ||
| return 1; | ||
| } | ||
| pDataRxCharacteristic->setCallbacks(new MyCallbacks()); | ||
|
|
||
| pService->start(); | ||
|
|
||
| EmotiBitBluetooth::startAdvertising(); | ||
| _bluetoothReconnect = true; // Allow reconnection after disconnection | ||
|
|
||
| return 0; | ||
|
Joseph-Jacobson marked this conversation as resolved.
|
||
| } | ||
|
|
||
| void EmotiBitBluetooth::MyServerCallbacks::onConnect(BLEServer* pServer) | ||
| { | ||
| server->deviceConnected = true; | ||
| server->_connId = pServer->getConnId(); | ||
| Serial.println("BLE client connected"); | ||
| } | ||
|
|
||
| void EmotiBitBluetooth::MyServerCallbacks::onDisconnect(BLEServer* pServer) | ||
| { | ||
| server->deviceConnected = false; | ||
| Serial.println("BLE client disconnected"); | ||
| //need to restart advertising to allow new connections after disconnection if accidentally disconnected | ||
| if (server->_bluetoothReconnect) | ||
| { | ||
| server->reconnect(); | ||
| Serial.println("Restarted BLE advertising"); | ||
| } | ||
| } | ||
|
|
||
| //ToDO: Current polling aproach can drop back to back writes since the characteristic only holds the last value. | ||
| void EmotiBitBluetooth::MyCallbacks::onWrite(BLECharacteristic *pCharacteristic) | ||
| { | ||
| std::string rxValue = pCharacteristic->getValue(); | ||
| if (rxValue.length() > 0) { | ||
| //Serial.print("Received: "); | ||
| //Serial.println(rxValue.c_str()); | ||
| } | ||
|
Joseph-Jacobson marked this conversation as resolved.
|
||
| } | ||
|
|
||
| void EmotiBitBluetooth::setDeviceId(const String& emotibitDeviceId) | ||
| { | ||
| _emotibitDeviceId = emotibitDeviceId; | ||
| } | ||
|
|
||
| void EmotiBitBluetooth::sendData(const String &message) | ||
| { | ||
| if (deviceConnected) | ||
| { | ||
| //TODO: consider truncating via MTU if message is too long | ||
| if (pDataTxCharacteristic == nullptr) | ||
| { | ||
| //Serial.println("ERROR: pDataTxCharacteristic is NULL!"); | ||
| return; | ||
| } | ||
|
|
||
| //Serial.print("BLE TX: Message length="); | ||
| //Serial.print(message.length()); | ||
|
|
||
| // Set the value | ||
| pDataTxCharacteristic->setValue(message.c_str()); | ||
|
|
||
| // Call notify - note: doesn't return success/failure status | ||
| pDataTxCharacteristic->notify(); | ||
|
|
||
| // Check descriptor status | ||
| BLEDescriptor* p2902 = pDataTxCharacteristic->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); | ||
| if (p2902) | ||
| { | ||
| const uint8_t* val = p2902->getValue(); | ||
| if (val) | ||
| { | ||
| //Serial.print(" | Notifications enabled="); | ||
| //Serial.print((val[0] & 0x01) ? "YES" : "NO"); | ||
| } | ||
| } | ||
|
|
||
| //Serial.print(" | Char ptr=0x"); | ||
| //Serial.print((uint32_t)pDataTxCharacteristic, HEX); | ||
| //Serial.print(" | Message: "); | ||
| //Serial.println(message.c_str()); | ||
| } | ||
| else | ||
| { | ||
| //ToDO: consider gating behind a debug flag | ||
| Serial.println("unable to send data: deviceConnected=false"); | ||
| } | ||
| } | ||
|
|
||
| uint8_t EmotiBitBluetooth::readControl(String& packet) | ||
| { | ||
| uint8_t numPackets = 0; | ||
| packet = ""; | ||
| if (deviceConnected) | ||
| { | ||
| std::string rxValue = pDataRxCharacteristic->getValue(); | ||
| if (!rxValue.empty()) | ||
| { | ||
| //Serial.print("Received: "); | ||
| //Serial.println(rxValue.c_str()); | ||
| _receivedControlMessage += String(rxValue.c_str()); | ||
|
|
||
| //CLEAR THE CHAR VALUE SO WE DON’T REUSE IT | ||
| pDataRxCharacteristic->setValue(""); | ||
| } | ||
|
|
||
| String tempPacket = ""; | ||
| while (_receivedControlMessage.length() > 0) | ||
| { | ||
| int c = _receivedControlMessage[0]; | ||
| _receivedControlMessage.remove(0, 1); | ||
|
|
||
| if (c == (int)EmotiBitPacket::PACKET_DELIMITER_CSV) | ||
| { | ||
| numPackets++; | ||
| packet = tempPacket; | ||
| tempPacket = ""; | ||
| _receivedControlMessage = ""; | ||
| return numPackets; | ||
| } | ||
| else | ||
| { | ||
| if (c == 0) { | ||
| // Throw out null term | ||
| } | ||
| else | ||
| { | ||
| tempPacket += (char)c; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return numPackets; | ||
| } | ||
|
Joseph-Jacobson marked this conversation as resolved.
|
||
|
|
||
| bool EmotiBitBluetooth::isOff() | ||
| { | ||
| return _bluetoothOff; | ||
| } | ||
|
|
||
| void EmotiBitBluetooth::end() | ||
| { | ||
| if (pServer && deviceConnected) | ||
| { | ||
| //tear down the old connection | ||
| pServer->disconnect(_connId); | ||
| Serial.println("BLE client disconnected by end()"); | ||
| } | ||
|
Joseph-Jacobson marked this conversation as resolved.
|
||
| if (pServer) | ||
| { | ||
| pServer->getAdvertising()->stop(); | ||
| Serial.println("BLE advertising stopped"); | ||
| } | ||
| _bluetoothOff = true; | ||
| _bluetoothReconnect = false; | ||
| } | ||
|
|
||
| void EmotiBitBluetooth::reconnect() | ||
| { | ||
| if (pServer) | ||
| { | ||
| EmotiBitBluetooth::startAdvertising(); | ||
| Serial.println("BLE advertising restarted after reconnect"); | ||
| _bluetoothOff = false; | ||
| _bluetoothReconnect = true; | ||
| } | ||
| else | ||
| { | ||
| Serial.println("ERROR: pServer is NULL, cannot reconnect"); | ||
| } | ||
| } | ||
|
|
||
| void EmotiBitBluetooth::startAdvertising() | ||
| { | ||
| if (pServer) | ||
| { | ||
| pServer->getAdvertising()->start(); | ||
| _bluetoothOff = false; | ||
| Serial.println("BLE advertising started"); | ||
| } | ||
|
Joseph-Jacobson marked this conversation as resolved.
|
||
| else | ||
| { | ||
| Serial.println("ERROR: pServer is NULL, cannot start advertising"); | ||
| } | ||
| } | ||
|
Joseph-Jacobson marked this conversation as resolved.
|
||
|
|
||
| void EmotiBitBluetooth::disableBluetooth() | ||
| { | ||
| esp_bt_controller_disable(); | ||
| } | ||
|
|
||
| #endif //ARDUINO_FEATHER_ESP32 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Encapsulation: avoid exposing transport internals publicly.
Exposing EmotiBitBluetooth _emotiBitBluetooth publicly couples callers to the transport and makes invariants harder to preserve. Prefer private with minimal accessors or friend usage within EmotiBit.
🤖 Prompt for AI Agents