Skip to content

Commit

Permalink
add java files and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
shisx committed Mar 27, 2024
1 parent 65f3b11 commit 04e2c27
Show file tree
Hide file tree
Showing 67 changed files with 3,914 additions and 1 deletion.
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,61 @@
# protocol-jt808
# protocol-jt808

`protocol-jt808` 是一个实现了对《JT/T808 2019道路运输车辆卫星定位系统终端通讯协议及数据格式》数据进行解析与拼接的工具库。

* 基于`JDK8`,`Netty`

# 1 使用准备

## 1.1 引入依赖

`Maven`

```xml

<dependency>
<groupId>com.shisx.protocol</groupId>
<artifactId>protocol-jt808</artifactId>
<version>1.0.0</version>
</dependency>
```

## 1.2 数据解析

> 将字节数组解析成`JT808Message`对象
```java
class Example {
public static void main(String[] args) {
byte[] bytes = ...;
JT808Message jt808Message = JT808Message.parse(bytes);
}
}
```

## 1.2 数据拼装

> `JT808Message`对象转换字节数组
示例:为手机号为`123456789123456789`的终端构建一个`0x8100`消息

```java
class Example {
public static void main(String[] args) {
Msg8100 body = new Msg8100();
body.setAckSn((short) 1);
body.setResult((byte) 0);
body.setAuthCode("success");

JT808Message.build("123456789123456789", body);
}
}
```

## 1.2 作为服务

### 1.2.1 TCP服务

启动一个TCP服务,监听客户端发送的消息,并将消息解析成[JT808Message](/src/main/java/com/shisx/protocol/jt808/message/JT808Message.java)
对象,并进行业务处理

[TcpListener](/src/main/java/com/shisx/protocol/jt808/network/TcpListener.java)
Binary file added docs/JTT808-2019.pdf
Binary file not shown.
75 changes: 75 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.shisx.protocol</groupId>
<artifactId>protocol-jt808</artifactId>
<version>1.0.0</version>
<name>Protocol Of JTT808</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<developers>
<developer>
<id>shisx</id>
<name>ShiShouXing</name>
<email>[email protected]</email>
</developer>
</developers>

<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.107.Final</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.6</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
51 changes: 51 additions & 0 deletions src/main/java/com/shisx/protocol/jt808/message/IBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.shisx.protocol.jt808.message;

import io.netty.buffer.ByteBuf;

public interface IBuilder {

byte[] build();

default ByteBuf allowBuffer(int initialCapacity) {
return io.netty.buffer.Unpooled.buffer(initialCapacity, 10240);
}

default ByteBuf allowBuffer(int initialCapacity, int maxCapacity) {
return io.netty.buffer.Unpooled.buffer(initialCapacity, maxCapacity);
}

default ByteBuf fixBuffer(int capacity) {
return io.netty.buffer.Unpooled.buffer(capacity, capacity);
}

default byte[] readReadableBytes(ByteBuf byteBuf) {
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
return bytes;
}

default void writeFixLengthBytes(ByteBuf byteBuf, byte[] bytes, int length, int mode) {
int zeros = bytes == null ? length : length - bytes.length;

// 前补0x00
if (mode == 0) {
if (zeros > 0) {
byteBuf.writeZero(zeros);
}
if (bytes != null && bytes.length > 0) {
byteBuf.writeBytes(bytes);
}
}

// 后补0x00
if (mode == 1) {
if (bytes != null && bytes.length > 0) {
byteBuf.writeBytes(bytes);
}
if (zeros > 0) {
byteBuf.writeZero(zeros);
}
}
}

}
9 changes: 9 additions & 0 deletions src/main/java/com/shisx/protocol/jt808/message/IParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.shisx.protocol.jt808.message;

import io.netty.buffer.ByteBuf;

public interface IParser {

void parse(ByteBuf message);

}
106 changes: 106 additions & 0 deletions src/main/java/com/shisx/protocol/jt808/message/JT808Message.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.shisx.protocol.jt808.message;

import com.shisx.protocol.jt808.util.JT808Utils;
import com.shisx.protocol.jt808.util.ProtocolUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Data;

/**
* Desc
*
* @author Brook
*/
@Data
public class JT808Message implements IParser, IBuilder {

// 消息头
private MessageHead messageHead;
// 消息体
private MessageBody messageBody;

@Override
public void parse(ByteBuf message) {
messageHead = new MessageHead();
messageHead.parse(message);

try {
messageBody = MessageBody.buildByMsgId(messageHead.getMsgId());
if (messageBody == null) {
throw new RuntimeException("Can't parse the message: " + ProtocolUtil.short2Hex(messageHead.getMsgId()));
}

messageBody.parse(message);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("The message body parsing failed.", e);
}
}

@Override
public byte[] build() {
byte[] bodyBytes = messageBody.build();
messageHead.setBodyLength((short) bodyBytes.length);
return _build(messageHead.build(), bodyBytes);
}

public static JT808Message parse(byte[] bytes) {
// 转义还原
byte[] finalData = JT808Utils.flagRestore(bytes);

// 验证校验和
if (!JT808Utils.verifyCRC(finalData)) {
throw new RuntimeException("校验和不通过");
}

// 解析
JT808Message jt808Message = new JT808Message();
jt808Message.parse(Unpooled.wrappedBuffer(finalData));
return jt808Message;
}

public static byte[] build(String terminalNumber, MessageBody messageBody) {
JT808Message jt808Message = new JT808Message();

byte[] bodyBytes = messageBody.build();

MessageHead head = new MessageHead();
head.setMsgId(MessageBody.getMsgIdByClass(messageBody.getClass()));
head.setMsgSn(JT808Utils.genMsgSn());
head.setProtocolVersion((byte) 0x01);
head.setTerminalNumber(terminalNumber);
head.setBodyLength(bodyBytes == null ? 0 : (short) bodyBytes.length);

return jt808Message._build(head.build(), bodyBytes);
}

private byte[] _build(byte[] headBytes, byte[] bodyBytes) {
ByteBuf byteBuf = allowBuffer(1024);

// 标识位-头
byteBuf.writeByte((byte) 0x7E);

// 消息头
byteBuf.writeBytes(headBytes);

// 消息体
if (bodyBytes != null && bodyBytes.length > 0) {
byteBuf.writeBytes(bodyBytes);
}

// 校验码
byte[] currBytes = new byte[byteBuf.readerIndex(1).readableBytes()];
byteBuf.readBytes(currBytes);
byteBuf.writeByte(ProtocolUtil.xor(currBytes));

// 标识位-尾
byteBuf.writeByte((byte) 0x7E);

// 转义,并返回数据
byte[] allBytes = new byte[byteBuf.readerIndex(0).readableBytes()];
byteBuf.readBytes(allBytes);
return JT808Utils.flagTransference(allBytes);
}

}
52 changes: 52 additions & 0 deletions src/main/java/com/shisx/protocol/jt808/message/MessageBody.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.shisx.protocol.jt808.message;

import java.util.HashMap;
import java.util.Map;

public abstract class MessageBody implements IParser, IBuilder {

public static MessageBody buildByMsgId(short msgId) throws IllegalAccessException, InstantiationException {
Class<? extends MessageBody> clazz = BODY_MAP.get(msgId);
return clazz == null ? null : clazz.newInstance();
}

public static short getMsgIdByClass(Class<? extends MessageBody> clazz) {
return BODY_MAP2.get(clazz);
}

private static final Map<Short, Class<? extends MessageBody>> BODY_MAP = new HashMap<>();
private static final Map<Class<? extends MessageBody>, Short> BODY_MAP2 = new HashMap<>();

static {
register((short) 0x0001, Msg0001.class);
register((short) 0x0002, Msg0002.class);
register((short) 0x0003, Msg0003.class);
register((short) 0x0004, Msg0004.class);
register((short) 0x0100, Msg0100.class);
register((short) 0x0102, Msg0102.class);
register((short) 0x0104, Msg0104.class);
register((short) 0x0107, Msg0107.class);
register((short) 0x0108, Msg0108.class);
register((short) 0x0200, Msg0200.class);
register((short) 0x0201, Msg0201.class);
register((short) 0x8001, Msg8001.class);
register((short) 0x8004, Msg8004.class);
register((short) 0x8100, Msg8100.class);
register((short) 0x8103, Msg8103.class);
register((short) 0x8104, Msg8104.class);
register((short) 0x8105, Msg8105.class);
register((short) 0x8106, Msg8106.class);
register((short) 0x8107, Msg8107.class);
register((short) 0x8108, Msg8108.class);
register((short) 0x8201, Msg8201.class);
register((short) 0x8202, Msg8202.class);
register((short) 0x8203, Msg8203.class);
register((short) 0x8204, Msg8204.class);
register((short) 0x8300, Msg8300.class);
}

private static void register(short msgId, Class<? extends MessageBody> clazz) {
BODY_MAP.put(msgId, clazz);
BODY_MAP2.put(clazz, msgId);
}
}
Loading

0 comments on commit 04e2c27

Please sign in to comment.