gt06
Parser and stream decoder for the GT06 GPS tracker protocol, with zero dependencies.
GT06 is used by a large family of low-cost GPS trackers to report location, status, and alarm events to a server over a raw TCP connection. This crate turns that byte stream into typed Rust values and builds the acknowledgement packets the devices expect back.
Status: pre-1.0. The API may change between minor versions until
1.0.0.
Features
- Stream decoder that reassembles packets from arbitrarily-chunked TCP reads, buffering partial packets.
- Single-packet parser for already-framed packets if you need it.
- Acknowledgement builder for the message types that require a reply.
- Typed messages and enums for every supported field.
Supported messages
| Protocol | Message | Parsed as | Needs ACK |
|---|---|---|---|
0x01 |
Login | Message::Login |
yes |
0x12 |
Location | Message::Location |
no |
0x22 |
Extended location | Message::Location |
no |
0x13 |
Status / heartbeat | Message::Status |
yes |
0x16 |
Alarm | Message::Alarm |
no |
Installation
Or add it to Cargo.toml:
[]
= "0.2"
Quick start
Feed raw bytes into a Decoder, handle each Message, and write back any ACK it
asks for:
use ;
let mut decoder = new;
// `chunk` is whatever you just read off the socket.
for result in decoder.push
decoder.push() returns one result per complete packet found. An incomplete
trailing packet is kept in the decoder's buffer and completed on a later push(),
so it's safe to feed it directly from a socket in whatever sizes reads arrive.
Usage
With a blocking std TCP server
use ;
use TcpListener;
use Decoder;
With an async tokio TCP server
gt06 has no async code of its own — the Decoder is a plain sync state
machine, so you just drive it from your own read loop.
use ;
use TcpListener;
use Decoder;
async
Parsing a single, already-framed packet
If you already have one complete packet (start marker through end marker) — say,
from a log file or a test — use parse_packet. It carries no connection state,
so the imei field on location/status/alarm messages is always None.
use ;
let packet: = ;
match parse_packet
Reading message data
use Message;
match message
Building an ACK by hand
Message::ack_bytes() covers the common case, but you can also build one
directly from a protocol byte and serial number:
use build_ack;
let ack = build_ack; // login ack for serial number 1
// -> [0x78, 0x78, 0x05, 0x01, 0x00, 0x01, 0xd9, 0xdc, 0x0d, 0x0a]
Handling errors
decoder.push() returns a Result per packet, and a bad packet never stops the
stream — the decoder resynchronizes on the next start marker and keeps going. The
Error enum covers short buffers, missing start/end markers, CRC mismatches,
unknown protocol numbers, and malformed messages. All variants implement
Display and std::error::Error.
Notes & caveats
- Timestamps are Unix seconds in UTC (
Fix::time). - Coordinates are signed decimal degrees, rounded to 6 decimal places.
- Several
Fixfields (satellites, cell tower info) areNonefor extended (0x22) location packets, which don't carry them. - The extended (
0x22) layout follows a length-based heuristic mirroring the reference implementation, as there's no single authoritative published layout.
API reference
Full documentation for every type, method, field, and enum variant lives on docs.rs/gt06. The main entry points are:
Decoder—new(),push(),imei()parse_packet()— parse a single framed packetbuild_ack()— build an acknowledgement packetMessage—ack_bytes(),expects_ack()
Testing
Contributing
Issues and pull requests are welcome.
License
MIT — see LICENSE.