2626from .. import Service
2727
2828try :
29- from typing import Dict , Optional
29+ from typing import Dict , Optional , Sequence
3030except ImportError :
3131 pass
3232
@@ -248,6 +248,60 @@ 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+ self ._first_report_in_id = None
264+ self ._first_report_out_id = None
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 self ._first_report_in_id is None :
279+ self ._first_report_in_id = 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 self ._first_report_out_id is None :
285+ self ._first_report_out_id = report_id
286+ self ._report_outs [report_id ] = report_out
287+
288+ def send_report (self , report : Dict , report_id : int | None = None ) -> None :
289+ """Send a report via the ReportIn class."""
290+ if report_id is None and self ._first_report_in_id is not None :
291+ report_id = self ._first_report_in_id
292+ if report_id is None :
293+ raise RuntimeError ("No input report available" )
294+ self ._report_ins [report_id ].send_report (report )
295+
296+ def get_last_received_report (self , report_id : int | None = None ):
297+ """Return the last OUT report received."""
298+ if report_id is None and self ._first_report_out_id is not None :
299+ report_id = self ._first_report_out_id
300+ if report_id is None :
301+ raise RuntimeError ("No output report available" )
302+ return self ._report_outs [report_id ].report
303+
304+
251305_ITEM_TYPE_MAIN = const (0 )
252306_ITEM_TYPE_GLOBAL = const (1 )
253307_ITEM_TYPE_LOCAL = const (2 )
@@ -268,9 +322,9 @@ class HIDService(Service):
268322
269323 Example::
270324
271- from adafruit_ble.hid_server import HIDServer
325+ from adafruit_ble.services.standard.hid import HIDService
272326
273- hid = HIDServer ()
327+ hid = HIDService ()
274328 """
275329
276330 uuid = StandardUUID (0x1812 )
@@ -429,25 +483,39 @@ def get_report_info(collection: Dict, reports: Dict) -> None:
429483 get_report_info (collection , reports )
430484 for report_id , report in reports .items ():
431485 output_size = report ["output_size" ]
486+ # Group ReportIn and ReportOut by usage_page and usage into a Devices
487+ input_size = report ["input_size" ]
488+
489+ # Find an existing device with same usage_page and usage
490+ device = None
491+ for d in self .devices :
492+ # Device instances expose usage_page and usage properties
493+ if d .usage_page == usage_page and d .usage == usage :
494+ device = d
495+ break
496+
497+ if device is None :
498+ device = Device (usage_page , usage )
499+ self .devices .append (device )
500+
432501 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- )
502+ # Create ReportOut and attach to device
503+ report_out = ReportOut (
504+ self ,
505+ report_id ,
506+ usage_page ,
507+ usage ,
508+ max_length = output_size // 8 ,
441509 )
510+ device .add_report_out (report_id , report_out )
442511
443- input_size = report ["input_size" ]
444512 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- )
513+ # Create ReportIn and attach to device
514+ report_in = ReportIn (
515+ self ,
516+ report_id ,
517+ usage_page ,
518+ usage ,
519+ max_length = input_size // 8 ,
453520 )
521+ device .add_report_in (report_id , report_in )
0 commit comments