forked from auracaster/bumble_mirror
Merge pull request #573 from ypomortsev/yegor
HFP: Fix reading multiple AT commands from a single data packet
This commit is contained in:
@@ -795,29 +795,32 @@ class HfProtocol(pyee.EventEmitter):
|
|||||||
# Append to the read buffer.
|
# Append to the read buffer.
|
||||||
self.read_buffer.extend(data)
|
self.read_buffer.extend(data)
|
||||||
|
|
||||||
# Locate header and trailer.
|
while self.read_buffer:
|
||||||
header = self.read_buffer.find(b'\r\n')
|
# Locate header and trailer.
|
||||||
trailer = self.read_buffer.find(b'\r\n', header + 2)
|
header = self.read_buffer.find(b'\r\n')
|
||||||
if header == -1 or trailer == -1:
|
trailer = self.read_buffer.find(b'\r\n', header + 2)
|
||||||
return
|
if header == -1 or trailer == -1:
|
||||||
|
return
|
||||||
|
|
||||||
# Isolate the AT response code and parameters.
|
# Isolate the AT response code and parameters.
|
||||||
raw_response = self.read_buffer[header + 2 : trailer]
|
raw_response = self.read_buffer[header + 2 : trailer]
|
||||||
response = AtResponse.parse_from(raw_response)
|
response = AtResponse.parse_from(raw_response)
|
||||||
logger.debug(f"<<< {raw_response.decode()}")
|
logger.debug(f"<<< {raw_response.decode()}")
|
||||||
|
|
||||||
# Consume the response bytes.
|
# Consume the response bytes.
|
||||||
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.command_lock.locked() and (
|
||||||
response.code in STATUS_CODES or response.code in RESPONSE_CODES
|
response.code in STATUS_CODES or response.code in RESPONSE_CODES
|
||||||
):
|
):
|
||||||
self.response_queue.put_nowait(response)
|
self.response_queue.put_nowait(response)
|
||||||
elif response.code in UNSOLICITED_CODES:
|
elif response.code in UNSOLICITED_CODES:
|
||||||
self.unsolicited_queue.put_nowait(response)
|
self.unsolicited_queue.put_nowait(response)
|
||||||
else:
|
else:
|
||||||
logger.warning(f"dropping unexpected response with code '{response.code}'")
|
logger.warning(
|
||||||
|
f"dropping unexpected response with code '{response.code}'"
|
||||||
|
)
|
||||||
|
|
||||||
async def execute_command(
|
async def execute_command(
|
||||||
self,
|
self,
|
||||||
@@ -1244,31 +1247,32 @@ class AgProtocol(pyee.EventEmitter):
|
|||||||
# Append to the read buffer.
|
# Append to the read buffer.
|
||||||
self.read_buffer.extend(data)
|
self.read_buffer.extend(data)
|
||||||
|
|
||||||
# Locate the trailer.
|
while self.read_buffer:
|
||||||
trailer = self.read_buffer.find(b'\r')
|
# Locate the trailer.
|
||||||
if trailer == -1:
|
trailer = self.read_buffer.find(b'\r')
|
||||||
return
|
if trailer == -1:
|
||||||
|
return
|
||||||
|
|
||||||
# Isolate the AT response code and parameters.
|
# Isolate the AT response code and parameters.
|
||||||
raw_command = self.read_buffer[:trailer]
|
raw_command = self.read_buffer[:trailer]
|
||||||
command = AtCommand.parse_from(raw_command)
|
command = AtCommand.parse_from(raw_command)
|
||||||
logger.debug(f"<<< {raw_command.decode()}")
|
logger.debug(f"<<< {raw_command.decode()}")
|
||||||
|
|
||||||
# Consume the response bytes.
|
# Consume the response bytes.
|
||||||
self.read_buffer = self.read_buffer[trailer + 1 :]
|
self.read_buffer = self.read_buffer[trailer + 1 :]
|
||||||
|
|
||||||
if command.sub_code == AtCommand.SubCode.TEST:
|
if command.sub_code == AtCommand.SubCode.TEST:
|
||||||
handler_name = f'_on_{command.code.lower()}_test'
|
handler_name = f'_on_{command.code.lower()}_test'
|
||||||
elif command.sub_code == AtCommand.SubCode.READ:
|
elif command.sub_code == AtCommand.SubCode.READ:
|
||||||
handler_name = f'_on_{command.code.lower()}_read'
|
handler_name = f'_on_{command.code.lower()}_read'
|
||||||
else:
|
else:
|
||||||
handler_name = f'_on_{command.code.lower()}'
|
handler_name = f'_on_{command.code.lower()}'
|
||||||
|
|
||||||
if handler := getattr(self, handler_name, None):
|
if handler := getattr(self, handler_name, None):
|
||||||
handler(*command.parameters)
|
handler(*command.parameters)
|
||||||
else:
|
else:
|
||||||
logger.warning('Handler %s not found', handler_name)
|
logger.warning('Handler %s not found', handler_name)
|
||||||
self.send_response('ERROR')
|
self.send_response('ERROR')
|
||||||
|
|
||||||
def send_response(self, response: str) -> None:
|
def send_response(self, response: str) -> None:
|
||||||
"""Sends an AT response."""
|
"""Sends an AT response."""
|
||||||
|
|||||||
@@ -569,6 +569,37 @@ async def test_sco_setup():
|
|||||||
await asyncio.gather(*sco_disconnection_futures)
|
await asyncio.gather(*sco_disconnection_futures)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_hf_batched_response(
|
||||||
|
hfp_connections: Tuple[hfp.HfProtocol, hfp.AgProtocol]
|
||||||
|
):
|
||||||
|
hf, ag = hfp_connections
|
||||||
|
|
||||||
|
ag.dlc.write(b'\r\n+BIND: (1,2)\r\n\r\nOK\r\n')
|
||||||
|
|
||||||
|
await hf.execute_command("AT+BIND=?", response_type=hfp.AtResponseType.SINGLE)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_ag_batched_commands(
|
||||||
|
hfp_connections: Tuple[hfp.HfProtocol, hfp.AgProtocol]
|
||||||
|
):
|
||||||
|
hf, ag = hfp_connections
|
||||||
|
|
||||||
|
answer_future = asyncio.get_running_loop().create_future()
|
||||||
|
ag.on('answer', lambda: answer_future.set_result(None))
|
||||||
|
|
||||||
|
hang_up_future = asyncio.get_running_loop().create_future()
|
||||||
|
ag.on('hang_up', lambda: hang_up_future.set_result(None))
|
||||||
|
|
||||||
|
hf.dlc.write(b'ATA\rAT+CHUP\r')
|
||||||
|
|
||||||
|
await answer_future
|
||||||
|
await hang_up_future
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
async def run():
|
async def run():
|
||||||
await test_slc()
|
await test_slc()
|
||||||
|
|||||||
Reference in New Issue
Block a user