diff options
author | Anton Tananaev <anton.tananaev@gmail.com> | 2019-02-10 13:49:44 -0800 |
---|---|---|
committer | Anton Tananaev <anton.tananaev@gmail.com> | 2019-02-10 13:49:44 -0800 |
commit | 3d2a3ee8ccf6f0989a149eec74b3d69d42963756 (patch) | |
tree | c7cc153246b818c2b672482a7f5cb988ee29e311 | |
parent | a50b9a890aaf5a1388f84449cc2978d55328e874 (diff) | |
download | trackermap-server-3d2a3ee8ccf6f0989a149eec74b3d69d42963756.tar.gz trackermap-server-3d2a3ee8ccf6f0989a149eec74b3d69d42963756.tar.bz2 trackermap-server-3d2a3ee8ccf6f0989a149eec74b3d69d42963756.zip |
Support camera for Teltonika
-rw-r--r-- | src/org/traccar/protocol/TeltonikaProtocolDecoder.java | 85 | ||||
-rw-r--r-- | test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java | 20 |
2 files changed, 96 insertions, 9 deletions
diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java index f69059104..0e1fd6280 100644 --- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2019 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. @@ -25,6 +25,7 @@ import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; import org.traccar.helper.UnitsConverter; import org.traccar.model.CellTower; import org.traccar.model.Network; @@ -33,13 +34,18 @@ import org.traccar.model.Position; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.Date; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { + private static final int IMAGE_PACKET_MAX = 2048; + private boolean connectionless; private boolean extended; + private Map<Long, ByteBuf> photos = new HashMap<>(); public void setExtended(boolean extended) { this.extended = extended; @@ -51,7 +57,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { this.extended = Context.getConfig().getBoolean(getProtocolName() + ".extended"); } - private DeviceSession parseIdentification(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + private void parseIdentification(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { int length = buf.readUnsignedShort(); String imei = buf.toString(buf.readerIndex(), length, StandardCharsets.US_ASCII); @@ -66,7 +72,6 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } - return deviceSession; } public static final int CODEC_GH3000 = 0x07; @@ -75,14 +80,74 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { public static final int CODEC_12 = 0x0C; public static final int CODEC_16 = 0x10; - private void decodeSerial(Position position, ByteBuf buf) { + private void sendImageRequest(Channel channel, SocketAddress remoteAddress, long id, int offset, int size) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeInt(0); + response.writeShort(0); + response.writeShort(19); // length + response.writeByte(CODEC_12); + response.writeByte(1); // nod + response.writeByte(0x0D); // camera + response.writeInt(11); // payload length + response.writeByte(2); // command + response.writeInt((int) id); + response.writeInt(offset); + response.writeShort(size); + response.writeByte(1); // nod + response.writeShort(0); + response.writeShort(Checksum.crc16( + Checksum.CRC16_IBM, response.nioBuffer(8, response.readableBytes() - 8))); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private void decodeSerial(Channel channel, SocketAddress remoteAddress, Position position, ByteBuf buf) { getLastLocation(position, null); - position.set(Position.KEY_TYPE, buf.readUnsignedByte()); + int type = buf.readUnsignedByte(); + if (type == 0x0D) { + + buf.readInt(); // length + int subtype = buf.readUnsignedByte(); + if (subtype == 0x01) { + + long photoId = buf.readUnsignedInt(); + ByteBuf photo = Unpooled.buffer(buf.readInt()); + photos.put(photoId, photo); + sendImageRequest( + channel, remoteAddress, photoId, + 0, Math.min(IMAGE_PACKET_MAX, photo.capacity())); + + } else if (subtype == 0x02) { + + long photoId = buf.readUnsignedInt(); + buf.readInt(); // offset + ByteBuf photo = photos.get(photoId); + photo.writeBytes(buf, buf.readUnsignedShort()); + if (photo.writableBytes() > 0) { + sendImageRequest( + channel, remoteAddress, photoId, + photo.writerIndex(), Math.min(IMAGE_PACKET_MAX, photo.writableBytes())); + } else { + String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId(); + photos.remove(photoId); + try { + position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg")); + } finally { + photo.release(); + } + } + + } - position.set(Position.KEY_RESULT, buf.readSlice(buf.readInt()).toString(StandardCharsets.US_ASCII)); + } else { + position.set(Position.KEY_TYPE, type); + position.set(Position.KEY_RESULT, buf.readSlice(buf.readInt()).toString(StandardCharsets.US_ASCII)); + + } } private long readValue(ByteBuf buf, int length, boolean signed) { @@ -462,12 +527,14 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { position.setValid(true); if (codec == CODEC_12) { - decodeSerial(position, buf); + decodeSerial(channel, remoteAddress, position, buf); } else { decodeLocation(position, buf, codec); } - positions.add(position); + if (!position.getOutdated() || !position.getAttributes().isEmpty()) { + positions.add(position); + } } if (channel != null) { @@ -486,7 +553,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } } - return positions; + return positions.isEmpty() ? null : positions; } @Override diff --git a/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java index 6450a8591..37dc21f55 100644 --- a/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java +++ b/test/org/traccar/protocol/TeltonikaProtocolDecoderTest.java @@ -96,6 +96,26 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest { } + + @Test + public void testDecodePhoto() throws Exception { + + TeltonikaProtocolDecoder decoder = new TeltonikaProtocolDecoder(null, false); + + verifyNull(decoder, binary( + "000F313233343536373839303132333435")); + + verifyNull(decoder, binary( + "00000000000000090c010D00000001000100000CD8")); + + verifyNull(decoder, binary( + "000000000000000D0c010D0000000501598493ED01000018B2")); + + verifyNull(decoder, binary( + "00000000000008130c010d0000080b02598493ED000000000800ffd8ffe000104a46494600010201006000600000ffdb0084000202020202020202020202020202020403020202020504040304060506060605060606070908060709070606080b08090a0a0a0a0a06080b0c0b0a0c090a0a0a01020202020202050303050a0706070a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0affc401a20000010501010101010100000000000000000102030405060708090a0b0100030101010101010101010000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffc000110801e002d003012200021101031101ffdd00040054ffda000c03010002110311003f00fc918d555b0c0007a8cd4e3054a8c807a64540a32d900f07e626ac2fce0f4014718ae652ba68e87ef222238da4f20f415226d00823a838045210149cf24fbd30305c31391cf18a52574269ad2c49b9be518c60d4dbb0194003232323b542092509e840c0a9304120e4827068924e5a8db761a0971b402011c1229ea02608f5ebeb4a09fba00001eb520552a001c83d09a1493d1149a48455009dc4020f029f210a98079a52a32a091b8f24d23042c41c93fc38a517a89b6f61b19dc371c923a1a9631f2b8639c1e326a280124ae0804fe55232153819c93924d17698452488c079380792dc1c5491a80e10825327f3a7b60052a36e4f069e9d77b1c053d4d24d3634aeee3769f31890060f03da9f364c6029cee5e09a7125db790013d69a49200000eb4ecbd0a5749d86a10ab1a827716c64d3d57639181ce4e29c880216246e43c12296360e0c8c4865e9c76a7169bb762534da18b1b3fdfc003a0a951004236e5b77ca49a8959c48a013f33723daa74604c84f0a0e011d8d36d27a83936c67987718c819cf20fa54ae018f6648048c0c74a810b1901009603a9ed53005958900943920f7a9d131deeb41854064519c01c934e000914124865e49a7901ca903af63da918a96418c91c311495a49836e438f240ebb4fcbf4a7a16219828000232691f3953c023a01446e49008da83ef0f5a6acb71249a41b4642331e0f5a7b8023193f311c81e94e5da496750016ea476a64b2050495279f9463b51aa2ac86a200c1412081c9a9810d2384206178c1a8d010a1ca92d8fc853e37551900167079a4db6ef70bc799362f963682c3073dfbd2e49508848e7e6a79264894e3033900543138569093b8b82001d8d5dd2d985d262801880bcaaf1c1ef52b92c91c600c27041f4a6292acaa9c0c724fad293f3161938eb93509b6f713695d844586e00e060e38a72260b9e8aab9247a546a30c40242b8e07a54b9fbca092ae3814ee9ec4ab45a60c140c81b8b918149b0b2ba3120eee707a5354b052554e54f04f6a7a9561b413bcb0249345d25a17a5ee3c81e5a804860723029502bec2fdb8201ea69db39c90403f74fb5359580057ef6780294527aafe98ad1487ae017278dab900d47390c8072188f978ef52e0b48c41fbc3048a6381bd41390a791449a6c4af263f0ab124472485cb0f53532c8137a6727193c77a81582caace7200e38a7be7cc9b6a819192cc78a77567b84795a240ac0463000232e734b127254fde4078a7021d22232d82371f4a69251caa900b3e4367b526928bbf512516eec91103204271d720fd6a605427cbc04e066aaa615d482483d81ef53306024503049c939e94dd96a55d5c6c6518b316e431c71d6a78c99033138c1f947ad5451f3aae7193f301eb5ad02a44c430071cb023a524d3d413e87b0e829245f0f3c73242e229e4f095e209ca062a1e278fa3023a39edeb5f13ce144ae01dc3770718afb5bc3e88fe0bf1c1b8252de4f09de9322a92630b113b801d4fe07815f155cb0695982ed19e00aceed55934fa47ff6ef989abc48c0cf23800f5cd3d4f24e38238a8949c00304e79a901e7a678a1b5ad898b492255c024824e48e2a55272307041a8548c01d077352a9c923ae2a559bd4a6d264c0e060f04f7a9800001ebd6a01b7007383d2a75008039a4d3be80f995c82f0916f290707674f5aa5e1c19b9949e3e4e3f3ab97b9fb34a31c05e9557c3a019a50724003b576615e8ccab5940ee62c123af5e302aeaf0463a8355225276e3a0ee2ad82474e83b115d8d7bda9cea4921aec76b678c83d6a9d9f319c1c658f22adc9cab6464e0e00aab60018723b93835c59838ac3dcebc124f106cdaa8dcbcf39afa13e0fc65b5e848c83b3e519ef91fe35f3f5a801973d8f15f48fc148fcdf10da2f003ca8a491dcbafaf7e2be2f3549e1a4bb9f474928c6ecfdd5d1a309a7d928fe1b68c0c7fbb5d1c28db01c77ac7d3d156de054185f2d76fd315d25a85d801e7938cd7d2609bf6d7f53e66ac7f77a010000b7cd")); + + } + @Ignore @Test public void testDecodeConnectionless() throws Exception { |