VintageNetECM. ATController
(vintage_net_ecm v0.2.0)
Copy Markdown
Supervised AT-control sidecar for VintageNetECM.
Started by VintageNet (as a child_spec) once the ECM netdev is present. Lifecycle:
- Open the AT tty.
- Configure the radio:
ATE0, verbose errors,AT+CEREG=2,AT+CFUN=1, set the APN (AT+CGDCONT), automatic operator selection (AT+COPS=0). - Poll
AT+CEREG?until registered (stat 1 = home or 5 = roaming). - Bring the ECM data call up via the
VintageNetECM.Modemimplementation. DHCP on the netdev — run by the composedVintageNetEthernetconfig — then obtains the lease. - Publish the modem/SIM identity (see
property/0) once, retrying anything the modem wasn't ready to answer. - Periodically publish registration, signal, technology and serving-cell details
under
["interface", ifname, "mobile", ...]and re-activate the data call if it drops.
Steps 1-3 and the identity/registration/signal reporting use standard 3GPP commands
handled here. The vendor-specific bits — data-call control, access technology, ICCID,
serving-cell info and network time — are delegated to the configured
VintageNetECM.Modem implementation (defaulting to VintageNetECM.Modem.Quectel).
Teardown is handled out-of-band by deactivate_data_call/3 (a VintageNetECM
down_cmds :fun), because VintageNet kills this process before running down_cmds,
so terminate/2 is not a reliable place to talk to the modem.
Published properties
Everything is published under ["interface", ifname, "mobile", ...]. A property is
nil when the modem couldn't answer for it.
| Property | Source |
|---|---|
"manufacturer", "model", "firmware_version" | AT+CGMI / AT+CGMM / AT+CGMR |
"imei", "serial_number" | AT+CGSN / AT+CGSN=0 |
"imsi" | AT+CIMI |
"iccid" | VintageNetECM.Modem.iccid/1 |
"registration" | AT+CEREG? |
"signal_dbm" | AT+CSQ |
"operator" | AT+COPS? |
"access_technology" | VintageNetECM.Modem.access_technology/1 |
"mcc", "mnc", "cell_id", "tac", "band", "channel", "rsrp_dbm", "rsrq_db", "sinr_db" | VintageNetECM.Modem.network_info/1 |
"timezone", "utc_offset", "dst_offset" | VintageNetECM.Modem.network_time/1, falling back to AT+CCLK? |
The current time is deliberately not a property — it would be stale the moment it
was published. Read it with VintageNetECM.utc_now/1 instead.
Summary
Types
The name of a property published under ["interface", ifname, "mobile", ...].
Functions
Returns a specification to start this module under a supervisor.
Tear the modem's ECM data call down. Invoked from VintageNetECM down_cmds, where
the controller GenServer is already gone — so this opens its own short-lived UART and
delegates the actual command to the VintageNetECM.Modem implementation.
Ask the modem what time the network says it is.
Types
@type property() :: String.t()
The name of a property published under ["interface", ifname, "mobile", ...].
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec deactivate_data_call(module(), String.t(), pos_integer()) :: :ok
Tear the modem's ECM data call down. Invoked from VintageNetECM down_cmds, where
the controller GenServer is already gone — so this opens its own short-lived UART and
delegates the actual command to the VintageNetECM.Modem implementation.
@spec network_time(VintageNet.ifname()) :: {:ok, VintageNetECM.Modem.network_time()} | {:error, term()}
Ask the modem what time the network says it is.
The AT tty is owned by this GenServer, so the query is serialized with the rest of
the lifecycle rather than opening a second connection. Returns
{:error, :not_running} if ifname has no VintageNetECM controller.