From fba1e6f6f43b35a520a5bd09f45796287b06293f Mon Sep 17 00:00:00 2001 From: Anton Tananaev <anton.tananaev@gmail.com> Date: Tue, 31 Jul 2012 22:40:27 +0400 Subject: Fix GL200 decoder (fix #33) --- src/org/traccar/protocol/Gl200ProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/org/traccar/protocol/Gl200ProtocolDecoder.java index 506b55790..63def5ddf 100644 --- a/src/org/traccar/protocol/Gl200ProtocolDecoder.java +++ b/src/org/traccar/protocol/Gl200ProtocolDecoder.java @@ -42,7 +42,7 @@ public class Gl200ProtocolDecoder extends GenericProtocolDecoder { */ static private Pattern pattern = Pattern.compile( "\\+RESP:GT...," + - "\\d{6}," + // Protocol version + "[0-9a-fA-F]{6}," + // Protocol version "(\\d{15})," + // IMEI "[^,]*," + // Device name "(?:(?:\\d," + // Report ID / Geo mode -- cgit v1.2.3 From 58b6dc11e08f43b1a0dc7dc96ad43241aff94f0c Mon Sep 17 00:00:00 2001 From: Anton Tananaev <anton.tananaev@gmail.com> 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 (limited to 'src/org/traccar') 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> @@ -21,15 +21,25 @@ <artifactId>netty</artifactId> <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")); + }*/ +} -- cgit v1.2.3 From d19a6c8cc2f5f2852e046eb20d5f00dfdf3baeff Mon Sep 17 00:00:00 2001 From: Anton Tananaev <anton.tananaev@gmail.com> Date: Sat, 4 Aug 2012 13:00:45 +0400 Subject: Style corrections --- pom.xml | 84 +- src/org/traccar/protocol/ST210ProtocolDecoder.java | 1242 ++++++++++---------- .../traccar/protocol/ST210ProtocolDecoderTest.java | 96 +- 3 files changed, 711 insertions(+), 711 deletions(-) (limited to 'src/org/traccar') diff --git a/pom.xml b/pom.xml index 9e11580f3..5b93f062f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,45 +1,45 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.traccar</groupId> - <artifactId>traccar</artifactId> - <version>1.1.0-SNAPSHOT</version> + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.traccar</groupId> + <artifactId>traccar</artifactId> + <version>1.1.0-SNAPSHOT</version> - <dependencies> - <dependency> - <groupId>com.h2database</groupId> - <artifactId>h2</artifactId> - <version>1.3.167</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.aggregate</groupId> - <artifactId>jetty-all</artifactId> - <version>8.1.4.v20120524</version> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty</artifactId> - <version>3.5.2.Final</version> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.10</version> - </dependency> - </dependencies> + <dependencies> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>1.3.167</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.aggregate</groupId> + <artifactId>jetty-all</artifactId> + <version>8.1.4.v20120524</version> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty</artifactId> + <version>3.5.2.Final</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 + <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> diff --git a/src/org/traccar/protocol/ST210ProtocolDecoder.java b/src/org/traccar/protocol/ST210ProtocolDecoder.java index 8fbea8da5..230dd5505 100644 --- a/src/org/traccar/protocol/ST210ProtocolDecoder.java +++ b/src/org/traccar/protocol/ST210ProtocolDecoder.java @@ -16,625 +16,625 @@ 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; - } + /** + * 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 index a2ffe5bac..cf5b0b8e6 100644 --- a/test/org/traccar/protocol/ST210ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/ST210ProtocolDecoderTest.java @@ -10,64 +10,64 @@ import org.junit.BeforeClass; import org.junit.Test; import org.traccar.Server; import org.traccar.helper.Log; -import org.traccar.server.SocketCliente; +//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); + /*@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(); + 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(); - } - }); + // 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(); - } - } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } - @Test - public void testClienteMsg() throws Exception { + @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"); + 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 { +/* @Test + public void testDecode() throws Exception { - ST210ProtocolDecoder decoder = new ST210ProtocolDecoder( - new TestDataManager(), 0); + 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")); - }*/ + 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 From 9784127324bee141e8f3740a156a6fd24bd0273b Mon Sep 17 00:00:00 2001 From: Anton Tananaev <anton.tananaev@gmail.com> Date: Sat, 4 Aug 2012 17:11:59 +0400 Subject: Change pattern (fix #34) --- src/org/traccar/protocol/Gps103ProtocolDecoder.java | 2 +- test/org/traccar/protocol/Gps103ProtocolDecoderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/org/traccar/protocol/Gps103ProtocolDecoder.java index 714a80e49..88a83ef80 100644 --- a/src/org/traccar/protocol/Gps103ProtocolDecoder.java +++ b/src/org/traccar/protocol/Gps103ProtocolDecoder.java @@ -45,7 +45,7 @@ public class Gps103ProtocolDecoder extends GenericProtocolDecoder { "([\\d]+)," + // IMEI "[^,]+," + "(\\d{2})(\\d{2})(\\d{2})[\\d]+," + // Date - "[+]?[\\d]*," + + "[^,]*," + "[FL]," + // F - full / L - low "([\\d]{2})([\\d]{2})([\\d]{2}).([\\d]{3})," + // Time (HHMMSS.SSS) "([AV])," + // Validity diff --git a/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java b/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java index c09b34bc7..7a90e4fbd 100644 --- a/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java +++ b/test/org/traccar/protocol/Gps103ProtocolDecoderTest.java @@ -23,6 +23,9 @@ public class Gps103ProtocolDecoderTest { assertNotNull(decoder.decode(null, null, "imei:359587010124900,tracker,0809231929,13554900601,F,112909.397,A,2234.4669,N,11354.3287,E,0.11,321.53,")); + + assertNotNull(decoder.decode(null, null, + "imei:353451049926460,tracker,1208042043,123456 99008026,F,124336.000,A,3509.8668,N,03322.7636,E,0.00,,")); } -- cgit v1.2.3 From 9d31234ca1882f58c6046e8f6897a39a77b1e6a7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev <anton.tananaev@gmail.com> Date: Sat, 4 Aug 2012 17:54:50 +0400 Subject: Modify directory structure --- pom.xml | 2 +- src/Main.java | 24 - src/favicon.ico | Bin 1150 -> 0 bytes src/index.html | 977 ------------------------------------ src/org/traccar/Main.java | 40 ++ src/org/traccar/http/WebServer.java | 4 +- src/web/favicon.ico | Bin 0 -> 1150 bytes src/web/index.html | 977 ++++++++++++++++++++++++++++++++++++ 8 files changed, 1020 insertions(+), 1004 deletions(-) delete mode 100644 src/Main.java delete mode 100644 src/favicon.ico delete mode 100644 src/index.html create mode 100644 src/org/traccar/Main.java create mode 100644 src/web/favicon.ico create mode 100644 src/web/index.html (limited to 'src/org/traccar') diff --git a/pom.xml b/pom.xml index 7b4a16420..c25d05498 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,7 @@ <configuration> <archive> <manifest> - <mainClass>Main</mainClass> + <mainClass>org.traccar.Main</mainClass> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> </manifest> diff --git a/src/Main.java b/src/Main.java deleted file mode 100644 index 8b6f2002e..000000000 --- a/src/Main.java +++ /dev/null @@ -1,24 +0,0 @@ -import org.traccar.Server; -import org.traccar.helper.Log; - -public class Main { - - public static void main(String[] args) throws Exception { - - final Server service = new Server(); - 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(); - } - }); - - } -} diff --git a/src/favicon.ico b/src/favicon.ico deleted file mode 100644 index 6fd696c25..000000000 Binary files a/src/favicon.ico and /dev/null differ diff --git a/src/index.html b/src/index.html deleted file mode 100644 index cde73f47b..000000000 --- a/src/index.html +++ /dev/null @@ -1,977 +0,0 @@ -<!doctype html> -<html> -<head> -<title>Traccar Manager</title> -<link rel="stylesheet" type="text/css" href="http://cdn.sencha.io/ext-4.1.0-gpl/resources/css/ext-all.css" /> -<script type="text/javascript" src="http://cdn.sencha.io/ext-4.1.0-gpl/ext-all.js"></script> - -<!-- check for new version: https://raw.github.com/VinylFox/ExtJS.ux.GMapPanel/master/src/GMapPanel3.js --> - -<script type="text/javascript"> -Ext.ns('Ext.ux'); -/** - * @class Ext.ux.GMapPanel - * @extends Ext.Panel - * @author Shea Frederick - */ -Ext.define('Ext.ux.GMapPanel', { - - extend: 'Ext.panel.Panel', - - alias: 'widget.gmappanel', - - requires: ['Ext.window.MessageBox'], - /** - * @cfg {Boolean} border - * Defaults to <tt>false</tt>. See {@link Ext.Panel}.<code>{@link Ext.Panel#border border}</code>. - */ - border: false, - - /** - * @cfg {Array} respErrors - * An array of msg/code pairs. - */ - respErrors: [{ - code: 'UNKNOWN_ERROR', - msg: 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.' - },{ - code: 'ERROR', - msg: 'There was a problem contacting the Google servers.' - },{ - code: 'ZERO_RESULTS', - msg: 'The request did not encounter any errors but returns zero results.' - },{ - code: 'INVALID_REQUEST', - msg: 'This request was invalid.' - },{ - code: 'REQUEST_DENIED', - msg: 'The webpage is not allowed to use the geocoder for some reason.' - },{ - code: 'OVER_QUERY_LIMIT', - msg: 'The webpage has gone over the requests limit in too short a period of time.' - }], - /** - * @cfg {Array} locationTypes - * An array of msg/code/level pairs. - */ - locationTypes: [{ - level: 4, - code: 'ROOFTOP', - msg: 'The returned result is a precise geocode for which we have location information accurate down to street address precision.' - },{ - level: 3, - code: 'RANGE_INTERPOLATED', - msg: 'The returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address.' - },{ - level: 2, - code: 'GEOMETRIC_CENTER', - msg: 'The returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region).' - },{ - level: 1, - code: 'APPROXIMATE', - msg: 'The returned result is approximate.' - }], - /** - * @cfg {String} respErrorTitle - * Defaults to <tt>'Error'</tt>. - */ - respErrorTitle : 'Error', - /** - * @cfg {String} geoErrorMsgUnable - * Defaults to <tt>'Unable to Locate the Address you provided'</tt>. - */ - geoErrorMsgUnable : 'Unable to Locate the Address you provided', - /** - * @cfg {String} geoErrorTitle - * Defaults to <tt>'Address Location Error'</tt>. - */ - geoErrorTitle : 'Address Location Error', - /** - * @cfg {String} geoErrorMsgAccuracy - * Defaults to <tt>'The address provided has a low accuracy.<br><br>{0} Accuracy.'</tt>. - * <div class="mdetail-params"><ul> - * <li><b><code>ROOFTOP</code></b> : <div class="sub-desc"><p> - * The returned result is a precise geocode for which we have location information accurate down to street address precision. - * </p></div></li> - * <li><b><code>RANGE_INTERPOLATED</code></b> : <div class="sub-desc"><p> - * The returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address. - * </p></div></li> - * <li><b><code>GEOMETRIC_CENTER</code></b> : <div class="sub-desc"><p> - * The returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region). - * </p></div></li> - * <li><b><code>APPROXIMATE</code></b> : <div class="sub-desc"><p> - * The returned result is approximate. - * </p></div></li> - * </ul></div> - */ - geoErrorMsgAccuracy : 'The address provided has a low accuracy.<br><br>"{0}" Accuracy.<br><br>{1}', - /** - * @cfg {String} gmapType - * The type of map to display, generic options available are: 'map', 'panorama'. - * Defaults to <tt>'map'</tt>. - * More specific maps can be used by specifying the google map type: - * <div class="mdetail-params"><ul> - * <li><b><code>G_NORMAL_MAP</code></b> : <div class="sub-desc"><p> - * Displays the default road map view - * </p></div></li> - * <li><b><code>G_SATELLITE_MAP</code></b> : <div class="sub-desc"><p> - * Displays Google Earth satellite images - * </p></div></li> - * <li><b><code>G_HYBRID_MAP</code></b> : <div class="sub-desc"><p> - * Displays a mixture of normal and satellite views - * </p></div></li> - * <li><b><code>G_DEFAULT_MAP_TYPES</code></b> : <div class="sub-desc"><p> - * Contains an array of the above three types, useful for iterative processing. - * </p></div></li> - * <li><b><code>G_PHYSICAL_MAP</code></b> : <div class="sub-desc"><p> - * Displays a physical map based on terrain information. - * </p></div></li> - * <li><b><code>G_MOON_ELEVATION_MAP</code></b> : <div class="sub-desc"><p> - * Displays a shaded terrain map of the surface of the Moon, color-coded by altitude. - * </p></div></li> - * <li><b><code>G_MOON_VISIBLE_MAP</code></b> : <div class="sub-desc"><p> - * Displays photographic imagery taken from orbit around the moon. - * </p></div></li> - * <li><b><code>G_MARS_ELEVATION_MAP</code></b> : <div class="sub-desc"><p> - * Displays a shaded terrain map of the surface of Mars, color-coded by altitude. - * </p></div></li> - * <li><b><code>G_MARS_VISIBLE_MAP</code></b> : <div class="sub-desc"><p> - * Displays photographs taken from orbit around Mars. - * </p></div></li> - * <li><b><code>G_MARS_INFRARED_MAP</code></b> : <div class="sub-desc"><p> - * Displays a shaded infrared map of the surface of Mars, where warmer areas appear brighter and colder areas appear darker. - * </p></div></li> - * <li><b><code>G_SKY_VISIBLE_MAP</code></b> : <div class="sub-desc"><p> - * Displays a mosaic of the sky, as seen from Earth, covering the full celestial sphere. - * </p></div></li> - * </ul></div> - * Sample usage: - * <pre><code> - * gmapType: G_MOON_VISIBLE_MAP - * </code></pre> - */ - gmapType : 'map', - /** - * @cfg {Object} setCenter - * The initial center location of the map. The map needs to be centered before it can be used. - * A marker is not required to be specified. - * More markers can be added to the map using the <code>{@link #markers}</code> array. - * For example: - * <pre><code> -setCenter: { - geoCodeAddr: '4 Yawkey Way, Boston, MA, 02215-3409, USA', - marker: {title: 'Fenway Park'} -}, - -// or just specify lat/long -setCenter: { - lat: 42.345573, - lng: -71.098326 -} - * </code></pre> - */ - /** - * @cfg {Number} zoomLevel - * The zoom level to initialize the map at, generally between 1 (whole planet) and 40 (street). - * Also used as the zoom level for panoramas, zero specifies no zoom at all. - * Defaults to <tt>3</tt>. - */ - zoomLevel: 3, - /** - * @cfg {Number} yaw - * The Yaw, or rotational direction of the users perspective in degrees. Only applies to panoramas. - * Defaults to <tt>180</tt>. - */ - yaw: 180, - /** - * @cfg {Number} pitch - * The pitch, or vertical direction of the users perspective in degrees. - * Defaults to <tt>0</tt> (straight ahead). Valid values are between +90 (straight up) and -90 (straight down). - */ - pitch: 0, - /** - * @cfg {Boolean} displayGeoErrors - * True to display geocoding errors to the end user via a message box. - * Defaults to <tt>false</tt>. - */ - displayGeoErrors: false, - /** - * @cfg {Boolean} minGeoAccuracy - * The level to display an accuracy error below. Defaults to <tt>ROOFTOP</tt>. For additional information - * see <a href="http://code.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy">here</a>. - */ - minGeoAccuracy: 'ROOFTOP', - /** - * @cfg {Array} mapConfOpts - * Array of strings representing configuration methods to call, a full list can be found - * <a href="http://code.google.com/apis/maps/documentation/reference.html#GMap2">here</a>. - * For example: - * <pre><code> - * mapConfOpts: ['enableScrollWheelZoom','enableDoubleClickZoom','enableDragging'], - * </code></pre> - */ - /** - * @cfg {Array} mapControls - * Array of strings representing map controls to initialize, a full list can be found - * <a href="http://code.google.com/apis/maps/documentation/reference.html#GControlImpl">here</a>. - * For example: - * <pre><code> - * mapControls: ['GSmallMapControl','GMapTypeControl','NonExistantControl'] - * </code></pre> - */ - /** - * @cfg {Array} markers - * Markers may be added to the map. Instead of specifying <code>lat</code>/<code>lng</code>, - * geocoding can be specified via a <code>geoCodeAddr</code> string. - * For example: - * <pre><code> -markers: [{ - //lat: 42.339641, - //lng: -71.094224, - // instead of lat/lng: - geoCodeAddr: '465 Huntington Avenue, Boston, MA, 02215-5597, USA', - marker: {title: 'Boston Museum of Fine Arts'}, - listeners: { - click: function(e){ - Ext.Msg.alert('Its fine', 'and its art.'); - } - } -},{ - lat: 42.339419, - lng: -71.09077, - marker: {title: 'Northeastern University'} -}] - * </code></pre> - */ - // private - mapDefined: false, - // private - mapDefinedGMap: false, - initComponent : function(){ - - this.addEvents( - /** - * @event mapready - * Fires when the map is ready for interaction - * @param {GMapPanel} this - * @param {GMap} map - */ - 'mapready', - /** - * @event apiready - * Fires when the Google Maps API is loaded - */ - 'apiready' - ); - - Ext.applyIf(this,{ - markers: [], - cache: { - marker: [], - polyline: [], - infowindow: [] - } - }); - - Ext.ux.GMapPanel.superclass.initComponent.call(this); - - if (window.google && window.google.maps){ - this.on('afterrender', this.apiReady, this); - }else{ - window.gmapapiready = Ext.Function.bind(this.apiReady,this); - this.buildScriptTag('http://maps.google.com/maps/api/js?sensor=false&callback=gmapapiready'); - } - - }, - apiReady : function(){ - - if (this.rendered){ - - Ext.defer(function(){ - if (this.gmapType === 'map'){ - this.gmap = new google.maps.Map(this.getEl().dom, {zoom:this.zoomLevel,mapTypeId: google.maps.MapTypeId.ROADMAP}); - this.mapDefined = true; - this.mapDefinedGMap = true; - } - - if (this.gmapType === 'panorama'){ - this.gmap = new GStreetviewPanorama(this.getEl().dom); - this.mapDefined = true; - } - - if (!this.mapDefined && this.gmapType){ - this.gmap = new google.maps.Map(this.getEl().dom, {zoom:this.zoomLevel,mapTypeId: google.maps.MapTypeId.ROADMAP}); - this.gmap.setMapTypeId(this.gmapType); - this.mapDefined = true; - this.mapDefinedGMap = true; - } - - google.maps.event.addListenerOnce(this.getMap(), 'tilesloaded', Ext.Function.bind(this.onMapReady, this)); - google.maps.event.addListener(this.getMap(), 'dragend', Ext.Function.bind(this.dragEnd, this)); - - - if (typeof this.setCenter === 'object') { - if (typeof this.setCenter.geoCodeAddr === 'string'){ - this.geoCodeLookup(this.setCenter.geoCodeAddr, this.setCenter.marker, false, true, this.setCenter.listeners); - }else{ - if (this.gmapType === 'map'){ - var point = new google.maps.LatLng(this.setCenter.lat,this.setCenter.lng); - this.getMap().setCenter(point, this.zoomLevel); - this.lastCenter = point; - } - if (typeof this.setCenter.marker === 'object' && typeof point === 'object') { - this.addMarker(point, this.setCenter.marker, this.setCenter.marker.clear); - } - } - if (this.gmapType === 'panorama'){ - this.getMap().setLocationAndPOV(new google.maps.LatLng(this.setCenter.lat,this.setCenter.lng), {yaw: this.yaw, pitch: this.pitch, zoom: this.zoomLevel}); - } - } - }, 200,this); // Ext.defer - - }else{ - this.on('afterrender', this.apiReady, this); - } - }, - // private - afterRender : function(){ - - var wh = this.ownerCt.getSize(); - Ext.applyIf(this, wh); - - Ext.ux.GMapPanel.superclass.afterRender.call(this); - - }, - // private - buildScriptTag: function(filename, callback) { - var script = document.createElement('script'), - head = document.getElementsByTagName("head")[0]; - script.type = "text/javascript"; - script.src = filename; - - return head.appendChild(script); - }, - // private - onMapReady : function(){ - - this.addMapControls(); - this.addOptions(); - - this.addMarkers(this.markers); - this.addMapListeners(); - - this.fireEvent('mapready', this, this.getMap()); - return this; - }, - // private - addMapListeners : function () { - if (this.maplisteners){ - Ext.iterate(this.maplisteners, function(key,val){ - google.maps.event.addListener(this.getMap(), key, Ext.Function.bind(val,this)); - },this); - } - }, - // private - onResize : function(w, h){ - - Ext.ux.GMapPanel.superclass.onResize.call(this, w, h); - - // check for the existance of the google map in case the onResize fires too early - if (typeof this.getMap() == 'object') { - google.maps.event.trigger(this.getMap(), 'resize'); - if (this.lastCenter){ - this.getMap().setCenter(this.lastCenter, this.zoomLevel); - } - } - - }, - // private - setSize : function(width, height, animate){ - - Ext.ux.GMapPanel.superclass.setSize.call(this, width, height, animate); - - // check for the existance of the google map in case setSize is called too early - if (Ext.isObject(this.getMap())) { - google.maps.event.trigger(this.getMap(), 'resize'); - if (this.lastCenter){ - this.getMap().setCenter(this.lastCenter, this.zoomLevel); - } - } - - }, - // private - dragEnd: function(){ - this.lastCenter = this.getMap().getCenter(); - }, - /** - * Returns the current google map which can be used to call Google Maps API specific handlers. - * @return {GMap} this - */ - getMap : function(){ - - return this.gmap; - - }, - /** - * Returns the maps center as a GLatLng object - * @return {GLatLng} this - */ - getCenter : function(){ - - return this.getMap().getCenter(); - - }, - /** - * Returns the maps center as a simple object - * @return {Object} this has lat and lng properties only - */ - getCenterLatLng : function(){ - - var ll = this.getCenter(); - return {lat: ll.lat(), lng: ll.lng()}; - - }, - /** - * Creates markers from the array that is passed in. Each marker must consist of at least - * <code>lat</code> and <code>lng</code> properties or a <code>geoCodeAddr</code>. - * @param {Array} markers an array of marker objects - */ - addMarkers : function(markers) { - if (Ext.isArray(markers)){ - for (var i = 0; i < markers.length; i++) { - if (markers[i]) { - if (typeof markers[i].geoCodeAddr == 'string') { - this.geoCodeLookup(markers[i].geoCodeAddr, markers[i].marker, false, markers[i].setCenter, markers[i].listeners); - } else { - var mkr_point = new google.maps.LatLng(markers[i].lat, markers[i].lng); - this.addMarker(mkr_point, markers[i].marker, false, markers[i].setCenter, markers[i].listeners); - } - } - } - } - - }, - /** - * Creates a single marker. - * @param {Object} point a GLatLng point - * @param {Object} marker a marker object consisting of at least lat and lng - * @param {Boolean} clear clear other markers before creating this marker - * @param {Boolean} center true to center the map on this marker - * @param {Object} listeners a listeners config - */ - addMarker : function(point, marker, clear, center, listeners){ - - Ext.applyIf(marker,{}); - - if (clear === true){ - this.clearMarkers(); - } - if (center === true) { - this.getMap().setCenter(point, this.zoomLevel) - this.lastCenter = point; - } - - var mark = new google.maps.Marker(Ext.apply(marker, { - position: point - })); - - if (marker.infoWindow){ - this.createInfoWindow(marker.infoWindow, point, mark); - } - - this.cache.marker.push(mark); - mark.setMap(this.getMap()); - - if (typeof listeners === 'object'){ - for (evt in listeners) { - google.maps.event.addListener(mark, evt, listeners[evt]); - } - } - - return mark; - - }, - /** - * Creates a single polyline. - * @param {Array} points an array of polyline points - * @param {Object} linestyle an object defining the line style to use - */ - addPolyline : function(points, linestyle){ - - var plinepnts = new google.maps.MVCArray, pline, linestyle = linestyle ? linestyle : { - strokeColor: '#FF0000', - strokeOpacity: 1.0, - strokeWeight: 2 - }; - - Ext.each(points, function(point){ - plinepnts.push(new google.maps.LatLng(point.lat, point.lng)); - }, this); - - var pline = new google.maps.Polyline(Ext.apply({ - path: plinepnts - },linestyle)); - - this.cache.polyline.push(pline); - - pline.setMap(this.getMap()); - - }, - /** - * Creates an Info Window. - * @param {Object} inwin an Info Window configuration - * @param {GLatLng} point the point to show the Info Window at - * @param {GMarker} marker a marker to attach the Info Window to - */ - createInfoWindow : function(inwin, point, marker){ - - var me = this, infoWindow = new google.maps.InfoWindow({ - content: inwin.content, - position: point - }); - - if (marker) { - google.maps.event.addListener(marker, 'click', function(){ - me.hideAllInfoWindows(); - infoWindow.open(me.getMap()); - }); - } - - this.cache.infowindow.push(infoWindow); - - return infoWindow; - - }, - // private - hideAllInfoWindows : function(){ - for (var i = 0; i < this.cache.infowindow.length; i++) { - this.cache.infowindow[i].close(); - } - }, - // private - clearMarkers : function(){ - - this.hideAllInfoWindows(); - this.hideMarkers(); - - }, - // private - hideMarkers : function(){ - Ext.each(this.cache.marker, function(mrk){ - mrk.setMap(null); - }); - }, - // private - showMarkers : function(){ - Ext.each(this.cache.marker, function(mrk){ - mrk.setMap(this.getMap()); - },this); - }, - // private - addMapControls : function(){ - - if (this.gmapType === 'map') { - if (Ext.isArray(this.mapControls)) { - for(i=0;i<this.mapControls.length;i++){ - //this.addMapControl(this.mapControls[i]); - } - }else if(typeof this.mapControls === 'string'){ - //this.addMapControl(this.mapControls); - }else if(typeof this.mapControls === 'object'){ - //this.getMap().add_control(this.mapControls); - } - } - - }, - /** - * Adds a GMap control to the map. - * @param {String} mc a string representation of the control to be instantiated. - */ - addMapControl : function(mc){ - - var mcf = window[mc]; - if (typeof mcf === 'function') { - //this.getMap().addControl(new mcf()); - } - - }, - // private - addOptions : function(){ - - if (Ext.isArray(this.mapConfOpts)) { - var mc; - for(i=0;i<this.mapConfOpts.length;i++){ - //this.addOption(this.mapConfOpts[i]); - } - }else if(typeof this.mapConfOpts === 'string'){ - //this.addOption(this.mapConfOpts); - } - - }, - /** - * Adds a GMap option to the map. - * @param {String} mo a string representation of the option to be instantiated. - */ - addOption : function(mo){ - - var mof = this.getMap()[mo]; - if (typeof mof === 'function') { - this.getMap()[mo](); - } - - }, - /** - * Looks up and address and optionally add a marker, center the map to this location, or - * clear other markers. Sample usage: - * <pre><code> -buttons: [ - { - text: 'Fenway Park', - handler: function(){ - var addr = '4 Yawkey Way, Boston, MA, 02215-3409, USA'; - Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined); - } - },{ - text: 'Zoom Fenway Park', - handler: function(){ - Ext.getCmp('my_map').zoomLevel = 19; - var addr = '4 Yawkey Way, Boston, MA, 02215-3409, USA'; - Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined); - } - },{ - text: 'Low Accuracy', - handler: function(){ - Ext.getCmp('my_map').geoCodeLookup('Paris, France', undefined, false, true, undefined); - } - },{ - - text: 'Bogus Address', - handler: function(){ - var addr = 'Some Fake, Address, For, Errors'; - Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined); - } - } -] - * </code></pre> - * @param {String} addr the address to lookup. - * @param {Object} marker the marker to add (optional). - * @param {Boolean} clear clear other markers before creating this marker - * @param {Boolean} center true to set this point as the center of the map. - * @param {Object} listeners a listeners config - */ - geoCodeLookup : function(addr, marker, clear, center, listeners) { - - if (!this.geocoder) { - this.geocoder = new google.maps.Geocoder(); - } - this.geocoder.geocode({ - address: addr - }, Ext.Function.bind(this.addAddressToMap, this, [addr, marker, clear, center, listeners], true)); - - }, - // private - centerOnClientLocation : function(){ - this.getClientLocation(function(loc){ - var point = new google.maps.LatLng(loc.latitude,loc.longitude); - this.getMap().setCenter(point, this.zoomLevel); - this.lastCenter = point; - }); - }, - // private - getClientLocation : function(fn, errorFn){ - if (!errorFn) { - errorFn = Ext.emptyFn; - } - if (!this.clientGeo) { - this.clientGeo = google.gears.factory.create('beta.geolocation'); - } - geo.getCurrentPosition(Ext.Function.bind(fn, this), errorFn); - }, - // private - addAddressToMap : function(response, status, addr, marker, clear, center, listeners){ - if (!response || status !== 'OK') { - this.respErrorMsg(status); - }else{ - var place = response[0].geometry.location, - accuracy = this.getLocationTypeInfo(response[0].geometry.location_type,'level'), - reqAccuracy = this.getLocationTypeInfo(this.minGeoAccuracy,'level'); - if (accuracy === 0) { - this.geoErrorMsg(this.geoErrorTitle, this.geoErrorMsgUnable); - }else{ - if (accuracy < reqAccuracy) { - this.geoErrorMsg(this.geoErrorTitle, Ext.String.format(this.geoErrorMsgAccuracy, response[0].geometry.location_type, this.getLocationTypeInfo(response[0].geometry.location_type,'msg'))); - }else{ - point = new google.maps.LatLng(place.lat(),place.lng()); - if (center){ - this.getMap().setCenter(point, this.zoomLevel); - this.lastCenter = point; - } - if (typeof marker === 'object') { - if (!marker.title){ - marker.title = response.formatted_address; - } - var mkr = this.addMarker(point, marker, clear, false, listeners); - if (marker.callback){ - marker.callback.call(this, mkr, point); - } - } - } - } - } - - }, - // private - geoErrorMsg : function(title,msg){ - if (this.displayGeoErrors) { - Ext.MessageBox.alert(title,msg); - } - }, - // private - respErrorMsg : function(code){ - Ext.each(this.respErrors, function(obj){ - if (code == obj.code){ - Ext.MessageBox.alert(this.respErrorTitle, obj.msg); - } - }, this); - }, - // private - getLocationTypeInfo: function(location_type,property){ - var val = 0; - Ext.each(this.locationTypes, function(itm){ - if (itm.code === location_type){ - val = itm[property]; - } - }); - return val; - } -}); -</script> - -<script type="text/javascript"> -Ext.onReady(function() { - - Ext.define('Device', { - extend: 'Ext.data.Model', - fields: [ - {name: 'id', type: 'int'}, - {name: 'imei',type: 'string'} - ] - }); - - Ext.define('Position', { - extend: 'Ext.data.Model', - fields: [ - {name: 'device_id', type: 'int'}, - {name: 'time', type: 'date'}, - {name: 'valid', type: 'boolean'}, - {name: 'latitude', type: 'float'}, - {name: 'longitude', type: 'float'}, - {name: 'speed', type: 'float'}, - {name: 'course', type: 'float'}, - {name: 'power', type: 'float'} - ] - }); - - var devicesUrl = 'devices.json'; - var positionsUrl = 'positions.json'; - - var devices = Ext.create('Ext.data.Store', { - id: 'devices', - model: 'Device', - fields: ['id', 'imei'], - autoSync: true, - proxy: { - type: 'ajax', - api: { - create: devicesUrl + '?action=create', - read: devicesUrl, - update: devicesUrl + '?action=update', - destroy: devicesUrl + '?action=destroy' - }, - reader: { - type: 'json', - root: 'results' - } - } - }); - - var positions = Ext.create('Ext.data.Store', { - id: 'positions', - model: 'Position', - fields: [ - 'device_id', - 'time', - 'valid', - 'latitude', - 'longitude', - 'speed', - 'course', - 'power' - ], - proxy: { - type: 'ajax', - url: positionsUrl, - reader: { - type: 'json', - root: 'results' - } - } - }); - - var map = Ext.create('Ext.ux.GMapPanel', { - id: 'gmap', - setCenter: {lat: 0, lng: 0} - }); - - var devicesPanel = Ext.create('Ext.grid.Panel', { - title: 'Devices', - region: 'west', - split: true, - width: 300, - margins: {top: 5, bottom: 0, right: 0, left: 5}, - - sortableColumns: false, - enableColumnHide: false, - - store: devices, - tbar: [ - { - id: 'device_update', - text: 'Update', - handler : function() { - devices.load(); - } - }, - { - id: 'device_add', - text: 'Add', - handler : function() { - Ext.Msg.prompt('Add', 'Device IMEI:', function(btn, text) { - if (btn == 'ok') { - devices.add({imei: text}); - } - }); - } - }, - { - id: 'device_remove', - text: 'Remove', - disabled: true, - handler : function() { - Ext.Msg.confirm('Remove', 'Are you sure to remove item?', function(btn) { - if (btn == 'yes') { - devices.remove(devicesPanel.getSelectionModel().getLastSelected()); - } - }); - } - }, - { - id: 'device_edit', - text: 'Edit', - disabled: true, - handler : function() { - Ext.Msg.prompt('Edit', 'Device IMEI:', function(btn, text) { - if (btn == 'ok') { - devicesPanel.getSelectionModel().getLastSelected().set('imei', text); - } - }, this, false, devicesPanel.getSelectionModel().getLastSelected().get('imei')); - } - } - ], - columns: [ - {header: 'Id', dataIndex: 'id'}, - {header: 'IMEI', dataIndex: 'imei', flex: 1} - ], - listeners: { - selectionchange: function(sender, selected, eOpts) { - if (selected.length != 0) { - Ext.getCmp('device_remove').enable(); - Ext.getCmp('device_edit').enable(); - - positions.getProxy().url = positionsUrl + '?deviceId=' + - devicesPanel.getSelectionModel().getLastSelected().get('id'); - positions.load(); - Ext.getCmp('position_update').enable(); - } else { - Ext.getCmp('position_update').disable(); - positions.getProxy().url = positionsUrl; - positions.load(); - - Ext.getCmp('device_edit').disable(); - Ext.getCmp('device_remove').disable(); - } - } - } - }); - - var positionsPanel = Ext.create('Ext.grid.Panel', { - title: 'Positions', - region: 'south', - split: true, - height: 300, - margins: {top: 0, bottom: 5, right: 5, left: 5}, - - sortableColumns: false, - enableColumnHide: false, - - store: positions, - tbar: [ - { - id: 'position_update', - text: 'Update', - disabled: true, - handler : function() { - positions.load(); - } - } - ], - columns: [ - {header: 'Device Id', dataIndex: 'device_id'}, - { - header: 'Time', - dataIndex: 'time', - flex: 1, - renderer: Ext.util.Format.dateRenderer('Y-m-d H:i:s') - }, - {header: 'Valid', dataIndex: 'valid'}, - {header: 'Latitude', dataIndex: 'latitude'}, - {header: 'Longitude', dataIndex: 'longitude'}, - {header: 'Speed', dataIndex: 'speed'}, - {header: 'Course', dataIndex: 'course'}, - {header: 'Power', dataIndex: 'power'} - ], - listeners: { - selectionchange: function(sender, selected, eOpts) { - if (selected.length != 0) { - var lat = positionsPanel.getSelectionModel().getLastSelected().get('latitude'); - var lng = positionsPanel.getSelectionModel().getLastSelected().get('longitude'); - var point = new google.maps.LatLng(lat, lng); - map.addMarker(point, {lat: lat, lng: lng}, true, true); - } else { - map.clearMarkers(); // private? - } - } - } - }); - - var mapPanel = Ext.create('Ext.panel.Panel', { - title: 'Map', - region: 'center', - margins: {top: 5, bottom: 0, right: 5, left: 0}, - - layout: 'fit', - items: [map] - }); - - Ext.create('Ext.container.Viewport', { - renderTo: Ext.getBody(), - layout: 'border', - items: [devicesPanel, positionsPanel, mapPanel] - }); - - devices.load(); -}); -</script> -</head> -<body></body> -</html> diff --git a/src/org/traccar/Main.java b/src/org/traccar/Main.java new file mode 100644 index 000000000..36228ee58 --- /dev/null +++ b/src/org/traccar/Main.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import org.traccar.helper.Log; + +public class Main { + + public static void main(String[] args) throws Exception { + + final Server service = new Server(); + 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(); + } + }); + + } +} diff --git a/src/org/traccar/http/WebServer.java b/src/org/traccar/http/WebServer.java index cf7b21623..6c79e6421 100644 --- a/src/org/traccar/http/WebServer.java +++ b/src/org/traccar/http/WebServer.java @@ -55,7 +55,7 @@ public class WebServer { response.setContentType("text/html"); - InputStream in = this.getClass().getClassLoader().getResourceAsStream("index.html"); + InputStream in = this.getClass().getClassLoader().getResourceAsStream("web/index.html"); OutputStream out = response.getOutputStream(); byte[] buffer = new byte[BUFFER_SIZE]; @@ -71,7 +71,7 @@ public class WebServer { response.setContentType("image/x-icon"); - InputStream in = this.getClass().getClassLoader().getResourceAsStream("favicon.ico"); + InputStream in = this.getClass().getClassLoader().getResourceAsStream("web/favicon.ico"); OutputStream out = response.getOutputStream(); byte[] buffer = new byte[BUFFER_SIZE]; diff --git a/src/web/favicon.ico b/src/web/favicon.ico new file mode 100644 index 000000000..6fd696c25 Binary files /dev/null and b/src/web/favicon.ico differ diff --git a/src/web/index.html b/src/web/index.html new file mode 100644 index 000000000..cde73f47b --- /dev/null +++ b/src/web/index.html @@ -0,0 +1,977 @@ +<!doctype html> +<html> +<head> +<title>Traccar Manager</title> +<link rel="stylesheet" type="text/css" href="http://cdn.sencha.io/ext-4.1.0-gpl/resources/css/ext-all.css" /> +<script type="text/javascript" src="http://cdn.sencha.io/ext-4.1.0-gpl/ext-all.js"></script> + +<!-- check for new version: https://raw.github.com/VinylFox/ExtJS.ux.GMapPanel/master/src/GMapPanel3.js --> + +<script type="text/javascript"> +Ext.ns('Ext.ux'); +/** + * @class Ext.ux.GMapPanel + * @extends Ext.Panel + * @author Shea Frederick + */ +Ext.define('Ext.ux.GMapPanel', { + + extend: 'Ext.panel.Panel', + + alias: 'widget.gmappanel', + + requires: ['Ext.window.MessageBox'], + /** + * @cfg {Boolean} border + * Defaults to <tt>false</tt>. See {@link Ext.Panel}.<code>{@link Ext.Panel#border border}</code>. + */ + border: false, + + /** + * @cfg {Array} respErrors + * An array of msg/code pairs. + */ + respErrors: [{ + code: 'UNKNOWN_ERROR', + msg: 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.' + },{ + code: 'ERROR', + msg: 'There was a problem contacting the Google servers.' + },{ + code: 'ZERO_RESULTS', + msg: 'The request did not encounter any errors but returns zero results.' + },{ + code: 'INVALID_REQUEST', + msg: 'This request was invalid.' + },{ + code: 'REQUEST_DENIED', + msg: 'The webpage is not allowed to use the geocoder for some reason.' + },{ + code: 'OVER_QUERY_LIMIT', + msg: 'The webpage has gone over the requests limit in too short a period of time.' + }], + /** + * @cfg {Array} locationTypes + * An array of msg/code/level pairs. + */ + locationTypes: [{ + level: 4, + code: 'ROOFTOP', + msg: 'The returned result is a precise geocode for which we have location information accurate down to street address precision.' + },{ + level: 3, + code: 'RANGE_INTERPOLATED', + msg: 'The returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address.' + },{ + level: 2, + code: 'GEOMETRIC_CENTER', + msg: 'The returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region).' + },{ + level: 1, + code: 'APPROXIMATE', + msg: 'The returned result is approximate.' + }], + /** + * @cfg {String} respErrorTitle + * Defaults to <tt>'Error'</tt>. + */ + respErrorTitle : 'Error', + /** + * @cfg {String} geoErrorMsgUnable + * Defaults to <tt>'Unable to Locate the Address you provided'</tt>. + */ + geoErrorMsgUnable : 'Unable to Locate the Address you provided', + /** + * @cfg {String} geoErrorTitle + * Defaults to <tt>'Address Location Error'</tt>. + */ + geoErrorTitle : 'Address Location Error', + /** + * @cfg {String} geoErrorMsgAccuracy + * Defaults to <tt>'The address provided has a low accuracy.<br><br>{0} Accuracy.'</tt>. + * <div class="mdetail-params"><ul> + * <li><b><code>ROOFTOP</code></b> : <div class="sub-desc"><p> + * The returned result is a precise geocode for which we have location information accurate down to street address precision. + * </p></div></li> + * <li><b><code>RANGE_INTERPOLATED</code></b> : <div class="sub-desc"><p> + * The returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address. + * </p></div></li> + * <li><b><code>GEOMETRIC_CENTER</code></b> : <div class="sub-desc"><p> + * The returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region). + * </p></div></li> + * <li><b><code>APPROXIMATE</code></b> : <div class="sub-desc"><p> + * The returned result is approximate. + * </p></div></li> + * </ul></div> + */ + geoErrorMsgAccuracy : 'The address provided has a low accuracy.<br><br>"{0}" Accuracy.<br><br>{1}', + /** + * @cfg {String} gmapType + * The type of map to display, generic options available are: 'map', 'panorama'. + * Defaults to <tt>'map'</tt>. + * More specific maps can be used by specifying the google map type: + * <div class="mdetail-params"><ul> + * <li><b><code>G_NORMAL_MAP</code></b> : <div class="sub-desc"><p> + * Displays the default road map view + * </p></div></li> + * <li><b><code>G_SATELLITE_MAP</code></b> : <div class="sub-desc"><p> + * Displays Google Earth satellite images + * </p></div></li> + * <li><b><code>G_HYBRID_MAP</code></b> : <div class="sub-desc"><p> + * Displays a mixture of normal and satellite views + * </p></div></li> + * <li><b><code>G_DEFAULT_MAP_TYPES</code></b> : <div class="sub-desc"><p> + * Contains an array of the above three types, useful for iterative processing. + * </p></div></li> + * <li><b><code>G_PHYSICAL_MAP</code></b> : <div class="sub-desc"><p> + * Displays a physical map based on terrain information. + * </p></div></li> + * <li><b><code>G_MOON_ELEVATION_MAP</code></b> : <div class="sub-desc"><p> + * Displays a shaded terrain map of the surface of the Moon, color-coded by altitude. + * </p></div></li> + * <li><b><code>G_MOON_VISIBLE_MAP</code></b> : <div class="sub-desc"><p> + * Displays photographic imagery taken from orbit around the moon. + * </p></div></li> + * <li><b><code>G_MARS_ELEVATION_MAP</code></b> : <div class="sub-desc"><p> + * Displays a shaded terrain map of the surface of Mars, color-coded by altitude. + * </p></div></li> + * <li><b><code>G_MARS_VISIBLE_MAP</code></b> : <div class="sub-desc"><p> + * Displays photographs taken from orbit around Mars. + * </p></div></li> + * <li><b><code>G_MARS_INFRARED_MAP</code></b> : <div class="sub-desc"><p> + * Displays a shaded infrared map of the surface of Mars, where warmer areas appear brighter and colder areas appear darker. + * </p></div></li> + * <li><b><code>G_SKY_VISIBLE_MAP</code></b> : <div class="sub-desc"><p> + * Displays a mosaic of the sky, as seen from Earth, covering the full celestial sphere. + * </p></div></li> + * </ul></div> + * Sample usage: + * <pre><code> + * gmapType: G_MOON_VISIBLE_MAP + * </code></pre> + */ + gmapType : 'map', + /** + * @cfg {Object} setCenter + * The initial center location of the map. The map needs to be centered before it can be used. + * A marker is not required to be specified. + * More markers can be added to the map using the <code>{@link #markers}</code> array. + * For example: + * <pre><code> +setCenter: { + geoCodeAddr: '4 Yawkey Way, Boston, MA, 02215-3409, USA', + marker: {title: 'Fenway Park'} +}, + +// or just specify lat/long +setCenter: { + lat: 42.345573, + lng: -71.098326 +} + * </code></pre> + */ + /** + * @cfg {Number} zoomLevel + * The zoom level to initialize the map at, generally between 1 (whole planet) and 40 (street). + * Also used as the zoom level for panoramas, zero specifies no zoom at all. + * Defaults to <tt>3</tt>. + */ + zoomLevel: 3, + /** + * @cfg {Number} yaw + * The Yaw, or rotational direction of the users perspective in degrees. Only applies to panoramas. + * Defaults to <tt>180</tt>. + */ + yaw: 180, + /** + * @cfg {Number} pitch + * The pitch, or vertical direction of the users perspective in degrees. + * Defaults to <tt>0</tt> (straight ahead). Valid values are between +90 (straight up) and -90 (straight down). + */ + pitch: 0, + /** + * @cfg {Boolean} displayGeoErrors + * True to display geocoding errors to the end user via a message box. + * Defaults to <tt>false</tt>. + */ + displayGeoErrors: false, + /** + * @cfg {Boolean} minGeoAccuracy + * The level to display an accuracy error below. Defaults to <tt>ROOFTOP</tt>. For additional information + * see <a href="http://code.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy">here</a>. + */ + minGeoAccuracy: 'ROOFTOP', + /** + * @cfg {Array} mapConfOpts + * Array of strings representing configuration methods to call, a full list can be found + * <a href="http://code.google.com/apis/maps/documentation/reference.html#GMap2">here</a>. + * For example: + * <pre><code> + * mapConfOpts: ['enableScrollWheelZoom','enableDoubleClickZoom','enableDragging'], + * </code></pre> + */ + /** + * @cfg {Array} mapControls + * Array of strings representing map controls to initialize, a full list can be found + * <a href="http://code.google.com/apis/maps/documentation/reference.html#GControlImpl">here</a>. + * For example: + * <pre><code> + * mapControls: ['GSmallMapControl','GMapTypeControl','NonExistantControl'] + * </code></pre> + */ + /** + * @cfg {Array} markers + * Markers may be added to the map. Instead of specifying <code>lat</code>/<code>lng</code>, + * geocoding can be specified via a <code>geoCodeAddr</code> string. + * For example: + * <pre><code> +markers: [{ + //lat: 42.339641, + //lng: -71.094224, + // instead of lat/lng: + geoCodeAddr: '465 Huntington Avenue, Boston, MA, 02215-5597, USA', + marker: {title: 'Boston Museum of Fine Arts'}, + listeners: { + click: function(e){ + Ext.Msg.alert('Its fine', 'and its art.'); + } + } +},{ + lat: 42.339419, + lng: -71.09077, + marker: {title: 'Northeastern University'} +}] + * </code></pre> + */ + // private + mapDefined: false, + // private + mapDefinedGMap: false, + initComponent : function(){ + + this.addEvents( + /** + * @event mapready + * Fires when the map is ready for interaction + * @param {GMapPanel} this + * @param {GMap} map + */ + 'mapready', + /** + * @event apiready + * Fires when the Google Maps API is loaded + */ + 'apiready' + ); + + Ext.applyIf(this,{ + markers: [], + cache: { + marker: [], + polyline: [], + infowindow: [] + } + }); + + Ext.ux.GMapPanel.superclass.initComponent.call(this); + + if (window.google && window.google.maps){ + this.on('afterrender', this.apiReady, this); + }else{ + window.gmapapiready = Ext.Function.bind(this.apiReady,this); + this.buildScriptTag('http://maps.google.com/maps/api/js?sensor=false&callback=gmapapiready'); + } + + }, + apiReady : function(){ + + if (this.rendered){ + + Ext.defer(function(){ + if (this.gmapType === 'map'){ + this.gmap = new google.maps.Map(this.getEl().dom, {zoom:this.zoomLevel,mapTypeId: google.maps.MapTypeId.ROADMAP}); + this.mapDefined = true; + this.mapDefinedGMap = true; + } + + if (this.gmapType === 'panorama'){ + this.gmap = new GStreetviewPanorama(this.getEl().dom); + this.mapDefined = true; + } + + if (!this.mapDefined && this.gmapType){ + this.gmap = new google.maps.Map(this.getEl().dom, {zoom:this.zoomLevel,mapTypeId: google.maps.MapTypeId.ROADMAP}); + this.gmap.setMapTypeId(this.gmapType); + this.mapDefined = true; + this.mapDefinedGMap = true; + } + + google.maps.event.addListenerOnce(this.getMap(), 'tilesloaded', Ext.Function.bind(this.onMapReady, this)); + google.maps.event.addListener(this.getMap(), 'dragend', Ext.Function.bind(this.dragEnd, this)); + + + if (typeof this.setCenter === 'object') { + if (typeof this.setCenter.geoCodeAddr === 'string'){ + this.geoCodeLookup(this.setCenter.geoCodeAddr, this.setCenter.marker, false, true, this.setCenter.listeners); + }else{ + if (this.gmapType === 'map'){ + var point = new google.maps.LatLng(this.setCenter.lat,this.setCenter.lng); + this.getMap().setCenter(point, this.zoomLevel); + this.lastCenter = point; + } + if (typeof this.setCenter.marker === 'object' && typeof point === 'object') { + this.addMarker(point, this.setCenter.marker, this.setCenter.marker.clear); + } + } + if (this.gmapType === 'panorama'){ + this.getMap().setLocationAndPOV(new google.maps.LatLng(this.setCenter.lat,this.setCenter.lng), {yaw: this.yaw, pitch: this.pitch, zoom: this.zoomLevel}); + } + } + }, 200,this); // Ext.defer + + }else{ + this.on('afterrender', this.apiReady, this); + } + }, + // private + afterRender : function(){ + + var wh = this.ownerCt.getSize(); + Ext.applyIf(this, wh); + + Ext.ux.GMapPanel.superclass.afterRender.call(this); + + }, + // private + buildScriptTag: function(filename, callback) { + var script = document.createElement('script'), + head = document.getElementsByTagName("head")[0]; + script.type = "text/javascript"; + script.src = filename; + + return head.appendChild(script); + }, + // private + onMapReady : function(){ + + this.addMapControls(); + this.addOptions(); + + this.addMarkers(this.markers); + this.addMapListeners(); + + this.fireEvent('mapready', this, this.getMap()); + return this; + }, + // private + addMapListeners : function () { + if (this.maplisteners){ + Ext.iterate(this.maplisteners, function(key,val){ + google.maps.event.addListener(this.getMap(), key, Ext.Function.bind(val,this)); + },this); + } + }, + // private + onResize : function(w, h){ + + Ext.ux.GMapPanel.superclass.onResize.call(this, w, h); + + // check for the existance of the google map in case the onResize fires too early + if (typeof this.getMap() == 'object') { + google.maps.event.trigger(this.getMap(), 'resize'); + if (this.lastCenter){ + this.getMap().setCenter(this.lastCenter, this.zoomLevel); + } + } + + }, + // private + setSize : function(width, height, animate){ + + Ext.ux.GMapPanel.superclass.setSize.call(this, width, height, animate); + + // check for the existance of the google map in case setSize is called too early + if (Ext.isObject(this.getMap())) { + google.maps.event.trigger(this.getMap(), 'resize'); + if (this.lastCenter){ + this.getMap().setCenter(this.lastCenter, this.zoomLevel); + } + } + + }, + // private + dragEnd: function(){ + this.lastCenter = this.getMap().getCenter(); + }, + /** + * Returns the current google map which can be used to call Google Maps API specific handlers. + * @return {GMap} this + */ + getMap : function(){ + + return this.gmap; + + }, + /** + * Returns the maps center as a GLatLng object + * @return {GLatLng} this + */ + getCenter : function(){ + + return this.getMap().getCenter(); + + }, + /** + * Returns the maps center as a simple object + * @return {Object} this has lat and lng properties only + */ + getCenterLatLng : function(){ + + var ll = this.getCenter(); + return {lat: ll.lat(), lng: ll.lng()}; + + }, + /** + * Creates markers from the array that is passed in. Each marker must consist of at least + * <code>lat</code> and <code>lng</code> properties or a <code>geoCodeAddr</code>. + * @param {Array} markers an array of marker objects + */ + addMarkers : function(markers) { + if (Ext.isArray(markers)){ + for (var i = 0; i < markers.length; i++) { + if (markers[i]) { + if (typeof markers[i].geoCodeAddr == 'string') { + this.geoCodeLookup(markers[i].geoCodeAddr, markers[i].marker, false, markers[i].setCenter, markers[i].listeners); + } else { + var mkr_point = new google.maps.LatLng(markers[i].lat, markers[i].lng); + this.addMarker(mkr_point, markers[i].marker, false, markers[i].setCenter, markers[i].listeners); + } + } + } + } + + }, + /** + * Creates a single marker. + * @param {Object} point a GLatLng point + * @param {Object} marker a marker object consisting of at least lat and lng + * @param {Boolean} clear clear other markers before creating this marker + * @param {Boolean} center true to center the map on this marker + * @param {Object} listeners a listeners config + */ + addMarker : function(point, marker, clear, center, listeners){ + + Ext.applyIf(marker,{}); + + if (clear === true){ + this.clearMarkers(); + } + if (center === true) { + this.getMap().setCenter(point, this.zoomLevel) + this.lastCenter = point; + } + + var mark = new google.maps.Marker(Ext.apply(marker, { + position: point + })); + + if (marker.infoWindow){ + this.createInfoWindow(marker.infoWindow, point, mark); + } + + this.cache.marker.push(mark); + mark.setMap(this.getMap()); + + if (typeof listeners === 'object'){ + for (evt in listeners) { + google.maps.event.addListener(mark, evt, listeners[evt]); + } + } + + return mark; + + }, + /** + * Creates a single polyline. + * @param {Array} points an array of polyline points + * @param {Object} linestyle an object defining the line style to use + */ + addPolyline : function(points, linestyle){ + + var plinepnts = new google.maps.MVCArray, pline, linestyle = linestyle ? linestyle : { + strokeColor: '#FF0000', + strokeOpacity: 1.0, + strokeWeight: 2 + }; + + Ext.each(points, function(point){ + plinepnts.push(new google.maps.LatLng(point.lat, point.lng)); + }, this); + + var pline = new google.maps.Polyline(Ext.apply({ + path: plinepnts + },linestyle)); + + this.cache.polyline.push(pline); + + pline.setMap(this.getMap()); + + }, + /** + * Creates an Info Window. + * @param {Object} inwin an Info Window configuration + * @param {GLatLng} point the point to show the Info Window at + * @param {GMarker} marker a marker to attach the Info Window to + */ + createInfoWindow : function(inwin, point, marker){ + + var me = this, infoWindow = new google.maps.InfoWindow({ + content: inwin.content, + position: point + }); + + if (marker) { + google.maps.event.addListener(marker, 'click', function(){ + me.hideAllInfoWindows(); + infoWindow.open(me.getMap()); + }); + } + + this.cache.infowindow.push(infoWindow); + + return infoWindow; + + }, + // private + hideAllInfoWindows : function(){ + for (var i = 0; i < this.cache.infowindow.length; i++) { + this.cache.infowindow[i].close(); + } + }, + // private + clearMarkers : function(){ + + this.hideAllInfoWindows(); + this.hideMarkers(); + + }, + // private + hideMarkers : function(){ + Ext.each(this.cache.marker, function(mrk){ + mrk.setMap(null); + }); + }, + // private + showMarkers : function(){ + Ext.each(this.cache.marker, function(mrk){ + mrk.setMap(this.getMap()); + },this); + }, + // private + addMapControls : function(){ + + if (this.gmapType === 'map') { + if (Ext.isArray(this.mapControls)) { + for(i=0;i<this.mapControls.length;i++){ + //this.addMapControl(this.mapControls[i]); + } + }else if(typeof this.mapControls === 'string'){ + //this.addMapControl(this.mapControls); + }else if(typeof this.mapControls === 'object'){ + //this.getMap().add_control(this.mapControls); + } + } + + }, + /** + * Adds a GMap control to the map. + * @param {String} mc a string representation of the control to be instantiated. + */ + addMapControl : function(mc){ + + var mcf = window[mc]; + if (typeof mcf === 'function') { + //this.getMap().addControl(new mcf()); + } + + }, + // private + addOptions : function(){ + + if (Ext.isArray(this.mapConfOpts)) { + var mc; + for(i=0;i<this.mapConfOpts.length;i++){ + //this.addOption(this.mapConfOpts[i]); + } + }else if(typeof this.mapConfOpts === 'string'){ + //this.addOption(this.mapConfOpts); + } + + }, + /** + * Adds a GMap option to the map. + * @param {String} mo a string representation of the option to be instantiated. + */ + addOption : function(mo){ + + var mof = this.getMap()[mo]; + if (typeof mof === 'function') { + this.getMap()[mo](); + } + + }, + /** + * Looks up and address and optionally add a marker, center the map to this location, or + * clear other markers. Sample usage: + * <pre><code> +buttons: [ + { + text: 'Fenway Park', + handler: function(){ + var addr = '4 Yawkey Way, Boston, MA, 02215-3409, USA'; + Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined); + } + },{ + text: 'Zoom Fenway Park', + handler: function(){ + Ext.getCmp('my_map').zoomLevel = 19; + var addr = '4 Yawkey Way, Boston, MA, 02215-3409, USA'; + Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined); + } + },{ + text: 'Low Accuracy', + handler: function(){ + Ext.getCmp('my_map').geoCodeLookup('Paris, France', undefined, false, true, undefined); + } + },{ + + text: 'Bogus Address', + handler: function(){ + var addr = 'Some Fake, Address, For, Errors'; + Ext.getCmp('my_map').geoCodeLookup(addr, undefined, false, true, undefined); + } + } +] + * </code></pre> + * @param {String} addr the address to lookup. + * @param {Object} marker the marker to add (optional). + * @param {Boolean} clear clear other markers before creating this marker + * @param {Boolean} center true to set this point as the center of the map. + * @param {Object} listeners a listeners config + */ + geoCodeLookup : function(addr, marker, clear, center, listeners) { + + if (!this.geocoder) { + this.geocoder = new google.maps.Geocoder(); + } + this.geocoder.geocode({ + address: addr + }, Ext.Function.bind(this.addAddressToMap, this, [addr, marker, clear, center, listeners], true)); + + }, + // private + centerOnClientLocation : function(){ + this.getClientLocation(function(loc){ + var point = new google.maps.LatLng(loc.latitude,loc.longitude); + this.getMap().setCenter(point, this.zoomLevel); + this.lastCenter = point; + }); + }, + // private + getClientLocation : function(fn, errorFn){ + if (!errorFn) { + errorFn = Ext.emptyFn; + } + if (!this.clientGeo) { + this.clientGeo = google.gears.factory.create('beta.geolocation'); + } + geo.getCurrentPosition(Ext.Function.bind(fn, this), errorFn); + }, + // private + addAddressToMap : function(response, status, addr, marker, clear, center, listeners){ + if (!response || status !== 'OK') { + this.respErrorMsg(status); + }else{ + var place = response[0].geometry.location, + accuracy = this.getLocationTypeInfo(response[0].geometry.location_type,'level'), + reqAccuracy = this.getLocationTypeInfo(this.minGeoAccuracy,'level'); + if (accuracy === 0) { + this.geoErrorMsg(this.geoErrorTitle, this.geoErrorMsgUnable); + }else{ + if (accuracy < reqAccuracy) { + this.geoErrorMsg(this.geoErrorTitle, Ext.String.format(this.geoErrorMsgAccuracy, response[0].geometry.location_type, this.getLocationTypeInfo(response[0].geometry.location_type,'msg'))); + }else{ + point = new google.maps.LatLng(place.lat(),place.lng()); + if (center){ + this.getMap().setCenter(point, this.zoomLevel); + this.lastCenter = point; + } + if (typeof marker === 'object') { + if (!marker.title){ + marker.title = response.formatted_address; + } + var mkr = this.addMarker(point, marker, clear, false, listeners); + if (marker.callback){ + marker.callback.call(this, mkr, point); + } + } + } + } + } + + }, + // private + geoErrorMsg : function(title,msg){ + if (this.displayGeoErrors) { + Ext.MessageBox.alert(title,msg); + } + }, + // private + respErrorMsg : function(code){ + Ext.each(this.respErrors, function(obj){ + if (code == obj.code){ + Ext.MessageBox.alert(this.respErrorTitle, obj.msg); + } + }, this); + }, + // private + getLocationTypeInfo: function(location_type,property){ + var val = 0; + Ext.each(this.locationTypes, function(itm){ + if (itm.code === location_type){ + val = itm[property]; + } + }); + return val; + } +}); +</script> + +<script type="text/javascript"> +Ext.onReady(function() { + + Ext.define('Device', { + extend: 'Ext.data.Model', + fields: [ + {name: 'id', type: 'int'}, + {name: 'imei',type: 'string'} + ] + }); + + Ext.define('Position', { + extend: 'Ext.data.Model', + fields: [ + {name: 'device_id', type: 'int'}, + {name: 'time', type: 'date'}, + {name: 'valid', type: 'boolean'}, + {name: 'latitude', type: 'float'}, + {name: 'longitude', type: 'float'}, + {name: 'speed', type: 'float'}, + {name: 'course', type: 'float'}, + {name: 'power', type: 'float'} + ] + }); + + var devicesUrl = 'devices.json'; + var positionsUrl = 'positions.json'; + + var devices = Ext.create('Ext.data.Store', { + id: 'devices', + model: 'Device', + fields: ['id', 'imei'], + autoSync: true, + proxy: { + type: 'ajax', + api: { + create: devicesUrl + '?action=create', + read: devicesUrl, + update: devicesUrl + '?action=update', + destroy: devicesUrl + '?action=destroy' + }, + reader: { + type: 'json', + root: 'results' + } + } + }); + + var positions = Ext.create('Ext.data.Store', { + id: 'positions', + model: 'Position', + fields: [ + 'device_id', + 'time', + 'valid', + 'latitude', + 'longitude', + 'speed', + 'course', + 'power' + ], + proxy: { + type: 'ajax', + url: positionsUrl, + reader: { + type: 'json', + root: 'results' + } + } + }); + + var map = Ext.create('Ext.ux.GMapPanel', { + id: 'gmap', + setCenter: {lat: 0, lng: 0} + }); + + var devicesPanel = Ext.create('Ext.grid.Panel', { + title: 'Devices', + region: 'west', + split: true, + width: 300, + margins: {top: 5, bottom: 0, right: 0, left: 5}, + + sortableColumns: false, + enableColumnHide: false, + + store: devices, + tbar: [ + { + id: 'device_update', + text: 'Update', + handler : function() { + devices.load(); + } + }, + { + id: 'device_add', + text: 'Add', + handler : function() { + Ext.Msg.prompt('Add', 'Device IMEI:', function(btn, text) { + if (btn == 'ok') { + devices.add({imei: text}); + } + }); + } + }, + { + id: 'device_remove', + text: 'Remove', + disabled: true, + handler : function() { + Ext.Msg.confirm('Remove', 'Are you sure to remove item?', function(btn) { + if (btn == 'yes') { + devices.remove(devicesPanel.getSelectionModel().getLastSelected()); + } + }); + } + }, + { + id: 'device_edit', + text: 'Edit', + disabled: true, + handler : function() { + Ext.Msg.prompt('Edit', 'Device IMEI:', function(btn, text) { + if (btn == 'ok') { + devicesPanel.getSelectionModel().getLastSelected().set('imei', text); + } + }, this, false, devicesPanel.getSelectionModel().getLastSelected().get('imei')); + } + } + ], + columns: [ + {header: 'Id', dataIndex: 'id'}, + {header: 'IMEI', dataIndex: 'imei', flex: 1} + ], + listeners: { + selectionchange: function(sender, selected, eOpts) { + if (selected.length != 0) { + Ext.getCmp('device_remove').enable(); + Ext.getCmp('device_edit').enable(); + + positions.getProxy().url = positionsUrl + '?deviceId=' + + devicesPanel.getSelectionModel().getLastSelected().get('id'); + positions.load(); + Ext.getCmp('position_update').enable(); + } else { + Ext.getCmp('position_update').disable(); + positions.getProxy().url = positionsUrl; + positions.load(); + + Ext.getCmp('device_edit').disable(); + Ext.getCmp('device_remove').disable(); + } + } + } + }); + + var positionsPanel = Ext.create('Ext.grid.Panel', { + title: 'Positions', + region: 'south', + split: true, + height: 300, + margins: {top: 0, bottom: 5, right: 5, left: 5}, + + sortableColumns: false, + enableColumnHide: false, + + store: positions, + tbar: [ + { + id: 'position_update', + text: 'Update', + disabled: true, + handler : function() { + positions.load(); + } + } + ], + columns: [ + {header: 'Device Id', dataIndex: 'device_id'}, + { + header: 'Time', + dataIndex: 'time', + flex: 1, + renderer: Ext.util.Format.dateRenderer('Y-m-d H:i:s') + }, + {header: 'Valid', dataIndex: 'valid'}, + {header: 'Latitude', dataIndex: 'latitude'}, + {header: 'Longitude', dataIndex: 'longitude'}, + {header: 'Speed', dataIndex: 'speed'}, + {header: 'Course', dataIndex: 'course'}, + {header: 'Power', dataIndex: 'power'} + ], + listeners: { + selectionchange: function(sender, selected, eOpts) { + if (selected.length != 0) { + var lat = positionsPanel.getSelectionModel().getLastSelected().get('latitude'); + var lng = positionsPanel.getSelectionModel().getLastSelected().get('longitude'); + var point = new google.maps.LatLng(lat, lng); + map.addMarker(point, {lat: lat, lng: lng}, true, true); + } else { + map.clearMarkers(); // private? + } + } + } + }); + + var mapPanel = Ext.create('Ext.panel.Panel', { + title: 'Map', + region: 'center', + margins: {top: 5, bottom: 0, right: 5, left: 0}, + + layout: 'fit', + items: [map] + }); + + Ext.create('Ext.container.Viewport', { + renderTo: Ext.getBody(), + layout: 'border', + items: [devicesPanel, positionsPanel, mapPanel] + }); + + devices.load(); +}); +</script> +</head> +<body></body> +</html> -- cgit v1.2.3