Coverage for src / bluetooth_sig / types / scan_interval_window.py: 100%

24 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-11 20:14 +0000

1"""Scan Interval Window characteristic data types.""" 

2 

3from __future__ import annotations 

4 

5import msgspec 

6 

7 

8class ScanIntervalWindowData(msgspec.Struct, frozen=True, kw_only=True): 

9 """Scan Interval Window characteristic data. 

10 

11 Contains scan interval and scan window parameters for BLE scanning. 

12 

13 Attributes: 

14 scan_interval: Scan interval in units of 0.625ms (range: 0x0004-0x4000) 

15 scan_window: Scan window in units of 0.625ms (range: 0x0004-0x4000) 

16 Must be less than or equal to scan_interval 

17 """ 

18 

19 # BLE scan parameter constants (in units of 0.625ms) 

20 SCAN_INTERVAL_MIN = 0x0004 # Minimum scan interval (2.5ms) 

21 SCAN_INTERVAL_MAX = 0x4000 # Maximum scan interval (10.24s) 

22 SCAN_WINDOW_MIN = 0x0004 # Minimum scan window (2.5ms) 

23 SCAN_WINDOW_MAX = 0x4000 # Maximum scan window (10.24s) 

24 

25 # Time conversion constants 

26 UNITS_TO_MS_FACTOR = 0.625 # Convert from 0.625ms units to milliseconds 

27 HEX_FORMAT_WIDTH = 6 # Width for hex formatting (#06x) 

28 

29 scan_interval: int 

30 scan_window: int 

31 

32 def __post_init__(self) -> None: 

33 """Validate scan parameters after initialization.""" 

34 # Validate ranges 

35 if not self.SCAN_INTERVAL_MIN <= self.scan_interval <= self.SCAN_INTERVAL_MAX: 

36 raise ValueError( 

37 f"Scan interval {self.scan_interval:#0{self.HEX_FORMAT_WIDTH}x} out of range " 

38 f"({self.SCAN_INTERVAL_MIN:#0{self.HEX_FORMAT_WIDTH}x}-{self.SCAN_INTERVAL_MAX:#0{self.HEX_FORMAT_WIDTH}x})" 

39 ) 

40 if not self.SCAN_WINDOW_MIN <= self.scan_window <= self.SCAN_WINDOW_MAX: 

41 raise ValueError( 

42 f"Scan window {self.scan_window:#0{self.HEX_FORMAT_WIDTH}x} out of range " 

43 f"({self.SCAN_WINDOW_MIN:#0{self.HEX_FORMAT_WIDTH}x}-{self.SCAN_WINDOW_MAX:#0{self.HEX_FORMAT_WIDTH}x})" 

44 ) 

45 if self.scan_window > self.scan_interval: 

46 raise ValueError( 

47 f"Scan window {self.scan_window:#0{self.HEX_FORMAT_WIDTH}x} must be <= scan interval " 

48 f"{self.scan_interval:#0{self.HEX_FORMAT_WIDTH}x}" 

49 ) 

50 

51 @property 

52 def scan_interval_ms(self) -> float: 

53 """Get scan interval in milliseconds.""" 

54 return self.scan_interval * self.UNITS_TO_MS_FACTOR 

55 

56 @property 

57 def scan_window_ms(self) -> float: 

58 """Get scan window in milliseconds.""" 

59 return self.scan_window * self.UNITS_TO_MS_FACTOR