Skip to content

BLE: BLECharacteristic::setValue() cleanup and optimization #11751

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

Kolcha
Copy link

@Kolcha Kolcha commented Aug 21, 2025

By completing this PR sufficiently, you help us to review this Pull Request quicker and also help improve the quality of Release Notes

Checklist

  1. Please provide specific title of the PR describing the change, including the component name (eg. „Update of Documentation link on Readme.md“)
  2. Please provide related links (eg. Issue which will be closed by this Pull Request)
  3. Please update relevant Documentation if applicable
  4. Please check Contributing guide
  5. Please confirm option to "Allow edits and access to secrets by maintainers" when opening a Pull Request

This entire section above can be deleted if all items are checked.


Description of Change

The change is just a code cleanup following common practices, no behavior change introduced.

  • Pass primitive types to BLECharacteristic::setValue() by value instead of by non-const reference.
    There is no technical need to passing values by non-const reference there, non-const reference makes usage inconvenient (function return can't be passed directly as argument, temporary variable required), passing by value eliminates this inconvenience.
  • Don't create temporary variables in setValue() implementations for primitive types.
    There is no technical need to create all those temporary variables, the address of the argument can be used directly. Such "integer to array" conversion is not required, because it basically does nothing, as ESP32 is little-endian architecture.
  • Pass pointer to const data to setValue()
    There is no technical need to pass non-const data there. This allows to pass the data from read-only sources without removing the constness what is not always safe.
  • Avoid unnecessary String copies
    Pass String by const reference to many setValue() functions to avoid copying it.

Test Scenarios

I have tested my Pull Request on Arduino-esp32 core v3.3.0 with ESP32 Board with this scenario:

  • Successful build of the project which uses BLE.
  • Created BLE service with 8 characteristics, 4 of them are uint16_t and 4 are float

Related links

nothing related found

@CLAassistant
Copy link

CLAassistant commented Aug 21, 2025

CLA assistant check
All committers have signed the CLA.

Copy link
Contributor

github-actions bot commented Aug 21, 2025

Messages
📖 🎉 Good Job! All checks are passing!

👋 Hello Kolcha, we appreciate your contribution to this project!


📘 Please review the project's Contributions Guide for key guidelines on code, documentation, testing, and more.

🖊️ Please also make sure you have read and signed the Contributor License Agreement for this project.

Click to see more instructions ...


This automated output is generated by the PR linter DangerJS, which checks if your Pull Request meets the project's requirements and helps you fix potential issues.

DangerJS is triggered with each push event to a Pull Request and modify the contents of this comment.

Please consider the following:
- Danger mainly focuses on the PR structure and formatting and can't understand the meaning behind your code or changes.
- Danger is not a substitute for human code reviews; it's still important to request a code review from your colleagues.
- To manually retry these Danger checks, please navigate to the Actions tab and re-run last Danger workflow.

Review and merge process you can expect ...


We do welcome contributions in the form of bug reports, feature requests and pull requests.

1. An internal issue has been created for the PR, we assign it to the relevant engineer.
2. They review the PR and either approve it or ask you for changes or clarifications.
3. Once the GitHub PR is approved we do the final review, collect approvals from core owners and make sure all the automated tests are passing.
- At this point we may do some adjustments to the proposed change, or extend it by adding tests or documentation.
4. If the change is approved and passes the tests it is merged into the default branch.

Generated by 🚫 dangerJS against 5edf464

@Kolcha Kolcha force-pushed the ble-cleanup branch 2 times, most recently from 05c13c0 to 3fa7ff5 Compare August 21, 2025 10:02
There is no need to pass primitive types by reference,
especially by non-const reference as it was in BLECharacteristic.

Pass primitive types by value instead, as it should be,
and used everywhere else except this one odd class.

This allows allows to pass function result as `setValue()`
argument without creating temporary variable.
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR optimizes the BLECharacteristic::setValue() methods by changing parameter passing from non-const references to pass-by-value for primitive types and simplifying the implementation by directly using parameter addresses instead of creating temporary variables.

  • Changes parameter passing from non-const reference to pass-by-value for primitive types (uint16_t, uint32_t, int, float, double)
  • Removes manual bit manipulation and temporary array creation in favor of direct memory address usage
  • Leverages ESP32's little-endian architecture to eliminate unnecessary byte-by-byte copying

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.

File Description
libraries/BLE/src/BLECharacteristic.h Updates method signatures to pass primitive types by value instead of non-const reference
libraries/BLE/src/BLECharacteristic.cpp Simplifies implementation by using direct parameter addresses and sizeof() instead of manual byte manipulation

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 21, 2025

It may be worth to test and verify it using other MCU SoCs, such as ESP32-S3 and ESP32-C3.
The proposed change has to do with making sure that the correct endianness (little and big endian) is used.

Based on BLE specification, it shall be little-endian, therefore if you try sending an int value, you will see that the hex values are arranged in little-endian format. The "human readable" value 0xAABBCCDD will for instance be transmitted and received as 0xDDCCBBAA.

The change takes into consideration the MCU endianless when compiling the code.

  • ESP32 is little-endian, therefore the PR proposed change works fine.
  • RISC-V is designed to be little-endian as default as well (C3/C6/C5/P4)
  • ESP32-S3 shall be also little-endian, therefore it shall work fine.

Copy link
Contributor

github-actions bot commented Aug 21, 2025

Test Results

 76 files   76 suites   13m 8s ⏱️
 38 tests  38 ✅ 0 💤 0 ❌
241 runs  241 ✅ 0 💤 0 ❌

Results for commit 5edf464.

♻️ This comment has been updated with latest results.

Copy link
Contributor

Memory usage test (comparing PR against master branch)

The table below shows the summary of memory usage change (decrease - increase) in bytes and percentage for each target.

MemoryFLASH [bytes]FLASH [%]RAM [bytes]RAM [%]
TargetDECINCDECINCDECINCDECINC
ESP32C5000.000.00000.000.00
ESP32S3000.000.00000.000.00
ESP32C3000.000.00000.000.00
ESP32C6000.000.00000.000.00
ESP32H2000.000.00000.000.00
ESP32000.000.00000.000.00
Click to expand the detailed deltas report [usage change in BYTES]
TargetESP32C5ESP32S3ESP32C3ESP32C6ESP32H2ESP32
ExampleFLASHRAMFLASHRAMFLASHRAMFLASHRAMFLASHRAMFLASHRAM
libraries/BLE/examples/Beacon_Scanner------------
libraries/BLE/examples/Client------------
libraries/BLE/examples/EddystoneTLM_Beacon------------
libraries/BLE/examples/EddystoneURL_Beacon------------
libraries/BLE/examples/Notify------------
libraries/BLE/examples/Scan------------
libraries/BLE/examples/Server------------
libraries/BLE/examples/Server_multiconnect------------
libraries/BLE/examples/UART------------
libraries/BLE/examples/Write------------
libraries/BLE/examples/iBeacon------------

Copy link
Collaborator

@SuGlider SuGlider left a comment

Choose a reason for hiding this comment

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

Using C++ reinterpret_cast<uint8_t*> instead.

@SuGlider
Copy link
Collaborator

Another suggestion of change here (using reinterpret_cast<uint8_t*>):

void BLECharacteristic::setValue(String value) {
  setValue(reinterpret_cast<uint8_t*>(value.c_str()), value.length());
}  // setValue

ESP32 is little-endian architecture, so the code that filled
temporary arrays created from integers basically did nothing.

Pass primitives as 'buffers' to generic `setValue()` instead.

Also use sizeof() instead of hardcoded sizes as the argument.
Kolcha added 2 commits August 22, 2025 05:54
There is no technical need to pass non-const data there.

Also it is a common practice to pass const data to the functions
with write semantics, as they not supposed to modify the data.

This allows to pass the data from read-only sources without
removing the constness what is not always safe.
Pass String by const reference to many `setValue()` functions
to avoid copying it.

Even there are not so much data inside these strings, it just
looks too odd to copy them every time.

Also this change decreases binary size (~200 bytes in my case).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants