Skip to content

feat(wdi): Wheelchair Digital Interface component (device role: USB + BLE) - #788

Merged
finger563 merged 13 commits into
mainfrom
feat/wdi
Sep 12, 2026
Merged

feat(wdi): Wheelchair Digital Interface component (device role: USB + BLE)#788
finger563 merged 13 commits into
mainfrom
feat/wdi

Conversation

@finger563

Copy link
Copy Markdown
Contributor

What

New wdi component implementing the Open-Mobility-Hub Wheelchair HID spec (v3.2) — a standard interface between a powered wheelchair and an app/accessory over USB or BLE. This PR is the device role (the app / accessory that drives the chair) over both transports; the host role (the wheelchair) is a follow-up.

Layers

  • Protocol core (detail/wdi_protocol.hpp) — host-testable, ESP-free: the five reports (Control/Feedback/Request-Feedback/Keepalive/Keepalive-Response) as structs with serialize()/parse(), the ControlBit/FeedbackBit enums, manufacturer IDs, keepalive timing. LE fields; the 128-bit Host UUID stays big-endian per spec.
  • HID report descriptor (wdi_hid.hpp) — the vendor (usage page 0xFF00) descriptor built with hid-rp.
  • Device role core (WdiDevice, wdi.hpp) — transport-agnostic: a send callback + handle_output(), with the keepalive state machine (poll() emits keepalives when due; send_control/request_feedback reset the timer). No internal timer, so it's host-testable via an injected clock.
  • BLE peripheral (WdiBlePeripheral, wdi_ble.hpp) — the WDI GATT service on ble_gatt_server + ble_example/.
  • USB HID device (WdiUsbPeripheral, wdi_usb.hpp) — the WDI HID descriptor on espp::UsbDevice (Input reports out; Output reports in via HidFunction::on_receive) + usb_example/.

Host library / interop

The protocol core is bundled into the espp host library: C++ via wdi/include, Python via espp.wdi bindings (ControlReport/FeedbackReport/HostUuid + enums, serialize/parse) — enough to build/test a WDI host on a PC. Tests: test/wdi_protocol_host_test.cpp, test/wdi_device_host_test.cpp, test/wdi_hid_host_test.cpp, python/wdi_test.py.

Notes

Both examples build clean on IDF v6.1 / esp32s3. Wheelchairs are safety-critical: the component can emulate a WDI device for development — see the README's safety note. Host role (USB Host HID + BLE central) to follow.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU

finger563 and others added 6 commits September 11, 2026 20:38
New `wdi` component implementing the Open-Mobility-Hub Wheelchair HID spec
(v3.2). This first commit is the host-testable, ESP-free protocol core shared by
every transport (USB / BLE) and role (device / host):

- The five HID reports (Control 0x01, Feedback 0x02, Request Feedback 0x03,
  Keepalive 0x04, Keepalive Response 0x05) as structs with serialize()/parse().
- ControlBit / FeedbackBit bitfield enums, ManufacturerId, keepalive timing
  constants, and the shared HID report descriptor (usage page 0xFF00) built with
  std::to_array so its length is deduced.
- Little-endian report fields; the 128-bit Host UUID kept big-endian per spec.
- Host unit test covering report round-trips, nibble packing (speed/profile,
  velocity), release/zero reports, wrong-size rejection, the descriptor shape,
  and the big-endian manufacturer id. Builds + passes with plain c++ -std=c++20
  -Wall -Wextra -Werror.

Component skeleton (CMakeLists / idf_component.yml / README) registers the
include dir; the device role (USB HID + BLE peripheral) and host role follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
WdiDevice is the app / accessory side of the WDI interface. Transport-agnostic:
a `send` callback puts a report on the wire (USB HID Input report or BLE notify),
and handle_output() consumes the host's reports (Feedback 0x02, Keepalive
Response 0x05). It owns the keepalive state machine:

- send_control() / send_release() / request_feedback() / send_keepalive() build
  and transmit the reports; Control / Request-Feedback / Keepalive all reset the
  keepalive timer (per spec), and a failed send does NOT reset it.
- poll() emits a Keepalive when the interval (~233 ms) has elapsed since the last
  transmit; ms_until_keepalive() reports the remaining time. No internal timer --
  call poll() from an espp::Timer / Task on device (kept out of the core so it is
  host-testable). Time comes from a caller-supplied clock (default steady ms).
- handle_output() parses + routes Feedback / Keepalive Response, stores the host
  UUID + last feedback, and ignores wrong-direction / malformed reports.

Depends only on the C++20 stdlib + the protocol core, so it is unit-tested on a
host (fake clock + mock send): control-resets-timer, keepalive timing edges,
request-feedback reset, failed-send behavior, and feedback/UUID routing. Passes
under -Wall -Wextra -Werror. USB / BLE transport bindings + examples follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
Replace the hand-rolled report-descriptor bytes with an idiomatic hid-rp
descriptor (new wdi_hid.hpp): a custom vendor usage page (0xFF00) + one report
item per report id, using the same raw-vendor-usage idiom as the espp switch-pro
descriptor. Removed the hand-written kReportDescriptor from the dependency-free
core (detail/wdi_protocol.hpp) — only the USB HID transport needs a descriptor
(BLE carries the same reports as GATT characteristics), so wdi_hid.hpp (which
pulls in hid-rp) is separate and the core / BLE path stays hid-rp-free.

hid-rp is header-only + stdlib-only, so wdi_hid.hpp is still host-testable
(add hid-rp as -isystem so its non-Werror-clean third-party headers don't break
-Werror). The new host test asserts the built descriptor's structure (vendor
page, 5 report ids, per-report counts 18/19/1/1/16, 3 Input + 2 Output items);
it comes out to the same 55 bytes as the hand-verified descriptor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
Make the WDI core available off-device for CI/interop testing and for building a
WDI host (the wheelchair side) on a PC to test a real peripheral against:

- C++ host library: add components/wdi/include to ESPP_INCLUDES (header-only;
  no sources). WdiDevice + the protocol structs are now on the host lib's include
  path. hid-rp (for wdi_hid.hpp) is already an ESPP include.
- Python: hand-written pybind11 bindings (lib/python_bindings/wdi_bindings.cpp,
  registered via py_init_wdi in module.cpp, added to ESPP_PYTHON_SOURCES) exposing
  espp.wdi.{ReportId, ControlBit, FeedbackBit, ManufacturerId, ControlReport,
  FeedbackReport, HostUuid} with serialize()/parse() -- enough to build/test a WDI
  host from Python. Kept out of the generated bindings (like dispatcher_bindings).
  Compiles clean against pybind11.
- python/wdi_test.py: Python mirror of the C++ host test (report round-trips,
  nibble packing, host-uuid big-endian, and a parse-Control/build-Feedback
  host-side round-trip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
WdiBlePeripheral (wdi_ble.hpp) wraps the transport-agnostic WdiDevice with the WDI
GATT service on esp-nimble-cpp / espp::BleGattServer:

- Service 10A50001-…, characteristics 10A5000{6..A}. Control / Request-Feedback /
  Keepalive are READ|NOTIFY (device→central); Feedback / Keepalive-Response are
  READ|WRITE_NR (central→device).
- WdiDevice's send is wired to characteristic notify(); the write characteristics'
  NimBLECharacteristicCallbacks route received bytes into WdiDevice.handle_output().
  App API forwards send_control / request_feedback / poll / host_uuid.

Adds ble_example/ (esp32s3): brings up BleGattServer, installs + advertises the WDI
service, and sweeps a demo joystick with drive-enable while polling keepalives.
Builds clean on IDF v6.1 (67% flash free).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
WdiUsbPeripheral (wdi_usb.hpp) wraps the transport-agnostic WdiDevice with an
espp::UsbDevice HID interface using the WDI report descriptor (wdi_hid.hpp):

- Control / Request-Feedback / Keepalive are HID Input reports (device->host via
  write_hid_report()); Feedback / Keepalive-Response are HID Output reports
  (host->device) delivered through HidFunction::on_receive (has_out_endpoint) --
  the usb_device HID-OUT support merged with switch_pro (#787). The report id is
  byte 0 of the received span; the rest is routed to WdiDevice.handle_output().
- App API forwards send_control / request_feedback / poll / host_uuid.

Adds usb_example/ (esp32s3): enumerates as a WDI HID device and sweeps a demo
joystick with drive-enable while polling keepalives. Console on UART0 (native USB
goes to TinyUSB). Builds clean on IDF v6.1 (58% flash free).

feat/wdi is rebased on main (which now has the usb_device HID-OUT extension).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
Copilot AI lite review requested due to automatic review settings September 12, 2026 03:08
@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown

✅Static analysis result - no issues found! ✅

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Critical protocol, safety, transport, dependency, and integration issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds the WDI v3.2 device-role component for USB HID and BLE, including protocol logic, peripherals, bindings, examples, and tests.

Changes:

  • Implements report serialization, parsing, HID descriptors, and device state management.
  • Adds BLE and USB peripheral adapters with ESP32 examples.
  • Adds C++/Python bindings and host-side tests.
File summaries
File Description and final review notes
python/wdi_test.py Python binding tests. moderate (1 vote): not included in automated Python testing.
lib/python_bindings/wdi_bindings.cpp WDI Python API bindings.
lib/python_bindings/module.cpp Registers WDI bindings.
lib/espp.cmake Host include and binding integration.
components/wdi/usb_example/sdkconfig.defaults USB/TinyUSB configuration.
components/wdi/usb_example/main/wdi_usb_example.cpp USB example. critical (2 votes): starts with forward motion enabled; default should send a release and make motion opt-in.
components/wdi/usb_example/main/CMakeLists.txt USB example dependencies.
components/wdi/usb_example/CMakeLists.txt USB example project configuration.
components/wdi/test/wdi_protocol_host_test.cpp Protocol host tests.
components/wdi/test/wdi_hid_host_test.cpp HID descriptor tests.
components/wdi/test/wdi_device_host_test.cpp Device-state host tests.
components/wdi/README.md Component documentation and safety guidance.
components/wdi/include/wdi.hpp Device state machine. critical (1 vote): enforce the 100 ms release interval; synchronize cross-task state, callbacks, and keepalive timestamps; persist and validate host identity before transmitting.
components/wdi/include/wdi_usb.hpp USB peripheral wrapper.
components/wdi/include/wdi_hid.hpp HID descriptor. critical (2 votes): expose required per-report fields and usages instead of opaque byte arrays.
components/wdi/include/wdi_ble.hpp BLE peripheral. critical (1 vote): persist and validate host identity, stop reports on mismatch, and delay advertising. critical (1 vote): add mandatory characteristics 0x02–0x05 and the report map.
components/wdi/include/detail/wdi_protocol.hpp Protocol reports and serialization. nit (2 votes): correct the Modifier/vendor1 comment. moderate (1 vote): reject or represent reserved velocity fractions as unknown.
components/wdi/idf_component.yml Registry metadata. critical (3 votes): declare public NimBLE, HID-RP, and USB dependencies. moderate (1 vote): add examples to build CI and the component to the upload allowlist. moderate (1 vote): add the component to the explicit upload list. nit (1 vote): accurately describe the implemented device role. nit (2 votes) and moderate (1 vote): add documentation, Doxygen, build-matrix, and publishing entries.
components/wdi/CMakeLists.txt Component build metadata. critical (3 votes): declare esp-nimble-cpp, hid-rp, and usb_device as public dependencies.
components/wdi/ble_example/sdkconfig.defaults.esp32s3 ESP32-S3 BLE configuration.
components/wdi/ble_example/sdkconfig.defaults BLE configuration.
components/wdi/ble_example/partitions.csv BLE partition layout.
components/wdi/ble_example/main/wdi_ble_example.cpp BLE example. critical (2 votes): starts with forward motion enabled; default should send a release and make motion opt-in.
components/wdi/ble_example/main/CMakeLists.txt BLE example dependencies.
components/wdi/ble_example/CMakeLists.txt BLE example project configuration. moderate (1 vote): add both examples to the build matrix.
Review details

Suppressed comments (7)

components/wdi/ble_example/CMakeLists.txt:22

  • Neither newly added example is present in the build matrix (build.yml), so the claimed BLE and USB example builds are not exercised by CI and compile/configuration regressions can merge unnoticed. Add matrix entries for both components/wdi/ble_example and components/wdi/usb_example (the repository adds one entry per example project).
project(wdi_ble_example)

set(CMAKE_CXX_STANDARD 20)

components/wdi/idf_component.yml:11

  • The two new example paths are not present in .github/workflows/build.yml, and components/wdi is not present in .github/workflows/upload_components.yml. Consequently neither transport example is compiled by the example matrix, and the component is excluded from the registry dry-run/release allowlist despite being advertised in this manifest. Add both examples to build CI and add components/wdi to the upload list.
examples:
  - path: ble_example
  - path: usb_example

components/wdi/idf_component.yml:11

  • upload_components.yml uses an explicit allowlist for both PR dry-run validation and release publication, but no components/wdi entry is added in this PR. As a result, this new manifest will never be validated or uploaded by the repository's component publishing workflow; add the component to that list.
examples:
  - path: ble_example
  - path: usb_example

components/wdi/idf_component.yml:3

  • The manifest description says this component provides host roles over USB and BLE, while the PR explicitly leaves USB Host HID and BLE central support for a follow-up and the README marks that role unimplemented. Published metadata should describe the currently implemented protocol core and device role rather than overstate the available API.
description: "Wheelchair Digital Interface (WDI / Open-Mobility-Hub Wheelchair HID): report protocol + device and host roles over USB and BLE"

components/wdi/idf_component.yml:11

  • This new component is not referenced by .github/workflows/build.yml, .github/workflows/upload_components.yml, or doc/Doxyfile, and no doc/en WDI page exists. Consequently the advertised documentation URL is dead, the examples are absent from the normal build matrix, and the component is absent from the explicit publishing allowlist. Add the required documentation, Doxygen, build, and upload entries before publishing the component.
documentation: "https://esp-cpp.github.io/espp/wdi/wdi.html"
examples:
  - path: ble_example
  - path: usb_example

components/wdi/include/detail/wdi_protocol.hpp:219

  • The velocity fraction reserves nibble values 0xA–0xF, but this parser accepts them and velocity_mph() then reports impossible values such as 15.5 mph for 0xF. Reject reserved fractions when parsing/serializing, or represent them as unknown so the helper cannot expose an invalid speed.
    r.speed = static_cast<uint8_t>((p[12] >> 4) & 0x0F);
    r.profile = static_cast<uint8_t>(p[12] & 0x0F);
    r.velocity_whole = static_cast<uint8_t>((p[13] >> 4) & 0x0F);
    r.velocity_tenths = static_cast<uint8_t>(p[13] & 0x0F);

python/wdi_test.py:5

  • This new binding test is not part of the automated Python test command: pyproject.toml runs rtps_bindings_smoke.py and dispatcher_test.py, but never wdi_test.py. Add this script to the wheel/CI smoke test so the newly exposed espp.wdi API is checked instead of remaining a manual-only test.
"""WDI (Wheelchair Digital Interface) Python binding test.

Exercises the espp.wdi protocol core (ControlReport / FeedbackReport / HostUuid
serialize+parse, bitfields, enums) -- the Python mirror of
components/wdi/test/wdi_protocol_host_test.cpp. This is also how a WDI *host* (the
  • Files reviewed: 25/25 changed files
  • Comments generated: 13
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread components/wdi/CMakeLists.txt
Comment thread components/wdi/ble_example/main/wdi_ble_example.cpp Outdated
Comment thread components/wdi/idf_component.yml
}

/// @brief Send an all-zero "release" Control report (neutral joystick, no flags).
bool send_release() { return send_control(wdi::ControlReport{}); }
Comment on lines +119 to +123
case wdi::ReportId::KeepaliveResponse:
if (auto uuid = wdi::HostUuid::parse(payload)) {
host_uuid_ = *uuid;
if (config_.on_keepalive_response)
config_.on_keepalive_response(*uuid);
Comment on lines +120 to +123
break;
default:
return false; // host->device reports are not sent by the device
}
Comment thread components/wdi/include/wdi_hid.hpp Outdated
Comment thread components/wdi/usb_example/main/wdi_usb_example.cpp Outdated
Comment thread components/wdi/idf_component.yml
Comment thread components/wdi/include/detail/wdi_protocol.hpp Outdated
finger563 and others added 2 commits September 11, 2026 23:26
Address review feedback + static analysis on the WDI device role.

- wdi_hid.hpp: rebuild the report descriptor to describe the REAL report fields
  (Control = 2x SInt8 axes + 4x 32-bit flag fields; Feedback = 3x 32-bit flags +
  packed speed/profile, velocity, odometer + 4 reserved bytes; etc.) instead of
  opaque byte arrays, so a host can introspect it. static_asserts tie the field
  decomposition to the protocol core's report sizes so the descriptor and
  serialize()/parse() can't drift. Descriptor is now 156 bytes.
- wdi_ble.hpp: add the HID-over-GATT characteristics the WDI spec defines
  (10A50002 Report Map, 10A50003 HID Information, 10A50004 HID Control Point,
  10A50005 Protocol Mode). The Report Map serves the SAME descriptor as USB, so
  BLE reports are introspectable too. notify_report() made const.
- wdi.hpp: fix data races between the transport RX task and the app task -
  last_tx_ms_ is atomic; host_uuid_ / last_feedback_ are mutex-guarded.
- detail/wdi_protocol.hpp: HostUuid::serialize() returns by const reference
  (returnByReference); clarify the vendor1 Modifier comment (the spec defines a
  vendor-scope Modifier bit distinct from standard1's).
- examples: send a neutral release first and do NOT assert DriveEnable in the
  demo sweep (a spec-compliant chair ignores motion without DriveEnable), so the
  test pattern can't command motion on connect.
- suppressions.txt: scope unreadVariable/redundantAssignment for the host tests
  (cppcheck can't see reads through the injected-clock std::function).
- README: document the field-accurate descriptor, the HOGP characteristics, and
  the per-transport component dependencies.

Descriptor + all host tests pass; usb_example (58% free) and ble_example (67%
free) build clean on IDF v6.1 esp32s3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
…tion

The Report Map characteristic serves the HID descriptor over BLE too, so the
descriptor is not USB-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
@finger563

Copy link
Copy Markdown
Contributor Author

Addressed the review + static-analysis feedback in the latest commits. Summary of dispositions:

Fixed

  • Opaque HID descriptor → rebuilt wdi_hid.hpp to describe the real fields (Control = 2× SInt8 axes + 4× 32-bit flag fields; Feedback = 3× 32-bit flags + speed/profile + velocity + odometer + 4 reserved; etc.), with static_asserts tying the field decomposition to the protocol-core report sizes so descriptor and serialize()/parse() can't drift. Descriptor is now 156 bytes.
  • Missing HID-over-GATT characteristics → added 10A50002 Report Map (serving the same descriptor as USB), 10A50003 HID Information, 10A50004 HID Control Point, 10A50005 Protocol Mode to WdiBlePeripheral.
  • Thread-safety (handle_output vs getters; keepalive timer) → last_tx_ms_ is atomic; host_uuid_/last_feedback_ are mutex-guarded.
  • HostUuid::serialize() returnByReference, notify_report() made const, useStlAlgorithm in the test.
  • Example safety → examples send a neutral release first and no longer assert DriveEnable in the demo sweep (a spec-compliant chair ignores motion without it), so the test pattern can't command motion on connect.
  • Test-harness cppcheck false positives (unreadVariable/redundantAssignment through the injected-clock std::function) scoped in suppressions.txt.

Clarified (not a bug)

  • vendor1 "Modifier" comment: the spec defines a vendor-scope Modifier at bit 0 of the VendorSpecific field, distinct from ControlBit::Modifier in standard1 — both exist. Comment reworded to make that explicit rather than changed.
  • Component REQUIRES/manifest deps: kept the core at REQUIRES base_component by design so a protocol-only (or single-transport) consumer doesn't pull in the BLE + USB stacks. The transport headers' dependencies are now documented in a README table and declared by each example.

Deferred to a follow-up (tracked)

  • 100 ms release-timing rule: this is an app-level send-cadence constraint; enforcing it inside the library would require inserting artificial delays and could mask real app bugs, so it's left as the caller's responsibility (documented).
  • Host-UUID save / mismatch handling + 15 s advertising delay: a reconnection-security feature (persist the first host UUID, gate transmission on mismatch, delay re-advertising). Larger than this PR's scope; planned as a follow-up.
  • Docs page / Doxyfile / CI wiring for the whole wdi component is added in the stacked host-role PR feat(wdi): host role (WdiHost) — USB Host HID + BLE central #792.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU

@finger563
finger563 requested a balanced review from Copilot September 12, 2026 04:32
NimBLEService::createCharacteristic() can return nullptr (e.g. out of memory).
Guard all of the WDI characteristics before dereferencing them (setValue /
setCallbacks), bailing with a logged error, instead of an unconditional
null-deref. Addresses a review comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 26 out of 26 changed files in this pull request and generated 13 comments.

Comment thread components/wdi/include/wdi.hpp
Comment thread components/wdi/include/wdi.hpp
Comment thread components/wdi/include/wdi.hpp
Comment thread components/wdi/include/detail/wdi_protocol.hpp Outdated
Comment thread components/wdi/include/detail/wdi_protocol.hpp
Comment thread lib/python_bindings/wdi_bindings.cpp
Comment thread components/wdi/ble_example/CMakeLists.txt
Comment thread components/wdi/test/wdi_hid_host_test.cpp Outdated
Comment thread lib/python_bindings/wdi_bindings.cpp
Comment thread lib/python_bindings/wdi_bindings.cpp
finger563 and others added 3 commits September 12, 2026 00:22
…nst)

Now that notify_report() is const, the make_device_config() helper only calls
const members, so cppcheck flags it as const-able. Make it const.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
Address the second review round:
- FeedbackReport::serialize() clamps velocity_tenths to 9 so an out-of-range
  value can't encode an invalid 10..15 nibble.
- Python bindings: parse() takes py::bytes instead of std::string, so a Python
  str can't be passed and silently UTF-8-encoded into wrong bytes; add <array>.
- wdi_hid_host_test.cpp: correct the "non-overlapping" comment on count_item.

Protocol + HID host tests pass; bindings syntax-check against pybind11.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
…mBLEService::start()

NimBLE v2 starts every service when the server starts; NimBLEService::start()
is a deprecated no-op. Keep start() for API symmetry with make_service() but
make it an explicit no-op instead of calling the deprecated API.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
@finger563

Copy link
Copy Markdown
Contributor Author

Self-review follow-up (pushed): WdiBlePeripheral::start() no longer calls the deprecated no-op NimBLEService::start(). The device-role code was reviewed alongside the host role (protocol packing, RFC-4122 nibbles, keepalive math, peripheral notify/onWrite threading all verified); the substantive findings were on the host side and landed in #791/#792.

@finger563
finger563 requested a balanced review from Copilot September 12, 2026 16:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 26 out of 26 changed files in this pull request and generated 4 comments.

Comment thread components/wdi/README.md Outdated
Comment thread components/wdi/idf_component.yml
Comment thread lib/python_bindings/wdi_bindings.cpp Outdated
Comment thread components/wdi/CMakeLists.txt Outdated
… comment)

- README dependency table / manifest description: this PR ships the protocol
  core + device role; the host-role headers it lists are delivered by the
  stacked follow-up PR -- say so instead of implying they exist here.
- Python bindings: check the PyBytes_AsStringAndSize() return and propagate
  the TypeError CPython raised (py::error_already_set) instead of building a
  span from an unset pointer.
- CMakeLists comment: base_component is required because the transport role
  classes derive from BaseComponent; the protocol core and the WdiDevice /
  WdiHost cores are dependency-free (the old comment said wdi.hpp used Logger).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
@finger563
finger563 merged commit 6dee023 into main Sep 12, 2026
164 checks passed
@finger563
finger563 deleted the feat/wdi branch September 12, 2026 17:23
finger563 added a commit that referenced this pull request Sep 12, 2026
Keep this branch's wording for the WDI README dependency table and manifest
description: the device-role PR said the host-role headers arrive in a
follow-up, and this PR is that follow-up.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
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.

2 participants