Skip to content

Feat ble prototype example#331

Draft
Joseph-Jacobson wants to merge 33 commits into
devfrom
feat-blePrototype-Example
Draft

Feat ble prototype example#331
Joseph-Jacobson wants to merge 33 commits into
devfrom
feat-blePrototype-Example

Conversation

@Joseph-Jacobson

@Joseph-Jacobson Joseph-Jacobson commented Jul 23, 2025

Copy link
Copy Markdown
Contributor

Description

This PR enables Bluetooth Low Energy (BLE) on the EmotiBit, adding the following functionality:

  • Setup button press to switch the EmotiBit into BLE mode
  • Sending EmotiBit sensor data over UART
  • Receiving Control Packets
  • Wireless Off

ARDUINO NOTE: If you are on Arduino, please set the partition table to Huge App

NOTE: This build does NOT have time syncing enabled so all data received does not account for start time/adjustments due to latency.

This PR allows users to press the side button on start up (same time frame to get into the debug mode) to switch the EmotiBit into bluetooth mode, which is signified by a faster blinking light. A synopsis of each change is outlined in the notes for reviewer. This code was built out with this arduino example here as an example.

Requirements

Issues Referenced

Fixes #345

Documentation update

None - we are not publicly releasing this PR

Notes for Reviewer

EmotiBitBluetooth.h/.cpp

This is where all the bluetooth specific functions will live and was built with EmotiBitWifi as a blueprint.

  • Begin: facilitates the bluetooth stack creation
  • Callbacks: Handles connection/disconnections/data sent
  • Send data: Handles sending data
  • Read control: Handles received data
  • Reconnect: Reestabilishes advertising

EmotiBit.h/.cpp

  • Set up: Button press during 2 second window switches the EmotiBit into bluetooth mode (same point that we get into debugger)
  • ParseIncomingControlPackets: We use bluetooth's readControl, which functions like WiFi's readControl
  • LED set up: Sets bluetooth lights to blink twice as fast
  • Wireless Off: Added provisions so wireless off works with bluetooth. NOTE: we do not entirely disable bluetooth for this mode due to deinitialization bugs. This results in a decrease in wireless off battery life compared to wifi's wireless off.

EmotiBit_stock_firemware.ino

  • onShortButtonPress edited to handle both bluetooth and wifi's wireless off modes.

board_feather_esp32.ini

  • Added huge_app.csv

Setup Flow

Setup drawio (2)

Bluetooth Connections Flow

Untitled Diagram drawio (2)

LED Speeds

Mode Speed
WiFi a1ux42
Bluetooth a1uxfl

Testing

All tests were run with Bluefruit Connect or nRF Connect which can be downloaded on the app store.

Results

Testing included the following feature tests. I also ensured that record begin/end would work as well.

Feature Tests

Feature Test Result Notes
Mock Data Testing ✔️
Packet Fixed Length Test ✔️
Recording Runtime Bluetooth ✔️ ~4.6 Hours
Wireless Off Recording Runtime Bluetooth ✔️ ~6.4 Hours
Record Begin over UART Bluetooth ✔️
Record End over UART Bluetooth ✔️
Setup EmotiBit in Bluetooth mode ✔️

Shared files

Checklist to allow merge

  • All dependent repositories used were on branch master
  • Firmware
    • Set testingMode to TestingMode::NONE
    • Set const bool DIGITAL_WRITE_DEBUG = false (if set true while testing)
    • Update version in EmotiBit.h
    • Update library.properties to the correct version (should match EmotiBit.h)
  • doxygen style comments included for new code snippets
  • Required documentation updated

Screenshots:

@coderabbitai

coderabbitai Bot commented Sep 13, 2025

Copy link
Copy Markdown

Walkthrough

Adds ESP32 BLE support and integrates it into EmotiBit core: new EmotiBitBluetooth.h/.cpp implement a BLE server, TX/RX characteristics, connection state, send/read/control APIs, and advertising/reconnect. EmotiBit.h adds BLUETOOTH power mode and _bluetoothEnabled. EmotiBit.cpp updates startup, setup, control-parsing, LED/connect logic, FTP/serial trigger handling, sendData() multi-transport dispatch, and changes setPowerMode() to return bool. Example firmware button behavior, board partition config, and docs were also updated.

Possibly related PRs

  • EmotiBit/EmotiBit_FeatherWing PR 329: Modifies EmotiBit::sendData() and FTP/serial trigger handling, overlapping this PR’s multi-transport dispatch and serial/FTP behavior changes.
🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feat ble prototype example' is partially related to the changeset as it references a BLE feature, but is vague and imprecise; it lacks specificity about Bluetooth Low Energy implementation and doesn't clearly convey the primary changes. Revise the title to be more descriptive and specific, such as 'Add Bluetooth Low Energy (BLE) support with setup button mode switching and sensor data transmission' or similar.
Linked Issues check ❓ Inconclusive The PR partially addresses the linked issue #345. The primary change enables BLE mode entry via button press and adds BLE communication, but the debugger buffering issue (every 2nd input processing) mentioned in #345 is not explicitly addressed in the code changes provided. Clarify whether the debugger buffering issue in #345 has been resolved; if not, ensure it is addressed before merge or document why it remains unresolved.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description is thorough and directly related to the changeset, providing clear implementation details, testing results, and developer notes for reviewers.
Out of Scope Changes check ✅ Passed Most changes align with BLE implementation scope. However, modifications to board_feather_esp32.ini (partition table change), version updates to library.properties, and documentation additions (README.md, WORKFLOWS_AND_SCRIPTS.md) are tangentially related but appear acceptable as supporting changes for the BLE feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Joseph-Jacobson

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 23, 2025

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 21

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
EmotiBit.cpp (3)

4045-4050: sendModePacket() always sends over WiFi, ignoring BLUETOOTH mode.

When in BLE mode, this won’t reach the client and unnecessarily wakes WiFi code paths.

 void EmotiBit::sendModePacket(String &sentModePacket, uint16_t &packetNumber)
 {
   createModePacket(sentModePacket, packetNumber);
-  // ToDo: This should probably be over TCP in response to specific messages from Host (but will require writing TCP ingest)
-  _emotiBitWiFi.sendData(sentModePacket); // Send packet immediately to update host
+  // Send over the active transport
+  if (getPowerMode() == PowerMode::BLUETOOTH) {
+  #ifdef ARDUINO_FEATHER_ESP32
+    _emotiBitBluetooth.sendData(sentModePacket);
+  #endif
+  } else {
+    _emotiBitWiFi.sendData(sentModePacket);
+  }
   _outDataPackets += sentModePacket;      // Add packet to slower data logging bucket
 }

2261-2273: Bitwise precedence bug causes incorrect overflow detection.

status & BufferFloat::ERROR_BUFFER_OVERFLOW == ... is parsed as status & (A==A). You’re effectively testing LSB of status.

-    if (status & BufferFloat::ERROR_BUFFER_OVERFLOW == BufferFloat::ERROR_BUFFER_OVERFLOW) {
+    if ((status & BufferFloat::ERROR_BUFFER_OVERFLOW) == BufferFloat::ERROR_BUFFER_OVERFLOW) {

This affects reliability of overflow handling.


3995-4042: Add BLUETOOTH power mode case to createModePacket() using existing MODE_BLUETOOTH.

The BLUETOOTH power mode case is missing from createModePacket(). EmotiBitPacket::TypeTag::MODE_BLUETOOTH already exists in the codebase and is actively used elsewhere (e.g., line 1601), so use it directly without a temporary string placeholder.

   else if(getPowerMode() == PowerMode::WIRELESS_OFF)
   {
     payload += EmotiBitPacket::TypeTag::MODE_WIRELESS_OFF;
   }
+  else if (getPowerMode() == PowerMode::BLUETOOTH)
+  {
+    payload += EmotiBitPacket::TypeTag::MODE_BLUETOOTH;
+  }
   else if (getPowerMode() == PowerMode::HIBERNATE)
EmotiBit.h (1)

266-274: Add PowerMode::BLUETOOTH handling to createModePacket().

The createModePacket() function (EmotiBit.cpp:3994-4042) handles NORMAL_POWER, LOW_POWER, MAX_LOW_POWER, WIRELESS_OFF, and HIBERNATE modes (lines 4017-4036), but lacks a case for PowerMode::BLUETOOTH. When the device is in BLUETOOTH mode, no MODE_BLUETOOTH tag is emitted, causing the host/UI to be unaware of the actual power state. Additionally, sendModePacket() (line 4048) always transmits via WiFi regardless of mode, which won't reach clients connected only over Bluetooth.

Add this condition in createModePacket() before the final dataCount++:

else if (getPowerMode() == PowerMode::BLUETOOTH)
{
	payload += EmotiBitPacket::TypeTag::MODE_BLUETOOTH;
}

Also review sendModePacket() to ensure Bluetooth-connected clients receive mode updates (the ToDo comment at line 4047 hints at this broader design need).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 441fbfc and 176cb58.

📒 Files selected for processing (6)
  • EmotiBit.cpp (10 hunks)
  • EmotiBit.h (5 hunks)
  • EmotiBitBluetooth.cpp (1 hunks)
  • EmotiBitBluetooth.h (1 hunks)
  • EmotiBit_stock_firmware/EmotiBit_stock_firmware.ino (1 hunks)
  • board_feather_esp32.ini (1 hunks)
🧰 Additional context used
🪛 Clang (14.0.6)
EmotiBit.cpp

[note] 960-960: +1, including nesting penalty of 0, nesting level increased to 1

(clang)


[note] 967-967: +1, nesting level increased to 1

(clang)


[warning] 960-960: redundant boolean literal supplied to boolean operator

(readability-simplify-boolean-expr)


[note] 1525-1525: +1, including nesting penalty of 0, nesting level increased to 1

(clang)


[note] 1601-1601: +1, nesting level increased to 3

(clang)


[note] 3227-3227: +5, including nesting penalty of 4, nesting level increased to 5

(clang)


[warning] 3860-3860: if with identical then and else branches

(bugprone-branch-clone)


[note] 3867-3867: else branch starts here

(clang)


[warning] 3860-3860: redundant boolean literal supplied to boolean operator

(readability-simplify-boolean-expr)


[warning] 3873-3873: repeated branch in conditional chain

(bugprone-branch-clone)


[note] 4452-4452: +1, nesting level increased to 2

(clang)


[note] 4451-4451: end of the original

(clang)


[note] 4453-4453: clone 1 starts here

(clang)

🪛 GitHub Actions: Build EmotiBit FeatherWing Firmware
EmotiBit.cpp

[error] 1601-1601: EmotiBitPacket::TypeTag does not contain MODE_BLUETOOTH. Compilation failed due to invalid enum value usage.

🔇 Additional comments (3)
board_feather_esp32.ini (1)

11-12: Partition change: confirm trade-offs.

huge_app.csv reduces SPIFFS/OTA space. Verify this is acceptable for your SD/FTP flows and that no OTA or on-device FS is relied upon elsewhere.

EmotiBit_stock_firmware/EmotiBit_stock_firmware.ino (1)

13-24: BLE/Wireless Off toggle logic LGTM.

The button toggles between BLUETOOTH and WIRELESS_OFF when Bluetooth is enabled; otherwise WiFi path toggles as before. Clear and consistent.

EmotiBitBluetooth.cpp (1)

31-33: I'm unable to locate EmotiBitBluetooth.cpp in the public repositories despite multiple attempts. Without access to the actual codebase, I cannot verify:

  1. Which BLE stack is in use (ESP32 Arduino Bluedroid vs NimBLE-Arduino)
  2. The current implementation at lines 31-33 and 112-121
  3. Whether security infrastructure is already configured elsewhere
  4. Whether the MyCallbacks implementation properly handles security

However, the web search results confirm that the review comment's suggested API patterns are accurate:

  • For ESP32 Arduino (Bluedroid): Use setAccessPermissions(ESP_GATT_PERM_WRITE_ENCRYPTED) or setAccessPermissions(ESP_GATT_PERM_WRITE_ENC_MITM) after creating the characteristic
  • For NimBLE-Arduino: Use NIMBLE_PROPERTY::WRITE_ENC when calling createCharacteristic()

Both approaches require security/pairing infrastructure to be enabled on the device.

The security concern raised in the review comment is valid — writable BLE characteristics should require encryption and ideally MITM authentication to prevent unauthorized control writes.

Comment thread EmotiBit.cpp
Comment thread EmotiBit.cpp
Comment thread EmotiBit.cpp Outdated
Comment thread EmotiBit.cpp
Comment thread EmotiBit.cpp Outdated
Comment thread EmotiBitBluetooth.cpp
Comment thread EmotiBitBluetooth.cpp
Comment thread EmotiBitBluetooth.h
Comment thread EmotiBitBluetooth.h
Comment thread EmotiBitBluetooth.h

@produceconsumerobot produceconsumerobot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think our future selves may be significantly less disappointed in our present selves if we refactor setPowerMode to correctly handle BT. I've made suggested changes in the branch feat-blePrototype-Example-fix-setPowerMode

Make sure to highlight in your PR which data integrity tests have been run on SD card data using wifi (normal use-case) in addition to BLE situations.

Please also specify in the PR the battery life when using wifi (and wifi->wireless off) modes.

Comment thread EmotiBit.cpp Outdated
Comment thread EmotiBit.cpp
Comment thread EmotiBit.cpp Outdated
Comment thread EmotiBit.cpp Outdated
Comment thread EmotiBit.cpp Outdated
}

if (getPowerMode() == PowerMode::BLUETOOTH) {
#ifdef ARDUINO_FEATHER_ESP32

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this #ifdef ARDUINO_FEATHER_ESP32?
If we got here, can't we just assume it's a BT compatible board?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the ifdefs here breaks m0

Comment thread EmotiBit.cpp Outdated
// Battery LED
if (battIndicationSeq)
{
led.setState(EmotiBitLedController::Led::YELLOW, true);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to have the Led::YELLOW and Led::RED controls duplicated for PowerMode::BLUETOOTH and not? Seems like one source of truth could be enough.

Comment thread EmotiBit.cpp
Comment thread EmotiBit.cpp
Comment thread EmotiBit.h Outdated
Comment thread EmotiBit.cpp Outdated
@Joseph-Jacobson

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3750fc8d-8fef-4688-8647-37cda11fbc8b

📥 Commits

Reviewing files that changed from the base of the PR and between 441fbfc and dab6c44.

📒 Files selected for processing (9)
  • EmotiBit.cpp
  • EmotiBit.h
  • EmotiBitBluetooth.cpp
  • EmotiBitBluetooth.h
  • EmotiBit_stock_firmware/EmotiBit_stock_firmware.ino
  • README.md
  • WORKFLOWS_AND_SCRIPTS.md
  • board_feather_esp32.ini
  • library.properties

Comment on lines +15 to +23
if (emotibit.getPowerMode() == EmotiBit::PowerMode::BLUETOOTH)
{
emotibit.setPowerMode(EmotiBit::PowerMode::WIRELESS_OFF);
Serial.println("PowerMode::WIRELESS_OFF");
}
else
{
emotibit.setPowerMode(EmotiBit::PowerMode::BLUETOOTH);
Serial.println("PowerMode::BLUETOOTH");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Only log a mode switch after setPowerMode() succeeds.

setPowerMode() now returns bool, but these branches print the target mode unconditionally. If BLE init fails or the transition is rejected, the stock sketch reports a state change that never happened.

🔧 Suggested pattern
-			emotibit.setPowerMode(EmotiBit::PowerMode::WIRELESS_OFF);
-			Serial.println("PowerMode::WIRELESS_OFF");
+			if (emotibit.setPowerMode(EmotiBit::PowerMode::WIRELESS_OFF))
+			{
+				Serial.println("PowerMode::WIRELESS_OFF");
+			}

Apply the same guard to the other three setPowerMode(...) calls in this handler.

Also applies to: 29-37

Comment thread EmotiBit.cpp Outdated
Comment thread EmotiBit.cpp
Comment thread EmotiBit.cpp
Comment thread EmotiBit.cpp Outdated
Comment thread library.properties
@@ -1,5 +1,5 @@
name=EmotiBit FeatherWing
version=1.14.3
version=1.14.4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep the runtime firmware string in sync with the package version.

library.properties now publishes 1.14.4, but Line 61 in EmotiBit.h still reports firmware_version = "1.14.3". That leaves serial output, factory-test metadata, and host-side version checks out of sync with the release you're shipping here.

🔧 Cross-file fix
-  String firmware_version = "1.14.3";
+  String firmware_version = "1.14.4";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth bringing up in review to fix

Comment thread README.md
Comment on lines +20 to +21
## Developer Documentation
- [GitHub Workflows and CI/CD](WORKFLOWS_AND_SCRIPTS.md) - Detailed documentation on automated builds, releases, and bash scripts

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a blank line after the heading to satisfy markdownlint.

MD022 is triggered because the list starts immediately after the heading.

Suggested patch
 ## Developer Documentation
+
 - [GitHub Workflows and CI/CD](WORKFLOWS_AND_SCRIPTS.md) - Detailed documentation on automated builds, releases, and bash scripts
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Developer Documentation
- [GitHub Workflows and CI/CD](WORKFLOWS_AND_SCRIPTS.md) - Detailed documentation on automated builds, releases, and bash scripts
## Developer Documentation
- [GitHub Workflows and CI/CD](WORKFLOWS_AND_SCRIPTS.md) - Detailed documentation on automated builds, releases, and bash scripts
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 20-20: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

Comment thread WORKFLOWS_AND_SCRIPTS.md
Comment on lines +12 to +17
- [Test Scripts](#test-scripts)
- [Development Process](#development-process)
- [Dependency Management Approaches](#dependency-management-approaches)
- [Configuration Files](#configuration-files)
- [Requirements Summary](#requirements-summary)
- [Maintenance Notes](#maintenance-notes)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix broken Table of Contents anchors.

The TOC links for Test Scripts, Configuration Files, Requirements Summary, and Maintenance Notes point to sections that do not exist in this file, so navigation is broken. Either add those sections or remove these TOC entries.

🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 12-12: Link fragments should be valid

(MD051, link-fragments)


[warning] 15-15: Link fragments should be valid

(MD051, link-fragments)


[warning] 16-16: Link fragments should be valid

(MD051, link-fragments)


[warning] 17-17: Link fragments should be valid

(MD051, link-fragments)

Comment thread WORKFLOWS_AND_SCRIPTS.md
Comment on lines +131 to +138
```
EmotiBit FeatherWing Dependency Report
Generated: [timestamp]

LibraryName1: version (git_commit_hash)
LibraryName2: version (git_commit_hash)
...
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add language identifiers to fenced code blocks.

These fenced blocks are missing a language tag (MD040), and this will keep markdownlint failing. Use text (or bash where appropriate) and keep fence spacing consistent.

Suggested patch
-```
+```text
 EmotiBit FeatherWing Dependency Report
 Generated: [timestamp]

 LibraryName1: version (git_commit_hash)
 LibraryName2: version (git_commit_hash)
 ...

@@
- +text

  1. Create feature branch from dev
  2. Make code changes
  3. Push to GitHub → automatic build runs
  4. Download artifacts from Actions tab to test
  5. Iterate on changes (each push triggers new build)
  6. Create pull request to dev
  7. Merge after review and successful build
@@
-```
+```text
1. Update version in library.properties and merge featire branch to dev branch 
2. Push changes → automatic build runs
3. Verify build succeeds on dev
4. Manually trigger "Create Release" workflow
5. Review draft release:
   - Check binaries are correct
   - Review auto-generated dependency information
   - Add/edit release notes as needed
6. Publish release when ready
</details>


Also applies to: 292-300, 303-313

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.22.0)</summary>

[warning] 131-131: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

---

[warning] 131-131: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

<!-- fingerprinting:phantom:triton:hawk:5aa04d8b-5029-4e1f-89a2-989397d8c65c -->

<!-- This is an auto-generated comment by CodeRabbit -->

Comment thread WORKFLOWS_AND_SCRIPTS.md

**Preparing a Release:**
```
1. Update version in library.properties and merge featire branch to dev branch

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Correct typo in release instructions.

Line 304 says featire; it should be feature.

@Joseph-Jacobson

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Apr 18, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (14)
library.properties (1)

2-2: ⚠️ Potential issue | 🟡 Minor

Keep the runtime firmware version in sync with this release.

library.properties publishes 1.14.4, but EmotiBit.h line 60 still reports firmware_version = "1.14.3", so runtime metadata will disagree with the packaged release.

🔧 Cross-file fix
-  String firmware_version = "1.14.3";
+  String firmware_version = "1.14.4";
EmotiBit.h (2)

285-287: 🧹 Nitpick | 🔵 Trivial

Keep the BLE transport member private.

_emotiBitBluetooth is still publicly mutable, so external code can bypass EmotiBit’s mode/lifecycle invariants. Prefer moving it to private and exposing only narrow methods needed by the sketch layer.


438-438: 🧹 Nitpick | 🔵 Trivial

Avoid exposing the Bluetooth mode flag as public mutable state.

_bluetoothEnabled can be toggled externally without coordinating PowerMode, BLE startup, or Wireless Off state. Keep it private and expose a read-only accessor or controlled setter if sketch code needs it.

WORKFLOWS_AND_SCRIPTS.md (2)

5-17: ⚠️ Potential issue | 🟡 Minor

Fix the broken Table of Contents anchors.

The TOC entries for Test Scripts, Configuration Files, Requirements Summary, and Maintenance Notes point to sections that do not exist in this file. Add those sections or remove the links.


131-138: ⚠️ Potential issue | 🟡 Minor

Add code-fence languages and fix the release typo.

These fenced blocks are missing language identifiers, and line 304 says featire instead of feature.

📝 Suggested doc fix
-```
+```text
 EmotiBit FeatherWing Dependency Report
 Generated: [timestamp]
@@
 ...

@@
- +text

  1. Create feature branch from dev
    @@
  2. Merge after review and successful build
@@
-```
-1. Update version in library.properties and merge featire branch to dev branch 
+```text
+1. Update version in library.properties and merge feature branch to dev branch
2. Push changes → automatic build runs
@@
6. Publish release when ready

</details>


Also applies to: 292-300, 303-313

</blockquote></details>
<details>
<summary>README.md (1)</summary><blockquote>

`20-21`: _⚠️ Potential issue_ | _🟡 Minor_

**Add a blank line after the heading.**

Markdownlint still flags `MD022` because the list starts immediately after `## Developer Documentation`.  

<details>
<summary>📝 Suggested doc fix</summary>

```diff
 ## Developer Documentation
+
 - [GitHub Workflows and CI/CD](WORKFLOWS_AND_SCRIPTS.md) - Detailed documentation on automated builds, releases, and bash scripts
EmotiBitBluetooth.h (2)

36-47: 🧹 Nitpick | 🔵 Trivial

Make BLE lifecycle state private.

pServer, characteristic pointers, deviceConnected, _bluetoothOff, _bluetoothReconnect, _connId, and receive buffers are all publicly mutable. External mutation can break connection lifecycle assumptions; expose only narrow read-only accessors if needed.


64-66: 🧹 Nitpick | 🔵 Trivial

Mark the characteristic callback override explicitly.

Declare onWrite under public: and add override so signature drift against BLECharacteristicCallbacks is caught at compile time.

♻️ Proposed header cleanup
 class MyCallbacks : public BLECharacteristicCallbacks {
-        void onWrite(BLECharacteristic *pCharacteristic);
+public:
+        void onWrite(BLECharacteristic *pCharacteristic) override;
 };
EmotiBitBluetooth.cpp (3)

28-30: ⚠️ Potential issue | 🔴 Critical

Guard pService before dereferencing it.

createService() is still used without checking the returned pointer; line 30 dereferences pService immediately. Also reset partial BLE state on any init failure so a later begin() does not treat an incomplete pServer as initialized.

🛡️ Proposed init guard
         BLEService* pService = pServer->createService(EMOTIBIT_SERVICE_UUID);
+        if (!pService)
+        {
+                Serial.println("ERROR: Failed to create BLE service");
+                pServer = nullptr;
+                return 1;
+        }
 
         pDataTxCharacteristic = pService->createCharacteristic(EMOTIBIT_DATA_TX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY);

73-80: ⚠️ Potential issue | 🟠 Major

Buffer incoming writes in onWrite() instead of dropping them.

The TODO describes the production bug: the callback copies rxValue locally and then discards it, so back-to-back writes can overwrite the characteristic before readControl() polls it. Capture each write into the instance buffer or a small queue here.

🔧 Directional fix
-//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());
+                // Append to an EmotiBitBluetooth-owned buffer/queue here.
+                // This callback needs a pointer/reference to the parent instance.
         }
 }

Do you want me to generate the complete header/callback refactor to pass the parent EmotiBitBluetooth* into MyCallbacks?


132-176: ⚠️ Potential issue | 🔴 Critical

Preserve partial and subsequent control packets.

readControl() drains _receivedControlMessage into a local tempPacket; if no delimiter is present, the partial packet is lost. When a delimiter is found, line 160 clears the entire buffer, dropping any packets received after the first delimiter. This breaks fragmented BLE writes and multi-packet bursts.

🐛 Proposed parser fix
 uint8_t EmotiBitBluetooth::readControl(String& packet)
 {
-        uint8_t numPackets = 0;
         packet = "";
-        if (deviceConnected)
+        if (deviceConnected && pDataRxCharacteristic != nullptr)
         {
                 std::string rxValue = pDataRxCharacteristic->getValue();
                 if (!rxValue.empty())
                 {
@@
                         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;
-                                }
-                        }
-                }
+                int delimiterIndex = _receivedControlMessage.indexOf((char)EmotiBitPacket::PACKET_DELIMITER_CSV);
+                if (delimiterIndex >= 0)
+                {
+                        packet = _receivedControlMessage.substring(0, delimiterIndex);
+                        _receivedControlMessage.remove(0, delimiterIndex + 1);
+                        return 1;
+                }
         }
-        return numPackets;
+        return 0;
 }
EmotiBit.cpp (2)

1523-1527: ⚠️ Potential issue | 🔴 Critical

Drain WiFi and BLE control queues independently.

This A || B still skips BLE whenever WiFi returns a packet, and BLE’s readControl() has different semantics than WiFi: it can consume the RX buffer and return only the first packet. Bursts of BLE control packets can be starved or dropped. Extract the packet-processing body and call it from separate WiFi and BLE drain loops. See EmotiBitBluetooth.cpp:132-172 vs EmotiBitWiFi.cpp:435-475.


3846-3899: ⚠️ Potential issue | 🟠 Major

Send mode acknowledgements over the active transport before teardown.

WIRELESS_OFF ends BLE/WiFi before the trailing sendModePacket() runs, and sendModePacket() still sends immediately through WiFi only. A BLE requester won’t receive the mode acknowledgement, and a Wireless Off acknowledgement is attempted after the active radio is already down. Route by the previous active transport, and for WIRELESS_OFF, create/send the mode packet before calling end().

Also applies to: 4057-4062

EmotiBit_stock_firmware/EmotiBit_stock_firmware.ino (1)

13-37: ⚠️ Potential issue | 🟠 Major

Only print the mode change after setPowerMode() succeeds.

These branches still log the target mode unconditionally. If BLE init fails or a transition is rejected, the sketch reports a state that was not entered.

🔧 Proposed fix pattern
-			emotibit.setPowerMode(EmotiBit::PowerMode::WIRELESS_OFF);
-			Serial.println("PowerMode::WIRELESS_OFF");
+			if (emotibit.setPowerMode(EmotiBit::PowerMode::WIRELESS_OFF))
+			{
+				Serial.println("PowerMode::WIRELESS_OFF");
+			}

Apply the same guard to the other setPowerMode(...) calls in this handler.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b4ce63be-6618-41f3-adc2-7a62c610617b

📥 Commits

Reviewing files that changed from the base of the PR and between 441fbfc and ce42cd5.

📒 Files selected for processing (9)
  • EmotiBit.cpp
  • EmotiBit.h
  • EmotiBitBluetooth.cpp
  • EmotiBitBluetooth.h
  • EmotiBit_stock_firmware/EmotiBit_stock_firmware.ino
  • README.md
  • WORKFLOWS_AND_SCRIPTS.md
  • board_feather_esp32.ini
  • library.properties

Comment thread EmotiBit.cpp
Comment thread EmotiBit.h
Comment on lines +454 to +455
//void setPowerMode(PowerMode mode);
bool setPowerMode(PowerMode mode);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove the stale commented-out signature.

The old void setPowerMode(...) declaration can be dropped now that the public API is bool setPowerMode(...); leaving both in the header makes the intended contract less clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants