mirror of
https://github.com/google/bumble.git
synced 2026-04-18 00:45:32 +00:00
@@ -27,8 +27,8 @@ from collections.abc import (
|
|||||||
Awaitable,
|
Awaitable,
|
||||||
Callable,
|
Callable,
|
||||||
Iterable,
|
Iterable,
|
||||||
Sequence,
|
|
||||||
Mapping,
|
Mapping,
|
||||||
|
Sequence,
|
||||||
)
|
)
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import ClassVar, SupportsBytes, TypeVar
|
from typing import ClassVar, SupportsBytes, TypeVar
|
||||||
|
|||||||
109
bumble/hfp.py
109
bumble/hfp.py
@@ -26,7 +26,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from typing import TYPE_CHECKING, Any, ClassVar
|
from typing import Any, ClassVar, Literal, overload
|
||||||
|
|
||||||
from typing_extensions import Self
|
from typing_extensions import Self
|
||||||
|
|
||||||
@@ -420,61 +420,6 @@ class CmeError(enum.IntEnum):
|
|||||||
# Hands-Free Control Interoperability Requirements
|
# Hands-Free Control Interoperability Requirements
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
# Response codes.
|
|
||||||
RESPONSE_CODES = {
|
|
||||||
"+APLSIRI",
|
|
||||||
"+BAC",
|
|
||||||
"+BCC",
|
|
||||||
"+BCS",
|
|
||||||
"+BIA",
|
|
||||||
"+BIEV",
|
|
||||||
"+BIND",
|
|
||||||
"+BINP",
|
|
||||||
"+BLDN",
|
|
||||||
"+BRSF",
|
|
||||||
"+BTRH",
|
|
||||||
"+BVRA",
|
|
||||||
"+CCWA",
|
|
||||||
"+CHLD",
|
|
||||||
"+CHUP",
|
|
||||||
"+CIND",
|
|
||||||
"+CLCC",
|
|
||||||
"+CLIP",
|
|
||||||
"+CMEE",
|
|
||||||
"+CMER",
|
|
||||||
"+CNUM",
|
|
||||||
"+COPS",
|
|
||||||
"+IPHONEACCEV",
|
|
||||||
"+NREC",
|
|
||||||
"+VGM",
|
|
||||||
"+VGS",
|
|
||||||
"+VTS",
|
|
||||||
"+XAPL",
|
|
||||||
"A",
|
|
||||||
"D",
|
|
||||||
}
|
|
||||||
|
|
||||||
# Unsolicited responses and statuses.
|
|
||||||
UNSOLICITED_CODES = {
|
|
||||||
"+APLSIRI",
|
|
||||||
"+BCS",
|
|
||||||
"+BIND",
|
|
||||||
"+BSIR",
|
|
||||||
"+BTRH",
|
|
||||||
"+BVRA",
|
|
||||||
"+CCWA",
|
|
||||||
"+CIEV",
|
|
||||||
"+CLIP",
|
|
||||||
"+VGM",
|
|
||||||
"+VGS",
|
|
||||||
"BLACKLISTED",
|
|
||||||
"BUSY",
|
|
||||||
"DELAYED",
|
|
||||||
"NO ANSWER",
|
|
||||||
"NO CARRIER",
|
|
||||||
"RING",
|
|
||||||
}
|
|
||||||
|
|
||||||
# Status codes
|
# Status codes
|
||||||
STATUS_CODES = {
|
STATUS_CODES = {
|
||||||
"+CME ERROR",
|
"+CME ERROR",
|
||||||
@@ -727,12 +672,9 @@ class HfProtocol(utils.EventEmitter):
|
|||||||
|
|
||||||
dlc: rfcomm.DLC
|
dlc: rfcomm.DLC
|
||||||
command_lock: asyncio.Lock
|
command_lock: asyncio.Lock
|
||||||
if TYPE_CHECKING:
|
pending_command: str | None = None
|
||||||
response_queue: asyncio.Queue[AtResponse]
|
response_queue: asyncio.Queue[AtResponse]
|
||||||
unsolicited_queue: asyncio.Queue[AtResponse | None]
|
unsolicited_queue: asyncio.Queue[AtResponse | None]
|
||||||
else:
|
|
||||||
response_queue: asyncio.Queue
|
|
||||||
unsolicited_queue: asyncio.Queue
|
|
||||||
read_buffer: bytearray
|
read_buffer: bytearray
|
||||||
active_codec: AudioCodec
|
active_codec: AudioCodec
|
||||||
|
|
||||||
@@ -805,16 +747,39 @@ class HfProtocol(utils.EventEmitter):
|
|||||||
self.read_buffer = self.read_buffer[trailer + 2 :]
|
self.read_buffer = self.read_buffer[trailer + 2 :]
|
||||||
|
|
||||||
# Forward the received code to the correct queue.
|
# Forward the received code to the correct queue.
|
||||||
if self.command_lock.locked() and (
|
if self.pending_command and (
|
||||||
response.code in STATUS_CODES or response.code in RESPONSE_CODES
|
response.code in STATUS_CODES or response.code in self.pending_command
|
||||||
):
|
):
|
||||||
self.response_queue.put_nowait(response)
|
self.response_queue.put_nowait(response)
|
||||||
elif response.code in UNSOLICITED_CODES:
|
|
||||||
self.unsolicited_queue.put_nowait(response)
|
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
self.unsolicited_queue.put_nowait(response)
|
||||||
f"dropping unexpected response with code '{response.code}'"
|
|
||||||
)
|
@overload
|
||||||
|
async def execute_command(
|
||||||
|
self,
|
||||||
|
cmd: str,
|
||||||
|
timeout: float = 1.0,
|
||||||
|
*,
|
||||||
|
response_type: Literal[AtResponseType.NONE] = AtResponseType.NONE,
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
async def execute_command(
|
||||||
|
self,
|
||||||
|
cmd: str,
|
||||||
|
timeout: float = 1.0,
|
||||||
|
*,
|
||||||
|
response_type: Literal[AtResponseType.SINGLE],
|
||||||
|
) -> AtResponse: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
async def execute_command(
|
||||||
|
self,
|
||||||
|
cmd: str,
|
||||||
|
timeout: float = 1.0,
|
||||||
|
*,
|
||||||
|
response_type: Literal[AtResponseType.MULTIPLE],
|
||||||
|
) -> list[AtResponse]: ...
|
||||||
|
|
||||||
async def execute_command(
|
async def execute_command(
|
||||||
self,
|
self,
|
||||||
@@ -835,7 +800,9 @@ class HfProtocol(utils.EventEmitter):
|
|||||||
asyncio.TimeoutError: the status is not received after a timeout (default 1 second).
|
asyncio.TimeoutError: the status is not received after a timeout (default 1 second).
|
||||||
ProtocolError: the status is not OK.
|
ProtocolError: the status is not OK.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
async with self.command_lock:
|
async with self.command_lock:
|
||||||
|
self.pending_command = cmd
|
||||||
logger.debug(f">>> {cmd}")
|
logger.debug(f">>> {cmd}")
|
||||||
self.dlc.write(cmd + '\r')
|
self.dlc.write(cmd + '\r')
|
||||||
responses: list[AtResponse] = []
|
responses: list[AtResponse] = []
|
||||||
@@ -845,7 +812,10 @@ class HfProtocol(utils.EventEmitter):
|
|||||||
self.response_queue.get(), timeout=timeout
|
self.response_queue.get(), timeout=timeout
|
||||||
)
|
)
|
||||||
if result.code == 'OK':
|
if result.code == 'OK':
|
||||||
if response_type == AtResponseType.SINGLE and len(responses) != 1:
|
if (
|
||||||
|
response_type == AtResponseType.SINGLE
|
||||||
|
and len(responses) != 1
|
||||||
|
):
|
||||||
raise HfpProtocolError("NO ANSWER")
|
raise HfpProtocolError("NO ANSWER")
|
||||||
|
|
||||||
if response_type == AtResponseType.MULTIPLE:
|
if response_type == AtResponseType.MULTIPLE:
|
||||||
@@ -856,6 +826,8 @@ class HfProtocol(utils.EventEmitter):
|
|||||||
if result.code in STATUS_CODES:
|
if result.code in STATUS_CODES:
|
||||||
raise HfpProtocolError(result.code)
|
raise HfpProtocolError(result.code)
|
||||||
responses.append(result)
|
responses.append(result)
|
||||||
|
finally:
|
||||||
|
self.pending_command = None
|
||||||
|
|
||||||
async def initiate_slc(self):
|
async def initiate_slc(self):
|
||||||
"""4.2.1 Service Level Connection Initialization."""
|
"""4.2.1 Service Level Connection Initialization."""
|
||||||
@@ -1067,7 +1039,6 @@ class HfProtocol(utils.EventEmitter):
|
|||||||
responses = await self.execute_command(
|
responses = await self.execute_command(
|
||||||
"AT+CLCC", response_type=AtResponseType.MULTIPLE
|
"AT+CLCC", response_type=AtResponseType.MULTIPLE
|
||||||
)
|
)
|
||||||
assert isinstance(responses, list)
|
|
||||||
|
|
||||||
calls = []
|
calls = []
|
||||||
for response in responses:
|
for response in responses:
|
||||||
|
|||||||
Reference in New Issue
Block a user