Skip to content

feat: replace ModemManager with pure Python AT state machine#37439

Open
juzigu40-ui wants to merge 3 commits intocommaai:masterfrom
juzigu40-ui:feat/pure-python-modem
Open

feat: replace ModemManager with pure Python AT state machine#37439
juzigu40-ui wants to merge 3 commits intocommaai:masterfrom
juzigu40-ui:feat/pure-python-modem

Conversation

@juzigu40-ui
Copy link

@juzigu40-ui juzigu40-ui commented Feb 27, 2026

This PR replaces ModemManager AT-command handling with a pure Python AT state machine.

What is implemented

  1. Dual-chip support (EG25 + EG916) with one state machine

    • The modem type is detected at startup via ATI.
    • EG25 and EG916 use chip-specific setup commands, but both go through the same core state flow.
  2. No D-Bus dependency in the pure modem path + shared-memory state export

    • The Python modem path uses direct serial AT commands only.
    • State transitions are written to /dev/shm/modem_state.txt (e.g. CONNECTING, CONNECTED).
  3. WiFi-over-LTE route priority

    • Route metrics are explicitly adjusted so WiFi wins when both links are present.
    • Implemented using Linux route commands in the modem setup path.
  4. Fast cold-boot path

    • Non-essential waits were reduced.
    • Minimal attach sequence is used (AT+CGATT=1, AT+CGACT=1,1) to prioritize first connectivity.

Files

  • system/hardware/tici/pure_python_modem.py
  • system/hardware/tici/hardware.py
  • system/qcomgpsd/at_port_interceptor.py
  • system/hardware/tici/tests/test_pure_python_modem.py
  • tests/test_pure_python_modem.py

Local tests

  • pytest -q --noconftest -o addopts='' tests/test_pure_python_modem.py
  • Result: 4 passed

Community Validation Runbook (Copy/Paste)

1) No-hardware smoke (simulated state machine)

cd openpilot
python3 system/hardware/tici/pure_python_modem_dry_run.py   --simulate   --simulate-transient-fail   --state-path /tmp/modem_state_dry_run.txt   --json

Expected result:

  • result.attached == true
  • result.published_state == "CONNECTED"
  • AT trace includes a recovery cycle (AT+CFUN=0 -> AT+CFUN=1) before final attach.

2) Real-device run (comma 3X / comma 4)

cd openpilot
sudo OPENPILOT_PURE_MODEM_STRICT=1   OPENPILOT_MODEM_TTY=/dev/ttyUSB2   OPENPILOT_MODEM_APN="<your-apn>"   OPENPILOT_MODEM_REG_TIMEOUT=45   OPENPILOT_MODEM_STARTUP_RETRIES=1   python3 system/hardware/tici/pure_python_modem_dry_run.py --json --enforce-route

Expected result:

  • state=ATTACHED, attached=true
  • /dev/shm/modem_state.txt transitions to CONNECTED

3) Route priority check (WiFi > LTE)

ip route | grep default

Expected result:

  • WiFi default route keeps lower metric than LTE route.

4) Test report template

Device: comma 3X / comma 4
SIM Carrier + APN: <carrier/apn>
Boot to first ping (google.com): <seconds>
Run result: ATTACHED=<true/false>, model=<EG25/EG916>
modem_state.txt final value: <CONNECTED/...>
Route metrics snapshot: <paste ip route default lines>
Any reconnect events observed: <yes/no + short log>

@juzigu40-ui juzigu40-ui force-pushed the feat/pure-python-modem branch 3 times, most recently from ed27aed to f415e8b Compare February 27, 2026 07:13
@juzigu40-ui juzigu40-ui changed the title WIP: Pure Python Quectel Modem implementation replacing ModemManager feat: replace ModemManager with pure Python AT state machine Feb 27, 2026
@juzigu40-ui juzigu40-ui force-pushed the feat/pure-python-modem branch from f415e8b to 46689ad Compare February 27, 2026 07:16
@juzigu40-ui juzigu40-ui marked this pull request as ready for review February 27, 2026 07:38
@juzigu40-ui juzigu40-ui force-pushed the feat/pure-python-modem branch from 46689ad to 402de5b Compare February 27, 2026 07:56
@juzigu40-ui
Copy link
Author

Updated this PR with a copy/paste validation runbook:

  • no-hardware simulated dry-run (with transient attach failure + recovery)
  • real-device execution command for comma 3X/comma 4
  • route-priority verification (WiFi > LTE)
  • standardized report template for testers

Also pushed a pure_python_modem_dry_run.py diagnostic tool to make validation reproducible from one command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant