From 534a0107dccd91556252ca927852476628465a4d Mon Sep 17 00:00:00 2001
From: Anton Tananaev <anton.tananaev@gmail.com>
Date: Fri, 18 Jan 2013 23:02:18 +1300
Subject: Add Megatek protocol (fix #112)

---
 src/org/traccar/ServerManager.java                 |  17 ++
 .../traccar/protocol/MegastekProtocolDecoder.java  | 182 +++++++++++++++++++++
 2 files changed, 199 insertions(+)
 create mode 100644 src/org/traccar/protocol/MegastekProtocolDecoder.java

(limited to 'src/org/traccar')

diff --git a/src/org/traccar/ServerManager.java b/src/org/traccar/ServerManager.java
index 23b067712..2fb9f3f6b 100644
--- a/src/org/traccar/ServerManager.java
+++ b/src/org/traccar/ServerManager.java
@@ -127,6 +127,7 @@ public class ServerManager {
         initSkypatrolServer("skypatrol");
         initGt02Server("gt02");
         initGt06Server("gt06");
+        initMegastekServer("megastek");
 
         // Initialize web server
         if (Boolean.valueOf(properties.getProperty("http.enable"))) {
@@ -574,4 +575,20 @@ public class ServerManager {
         }
     }
 
+    private void initMegastekServer(String protocol) throws SQLException {
+        if (isProtocolEnabled(properties, protocol)) {
+            serverList.add(new TrackerServer(this, new ServerBootstrap(), protocol) {
+                @Override
+                protected void addSpecificHandlers(ChannelPipeline pipeline) {
+                    byte delimiter[] = { (byte) '\r', (byte) '\n' };
+                    pipeline.addLast("frameDecoder",
+                            new DelimiterBasedFrameDecoder(1024, ChannelBuffers.wrappedBuffer(delimiter)));
+                    pipeline.addLast("stringDecoder", new StringDecoder());
+                    pipeline.addLast("stringEncoder", new StringEncoder());
+                    pipeline.addLast("objectDecoder", new MegastekProtocolDecoder(ServerManager.this));
+                }
+            });
+        }
+    }
+
 }
diff --git a/src/org/traccar/protocol/MegastekProtocolDecoder.java b/src/org/traccar/protocol/MegastekProtocolDecoder.java
new file mode 100644
index 000000000..77d24837a
--- /dev/null
+++ b/src/org/traccar/protocol/MegastekProtocolDecoder.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2013 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.protocol;
+
+import java.util.Calendar;
+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.BaseProtocolDecoder;
+import org.traccar.ServerManager;
+import org.traccar.helper.Log;
+import org.traccar.model.Position;
+
+public class MegastekProtocolDecoder extends BaseProtocolDecoder {
+
+    public MegastekProtocolDecoder(ServerManager serverManager) {
+        super(serverManager);
+    }
+
+    //STX,102110830074542,$GPRMC,114229.000,A,2238.2024,N,11401.9619,E,0.00,0.00,310811,,,A*64
+    //,F,LowBattery,imei:012207005553885,03,113.1,Battery=24%,,1,460,01,2531,647E;57
+    static private Pattern pattern = Pattern.compile(
+            "STX," +
+            "\\d+," +                      // Identifier (not IMEI)
+            "\\$GPRMC," +
+            "(\\d{2})(\\d{2})(\\d{2})\\.\\d+," + // Time (HHMMSS.SSS)
+            "([AV])," +                    // Validity
+            "(\\d{2})(\\d{2}\\.\\d+)," +   // Latitude (DDMM.MMMM)
+            "([NS])," +
+            "(\\d{3})(\\d{2}\\.\\d+)," +   // Longitude (DDDMM.MMMM)
+            "([EW])," +
+            "(\\d+\\.\\d{2})?," +          // Speed
+            "(\\d+\\.\\d{2})?," +          // Course
+            "(\\d{2})(\\d{2})(\\d{2})" +   // Date (DDMMYY)
+            "[^\\*]+\\*[0-9a-fA-F]{2}," +  // Checksumm
+            "[FL]," +                      // Flag
+            "([^,]*)," +                   // Alarm
+            "imei:(\\d+)," +               // IMEI
+            "(\\d+)?," +                   // Satellites
+            "(\\d+\\.\\d+)," +             // Altitude
+            "Battery=(\\d+)%,," +          // Battery
+            "(\\d)?," +                    // Charger
+            "(\\d+)," +                    // MCC
+            "(\\d+)," +                    // MNC
+            "([0-9a-fA-F]+,[0-9a-fA-F]+);" + // Location code
+            ".+");                         // Checksumm
+
+    @Override
+    protected Object decode(
+            ChannelHandlerContext ctx, Channel channel, Object msg)
+            throws Exception {
+
+        String sentence = (String) msg;
+
+        // Parse message
+        Matcher parser = pattern.matcher(sentence);
+        if (!parser.matches()) {
+            return null;
+        }
+
+        // Create new position
+        Position position = new Position();
+        StringBuilder extendedInfo = new StringBuilder("<protocol>megastek</protocol>");
+        int index = 1;
+
+        // Time
+        Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+        time.clear();
+        time.set(Calendar.HOUR, Integer.valueOf(parser.group(index++)));
+        time.set(Calendar.MINUTE, Integer.valueOf(parser.group(index++)));
+        time.set(Calendar.SECOND, Integer.valueOf(parser.group(index++)));
+
+        // Validity
+        position.setValid(parser.group(index++).compareTo("A") == 0 ? true : false);
+
+        // Latitude
+        Double latitude = Double.valueOf(parser.group(index++));
+        latitude += Double.valueOf(parser.group(index++)) / 60;
+        if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
+        position.setLatitude(latitude);
+
+        // Longitude
+        Double lonlitude = Double.valueOf(parser.group(index++));
+        lonlitude += Double.valueOf(parser.group(index++)) / 60;
+        if (parser.group(index++).compareTo("W") == 0) lonlitude = -lonlitude;
+        position.setLongitude(lonlitude);
+
+        // Speed
+        String speed = parser.group(index++);
+        if (speed != null) {
+            position.setSpeed(Double.valueOf(speed));
+        } else {
+            position.setSpeed(0.0);
+        }
+
+        // Course
+        String course = parser.group(index++);
+        if (course != null) {
+            position.setCourse(Double.valueOf(course));
+        } else {
+            position.setCourse(0.0);
+        }
+
+        // Date
+        time.set(Calendar.DAY_OF_MONTH, Integer.valueOf(parser.group(index++)));
+        time.set(Calendar.MONTH, Integer.valueOf(parser.group(index++)) - 1);
+        time.set(Calendar.YEAR, 2000 + Integer.valueOf(parser.group(index++)));
+        position.setTime(time.getTime());
+
+        // Alarm
+        extendedInfo.append("<alarm>");
+        extendedInfo.append(parser.group(index++));
+        extendedInfo.append("</alarm>");
+
+        // IMEI
+        String imei = parser.group(index++);
+        try {
+            position.setDeviceId(getDataManager().getDeviceByImei(imei).getId());
+        } catch(Exception error) {
+            Log.warning("Unknown device - " + imei);
+            return null;
+        }
+
+        // Satellites
+        String satellites = parser.group(index++);
+        if (satellites != null) {
+            extendedInfo.append("<satellites>");
+            extendedInfo.append(satellites);
+            extendedInfo.append("</satellites>");
+        }
+
+        // Altitude
+        position.setAltitude(Double.valueOf(parser.group(index++)));
+
+        // Battery
+        position.setPower(Double.valueOf(parser.group(index++)));
+
+        // Charger
+        String charger = parser.group(index++);
+        if (charger != null) {
+            extendedInfo.append("<charger>");
+            extendedInfo.append(Integer.valueOf(charger) == 1);
+            extendedInfo.append("</charger>");
+        }
+
+        // MCC
+        extendedInfo.append("<mcc>");
+        extendedInfo.append(parser.group(index++));
+        extendedInfo.append("</mcc>");
+
+        // MNC
+        extendedInfo.append("<mnc>");
+        extendedInfo.append(parser.group(index++));
+        extendedInfo.append("</mnc>");
+
+        // LAC
+        extendedInfo.append("<lac>");
+        extendedInfo.append(parser.group(index++));
+        extendedInfo.append("</lac>");
+
+        // Extended info
+        position.setExtendedInfo(extendedInfo.toString());
+
+        return position;
+    }
+
+}
-- 
cgit v1.2.3