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:

  1. Open the AT tty.
  2. Configure the radio: ATE0, verbose errors, AT+CEREG=2, AT+CFUN=1, set the APN (AT+CGDCONT), automatic operator selection (AT+COPS=0).
  3. Poll AT+CEREG? until registered (stat 1 = home or 5 = roaming).
  4. Bring the ECM data call up via the VintageNetECM.Modem implementation. DHCP on the netdev — run by the composed VintageNetEthernet config — then obtains the lease.
  5. Publish the modem/SIM identity (see property/0) once, retrying anything the modem wasn't ready to answer.
  6. 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.

PropertySource
"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

property()

@type property() :: String.t()

The name of a property published under ["interface", ifname, "mobile", ...].

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

deactivate_data_call(modem, tty, context_id)

@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.

network_time(ifname)

@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.