# `NervesGate.Buses`

CAN and RS485 ownership, SDK access and bounded diagnostics on allowlisted ports.

SDK serial claims exclude diagnostics and are released on owner exit. CAN
receive sockets are shared by process-owned subscriptions. SDK sends never
configure an interface or leave listen-only mode.

## Commands

`configure/3`, `capture/2` and `modbus_read/3` return `:ok` when accepted,
or `{:error, reason}`. CAN configuration and diagnostics complete asynchronously;
RS485 configuration changes its in-memory opt-in immediately. Only one worker
runs at a time. Read `status/1` for completion, errors and results.

## Queries and notifications

`status/1` returns detected ports, the current operation and the last result.
`observe/1` subscribes the caller to changes. Idle observations never open UARTs
or transmit traffic. Serial opt-in and results reset on restart.
The optional server argument defaults to this module.

`:bus_port_unavailable` reports a missing, known enabled port. CAN enablement
comes from observations; RS485 from explicit opt-in. Missing observations never
erase known enablement. An observed return or removal of opt-in clears the
condition. After restart, unknown CAN state preserves the previous alarm.

# `capture`

```elixir
@spec capture(String.t(), GenServer.server()) :: :ok | {:error, term()}
```

Start receive-only capture on an enabled port: up to five seconds, 200 frames or 4096 bytes.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `configure`

```elixir
@spec configure(String.t(), map(), GenServer.server()) :: :ok | {:error, term()}
```

Configure can0/can1 or opt ttyS3/ttyS4 in or out of diagnostics.

Params use string keys: `"enabled"` is required; CAN also requires a supported
`"bitrate"` and defaults to listen-only mode. Administrators can explicitly set
`"listen_only" => false` to permit SDK transmission; passive diagnostics still
require listen-only mode. RS485 uses fixed 9600 8N1.

# `modbus_read`

```elixir
@spec modbus_read(String.t(), map(), GenServer.server()) :: :ok | {:error, term()}
```

Request one authorized Modbus RTU read on ttyS3/ttyS4, without retry.

String-keyed params: `"authorized"` must be true, `"unit"` 1–247,
`"function"` 3 or 4, `"address"` zero-based 0–65535, and `"count"` 1–32
without crossing address 65535. The operator must ensure no other master is active.

# `observe`

```elixir
@spec observe(GenServer.server()) :: :ok | {:error, :unavailable}
```

Subscribe the caller to bus status/result hints; reread status on notification.

# `status`

```elixir
@spec status(GenServer.server()) :: map()
```

Read ports, operation, result and error. An accepted operation finishes when operation is nil.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
