Skip to content

Commit 6a5073a

Browse files
committed
Implemented ble hid Device class
1 parent 6744b68 commit 6a5073a

File tree

2 files changed

+98
-20
lines changed

2 files changed

+98
-20
lines changed

adafruit_ble/services/standard/hid.py

Lines changed: 97 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from .. import Service
2727

2828
try:
29-
from typing import Dict, Optional
29+
from typing import Dict, Optional, Sequence
3030
except ImportError:
3131
pass
3232

@@ -248,6 +248,69 @@ def report(self) -> Dict:
248248
return self._characteristic.value
249249

250250

251+
class Device:
252+
"""Container that groups multiple ReportIn and ReportOut objects for a given
253+
usage_page/usage.
254+
255+
Each device may have multiple report IDs. This class keeps mappings from
256+
report_id -> ReportIn/ReportOut and provides convenience methods that use
257+
the first-added report_id when none is specified.
258+
"""
259+
260+
def __init__(self, usage_page, usage):
261+
self._usage_page = usage_page
262+
self._usage = usage
263+
# Maintain insertion order of report_ids
264+
self._report_id_order = [] # list of report_id in insertion order
265+
self._report_ins = {} # report_id -> ReportIn
266+
self._report_outs = {} # report_id -> ReportOut
267+
268+
@property
269+
def usage_page(self):
270+
return self._usage_page
271+
272+
@property
273+
def usage(self):
274+
return self._usage
275+
276+
def add_report_in(self, report_id: int, report_in: ReportIn) -> None:
277+
"""Register a ReportIn instance for a report_id."""
278+
if report_id not in self._report_id_order:
279+
self._report_id_order.append(report_id)
280+
self._report_ins[report_id] = report_in
281+
282+
def add_report_out(self, report_id: int, report_out: ReportOut) -> None:
283+
"""Register a ReportOut instance for a report_id."""
284+
if report_id not in self._report_id_order:
285+
self._report_id_order.append(report_id)
286+
self._report_outs[report_id] = report_out
287+
288+
def _first_report_id(self):
289+
return self._report_id_order[0] if self._report_id_order else None
290+
291+
def send_report(self, report: Dict, report_id: int | None = None) -> None:
292+
"""Send a report via the ReportIn class.
293+
294+
If report_id is None, uses the first-added report_id for this device.
295+
Raises RuntimeError if no matching ReportIn exists.
296+
"""
297+
if report_id is None:
298+
report_id = self._first_report_id()
299+
if report_id is None or report_id not in self._report_ins:
300+
raise RuntimeError(f"No input report available for report_id {report_id}")
301+
self._report_ins[report_id].send_report(report)
302+
303+
def get_last_received_report(self, report_id: int | None = None):
304+
"""Return the last OUT report received.
305+
If report_id is None, uses the first-added report_id for this device.
306+
"""
307+
if report_id is None:
308+
report_id = self._first_report_id()
309+
if report_id is None or report_id not in self._report_outs:
310+
return None
311+
return self._report_outs[report_id].report
312+
313+
251314
_ITEM_TYPE_MAIN = const(0)
252315
_ITEM_TYPE_GLOBAL = const(1)
253316
_ITEM_TYPE_LOCAL = const(2)
@@ -268,9 +331,9 @@ class HIDService(Service):
268331
269332
Example::
270333
271-
from adafruit_ble.hid_server import HIDServer
334+
from adafruit_ble.services.standard.hid import HIDService
272335
273-
hid = HIDServer()
336+
hid = HIDService()
274337
"""
275338

276339
uuid = StandardUUID(0x1812)
@@ -429,25 +492,39 @@ def get_report_info(collection: Dict, reports: Dict) -> None:
429492
get_report_info(collection, reports)
430493
for report_id, report in reports.items():
431494
output_size = report["output_size"]
495+
# Group ReportIn and ReportOut by usage_page and usage into a Devices
496+
input_size = report["input_size"]
497+
498+
# Find an existing device with same usage_page and usage
499+
device = None
500+
for d in self.devices:
501+
# Device instances expose usage_page and usage properties
502+
if d.usage_page == usage_page and d.usage == usage:
503+
device = d
504+
break
505+
506+
if device is None:
507+
device = Device(usage_page, usage)
508+
self.devices.append(device)
509+
432510
if output_size > 0:
433-
self.devices.append(
434-
ReportOut(
435-
self,
436-
report_id,
437-
usage_page,
438-
usage,
439-
max_length=output_size // 8,
440-
)
511+
# Create ReportOut and attach to device
512+
report_out = ReportOut(
513+
self,
514+
report_id,
515+
usage_page,
516+
usage,
517+
max_length=output_size // 8,
441518
)
519+
device.add_report_out(report_id, report_out)
442520

443-
input_size = report["input_size"]
444521
if input_size > 0:
445-
self.devices.append(
446-
ReportIn(
447-
self,
448-
report_id,
449-
usage_page,
450-
usage,
451-
max_length=input_size // 8,
452-
)
522+
# Create ReportIn and attach to device
523+
report_in = ReportIn(
524+
self,
525+
report_id,
526+
usage_page,
527+
usage,
528+
max_length=input_size // 8,
453529
)
530+
device.add_report_in(report_id, report_in)

examples/ble_hid_periph.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@
4646
sys.stdout.write(c)
4747
kl.write(c)
4848
# print("sleeping")
49+
# print(f"{k.led_status}") #read led_status
4950
time.sleep(0.1)
5051
ble.start_advertising(advertisement)

0 commit comments

Comments
 (0)