# mgf-tele-teltonika

Teltonika **Codec 8 / 8 Extended** decoder + a `TelematicsProvider`
implementation for FMB/FMC/FMM devices. The first vendor package in the
`mgf-tele-*` family — it builds on [`mgf-tele-core`](../mgf-tele-core)
(the vendor-neutral seam) and never the other way around.

Extracted from PlasmaMapper's ingest path.

## Install

```bash
pip install mgf-tele-teltonika
```

## Use

```python
from mgf.tele.teltonika import TeltonikaProvider, decode_avl_packet

# Decoder (pure: bytes -> mgf.tele.core.DecodedAvlRecord[]):
records = decode_avl_packet(wire_bytes)

# Provider (the mgf.tele.core.TelematicsProvider seam) in an ingest loop:
provider = TeltonikaProvider(imei_authoriser=my_registry_lookup)
handle = await provider.open_session(reader, writer)   # IMEI handshake
packet = await provider.receive_packet(handle)         # ReceivedPacket
```

## What's in it

| Name | What |
|---|---|
| `decode_avl_packet` / `decode_codec8` / `decode_codec8e` | pure decoders → `mgf.tele.core.DecodedAvlRecord`; unsupported codecs raise `mgf.tele.core.UnsupportedCodecError` |
| `TeltonikaProvider` / `TeltonikaSessionHandle` | the `TelematicsProvider` concrete (TCP handshake → receive → ack → close) |
| `mgf.tele.teltonika._crc.crc16_ibm` | the CRC-16/IBM primitive |
| `mgf.tele.teltonika._packets` | wire-packet encoders (round-trip testing) |

Codec 12 RX (command responses), 13/14/15, and 16 are not yet
implemented and raise `UnsupportedCodecError`.

## Design

- The decoder is a **pure function** (`bytes → records`); the provider
  owns the session lifecycle (the `mgf-tele-core` two-layer shape).
- Every malformed-frame / CRC / unsupported-codec / handshake / unknown-
  tracker / peer-close condition is a typed `mgf.tele.core.TelematicsError`
  subclass (rule EH-02).
- A 64 KiB frame cap (SH-04) bounds the unauthenticated ingest socket
  against a hostile `data_field_length`.
