Skip to content

Commit

Permalink
Implement Atlanta OBD protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
tananaev committed Jun 10, 2018
1 parent 77f5a12 commit 9cbd8fa
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 9 deletions.
24 changes: 17 additions & 7 deletions src/org/traccar/protocol/L100FrameDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,32 @@ public class L100FrameDecoder extends FrameDecoder {
protected Object decode(
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception {

if (buf.readableBytes() < 80) {
if (buf.readableBytes() < 10) {
return null;
}

int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02);
if (index == -1) {
index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x04);
int header = buf.getByte(buf.readerIndex());
boolean obd = header == 'L' || header == 'H';

int index;
if (obd) {
index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*');
} else {
index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02);
if (index == -1) {
return null;
index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x04);
if (index == -1) {
return null;
}
}
}

index += 2; // checksum

if (buf.readableBytes() >= index - buf.readerIndex()) {
buf.skipBytes(2); // header
if (buf.writerIndex() >= index) {
if (!obd) {
buf.skipBytes(2); // header
}
ChannelBuffer frame = buf.readBytes(index - buf.readerIndex() - 2);
buf.skipBytes(2); // footer
return frame;
Expand Down
109 changes: 107 additions & 2 deletions src/org/traccar/protocol/L100ProtocolDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.helper.Checksum;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
Expand Down Expand Up @@ -66,23 +67,59 @@ public L100ProtocolDecoder(L100Protocol protocol) {
.text("ATL")
.compile();

private static final Pattern PATTERN_OBD = new PatternBuilder()
.expression("[LH],") // archive
.text("ATL,")
.number("(d{15}),") // imei
.number("(d+),") // type
.number("(d+),") // index
.groupBegin()
.number("(dd)(dd)(dd),") // time (hhmmss)
.number("(dd)(dd)(dd),") // date (ddmmyy)
.expression("([AV]),") // validity
.number("(d+.d+);([NS]),") // latitude
.number("(d+.d+);([EW]),") // longitude
.number("(d+),") // speed
.number("(d+),") // course
.number("(d+.d+),") // odometer
.number("(d+.d+),") // battery
.number("(d+),") // rssi
.number("(d+),") // mcc
.number("(d+),") // mnc
.number("(d+),") // lac
.number("(x+),") // cid
.number("#(d)(d)(d)(d),") // status
.number("(d),") // overspeed
.text("ATL,")
.groupEnd("?")
.compile();

@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {

String sentence = (String) msg;

if (sentence.startsWith("L") || sentence.startsWith("H")) {
return decodeObd(channel, remoteAddress, sentence);
} else {
return decodeNormal(channel, remoteAddress, sentence);
}
}

private Object decodeNormal(Channel channel, SocketAddress remoteAddress, String sentence) {

Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}

Position position = new Position(getProtocolName());

DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
if (deviceSession == null) {
return null;
}

Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());

DateBuilder dateBuilder = new DateBuilder()
Expand Down Expand Up @@ -112,4 +149,72 @@ protected Object decode(
return position;
}

private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) {

Parser parser = new Parser(PATTERN_OBD, sentence);
if (!parser.matches()) {
return null;
}

String imei = parser.next();
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
if (deviceSession == null) {
return null;
}

int type = parser.nextInt();
int index = parser.nextInt();

if (type == 1) {
if (channel != null) {
String response = "@" + imei + ",00," + index + ",";
response += "*" + (char) Checksum.xor(response);
channel.write(response, remoteAddress);
}
return null;
}

Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());

position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY));
position.setValid(parser.next().equals("A"));
position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
position.setSpeed(parser.nextInt());
position.setCourse(parser.nextInt());

position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
position.set(Position.KEY_BATTERY, parser.nextDouble());

int rssi = parser.nextInt();
position.setNetwork(new Network(CellTower.from(
parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextHexInt(), rssi)));

position.set(Position.KEY_IGNITION, parser.nextInt() == 1);
parser.next(); // reserved

switch (parser.nextInt()) {
case 0:
position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
break;
case 2:
position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
break;
case 1:
position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
break;
default:
break;
}

position.set(Position.KEY_CHARGE, parser.nextInt() == 1);

if (parser.nextInt() == 1) {
position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
}

return position;
}

}
4 changes: 4 additions & 0 deletions test/org/traccar/protocol/L100FrameDecoderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public void testDecode() throws Exception {

L100FrameDecoder decoder = new L100FrameDecoder();

verifyFrame(
binary("4c2c41544c2c3836363739353033303437373935322c30312c303033352c"),
decoder.decode(null, null, binary("4c2c41544c2c3836363739353033303437373935322c30312c303033352c2a28")));

verifyFrame(
binary("41544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c"),
decoder.decode(null, null, binary("200141544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c027a")));
Expand Down
6 changes: 6 additions & 0 deletions test/org/traccar/protocol/L100ProtocolDecoderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ public void testDecode() throws Exception {

L100ProtocolDecoder decoder = new L100ProtocolDecoder(new L100Protocol());

verifyPosition(decoder, text(
"H,ATL,866795030478513,02,0981,054448,230318,A,28.633486;N,77.222595;E,0,154,1.14,4.2,18,404,4,88,ad7b,#1031,0,ATL,"));

verifyNull(decoder, text(
"L,ATL,866795030477952,01,0035,"));

verifyPosition(decoder, text(
"ATL861693039769518,$GPRMC,074930.000,A,2838.0112,N,07713.3602,E,0000,223.36,290518,,,A*7E,#01111011000100,0.012689,0,0,2.572415,0,4.015,22,404,4,88,3ad5,0,0.01,1.4_800F_VTS3D3_gen_peri_myn,,internet,00000000,ATL"));

Expand Down

0 comments on commit 9cbd8fa

Please sign in to comment.