#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Helper for parsing AT command responses. """ import logging from typing import TYPE_CHECKING if TYPE_CHECKING: from m2m.serial.serial_port import SerialPort logger = logging.getLogger('atparser') class AtParser: """ Parses responses from the serial port to determine command success/failure. """ def __init__(self, serial_port: 'SerialPort'): self._port = serial_port self._last_response = b'' @property def last_response(self) -> bytes: return self._last_response def read_ok(self, timeout: float = 1.0) -> bool: """ Reads until a terminator is found and checks if it was 'OK'. """ self._last_response = self._port.read_until(terminator=b'OK', timeout=timeout) # Check if the buffer *ends* with OK, or contains it on a line. # Strict check: lines = self._last_response.splitlines() for line in reversed(lines): line = line.strip() if line == b'OK': return True if line == b'ERROR' or b'CME ERROR' in line: return False return False def is_on(self, query_cmd: bytes, response_prefix: bytes, timeout: float = 1.0) -> bool: """ Sends a query and checks if the value is '1'. Example: is_on(b'AT+CFUN?', b'+CFUN:') """ self._port.send_cmd(query_cmd) response = self._port.read_until(timeout=timeout) self._last_response = response # Parse for prefix for line in response.splitlines(): line = line.strip() if line.startswith(response_prefix): # +CFUN: 1 try: # Remove prefix, then split by comma if multiple params # We assume the first param is the status payload = line[len(response_prefix):].strip() # Handle cases like "1" or "1,0" val_str = payload.split(b',')[0] return int(val_str) == 1 except ValueError: pass return False