diff options
author | Anton Tananaev <anton.tananaev@gmail.com> | 2018-05-14 06:27:55 +1200 |
---|---|---|
committer | Anton Tananaev <anton.tananaev@gmail.com> | 2018-05-14 06:27:55 +1200 |
commit | 849cfa52a907666241b58d988c9a3b324ac67ba0 (patch) | |
tree | 5db0d121a75f37d39e05f964d48a3ea9202ff04e | |
parent | 662b774234298c38a38c172d1dcb4668996045ac (diff) | |
download | traccar-server-849cfa52a907666241b58d988c9a3b324ac67ba0.tar.gz traccar-server-849cfa52a907666241b58d988c9a3b324ac67ba0.tar.bz2 traccar-server-849cfa52a907666241b58d988c9a3b324ac67ba0.zip |
Implement Meiligao photo capturing
4 files changed, 98 insertions, 51 deletions
diff --git a/src/org/traccar/protocol/MeiligaoProtocol.java b/src/org/traccar/protocol/MeiligaoProtocol.java index dbdd2619a..c72262017 100644 --- a/src/org/traccar/protocol/MeiligaoProtocol.java +++ b/src/org/traccar/protocol/MeiligaoProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ public class MeiligaoProtocol extends BaseProtocol { Command.TYPE_ENGINE_RESUME, Command.TYPE_ALARM_GEOFENCE, Command.TYPE_SET_TIMEZONE, + Command.TYPE_REQUEST_PHOTO, Command.TYPE_REBOOT_DEVICE); } diff --git a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java index 9f7b8abf7..7ae98b46d 100644 --- a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java +++ b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,12 +30,16 @@ import org.traccar.model.Position; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.regex.Pattern; public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { + private Map<Byte, ChannelBuffer> photos = new HashMap<>(); + public MeiligaoProtocolDecoder(MeiligaoProtocol protocol) { super(protocol); } @@ -135,6 +139,19 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { public static final int MSG_OBD_RT = 0x9901; public static final int MSG_OBD_RTA = 0x9902; + public static final int MSG_TRACK_ON_DEMAND = 0x4101; + public static final int MSG_TRACK_BY_INTERVAL = 0x4102; + public static final int MSG_MOVEMENT_ALARM = 0x4106; + public static final int MSG_OUTPUT_CONTROL = 0x4115; + public static final int MSG_TIME_ZONE = 0x4132; + public static final int MSG_TAKE_PHOTO = 0x4151; + public static final int MSG_UPLOAD_PHOTO = 0x0800; + public static final int MSG_UPLOAD_PHOTO_RESPONSE = 0x8801; + public static final int MSG_DATA_PHOTO = 0x9988; + public static final int MSG_POSITION_IMAGE = 0x9977; + public static final int MSG_UPLOAD_COMPLETE = 0x0f80; + public static final int MSG_REBOOT_GPS = 0x4902; + private DeviceSession identify(ChannelBuffer buf, Channel channel, SocketAddress remoteAddress) { StringBuilder builder = new StringBuilder(); @@ -188,7 +205,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { private String getServer(Channel channel) { String server = Context.getConfig().getString(getProtocolName() + ".server"); - if (server == null) { + if (server == null && channel != null) { InetSocketAddress address = (InetSocketAddress) channel.getLocalAddress(); server = address.getAddress().getHostAddress() + ":" + address.getPort(); } @@ -375,20 +392,29 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { int command = buf.readUnsignedShort(); ChannelBuffer response; - if (channel != null) { - if (command == MSG_LOGIN) { - response = ChannelBuffers.wrappedBuffer(new byte[]{0x01}); - sendResponse(channel, remoteAddress, id, MSG_LOGIN_RESPONSE, response); - return null; - } else if (command == MSG_HEARTBEAT) { - response = ChannelBuffers.wrappedBuffer(new byte[]{0x01}); - sendResponse(channel, remoteAddress, id, MSG_HEARTBEAT, response); - return null; - } else if (command == MSG_SERVER) { - response = ChannelBuffers.copiedBuffer(getServer(channel), StandardCharsets.US_ASCII); - sendResponse(channel, remoteAddress, id, MSG_SERVER, response); - return null; - } + if (command == MSG_LOGIN) { + response = ChannelBuffers.wrappedBuffer(new byte[]{0x01}); + sendResponse(channel, remoteAddress, id, MSG_LOGIN_RESPONSE, response); + return null; + } else if (command == MSG_HEARTBEAT) { + response = ChannelBuffers.wrappedBuffer(new byte[]{0x01}); + sendResponse(channel, remoteAddress, id, MSG_HEARTBEAT, response); + return null; + } else if (command == MSG_SERVER) { + response = ChannelBuffers.copiedBuffer(getServer(channel), StandardCharsets.US_ASCII); + sendResponse(channel, remoteAddress, id, MSG_SERVER, response); + return null; + } else if (command == MSG_UPLOAD_PHOTO) { + byte imageIndex = buf.readByte(); + photos.put(imageIndex, ChannelBuffers.dynamicBuffer()); + response = ChannelBuffers.copiedBuffer(new byte[]{imageIndex}); + sendResponse(channel, remoteAddress, id, MSG_UPLOAD_PHOTO_RESPONSE, response); + return null; + } else if (command == MSG_UPLOAD_COMPLETE) { + byte imageIndex = buf.readByte(); + response = ChannelBuffers.copiedBuffer(new byte[]{imageIndex, 0, 0}); + sendResponse(channel, remoteAddress, id, MSG_RETRANSMISSION, response); + return null; } DeviceSession deviceSession = identify(id, channel, remoteAddress); @@ -396,7 +422,18 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { return null; } - if (command == MSG_RETRANSMISSION) { + if (command == MSG_DATA_PHOTO) { + + byte imageIndex = buf.readByte(); + buf.readUnsignedShort(); // image footage + buf.readUnsignedByte(); // total packets + buf.readUnsignedByte(); // packet index + + photos.get(imageIndex).writeBytes(buf, buf.readableBytes() - 2 - 2); + + return null; + + } else if (command == MSG_RETRANSMISSION) { return decodeRetransmission(buf, deviceSession); @@ -404,6 +441,8 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + if (command == MSG_ALARM) { short alarmCode = buf.readUnsignedByte(); position.set(Position.KEY_ALARM, decodeAlarm(alarmCode)); @@ -414,11 +453,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { } } else if (command == MSG_POSITION_LOGGED) { buf.skipBytes(6); - } - - position.setDeviceId(deviceSession.getDeviceId()); - - if (command == MSG_RFID) { + } else if (command == MSG_RFID) { for (int i = 0; i < 15; i++) { long rfid = buf.readUnsignedInt(); if (rfid != 0) { @@ -427,23 +462,33 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_DRIVER_UNIQUE_ID, card); } } + } else if (command == MSG_POSITION_IMAGE) { + byte imageIndex = buf.readByte(); + buf.readUnsignedByte(); // image upload type + String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId(); + String file = Context.getMediaManager().writeFile(uniqueId, photos.remove(imageIndex), "jpg"); + position.set(Position.KEY_IMAGE, file); } String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 4, StandardCharsets.US_ASCII); - if (command == MSG_POSITION || command == MSG_POSITION_LOGGED || command == MSG_ALARM) { - return decodeRegular(position, sentence); - } else if (command == MSG_RFID) { - return decodeRfid(position, sentence); - } else if (command == MSG_OBD_RT) { - return decodeObd(position, sentence); - } else if (command == MSG_OBD_RTA) { - return decodeObdA(position, sentence); + switch (command) { + case MSG_POSITION: + case MSG_POSITION_LOGGED: + case MSG_ALARM: + case MSG_POSITION_IMAGE: + return decodeRegular(position, sentence); + case MSG_RFID: + return decodeRfid(position, sentence); + case MSG_OBD_RT: + return decodeObd(position, sentence); + case MSG_OBD_RTA: + return decodeObdA(position, sentence); + default: + return null; } } - - return null; } } diff --git a/src/org/traccar/protocol/MeiligaoProtocolEncoder.java b/src/org/traccar/protocol/MeiligaoProtocolEncoder.java index 340d947e3..1b444e90a 100644 --- a/src/org/traccar/protocol/MeiligaoProtocolEncoder.java +++ b/src/org/traccar/protocol/MeiligaoProtocolEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,13 +28,6 @@ import java.util.TimeZone; public class MeiligaoProtocolEncoder extends BaseProtocolEncoder { - public static final int MSG_TRACK_ON_DEMAND = 0x4101; - public static final int MSG_TRACK_BY_INTERVAL = 0x4102; - public static final int MSG_MOVEMENT_ALARM = 0x4106; - public static final int MSG_OUTPUT_CONTROL = 0x4115; - public static final int MSG_TIME_ZONE = 0x4132; - public static final int MSG_REBOOT_GPS = 0x4902; - private ChannelBuffer encodeContent(long deviceId, int type, ChannelBuffer content) { ChannelBuffer buf = ChannelBuffers.dynamicBuffer(); @@ -65,25 +58,27 @@ public class MeiligaoProtocolEncoder extends BaseProtocolEncoder { switch (command.getType()) { case Command.TYPE_POSITION_SINGLE: - return encodeContent(command.getDeviceId(), MSG_TRACK_ON_DEMAND, content); + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_TRACK_ON_DEMAND, content); case Command.TYPE_POSITION_PERIODIC: content.writeShort(command.getInteger(Command.KEY_FREQUENCY) / 10); - return encodeContent(command.getDeviceId(), MSG_TRACK_BY_INTERVAL, content); + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_TRACK_BY_INTERVAL, content); case Command.TYPE_ENGINE_STOP: content.writeByte(0x01); - return encodeContent(command.getDeviceId(), MSG_OUTPUT_CONTROL, content); + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL, content); case Command.TYPE_ENGINE_RESUME: content.writeByte(0x00); - return encodeContent(command.getDeviceId(), MSG_OUTPUT_CONTROL, content); + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL, content); case Command.TYPE_ALARM_GEOFENCE: content.writeShort(command.getInteger(Command.KEY_RADIUS)); - return encodeContent(command.getDeviceId(), MSG_MOVEMENT_ALARM, content); + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_MOVEMENT_ALARM, content); case Command.TYPE_SET_TIMEZONE: int offset = TimeZone.getTimeZone(command.getString(Command.KEY_TIMEZONE)).getRawOffset() / 60000; content.writeBytes(String.valueOf(offset).getBytes(StandardCharsets.US_ASCII)); - return encodeContent(command.getDeviceId(), MSG_TIME_ZONE, content); + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_TIME_ZONE, content); + case Command.TYPE_REQUEST_PHOTO: + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_TAKE_PHOTO, content); case Command.TYPE_REBOOT_DEVICE: - return encodeContent(command.getDeviceId(), MSG_REBOOT_GPS, content); + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_REBOOT_GPS, content); default: Log.warning(new UnsupportedOperationException(command.getType())); break; diff --git a/test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java b/test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java index 41d02ae31..893b94653 100644 --- a/test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java +++ b/test/org/traccar/protocol/MeiligaoProtocolDecoderTest.java @@ -10,6 +10,15 @@ public class MeiligaoProtocolDecoderTest extends ProtocolTest { MeiligaoProtocolDecoder decoder = new MeiligaoProtocolDecoder(new MeiligaoProtocol()); + verifyNull(decoder, binary( + "24240012254748594772ff080002ffff0d0a")); + + verifyNull(decoder, binary( + "242403fe254748594772ff99880242681100ffd8ffe000104a46494600010101000000000000ffdb004300080606070605080707070909080a0c140d0c0b0b0c1912130f141d1a1f1e1d1a1c1c20242e2720222c231c1c2837292c30313434341f27393d38323c2e333432ffdb0043010909090c0b0c180d0d1832211c213232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffc000110801e0028003012100021101031101ffda000c03010002110311003f00f0cc679a5a977d84b517d69474a98f615930e3a52edabea50b8a5c54c9e84c9f4178a5c7b50ad617bbd45a5c00287b16d681f852f5eb44aefde32e5bbb0ec0a38eb4d36d9a48753f150f4d5916f74318a70ad5dd8dc75168ed53ccadee8e239452f434afd10921719a7639aad56854ac3c0a5a98cfc8971d6c85a7f6a65ad07e29f8a1b10fc52ff153f405a6e48053f145f4b31abc5928e9cd4cabd3152f4d01ab6a4ca2a50a33509d9d809d56a50b56a7a87c24cbd6a655a2510ea4aa2a555a953b30255a92a80945498a435b8f1520a3d043b14e02974d40752d37a20490b4b40076a2a760129298094949e8030d368527b8c6530d4ddc84861a6353b8119a69e94b402334ca6e5a0861eb4c22b3d876184530d56e85623c506b27cd719e494bdabadab6a2d43e945227588a7d29739e69d92dc7d4703476cd569612d472b6452d4fbb61d828c734d6eac263fb52d539caf7634c55f6a2a1b8885a78e949db94528bd90539714dbea69bea2e7d29d9c51b19db4b053c75abffff0d0a")); + + verifyPosition(decoder, binary( + "242400716578902405843299553136323533332e3937382c412c343632332e313137392c4e2c30373932342e323437312c572c303030302c3030302c3139313231372c2c2a31437c31312e357c3139347c303030307c313139322c303030307c3835383030307c30303331343809540d0a")); + verifyPosition(decoder, binary( "242400716578902405843299553136323533332e3937382c412c343632332e313137392c4e2c30373932342e323437312c572c303030302c3030302c3139313231372c2c2a31437c31312e357c3139347c303030307c313139322c303030307c3835383030307c30303331343809540d0a")); @@ -66,9 +75,6 @@ public class MeiligaoProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "24240000123456FFFFFFFF50008B9B0D0A")); - verifyNull(decoder, binary( - "24240011300600000046090002849a0d0a")); - verifyPosition(decoder, binary( "242400722015032700004299553134313131352e3030302c412c353031312e343335342c4e2c30303834332e373039322c452c3030302e302c3034342e362c3134303431352c2c2c412a36437c322e317c39392e347c303030307c303030302c303030307c3030303032343730350e480d0a")); |