Add GoSafe binary frame decoder

This commit is contained in:
Anton Tananaev 2024-12-08 10:43:31 -08:00
parent dda596677c
commit 16ca6ed4ac
5 changed files with 127 additions and 42 deletions

View File

@ -0,0 +1,62 @@
/*
* Copyright 2024 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import org.traccar.BaseFrameDecoder;
public class GoSafeFrameDecoder extends BaseFrameDecoder {
@Override
protected Object decode(
ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
char marker = (char) buf.getByte(buf.readerIndex());
if (marker == '*') {
int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '#');
if (index != -1) {
return buf.readRetainedSlice(index + 1 - buf.readerIndex());
}
} else {
int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0xf8);
if (index >= 0) {
ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex());
while (buf.readerIndex() <= index) {
int b = buf.readUnsignedByte();
if (b == 0x1b) {
int ext = buf.readUnsignedByte();
if (ext == 0x00) {
result.writeByte(0x1b);
} else if (ext == 0xe3) {
result.writeByte(0xf8);
}
} else {
result.writeByte(b);
}
}
return result;
}
}
return null;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
* Copyright 2015 - 2024 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,10 +15,7 @@
*/
package org.traccar.protocol;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
import org.traccar.config.Config;
@ -32,17 +29,13 @@ public class GoSafeProtocol extends BaseProtocol {
addServer(new TrackerServer(config, getName(), false) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new GoSafeFrameDecoder());
pipeline.addLast(new GoSafeProtocolDecoder(GoSafeProtocol.this));
}
});
addServer(new TrackerServer(config, getName(), true) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new GoSafeProtocolDecoder(GoSafeProtocol.this));
}
});

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org)
* Copyright 2015 - 2024 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,6 +15,8 @@
*/
package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.session.DeviceSession;
@ -30,6 +32,7 @@ import org.traccar.model.Network;
import org.traccar.model.Position;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
@ -212,16 +215,18 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
if (channel != null) {
channel.writeAndFlush(new NetworkMessage("1234", remoteAddress));
channel.writeAndFlush(new NetworkMessage(
Unpooled.copiedBuffer("1234", StandardCharsets.US_ASCII), remoteAddress));
}
String sentence = (String) msg;
ByteBuf buf = (ByteBuf) msg;
String sentence = buf.toString(StandardCharsets.US_ASCII);
Pattern pattern = PATTERN;
if (sentence.startsWith("*GS02")) {
pattern = PATTERN_OLD;
}
Parser parser = new Parser(pattern, (String) msg);
Parser parser = new Parser(pattern, sentence);
if (!parser.matches()) {
return null;
}

View File

@ -0,0 +1,25 @@
package org.traccar.protocol;
import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class GoSafeFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
var decoder = inject(new GoSafeFrameDecoder());
assertEquals(
binary("2a475330362c3836303037383032343230363834342c3037343932393235303631392c2c5359533a473353433b56332e33373b56312e312e382c4750533a413b31303b4e332e3030393533343b453130312e3531323039363b333b3138383b33313b302e37302c434f543a32373337363637312c4144433a32352e36323b342e33373b322e35312c4454543a353030343b45313b303b303b303b3323"),
decoder.decode(null, null, binary("2a475330362c3836303037383032343230363834342c3037343932393235303631392c2c5359533a473353433b56332e33373b56312e312e382c4750533a413b31303b4e332e3030393533343b453130312e3531323039363b333b3138383b33313b302e37302c434f543a32373337363637312c4144433a32352e36323b342e33373b322e35312c4454543a353030343b45313b303b303b303b3323")));
assertEquals(
binary("f80601013fb82203661b2ee46249007a13003f45feefeeb401db1bbe00000000060e00d602018904036412080c010111e121003100410051010807000000000000004655f8"),
decoder.decode(null, null, binary("f80601013fb82203661b002ee46249007a13003f45feefeeb401db1b00be00000000060e00d602018904036412080c010111e121003100410051010807000000000000004655f8")));
}
}

View File

@ -11,94 +11,94 @@ public class GoSafeProtocolDecoderTest extends ProtocolTest {
var decoder = inject(new GoSafeProtocolDecoder(null));
verifyPositions(decoder, false, text(
verifyPositions(decoder, false, buffer(
"*GS06,357330050846344,RST#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS06,353218073585128,181255300523,,SYS:Smart Track;V9.31;V1.1.5,GPS:A;5;N31.551856;E74.366920;0;0;;2.15;2.64,COT:0,ADC:10.78;0.02,DTT:4002;E1;0;0;0;1$181325300523,,SYS:Smart Track;V9.31;V1.1.5,GPS:A;6;N31.551856;E74.366920;0;0;;2.05;2.13,COT:0,ADC:10.79;0.02,DTT:4002;E1;0;0;0;1#"));
verifyAttribute(decoder, text(
verifyAttribute(decoder, buffer(
"*GS06,356449068350122,013519070819,,SYS:G6S;V3.37;V1.1.8,GPS:A;12;N23.169866;E113.450728;0;255;54;0.79,COT:18779;,ADC:12.66;0.58,DTT:4084;E1;0;0;0;1,IWD:0;1;ad031652643fff28;23.2;1;1;86031652504fff28;24.3;2;1;e603165252a5ff28;24.2;3;1;bb0416557da6ff28;24.0#"),
Position.PREFIX_TEMP + 3, 24.0);
verifyAttribute(decoder, text(
verifyAttribute(decoder, buffer(
"*GS06,351535058659335,081234310719,,SYS:G6S;V3.37;V1.1.8,GPS:A;10;N23.169758;E113.450640;0;323;47;0.82,COT:18539;,ADC:10.81;4.07,DTT:4000;E0;0;0;0;1,IWD:0;1;9f00000655705d28;22.5#"),
Position.PREFIX_TEMP + 0, 22.5);
verifyAttribute(decoder, text(
verifyAttribute(decoder, buffer(
"*GS06,359568052580548,091946150719,1C,SYS:G3C;V1.40;V1.0.4,GPS:A;5;S25.750200;E28.204858;0;0;1337;1.68,COT:,ADC:13.12;4.06,DTT:4004;C6;0;0;10000000;0$091948150719,,SYS:G3C;V1.40;V1.0.4,GPS:A;5;S25.750200;E28.204858;0;0;1337;1.68,COT:,ADC:12.96;4.06,DTT:4004;C6;0;0;0;1#"),
Position.KEY_EVENT, 0x1C);
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS06,860078024226974,101437211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;7;N3.052302;E101.787216;16;137;48;1.58,COT:4261733103,ADC:22.86;0.58;0.01,DTT:4004;E1;0;0;0;3$101439211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;8;N3.052265;E101.787200;12;152;46;1.31,COT:4261733103,ADC:22.98;0.58;0.01,DTT:4004;E1;0;0;0;3$101441211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;8;N3.052247;E101.787232;8;131;46;1.34,COT:4261733103,ADC:23.13;0.58;0.01,DTT:4004;E1;0;0;0;3$101510211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;8;N3.052150;E101.787152;0;131;40;0.97,COT:4261733160,ADC:22.88;0.58;0.01,DTT:4000;E1;0;0;0;1$101540211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;7;N3.052150;E101.787152;0;131;40;0.97,COT:4261733160,ADC:22.91;0.58;0.00,DTT:4000;E1;0;0;0;1#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS06,359568052570135,090349191018,,SYS:G3C;V1.40;V1.0.4,GPS:A;10;S26.112722;E28.078766;0;23;1581;0.80,COT:,ADC:10.86;3.79,DTT:4000;E7;0;0;0;1$090419191018,,SYS:G3C;V1.40;V1.0.4,GPS:A;10;S26.112722;E28.078766;0;23;1581;0.80,COT:,ADC:10.85;3.79,DTT:4000;E7;0;0;0;1#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS06,359913060650380,152248050718,,SYS:G3C;V1.38;V05,GPS:A;10;N31.914370;E35.914640;0;0,COT:689,ADC:0.18;3.55,DTT:4025;E6;0;0;0;1#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS06,359913060650380,101019050718,,SYS:G3C;V1.38;V05,GPS:L;6;N31.916576;E35.908480;0;0,GSM:1;4;416;3;627A;A84B;-66,COT:188,ADC:4.31;3.88,DTT:4005;E6;0;0;0;1#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS06,860078024287174,070120310318,,SYS:G3SC;V3.32;V1.1.8,GPS:A;9;N23.169946;E113.450568;0;0;23;0.86,COT:65;20,ADC:4.27;3.73;0.01;0.02,DTT:4004;E0;0;0;0;1,IWD:0;0;000000000000#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS06,860078024213915,032544190318,,SYS:G3SC;V3.32;V1.1.8,GPS:A;7;N3.052417;E101.787112;0;0;94;1.38,COT:686;0-0-0,ADC:16.25;4.09,DTT:4000;E0;0;0;0;1#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS06,351535058659335,062728190318,,SYS:G6S;V3.32;V1.0.5,GPS:A;10;N23.169806;E113.450760;0;0;81;0.77,COT:0,ADC:0.00;0.16,DTT:80;E0;0;0;0;1#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS26,356449061046586,082522030117,,SYS:G737IC;V1.13;V1.0.5,GPS:V;5;N42.594136;W70.723832;0;0;8;2.06,GSM:;;310;260;C76D;9F1D;-85,ADC:3.86,DTT:3918C;;0;0;0;1,#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS56,357330051092344,123918301116,10,GPS:L;9;N47.582920;W122.238720;0;0;102;0.99,GSM:0;0;310;410;A7DB;385C;-86,COT:76506,ADC:0.82;3.77,DTT:2184;;0;0;10000;0$000000000000,86,GPS:A;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:0.00;3.75,DTT:0;;0;0;40;0$000000000000,86,GPS:A;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:0.00;3.74,DTT:0;;0;0;40;0$000000000000,93,GPS:A;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:0.00;3.73,DTT:8000;;0;0;80000;0$000000000000,13,GPS:L;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:11.09;3.79,DTT:2004;;0;0;80000;0$000000000000,90,GPS:L;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:11.13;3.79,DTT:23004;;0;0;10000;0$000000000000,,GPS:L;6;N47.582912;W122.238840;0;0;88;2.20,GSM:5;2;310;410;A7DB;385C;-89,COT:76506,ADC:14.12;3.81,DTT:23184;;0;0;0;6#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS26,356449061139936,022918011216,,SYS:G737IC;V1.13;V1.0.5,GPS:A;9;N42.651728;W70.623520;0;0;48;1.50,ADC:4.08,DTT:3900C;;0;0;0;1,#"));
verifyNotNull(decoder, text(
verifyNotNull(decoder, buffer(
"*GS56,356449063230915,052339180916,,SYS:G7S;V1.08;V1.2,GPS:V;4;N24.730006;E46.637816;14;0;630,GSM:;;420;4;5655;507A;-70,COT:75242;2-8-17,ADC:13.22;0.08,DTT:23004;;0;0;0;1#"));
verifyNotNull(decoder, text(
verifyNotNull(decoder, buffer(
"*GS56,356449063230915,052349180916,,SYS:G7S;V1.08;V1.2,GPS:V;6;N24.730384;E46.637620;47;56;607,GSM:;;420;4;5655;507A;-70,COT:75290;2-8-27,ADC:13.24;0.08,DTT:23004;;0;0;0;1#"));
verifyNotNull(decoder, text(
verifyNotNull(decoder, buffer(
"*GS56,356449063230915,052444180916,,SYS:G7S;V1.08;V1.2,GPS:V;6;N24.730384;E46.637620;47;56;607,GSM:;;420;4;5655;F319;-102,COT:75290;2-9-27,ADC:13.00;0.08,DTT:23004;;0;0;0;1$052449180916,,SYS:G7S;V1.08;V1.2,GPS:V;6;N24.730384;E46.637620;47;56;607,GSM:;;420;4;5655;F319;-102,COT:75290;2-9-27,ADC:13.13;0.08,DTT:23004;;0;0;0;1#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS16,356449062643845,141224290316,,SYS:G79;V1.13;V1.0.2,GPS:V;5;N24.694972;E46.680736;46;334;606;1.43,GSM:;;420;4;5655;4EB8;-57,COT:330034,ADC:13.31;3.83,DTT:27004;;0;0;0;1,OBD:064101000400000341057E04410304000341510104411001C203410F4B0341112904411F01AB0641010004000014490201FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03410D21,FUL:28260"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS16,351535059439208,145425130316,,GPS:V;0;N0.000000;E0.000000;0;0;0;0.00;0.00,GSM:1;3;416;3;A8C;2820;-81;416;3;A8C;281F;-83;416;3;A8C;368A;-87;416;3;A8C;368B;-89;416;3;A8C;2C26;-103;416;3;A8C;3689;-107;416;3;A8C;2D83;-107"));
verifyPosition(decoder, text(
verifyPosition(decoder, buffer(
"*GS02,358696043774648,GPS:230040;A;S1.166829;E36.934287;0;0;170116,STT:20;0,MGR:32755204,ADC:0;11.2;1;28.3;2;4.1,GFS:0;0"));
verifyNull(decoder, text(
verifyNull(decoder, buffer(
"*GS02,358696043774648"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS16,351535058709775,100356130215,,SYS:G79W;V1.06;V1.0.2,GPS:A;6;N24.802700;E46.616828;0;0;684;1.35,COT:60,ADC:4.31;0.10,DTT:20000;;0;0;0;1"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS16,351535059439208,074558291015,,GPS:A;9;N31.935942;E35.867092;;345;921;1.03;1.59,GSM:1;3;416;3;A8C;368B;-78;416;3;A8C;2820;-73;416;3;BB8;2CBE;-76;416;3;A8C;368A;-76;416;3;A8C;2C26;-79,OBD:04410C122003410D0F03411C0103410547037F011203411100"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS16,351535059439208,083515281015,,GPS:A;9;N31.959502;E35.908316;;108;890;1.05;1.79,GSM:1;4;416;3;AF0;A3A6;-59;416;3;AF0;A3A3;-50;416;3;AF0;A3A4;-56;416;3;AF0;A3A5;-62;416;3;AF0;B195;-76,OBD:04410C194603410D2303411C0103410583037F011203411115"));
verifyNull(decoder, text(
verifyNull(decoder, buffer(
"*GS16,351535058709775"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS16,351535059439208,103441131015,,GPS:A;8;N31.960122;E35.921652;27;99;847;1.33;2.41,GSM:1;4;416;3;AF0;9C73;-61;416;3;AF0;9C89;-68,OBD:04410C0DA403410D0B03411C010341057A037F011203411100$103453131015,,GPS:A;8;N31.959976;E35.922144;6;0;835;1.33;2.41,GSM:1;4;416;3;AF0;9C73;-67;416;3;AF0;9C89;-64;416;3;AF0;B389;-83,OBD:04410C0D8E03410D0B03411C010341057D037F011203411100$103503131015,,GPS:A;9;N31.959870;E35.922284;11;127;830;1.33;2.41,GSM:1;4;416;3;AF0;9C73;-67;416;3;AF0;9C89;-64;416;3;AF0;B389;-83,OBD:04410C0D8E03410D0B03411C010341057D037F011203411100$103513131015,,GPS:A;9;N31.959742;E35.922516;10;106;830;1.37;2.91,GSM:1;4;416;3;AF0;9C73;-67;416;3;AF0;9C89;-64;416;3;AF0;B389;-83,OBD:04410C0D1003410D0603411C010341057E037F011203411100$103553131015,,GPS:A;8;N31.959564;E35.923308;6;0;836;1.41;2.43,GSM:1;4;416;3;AF0;9C73;-65;416;3;AF0;B389;-71;416;3;AF0;9C89;-74,OBD:04410C0DAE03410D0403411C010341057C037F011203411100#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS16,351535059439208,155750220815,,SYS:G79;V1.10;V1.0.2,GPS:A;4;N31.944198;E35.846644;0;0;923;9.47;1.00,COT:155133,ADC:12.21;0.10,DTT:20002;;0;0;0;1#"));
verifyPositions(decoder, text(
verifyPositions(decoder, buffer(
"*GS16,351535059439208,070034220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945970;E35.859848;29;65;922;1.14;1.68,COT:147528,ADC:14.07;0.11,DTT:27006;;0;0;0;3,OBD:04410C1ECD03410D2D03411C010341057A037F011203411107$070035220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945934;E35.859908;29;86;922;1.14;1.68,COT:147528,ADC:13.94;0.15,DTT:27006;;0;0;0;3,OBD:04410C1ECD03410D2D03411C010341057A037F011203411107$070037220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945844;E35.859952;29;123;922;1.14;1.68,COT:147625,ADC:13.75;0.11,DTT:27006;;0;0;0;3,OBD:04410C0FE803410D1803411C010341057C037F011203411100$070038220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945808;E35.859940;29;145;923;1.14;1.68,COT:147625,ADC:14.00;0.11,DTT:27006;;0;0;0;3,OBD:04410C0FE803410D1803411C010341057C037F011203411100#"));
}