Support versioned JT808 encoder

This commit is contained in:
Anton Tananaev
2026-05-08 20:45:29 -07:00
parent 99f45bc590
commit ec6fcb5d7f
2 changed files with 42 additions and 31 deletions

View File

@@ -92,7 +92,7 @@ public class Jt808ProtocolDecoder extends BaseProtocolDecoder {
return protocolVersion;
}
public ByteBuf formatMessage(int delimiter, int type, ByteBuf id, boolean shortIndex, ByteBuf data) {
public ByteBuf formatMessage(int type, ByteBuf id, boolean shortIndex, ByteBuf data) {
ByteBuf buf = Unpooled.buffer();
buf.writeByte(delimiter);
buf.writeShort(type);
@@ -125,7 +125,7 @@ public class Jt808ProtocolDecoder extends BaseProtocolDecoder {
response.writeShort(type);
response.writeByte(RESULT_SUCCESS);
channel.writeAndFlush(new NetworkMessage(
formatMessage(delimiter, MSG_GENERAL_RESPONSE, id, false, response), remoteAddress));
formatMessage(MSG_GENERAL_RESPONSE, id, false, response), remoteAddress));
}
}
@@ -136,7 +136,7 @@ public class Jt808ProtocolDecoder extends BaseProtocolDecoder {
response.writeShort(type);
response.writeByte(RESULT_SUCCESS);
channel.writeAndFlush(new NetworkMessage(
formatMessage(delimiter, MSG_GENERAL_RESPONSE_2, id, true, response), remoteAddress));
formatMessage(MSG_GENERAL_RESPONSE_2, id, true, response), remoteAddress));
}
}
@@ -228,7 +228,11 @@ public class Jt808ProtocolDecoder extends BaseProtocolDecoder {
}
}
static ByteBuf encodeId(String uniqueId) {
static ByteBuf encodeId(String uniqueId, int length) {
if (length == 10) {
return Unpooled.wrappedBuffer(DataConverter.parseHex(
String.format("%20s", uniqueId).replace(' ', '0')));
}
if (uniqueId.length() % 2 == 0) {
return Unpooled.wrappedBuffer(DataConverter.parseHex(uniqueId));
} else {
@@ -335,7 +339,7 @@ public class Jt808ProtocolDecoder extends BaseProtocolDecoder {
response.writeByte(RESULT_SUCCESS);
response.writeBytes(decodeId(id).getBytes(StandardCharsets.US_ASCII));
channel.writeAndFlush(new NetworkMessage(
formatMessage(delimiter, MSG_TERMINAL_REGISTER_RESPONSE, id, false, response), remoteAddress));
formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, false, response), remoteAddress));
}
} else if (type == MSG_REPORT_TEXT_MESSAGE) {
@@ -408,7 +412,7 @@ public class Jt808ProtocolDecoder extends BaseProtocolDecoder {
response.writeByte(calendar.get(Calendar.MINUTE));
response.writeByte(calendar.get(Calendar.SECOND));
channel.writeAndFlush(new NetworkMessage(
formatMessage(delimiter, MSG_TERMINAL_REGISTER_RESPONSE, id, false, response), remoteAddress));
formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, false, response), remoteAddress));
}
} else if (type == MSG_ACCELERATION) {

View File

@@ -17,6 +17,8 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BasePipelineFactory;
import org.traccar.BaseProtocol;
import org.traccar.BaseProtocolEncoder;
import org.traccar.Protocol;
@@ -39,32 +41,37 @@ public class Jt808ProtocolEncoder extends BaseProtocolEncoder {
}
@Override
protected Object encodeCommand(Command command) {
protected Object encodeCommand(Channel channel, Command command) {
Jt808ProtocolDecoder decoder = BasePipelineFactory.getHandler(
channel.pipeline(), Jt808ProtocolDecoder.class);
boolean alternative = AttributeUtil.lookup(
getCacheManager(), Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName()), command.getDeviceId());
ByteBuf id = Jt808ProtocolDecoder.encodeId(getUniqueId(command.getDeviceId()));
Integer protocolVersion = decoder.getProtocolVersion();
ByteBuf id = Jt808ProtocolDecoder.encodeId(
getUniqueId(command.getDeviceId()), protocolVersion != null ? 10 : 6);
String model = getDeviceModel(command.getDeviceId());
try {
ByteBuf data = Unpooled.buffer();
switch (command.getType()) {
case Command.TYPE_CUSTOM:
String model = getDeviceModel(command.getDeviceId());
if (model != null && Set.of("AL300", "GL100", "VL300").contains(model)) {
data.writeByte(1); // number of parameters
data.writeInt(0xF030); // AT command transparent transmission
int length = command.getString(Command.KEY_DATA).length();
data.writeByte(length);
data.writeCharSequence(command.getString(Command.KEY_DATA), StandardCharsets.US_ASCII);
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_CONFIGURATION_PARAMETERS, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_CONFIGURATION_PARAMETERS, id, false, data);
} else if ("BSJ".equals(model)) {
data.writeByte(1); // flag
var charset = Charset.isSupported("GBK") ? Charset.forName("GBK") : StandardCharsets.US_ASCII;
data.writeCharSequence(command.getString(Command.KEY_DATA), charset);
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_SEND_TEXT_MESSAGE, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_SEND_TEXT_MESSAGE, id, false, data);
} else {
return Unpooled.wrappedBuffer(DataConverter.parseHex(command.getString(Command.KEY_DATA)));
}
@@ -73,15 +80,15 @@ public class Jt808ProtocolEncoder extends BaseProtocolEncoder {
data.writeByte(0x23); // parameter id
data.writeByte(1); // parameter value length
data.writeByte(0x03); // restart
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_PARAMETER_SETTING, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_PARAMETER_SETTING, id, false, data);
case Command.TYPE_POSITION_PERIODIC:
data.writeByte(1); // number of parameters
data.writeByte(0x06); // parameter id
data.writeByte(4); // parameter value length
data.writeInt(command.getInteger(Command.KEY_FREQUENCY));
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_PARAMETER_SETTING, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_PARAMETER_SETTING, id, false, data);
case Command.TYPE_ALARM_ARM:
case Command.TYPE_ALARM_DISARM:
data.writeByte(1); // number of parameters
@@ -90,50 +97,50 @@ public class Jt808ProtocolEncoder extends BaseProtocolEncoder {
data.writeByte(1 + username.length()); // parameter value length
data.writeByte(command.getType().equals(Command.TYPE_ALARM_ARM) ? 0x01 : 0x00);
data.writeCharSequence(username, StandardCharsets.US_ASCII);
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_PARAMETER_SETTING, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_PARAMETER_SETTING, id, false, data);
case Command.TYPE_ENGINE_STOP:
case Command.TYPE_ENGINE_RESUME:
if (alternative) {
data.writeByte(command.getType().equals(Command.TYPE_ENGINE_STOP) ? 0x01 : 0x00);
data.writeBytes(DataConverter.parseHex(
new SimpleDateFormat("yyMMddHHmmss").format(new Date())));
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_OIL_CONTROL, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_OIL_CONTROL, id, false, data);
} else {
if ("VL300".equals(getDeviceModel(command.getDeviceId()))) {
if ("VL300".equals(model)) {
data.writeCharSequence(command.getType().equals(Command.TYPE_ENGINE_STOP) ? "#0;1" : "#0;0",
StandardCharsets.US_ASCII);
} else if ("W15L".equals(getDeviceModel(command.getDeviceId()))) {
} else if ("W15L".equals(model)) {
data.writeByte(command.getType().equals(Command.TYPE_ENGINE_STOP) ? 0x64 : 0x65);
} else {
data.writeByte(command.getType().equals(Command.TYPE_ENGINE_STOP) ? 0xf0 : 0xf1);
}
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_TERMINAL_CONTROL, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_TERMINAL_CONTROL, id, false, data);
}
case Command.TYPE_VIDEO_START:
var config = getCacheManager().getConfig();
String host = URI.create(config.getString(Keys.WEB_URL)).getHost();
int port = config.getInteger(
Keys.PROTOCOL_PORT.withPrefix(BaseProtocol.nameFromClass(Jt1078Protocol.class)));
int channel = command.getInteger(Command.KEY_INDEX, 1);
int videoChannel = command.getInteger(Command.KEY_INDEX, 1);
data.writeByte(host.length());
data.writeCharSequence(host, StandardCharsets.US_ASCII);
data.writeShort(port); // tcp port
data.writeShort(0); // udp port
data.writeByte(channel);
data.writeByte(videoChannel);
data.writeByte(1); // video only
data.writeByte(0); // main stream
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_VIDEO_REQUEST, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_VIDEO_REQUEST, id, false, data);
case Command.TYPE_VIDEO_STOP:
data.writeByte(command.getInteger(Command.KEY_INDEX, 1));
data.writeByte(0); // close audio/video transmission
data.writeByte(0); // close both audio and video
data.writeByte(0); // main stream
return Jt808ProtocolDecoder.formatMessage(
0x7e, Jt808ProtocolDecoder.MSG_VIDEO_CONTROL, id, false, data);
return decoder.formatMessage(
Jt808ProtocolDecoder.MSG_VIDEO_CONTROL, id, false, data);
default:
return null;
}