# `IEC60870.CS104.Slave`
[🔗](https://github.com/Ultraluv/ex_iec60870/blob/main/lib/iec60870/cs104/slave.ex#L45)

IEC 60870-5-104 Slave / Server (`cs104_slave.c`).

Supports:
- TCP and TLS (`:ssl`) listening sockets
- Three redundancy modes:
  - `:single_redundancy_group` (default: single shared low/high priority queue; only one active connection at a time)
  - `:connection_is_redundancy_group` (each connection has its own independent low/high priority queue)
  - `:multiple_redundancy_groups` (connections are grouped by IP into `RedundancyGroup`s, each with its own queues and single active connection)
- Low-priority event queue (with ring-buffer overflow replacement and unconfirmed requeue on failover)
- High-priority response queue
- Standard application callbacks:
  - `interrogation_handler`: `fn conn_pid, asdu, qoi -> boolean() end`
  - `counter_interrogation_handler`: `fn conn_pid, asdu, qcc -> boolean() end`
  - `read_handler`: `fn conn_pid, asdu, ioa -> boolean() end`
  - `clock_sync_handler`: `fn conn_pid, asdu, cp56time2a -> boolean() | {:ok, CP56Time2a.t()} end`
  - `reset_process_handler`: `fn conn_pid, asdu, qrp -> boolean() end`
  - `delay_acquisition_handler`: `fn conn_pid, asdu, delay_ms -> boolean() end`
  - `asdu_handler`: `fn conn_pid, asdu -> boolean() end`
  - `connection_request_handler`: `fn {ip_str, port} -> boolean() end`
  - `connection_event_handler`: `fn conn_pid, event -> any() end`
  - `is_ca_allowed_handler`: `fn ca -> boolean() end`

# `server_mode`

```elixir
@type server_mode() ::
  :single_redundancy_group
  | :connection_is_redundancy_group
  | :multiple_redundancy_groups
```

# `add_redundancy_group`

```elixir
@spec add_redundancy_group(GenServer.server(), IEC60870.CS104.RedundancyGroup.t()) ::
  :ok
```

Adds a `RedundancyGroup` to the Slave (`CS104_Slave_addRedundancyGroup`).

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `enqueue_asdu`

```elixir
@spec enqueue_asdu(GenServer.server(), IEC60870.ASDU.t()) :: :ok
```

Enqueues a spontaneous/periodic ASDU into the low-priority transmission queue(s).
Matches `CS104_Slave_enqueueASDU` in `cs104_slave.c`.

# `enqueue_user_data`

```elixir
@spec enqueue_user_data(GenServer.server(), IEC60870.ASDU.t()) :: :ok
```

Enqueues an ASDU into the transmission queue(s). Convenience alias for `enqueue_asdu/2`.

# `get_apci_parameters`

```elixir
@spec get_apci_parameters(GenServer.server()) :: IEC60870.APCIParameters.t()
```

# `get_app_layer_parameters`

```elixir
@spec get_app_layer_parameters(GenServer.server()) :: IEC60870.AppLayerParameters.t()
```

# `get_number_of_queue_entries`

```elixir
@spec get_number_of_queue_entries(
  GenServer.server(),
  IEC60870.CS104.RedundancyGroup.t() | non_neg_integer() | nil
) :: non_neg_integer()
```

Returns the number of entries in the low-priority ASDU queue (`CS104_Slave_getNumberOfQueueEntries`).
If `redundancy_group` is `nil`, returns the count for the default queue (or first redundancy group).

# `get_open_connections`

```elixir
@spec get_open_connections(GenServer.server()) :: non_neg_integer()
```

Returns the number of currently open client connections.

# `get_port`

```elixir
@spec get_port(GenServer.server()) :: {:ok, non_neg_integer()} | {:error, term()}
```

Returns the actual local TCP port the server is listening on (useful when started with `port: 0`).

# `is_running?`

```elixir
@spec is_running?(GenServer.server()) :: boolean()
```

Checks whether the Slave server is currently listening for connections (`CS104_Slave_isRunning`).

# `start`

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

# `start_link`

Starts a `CS104.Slave` server process.
By default starts listening immediately unless `auto_start: false` is passed.

# `stop`

```elixir
@spec stop(GenServer.server()) :: :ok
```

---

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