Fix NimBLEEddystoneTLM byte-order mismatch between getters and setters#431
Fix NimBLEEddystoneTLM byte-order mismatch between getters and setters#43194xhn wants to merge 2 commits into
Conversation
m_eddystoneData must always hold Eddystone-TLM wire-format (big-endian) bytes, since getData() returns it directly for the caller to memcpy straight into the BLE advertisement payload (see the BLE_EddystoneTLM_Beacon example), and setData()/getData() already treat it as raw wire bytes. The getters (getVolt/getTemp) correctly un-swap on read, but the setters (setVolt/setTemp/setCount/setTime) stored their host-order input directly with no swap, and the BeaconData default member initializers were host-order values instead of pre-swapped wire-format values. This breaks the setter/getter round trip for any value set locally (as opposed to arriving over the air via setData()), and means a freshly constructed object reports a garbage battery voltage. toString() also failed to un-swap the temperature field at all, and used unsigned division/modulo on a signed 8.8 fixed-point value, producing garbage output for negative temperatures. This mirrors the existing, correct pattern already used by the sibling NimBLEBeacon class, which swaps in its setters (setMajor/setMinor/ setManufacturerId). Fix: - setVolt/setTemp/setCount/setTime now apply ENDIAN_CHANGE_U16/U32 to their input before storing, matching what the getters already assume. - BeaconData's default volt/temp member initializers are now the wire-format (byte-swapped) encoding of the intended defaults (3300 mV, 23.0C), so a freshly constructed object reports correct values without calling a setter first. - toString() now swaps the temperature field the same way it already swaps voltage, and computes the displayed magnitude from a signed value with explicit sign handling instead of unsigned arithmetic on the raw field. No change to the over-the-air byte layout: setData()/getData() still operate on raw wire-format bytes exactly as before.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughArrr, Eddystone TLM fields now store endian-adjusted wire values, while temperature rendering handles signed fixed-point data correctly. ChangesEddystone TLM endian handling
Estimated code review effort: 3 (Moderate) | ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/NimBLEEddystoneTLM.cpp`:
- Around line 104-109: Update the temperature format string in the value
formatting logic to render the fractional component with two digits, preserving
leading zeros for values below 10. Keep the existing sign, integer, and fraction
calculations unchanged.
In `@src/NimBLEEddystoneTLM.h`:
- Around line 40-41: Update the default member initializers for the voltage and
temperature fields in the Eddystone TLM data structure to pass the host-order
values (3300 mV and 23 × 256) through ENDIAN_CHANGE_U16 instead of using
pre-swapped literals. Ensure the header exposes the macro through the
appropriate existing include or definition, while preserving the current
wire-format behavior and getter conversions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 82247566-3e01-4d99-b92e-76705f2aba12
📒 Files selected for processing (2)
src/NimBLEEddystoneTLM.cppsrc/NimBLEEddystoneTLM.h
A one-digit fractional component changed the displayed value; for example, 23.05 C was rendered as 23.5 C. Constraint: Eddystone temperature uses signed 8.8 fixed point Confidence: high Scope-risk: narrow Tested: seven positive/negative boundaries; MinGW GCC 8 -Werror Not-tested: hardware advertisement display
Problem
NimBLEEddystoneTLM::m_eddystoneDatais meant to always hold Eddystone-TLM wire-format (big-endian) bytes:getData()returns it directly for the caller tomemcpystraight into the BLE advertisement payload (see theBLE_EddystoneTLM_Beaconexample in the sibling NimBLE-Arduino repo), andsetData()/getData()already treat it purely as raw wire bytes with no conversion.The getters (
getVolt()/getTemp()) correctly un-swap on read viaENDIAN_CHANGE_U16. But the setters (setVolt/setTemp/setCount/setTime) store their host-order input with no swap, and theBeaconDatadefault member initializers (volt{3300},temp{23 * 256}) are host-order values, not pre-swapped wire-format values.Effects of this mismatch:
NimBLEEddystoneTLM(before calling any setter) reportsgetVolt() == 58380instead of the intended default3300.setTemp(23 * 256); getTemp();returns23, not5888— the setter/getter round trip is broken for any value set locally (as opposed to arriving over the air viasetData()).toString()never un-swaps the temperature field at all, and computes the displayed magnitude with unsigned division/modulo (m_eddystoneData.temp / 256) on a signed 8.8 fixed-point value, so negative temperatures print garbage.setVolt/setTempand then transmitsgetData()'s raw bytes directly, the actual over-the-air TLM battery/temperature values are corrupted for any real device using this class today.This is the same class of bug fixed for the
float-based API prior to theint16_t-based refactor in #248, which reintroduced it.The sibling
NimBLEBeaconclass already applies the swap in its setters (setMajor/setMinor/setManufacturerId) for the same reason — this fix bringsNimBLEEddystoneTLMin line with that existing, working pattern.Fix
setVolt/setTemp/setCount/setTimenow applyENDIAN_CHANGE_U16/ENDIAN_CHANGE_U32to their input before storing, matching what the getters already assume.BeaconData's defaultvolt/tempmember initializers are now the wire-format (byte-swapped) encoding of the intended defaults (3300 mV, 23.0°C), so a freshly constructed object reports correct values without calling a setter first.toString()now swaps the temperature field the same way it already swaps voltage, and computes the displayed magnitude from a signed value with explicit sign handling instead of unsigned arithmetic on the raw field.No change to the over-the-air byte layout —
setData()/getData()still operate on raw wire-format bytes exactly as before; only host-order local access via the individual setters/getters/toString()is fixed.Testing
Verified with a standalone host-compiled (g++ -std=c++17) test extracting the exact struct/macro/getter/setter/toString logic:
getVolt() == 3300,getTemp() == 5888,toString()prints "Battery Voltage 3300 mV" / "Temperature 23.0 C".setVolt(4000)/setTemp(5888)round-trip exactly.setTemp(-26)(-0.1015625°C) round-trips exactly andtoString()prints "Temperature -0.10 C".setTemp(-1408)(-5.5°C) round-trips exactly andtoString()prints "Temperature -5.50 C".setData()with wire-format big-endian bytes (simulating a real radio) is unaffected and still correctly returnsgetVolt() == 3300,getTemp() == 5888.Also syntax-checked the actual modified
src/NimBLEEddystoneTLM.cpp/.hagainst the real header dependencies (with minimal local stubs forNimBLEUUID.h/NimBLELog.h/syscfg.h) — compiles cleanly with-Wall -Wextra.Summary by CodeRabbit