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.
6.3 KiB
title, type, created, updated, sources, tags
| title | type | created | updated | sources | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| AVL Data Format (Teltonika canonical) | concept | 2026-04-30 | 2026-04-30 |
|
|
AVL Data Format
The canonical Teltonika AVL packet structure across codecs 8, 8E, and 16. This is the byte-level reference the teltonika adapter implements. See teltonika-data-sending-protocols for the official source and codec-dispatch for how the codec ID byte selects between the three formats.
Outer envelope (TCP)
┌────────────────┬──────────────────┬──────────┬────┬──────────┬────┬───────┐
│ Preamble │ Data Field Length│ Codec ID │ N1 │ AVL Data │ N2 │ CRC-16│
│ 4B = 0x00000000│ 4B │ 1B │ 1B │ X bytes │ 1B │ 4B │
└────────────────┴──────────────────┴──────────┴────┴──────────┴────┴───────┘
- Data Field Length is computed from the start of
Codec IDthroughN2(not the whole packet). - CRC-16/IBM is computed over the same range. Lower 2 bytes of the 4-byte CRC field carry the value; upper 2 bytes are zero.
- N1 must equal N2 — record count repeated for integrity.
- Server ACK is a 4-byte big-endian integer equal to the number of records accepted. Mismatched count → device retransmits.
AVL record (one of N records)
[Timestamp 8B][Priority 1B][GPS Element 15B][IO Element X B]
- Timestamp: UNIX milliseconds since epoch (UTC), big-endian.
- Priority: enum —
0Low,1High,2Panic.
GPS Element (15B)
[Longitude 4B][Latitude 4B][Altitude 2B][Angle 2B][Satellites 1B][Speed 2B]
- Lat/Lon: signed 32-bit integer =
((d + m/60 + s/3600 + ms/3600000) × 10⁷), where d/m/s/ms are degrees/minutes/seconds/milliseconds. Two's complement — first bit = sign (0 positive, 1 negative). - Altitude: meters above sea level, signed 16-bit.
- Angle: heading 0–360°, unsigned 16-bit.
- Satellites: count of satellites in use, unsigned 8-bit.
- Speed: km/h, unsigned 16-bit.
0x0000when GPS data is invalid — distinct from "stationary."
IO Element — codec-specific
The IO Element layout is where the three codecs diverge. The parser must dispatch on codec ID to read these correctly.
Codec 8 (0x08) — 1-byte everything
[Event IO ID 1B]
[N total 1B]
[N1 1B] [IO ID 1B][Value 1B] × N1
[N2 1B] [IO ID 1B][Value 2B] × N2
[N4 1B] [IO ID 1B][Value 4B] × N4
[N8 1B] [IO ID 1B][Value 8B] × N8
Codec 8 Extended (0x8E) — 2-byte fields + variable-length
[Event IO ID 2B]
[N total 2B]
[N1 2B] [IO ID 2B][Value 1B] × N1
[N2 2B] [IO ID 2B][Value 2B] × N2
[N4 2B] [IO ID 2B][Value 4B] × N4
[N8 2B] [IO ID 2B][Value 8B] × N8
[NX 2B] [IO ID 2B][Length 2B][Value <Length>B] × NX ← variable-length section
The NX section is unique to 8E. Carries arbitrary-length values (e.g. ICCID-class data, BLE payloads). Each entry self-describes its length. The parser must be length-aware here — getting it wrong silently corrupts subsequent records.
Codec 16 (0x10) — Generation Type, mixed widths
[Event IO ID 2B]
[Generation Type 1B] ← unique to Codec 16
[N total 1B]
[N1 1B] [IO ID 2B][Value 1B] × N1
[N2 1B] [IO ID 2B][Value 2B] × N2
[N4 1B] [IO ID 2B][Value 4B] × N4
[N8 1B] [IO ID 2B][Value 8B] × N8
- No NX section — Codec 16 does not include variable-size IO elements.
- Generation Type values:
0=On Exit,1=On Entrance,2=On Both,3=Reserved,4=Hysteresis,5=On Change,6=Eventual,7=Periodical. - Codec 16 is the channel for AVL IDs > 255 on FMB630/FM63XY.
Side-by-side
| Codec 8 | Codec 8 Extended | Codec 16 | |
|---|---|---|---|
| Codec ID | 0x08 | 0x8E | 0x10 |
| Event IO ID width | 1B | 2B | 2B |
| N total / Nk count widths | 1B / 1B | 2B / 2B | 1B / 1B |
| IO ID width | 1B | 2B | 2B |
| Generation Type | — | — | 1B |
| Variable-length IO (NX) | — | yes | — |
| AVL IDs > 255 supported | no | yes | yes |
Size limits
- Minimum AVL record: 45 bytes (all IO elements disabled).
- Maximum AVL record: 255 bytes.
- Maximum AVL packet: 512 bytes for FMB640/FMB641/FMC640/FMM640; 1280 bytes for other devices.
The parser should treat oversized packets as malformed (drop the connection per the codec-dispatch unknown-codec policy — though this is a different malformation, the same loud-failure principle applies).
UDP envelope
When the device runs over UDP instead of TCP:
[UDP Channel Header 5B] [AVL Packet Header (1+2+15)B] [AVL Data Array — same as TCP]
- UDP Channel Header:
Length 2B + Packet ID 2B + Not Usable Byte 1B. - AVL Packet Header:
AVL Packet ID 1B + IMEI Length 2B = 0x000F + IMEI 15B. - Server ACK over UDP is short:
[UDP Channel Header 5B][AVL Packet ID 1B][Number Accepted 1B].
The AVL Data Array (Codec ID byte + records + N2) is identical to TCP. The Phase 1 implementation is TCP-only; UDP is documented here for completeness and future evaluation.
Mapping to position-record
The parser writes:
device_id← IMEI from the handshake (or from the UDP AVL Packet Header).timestamp← AVL recordTimestamp(UNIX ms →Date).latitude,longitude,altitude,angle,speed,satellites← GPS Element fields, with two's-complement decoding for lat/lon andSpeed === 0x0000 ⇒ "GPS invalid"retained as-is (the Processor decides how to surface it).priority← AVL recordPriority(0/1/2).attributes← every IO element from N1/N2/N4/N8 (and NX for Codec 8E), keyed by numeric IO ID as string, value asnumber | bigint | Bufferper IO width. See io-element-bag for why naming/units stay out of the parser.
Note: Codec 16's
Generation Typeand 8E's NXLengthare not currently in the position-record shape. Generation Type is codec-defined (not model-defined) and may deserve a typed field — flagged as an open question on the source page.