aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pom.xml22
-rw-r--r--src/org/traccar/protocol/ST210ProtocolDecoder.java640
-rw-r--r--test/org/traccar/protocol/ST210ProtocolDecoderTest.java73
3 files changed, 729 insertions, 6 deletions
diff --git a/pom.xml b/pom.xml
index b6d4a5a6d..9e11580f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.traccar</groupId>
<artifactId>traccar</artifactId>
- <version>0.0.1-SNAPSHOT</version>
+ <version>1.1.0-SNAPSHOT</version>
<dependencies>
<dependency>
@@ -22,14 +22,24 @@
<version>3.5.2.Final</version>
</dependency>
<dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>javax.servlet-api</artifactId>
- <version>3.0.1</version>
- </dependency>
- <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
+
+ <build>
+ <finalName>tracker-server</finalName>
+ <outputDirectory>target\classes</outputDirectory>
+ <sourceDirectory>src</sourceDirectory>
+ <testSourceDirectory>test</testSourceDirectory>
+ <resources>
+ <resource>
+ <directory>src</directory>
+ <excludes>
+ <exclude>**/*.java</exclude>
+ </excludes>
+ </resource>
+ </resources>
+ </build>
</project> \ No newline at end of file
diff --git a/src/org/traccar/protocol/ST210ProtocolDecoder.java b/src/org/traccar/protocol/ST210ProtocolDecoder.java
new file mode 100644
index 000000000..8fbea8da5
--- /dev/null
+++ b/src/org/traccar/protocol/ST210ProtocolDecoder.java
@@ -0,0 +1,640 @@
+package org.traccar.protocol;
+
+import java.util.Calendar;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.traccar.GenericProtocolDecoder;
+import org.traccar.helper.Log;
+import org.traccar.model.DataManager;
+import org.traccar.model.Position;
+
+public class ST210ProtocolDecoder extends GenericProtocolDecoder {
+
+ /**
+ * Initialize
+ */
+ public ST210ProtocolDecoder(DataManager dataManager, Integer resetDelay) {
+ super(dataManager, resetDelay);
+ }
+
+ private enum ST210FIELDS {
+ HDR_STATUS("SA200STT;", "Status Report"), HDR_EMERGENCY("SA200EMG;",
+ "Emergency Report"), HDR_EVENT("SA200EVT;", "Event Report"), HDR_ALERT(
+ "SA200ALT;", "Alert Report"), HDR_ALIVE("SA200ALV;",
+ "Alive Report"), DEV_ID("(\\d+);", "Device ID"), SW_VER(
+ "(\\d{3});", "Software Release Version"), DATE("(\\d+);",
+ "GPS date (yyyymmdd) Year + Month + Day"), TIME(
+ "(\\d{2}:\\d{2}:\\d{2});",
+ "GPS time (hh:mm:ss) Hour : Minute : Second"), CELL(
+ "(\\d{2}\\w\\d{2});",
+ "Location Code ID (3 digits hex) + Serving Cell BSIC(2 digits decimal)"), LAT(
+ "(-\\d{2}.\\d+);", "Latitude (+/-xx.xxxxxx)"), LON(
+ "(-\\d{3}.\\d+);", "Longitude (+/-xxx.xxxxxx)"), SPD(
+ "(\\d{3}.\\d{3});",
+ "Speed in km/h - This value returns to 0 when it is over than 200,000Km"), CRS(
+ "(\\d{3}.\\d{2});", "Course over ground in degree"), SATT(
+ "(\\d+);", "Number of satellites"), FIX("(\\d);",
+ "GPS is fixed(1)\n" + "GPS is not fixed(0)"), DIST("(\\d+);",
+ "Traveled ddistance in meter"), PWR_VOLT("(\\d{2}.\\d{2});",
+ "Voltage value of main power"), IO("(\\d+);",
+ "Current I/O status of inputs and outputs."), MODE("(\\d);",
+ "1 = Idle mode (Parking)\n" + "2 = Active Mode (Driving)"), MSG_NUM(
+ "(\\d{4})",
+ "Message number - After 9999 is reported, message number returns to 0000"), EMG_ID(
+ "(\\d);", "Emergency type"), EVT_ID("(\\d);", "Event type"), ALERT_ID(
+ "(\\d);", "Alert type");
+
+ private String pattern;
+
+ private String desc;
+
+ private ST210FIELDS(String pattern, String desc) {
+ this.pattern = pattern;
+ this.desc = desc;
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void populatePosition(Position position, String groupValue,
+ DataManager dataManager) throws Exception {
+
+ switch (this) {
+
+ case DEV_ID:
+ position.setDeviceId(dataManager.getDeviceByImei(groupValue)
+ .getId());
+ break;
+
+ case LAT:
+ position.setLatitude(Double.valueOf(groupValue));
+ break;
+
+ case LON:
+ position.setLongitude(Double.valueOf(groupValue));
+ break;
+
+ case CRS:
+ position.setCourse(Double.valueOf(groupValue));
+ break;
+
+ case PWR_VOLT:
+ position.setPower(Double.valueOf(groupValue));
+ break;
+
+ case SPD:
+ position.setSpeed(Double.valueOf(groupValue));
+ break;
+
+ case DATE: {
+ // Date
+ Calendar time = Calendar.getInstance(TimeZone
+ .getTimeZone("UTC"));
+ time.clear();
+ time.set(Calendar.YEAR, Integer.valueOf(Integer
+ .valueOf(groupValue.substring(0, 4))));
+ time.set(Calendar.MONTH, Integer.valueOf(Integer
+ .valueOf(groupValue.substring(4, 6))));
+ time.set(Calendar.DAY_OF_MONTH, Integer.valueOf(Integer
+ .valueOf(groupValue.substring(6, 8))));
+ position.setTime(time.getTime());
+ break;
+ }
+
+ case TIME: {
+
+ Calendar time = Calendar.getInstance(TimeZone
+ .getTimeZone("UTC"));
+ time.clear();
+ time.setTime(position.getTime());
+
+ time.set(Calendar.HOUR, Integer.valueOf(Integer
+ .valueOf(groupValue.substring(0, 2))));
+ time.set(Calendar.MINUTE, Integer.valueOf(Integer
+ .valueOf(groupValue.substring(3, 5))));
+ time.set(Calendar.SECOND, Integer.valueOf(Integer
+ .valueOf(groupValue.substring(6, 8))));
+
+ position.setTime(time.getTime());
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+ }
+
+ private enum FIELD_FIX_VALUE {
+ FIXED(1, "GPS is fixed"), NOT_FIXED(0, "GPS is not fixed");
+
+ private int value;
+
+ private String desc;
+
+ private FIELD_FIX_VALUE(int value, String desc) {
+ this.value = value;
+ this.desc = desc;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public FIELD_FIX_VALUE getValueOf(String indiceStr) {
+ int indice = Integer.valueOf(indiceStr);
+ return getValueOf(indice);
+ }
+
+ public FIELD_FIX_VALUE getValueOf(int indice) {
+ switch (indice) {
+ case 1:
+ return FIXED;
+ case 0:
+ return NOT_FIXED;
+ default:
+ throw new IllegalArgumentException("Índice não definido");
+ }
+ }
+ }
+
+ private enum FIELD_MODE_VALUE {
+ PARKING(1, "Idle mode (Parking)"), DRIVING(2, "Active Mode (Driving)");
+
+ private int value;
+
+ private String desc;
+
+ private FIELD_MODE_VALUE(int value, String desc) {
+ this.value = value;
+ this.desc = desc;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public FIELD_MODE_VALUE getValueOf(String indiceStr) {
+ int indice = Integer.valueOf(indiceStr);
+ return getValueOf(indice);
+ }
+
+ public FIELD_MODE_VALUE getValueOf(int indice) {
+ switch (indice) {
+ case 1:
+ return PARKING;
+ case 2:
+ return DRIVING;
+ default:
+ throw new IllegalArgumentException("Índice não definido");
+ }
+ }
+ }
+
+ private enum FIELD_EMG_ID_VALUE {
+ PANIC(1, "Emergency by panic button"), PARKING(2,
+ "Emergency by parking lock"), MAIN_POWER(3,
+ "Emergency by removing main power"), ANTI_THEFT(5,
+ "Emergency by anti-theft");
+
+ private int value;
+
+ private String desc;
+
+ private FIELD_EMG_ID_VALUE(int value, String desc) {
+ this.value = value;
+ this.desc = desc;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public FIELD_EMG_ID_VALUE getValueOf(String indiceStr) {
+ int indice = Integer.valueOf(indiceStr);
+ return getValueOf(indice);
+ }
+
+ public FIELD_EMG_ID_VALUE getValueOf(int indice) {
+ switch (indice) {
+ case 1:
+ return PANIC;
+ case 2:
+ return PARKING;
+ case 3:
+ return MAIN_POWER;
+ case 5:
+ return ANTI_THEFT;
+ default:
+ throw new IllegalArgumentException("Índice não definido");
+ }
+ }
+ }
+
+ private enum FIELD_EVT_ID_VALUE {
+ INPUT1_GROUND(1, "Input1 goes to ground state"), INPUT1_OPEN(2,
+ "Input1 goes to open state"), INPUT2_GROUND(3,
+ "Input2 goes to ground state"), INPUT2_OPEN(4,
+ "Input2 goes to open state"), INPUT3_GROUND(5,
+ "Input3 goes to ground state"), INPUT3_OPEN(6,
+ "Input3 goes to open state");
+
+ private int value;
+
+ private String desc;
+
+ private FIELD_EVT_ID_VALUE(int value, String desc) {
+ this.value = value;
+ this.desc = desc;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public FIELD_EVT_ID_VALUE getValueOf(String indiceStr) {
+ int indice = Integer.valueOf(indiceStr);
+ return getValueOf(indice);
+ }
+
+ public FIELD_EVT_ID_VALUE getValueOf(int indice) {
+ switch (indice) {
+ case 1:
+ return INPUT1_GROUND;
+ case 2:
+ return INPUT1_OPEN;
+ case 3:
+ return INPUT2_GROUND;
+ case 4:
+ return INPUT2_OPEN;
+ case 5:
+ return INPUT3_GROUND;
+ case 6:
+ return INPUT3_OPEN;
+ default:
+ throw new IllegalArgumentException("Índice não definido");
+ }
+ }
+ }
+
+ private enum FIELD_ALERT_ID_VALUE {
+ DRIVING_FASTER(1, "Start driving faster than SPEED_LIMIT"), OVER_SPPED(
+ 2, "Ended over speed condition"), DISCON_GPS(3,
+ "Disconnected GPS antenna"), RECON_GPS(4,
+ "Reconnected GPS antenna after disconnected"), OUT_GEO_FENCE(5,
+ "The vehicle went out from the geo-fence that has following ID"), INTO_GEO_FENCE(
+ 6,
+ "The vehicle entered into the geo-fence that has following ID"), SHORTED_GPS(
+ 8, "Shorted GPS antenna"), DEEP_SLEEP_ON(9,
+ "Enter to deep sleep mode"), DEEP_SLEEP_OFF(10,
+ "Exite from deep sleep mode"), BKP_BATTERY(13,
+ "Backup battery error"), BATTERY_DOWN(14,
+ "Vehicle battery goes down to so low level"), SHOCKED(15,
+ "Shocked"), COLLISION(16, "Occurred some collision"), DEVIATE_ROUT(
+ 18, "Deviate from predefined rout"), ENTER_ROUT(19,
+ "Enter into predefined rout");
+
+ private int value;
+
+ private String desc;
+
+ private FIELD_ALERT_ID_VALUE(int value, String desc) {
+ this.value = value;
+ this.desc = desc;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public FIELD_ALERT_ID_VALUE getValueOf(String indiceStr) {
+ int indice = Integer.valueOf(indiceStr);
+ return getValueOf(indice);
+ }
+
+ public FIELD_ALERT_ID_VALUE getValueOf(int indice) {
+ switch (indice) {
+ case 1:
+ return DRIVING_FASTER;
+ case 2:
+ return OVER_SPPED;
+ case 3:
+ return DISCON_GPS;
+ case 4:
+ return RECON_GPS;
+ case 5:
+ return OUT_GEO_FENCE;
+ case 6:
+ return INTO_GEO_FENCE;
+ case 8:
+ return SHORTED_GPS;
+ case 9:
+ return DEEP_SLEEP_ON;
+ case 10:
+ return DEEP_SLEEP_OFF;
+ case 13:
+ return BKP_BATTERY;
+ case 14:
+ return BATTERY_DOWN;
+ case 15:
+ return SHOCKED;
+ case 16:
+ return COLLISION;
+ case 18:
+ return DEVIATE_ROUT;
+ case 19:
+ return ENTER_ROUT;
+ default:
+ throw new IllegalArgumentException("Índice não definido");
+ }
+ }
+ }
+
+ private enum ST210REPORTS {
+
+ STATUS("SA200STT"), EMERGENCY("SA200EMG"), EVENT("SA200EVT"), ALERT(
+ "SA200ALT"), ALIVE("SA200ALV");
+
+ private String header;
+
+ private ST210REPORTS(String header) {
+ this.header = header;
+ }
+
+ public String getHeader() {
+ return this.header;
+ }
+
+ public List<ST210FIELDS> getProtocol() {
+
+ if (this.equals(STATUS)) {
+ return StatusProtocol;
+ }
+
+ if (this.equals(EMERGENCY)) {
+ return EmergencyProtocol;
+ }
+
+ if (this.equals(EVENT)) {
+ return EventProtocol;
+ }
+
+ if (this.equals(ALERT)) {
+ return AlertProtocol;
+ }
+
+ if (this.equals(ALIVE)) {
+ return AliveProtocol;
+ }
+
+ return null;
+ }
+
+ public Pattern getProtocolPattern() {
+
+ if (this.equals(STATUS)) {
+ return getPattern(StatusProtocol);
+ }
+
+ if (this.equals(EMERGENCY)) {
+ return getPattern(EmergencyProtocol);
+ }
+
+ if (this.equals(EVENT)) {
+ return getPattern(EventProtocol);
+ }
+
+ if (this.equals(ALERT)) {
+ return getPattern(AlertProtocol);
+ }
+
+ if (this.equals(ALIVE)) {
+ return getPattern(AliveProtocol);
+ }
+
+ return null;
+ }
+
+ }
+
+ private static ST210REPORTS getReportType(String msg) {
+
+ if (msg.startsWith(ST210REPORTS.STATUS.getHeader())) {
+ return ST210REPORTS.STATUS;
+ }
+
+ if (msg.startsWith(ST210REPORTS.EMERGENCY.getHeader())) {
+ return ST210REPORTS.EMERGENCY;
+ }
+
+ if (msg.startsWith(ST210REPORTS.EVENT.getHeader())) {
+ return ST210REPORTS.EVENT;
+ }
+
+ if (msg.startsWith(ST210REPORTS.ALERT.getHeader())) {
+ return ST210REPORTS.ALERT;
+ }
+
+ if (msg.startsWith(ST210REPORTS.ALIVE.getHeader())) {
+ return ST210REPORTS.ALIVE;
+ }
+
+ return null;
+ }
+
+ public static Pattern getPattern(List<ST210FIELDS> protocol) {
+
+ String patternStr = "";
+
+ for (ST210FIELDS field : protocol) {
+ patternStr += field.getPattern();
+ }
+
+ return Pattern.compile(patternStr);
+
+ }
+
+ @SuppressWarnings("serial")
+ static private List<ST210FIELDS> StatusProtocol = new LinkedList<ST210FIELDS>() {
+
+ {
+ add(ST210FIELDS.HDR_STATUS);
+ add(ST210FIELDS.DEV_ID);
+ add(ST210FIELDS.SW_VER);
+ add(ST210FIELDS.DATE);
+ add(ST210FIELDS.TIME);
+ add(ST210FIELDS.CELL);
+ add(ST210FIELDS.LAT);
+ add(ST210FIELDS.LON);
+ add(ST210FIELDS.SPD);
+ add(ST210FIELDS.CRS);
+ add(ST210FIELDS.SATT);
+ add(ST210FIELDS.FIX);
+ add(ST210FIELDS.DIST);
+ add(ST210FIELDS.PWR_VOLT);
+ add(ST210FIELDS.IO);
+ add(ST210FIELDS.MODE);
+ add(ST210FIELDS.MSG_NUM);
+ }
+
+ };
+
+ @SuppressWarnings("serial")
+ static private List<ST210FIELDS> EmergencyProtocol = new LinkedList<ST210FIELDS>() {
+
+ {
+ add(ST210FIELDS.HDR_EMERGENCY);
+ add(ST210FIELDS.DEV_ID);
+ add(ST210FIELDS.SW_VER);
+ add(ST210FIELDS.DATE);
+ add(ST210FIELDS.TIME);
+ add(ST210FIELDS.CELL);
+ add(ST210FIELDS.LAT);
+ add(ST210FIELDS.LON);
+ add(ST210FIELDS.SPD);
+ add(ST210FIELDS.CRS);
+ add(ST210FIELDS.SATT);
+ add(ST210FIELDS.FIX);
+ add(ST210FIELDS.DIST);
+ add(ST210FIELDS.PWR_VOLT);
+ add(ST210FIELDS.IO);
+ add(ST210FIELDS.EMG_ID);
+ }
+
+ };
+
+ @SuppressWarnings("serial")
+ static private List<ST210FIELDS> EventProtocol = new LinkedList<ST210FIELDS>() {
+
+ {
+ add(ST210FIELDS.HDR_EVENT);
+ add(ST210FIELDS.DEV_ID);
+ add(ST210FIELDS.SW_VER);
+ add(ST210FIELDS.DATE);
+ add(ST210FIELDS.TIME);
+ add(ST210FIELDS.CELL);
+ add(ST210FIELDS.LAT);
+ add(ST210FIELDS.LON);
+ add(ST210FIELDS.SPD);
+ add(ST210FIELDS.CRS);
+ add(ST210FIELDS.SATT);
+ add(ST210FIELDS.FIX);
+ add(ST210FIELDS.DIST);
+ add(ST210FIELDS.PWR_VOLT);
+ add(ST210FIELDS.IO);
+ add(ST210FIELDS.EVT_ID);
+ }
+
+ };
+
+ @SuppressWarnings("serial")
+ static private List<ST210FIELDS> AlertProtocol = new LinkedList<ST210FIELDS>() {
+
+ {
+ add(ST210FIELDS.HDR_ALERT);
+ add(ST210FIELDS.DEV_ID);
+ add(ST210FIELDS.SW_VER);
+ add(ST210FIELDS.DATE);
+ add(ST210FIELDS.TIME);
+ add(ST210FIELDS.CELL);
+ add(ST210FIELDS.LAT);
+ add(ST210FIELDS.LON);
+ add(ST210FIELDS.SPD);
+ add(ST210FIELDS.CRS);
+ add(ST210FIELDS.SATT);
+ add(ST210FIELDS.FIX);
+ add(ST210FIELDS.DIST);
+ add(ST210FIELDS.PWR_VOLT);
+ add(ST210FIELDS.IO);
+ add(ST210FIELDS.ALERT_ID);
+ }
+
+ };
+
+ @SuppressWarnings("serial")
+ static private List<ST210FIELDS> AliveProtocol = new LinkedList<ST210FIELDS>() {
+
+ {
+ add(ST210FIELDS.HDR_ALIVE);
+ add(ST210FIELDS.DEV_ID);
+ }
+
+ };
+
+ @Override
+ public Object decode(ChannelHandlerContext ctx, Channel channel, Object msg)
+ throws Exception {
+ if (channel != null) {
+ channel.write("OI AMIGO do decoder");
+ }
+ String sentence = (String) msg;
+ return decodeMsg(sentence);
+ }
+
+ public Position decodeMsg(String msg) throws Exception {
+
+ ST210REPORTS report = getReportType(msg);
+
+ List<ST210FIELDS> protocol = report.getProtocol();
+
+ Pattern protocolPattern = report.getProtocolPattern();
+
+ Log.info("Protocol Pattern: " + protocolPattern.toString());
+ Log.info("Msg: " + msg);
+
+ // Parse message
+ Matcher parser = protocolPattern.matcher(msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ // Create new position
+ Position position = new Position();
+
+ position.setAltitude(0D);
+ position.setExtendedInfo("");
+ position.setValid(true);
+
+ Integer index = 0;
+ for (ST210FIELDS field : protocol) {
+
+ String groupValue = parser.group(index++);
+
+ field.populatePosition(position, groupValue, getDataManager());
+ }
+
+ return position;
+ }
+}
diff --git a/test/org/traccar/protocol/ST210ProtocolDecoderTest.java b/test/org/traccar/protocol/ST210ProtocolDecoderTest.java
new file mode 100644
index 000000000..a2ffe5bac
--- /dev/null
+++ b/test/org/traccar/protocol/ST210ProtocolDecoderTest.java
@@ -0,0 +1,73 @@
+package org.traccar.protocol;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.sql.SQLException;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.traccar.Server;
+import org.traccar.helper.Log;
+import org.traccar.server.SocketCliente;
+
+public class ST210ProtocolDecoderTest {
+
+ @BeforeClass
+ public static void UpServer() {
+ final Server service = new Server();
+ String[] args = new String[1];
+ args[0] = "setup\\windows\\windows.cfg";
+ try {
+ service.init(args);
+
+ Log.info("starting server...");
+ service.start();
+
+ // Shutdown server properly
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ Log.info("shutting down server...");
+ service.stop();
+ }
+ });
+
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testClienteMsg() throws Exception {
+
+ SocketCliente cliente = new SocketCliente();
+ cliente.SendMSG(
+ "localhost",
+ 5010,
+ "SA200STT;317652;042;20120718;15:37:12;16d41;-15.618755;-056.083241;000.024;000.00;8;1;41548;12.17;100000;2;1979");
+
+ }
+
+/* @Test
+ public void testDecode() throws Exception {
+
+ ST210ProtocolDecoder decoder = new ST210ProtocolDecoder(
+ new TestDataManager(), 0);
+
+ assertNotNull(decoder
+ .decode(null,
+ null,
+ "SA200STT;317652;042;20120718;15:37:12;16d41;-15.618755;-056.083241;000.024;000.00;8;1;41548;12.17;100000;2;1979"));
+ assertNotNull(decoder
+ .decode(null,
+ null,
+ "SA200STT;317652;042;20120721;19:04:30;16d41;-15.618743;-056.083221;000.001;000.00;12;1;41557;12.21;000000;1;3125"));
+ assertNotNull(decoder
+ .decode(null,
+ null,
+ "SA200STT;317652;042;20120722;00:24:23;16d41;-15.618767;-056.083214;000.011;000.00;11;1;41557;12.21;000000;1;3205"));
+ }*/
+}