From 58b6dc11e08f43b1a0dc7dc96ad43241aff94f0c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 Aug 2012 11:36:43 +0400 Subject: Merge pull request --- pom.xml | 22 +- src/org/traccar/protocol/ST210ProtocolDecoder.java | 640 +++++++++++++++++++++ .../traccar/protocol/ST210ProtocolDecoderTest.java | 73 +++ 3 files changed, 729 insertions(+), 6 deletions(-) create mode 100644 src/org/traccar/protocol/ST210ProtocolDecoder.java create mode 100644 test/org/traccar/protocol/ST210ProtocolDecoderTest.java diff --git a/pom.xml b/pom.xml index b6d4a5a6d..9e11580f3 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.traccar traccar - 0.0.1-SNAPSHOT + 1.1.0-SNAPSHOT @@ -21,15 +21,25 @@ netty 3.5.2.Final - - javax.servlet - javax.servlet-api - 3.0.1 - junit junit 4.10 + + + tracker-server + target\classes + src + test + + + src + + **/*.java + + + + \ 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 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 protocol) { + + String patternStr = ""; + + for (ST210FIELDS field : protocol) { + patternStr += field.getPattern(); + } + + return Pattern.compile(patternStr); + + } + + @SuppressWarnings("serial") + static private List StatusProtocol = new LinkedList() { + + { + 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 EmergencyProtocol = new LinkedList() { + + { + 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 EventProtocol = new LinkedList() { + + { + 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 AlertProtocol = new LinkedList() { + + { + 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 AliveProtocol = new LinkedList() { + + { + 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 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")); + }*/ +} -- cgit v1.2.3