# JT808: a C# implementation of the Chinese vehicle terminal protocol

> JT808 is a C# library for the JT/T 808 transport protocol used by Chinese vehicle tracking terminals, with packet framing, escaping, checksum handling and per-message body types for the 2011, 2013 and 2019 revisions. The interesting engineering is in the serializer and the extension points for proprietary message IDs, and the weakness is that the documentation lives in a Chinese README.

**SmallChi/JT808** — JT/T808 protocol,JT808 protocol, GB808 protocol (support 2011, 2013, 2019 version)  JT/T808协议、JT808协议、GB808协议(支持2011、2013、2019版本)

- Repository: https://github.com/SmallChi/JT808
- Stars: 613 · Forks: 277
- Language: C#
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/smallchi-jt808

## What the protocol is and who has to speak it

JT808 is a library for the JT/T 808 protocol, also referred to as the JT808 and GB808 protocols, and the repository description states that it supports the 2011, 2013 and 2019 versions of the standard.

The protocol itself is the transport layer for vehicle terminals in China, and the reason a library like this exists is that the wire format is not difficult in principle but is fiddly in practice. A packet is framed, the body is escaped, a checksum covers the frame, and the body layout differs per message ID. Any one of those steps done slightly wrong produces a terminal that ignores you, and the debugging loop for that is expensive because the symptom is silence rather than an error.

The implementation is C# and the package is MIT licensed. The repository topics give a good picture of the scope: jt808, jt1078, jt19056, jtt808, jtt19056, gb19056, gb808, 1078, 808, gps and tracker, alongside csharp, dotnet, dotnetcore, net8, net9 and net10. So this is not a single message parser, it is a family of related Chinese transport standards handled by one library, and the tracker and GPS topics say who the audience is: teams building systems that talk to vehicle trackers.

The release history is steady, with v2.8.2 from 2026-09-16, v2.7.3 from 2025-07-18 and v2.7.2 from 2025-04-01, and the last push to the repository was on 2026-09-16, so the project is not abandoned.

## Packet framing, and the escaping rule that hides the payload

The packet structure is a fixed five part frame: a begin marker, the data header, the body or sub-package body, a checksum byte, and an end marker. The begin and end markers are both 0x7E, and the middle three parts are the header, the body and the checksum.

The header is where the routing information lives. It carries the message ID, the message body properties, the protocol version number for the 2019 revision, the terminal phone number, the message sequence number, and, when a message is split, the total package count and the package index. The body properties are themselves a small struct of the version flag for the 2019 revision, the split flag, the encryption flag and the body length.

The part that catches people out is escaping, and the library treats it as a first class concern rather than an afterthought. The rule applies to the data content with the head and tail markers excluded. A 0x7E byte in the content is replaced by 0x7D followed by 0x02, and a 0x7D byte in the content is replaced by 0x7D followed by 0x01. The stated reason is to make the TCP message boundaries of the JT808 protocol unambiguous, and the mechanism is the classic one: the escape sequences make the reserved marker byte impossible to confuse with data, so a receiver can find the frame end without a length field, and a payload byte cannot be mistaken for a terminator.

Working the escape in the other direction is equally mechanical, and the README walks through it with a real packet. The example shows the original frame with the escape sequences visible in parentheses, then the unescaped form where 7D 02 becomes 7E and 7D 01 becomes 7D, and then a field by field breakdown of the result: the head marker, then the message ID from the header, the body properties, the terminal phone number, the message sequence number, and then the body fields, the attached information, the checksum byte and the tail marker. That example is the clearest available description of the format, and it is worth reading in full before you write anything against it.

## Serialising a location report in code

The example in the README builds a 0x0200 message, a position report, and serialises it. The shape of the API is a package object with a header and a body, and the body is one of the typed message classes.

```csharp
JT808Package jT808Package = new JT808Package();
jT808Package.Header = new JT808Header
{
    MsgId = (ushort)JT808.Protocol.Enums.JT808MsgId._0x0200,
    ManualMsgNum = 126,
    TerminalPhoneNo = "123456789012"
};
```

The message ID comes from an enum, so a message type is a named constant rather than a magic number, and the sequence number can be set manually with ManualMsgNum, which is what a test wants. The terminal phone number is the identifier the device is known by.

The body is then assigned, serialised, and dumped as hex:

```csharp
jT808Package.Bodies = jT808_0x0200;
byte[] data = JT808Serializer.Serialize(jT808Package);
var hex = data.ToHexString();
```

The body type for a position report carries the alarm flag, the altitude, the GPS time, the latitude and longitude as scaled integers rather than decimal degrees, the speed, the direction, the status flag, and a dictionary of attached information keyed by a byte identifier. The scaled-integer representation for coordinates is a detail of the protocol rather than of the library, and it is the kind of thing that produces plausible but wrong positions if you assume the values are degrees.

The attached information dictionary is how optional extra data rides along. The example adds a mileage entry and an oil entry under their own identifiers, and the type names carry the message ID and the attachment ID, so a reader can tell at a glance which field belongs to which part of the protocol.

## Deserialising, and what the tests assert

Deserialisation takes a byte array and gives you back a package, and the README's example shows the whole path: turn a hex string into bytes, deserialise, then assert on the header and the body.

```csharp
byte[] bytes = "7E 02 00 00 26 12 34 56 78 90 12 00 7D 02 00 00 00 01 00 00 00 02 00 BA 7F 0E 07 E4 F1 1C 00 28 00 3C 00 00 18 10 15 10 10 10 01 04 00 00 00 64 02 02 00 7D 01 13 7E".ToHexBytes();
var jT808Package = JT808Serializer.Deserialize(bytes);
Assert.Equal(Enums.JT808MsgId._0x0200, jT808Package.Header.MsgId);
Assert.Equal(38, jT808Package.Header.MessageBodyProperty.DataLength);
```

The assertions are worth studying because they document the deserialised shape precisely: the message ID, the computed body length of 38, the sequence number, the terminal phone number, the split flag being false, the package index and count both zero, and the encryption method being none.

The body assertions follow the same pattern, checking the alarm flag, the altitude, the GPS time parsed into a DateTime, the scaled coordinates, the speed, the direction and the status flag, and then reaching into the attached information dictionary to check the mileage and the oil value under their identifiers.

Note what is not asserted. There is no assertion about the checksum, which tells you the deserialiser is not verifying it by default, and there is no assertion about the escaping, because the input bytes here still contain the escape sequences. That is consistent with the configuration model in the next section, where checksum validation and the factory mappings are both things you set explicitly.

## Configuration objects are where vendor extensions live

The library's answer to vendor-specific messages is a configuration object rather than a base class you are expected to subclass, and that is the most extensible part of the design.

```csharp
IJT808Config DT1JT808Config = new DT1Config();
IJT808Config DT2JT808Config = new DT2Config();
DT1JT808Config.SkipCRCCode = true;
DT1JT808Config.MsgIdFactory.SetMap<DT1Demo6>();
DT1JT808Config.FormatterFactory.SetMap<DT1Demo6>();
JT808Serializer DT1JT808Serializer = new JT808Serializer(DT1JT808Config);
```

Each configuration instance belongs to one device or one vendor, and a serializer is constructed with a configuration. The MsgIdFactory maps a custom message type to its message ID, and the FormatterFactory maps it to the formatter that knows how to read and write that body. Registering an external assembly lets the library discover the custom types at run time, which is how a vendor extension is added without touching the library itself.

The SkipCRCCode flag is the escape hatch for devices whose checksum does not follow the standard. That is a real and common need in this ecosystem, since some terminals were built with a different checksum calculation, and having it as a per-configuration flag rather than a global setting means you can talk to a misbehaving device and a correct one in the same process.

Having two configurations and two serializers in the same snippet is the point rather than an accident: it shows that the library is designed for a fleet where different devices speak different dialects, which is the normal case in Chinese vehicle tracking.

## Where the documentation will slow you down

The first limitation is language. The repository carries both a Chinese README.md and an English README.en.md, and the primary README is the Chinese one, with the English version linked from it. The English version covers less. For a reader working in English, the practical situation is that the protocol tables, the escaping rules and the field by field breakdown of a decoded packet are in the Chinese document, and the code samples are the part that carries across.

The second limitation is the message catalogue. The library covers a family of standards, jt808, jt1078, jt19056, jtt808, jtt19056 and gb19056 according to the repository topics, and the README's own table of contents lists sections for the 2019 version features, so the surface is large and the documentation of it is a set of tables rather than prose. The named message IDs and their body layouts are the thing you will actually look up, and the source is the reference for them.

The third limitation is that the library does not do the transport. It serialises and deserialises packets; something else has to open the TCP connection, decide when to send a heartbeat, deal with a terminal that never answers and retry a request that timed out. The packet layer is the part that is genuinely hard to get right and the part this library handles, and the session layer is the part it leaves entirely to you.

The real alternative for the transport question is to write the framing yourself. It is a day of work, the format is documented in the standard, and what you gain is total control over the connection handling, the retry policy and the heartbeats, plus no dependency. What you lose is the typed bodies for the standard message IDs, the per-device configuration model and the extension points, all of which represent considerably more than the framing itself. The sensible split for most teams is to use this library for the packets and keep the session logic in your own code, and to check the two things that will bite first: the coordinate scaling, which is not degrees, and the checksum, which some terminals compute differently.

## Conclusion

Adopt JT808 if you are integrating Chinese vehicle tracking terminals and need packet framing, escaping and checksum handling that already matches the specification, plus typed bodies for the standard message IDs. Do not adopt it if you need a documented API surface, because the repository's own documentation is a Chinese README with an English version that covers less, and the source is where the real reference is. Before you build on it, confirm the target framework, since the repository topics list net8, net9 and net10 while the newest release v2.8.2 is from 2026-09-16, and read the protocol tables in the README against the standard your terminals actually speak.

## FAQ

### What is the JT808 C# library?

It is an MIT licensed C# implementation of the JT/T 808 protocol, also known as JT808 and GB808, supporting the 2011, 2013 and 2019 versions of the standard. The repository topics show it also covers the related jt1078, jt19056, jtt808, jtt19056 and gb19056 standards.

### How does JT808 escape packet content?

The rule applies to the data content with the head and tail markers excluded. A 0x7E byte in the content is replaced by 0x7D followed by 0x02, and a 0x7D byte is replaced by 0x7D followed by 0x01. The stated reason is to confirm the TCP message boundaries of the JT808 protocol.

### How do I add a custom message ID to JT808?

You create a configuration, register the external assembly that contains your custom message type, and map the type in both the MsgIdFactory and the FormatterFactory before constructing a serializer with that configuration. Each configuration can also set SkipCRCCode for terminals whose checksum does not follow the standard.

### What are the JT808 coordinates and time fields like in code?

In the position report body the latitude and longitude are plain integers rather than decimal degrees, and the GPS time is a DateTime. The example uses latitude 12222222 and longitude 132444444, and the deserialisation example asserts the same scaled values along with the altitude, speed, direction and status flag.

### Does the JT808 library handle the network connection?

No. The library covers packet serialisation and deserialisation through JT808Serializer, and the README does not describe a session or transport layer. Opening the TCP connection, heartbeats, retries and timeouts remain the responsibility of the application that uses it.

## Sources

- [Issues](https://github.com/SmallChi/JT808/issues)
- [License: MIT](https://github.com/SmallChi/JT808/blob/master/LICENSE)
- [README](https://github.com/SmallChi/JT808/blob/master/README.md)
- [Releases](https://github.com/SmallChi/JT808/releases)
- [SmallChi/JT808 on GitHub](https://github.com/SmallChi/JT808)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/smallchi-jt808
