22b1b069df
Initialize CLAUDE.md schema, index, and log; ingest three architecture sources (system overview, Teltonika ingestion design, official Teltonika data-sending protocols) into 7 entity pages, 8 concept pages, and 3 source pages with wikilink cross-references.
76 lines
3.6 KiB
Markdown
76 lines
3.6 KiB
Markdown
---
|
|
title: Codec Dispatch (Registry)
|
|
type: concept
|
|
created: 2026-04-30
|
|
updated: 2026-04-30
|
|
sources: [teltonika-ingestion-architecture, teltonika-data-sending-protocols]
|
|
tags: [teltonika, parser, design-seam]
|
|
---
|
|
|
|
# Codec Dispatch
|
|
|
|
How the [[teltonika]] adapter routes incoming frames to the right parser, and the seam that makes [[phase-2-commands]] additive instead of a rewrite.
|
|
|
|
## The mechanism
|
|
|
|
The codec ID (byte 0 of the AVL data payload) indexes into a **flat registry** of handlers. Each handler implements:
|
|
|
|
```ts
|
|
interface CodecHandler {
|
|
codec_id: number
|
|
handle(
|
|
payload: Buffer,
|
|
ctx: { imei: string; publish: (p: Position) => Promise<void> }
|
|
): Promise<{ ack_count: number }>
|
|
}
|
|
```
|
|
|
|
Phase 1 registers handlers for IDs `0x08`, `0x8E`, and `0x10`. Phase 2 will register additional handlers for `0x0C`, `0x0D`, `0x0E` — these will use a different `ctx` shape (they need to write bytes back, not just `publish`), but the registry shape is identical.
|
|
|
|
Per-codec directionality matters for the Phase 2 handler shape:
|
|
|
|
| Codec | ID | Direction | Handler needs |
|
|
|-------|-----|-----------|---------------|
|
|
| 8 / 8E / 16 | `0x08` / `0x8E` / `0x10` | device → server | `publish(Position)` only |
|
|
| 12 | `0x0C` | bidirectional | `respond(bytes)` for outbound + parse responses |
|
|
| 13 | `0x0D` | device → server only | parse-only (no `respond`) |
|
|
| 14 | `0x0E` | bidirectional | `respond(bytes)` + ACK type `0x06` / nACK type `0x11` |
|
|
| 15 | `0x0F` | device → server only | out of scope (FMX6 RS232 only) |
|
|
|
|
Codec 13 and 15, despite living in the GPRS-message family, are *one-way* — handlers for them never write to the socket. This matters for handler-shape design: the Phase 2 outbound family is not "all command codecs," it's specifically `0x0C` and `0x0E`.
|
|
|
|
## Why a registry, not a switch
|
|
|
|
- Adding a new codec is a registration, not a code change in dispatch logic.
|
|
- Phase 2 command codecs slot in alongside Phase 1 data codecs without modifying Phase 1 paths.
|
|
- Codec parsers are **independent** — there is no shared base class. Their record shapes diverge in ways abstraction would obscure rather than help.
|
|
|
|
## The "session owns the socket; handler borrows it" rule
|
|
|
|
Phase 1 handlers receive payload + a `publish(Position)` callback and emit records via Redis. They never write to the socket directly — the session loop handles ACKs.
|
|
|
|
Phase 2 command handlers will need to **write to the socket** (to send commands). They borrow write access through a `respond(bytes: Buffer)` callback added to `ctx` for command codecs. The session retains socket ownership; handlers borrow write access through a narrow interface.
|
|
|
|
## Unknown codec policy
|
|
|
|
When the codec ID does not match a registered handler:
|
|
|
|
- `WARN` log entry with IMEI, offending codec ID, raw header bytes.
|
|
- Socket is destroyed.
|
|
- No ACK sent.
|
|
- No attempt to "skip ahead" or guess record layout.
|
|
|
|
Reasoning: a Teltonika device sending an unrecognized codec is **misconfigured**, not subtly broken. Silently truncating its data — or worse, mis-parsing — produces records with plausible-looking but wrong coordinates. Loud failure beats quiet corruption.
|
|
|
|
The `teltonika_unknown_codec_total{codec_id}` counter is the canary for codec coverage drift.
|
|
|
|
## CRC failure policy
|
|
|
|
Different from unknown-codec. CRC mismatch = transient transmission issue:
|
|
|
|
- Frame is **not** ACK'd → device retransmits on next session.
|
|
- `WARN` log with IMEI, expected CRC, computed CRC, frame length.
|
|
- Connection stays open.
|
|
|
|
Repeated CRC failures from the same device in a short window indicate a deeper problem (firmware, line quality) — surface via metrics, not just logs.
|