bumble 0.0.221__py3-none-any.whl → 0.0.222__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bumble/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.0.221'
32
- __version_tuple__ = version_tuple = (0, 0, 221)
31
+ __version__ = version = '0.0.222'
32
+ __version_tuple__ = version_tuple = (0, 0, 222)
33
33
 
34
34
  __commit_id__ = commit_id = None
bumble/l2cap.py CHANGED
@@ -20,6 +20,7 @@ from __future__ import annotations
20
20
  import asyncio
21
21
  import dataclasses
22
22
  import enum
23
+ import itertools
23
24
  import logging
24
25
  import struct
25
26
  from collections import deque
@@ -302,11 +303,9 @@ class EnhancedControlField(ControlField):
302
303
 
303
304
  @dataclasses.dataclass
304
305
  class InformationEnhancedControlField(EnhancedControlField):
305
- tx_seq: int = 0
306
+ tx_seq: int
307
+ sar: int
306
308
  req_seq: int = 0
307
- segmentation_and_reassembly: int = (
308
- EnhancedControlField.SegmentationAndReassembly.UNSEGMENTED
309
- )
310
309
  final: int = 1
311
310
 
312
311
  frame_type = EnhancedControlField.FieldType.I_FRAME
@@ -316,15 +315,15 @@ class InformationEnhancedControlField(EnhancedControlField):
316
315
  return cls(
317
316
  tx_seq=(data[0] >> 1) & 0b0111111,
318
317
  final=(data[0] >> 7) & 0b1,
319
- req_seq=(data[1] & 0b001111111),
320
- segmentation_and_reassembly=(data[1] >> 6) & 0b11,
318
+ req_seq=(data[1] & 0b00111111),
319
+ sar=(data[1] >> 6) & 0b11,
321
320
  )
322
321
 
323
322
  def __bytes__(self) -> bytes:
324
323
  return bytes(
325
324
  [
326
325
  self.frame_type | (self.tx_seq << 1) | (self.final << 7),
327
- self.req_seq | (self.segmentation_and_reassembly << 6),
326
+ self.req_seq | (self.sar << 6),
328
327
  ]
329
328
  )
330
329
 
@@ -889,27 +888,38 @@ class EnhancedRetransmissionProcessor(Processor):
889
888
  class _PendingPdu:
890
889
  payload: bytes
891
890
  tx_seq: int
891
+ sar: InformationEnhancedControlField.SegmentationAndReassembly
892
+ sdu_length: int = 0
892
893
  req_seq: int = 0
893
894
 
894
895
  def __bytes__(self) -> bytes:
895
896
  return (
896
897
  bytes(
897
898
  InformationEnhancedControlField(
898
- tx_seq=self.tx_seq, req_seq=self.req_seq
899
+ tx_seq=self.tx_seq,
900
+ req_seq=self.req_seq,
901
+ sar=self.sar,
899
902
  )
900
903
  )
904
+ + (
905
+ struct.pack('<H', self.sdu_length)
906
+ if self.sar
907
+ == InformationEnhancedControlField.SegmentationAndReassembly.START
908
+ else b''
909
+ )
901
910
  + self.payload
902
911
  )
903
912
 
904
- _expected_ack_seq: int = 0
913
+ _last_acked_tx_seq: int = 0
914
+ _last_acked_rx_seq: int = 0
905
915
  _next_tx_seq: int = 0
906
- _last_tx_seq: int = 0
907
916
  _req_seq_num: int = 0
908
- _next_seq_num: int = 0
909
917
  _remote_is_busy: bool = False
918
+ _in_sdu: bytes = b''
910
919
 
911
920
  _num_receiver_ready_polls_sent: int = 0
912
921
  _pending_pdus: list[_PendingPdu]
922
+ _tx_window: list[_PendingPdu]
913
923
  _monitor_handle: asyncio.TimerHandle | None = None
914
924
  _receiver_ready_poll_handle: asyncio.TimerHandle | None = None
915
925
 
@@ -917,12 +927,6 @@ class EnhancedRetransmissionProcessor(Processor):
917
927
  monitor_timeout: float
918
928
  retransmission_timeout: float
919
929
 
920
- @classmethod
921
- def _num_frames_between(cls, low: int, high: int) -> int:
922
- if high < low:
923
- high += cls.MAX_SEQ_NUM
924
- return high - low
925
-
926
930
  def __init__(
927
931
  self,
928
932
  channel: ClassicChannel,
@@ -935,6 +939,7 @@ class EnhancedRetransmissionProcessor(Processor):
935
939
  self.peer_mps = peer_mps
936
940
  self.peer_tx_window_size = peer_tx_window_size
937
941
  self._pending_pdus = []
942
+ self._tx_window = []
938
943
  self.monitor_timeout = spec.monitor_timeout
939
944
  self.channel = channel
940
945
  self.retransmission_timeout = spec.retransmission_timeout
@@ -972,12 +977,9 @@ class EnhancedRetransmissionProcessor(Processor):
972
977
 
973
978
  def _send_receiver_ready_poll(self) -> None:
974
979
  self._num_receiver_ready_polls_sent += 1
975
- self.channel.send_pdu(
976
- SupervisoryEnhancedControlField(
977
- supervision_function=SupervisoryEnhancedControlField.SupervisoryFunction.RR,
978
- final=1,
979
- req_seq=self._next_seq_num,
980
- )
980
+ self._send_s_frame(
981
+ supervision_function=SupervisoryEnhancedControlField.SupervisoryFunction.RR,
982
+ final=1,
981
983
  )
982
984
 
983
985
  def _get_next_tx_seq(self) -> int:
@@ -987,12 +989,35 @@ class EnhancedRetransmissionProcessor(Processor):
987
989
 
988
990
  @override
989
991
  def send_sdu(self, sdu: bytes) -> None:
990
- if len(sdu) > self.peer_mps:
991
- raise InvalidArgumentError(
992
- f'SDU size({len(sdu)}) exceeds channel MPS {self.peer_mps}'
992
+ if len(sdu) <= self.peer_mps:
993
+ pdu = self._PendingPdu(
994
+ payload=sdu,
995
+ tx_seq=self._get_next_tx_seq(),
996
+ req_seq=self._req_seq_num,
997
+ sar=InformationEnhancedControlField.SegmentationAndReassembly.UNSEGMENTED,
993
998
  )
994
- pdu = self._PendingPdu(payload=sdu, tx_seq=self._get_next_tx_seq())
995
- self._pending_pdus.append(pdu)
999
+ self._pending_pdus.append(pdu)
1000
+ else:
1001
+ for offset in range(0, len(sdu), self.peer_mps):
1002
+ payload = sdu[offset : offset + self.peer_mps]
1003
+ if offset == 0:
1004
+ sar = (
1005
+ InformationEnhancedControlField.SegmentationAndReassembly.START
1006
+ )
1007
+ elif offset + len(payload) >= len(sdu):
1008
+ sar = InformationEnhancedControlField.SegmentationAndReassembly.END
1009
+ else:
1010
+ sar = (
1011
+ InformationEnhancedControlField.SegmentationAndReassembly.CONTINUATION
1012
+ )
1013
+ pdu = self._PendingPdu(
1014
+ payload=payload,
1015
+ tx_seq=self._get_next_tx_seq(),
1016
+ req_seq=self._req_seq_num,
1017
+ sar=sar,
1018
+ sdu_length=len(sdu),
1019
+ )
1020
+ self._pending_pdus.append(pdu)
996
1021
  self._process_output()
997
1022
 
998
1023
  @override
@@ -1000,17 +1025,37 @@ class EnhancedRetransmissionProcessor(Processor):
1000
1025
  control_field = EnhancedControlField.from_bytes(pdu)
1001
1026
  self._update_ack_seq(control_field.req_seq, control_field.final != 0)
1002
1027
  if isinstance(control_field, InformationEnhancedControlField):
1003
- if control_field.tx_seq != self._next_seq_num:
1028
+ if control_field.tx_seq != self._req_seq_num:
1029
+ logger.error(
1030
+ "tx_seq != self._req_seq_num, tx_seq: %d, self._req_seq_num: %d",
1031
+ control_field.tx_seq,
1032
+ self._req_seq_num,
1033
+ )
1004
1034
  return
1005
- self._next_seq_num = (self._next_seq_num + 1) % self.MAX_SEQ_NUM
1006
- self._req_seq_num = self._next_seq_num
1035
+ self._req_seq_num = (control_field.tx_seq + 1) % self.MAX_SEQ_NUM
1007
1036
 
1008
- ack_frame = SupervisoryEnhancedControlField(
1009
- supervision_function=SupervisoryEnhancedControlField.SupervisoryFunction.RR,
1010
- req_seq=self._next_seq_num,
1011
- )
1012
- self.channel.send_pdu(ack_frame)
1013
- self.channel.on_sdu(pdu[2:])
1037
+ if (
1038
+ control_field.sar
1039
+ == InformationEnhancedControlField.SegmentationAndReassembly.START
1040
+ ):
1041
+ # Drop Control Field(2) + SDU Length(2)
1042
+ self._in_sdu += pdu[4:]
1043
+ else:
1044
+ # Drop Control Field(2)
1045
+ self._in_sdu += pdu[2:]
1046
+ if control_field.sar in (
1047
+ InformationEnhancedControlField.SegmentationAndReassembly.END,
1048
+ InformationEnhancedControlField.SegmentationAndReassembly.UNSEGMENTED,
1049
+ ):
1050
+ self.channel.on_sdu(self._in_sdu)
1051
+ self._in_sdu = b''
1052
+
1053
+ # If sink doesn't trigger any I-frame, ack this frame.
1054
+ if self._req_seq_num != self._last_acked_rx_seq:
1055
+ self._send_s_frame(
1056
+ supervision_function=SupervisoryEnhancedControlField.SupervisoryFunction.RR,
1057
+ final=0,
1058
+ )
1014
1059
  elif isinstance(control_field, SupervisoryEnhancedControlField):
1015
1060
  self._remote_is_busy = (
1016
1061
  control_field.supervision_function
@@ -1022,56 +1067,66 @@ class EnhancedRetransmissionProcessor(Processor):
1022
1067
  SupervisoryEnhancedControlField.SupervisoryFunction.RNR,
1023
1068
  ):
1024
1069
  if control_field.poll:
1025
- self.channel.send_pdu(
1026
- SupervisoryEnhancedControlField(
1027
- supervision_function=SupervisoryEnhancedControlField.SupervisoryFunction.RR,
1028
- final=1,
1029
- req_seq=self._next_seq_num,
1030
- )
1070
+ self._send_s_frame(
1071
+ supervision_function=SupervisoryEnhancedControlField.SupervisoryFunction.RR,
1072
+ final=1,
1031
1073
  )
1032
1074
  else:
1033
1075
  # TODO: Handle Retransmission.
1034
1076
  pass
1035
1077
 
1036
1078
  def _process_output(self) -> None:
1037
- if self._remote_is_busy or self._monitor_handle:
1079
+ if self._remote_is_busy:
1080
+ logger.debug("Remote is busy")
1081
+ return
1082
+ if self._monitor_handle:
1083
+ logger.debug("Monitor handle is not None")
1038
1084
  return
1039
1085
 
1040
- for pdu in self._pending_pdus:
1041
- if self._num_unacked_frames >= self.peer_tx_window_size:
1042
- return
1043
- self._send_pdu(pdu)
1044
- self._last_tx_seq = pdu.tx_seq
1045
-
1046
- @property
1047
- def _num_unacked_frames(self) -> int:
1048
- if not self._pending_pdus:
1049
- return 0
1050
- return self._num_frames_between(self._expected_ack_seq, self._last_tx_seq + 1)
1086
+ pdu_to_send = self.peer_tx_window_size - len(self._tx_window)
1087
+ for pdu in itertools.islice(self._pending_pdus, pdu_to_send):
1088
+ self._send_i_frame(pdu)
1089
+ self._pending_pdus = self._pending_pdus[pdu_to_send:]
1051
1090
 
1052
- def _send_pdu(self, pdu: _PendingPdu) -> None:
1091
+ def _send_i_frame(self, pdu: _PendingPdu) -> None:
1053
1092
  pdu.req_seq = self._req_seq_num
1054
1093
 
1055
1094
  self._start_receiver_ready_poll()
1095
+ self._tx_window.append(pdu)
1056
1096
  self.channel.send_pdu(bytes(pdu))
1097
+ self._last_acked_rx_seq = self._req_seq_num
1098
+
1099
+ def _send_s_frame(
1100
+ self,
1101
+ supervision_function: SupervisoryEnhancedControlField.SupervisoryFunction,
1102
+ final: int,
1103
+ ) -> None:
1104
+ self.channel.send_pdu(
1105
+ SupervisoryEnhancedControlField(
1106
+ supervision_function=supervision_function,
1107
+ final=final,
1108
+ req_seq=self._req_seq_num,
1109
+ )
1110
+ )
1111
+ self._last_acked_rx_seq = self._req_seq_num
1057
1112
 
1058
1113
  def _update_ack_seq(self, new_seq: int, is_poll_response: bool) -> None:
1059
- num_frames_acked = self._num_frames_between(self._expected_ack_seq, new_seq)
1060
- if num_frames_acked > self._num_unacked_frames:
1114
+ num_frames_acked = (new_seq - self._last_acked_tx_seq) % self.MAX_SEQ_NUM
1115
+ if num_frames_acked > len(self._tx_window):
1061
1116
  logger.error(
1062
1117
  "Received acknowledgment for %d frames but only %d frames are pending",
1063
1118
  num_frames_acked,
1064
- self._num_unacked_frames,
1119
+ len(self._tx_window),
1065
1120
  )
1066
1121
  return
1067
1122
  if is_poll_response and self._monitor_handle:
1068
1123
  self._monitor_handle.cancel()
1069
1124
  self._monitor_handle = None
1070
1125
 
1071
- del self._pending_pdus[:num_frames_acked]
1072
- self._expected_ack_seq = new_seq
1126
+ del self._tx_window[:num_frames_acked]
1127
+ self._last_acked_tx_seq = new_seq
1073
1128
  if (
1074
- self._expected_ack_seq == self._next_tx_seq
1129
+ self._last_acked_tx_seq == self._next_tx_seq
1075
1130
  and self._receiver_ready_poll_handle
1076
1131
  ):
1077
1132
  self._receiver_ready_poll_handle.cancel()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bumble
3
- Version: 0.0.221
3
+ Version: 0.0.222
4
4
  Summary: Bluetooth Stack for Apps, Emulation, Test and Experimentation
5
5
  Author-email: Google <bumble-dev@google.com>
6
6
  License-Expression: Apache-2.0
@@ -1,5 +1,5 @@
1
1
  bumble/__init__.py,sha256=Q8jkz6rgl95IMAeInQVt_2GLoJl3DcEP2cxtrQ-ho5c,110
2
- bumble/_version.py,sha256=b0FO3MSqJtURaHMqUBs1P8OF7O0uCFUcWMLaVttHtwg,708
2
+ bumble/_version.py,sha256=iCVPnXJk250i-zuGezYSSco90VVqd3Imnx_2NCDTb8M,708
3
3
  bumble/a2dp.py,sha256=4eFKYOXkl10TRAJqVw4no6aCilYHdmgtd2ZMNY0yNQo,33436
4
4
  bumble/at.py,sha256=xtboorCqSdRDoIfRFOIhvV5x2cgXaYqKk5FSMNzuYPo,3062
5
5
  bumble/att.py,sha256=H-6zsJhM59KH7iuDZ3mksHXKdywPlng-AwSSd9SHLZE,36039
@@ -27,7 +27,7 @@ bumble/hfp.py,sha256=OwANwtXWBU3cwAnZ6oODvI0reZfKwCuG0DLI18mevr0,76696
27
27
  bumble/hid.py,sha256=dEFUN22YYjVcf7h6bdXsjWK8xUp6kDT6ffuDr9zSq-I,21031
28
28
  bumble/host.py,sha256=2W_BFI3q7ZBoL231Ii6oEuBDxcbV2phA9vDpk9ZKZ-Q,67833
29
29
  bumble/keys.py,sha256=iioiJZkqCoK2qopjDLLM0aeSy9l4bBrSyHfit4tNJek,13356
30
- bumble/l2cap.py,sha256=beiBeQENUhzaATK7OCHlDkvQc3Ao_b6D_oAr5WZFiwo,109543
30
+ bumble/l2cap.py,sha256=DluqPOWcG0vuw4H6fU1PWHDg6a1d8U9NCkHkU_bouEE,111741
31
31
  bumble/link.py,sha256=3dvwLyUlkfUPHsOthdOvl9wytToQqVweLmXWlub7Z34,5403
32
32
  bumble/ll.py,sha256=EH3OIM-6KL1Q22bqa6G1x-SgFqHOqc3_8nVj66RII0Q,5380
33
33
  bumble/lmp.py,sha256=9TsV8W1lbudCEytzhWg0N492xFbNEWy1-a3VuF1US-k,10433
@@ -177,9 +177,9 @@ bumble/vendor/android/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
177
177
  bumble/vendor/android/hci.py,sha256=Fk1SQVhhdoMGg65TIBX7C3FcgqqKfJ3ulMb5n2jfvkc,10457
178
178
  bumble/vendor/zephyr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
179
179
  bumble/vendor/zephyr/hci.py,sha256=ysct40uIVohaKKLrWjcWo-7YqozU17xGia2dWeHoMoI,3435
180
- bumble-0.0.221.dist-info/licenses/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
181
- bumble-0.0.221.dist-info/METADATA,sha256=ULSHbPBoUOwYeJM6-3AlPPecEiNj_5BZb647Mlqhu-w,6218
182
- bumble-0.0.221.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
183
- bumble-0.0.221.dist-info/entry_points.txt,sha256=mX5dzixNMRo4CTAEQqiYTr-JIaWF62TYrRvJOstjjL8,1081
184
- bumble-0.0.221.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
185
- bumble-0.0.221.dist-info/RECORD,,
180
+ bumble-0.0.222.dist-info/licenses/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
181
+ bumble-0.0.222.dist-info/METADATA,sha256=jd7Hsfxcgz2mNZH-dMImjU_S5x4ohYLW9pIBY256RfA,6218
182
+ bumble-0.0.222.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
183
+ bumble-0.0.222.dist-info/entry_points.txt,sha256=mX5dzixNMRo4CTAEQqiYTr-JIaWF62TYrRvJOstjjL8,1081
184
+ bumble-0.0.222.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
185
+ bumble-0.0.222.dist-info/RECORD,,