From 59416923dcb3a756eaf532cc4259f2f6625c0762 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 31 Mar 2019 22:35:39 -0700 Subject: Convert project to gradle --- src/main/java/org/traccar/BaseDataHandler.java | 38 + src/main/java/org/traccar/BaseFrameDecoder.java | 37 + .../java/org/traccar/BaseHttpProtocolDecoder.java | 39 + src/main/java/org/traccar/BasePipelineFactory.java | 169 +++ src/main/java/org/traccar/BaseProtocol.java | 131 ++ src/main/java/org/traccar/BaseProtocolDecoder.java | 255 ++++ src/main/java/org/traccar/BaseProtocolEncoder.java | 85 ++ .../traccar/CharacterDelimiterFrameDecoder.java | 65 + src/main/java/org/traccar/Context.java | 410 +++++++ src/main/java/org/traccar/DeviceSession.java | 42 + .../java/org/traccar/EventLoopGroupFactory.java | 37 + .../java/org/traccar/ExtendedObjectDecoder.java | 82 ++ src/main/java/org/traccar/GlobalTimer.java | 42 + src/main/java/org/traccar/Main.java | 156 +++ src/main/java/org/traccar/MainEventHandler.java | 161 +++ src/main/java/org/traccar/MainModule.java | 373 ++++++ src/main/java/org/traccar/NetworkMessage.java | 38 + src/main/java/org/traccar/PipelineBuilder.java | 24 + src/main/java/org/traccar/Protocol.java | 37 + src/main/java/org/traccar/ServerManager.java | 103 ++ .../java/org/traccar/StringProtocolEncoder.java | 51 + src/main/java/org/traccar/TrackerServer.java | 115 ++ src/main/java/org/traccar/WebDataHandler.java | 201 ++++ src/main/java/org/traccar/WindowsService.java | 231 ++++ src/main/java/org/traccar/WrapperContext.java | 255 ++++ .../java/org/traccar/WrapperInboundHandler.java | 94 ++ .../java/org/traccar/WrapperOutboundHandler.java | 99 ++ src/main/java/org/traccar/api/AsyncSocket.java | 96 ++ .../java/org/traccar/api/AsyncSocketServlet.java | 46 + .../java/org/traccar/api/BaseObjectResource.java | 176 +++ src/main/java/org/traccar/api/BaseResource.java | 32 + .../java/org/traccar/api/CorsResponseFilter.java | 58 + .../org/traccar/api/ExtendedObjectResource.java | 62 + src/main/java/org/traccar/api/MediaFilter.java | 92 ++ .../java/org/traccar/api/ObjectMapperProvider.java | 32 + .../java/org/traccar/api/ResourceErrorHandler.java | 42 + .../org/traccar/api/SecurityRequestFilter.java | 119 ++ .../java/org/traccar/api/SimpleObjectResource.java | 43 + src/main/java/org/traccar/api/UserPrincipal.java | 37 + .../java/org/traccar/api/UserSecurityContext.java | 49 + .../traccar/api/resource/AttributeResource.java | 97 ++ .../org/traccar/api/resource/CalendarResource.java | 36 + .../org/traccar/api/resource/CommandResource.java | 89 ++ .../org/traccar/api/resource/DeviceResource.java | 100 ++ .../org/traccar/api/resource/DriverResource.java | 36 + .../org/traccar/api/resource/EventResource.java | 38 + .../org/traccar/api/resource/GeofenceResource.java | 35 + .../org/traccar/api/resource/GroupResource.java | 35 + .../traccar/api/resource/MaintenanceResource.java | 36 + .../traccar/api/resource/NotificationResource.java | 76 ++ .../traccar/api/resource/PermissionsResource.java | 84 ++ .../org/traccar/api/resource/PositionResource.java | 96 ++ .../org/traccar/api/resource/ReportResource.java | 210 ++++ .../org/traccar/api/resource/ServerResource.java | 63 + .../org/traccar/api/resource/SessionResource.java | 120 ++ .../traccar/api/resource/StatisticsResource.java | 44 + .../org/traccar/api/resource/UserResource.java | 94 ++ src/main/java/org/traccar/config/Config.java | 166 +++ src/main/java/org/traccar/config/ConfigKey.java | 36 + src/main/java/org/traccar/config/ConfigSuffix.java | 28 + src/main/java/org/traccar/config/Keys.java | 356 ++++++ .../java/org/traccar/database/ActiveDevice.java | 55 + .../org/traccar/database/AttributesManager.java | 36 + .../org/traccar/database/BaseObjectManager.java | 127 ++ .../java/org/traccar/database/CalendarManager.java | 27 + .../java/org/traccar/database/CommandsManager.java | 157 +++ .../org/traccar/database/ConnectionManager.java | 218 ++++ .../java/org/traccar/database/DataManager.java | 478 ++++++++ .../java/org/traccar/database/DeviceManager.java | 419 +++++++ .../java/org/traccar/database/DriversManager.java | 73 ++ .../traccar/database/ExtendedObjectManager.java | 115 ++ .../java/org/traccar/database/GeofenceManager.java | 66 + src/main/java/org/traccar/database/GroupTree.java | 151 +++ .../java/org/traccar/database/GroupsManager.java | 106 ++ .../java/org/traccar/database/IdentityManager.java | 43 + .../java/org/traccar/database/LdapProvider.java | 179 +++ .../java/org/traccar/database/MailManager.java | 147 +++ .../org/traccar/database/MaintenancesManager.java | 27 + .../org/traccar/database/ManagableObjects.java | 27 + .../java/org/traccar/database/MediaManager.java | 72 ++ .../org/traccar/database/NotificationManager.java | 135 +++ .../org/traccar/database/PermissionsManager.java | 459 +++++++ .../java/org/traccar/database/QueryBuilder.java | 519 ++++++++ .../java/org/traccar/database/QueryExtended.java | 27 + .../java/org/traccar/database/QueryIgnore.java | 26 + .../org/traccar/database/SimpleObjectManager.java | 94 ++ .../org/traccar/database/StatisticsManager.java | 160 +++ .../java/org/traccar/database/UsersManager.java | 86 ++ src/main/java/org/traccar/geocoder/Address.java | 110 ++ .../java/org/traccar/geocoder/AddressFormat.java | 82 ++ .../java/org/traccar/geocoder/BanGeocoder.java | 66 + .../org/traccar/geocoder/BingMapsGeocoder.java | 63 + .../java/org/traccar/geocoder/FactualGeocoder.java | 58 + .../org/traccar/geocoder/GeocodeFarmGeocoder.java | 70 ++ .../org/traccar/geocoder/GeocodeXyzGeocoder.java | 60 + src/main/java/org/traccar/geocoder/Geocoder.java | 30 + .../org/traccar/geocoder/GeocoderException.java | 24 + .../org/traccar/geocoder/GisgraphyGeocoder.java | 55 + .../java/org/traccar/geocoder/GoogleGeocoder.java | 98 ++ .../java/org/traccar/geocoder/HereGeocoder.java | 84 ++ .../java/org/traccar/geocoder/JsonGeocoder.java | 121 ++ .../org/traccar/geocoder/MapQuestGeocoder.java | 63 + .../org/traccar/geocoder/MapmyIndiaGeocoder.java | 82 ++ .../org/traccar/geocoder/NominatimGeocoder.java | 91 ++ .../org/traccar/geocoder/OpenCageGeocoder.java | 76 ++ .../java/org/traccar/geofence/GeofenceCircle.java | 98 ++ .../org/traccar/geofence/GeofenceGeometry.java | 50 + .../java/org/traccar/geofence/GeofencePolygon.java | 164 +++ .../org/traccar/geofence/GeofencePolyline.java | 107 ++ .../traccar/geolocation/GeolocationException.java | 24 + .../traccar/geolocation/GeolocationProvider.java | 32 + .../geolocation/GoogleGeolocationProvider.java | 26 + .../geolocation/MozillaGeolocationProvider.java | 26 + .../geolocation/OpenCellIdGeolocationProvider.java | 68 ++ .../geolocation/UniversalGeolocationProvider.java | 58 + .../geolocation/UnwiredGeolocationProvider.java | 111 ++ .../traccar/handler/ComputedAttributesHandler.java | 140 +++ .../org/traccar/handler/CopyAttributesHandler.java | 53 + .../org/traccar/handler/DefaultDataHandler.java | 48 + .../java/org/traccar/handler/DistanceHandler.java | 82 ++ .../org/traccar/handler/EngineHoursHandler.java | 50 + .../java/org/traccar/handler/FilterHandler.java | 206 ++++ .../java/org/traccar/handler/GeocoderHandler.java | 94 ++ .../org/traccar/handler/GeolocationHandler.java | 86 ++ .../org/traccar/handler/HemisphereHandler.java | 60 + .../java/org/traccar/handler/MotionHandler.java | 40 + .../org/traccar/handler/NetworkMessageHandler.java | 57 + .../org/traccar/handler/OpenChannelHandler.java | 42 + .../org/traccar/handler/RemoteAddressHandler.java | 42 + .../traccar/handler/StandardLoggingHandler.java | 81 ++ .../traccar/handler/events/AlertEventHandler.java | 59 + .../traccar/handler/events/BaseEventHandler.java | 38 + .../handler/events/CommandResultEventHandler.java | 39 + .../traccar/handler/events/DriverEventHandler.java | 57 + .../handler/events/FuelDropEventHandler.java | 70 ++ .../handler/events/GeofenceEventHandler.java | 89 ++ .../handler/events/IgnitionEventHandler.java | 65 + .../handler/events/MaintenanceEventHandler.java | 72 ++ .../traccar/handler/events/MotionEventHandler.java | 135 +++ .../handler/events/OverspeedEventHandler.java | 164 +++ src/main/java/org/traccar/helper/BcdUtil.java | 63 + src/main/java/org/traccar/helper/BitBuffer.java | 101 ++ src/main/java/org/traccar/helper/BitUtil.java | 51 + src/main/java/org/traccar/helper/BufferUtil.java | 47 + src/main/java/org/traccar/helper/Checksum.java | 200 ++++ .../java/org/traccar/helper/DataConverter.java | 47 + src/main/java/org/traccar/helper/DateBuilder.java | 126 ++ src/main/java/org/traccar/helper/DateUtil.java | 78 ++ .../org/traccar/helper/DistanceCalculator.java | 53 + src/main/java/org/traccar/helper/Hashing.java | 100 ++ src/main/java/org/traccar/helper/LocationTree.java | 125 ++ src/main/java/org/traccar/helper/Log.java | 265 ++++ src/main/java/org/traccar/helper/LogAction.java | 99 ++ src/main/java/org/traccar/helper/ObdDecoder.java | 105 ++ src/main/java/org/traccar/helper/Parser.java | 348 ++++++ .../java/org/traccar/helper/PatternBuilder.java | 98 ++ src/main/java/org/traccar/helper/PatternUtil.java | 81 ++ .../java/org/traccar/helper/SanitizerModule.java | 45 + .../java/org/traccar/helper/UnitsConverter.java | 88 ++ src/main/java/org/traccar/model/Attribute.java | 61 + src/main/java/org/traccar/model/BaseModel.java | 31 + src/main/java/org/traccar/model/Calendar.java | 82 ++ src/main/java/org/traccar/model/CellTower.java | 115 ++ src/main/java/org/traccar/model/Command.java | 113 ++ src/main/java/org/traccar/model/Device.java | 152 +++ .../java/org/traccar/model/DeviceAccumulators.java | 51 + src/main/java/org/traccar/model/DeviceState.java | 71 ++ src/main/java/org/traccar/model/Driver.java | 40 + src/main/java/org/traccar/model/Event.java | 104 ++ src/main/java/org/traccar/model/ExtendedModel.java | 127 ++ src/main/java/org/traccar/model/Geofence.java | 92 ++ src/main/java/org/traccar/model/Group.java | 30 + src/main/java/org/traccar/model/GroupedModel.java | 31 + src/main/java/org/traccar/model/Maintenance.java | 61 + src/main/java/org/traccar/model/ManagedUser.java | 21 + src/main/java/org/traccar/model/Message.java | 40 + src/main/java/org/traccar/model/MiscFormatter.java | 56 + src/main/java/org/traccar/model/Network.java | 117 ++ src/main/java/org/traccar/model/Notification.java | 72 ++ src/main/java/org/traccar/model/Permission.java | 57 + src/main/java/org/traccar/model/Position.java | 302 +++++ .../java/org/traccar/model/ScheduledModel.java | 30 + src/main/java/org/traccar/model/Server.java | 169 +++ src/main/java/org/traccar/model/Statistics.java | 122 ++ src/main/java/org/traccar/model/Typed.java | 33 + src/main/java/org/traccar/model/User.java | 276 +++++ .../java/org/traccar/model/WifiAccessPoint.java | 66 + .../org/traccar/notification/EventForwarder.java | 91 ++ .../java/org/traccar/notification/FullMessage.java | 36 + .../notification/JsonTypeEventForwarder.java | 18 + .../org/traccar/notification/MessageException.java | 29 + .../notification/NotificationFormatter.java | 118 ++ .../traccar/notification/NotificatorManager.java | 90 ++ .../traccar/notification/PropertiesProvider.java | 81 ++ .../java/org/traccar/notificators/Notificator.java | 44 + .../traccar/notificators/NotificatorFirebase.java | 87 ++ .../org/traccar/notificators/NotificatorMail.java | 40 + .../org/traccar/notificators/NotificatorNull.java | 38 + .../org/traccar/notificators/NotificatorSms.java | 62 + .../org/traccar/notificators/NotificatorWeb.java | 30 + .../java/org/traccar/protocol/AdmProtocol.java | 44 + .../org/traccar/protocol/AdmProtocolDecoder.java | 198 +++ .../org/traccar/protocol/AdmProtocolEncoder.java | 39 + .../java/org/traccar/protocol/AisProtocol.java | 35 + .../org/traccar/protocol/AisProtocolDecoder.java | 140 +++ .../traccar/protocol/AlematicsFrameDecoder.java | 50 + .../org/traccar/protocol/AlematicsProtocol.java | 38 + .../traccar/protocol/AlematicsProtocolDecoder.java | 157 +++ .../java/org/traccar/protocol/AnytrekProtocol.java | 35 + .../traccar/protocol/AnytrekProtocolDecoder.java | 120 ++ .../java/org/traccar/protocol/ApelProtocol.java | 36 + .../org/traccar/protocol/ApelProtocolDecoder.java | 210 ++++ .../org/traccar/protocol/AplicomFrameDecoder.java | 62 + .../java/org/traccar/protocol/AplicomProtocol.java | 34 + .../traccar/protocol/AplicomProtocolDecoder.java | 702 +++++++++++ .../java/org/traccar/protocol/AppelloProtocol.java | 39 + .../traccar/protocol/AppelloProtocolDecoder.java | 92 ++ .../java/org/traccar/protocol/AppletProtocol.java | 39 + .../traccar/protocol/AppletProtocolDecoder.java | 48 + .../java/org/traccar/protocol/AquilaProtocol.java | 39 + .../traccar/protocol/AquilaProtocolDecoder.java | 403 +++++++ .../java/org/traccar/protocol/Ardi01Protocol.java | 39 + .../traccar/protocol/Ardi01ProtocolDecoder.java | 87 ++ .../java/org/traccar/protocol/ArknavProtocol.java | 39 + .../traccar/protocol/ArknavProtocolDecoder.java | 83 ++ .../org/traccar/protocol/ArknavX8Protocol.java | 39 + .../traccar/protocol/ArknavX8ProtocolDecoder.java | 139 +++ .../java/org/traccar/protocol/ArnaviProtocol.java | 39 + .../traccar/protocol/ArnaviProtocolDecoder.java | 105 ++ .../java/org/traccar/protocol/AstraProtocol.java | 41 + .../org/traccar/protocol/AstraProtocolDecoder.java | 129 ++ .../org/traccar/protocol/At2000FrameDecoder.java | 81 ++ .../java/org/traccar/protocol/At2000Protocol.java | 34 + .../traccar/protocol/At2000ProtocolDecoder.java | 171 +++ .../org/traccar/protocol/AtrackFrameDecoder.java | 80 ++ .../java/org/traccar/protocol/AtrackProtocol.java | 45 + .../traccar/protocol/AtrackProtocolDecoder.java | 586 +++++++++ .../traccar/protocol/AtrackProtocolEncoder.java | 38 + .../java/org/traccar/protocol/AuroProtocol.java | 39 + .../org/traccar/protocol/AuroProtocolDecoder.java | 91 ++ .../org/traccar/protocol/AustinNbProtocol.java | 37 + .../traccar/protocol/AustinNbProtocolDecoder.java | 81 ++ .../org/traccar/protocol/AutoFonFrameDecoder.java | 65 + .../java/org/traccar/protocol/AutoFonProtocol.java | 34 + .../traccar/protocol/AutoFonProtocolDecoder.java | 215 ++++ .../org/traccar/protocol/AutoGradeProtocol.java | 39 + .../traccar/protocol/AutoGradeProtocolDecoder.java | 107 ++ .../org/traccar/protocol/AutoTrackProtocol.java | 36 + .../traccar/protocol/AutoTrackProtocolDecoder.java | 138 +++ .../java/org/traccar/protocol/AvemaProtocol.java | 39 + .../org/traccar/protocol/AvemaProtocolDecoder.java | 107 ++ .../java/org/traccar/protocol/Avl301Protocol.java | 35 + .../traccar/protocol/Avl301ProtocolDecoder.java | 145 +++ .../java/org/traccar/protocol/BceFrameDecoder.java | 59 + .../java/org/traccar/protocol/BceProtocol.java | 38 + .../org/traccar/protocol/BceProtocolDecoder.java | 175 +++ .../org/traccar/protocol/BceProtocolEncoder.java | 47 + .../org/traccar/protocol/BlackKiteProtocol.java | 35 + .../traccar/protocol/BlackKiteProtocolDecoder.java | 195 +++ .../java/org/traccar/protocol/BoxProtocol.java | 39 + .../org/traccar/protocol/BoxProtocolDecoder.java | 108 ++ .../java/org/traccar/protocol/C2stekProtocol.java | 39 + .../traccar/protocol/C2stekProtocolDecoder.java | 121 ++ .../java/org/traccar/protocol/CalAmpProtocol.java | 33 + .../traccar/protocol/CalAmpProtocolDecoder.java | 202 ++++ .../org/traccar/protocol/CarTrackProtocol.java | 39 + .../traccar/protocol/CarTrackProtocolDecoder.java | 108 ++ .../java/org/traccar/protocol/CarcellProtocol.java | 44 + .../traccar/protocol/CarcellProtocolDecoder.java | 164 +++ .../traccar/protocol/CarcellProtocolEncoder.java | 36 + .../java/org/traccar/protocol/CarscopProtocol.java | 39 + .../traccar/protocol/CarscopProtocolDecoder.java | 101 ++ .../java/org/traccar/protocol/CastelProtocol.java | 48 + .../traccar/protocol/CastelProtocolDecoder.java | 573 +++++++++ .../traccar/protocol/CastelProtocolEncoder.java | 70 ++ .../java/org/traccar/protocol/CautelaProtocol.java | 39 + .../traccar/protocol/CautelaProtocolDecoder.java | 78 ++ .../traccar/protocol/CellocatorFrameDecoder.java | 66 + .../org/traccar/protocol/CellocatorProtocol.java | 45 + .../protocol/CellocatorProtocolDecoder.java | 177 +++ .../protocol/CellocatorProtocolEncoder.java | 66 + .../java/org/traccar/protocol/CguardProtocol.java | 39 + .../traccar/protocol/CguardProtocolDecoder.java | 147 +++ .../org/traccar/protocol/CityeasyProtocol.java | 42 + .../traccar/protocol/CityeasyProtocolDecoder.java | 127 ++ .../traccar/protocol/CityeasyProtocolEncoder.java | 73 ++ .../org/traccar/protocol/ContinentalProtocol.java | 35 + .../protocol/ContinentalProtocolDecoder.java | 114 ++ .../org/traccar/protocol/CradlepointProtocol.java | 39 + .../protocol/CradlepointProtocolDecoder.java | 95 ++ .../java/org/traccar/protocol/DishaProtocol.java | 39 + .../org/traccar/protocol/DishaProtocolDecoder.java | 102 ++ .../java/org/traccar/protocol/DmtHttpProtocol.java | 39 + .../traccar/protocol/DmtHttpProtocolDecoder.java | 133 ++ .../java/org/traccar/protocol/DmtProtocol.java | 36 + .../org/traccar/protocol/DmtProtocolDecoder.java | 289 +++++ .../java/org/traccar/protocol/DwayProtocol.java | 39 + .../org/traccar/protocol/DwayProtocolDecoder.java | 103 ++ .../org/traccar/protocol/EasyTrackProtocol.java | 39 + .../traccar/protocol/EasyTrackProtocolDecoder.java | 138 +++ .../java/org/traccar/protocol/EelinkProtocol.java | 50 + .../traccar/protocol/EelinkProtocolDecoder.java | 441 +++++++ .../traccar/protocol/EelinkProtocolEncoder.java | 107 ++ .../org/traccar/protocol/EgtsFrameDecoder.java | 45 + .../java/org/traccar/protocol/EgtsProtocol.java | 34 + .../org/traccar/protocol/EgtsProtocolDecoder.java | 265 ++++ .../java/org/traccar/protocol/EnforaProtocol.java | 48 + .../traccar/protocol/EnforaProtocolDecoder.java | 115 ++ .../traccar/protocol/EnforaProtocolEncoder.java | 55 + .../java/org/traccar/protocol/EsealProtocol.java | 45 + .../org/traccar/protocol/EsealProtocolDecoder.java | 158 +++ .../org/traccar/protocol/EsealProtocolEncoder.java | 41 + .../org/traccar/protocol/EskyFrameDecoder.java | 39 + .../java/org/traccar/protocol/EskyProtocol.java | 38 + .../org/traccar/protocol/EskyProtocolDecoder.java | 94 ++ .../org/traccar/protocol/ExtremTracProtocol.java | 39 + .../protocol/ExtremTracProtocolDecoder.java | 83 ++ .../org/traccar/protocol/FifotrackProtocol.java | 39 + .../traccar/protocol/FifotrackProtocolDecoder.java | 198 +++ .../java/org/traccar/protocol/FlespiProtocol.java | 38 + .../traccar/protocol/FlespiProtocolDecoder.java | 246 ++++ .../org/traccar/protocol/FlexCommProtocol.java | 39 + .../traccar/protocol/FlexCommProtocolDecoder.java | 128 ++ .../org/traccar/protocol/FlextrackProtocol.java | 39 + .../traccar/protocol/FlextrackProtocolDecoder.java | 144 +++ .../java/org/traccar/protocol/FoxProtocol.java | 39 + .../org/traccar/protocol/FoxProtocolDecoder.java | 124 ++ .../java/org/traccar/protocol/FreedomProtocol.java | 39 + .../traccar/protocol/FreedomProtocolDecoder.java | 77 ++ .../org/traccar/protocol/FreematicsProtocol.java | 37 + .../protocol/FreematicsProtocolDecoder.java | 184 +++ .../org/traccar/protocol/GalileoFrameDecoder.java | 43 + .../java/org/traccar/protocol/GalileoProtocol.java | 39 + .../traccar/protocol/GalileoProtocolDecoder.java | 342 ++++++ .../traccar/protocol/GalileoProtocolEncoder.java | 67 ++ .../java/org/traccar/protocol/GatorProtocol.java | 41 + .../org/traccar/protocol/GatorProtocolDecoder.java | 133 ++ .../java/org/traccar/protocol/GenxProtocol.java | 37 + .../org/traccar/protocol/GenxProtocolDecoder.java | 99 ++ .../java/org/traccar/protocol/Gl100Protocol.java | 47 + .../org/traccar/protocol/Gl100ProtocolDecoder.java | 97 ++ .../protocol/Gl200BinaryProtocolDecoder.java | 403 +++++++ .../org/traccar/protocol/Gl200FrameDecoder.java | 97 ++ .../java/org/traccar/protocol/Gl200Protocol.java | 53 + .../org/traccar/protocol/Gl200ProtocolDecoder.java | 50 + .../org/traccar/protocol/Gl200ProtocolEncoder.java | 46 + .../traccar/protocol/Gl200TextProtocolDecoder.java | 1266 ++++++++++++++++++++ .../org/traccar/protocol/GlobalSatProtocol.java | 39 + .../traccar/protocol/GlobalSatProtocolDecoder.java | 248 ++++ .../java/org/traccar/protocol/GnxProtocol.java | 39 + .../org/traccar/protocol/GnxProtocolDecoder.java | 111 ++ .../java/org/traccar/protocol/GoSafeProtocol.java | 39 + .../traccar/protocol/GoSafeProtocolDecoder.java | 269 +++++ .../java/org/traccar/protocol/GotopProtocol.java | 39 + .../org/traccar/protocol/GotopProtocolDecoder.java | 82 ++ .../org/traccar/protocol/Gps056FrameDecoder.java | 47 + .../java/org/traccar/protocol/Gps056Protocol.java | 34 + .../traccar/protocol/Gps056ProtocolDecoder.java | 140 +++ .../java/org/traccar/protocol/Gps103Protocol.java | 60 + .../traccar/protocol/Gps103ProtocolDecoder.java | 422 +++++++ .../traccar/protocol/Gps103ProtocolEncoder.java | 68 ++ .../java/org/traccar/protocol/GpsGateProtocol.java | 39 + .../traccar/protocol/GpsGateProtocolDecoder.java | 170 +++ .../org/traccar/protocol/GpsMarkerProtocol.java | 39 + .../traccar/protocol/GpsMarkerProtocolDecoder.java | 90 ++ .../java/org/traccar/protocol/GpsmtaProtocol.java | 37 + .../traccar/protocol/GpsmtaProtocolDecoder.java | 92 ++ .../org/traccar/protocol/GranitFrameDecoder.java | 47 + .../java/org/traccar/protocol/GranitProtocol.java | 45 + .../traccar/protocol/GranitProtocolDecoder.java | 239 ++++ .../traccar/protocol/GranitProtocolEncoder.java | 48 + .../traccar/protocol/GranitProtocolSmsEncoder.java | 36 + .../java/org/traccar/protocol/Gt02Protocol.java | 35 + .../org/traccar/protocol/Gt02ProtocolDecoder.java | 125 ++ .../org/traccar/protocol/Gt06FrameDecoder.java | 56 + .../java/org/traccar/protocol/Gt06Protocol.java | 40 + .../org/traccar/protocol/Gt06ProtocolDecoder.java | 929 ++++++++++++++ .../org/traccar/protocol/Gt06ProtocolEncoder.java | 78 ++ .../java/org/traccar/protocol/Gt30Protocol.java | 39 + .../org/traccar/protocol/Gt30ProtocolDecoder.java | 114 ++ .../java/org/traccar/protocol/H02FrameDecoder.java | 95 ++ .../java/org/traccar/protocol/H02Protocol.java | 54 + .../org/traccar/protocol/H02ProtocolDecoder.java | 583 +++++++++ .../org/traccar/protocol/H02ProtocolEncoder.java | 73 ++ .../java/org/traccar/protocol/HaicomProtocol.java | 39 + .../traccar/protocol/HaicomProtocolDecoder.java | 109 ++ .../java/org/traccar/protocol/HomtecsProtocol.java | 37 + .../traccar/protocol/HomtecsProtocolDecoder.java | 91 ++ .../org/traccar/protocol/HuaShengFrameDecoder.java | 58 + .../org/traccar/protocol/HuaShengProtocol.java | 34 + .../traccar/protocol/HuaShengProtocolDecoder.java | 155 +++ .../org/traccar/protocol/HuabaoFrameDecoder.java | 58 + .../java/org/traccar/protocol/HuabaoProtocol.java | 39 + .../traccar/protocol/HuabaoProtocolDecoder.java | 235 ++++ .../traccar/protocol/HuabaoProtocolEncoder.java | 73 ++ .../org/traccar/protocol/HunterProProtocol.java | 39 + .../traccar/protocol/HunterProProtocolDecoder.java | 83 ++ .../java/org/traccar/protocol/IdplProtocol.java | 39 + .../org/traccar/protocol/IdplProtocolDecoder.java | 112 ++ .../traccar/protocol/IntellitracFrameDecoder.java | 52 + .../org/traccar/protocol/IntellitracProtocol.java | 38 + .../protocol/IntellitracProtocolDecoder.java | 117 ++ .../java/org/traccar/protocol/ItsProtocol.java | 39 + .../org/traccar/protocol/ItsProtocolDecoder.java | 170 +++ .../java/org/traccar/protocol/Ivt401Protocol.java | 37 + .../traccar/protocol/Ivt401ProtocolDecoder.java | 183 +++ .../org/traccar/protocol/JpKorjarFrameDecoder.java | 47 + .../org/traccar/protocol/JpKorjarProtocol.java | 37 + .../traccar/protocol/JpKorjarProtocolDecoder.java | 89 ++ .../org/traccar/protocol/Jt600FrameDecoder.java | 55 + .../java/org/traccar/protocol/Jt600Protocol.java | 43 + .../org/traccar/protocol/Jt600ProtocolDecoder.java | 375 ++++++ .../org/traccar/protocol/Jt600ProtocolEncoder.java | 43 + .../java/org/traccar/protocol/KenjiProtocol.java | 40 + .../org/traccar/protocol/KenjiProtocolDecoder.java | 110 ++ .../java/org/traccar/protocol/KhdProtocol.java | 40 + .../org/traccar/protocol/KhdProtocolDecoder.java | 157 +++ .../org/traccar/protocol/KhdProtocolEncoder.java | 67 ++ .../org/traccar/protocol/L100FrameDecoder.java | 90 ++ .../java/org/traccar/protocol/L100Protocol.java | 38 + .../org/traccar/protocol/L100ProtocolDecoder.java | 341 ++++++ .../java/org/traccar/protocol/LaipacProtocol.java | 39 + .../traccar/protocol/LaipacProtocolDecoder.java | 167 +++ .../java/org/traccar/protocol/M2cProtocol.java | 39 + .../org/traccar/protocol/M2cProtocolDecoder.java | 131 ++ .../java/org/traccar/protocol/M2mProtocol.java | 35 + .../org/traccar/protocol/M2mProtocolDecoder.java | 127 ++ .../java/org/traccar/protocol/MaestroProtocol.java | 39 + .../traccar/protocol/MaestroProtocolDecoder.java | 103 ++ .../org/traccar/protocol/ManPowerProtocol.java | 39 + .../traccar/protocol/ManPowerProtocolDecoder.java | 81 ++ .../org/traccar/protocol/MegastekFrameDecoder.java | 59 + .../org/traccar/protocol/MegastekProtocol.java | 38 + .../traccar/protocol/MegastekProtocolDecoder.java | 419 +++++++ .../org/traccar/protocol/MeiligaoFrameDecoder.java | 47 + .../org/traccar/protocol/MeiligaoProtocol.java | 52 + .../traccar/protocol/MeiligaoProtocolDecoder.java | 499 ++++++++ .../traccar/protocol/MeiligaoProtocolEncoder.java | 86 ++ .../org/traccar/protocol/MeitrackFrameDecoder.java | 47 + .../org/traccar/protocol/MeitrackProtocol.java | 54 + .../traccar/protocol/MeitrackProtocolDecoder.java | 534 +++++++++ .../traccar/protocol/MeitrackProtocolEncoder.java | 65 + .../org/traccar/protocol/MilesmateProtocol.java | 39 + .../traccar/protocol/MilesmateProtocolDecoder.java | 108 ++ .../org/traccar/protocol/MiniFinderProtocol.java | 53 + .../protocol/MiniFinderProtocolDecoder.java | 208 ++++ .../protocol/MiniFinderProtocolEncoder.java | 82 ++ .../java/org/traccar/protocol/Mta6Protocol.java | 41 + .../org/traccar/protocol/Mta6ProtocolDecoder.java | 319 +++++ .../java/org/traccar/protocol/MtxProtocol.java | 39 + .../org/traccar/protocol/MtxProtocolDecoder.java | 98 ++ .../java/org/traccar/protocol/MxtFrameDecoder.java | 53 + .../java/org/traccar/protocol/MxtProtocol.java | 34 + .../org/traccar/protocol/MxtProtocolDecoder.java | 175 +++ .../org/traccar/protocol/NavigilFrameDecoder.java | 56 + .../java/org/traccar/protocol/NavigilProtocol.java | 34 + .../traccar/protocol/NavigilProtocolDecoder.java | 308 +++++ .../org/traccar/protocol/NavisFrameDecoder.java | 109 ++ .../java/org/traccar/protocol/NavisProtocol.java | 33 + .../org/traccar/protocol/NavisProtocolDecoder.java | 683 +++++++++++ .../java/org/traccar/protocol/NeosProtocol.java | 37 + .../org/traccar/protocol/NeosProtocolDecoder.java | 98 ++ .../java/org/traccar/protocol/NoranProtocol.java | 41 + .../org/traccar/protocol/NoranProtocolDecoder.java | 164 +++ .../org/traccar/protocol/NoranProtocolEncoder.java | 64 + .../java/org/traccar/protocol/NvsFrameDecoder.java | 47 + .../java/org/traccar/protocol/NvsProtocol.java | 34 + .../org/traccar/protocol/NvsProtocolDecoder.java | 137 +++ .../java/org/traccar/protocol/NyitechProtocol.java | 37 + .../traccar/protocol/NyitechProtocolDecoder.java | 123 ++ .../org/traccar/protocol/ObdDongleProtocol.java | 35 + .../traccar/protocol/ObdDongleProtocolDecoder.java | 130 ++ .../java/org/traccar/protocol/OigoProtocol.java | 33 + .../org/traccar/protocol/OigoProtocolDecoder.java | 240 ++++ .../java/org/traccar/protocol/OkoProtocol.java | 37 + .../org/traccar/protocol/OkoProtocolDecoder.java | 100 ++ .../java/org/traccar/protocol/OpenGtsProtocol.java | 39 + .../traccar/protocol/OpenGtsProtocolDecoder.java | 115 ++ .../org/traccar/protocol/OrionFrameDecoder.java | 68 ++ .../java/org/traccar/protocol/OrionProtocol.java | 34 + .../org/traccar/protocol/OrionProtocolDecoder.java | 115 ++ .../java/org/traccar/protocol/OsmAndProtocol.java | 39 + .../traccar/protocol/OsmAndProtocolDecoder.java | 184 +++ .../org/traccar/protocol/OwnTracksProtocol.java | 40 + .../traccar/protocol/OwnTracksProtocolDecoder.java | 215 ++++ .../org/traccar/protocol/PathAwayProtocol.java | 39 + .../traccar/protocol/PathAwayProtocolDecoder.java | 97 ++ .../org/traccar/protocol/PiligrimProtocol.java | 39 + .../traccar/protocol/PiligrimProtocolDecoder.java | 167 +++ .../org/traccar/protocol/PretraceProtocol.java | 44 + .../traccar/protocol/PretraceProtocolDecoder.java | 132 ++ .../traccar/protocol/PretraceProtocolEncoder.java | 46 + .../java/org/traccar/protocol/PricolProtocol.java | 41 + .../traccar/protocol/PricolProtocolDecoder.java | 98 ++ .../org/traccar/protocol/ProgressProtocol.java | 36 + .../traccar/protocol/ProgressProtocolDecoder.java | 172 +++ .../java/org/traccar/protocol/Pt3000Protocol.java | 39 + .../traccar/protocol/Pt3000ProtocolDecoder.java | 83 ++ .../org/traccar/protocol/Pt502FrameDecoder.java | 73 ++ .../java/org/traccar/protocol/Pt502Protocol.java | 44 + .../org/traccar/protocol/Pt502ProtocolDecoder.java | 212 ++++ .../org/traccar/protocol/Pt502ProtocolEncoder.java | 58 + .../java/org/traccar/protocol/Pt60Protocol.java | 39 + .../org/traccar/protocol/Pt60ProtocolDecoder.java | 184 +++ .../java/org/traccar/protocol/RaveonProtocol.java | 39 + .../traccar/protocol/RaveonProtocolDecoder.java | 99 ++ .../java/org/traccar/protocol/RecodaProtocol.java | 36 + .../traccar/protocol/RecodaProtocolDecoder.java | 110 ++ .../traccar/protocol/RetranslatorFrameDecoder.java | 37 + .../org/traccar/protocol/RetranslatorProtocol.java | 34 + .../protocol/RetranslatorProtocolDecoder.java | 114 ++ .../java/org/traccar/protocol/RitiProtocol.java | 36 + .../org/traccar/protocol/RitiProtocolDecoder.java | 102 ++ .../traccar/protocol/RoboTrackFrameDecoder.java | 57 + .../org/traccar/protocol/RoboTrackProtocol.java | 34 + .../traccar/protocol/RoboTrackProtocolDecoder.java | 131 ++ .../java/org/traccar/protocol/RuptelaProtocol.java | 45 + .../traccar/protocol/RuptelaProtocolDecoder.java | 248 ++++ .../traccar/protocol/RuptelaProtocolEncoder.java | 73 ++ .../org/traccar/protocol/SabertekFrameDecoder.java | 44 + .../org/traccar/protocol/SabertekProtocol.java | 36 + .../traccar/protocol/SabertekProtocolDecoder.java | 135 +++ .../java/org/traccar/protocol/SanavProtocol.java | 45 + .../org/traccar/protocol/SanavProtocolDecoder.java | 107 ++ .../java/org/traccar/protocol/SatsolProtocol.java | 37 + .../traccar/protocol/SatsolProtocolDecoder.java | 104 ++ .../java/org/traccar/protocol/SigfoxProtocol.java | 39 + .../traccar/protocol/SigfoxProtocolDecoder.java | 92 ++ .../java/org/traccar/protocol/SiwiProtocol.java | 37 + .../org/traccar/protocol/SiwiProtocolDecoder.java | 96 ++ .../org/traccar/protocol/SkypatrolProtocol.java | 33 + .../traccar/protocol/SkypatrolProtocolDecoder.java | 193 +++ .../org/traccar/protocol/SmartSoleProtocol.java | 39 + .../traccar/protocol/SmartSoleProtocolDecoder.java | 91 ++ .../java/org/traccar/protocol/SmokeyProtocol.java | 33 + .../traccar/protocol/SmokeyProtocolDecoder.java | 161 +++ .../java/org/traccar/protocol/SpotProtocol.java | 39 + .../org/traccar/protocol/SpotProtocolDecoder.java | 102 ++ .../org/traccar/protocol/StarLinkProtocol.java | 39 + .../traccar/protocol/StarLinkProtocolDecoder.java | 229 ++++ .../org/traccar/protocol/Stl060FrameDecoder.java | 48 + .../java/org/traccar/protocol/Stl060Protocol.java | 38 + .../traccar/protocol/Stl060ProtocolDecoder.java | 120 ++ .../java/org/traccar/protocol/SuntechProtocol.java | 49 + .../traccar/protocol/SuntechProtocolDecoder.java | 467 ++++++++ .../traccar/protocol/SuntechProtocolEncoder.java | 54 + .../org/traccar/protocol/SupermateProtocol.java | 39 + .../traccar/protocol/SupermateProtocolDecoder.java | 122 ++ .../java/org/traccar/protocol/SviasProtocol.java | 51 + .../org/traccar/protocol/SviasProtocolDecoder.java | 105 ++ .../org/traccar/protocol/SviasProtocolEncoder.java | 48 + .../java/org/traccar/protocol/T55Protocol.java | 47 + .../org/traccar/protocol/T55ProtocolDecoder.java | 283 +++++ .../java/org/traccar/protocol/T57FrameDecoder.java | 49 + .../java/org/traccar/protocol/T57Protocol.java | 38 + .../org/traccar/protocol/T57ProtocolDecoder.java | 84 ++ .../java/org/traccar/protocol/T800xProtocol.java | 39 + .../org/traccar/protocol/T800xProtocolDecoder.java | 199 +++ .../org/traccar/protocol/T800xProtocolEncoder.java | 59 + .../java/org/traccar/protocol/TaipProtocol.java | 47 + .../org/traccar/protocol/TaipProtocolDecoder.java | 287 +++++ .../java/org/traccar/protocol/TekFrameDecoder.java | 42 + .../java/org/traccar/protocol/TekProtocol.java | 34 + .../org/traccar/protocol/TekProtocolDecoder.java | 139 +++ .../java/org/traccar/protocol/TelemaxProtocol.java | 39 + .../traccar/protocol/TelemaxProtocolDecoder.java | 112 ++ .../org/traccar/protocol/TelicFrameDecoder.java | 55 + .../java/org/traccar/protocol/TelicProtocol.java | 38 + .../org/traccar/protocol/TelicProtocolDecoder.java | 135 +++ .../traccar/protocol/TeltonikaFrameDecoder.java | 53 + .../org/traccar/protocol/TeltonikaProtocol.java | 45 + .../traccar/protocol/TeltonikaProtocolDecoder.java | 597 +++++++++ .../traccar/protocol/TeltonikaProtocolEncoder.java | 59 + .../org/traccar/protocol/ThinkRaceProtocol.java | 35 + .../traccar/protocol/ThinkRaceProtocolDecoder.java | 116 ++ .../java/org/traccar/protocol/Tk102Protocol.java | 35 + .../org/traccar/protocol/Tk102ProtocolDecoder.java | 144 +++ .../org/traccar/protocol/Tk103FrameDecoder.java | 75 ++ .../java/org/traccar/protocol/Tk103Protocol.java | 69 ++ .../org/traccar/protocol/Tk103ProtocolDecoder.java | 453 +++++++ .../org/traccar/protocol/Tk103ProtocolEncoder.java | 110 ++ .../java/org/traccar/protocol/Tlt2hProtocol.java | 39 + .../org/traccar/protocol/Tlt2hProtocolDecoder.java | 152 +++ .../java/org/traccar/protocol/TlvProtocol.java | 35 + .../org/traccar/protocol/TlvProtocolDecoder.java | 110 ++ .../java/org/traccar/protocol/TmgFrameDecoder.java | 67 ++ .../java/org/traccar/protocol/TmgProtocol.java | 38 + .../org/traccar/protocol/TmgProtocolDecoder.java | 194 +++ .../org/traccar/protocol/TopflytechProtocol.java | 39 + .../protocol/TopflytechProtocolDecoder.java | 76 ++ .../org/traccar/protocol/TotemFrameDecoder.java | 59 + .../java/org/traccar/protocol/TotemProtocol.java | 44 + .../org/traccar/protocol/TotemProtocolDecoder.java | 444 +++++++ .../org/traccar/protocol/TotemProtocolEncoder.java | 40 + .../java/org/traccar/protocol/Tr20Protocol.java | 39 + .../org/traccar/protocol/Tr20ProtocolDecoder.java | 103 ++ .../java/org/traccar/protocol/Tr900Protocol.java | 47 + .../org/traccar/protocol/Tr900ProtocolDecoder.java | 94 ++ .../org/traccar/protocol/TrackboxProtocol.java | 39 + .../traccar/protocol/TrackboxProtocolDecoder.java | 110 ++ .../org/traccar/protocol/TrakMateProtocol.java | 39 + .../traccar/protocol/TrakMateProtocolDecoder.java | 233 ++++ .../org/traccar/protocol/TramigoFrameDecoder.java | 46 + .../java/org/traccar/protocol/TramigoProtocol.java | 34 + .../traccar/protocol/TramigoProtocolDecoder.java | 160 +++ .../java/org/traccar/protocol/TrvProtocol.java | 39 + .../org/traccar/protocol/TrvProtocolDecoder.java | 258 ++++ .../java/org/traccar/protocol/Tt8850Protocol.java | 39 + .../traccar/protocol/Tt8850ProtocolDecoder.java | 99 ++ .../java/org/traccar/protocol/TytanProtocol.java | 33 + .../org/traccar/protocol/TytanProtocolDecoder.java | 192 +++ .../java/org/traccar/protocol/TzoneProtocol.java | 36 + .../org/traccar/protocol/TzoneProtocolDecoder.java | 293 +++++ .../org/traccar/protocol/UlbotechFrameDecoder.java | 70 ++ .../org/traccar/protocol/UlbotechProtocol.java | 34 + .../traccar/protocol/UlbotechProtocolDecoder.java | 371 ++++++ .../java/org/traccar/protocol/UproProtocol.java | 37 + .../org/traccar/protocol/UproProtocolDecoder.java | 212 ++++ .../java/org/traccar/protocol/V680Protocol.java | 47 + .../org/traccar/protocol/V680ProtocolDecoder.java | 132 ++ .../org/traccar/protocol/VisiontekProtocol.java | 39 + .../traccar/protocol/VisiontekProtocolDecoder.java | 138 +++ .../org/traccar/protocol/Vt200FrameDecoder.java | 52 + .../java/org/traccar/protocol/Vt200Protocol.java | 34 + .../org/traccar/protocol/Vt200ProtocolDecoder.java | 150 +++ .../org/traccar/protocol/VtfmsFrameDecoder.java | 41 + .../java/org/traccar/protocol/VtfmsProtocol.java | 44 + .../org/traccar/protocol/VtfmsProtocolDecoder.java | 167 +++ .../org/traccar/protocol/WatchFrameDecoder.java | 67 ++ .../java/org/traccar/protocol/WatchProtocol.java | 53 + .../org/traccar/protocol/WatchProtocolDecoder.java | 329 +++++ .../org/traccar/protocol/WatchProtocolEncoder.java | 167 +++ .../java/org/traccar/protocol/WialonProtocol.java | 54 + .../traccar/protocol/WialonProtocolDecoder.java | 196 +++ .../traccar/protocol/WialonProtocolEncoder.java | 40 + .../org/traccar/protocol/WondexFrameDecoder.java | 62 + .../java/org/traccar/protocol/WondexProtocol.java | 55 + .../traccar/protocol/WondexProtocolDecoder.java | 128 ++ .../traccar/protocol/WondexProtocolEncoder.java | 46 + .../org/traccar/protocol/WristbandProtocol.java | 35 + .../traccar/protocol/WristbandProtocolDecoder.java | 207 ++++ .../org/traccar/protocol/XexunFrameDecoder.java | 58 + .../java/org/traccar/protocol/XexunProtocol.java | 51 + .../org/traccar/protocol/XexunProtocolDecoder.java | 152 +++ .../org/traccar/protocol/XexunProtocolEncoder.java | 38 + .../java/org/traccar/protocol/XirgoProtocol.java | 53 + .../org/traccar/protocol/XirgoProtocolDecoder.java | 355 ++++++ .../org/traccar/protocol/XirgoProtocolEncoder.java | 34 + .../java/org/traccar/protocol/Xrb28Protocol.java | 49 + .../org/traccar/protocol/Xrb28ProtocolDecoder.java | 187 +++ .../org/traccar/protocol/Xrb28ProtocolEncoder.java | 52 + .../java/org/traccar/protocol/Xt013Protocol.java | 40 + .../org/traccar/protocol/Xt013ProtocolDecoder.java | 94 ++ .../java/org/traccar/protocol/Xt2400Protocol.java | 33 + .../traccar/protocol/Xt2400ProtocolDecoder.java | 198 +++ .../java/org/traccar/protocol/YwtProtocol.java | 39 + .../org/traccar/protocol/YwtProtocolDecoder.java | 116 ++ src/main/java/org/traccar/reports/Events.java | 133 ++ src/main/java/org/traccar/reports/ReportUtils.java | 378 ++++++ src/main/java/org/traccar/reports/Route.java | 85 ++ src/main/java/org/traccar/reports/Stops.java | 102 ++ src/main/java/org/traccar/reports/Summary.java | 117 ++ src/main/java/org/traccar/reports/Trips.java | 100 ++ .../java/org/traccar/reports/model/BaseReport.java | 106 ++ .../org/traccar/reports/model/DeviceReport.java | 55 + .../java/org/traccar/reports/model/StopReport.java | 106 ++ .../org/traccar/reports/model/SummaryReport.java | 34 + .../java/org/traccar/reports/model/TripReport.java | 152 +++ .../org/traccar/reports/model/TripsConfig.java | 105 ++ src/main/java/org/traccar/sms/HttpSmsClient.java | 110 ++ src/main/java/org/traccar/sms/SmsManager.java | 29 + .../traccar/sms/smpp/ClientSmppSessionHandler.java | 82 ++ .../java/org/traccar/sms/smpp/EnquireLinkTask.java | 59 + .../org/traccar/sms/smpp/ReconnectionTask.java | 32 + src/main/java/org/traccar/sms/smpp/SmppClient.java | 272 +++++ .../traccar/sms/smpp/TextMessageEventHandler.java | 37 + src/main/java/org/traccar/web/ConsoleServlet.java | 61 + src/main/java/org/traccar/web/CsvBuilder.java | 164 +++ src/main/java/org/traccar/web/GpxBuilder.java | 69 ++ src/main/java/org/traccar/web/WebServer.java | 173 +++ src/org/traccar/BaseDataHandler.java | 38 - src/org/traccar/BaseFrameDecoder.java | 37 - src/org/traccar/BaseHttpProtocolDecoder.java | 39 - src/org/traccar/BasePipelineFactory.java | 169 --- src/org/traccar/BaseProtocol.java | 131 -- src/org/traccar/BaseProtocolDecoder.java | 255 ---- src/org/traccar/BaseProtocolEncoder.java | 85 -- .../traccar/CharacterDelimiterFrameDecoder.java | 65 - src/org/traccar/Context.java | 410 ------- src/org/traccar/DeviceSession.java | 42 - src/org/traccar/EventLoopGroupFactory.java | 37 - src/org/traccar/ExtendedObjectDecoder.java | 82 -- src/org/traccar/GlobalTimer.java | 42 - src/org/traccar/Main.java | 156 --- src/org/traccar/MainEventHandler.java | 161 --- src/org/traccar/MainModule.java | 373 ------ src/org/traccar/NetworkMessage.java | 38 - src/org/traccar/PipelineBuilder.java | 24 - src/org/traccar/Protocol.java | 37 - src/org/traccar/ServerManager.java | 103 -- src/org/traccar/StringProtocolEncoder.java | 51 - src/org/traccar/TrackerServer.java | 115 -- src/org/traccar/WebDataHandler.java | 201 ---- src/org/traccar/WindowsService.java | 231 ---- src/org/traccar/WrapperContext.java | 255 ---- src/org/traccar/WrapperInboundHandler.java | 94 -- src/org/traccar/WrapperOutboundHandler.java | 99 -- src/org/traccar/api/AsyncSocket.java | 96 -- src/org/traccar/api/AsyncSocketServlet.java | 46 - src/org/traccar/api/BaseObjectResource.java | 176 --- src/org/traccar/api/BaseResource.java | 32 - src/org/traccar/api/CorsResponseFilter.java | 58 - src/org/traccar/api/ExtendedObjectResource.java | 62 - src/org/traccar/api/MediaFilter.java | 92 -- src/org/traccar/api/ObjectMapperProvider.java | 32 - src/org/traccar/api/ResourceErrorHandler.java | 42 - src/org/traccar/api/SecurityRequestFilter.java | 119 -- src/org/traccar/api/SimpleObjectResource.java | 43 - src/org/traccar/api/UserPrincipal.java | 37 - src/org/traccar/api/UserSecurityContext.java | 49 - .../traccar/api/resource/AttributeResource.java | 97 -- src/org/traccar/api/resource/CalendarResource.java | 36 - src/org/traccar/api/resource/CommandResource.java | 89 -- src/org/traccar/api/resource/DeviceResource.java | 100 -- src/org/traccar/api/resource/DriverResource.java | 36 - src/org/traccar/api/resource/EventResource.java | 38 - src/org/traccar/api/resource/GeofenceResource.java | 35 - src/org/traccar/api/resource/GroupResource.java | 35 - .../traccar/api/resource/MaintenanceResource.java | 36 - .../traccar/api/resource/NotificationResource.java | 76 -- .../traccar/api/resource/PermissionsResource.java | 84 -- src/org/traccar/api/resource/PositionResource.java | 96 -- src/org/traccar/api/resource/ReportResource.java | 210 ---- src/org/traccar/api/resource/ServerResource.java | 63 - src/org/traccar/api/resource/SessionResource.java | 120 -- .../traccar/api/resource/StatisticsResource.java | 44 - src/org/traccar/api/resource/UserResource.java | 94 -- src/org/traccar/config/Config.java | 166 --- src/org/traccar/config/ConfigKey.java | 36 - src/org/traccar/config/ConfigSuffix.java | 28 - src/org/traccar/config/Keys.java | 356 ------ src/org/traccar/database/ActiveDevice.java | 55 - src/org/traccar/database/AttributesManager.java | 36 - src/org/traccar/database/BaseObjectManager.java | 127 -- src/org/traccar/database/CalendarManager.java | 27 - src/org/traccar/database/CommandsManager.java | 157 --- src/org/traccar/database/ConnectionManager.java | 218 ---- src/org/traccar/database/DataManager.java | 478 -------- src/org/traccar/database/DeviceManager.java | 419 ------- src/org/traccar/database/DriversManager.java | 73 -- .../traccar/database/ExtendedObjectManager.java | 115 -- src/org/traccar/database/GeofenceManager.java | 66 - src/org/traccar/database/GroupTree.java | 151 --- src/org/traccar/database/GroupsManager.java | 106 -- src/org/traccar/database/IdentityManager.java | 43 - src/org/traccar/database/LdapProvider.java | 179 --- src/org/traccar/database/MailManager.java | 147 --- src/org/traccar/database/MaintenancesManager.java | 27 - src/org/traccar/database/ManagableObjects.java | 27 - src/org/traccar/database/MediaManager.java | 72 -- src/org/traccar/database/NotificationManager.java | 135 --- src/org/traccar/database/PermissionsManager.java | 459 ------- src/org/traccar/database/QueryBuilder.java | 519 -------- src/org/traccar/database/QueryExtended.java | 27 - src/org/traccar/database/QueryIgnore.java | 26 - src/org/traccar/database/SimpleObjectManager.java | 94 -- src/org/traccar/database/StatisticsManager.java | 160 --- src/org/traccar/database/UsersManager.java | 86 -- src/org/traccar/geocoder/Address.java | 110 -- src/org/traccar/geocoder/AddressFormat.java | 82 -- src/org/traccar/geocoder/BanGeocoder.java | 66 - src/org/traccar/geocoder/BingMapsGeocoder.java | 63 - src/org/traccar/geocoder/FactualGeocoder.java | 58 - src/org/traccar/geocoder/GeocodeFarmGeocoder.java | 70 -- src/org/traccar/geocoder/GeocodeXyzGeocoder.java | 60 - src/org/traccar/geocoder/Geocoder.java | 30 - src/org/traccar/geocoder/GeocoderException.java | 24 - src/org/traccar/geocoder/GisgraphyGeocoder.java | 55 - src/org/traccar/geocoder/GoogleGeocoder.java | 98 -- src/org/traccar/geocoder/HereGeocoder.java | 84 -- src/org/traccar/geocoder/JsonGeocoder.java | 121 -- src/org/traccar/geocoder/MapQuestGeocoder.java | 63 - src/org/traccar/geocoder/MapmyIndiaGeocoder.java | 82 -- src/org/traccar/geocoder/NominatimGeocoder.java | 91 -- src/org/traccar/geocoder/OpenCageGeocoder.java | 76 -- src/org/traccar/geofence/GeofenceCircle.java | 98 -- src/org/traccar/geofence/GeofenceGeometry.java | 50 - src/org/traccar/geofence/GeofencePolygon.java | 164 --- src/org/traccar/geofence/GeofencePolyline.java | 107 -- .../traccar/geolocation/GeolocationException.java | 24 - .../traccar/geolocation/GeolocationProvider.java | 32 - .../geolocation/GoogleGeolocationProvider.java | 26 - .../geolocation/MozillaGeolocationProvider.java | 26 - .../geolocation/OpenCellIdGeolocationProvider.java | 68 -- .../geolocation/UniversalGeolocationProvider.java | 58 - .../geolocation/UnwiredGeolocationProvider.java | 111 -- .../traccar/handler/ComputedAttributesHandler.java | 140 --- src/org/traccar/handler/CopyAttributesHandler.java | 53 - src/org/traccar/handler/DefaultDataHandler.java | 48 - src/org/traccar/handler/DistanceHandler.java | 82 -- src/org/traccar/handler/EngineHoursHandler.java | 50 - src/org/traccar/handler/FilterHandler.java | 206 ---- src/org/traccar/handler/GeocoderHandler.java | 94 -- src/org/traccar/handler/GeolocationHandler.java | 86 -- src/org/traccar/handler/HemisphereHandler.java | 60 - src/org/traccar/handler/MotionHandler.java | 40 - src/org/traccar/handler/NetworkMessageHandler.java | 57 - src/org/traccar/handler/OpenChannelHandler.java | 42 - src/org/traccar/handler/RemoteAddressHandler.java | 42 - .../traccar/handler/StandardLoggingHandler.java | 81 -- .../traccar/handler/events/AlertEventHandler.java | 59 - .../traccar/handler/events/BaseEventHandler.java | 38 - .../handler/events/CommandResultEventHandler.java | 39 - .../traccar/handler/events/DriverEventHandler.java | 57 - .../handler/events/FuelDropEventHandler.java | 70 -- .../handler/events/GeofenceEventHandler.java | 89 -- .../handler/events/IgnitionEventHandler.java | 65 - .../handler/events/MaintenanceEventHandler.java | 72 -- .../traccar/handler/events/MotionEventHandler.java | 135 --- .../handler/events/OverspeedEventHandler.java | 164 --- src/org/traccar/helper/BcdUtil.java | 63 - src/org/traccar/helper/BitBuffer.java | 101 -- src/org/traccar/helper/BitUtil.java | 51 - src/org/traccar/helper/BufferUtil.java | 47 - src/org/traccar/helper/Checksum.java | 200 ---- src/org/traccar/helper/DataConverter.java | 47 - src/org/traccar/helper/DateBuilder.java | 126 -- src/org/traccar/helper/DateUtil.java | 78 -- src/org/traccar/helper/DistanceCalculator.java | 53 - src/org/traccar/helper/Hashing.java | 100 -- src/org/traccar/helper/LocationTree.java | 125 -- src/org/traccar/helper/Log.java | 265 ---- src/org/traccar/helper/LogAction.java | 99 -- src/org/traccar/helper/ObdDecoder.java | 105 -- src/org/traccar/helper/Parser.java | 348 ------ src/org/traccar/helper/PatternBuilder.java | 98 -- src/org/traccar/helper/PatternUtil.java | 81 -- src/org/traccar/helper/SanitizerModule.java | 45 - src/org/traccar/helper/UnitsConverter.java | 88 -- src/org/traccar/model/Attribute.java | 61 - src/org/traccar/model/BaseModel.java | 31 - src/org/traccar/model/Calendar.java | 82 -- src/org/traccar/model/CellTower.java | 115 -- src/org/traccar/model/Command.java | 113 -- src/org/traccar/model/Device.java | 152 --- src/org/traccar/model/DeviceAccumulators.java | 51 - src/org/traccar/model/DeviceState.java | 71 -- src/org/traccar/model/Driver.java | 40 - src/org/traccar/model/Event.java | 104 -- src/org/traccar/model/ExtendedModel.java | 127 -- src/org/traccar/model/Geofence.java | 92 -- src/org/traccar/model/Group.java | 30 - src/org/traccar/model/GroupedModel.java | 31 - src/org/traccar/model/Maintenance.java | 61 - src/org/traccar/model/ManagedUser.java | 21 - src/org/traccar/model/Message.java | 40 - src/org/traccar/model/MiscFormatter.java | 56 - src/org/traccar/model/Network.java | 117 -- src/org/traccar/model/Notification.java | 72 -- src/org/traccar/model/Permission.java | 57 - src/org/traccar/model/Position.java | 302 ----- src/org/traccar/model/ScheduledModel.java | 30 - src/org/traccar/model/Server.java | 169 --- src/org/traccar/model/Statistics.java | 122 -- src/org/traccar/model/Typed.java | 33 - src/org/traccar/model/User.java | 276 ----- src/org/traccar/model/WifiAccessPoint.java | 66 - src/org/traccar/notification/EventForwarder.java | 91 -- src/org/traccar/notification/FullMessage.java | 36 - .../notification/JsonTypeEventForwarder.java | 18 - src/org/traccar/notification/MessageException.java | 29 - .../notification/NotificationFormatter.java | 118 -- .../traccar/notification/NotificatorManager.java | 90 -- .../traccar/notification/PropertiesProvider.java | 81 -- src/org/traccar/notificators/Notificator.java | 44 - .../traccar/notificators/NotificatorFirebase.java | 87 -- src/org/traccar/notificators/NotificatorMail.java | 40 - src/org/traccar/notificators/NotificatorNull.java | 38 - src/org/traccar/notificators/NotificatorSms.java | 62 - src/org/traccar/notificators/NotificatorWeb.java | 30 - src/org/traccar/protocol/AdmProtocol.java | 44 - src/org/traccar/protocol/AdmProtocolDecoder.java | 198 --- src/org/traccar/protocol/AdmProtocolEncoder.java | 39 - src/org/traccar/protocol/AisProtocol.java | 35 - src/org/traccar/protocol/AisProtocolDecoder.java | 140 --- .../traccar/protocol/AlematicsFrameDecoder.java | 50 - src/org/traccar/protocol/AlematicsProtocol.java | 38 - .../traccar/protocol/AlematicsProtocolDecoder.java | 157 --- src/org/traccar/protocol/AnytrekProtocol.java | 35 - .../traccar/protocol/AnytrekProtocolDecoder.java | 120 -- src/org/traccar/protocol/ApelProtocol.java | 36 - src/org/traccar/protocol/ApelProtocolDecoder.java | 210 ---- src/org/traccar/protocol/AplicomFrameDecoder.java | 62 - src/org/traccar/protocol/AplicomProtocol.java | 34 - .../traccar/protocol/AplicomProtocolDecoder.java | 702 ----------- src/org/traccar/protocol/AppelloProtocol.java | 39 - .../traccar/protocol/AppelloProtocolDecoder.java | 92 -- src/org/traccar/protocol/AppletProtocol.java | 39 - .../traccar/protocol/AppletProtocolDecoder.java | 48 - src/org/traccar/protocol/AquilaProtocol.java | 39 - .../traccar/protocol/AquilaProtocolDecoder.java | 403 ------- src/org/traccar/protocol/Ardi01Protocol.java | 39 - .../traccar/protocol/Ardi01ProtocolDecoder.java | 87 -- src/org/traccar/protocol/ArknavProtocol.java | 39 - .../traccar/protocol/ArknavProtocolDecoder.java | 83 -- src/org/traccar/protocol/ArknavX8Protocol.java | 39 - .../traccar/protocol/ArknavX8ProtocolDecoder.java | 139 --- src/org/traccar/protocol/ArnaviProtocol.java | 39 - .../traccar/protocol/ArnaviProtocolDecoder.java | 105 -- src/org/traccar/protocol/AstraProtocol.java | 41 - src/org/traccar/protocol/AstraProtocolDecoder.java | 129 -- src/org/traccar/protocol/At2000FrameDecoder.java | 81 -- src/org/traccar/protocol/At2000Protocol.java | 34 - .../traccar/protocol/At2000ProtocolDecoder.java | 171 --- src/org/traccar/protocol/AtrackFrameDecoder.java | 80 -- src/org/traccar/protocol/AtrackProtocol.java | 45 - .../traccar/protocol/AtrackProtocolDecoder.java | 586 --------- .../traccar/protocol/AtrackProtocolEncoder.java | 38 - src/org/traccar/protocol/AuroProtocol.java | 39 - src/org/traccar/protocol/AuroProtocolDecoder.java | 91 -- src/org/traccar/protocol/AustinNbProtocol.java | 37 - .../traccar/protocol/AustinNbProtocolDecoder.java | 81 -- src/org/traccar/protocol/AutoFonFrameDecoder.java | 65 - src/org/traccar/protocol/AutoFonProtocol.java | 34 - .../traccar/protocol/AutoFonProtocolDecoder.java | 215 ---- src/org/traccar/protocol/AutoGradeProtocol.java | 39 - .../traccar/protocol/AutoGradeProtocolDecoder.java | 107 -- src/org/traccar/protocol/AutoTrackProtocol.java | 36 - .../traccar/protocol/AutoTrackProtocolDecoder.java | 138 --- src/org/traccar/protocol/AvemaProtocol.java | 39 - src/org/traccar/protocol/AvemaProtocolDecoder.java | 107 -- src/org/traccar/protocol/Avl301Protocol.java | 35 - .../traccar/protocol/Avl301ProtocolDecoder.java | 145 --- src/org/traccar/protocol/BceFrameDecoder.java | 59 - src/org/traccar/protocol/BceProtocol.java | 38 - src/org/traccar/protocol/BceProtocolDecoder.java | 175 --- src/org/traccar/protocol/BceProtocolEncoder.java | 47 - src/org/traccar/protocol/BlackKiteProtocol.java | 35 - .../traccar/protocol/BlackKiteProtocolDecoder.java | 195 --- src/org/traccar/protocol/BoxProtocol.java | 39 - src/org/traccar/protocol/BoxProtocolDecoder.java | 108 -- src/org/traccar/protocol/C2stekProtocol.java | 39 - .../traccar/protocol/C2stekProtocolDecoder.java | 121 -- src/org/traccar/protocol/CalAmpProtocol.java | 33 - .../traccar/protocol/CalAmpProtocolDecoder.java | 202 ---- src/org/traccar/protocol/CarTrackProtocol.java | 39 - .../traccar/protocol/CarTrackProtocolDecoder.java | 108 -- src/org/traccar/protocol/CarcellProtocol.java | 44 - .../traccar/protocol/CarcellProtocolDecoder.java | 164 --- .../traccar/protocol/CarcellProtocolEncoder.java | 36 - src/org/traccar/protocol/CarscopProtocol.java | 39 - .../traccar/protocol/CarscopProtocolDecoder.java | 101 -- src/org/traccar/protocol/CastelProtocol.java | 48 - .../traccar/protocol/CastelProtocolDecoder.java | 573 --------- .../traccar/protocol/CastelProtocolEncoder.java | 70 -- src/org/traccar/protocol/CautelaProtocol.java | 39 - .../traccar/protocol/CautelaProtocolDecoder.java | 78 -- .../traccar/protocol/CellocatorFrameDecoder.java | 66 - src/org/traccar/protocol/CellocatorProtocol.java | 45 - .../protocol/CellocatorProtocolDecoder.java | 177 --- .../protocol/CellocatorProtocolEncoder.java | 66 - src/org/traccar/protocol/CguardProtocol.java | 39 - .../traccar/protocol/CguardProtocolDecoder.java | 147 --- src/org/traccar/protocol/CityeasyProtocol.java | 42 - .../traccar/protocol/CityeasyProtocolDecoder.java | 127 -- .../traccar/protocol/CityeasyProtocolEncoder.java | 73 -- src/org/traccar/protocol/ContinentalProtocol.java | 35 - .../protocol/ContinentalProtocolDecoder.java | 114 -- src/org/traccar/protocol/CradlepointProtocol.java | 39 - .../protocol/CradlepointProtocolDecoder.java | 95 -- src/org/traccar/protocol/DishaProtocol.java | 39 - src/org/traccar/protocol/DishaProtocolDecoder.java | 102 -- src/org/traccar/protocol/DmtHttpProtocol.java | 39 - .../traccar/protocol/DmtHttpProtocolDecoder.java | 133 -- src/org/traccar/protocol/DmtProtocol.java | 36 - src/org/traccar/protocol/DmtProtocolDecoder.java | 289 ----- src/org/traccar/protocol/DwayProtocol.java | 39 - src/org/traccar/protocol/DwayProtocolDecoder.java | 103 -- src/org/traccar/protocol/EasyTrackProtocol.java | 39 - .../traccar/protocol/EasyTrackProtocolDecoder.java | 138 --- src/org/traccar/protocol/EelinkProtocol.java | 50 - .../traccar/protocol/EelinkProtocolDecoder.java | 441 ------- .../traccar/protocol/EelinkProtocolEncoder.java | 107 -- src/org/traccar/protocol/EgtsFrameDecoder.java | 45 - src/org/traccar/protocol/EgtsProtocol.java | 34 - src/org/traccar/protocol/EgtsProtocolDecoder.java | 265 ---- src/org/traccar/protocol/EnforaProtocol.java | 48 - .../traccar/protocol/EnforaProtocolDecoder.java | 115 -- .../traccar/protocol/EnforaProtocolEncoder.java | 55 - src/org/traccar/protocol/EsealProtocol.java | 45 - src/org/traccar/protocol/EsealProtocolDecoder.java | 158 --- src/org/traccar/protocol/EsealProtocolEncoder.java | 41 - src/org/traccar/protocol/EskyFrameDecoder.java | 39 - src/org/traccar/protocol/EskyProtocol.java | 38 - src/org/traccar/protocol/EskyProtocolDecoder.java | 94 -- src/org/traccar/protocol/ExtremTracProtocol.java | 39 - .../protocol/ExtremTracProtocolDecoder.java | 83 -- src/org/traccar/protocol/FifotrackProtocol.java | 39 - .../traccar/protocol/FifotrackProtocolDecoder.java | 198 --- src/org/traccar/protocol/FlespiProtocol.java | 38 - .../traccar/protocol/FlespiProtocolDecoder.java | 246 ---- src/org/traccar/protocol/FlexCommProtocol.java | 39 - .../traccar/protocol/FlexCommProtocolDecoder.java | 128 -- src/org/traccar/protocol/FlextrackProtocol.java | 39 - .../traccar/protocol/FlextrackProtocolDecoder.java | 144 --- src/org/traccar/protocol/FoxProtocol.java | 39 - src/org/traccar/protocol/FoxProtocolDecoder.java | 124 -- src/org/traccar/protocol/FreedomProtocol.java | 39 - .../traccar/protocol/FreedomProtocolDecoder.java | 77 -- src/org/traccar/protocol/FreematicsProtocol.java | 37 - .../protocol/FreematicsProtocolDecoder.java | 184 --- src/org/traccar/protocol/GalileoFrameDecoder.java | 43 - src/org/traccar/protocol/GalileoProtocol.java | 39 - .../traccar/protocol/GalileoProtocolDecoder.java | 342 ------ .../traccar/protocol/GalileoProtocolEncoder.java | 67 -- src/org/traccar/protocol/GatorProtocol.java | 41 - src/org/traccar/protocol/GatorProtocolDecoder.java | 133 -- src/org/traccar/protocol/GenxProtocol.java | 37 - src/org/traccar/protocol/GenxProtocolDecoder.java | 99 -- src/org/traccar/protocol/Gl100Protocol.java | 47 - src/org/traccar/protocol/Gl100ProtocolDecoder.java | 97 -- .../protocol/Gl200BinaryProtocolDecoder.java | 403 ------- src/org/traccar/protocol/Gl200FrameDecoder.java | 97 -- src/org/traccar/protocol/Gl200Protocol.java | 53 - src/org/traccar/protocol/Gl200ProtocolDecoder.java | 50 - src/org/traccar/protocol/Gl200ProtocolEncoder.java | 46 - .../traccar/protocol/Gl200TextProtocolDecoder.java | 1266 -------------------- src/org/traccar/protocol/GlobalSatProtocol.java | 39 - .../traccar/protocol/GlobalSatProtocolDecoder.java | 248 ---- src/org/traccar/protocol/GnxProtocol.java | 39 - src/org/traccar/protocol/GnxProtocolDecoder.java | 111 -- src/org/traccar/protocol/GoSafeProtocol.java | 39 - .../traccar/protocol/GoSafeProtocolDecoder.java | 269 ----- src/org/traccar/protocol/GotopProtocol.java | 39 - src/org/traccar/protocol/GotopProtocolDecoder.java | 82 -- src/org/traccar/protocol/Gps056FrameDecoder.java | 47 - src/org/traccar/protocol/Gps056Protocol.java | 34 - .../traccar/protocol/Gps056ProtocolDecoder.java | 140 --- src/org/traccar/protocol/Gps103Protocol.java | 60 - .../traccar/protocol/Gps103ProtocolDecoder.java | 422 ------- .../traccar/protocol/Gps103ProtocolEncoder.java | 68 -- src/org/traccar/protocol/GpsGateProtocol.java | 39 - .../traccar/protocol/GpsGateProtocolDecoder.java | 170 --- src/org/traccar/protocol/GpsMarkerProtocol.java | 39 - .../traccar/protocol/GpsMarkerProtocolDecoder.java | 90 -- src/org/traccar/protocol/GpsmtaProtocol.java | 37 - .../traccar/protocol/GpsmtaProtocolDecoder.java | 92 -- src/org/traccar/protocol/GranitFrameDecoder.java | 47 - src/org/traccar/protocol/GranitProtocol.java | 45 - .../traccar/protocol/GranitProtocolDecoder.java | 239 ---- .../traccar/protocol/GranitProtocolEncoder.java | 48 - .../traccar/protocol/GranitProtocolSmsEncoder.java | 36 - src/org/traccar/protocol/Gt02Protocol.java | 35 - src/org/traccar/protocol/Gt02ProtocolDecoder.java | 125 -- src/org/traccar/protocol/Gt06FrameDecoder.java | 56 - src/org/traccar/protocol/Gt06Protocol.java | 40 - src/org/traccar/protocol/Gt06ProtocolDecoder.java | 929 -------------- src/org/traccar/protocol/Gt06ProtocolEncoder.java | 78 -- src/org/traccar/protocol/Gt30Protocol.java | 39 - src/org/traccar/protocol/Gt30ProtocolDecoder.java | 114 -- src/org/traccar/protocol/H02FrameDecoder.java | 95 -- src/org/traccar/protocol/H02Protocol.java | 54 - src/org/traccar/protocol/H02ProtocolDecoder.java | 583 --------- src/org/traccar/protocol/H02ProtocolEncoder.java | 73 -- src/org/traccar/protocol/HaicomProtocol.java | 39 - .../traccar/protocol/HaicomProtocolDecoder.java | 109 -- src/org/traccar/protocol/HomtecsProtocol.java | 37 - .../traccar/protocol/HomtecsProtocolDecoder.java | 91 -- src/org/traccar/protocol/HuaShengFrameDecoder.java | 58 - src/org/traccar/protocol/HuaShengProtocol.java | 34 - .../traccar/protocol/HuaShengProtocolDecoder.java | 155 --- src/org/traccar/protocol/HuabaoFrameDecoder.java | 58 - src/org/traccar/protocol/HuabaoProtocol.java | 39 - .../traccar/protocol/HuabaoProtocolDecoder.java | 235 ---- .../traccar/protocol/HuabaoProtocolEncoder.java | 73 -- src/org/traccar/protocol/HunterProProtocol.java | 39 - .../traccar/protocol/HunterProProtocolDecoder.java | 83 -- src/org/traccar/protocol/IdplProtocol.java | 39 - src/org/traccar/protocol/IdplProtocolDecoder.java | 112 -- .../traccar/protocol/IntellitracFrameDecoder.java | 52 - src/org/traccar/protocol/IntellitracProtocol.java | 38 - .../protocol/IntellitracProtocolDecoder.java | 117 -- src/org/traccar/protocol/ItsProtocol.java | 39 - src/org/traccar/protocol/ItsProtocolDecoder.java | 170 --- src/org/traccar/protocol/Ivt401Protocol.java | 37 - .../traccar/protocol/Ivt401ProtocolDecoder.java | 183 --- src/org/traccar/protocol/JpKorjarFrameDecoder.java | 47 - src/org/traccar/protocol/JpKorjarProtocol.java | 37 - .../traccar/protocol/JpKorjarProtocolDecoder.java | 89 -- src/org/traccar/protocol/Jt600FrameDecoder.java | 55 - src/org/traccar/protocol/Jt600Protocol.java | 43 - src/org/traccar/protocol/Jt600ProtocolDecoder.java | 375 ------ src/org/traccar/protocol/Jt600ProtocolEncoder.java | 43 - src/org/traccar/protocol/KenjiProtocol.java | 40 - src/org/traccar/protocol/KenjiProtocolDecoder.java | 110 -- src/org/traccar/protocol/KhdProtocol.java | 40 - src/org/traccar/protocol/KhdProtocolDecoder.java | 157 --- src/org/traccar/protocol/KhdProtocolEncoder.java | 67 -- src/org/traccar/protocol/L100FrameDecoder.java | 90 -- src/org/traccar/protocol/L100Protocol.java | 38 - src/org/traccar/protocol/L100ProtocolDecoder.java | 341 ------ src/org/traccar/protocol/LaipacProtocol.java | 39 - .../traccar/protocol/LaipacProtocolDecoder.java | 167 --- src/org/traccar/protocol/M2cProtocol.java | 39 - src/org/traccar/protocol/M2cProtocolDecoder.java | 131 -- src/org/traccar/protocol/M2mProtocol.java | 35 - src/org/traccar/protocol/M2mProtocolDecoder.java | 127 -- src/org/traccar/protocol/MaestroProtocol.java | 39 - .../traccar/protocol/MaestroProtocolDecoder.java | 103 -- src/org/traccar/protocol/ManPowerProtocol.java | 39 - .../traccar/protocol/ManPowerProtocolDecoder.java | 81 -- src/org/traccar/protocol/MegastekFrameDecoder.java | 59 - src/org/traccar/protocol/MegastekProtocol.java | 38 - .../traccar/protocol/MegastekProtocolDecoder.java | 419 ------- src/org/traccar/protocol/MeiligaoFrameDecoder.java | 47 - src/org/traccar/protocol/MeiligaoProtocol.java | 52 - .../traccar/protocol/MeiligaoProtocolDecoder.java | 499 -------- .../traccar/protocol/MeiligaoProtocolEncoder.java | 86 -- src/org/traccar/protocol/MeitrackFrameDecoder.java | 47 - src/org/traccar/protocol/MeitrackProtocol.java | 54 - .../traccar/protocol/MeitrackProtocolDecoder.java | 534 --------- .../traccar/protocol/MeitrackProtocolEncoder.java | 65 - src/org/traccar/protocol/MilesmateProtocol.java | 39 - .../traccar/protocol/MilesmateProtocolDecoder.java | 108 -- src/org/traccar/protocol/MiniFinderProtocol.java | 53 - .../protocol/MiniFinderProtocolDecoder.java | 208 ---- .../protocol/MiniFinderProtocolEncoder.java | 82 -- src/org/traccar/protocol/Mta6Protocol.java | 41 - src/org/traccar/protocol/Mta6ProtocolDecoder.java | 319 ----- src/org/traccar/protocol/MtxProtocol.java | 39 - src/org/traccar/protocol/MtxProtocolDecoder.java | 98 -- src/org/traccar/protocol/MxtFrameDecoder.java | 53 - src/org/traccar/protocol/MxtProtocol.java | 34 - src/org/traccar/protocol/MxtProtocolDecoder.java | 175 --- src/org/traccar/protocol/NavigilFrameDecoder.java | 56 - src/org/traccar/protocol/NavigilProtocol.java | 34 - .../traccar/protocol/NavigilProtocolDecoder.java | 308 ----- src/org/traccar/protocol/NavisFrameDecoder.java | 109 -- src/org/traccar/protocol/NavisProtocol.java | 33 - src/org/traccar/protocol/NavisProtocolDecoder.java | 683 ----------- src/org/traccar/protocol/NeosProtocol.java | 37 - src/org/traccar/protocol/NeosProtocolDecoder.java | 98 -- src/org/traccar/protocol/NoranProtocol.java | 41 - src/org/traccar/protocol/NoranProtocolDecoder.java | 164 --- src/org/traccar/protocol/NoranProtocolEncoder.java | 64 - src/org/traccar/protocol/NvsFrameDecoder.java | 47 - src/org/traccar/protocol/NvsProtocol.java | 34 - src/org/traccar/protocol/NvsProtocolDecoder.java | 137 --- src/org/traccar/protocol/NyitechProtocol.java | 37 - .../traccar/protocol/NyitechProtocolDecoder.java | 123 -- src/org/traccar/protocol/ObdDongleProtocol.java | 35 - .../traccar/protocol/ObdDongleProtocolDecoder.java | 130 -- src/org/traccar/protocol/OigoProtocol.java | 33 - src/org/traccar/protocol/OigoProtocolDecoder.java | 240 ---- src/org/traccar/protocol/OkoProtocol.java | 37 - src/org/traccar/protocol/OkoProtocolDecoder.java | 100 -- src/org/traccar/protocol/OpenGtsProtocol.java | 39 - .../traccar/protocol/OpenGtsProtocolDecoder.java | 115 -- src/org/traccar/protocol/OrionFrameDecoder.java | 68 -- src/org/traccar/protocol/OrionProtocol.java | 34 - src/org/traccar/protocol/OrionProtocolDecoder.java | 115 -- src/org/traccar/protocol/OsmAndProtocol.java | 39 - .../traccar/protocol/OsmAndProtocolDecoder.java | 184 --- src/org/traccar/protocol/OwnTracksProtocol.java | 40 - .../traccar/protocol/OwnTracksProtocolDecoder.java | 215 ---- src/org/traccar/protocol/PathAwayProtocol.java | 39 - .../traccar/protocol/PathAwayProtocolDecoder.java | 97 -- src/org/traccar/protocol/PiligrimProtocol.java | 39 - .../traccar/protocol/PiligrimProtocolDecoder.java | 167 --- src/org/traccar/protocol/PretraceProtocol.java | 44 - .../traccar/protocol/PretraceProtocolDecoder.java | 132 -- .../traccar/protocol/PretraceProtocolEncoder.java | 46 - src/org/traccar/protocol/PricolProtocol.java | 41 - .../traccar/protocol/PricolProtocolDecoder.java | 98 -- src/org/traccar/protocol/ProgressProtocol.java | 36 - .../traccar/protocol/ProgressProtocolDecoder.java | 172 --- src/org/traccar/protocol/Pt3000Protocol.java | 39 - .../traccar/protocol/Pt3000ProtocolDecoder.java | 83 -- src/org/traccar/protocol/Pt502FrameDecoder.java | 73 -- src/org/traccar/protocol/Pt502Protocol.java | 44 - src/org/traccar/protocol/Pt502ProtocolDecoder.java | 212 ---- src/org/traccar/protocol/Pt502ProtocolEncoder.java | 58 - src/org/traccar/protocol/Pt60Protocol.java | 39 - src/org/traccar/protocol/Pt60ProtocolDecoder.java | 184 --- src/org/traccar/protocol/RaveonProtocol.java | 39 - .../traccar/protocol/RaveonProtocolDecoder.java | 99 -- src/org/traccar/protocol/RecodaProtocol.java | 36 - .../traccar/protocol/RecodaProtocolDecoder.java | 110 -- .../traccar/protocol/RetranslatorFrameDecoder.java | 37 - src/org/traccar/protocol/RetranslatorProtocol.java | 34 - .../protocol/RetranslatorProtocolDecoder.java | 114 -- src/org/traccar/protocol/RitiProtocol.java | 36 - src/org/traccar/protocol/RitiProtocolDecoder.java | 102 -- .../traccar/protocol/RoboTrackFrameDecoder.java | 57 - src/org/traccar/protocol/RoboTrackProtocol.java | 34 - .../traccar/protocol/RoboTrackProtocolDecoder.java | 131 -- src/org/traccar/protocol/RuptelaProtocol.java | 45 - .../traccar/protocol/RuptelaProtocolDecoder.java | 248 ---- .../traccar/protocol/RuptelaProtocolEncoder.java | 73 -- src/org/traccar/protocol/SabertekFrameDecoder.java | 44 - src/org/traccar/protocol/SabertekProtocol.java | 36 - .../traccar/protocol/SabertekProtocolDecoder.java | 135 --- src/org/traccar/protocol/SanavProtocol.java | 45 - src/org/traccar/protocol/SanavProtocolDecoder.java | 107 -- src/org/traccar/protocol/SatsolProtocol.java | 37 - .../traccar/protocol/SatsolProtocolDecoder.java | 104 -- src/org/traccar/protocol/SigfoxProtocol.java | 39 - .../traccar/protocol/SigfoxProtocolDecoder.java | 92 -- src/org/traccar/protocol/SiwiProtocol.java | 37 - src/org/traccar/protocol/SiwiProtocolDecoder.java | 96 -- src/org/traccar/protocol/SkypatrolProtocol.java | 33 - .../traccar/protocol/SkypatrolProtocolDecoder.java | 193 --- src/org/traccar/protocol/SmartSoleProtocol.java | 39 - .../traccar/protocol/SmartSoleProtocolDecoder.java | 91 -- src/org/traccar/protocol/SmokeyProtocol.java | 33 - .../traccar/protocol/SmokeyProtocolDecoder.java | 161 --- src/org/traccar/protocol/SpotProtocol.java | 39 - src/org/traccar/protocol/SpotProtocolDecoder.java | 102 -- src/org/traccar/protocol/StarLinkProtocol.java | 39 - .../traccar/protocol/StarLinkProtocolDecoder.java | 229 ---- src/org/traccar/protocol/Stl060FrameDecoder.java | 48 - src/org/traccar/protocol/Stl060Protocol.java | 38 - .../traccar/protocol/Stl060ProtocolDecoder.java | 120 -- src/org/traccar/protocol/SuntechProtocol.java | 49 - .../traccar/protocol/SuntechProtocolDecoder.java | 467 -------- .../traccar/protocol/SuntechProtocolEncoder.java | 54 - src/org/traccar/protocol/SupermateProtocol.java | 39 - .../traccar/protocol/SupermateProtocolDecoder.java | 122 -- src/org/traccar/protocol/SviasProtocol.java | 51 - src/org/traccar/protocol/SviasProtocolDecoder.java | 105 -- src/org/traccar/protocol/SviasProtocolEncoder.java | 48 - src/org/traccar/protocol/T55Protocol.java | 47 - src/org/traccar/protocol/T55ProtocolDecoder.java | 283 ----- src/org/traccar/protocol/T57FrameDecoder.java | 49 - src/org/traccar/protocol/T57Protocol.java | 38 - src/org/traccar/protocol/T57ProtocolDecoder.java | 84 -- src/org/traccar/protocol/T800xProtocol.java | 39 - src/org/traccar/protocol/T800xProtocolDecoder.java | 199 --- src/org/traccar/protocol/T800xProtocolEncoder.java | 59 - src/org/traccar/protocol/TaipProtocol.java | 47 - src/org/traccar/protocol/TaipProtocolDecoder.java | 287 ----- src/org/traccar/protocol/TekFrameDecoder.java | 42 - src/org/traccar/protocol/TekProtocol.java | 34 - src/org/traccar/protocol/TekProtocolDecoder.java | 139 --- src/org/traccar/protocol/TelemaxProtocol.java | 39 - .../traccar/protocol/TelemaxProtocolDecoder.java | 112 -- src/org/traccar/protocol/TelicFrameDecoder.java | 55 - src/org/traccar/protocol/TelicProtocol.java | 38 - src/org/traccar/protocol/TelicProtocolDecoder.java | 135 --- .../traccar/protocol/TeltonikaFrameDecoder.java | 53 - src/org/traccar/protocol/TeltonikaProtocol.java | 45 - .../traccar/protocol/TeltonikaProtocolDecoder.java | 597 --------- .../traccar/protocol/TeltonikaProtocolEncoder.java | 59 - src/org/traccar/protocol/ThinkRaceProtocol.java | 35 - .../traccar/protocol/ThinkRaceProtocolDecoder.java | 116 -- src/org/traccar/protocol/Tk102Protocol.java | 35 - src/org/traccar/protocol/Tk102ProtocolDecoder.java | 144 --- src/org/traccar/protocol/Tk103FrameDecoder.java | 75 -- src/org/traccar/protocol/Tk103Protocol.java | 69 -- src/org/traccar/protocol/Tk103ProtocolDecoder.java | 453 ------- src/org/traccar/protocol/Tk103ProtocolEncoder.java | 110 -- src/org/traccar/protocol/Tlt2hProtocol.java | 39 - src/org/traccar/protocol/Tlt2hProtocolDecoder.java | 152 --- src/org/traccar/protocol/TlvProtocol.java | 35 - src/org/traccar/protocol/TlvProtocolDecoder.java | 110 -- src/org/traccar/protocol/TmgFrameDecoder.java | 67 -- src/org/traccar/protocol/TmgProtocol.java | 38 - src/org/traccar/protocol/TmgProtocolDecoder.java | 194 --- src/org/traccar/protocol/TopflytechProtocol.java | 39 - .../protocol/TopflytechProtocolDecoder.java | 76 -- src/org/traccar/protocol/TotemFrameDecoder.java | 59 - src/org/traccar/protocol/TotemProtocol.java | 44 - src/org/traccar/protocol/TotemProtocolDecoder.java | 444 ------- src/org/traccar/protocol/TotemProtocolEncoder.java | 40 - src/org/traccar/protocol/Tr20Protocol.java | 39 - src/org/traccar/protocol/Tr20ProtocolDecoder.java | 103 -- src/org/traccar/protocol/Tr900Protocol.java | 47 - src/org/traccar/protocol/Tr900ProtocolDecoder.java | 94 -- src/org/traccar/protocol/TrackboxProtocol.java | 39 - .../traccar/protocol/TrackboxProtocolDecoder.java | 110 -- src/org/traccar/protocol/TrakMateProtocol.java | 39 - .../traccar/protocol/TrakMateProtocolDecoder.java | 233 ---- src/org/traccar/protocol/TramigoFrameDecoder.java | 46 - src/org/traccar/protocol/TramigoProtocol.java | 34 - .../traccar/protocol/TramigoProtocolDecoder.java | 160 --- src/org/traccar/protocol/TrvProtocol.java | 39 - src/org/traccar/protocol/TrvProtocolDecoder.java | 258 ---- src/org/traccar/protocol/Tt8850Protocol.java | 39 - .../traccar/protocol/Tt8850ProtocolDecoder.java | 99 -- src/org/traccar/protocol/TytanProtocol.java | 33 - src/org/traccar/protocol/TytanProtocolDecoder.java | 192 --- src/org/traccar/protocol/TzoneProtocol.java | 36 - src/org/traccar/protocol/TzoneProtocolDecoder.java | 293 ----- src/org/traccar/protocol/UlbotechFrameDecoder.java | 70 -- src/org/traccar/protocol/UlbotechProtocol.java | 34 - .../traccar/protocol/UlbotechProtocolDecoder.java | 371 ------ src/org/traccar/protocol/UproProtocol.java | 37 - src/org/traccar/protocol/UproProtocolDecoder.java | 212 ---- src/org/traccar/protocol/V680Protocol.java | 47 - src/org/traccar/protocol/V680ProtocolDecoder.java | 132 -- src/org/traccar/protocol/VisiontekProtocol.java | 39 - .../traccar/protocol/VisiontekProtocolDecoder.java | 138 --- src/org/traccar/protocol/Vt200FrameDecoder.java | 52 - src/org/traccar/protocol/Vt200Protocol.java | 34 - src/org/traccar/protocol/Vt200ProtocolDecoder.java | 150 --- src/org/traccar/protocol/VtfmsFrameDecoder.java | 41 - src/org/traccar/protocol/VtfmsProtocol.java | 44 - src/org/traccar/protocol/VtfmsProtocolDecoder.java | 167 --- src/org/traccar/protocol/WatchFrameDecoder.java | 67 -- src/org/traccar/protocol/WatchProtocol.java | 53 - src/org/traccar/protocol/WatchProtocolDecoder.java | 329 ----- src/org/traccar/protocol/WatchProtocolEncoder.java | 167 --- src/org/traccar/protocol/WialonProtocol.java | 54 - .../traccar/protocol/WialonProtocolDecoder.java | 196 --- .../traccar/protocol/WialonProtocolEncoder.java | 40 - src/org/traccar/protocol/WondexFrameDecoder.java | 62 - src/org/traccar/protocol/WondexProtocol.java | 55 - .../traccar/protocol/WondexProtocolDecoder.java | 128 -- .../traccar/protocol/WondexProtocolEncoder.java | 46 - src/org/traccar/protocol/WristbandProtocol.java | 35 - .../traccar/protocol/WristbandProtocolDecoder.java | 207 ---- src/org/traccar/protocol/XexunFrameDecoder.java | 58 - src/org/traccar/protocol/XexunProtocol.java | 51 - src/org/traccar/protocol/XexunProtocolDecoder.java | 152 --- src/org/traccar/protocol/XexunProtocolEncoder.java | 38 - src/org/traccar/protocol/XirgoProtocol.java | 53 - src/org/traccar/protocol/XirgoProtocolDecoder.java | 355 ------ src/org/traccar/protocol/XirgoProtocolEncoder.java | 34 - src/org/traccar/protocol/Xrb28Protocol.java | 49 - src/org/traccar/protocol/Xrb28ProtocolDecoder.java | 187 --- src/org/traccar/protocol/Xrb28ProtocolEncoder.java | 52 - src/org/traccar/protocol/Xt013Protocol.java | 40 - src/org/traccar/protocol/Xt013ProtocolDecoder.java | 94 -- src/org/traccar/protocol/Xt2400Protocol.java | 33 - .../traccar/protocol/Xt2400ProtocolDecoder.java | 198 --- src/org/traccar/protocol/YwtProtocol.java | 39 - src/org/traccar/protocol/YwtProtocolDecoder.java | 116 -- src/org/traccar/reports/Events.java | 133 -- src/org/traccar/reports/ReportUtils.java | 378 ------ src/org/traccar/reports/Route.java | 85 -- src/org/traccar/reports/Stops.java | 102 -- src/org/traccar/reports/Summary.java | 117 -- src/org/traccar/reports/Trips.java | 100 -- src/org/traccar/reports/model/BaseReport.java | 106 -- src/org/traccar/reports/model/DeviceReport.java | 55 - src/org/traccar/reports/model/StopReport.java | 106 -- src/org/traccar/reports/model/SummaryReport.java | 34 - src/org/traccar/reports/model/TripReport.java | 152 --- src/org/traccar/reports/model/TripsConfig.java | 105 -- src/org/traccar/sms/HttpSmsClient.java | 110 -- src/org/traccar/sms/SmsManager.java | 29 - .../traccar/sms/smpp/ClientSmppSessionHandler.java | 82 -- src/org/traccar/sms/smpp/EnquireLinkTask.java | 59 - src/org/traccar/sms/smpp/ReconnectionTask.java | 32 - src/org/traccar/sms/smpp/SmppClient.java | 272 ----- .../traccar/sms/smpp/TextMessageEventHandler.java | 37 - src/org/traccar/web/ConsoleServlet.java | 61 - src/org/traccar/web/CsvBuilder.java | 164 --- src/org/traccar/web/GpxBuilder.java | 69 -- src/org/traccar/web/WebServer.java | 173 --- src/test/java/org/traccar/BaseTest.java | 34 + src/test/java/org/traccar/ProtocolTest.java | 324 +++++ src/test/java/org/traccar/TestIdentityManager.java | 72 ++ src/test/java/org/traccar/WebDataHandlerTest.java | 28 + .../java/org/traccar/calendar/CalendarTest.java | 59 + src/test/java/org/traccar/config/ConfigTest.java | 19 + .../java/org/traccar/database/DataManagerTest.java | 81 ++ .../java/org/traccar/database/GroupTreeTest.java | 56 + .../org/traccar/geocoder/AddressFormatTest.java | 33 + .../java/org/traccar/geocoder/GeocoderTest.java | 88 ++ .../org/traccar/geofence/GeofenceCircleTest.java | 28 + .../org/traccar/geofence/GeofencePolygonTest.java | 52 + .../org/traccar/geofence/GeofencePolylineTest.java | 47 + .../geolocation/GeolocationProviderTest.java | 41 + .../traccar/handler/ComputedAttributesTest.java | 71 ++ .../org/traccar/handler/DistanceHandlerTest.java | 30 + .../org/traccar/handler/FilterHandlerTest.java | 88 ++ .../org/traccar/handler/MotionHandlerTest.java | 21 + .../handler/events/AlertEventHandlerTest.java | 30 + .../events/CommandResultEventHandlerTest.java | 28 + .../handler/events/IgnitionEventHandlerTest.java | 27 + .../handler/events/MotionEventHandlerTest.java | 119 ++ .../handler/events/OverspeedEventHandlerTest.java | 128 ++ src/test/java/org/traccar/helper/BcdUtilTest.java | 24 + .../java/org/traccar/helper/BitBufferTest.java | 23 + src/test/java/org/traccar/helper/BitUtilTest.java | 38 + src/test/java/org/traccar/helper/ChecksumTest.java | 39 + .../java/org/traccar/helper/DateBuilderTest.java | 27 + src/test/java/org/traccar/helper/DateUtilTest.java | 30 + .../org/traccar/helper/DistanceCalculatorTest.java | 24 + .../java/org/traccar/helper/LocationTreeTest.java | 30 + src/test/java/org/traccar/helper/LogTest.java | 14 + .../java/org/traccar/helper/ObdDecoderTest.java | 26 + .../org/traccar/helper/PatternBuilderTest.java | 20 + .../java/org/traccar/helper/PatternUtilTest.java | 18 + .../java/org/traccar/model/MiscFormatterTest.java | 20 + .../notification/NotificiationMailTest.java | 59 + .../traccar/protocol/AdmProtocolDecoderTest.java | 38 + .../traccar/protocol/AdmProtocolEncoderTest.java | 44 + .../traccar/protocol/AisProtocolDecoderTest.java | 31 + .../protocol/AlematicsProtocolDecoderTest.java | 42 + .../protocol/AnytrekProtocolDecoderTest.java | 21 + .../traccar/protocol/ApelProtocolDecoderTest.java | 25 + .../traccar/protocol/AplicomFrameDecoderTest.java | 25 + .../protocol/AplicomProtocolDecoderTest.java | 93 ++ .../protocol/AppelloProtocolDecoderTest.java | 30 + .../protocol/AppletProtocolDecoderTest.java | 27 + .../protocol/AquilaProtocolDecoderTest.java | 79 ++ .../protocol/Ardi01ProtocolDecoderTest.java | 22 + .../protocol/ArknavProtocolDecoderTest.java | 25 + .../protocol/ArknavX8ProtocolDecoderTest.java | 45 + .../protocol/ArnaviProtocolDecoderTest.java | 42 + .../traccar/protocol/AstraProtocolDecoderTest.java | 24 + .../traccar/protocol/At2000FrameDecoderTest.java | 23 + .../protocol/At2000ProtocolDecoderTest.java | 59 + .../traccar/protocol/AtrackFrameDecoderTest.java | 39 + .../protocol/AtrackProtocolDecoderTest.java | 99 ++ .../traccar/protocol/AuroProtocolDecoderTest.java | 24 + .../protocol/AustinNbProtocolDecoderTest.java | 33 + .../protocol/AutoFonProtocolDecoderTest.java | 41 + .../protocol/AutoGradeProtocolDecoderTest.java | 21 + .../protocol/AutoTrackProtocolDecoderTest.java | 18 + .../traccar/protocol/AvemaProtocolDecoderTest.java | 21 + .../protocol/Avl301ProtocolDecoderTest.java | 25 + .../traccar/protocol/BceProtocolDecoderTest.java | 39 + .../traccar/protocol/BceProtocolEncoderTest.java | 24 + .../protocol/BlackKiteProtocolDecoderTest.java | 21 + .../traccar/protocol/BoxProtocolDecoderTest.java | 67 ++ .../protocol/C2stekProtocolDecoderTest.java | 24 + .../protocol/CalAmpProtocolDecoderTest.java | 54 + .../protocol/CarTrackProtocolDecoderTest.java | 32 + .../protocol/CarscopProtocolDecoderTest.java | 46 + .../protocol/CastelProtocolDecoderTest.java | 144 +++ .../protocol/CastelProtocolEncoderTest.java | 22 + .../protocol/CautelaProtocolDecoderTest.java | 18 + .../protocol/CellocatorProtocolDecoderTest.java | 33 + .../protocol/CellocatorProtocolEncoderTest.java | 26 + .../protocol/CguardProtocolDecoderTest.java | 78 ++ .../protocol/CityeasyProtocolDecoderTest.java | 41 + .../protocol/CityeasyProtocolEncoderTest.java | 23 + .../protocol/ContinentalProtocolDecoderTest.java | 29 + .../protocol/CradlepointProtocolDecoderTest.java | 36 + .../traccar/protocol/DishaProtocolDecoderTest.java | 25 + .../protocol/DmtHttpProtocolDecoderTest.java | 19 + .../traccar/protocol/DmtProtocolDecoderTest.java | 42 + .../traccar/protocol/DwayProtocolDecoderTest.java | 30 + .../protocol/EasyTrackProtocolDecoderTest.java | 55 + .../protocol/EelinkProtocolDecoderTest.java | 114 ++ .../protocol/EelinkProtocolEncoderTest.java | 22 + .../org/traccar/protocol/EgtsFrameDecoderTest.java | 19 + .../traccar/protocol/EgtsProtocolDecoderTest.java | 37 + .../protocol/EnforaProtocolDecoderTest.java | 31 + .../traccar/protocol/EsealProtocolDecoderTest.java | 33 + .../traccar/protocol/EsealProtocolEncoderTest.java | 24 + .../org/traccar/protocol/EskyFrameDecoderTest.java | 31 + .../traccar/protocol/EskyProtocolDecoderTest.java | 30 + .../protocol/ExtremTracProtocolDecoderTest.java | 33 + .../protocol/FifotrackProtocolDecoderTest.java | 30 + .../protocol/FlespiProtocolDecoderTest.java | 24 + .../protocol/FlexCommProtocolDecoderTest.java | 21 + .../protocol/FlextrackProtocolDecoderTest.java | 32 + .../traccar/protocol/FoxProtocolDecoderTest.java | 30 + .../protocol/FreedomProtocolDecoderTest.java | 22 + .../protocol/FreematicsProtocolDecoderTest.java | 36 + .../traccar/protocol/GalileoFrameDecoderTest.java | 25 + .../protocol/GalileoProtocolDecoderTest.java | 45 + .../protocol/GalileoProtocolEncoderTest.java | 23 + .../traccar/protocol/GatorProtocolDecoderTest.java | 50 + .../traccar/protocol/GenxProtocolDecoderTest.java | 36 + .../traccar/protocol/Gl100ProtocolDecoderTest.java | 56 + .../protocol/Gl200BinaryProtocolDecoderTest.java | 36 + .../traccar/protocol/Gl200FrameDecoderTest.java | 29 + .../protocol/Gl200TextProtocolDecoderTest.java | 390 ++++++ .../protocol/GlobalSatProtocolDecoderTest.java | 56 + .../traccar/protocol/GnxProtocolDecoderTest.java | 30 + .../protocol/GoSafeProtocolDecoderTest.java | 87 ++ .../traccar/protocol/GotopProtocolDecoderTest.java | 37 + .../traccar/protocol/Gps056FrameDecoderTest.java | 25 + .../protocol/Gps056ProtocolDecoderTest.java | 24 + .../protocol/Gps103ProtocolDecoderTest.java | 261 ++++ .../protocol/Gps103ProtocolEncoderTest.java | 39 + .../protocol/GpsGateProtocolDecoderTest.java | 52 + .../protocol/GpsMarkerProtocolDecoderTest.java | 32 + .../protocol/GpsmtaProtocolDecoderTest.java | 24 + .../traccar/protocol/GranitFrameDecoderTest.java | 45 + .../protocol/GranitProtocolDecoderTest.java | 49 + .../traccar/protocol/Gt02ProtocolDecoderTest.java | 43 + .../org/traccar/protocol/Gt06FrameDecoderTest.java | 51 + .../traccar/protocol/Gt06ProtocolDecoderTest.java | 294 +++++ .../traccar/protocol/Gt06ProtocolEncoderTest.java | 22 + .../traccar/protocol/Gt30ProtocolDecoderTest.java | 30 + .../org/traccar/protocol/H02FrameDecoderTest.java | 71 ++ .../traccar/protocol/H02ProtocolDecoderTest.java | 261 ++++ .../traccar/protocol/H02ProtocolEncoderTest.java | 72 ++ .../protocol/HaicomProtocolDecoderTest.java | 28 + .../protocol/HomtecsProtocolDecoderTest.java | 24 + .../traccar/protocol/HuaShengFrameDecoderTest.java | 33 + .../protocol/HuaShengProtocolDecoderTest.java | 45 + .../traccar/protocol/HuabaoFrameDecoderTest.java | 21 + .../protocol/HuabaoProtocolDecoderTest.java | 69 ++ .../protocol/HuabaoProtocolEncoderTest.java | 24 + .../protocol/HunterProProtocolDecoderTest.java | 18 + .../traccar/protocol/IdplProtocolDecoderTest.java | 22 + .../protocol/IntellitracProtocolDecoderTest.java | 64 + .../traccar/protocol/ItsProtocolDecoderTest.java | 54 + .../protocol/Ivt401ProtocolDecoderTest.java | 60 + .../protocol/JpKorjarProtocolDecoderTest.java | 24 + .../traccar/protocol/Jt600FrameDecoderTest.java | 39 + .../traccar/protocol/Jt600ProtocolDecoderTest.java | 108 ++ .../traccar/protocol/Jt600ProtocolEncoderTest.java | 37 + .../traccar/protocol/KenjiProtocolDecoderTest.java | 18 + .../traccar/protocol/KhdProtocolDecoderTest.java | 48 + .../traccar/protocol/KhdProtocolEncoderTest.java | 22 + .../org/traccar/protocol/L100FrameDecoderTest.java | 31 + .../traccar/protocol/L100ProtocolDecoderTest.java | 51 + .../protocol/LaipacProtocolDecoderTest.java | 125 ++ .../traccar/protocol/M2cProtocolDecoderTest.java | 27 + .../traccar/protocol/M2mProtocolDecoderTest.java | 21 + .../protocol/MaestroProtocolDecoderTest.java | 30 + .../protocol/ManPowerProtocolDecoderTest.java | 24 + .../traccar/protocol/MegastekFrameDecoderTest.java | 27 + .../protocol/MegastekProtocolDecoderTest.java | 100 ++ .../traccar/protocol/MeiligaoFrameDecoderTest.java | 29 + .../protocol/MeiligaoProtocolDecoderTest.java | 137 +++ .../protocol/MeiligaoProtocolEncoderTest.java | 41 + .../traccar/protocol/MeitrackFrameDecoderTest.java | 21 + .../protocol/MeitrackProtocolDecoderTest.java | 110 ++ .../protocol/MeitrackProtocolEncoderTest.java | 36 + .../protocol/MilesmateProtocolDecoderTest.java | 25 + .../protocol/MiniFinderProtocolDecoderTest.java | 73 ++ .../protocol/MiniFinderProtocolEncoderTest.java | 33 + .../traccar/protocol/MtxProtocolDecoderTest.java | 18 + .../traccar/protocol/MxtProtocolDecoderTest.java | 45 + .../protocol/NavigilProtocolDecoderTest.java | 21 + .../traccar/protocol/NavisFrameDecoderTest.java | 36 + .../traccar/protocol/NavisProtocolDecoderTest.java | 79 ++ .../traccar/protocol/NeosProtocolDecoderTest.java | 18 + .../traccar/protocol/NoranProtocolDecoderTest.java | 45 + .../traccar/protocol/NoranProtocolEncoderTest.java | 23 + .../org/traccar/protocol/NvsFrameDecoderTest.java | 25 + .../traccar/protocol/NvsProtocolDecoderTest.java | 30 + .../protocol/NyitechProtocolDecoderTest.java | 30 + .../protocol/ObdDongleProtocolDecoderTest.java | 22 + .../traccar/protocol/OigoProtocolDecoderTest.java | 42 + .../traccar/protocol/OkoProtocolDecoderTest.java | 33 + .../protocol/OpenGtsProtocolDecoderTest.java | 24 + .../traccar/protocol/OrionProtocolDecoderTest.java | 30 + .../protocol/OsmAndProtocolDecoderTest.java | 48 + .../protocol/OwnTracksProtocolDecoderTest.java | 27 + .../protocol/PathAwayProtocolDecoderTest.java | 18 + .../protocol/PiligrimProtocolDecoderTest.java | 20 + .../protocol/PretraceProtocolDecoderTest.java | 21 + .../protocol/PretraceProtocolEncoderTest.java | 39 + .../protocol/PricolProtocolDecoderTest.java | 24 + .../protocol/ProgressProtocolDecoderTest.java | 18 + .../protocol/Pt3000ProtocolDecoderTest.java | 22 + .../traccar/protocol/Pt502FrameDecoderTest.java | 39 + .../traccar/protocol/Pt502ProtocolDecoderTest.java | 86 ++ .../traccar/protocol/Pt502ProtocolEncoderTest.java | 69 ++ .../traccar/protocol/Pt60ProtocolDecoderTest.java | 54 + .../protocol/RaveonProtocolDecoderTest.java | 18 + .../protocol/RecodaProtocolDecoderTest.java | 24 + .../protocol/RetranslatorProtocolDecoderTest.java | 21 + .../traccar/protocol/RitiProtocolDecoderTest.java | 21 + .../protocol/RoboTrackFrameDecoderTest.java | 19 + .../protocol/RoboTrackProtocolDecoderTest.java | 24 + .../protocol/RuptelaProtocolDecoderTest.java | 48 + .../protocol/RuptelaProtocolEncoderTest.java | 23 + .../traccar/protocol/SabertekFrameDecoderTest.java | 21 + .../protocol/SabertekProtocolDecoderTest.java | 21 + .../traccar/protocol/SanavProtocolDecoderTest.java | 37 + .../protocol/SatsolProtocolDecoderTest.java | 21 + .../protocol/SigfoxProtocolDecoderTest.java | 19 + .../traccar/protocol/SiwiProtocolDecoderTest.java | 36 + .../protocol/SkypatrolProtocolDecoderTest.java | 34 + .../protocol/SmartSoleProtocolDecoderTest.java | 21 + .../protocol/SmokeyProtocolDecoderTest.java | 21 + .../traccar/protocol/SpotProtocolDecoderTest.java | 19 + .../protocol/StarLinkProtocolDecoderTest.java | 54 + .../protocol/Stl060ProtocolDecoderTest.java | 28 + .../protocol/SuntechProtocolDecoderTest.java | 167 +++ .../protocol/SupermateProtocolDecoderTest.java | 24 + .../traccar/protocol/SviasProtocolDecoderTest.java | 24 + .../traccar/protocol/T55ProtocolDecoderTest.java | 126 ++ .../org/traccar/protocol/T57FrameDecoderTest.java | 19 + .../traccar/protocol/T57ProtocolDecoderTest.java | 27 + .../traccar/protocol/T800xProtocolDecoderTest.java | 48 + .../traccar/protocol/T800xProtocolEncoderTest.java | 23 + .../traccar/protocol/TaipProtocolDecoderTest.java | 86 ++ .../org/traccar/protocol/TekFrameDecoderTest.java | 23 + .../traccar/protocol/TekProtocolDecoderTest.java | 24 + .../protocol/TelemaxProtocolDecoderTest.java | 21 + .../traccar/protocol/TelicFrameDecoderTest.java | 42 + .../traccar/protocol/TelicProtocolDecoderTest.java | 94 ++ .../protocol/TeltonikaProtocolDecoderTest.java | 134 +++ .../protocol/TeltonikaProtocolEncoderTest.java | 23 + .../protocol/ThinkRaceProtocolDecoderTest.java | 21 + .../traccar/protocol/Tk102ProtocolDecoderTest.java | 51 + .../traccar/protocol/Tk103FrameDecoderTest.java | 44 + .../traccar/protocol/Tk103ProtocolDecoderTest.java | 202 ++++ .../traccar/protocol/Tk103ProtocolEncoderTest.java | 282 +++++ .../traccar/protocol/Tlt2hProtocolDecoderTest.java | 64 + .../traccar/protocol/TlvProtocolDecoderTest.java | 24 + .../org/traccar/protocol/TmgFrameDecoderTest.java | 23 + .../traccar/protocol/TmgProtocolDecoderTest.java | 54 + .../protocol/TopflytechProtocolDecoderTest.java | 18 + .../traccar/protocol/TotemFrameDecoderTest.java | 35 + .../traccar/protocol/TotemProtocolDecoderTest.java | 116 ++ .../traccar/protocol/TotemProtocolEncoderTest.java | 25 + .../traccar/protocol/Tr20ProtocolDecoderTest.java | 31 + .../traccar/protocol/Tr900ProtocolDecoderTest.java | 25 + .../protocol/TrackboxProtocolDecoderTest.java | 25 + .../protocol/TrakMateProtocolDecoderTest.java | 27 + .../traccar/protocol/TramigoFrameDecoderTest.java | 23 + .../protocol/TramigoProtocolDecoderTest.java | 63 + .../traccar/protocol/TrvProtocolDecoderTest.java | 67 ++ .../protocol/Tt8850ProtocolDecoderTest.java | 36 + .../traccar/protocol/TytanProtocolDecoderTest.java | 36 + .../traccar/protocol/TzoneProtocolDecoderTest.java | 53 + .../traccar/protocol/UlbotechFrameDecoderTest.java | 29 + .../protocol/UlbotechProtocolDecoderTest.java | 90 ++ .../traccar/protocol/UproProtocolDecoderTest.java | 65 + .../traccar/protocol/V680ProtocolDecoderTest.java | 77 ++ .../protocol/VisiontekProtocolDecoderTest.java | 40 + .../traccar/protocol/Vt200FrameDecoderTest.java | 23 + .../traccar/protocol/Vt200ProtocolDecoderTest.java | 60 + .../traccar/protocol/VtfmsFrameDecoderTest.java | 21 + .../traccar/protocol/VtfmsProtocolDecoderTest.java | 25 + .../traccar/protocol/WatchFrameDecoderTest.java | 35 + .../traccar/protocol/WatchProtocolDecoderTest.java | 128 ++ .../traccar/protocol/WatchProtocolEncoderTest.java | 83 ++ .../protocol/WialonProtocolDecoderTest.java | 67 ++ .../traccar/protocol/WondexFrameDecoderTest.java | 28 + .../protocol/WondexProtocolDecoderTest.java | 62 + .../protocol/WondexProtocolEncoderTest.java | 24 + .../protocol/WristbandProtocolDecoderTest.java | 36 + .../traccar/protocol/XexunFrameDecoderTest.java | 25 + .../traccar/protocol/XexunProtocolDecoderTest.java | 118 ++ .../traccar/protocol/XirgoProtocolDecoderTest.java | 76 ++ .../traccar/protocol/XirgoProtocolEncoderTest.java | 26 + .../traccar/protocol/Xrb28ProtocolDecoderTest.java | 33 + .../traccar/protocol/Xrb28ProtocolEncoderTest.java | 39 + .../traccar/protocol/Xt013ProtocolDecoderTest.java | 25 + .../protocol/Xt2400ProtocolDecoderTest.java | 25 + .../traccar/protocol/YwtProtocolDecoderTest.java | 31 + .../java/org/traccar/reports/ReportUtilsTest.java | 390 ++++++ src/test/java/org/traccar/web/WebServerTest.java | 29 + 1647 files changed, 84393 insertions(+), 70494 deletions(-) create mode 100644 src/main/java/org/traccar/BaseDataHandler.java create mode 100644 src/main/java/org/traccar/BaseFrameDecoder.java create mode 100644 src/main/java/org/traccar/BaseHttpProtocolDecoder.java create mode 100644 src/main/java/org/traccar/BasePipelineFactory.java create mode 100644 src/main/java/org/traccar/BaseProtocol.java create mode 100644 src/main/java/org/traccar/BaseProtocolDecoder.java create mode 100644 src/main/java/org/traccar/BaseProtocolEncoder.java create mode 100644 src/main/java/org/traccar/CharacterDelimiterFrameDecoder.java create mode 100644 src/main/java/org/traccar/Context.java create mode 100644 src/main/java/org/traccar/DeviceSession.java create mode 100644 src/main/java/org/traccar/EventLoopGroupFactory.java create mode 100644 src/main/java/org/traccar/ExtendedObjectDecoder.java create mode 100644 src/main/java/org/traccar/GlobalTimer.java create mode 100644 src/main/java/org/traccar/Main.java create mode 100644 src/main/java/org/traccar/MainEventHandler.java create mode 100644 src/main/java/org/traccar/MainModule.java create mode 100644 src/main/java/org/traccar/NetworkMessage.java create mode 100644 src/main/java/org/traccar/PipelineBuilder.java create mode 100644 src/main/java/org/traccar/Protocol.java create mode 100644 src/main/java/org/traccar/ServerManager.java create mode 100644 src/main/java/org/traccar/StringProtocolEncoder.java create mode 100644 src/main/java/org/traccar/TrackerServer.java create mode 100644 src/main/java/org/traccar/WebDataHandler.java create mode 100644 src/main/java/org/traccar/WindowsService.java create mode 100644 src/main/java/org/traccar/WrapperContext.java create mode 100644 src/main/java/org/traccar/WrapperInboundHandler.java create mode 100644 src/main/java/org/traccar/WrapperOutboundHandler.java create mode 100644 src/main/java/org/traccar/api/AsyncSocket.java create mode 100644 src/main/java/org/traccar/api/AsyncSocketServlet.java create mode 100644 src/main/java/org/traccar/api/BaseObjectResource.java create mode 100644 src/main/java/org/traccar/api/BaseResource.java create mode 100644 src/main/java/org/traccar/api/CorsResponseFilter.java create mode 100644 src/main/java/org/traccar/api/ExtendedObjectResource.java create mode 100644 src/main/java/org/traccar/api/MediaFilter.java create mode 100644 src/main/java/org/traccar/api/ObjectMapperProvider.java create mode 100644 src/main/java/org/traccar/api/ResourceErrorHandler.java create mode 100644 src/main/java/org/traccar/api/SecurityRequestFilter.java create mode 100644 src/main/java/org/traccar/api/SimpleObjectResource.java create mode 100644 src/main/java/org/traccar/api/UserPrincipal.java create mode 100644 src/main/java/org/traccar/api/UserSecurityContext.java create mode 100644 src/main/java/org/traccar/api/resource/AttributeResource.java create mode 100644 src/main/java/org/traccar/api/resource/CalendarResource.java create mode 100644 src/main/java/org/traccar/api/resource/CommandResource.java create mode 100644 src/main/java/org/traccar/api/resource/DeviceResource.java create mode 100644 src/main/java/org/traccar/api/resource/DriverResource.java create mode 100644 src/main/java/org/traccar/api/resource/EventResource.java create mode 100644 src/main/java/org/traccar/api/resource/GeofenceResource.java create mode 100644 src/main/java/org/traccar/api/resource/GroupResource.java create mode 100644 src/main/java/org/traccar/api/resource/MaintenanceResource.java create mode 100644 src/main/java/org/traccar/api/resource/NotificationResource.java create mode 100644 src/main/java/org/traccar/api/resource/PermissionsResource.java create mode 100644 src/main/java/org/traccar/api/resource/PositionResource.java create mode 100644 src/main/java/org/traccar/api/resource/ReportResource.java create mode 100644 src/main/java/org/traccar/api/resource/ServerResource.java create mode 100644 src/main/java/org/traccar/api/resource/SessionResource.java create mode 100644 src/main/java/org/traccar/api/resource/StatisticsResource.java create mode 100644 src/main/java/org/traccar/api/resource/UserResource.java create mode 100644 src/main/java/org/traccar/config/Config.java create mode 100644 src/main/java/org/traccar/config/ConfigKey.java create mode 100644 src/main/java/org/traccar/config/ConfigSuffix.java create mode 100644 src/main/java/org/traccar/config/Keys.java create mode 100644 src/main/java/org/traccar/database/ActiveDevice.java create mode 100644 src/main/java/org/traccar/database/AttributesManager.java create mode 100644 src/main/java/org/traccar/database/BaseObjectManager.java create mode 100644 src/main/java/org/traccar/database/CalendarManager.java create mode 100644 src/main/java/org/traccar/database/CommandsManager.java create mode 100644 src/main/java/org/traccar/database/ConnectionManager.java create mode 100644 src/main/java/org/traccar/database/DataManager.java create mode 100644 src/main/java/org/traccar/database/DeviceManager.java create mode 100644 src/main/java/org/traccar/database/DriversManager.java create mode 100644 src/main/java/org/traccar/database/ExtendedObjectManager.java create mode 100644 src/main/java/org/traccar/database/GeofenceManager.java create mode 100644 src/main/java/org/traccar/database/GroupTree.java create mode 100644 src/main/java/org/traccar/database/GroupsManager.java create mode 100644 src/main/java/org/traccar/database/IdentityManager.java create mode 100644 src/main/java/org/traccar/database/LdapProvider.java create mode 100644 src/main/java/org/traccar/database/MailManager.java create mode 100644 src/main/java/org/traccar/database/MaintenancesManager.java create mode 100644 src/main/java/org/traccar/database/ManagableObjects.java create mode 100644 src/main/java/org/traccar/database/MediaManager.java create mode 100644 src/main/java/org/traccar/database/NotificationManager.java create mode 100644 src/main/java/org/traccar/database/PermissionsManager.java create mode 100644 src/main/java/org/traccar/database/QueryBuilder.java create mode 100644 src/main/java/org/traccar/database/QueryExtended.java create mode 100644 src/main/java/org/traccar/database/QueryIgnore.java create mode 100644 src/main/java/org/traccar/database/SimpleObjectManager.java create mode 100644 src/main/java/org/traccar/database/StatisticsManager.java create mode 100644 src/main/java/org/traccar/database/UsersManager.java create mode 100644 src/main/java/org/traccar/geocoder/Address.java create mode 100644 src/main/java/org/traccar/geocoder/AddressFormat.java create mode 100644 src/main/java/org/traccar/geocoder/BanGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/BingMapsGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/FactualGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/Geocoder.java create mode 100644 src/main/java/org/traccar/geocoder/GeocoderException.java create mode 100644 src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/GoogleGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/HereGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/JsonGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/MapQuestGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/NominatimGeocoder.java create mode 100644 src/main/java/org/traccar/geocoder/OpenCageGeocoder.java create mode 100644 src/main/java/org/traccar/geofence/GeofenceCircle.java create mode 100644 src/main/java/org/traccar/geofence/GeofenceGeometry.java create mode 100644 src/main/java/org/traccar/geofence/GeofencePolygon.java create mode 100644 src/main/java/org/traccar/geofence/GeofencePolyline.java create mode 100644 src/main/java/org/traccar/geolocation/GeolocationException.java create mode 100644 src/main/java/org/traccar/geolocation/GeolocationProvider.java create mode 100644 src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java create mode 100644 src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java create mode 100644 src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java create mode 100644 src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java create mode 100644 src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java create mode 100644 src/main/java/org/traccar/handler/ComputedAttributesHandler.java create mode 100644 src/main/java/org/traccar/handler/CopyAttributesHandler.java create mode 100644 src/main/java/org/traccar/handler/DefaultDataHandler.java create mode 100644 src/main/java/org/traccar/handler/DistanceHandler.java create mode 100644 src/main/java/org/traccar/handler/EngineHoursHandler.java create mode 100644 src/main/java/org/traccar/handler/FilterHandler.java create mode 100644 src/main/java/org/traccar/handler/GeocoderHandler.java create mode 100644 src/main/java/org/traccar/handler/GeolocationHandler.java create mode 100644 src/main/java/org/traccar/handler/HemisphereHandler.java create mode 100644 src/main/java/org/traccar/handler/MotionHandler.java create mode 100644 src/main/java/org/traccar/handler/NetworkMessageHandler.java create mode 100644 src/main/java/org/traccar/handler/OpenChannelHandler.java create mode 100644 src/main/java/org/traccar/handler/RemoteAddressHandler.java create mode 100644 src/main/java/org/traccar/handler/StandardLoggingHandler.java create mode 100644 src/main/java/org/traccar/handler/events/AlertEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/BaseEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/CommandResultEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/DriverEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/FuelDropEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/GeofenceEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/IgnitionEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/MotionEventHandler.java create mode 100644 src/main/java/org/traccar/handler/events/OverspeedEventHandler.java create mode 100644 src/main/java/org/traccar/helper/BcdUtil.java create mode 100644 src/main/java/org/traccar/helper/BitBuffer.java create mode 100644 src/main/java/org/traccar/helper/BitUtil.java create mode 100644 src/main/java/org/traccar/helper/BufferUtil.java create mode 100644 src/main/java/org/traccar/helper/Checksum.java create mode 100644 src/main/java/org/traccar/helper/DataConverter.java create mode 100644 src/main/java/org/traccar/helper/DateBuilder.java create mode 100644 src/main/java/org/traccar/helper/DateUtil.java create mode 100644 src/main/java/org/traccar/helper/DistanceCalculator.java create mode 100644 src/main/java/org/traccar/helper/Hashing.java create mode 100644 src/main/java/org/traccar/helper/LocationTree.java create mode 100644 src/main/java/org/traccar/helper/Log.java create mode 100644 src/main/java/org/traccar/helper/LogAction.java create mode 100644 src/main/java/org/traccar/helper/ObdDecoder.java create mode 100644 src/main/java/org/traccar/helper/Parser.java create mode 100644 src/main/java/org/traccar/helper/PatternBuilder.java create mode 100644 src/main/java/org/traccar/helper/PatternUtil.java create mode 100644 src/main/java/org/traccar/helper/SanitizerModule.java create mode 100644 src/main/java/org/traccar/helper/UnitsConverter.java create mode 100644 src/main/java/org/traccar/model/Attribute.java create mode 100644 src/main/java/org/traccar/model/BaseModel.java create mode 100644 src/main/java/org/traccar/model/Calendar.java create mode 100644 src/main/java/org/traccar/model/CellTower.java create mode 100644 src/main/java/org/traccar/model/Command.java create mode 100644 src/main/java/org/traccar/model/Device.java create mode 100644 src/main/java/org/traccar/model/DeviceAccumulators.java create mode 100644 src/main/java/org/traccar/model/DeviceState.java create mode 100644 src/main/java/org/traccar/model/Driver.java create mode 100644 src/main/java/org/traccar/model/Event.java create mode 100644 src/main/java/org/traccar/model/ExtendedModel.java create mode 100644 src/main/java/org/traccar/model/Geofence.java create mode 100644 src/main/java/org/traccar/model/Group.java create mode 100644 src/main/java/org/traccar/model/GroupedModel.java create mode 100644 src/main/java/org/traccar/model/Maintenance.java create mode 100644 src/main/java/org/traccar/model/ManagedUser.java create mode 100644 src/main/java/org/traccar/model/Message.java create mode 100644 src/main/java/org/traccar/model/MiscFormatter.java create mode 100644 src/main/java/org/traccar/model/Network.java create mode 100644 src/main/java/org/traccar/model/Notification.java create mode 100644 src/main/java/org/traccar/model/Permission.java create mode 100644 src/main/java/org/traccar/model/Position.java create mode 100644 src/main/java/org/traccar/model/ScheduledModel.java create mode 100644 src/main/java/org/traccar/model/Server.java create mode 100644 src/main/java/org/traccar/model/Statistics.java create mode 100644 src/main/java/org/traccar/model/Typed.java create mode 100644 src/main/java/org/traccar/model/User.java create mode 100644 src/main/java/org/traccar/model/WifiAccessPoint.java create mode 100644 src/main/java/org/traccar/notification/EventForwarder.java create mode 100644 src/main/java/org/traccar/notification/FullMessage.java create mode 100644 src/main/java/org/traccar/notification/JsonTypeEventForwarder.java create mode 100644 src/main/java/org/traccar/notification/MessageException.java create mode 100644 src/main/java/org/traccar/notification/NotificationFormatter.java create mode 100644 src/main/java/org/traccar/notification/NotificatorManager.java create mode 100644 src/main/java/org/traccar/notification/PropertiesProvider.java create mode 100644 src/main/java/org/traccar/notificators/Notificator.java create mode 100644 src/main/java/org/traccar/notificators/NotificatorFirebase.java create mode 100644 src/main/java/org/traccar/notificators/NotificatorMail.java create mode 100644 src/main/java/org/traccar/notificators/NotificatorNull.java create mode 100644 src/main/java/org/traccar/notificators/NotificatorSms.java create mode 100644 src/main/java/org/traccar/notificators/NotificatorWeb.java create mode 100644 src/main/java/org/traccar/protocol/AdmProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AdmProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AdmProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/AisProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AisProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AlematicsFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AlematicsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AnytrekProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ApelProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ApelProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AplicomFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AplicomProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AppelloProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AppletProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AppletProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AquilaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Ardi01Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ArknavProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ArknavX8Protocol.java create mode 100644 src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ArnaviProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AstraProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AstraProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/At2000FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/At2000Protocol.java create mode 100644 src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AtrackFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AtrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AtrackProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/AuroProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AuroProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AustinNbProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AutoFonFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AutoFonProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AutoGradeProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AutoTrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/AvemaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Avl301Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/BceFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/BceProtocol.java create mode 100644 src/main/java/org/traccar/protocol/BceProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/BceProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/BlackKiteProtocol.java create mode 100644 src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/BoxProtocol.java create mode 100644 src/main/java/org/traccar/protocol/BoxProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/C2stekProtocol.java create mode 100644 src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CalAmpProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CarTrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CarcellProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/CarscopProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CastelProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CastelProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CastelProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/CautelaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CellocatorFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CellocatorProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CellocatorProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/CguardProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CguardProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CityeasyProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CityeasyProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/ContinentalProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/CradlepointProtocol.java create mode 100644 src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/DishaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/DishaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/DmtHttpProtocol.java create mode 100644 src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/DmtProtocol.java create mode 100644 src/main/java/org/traccar/protocol/DmtProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/DwayProtocol.java create mode 100644 src/main/java/org/traccar/protocol/DwayProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/EasyTrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/EelinkProtocol.java create mode 100644 src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/EelinkProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/EgtsFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/EgtsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/EnforaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/EnforaProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/EsealProtocol.java create mode 100644 src/main/java/org/traccar/protocol/EsealProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/EsealProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/EskyFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/EskyProtocol.java create mode 100644 src/main/java/org/traccar/protocol/EskyProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ExtremTracProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/FifotrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/FlespiProtocol.java create mode 100644 src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/FlexCommProtocol.java create mode 100644 src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/FlextrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/FoxProtocol.java create mode 100644 src/main/java/org/traccar/protocol/FoxProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/FreedomProtocol.java create mode 100644 src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/FreematicsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GalileoFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GalileoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GalileoProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/GatorProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GatorProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GenxProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GenxProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gl100Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gl200FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gl200Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GlobalSatProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GnxProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GnxProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GoSafeProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GotopProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GotopProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gps056FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gps056Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gps103Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/GpsGateProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GpsMarkerProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GpsmtaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GranitFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GranitProtocol.java create mode 100644 src/main/java/org/traccar/protocol/GranitProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/GranitProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Gt02Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gt06FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gt06Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Gt30Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/H02FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/H02Protocol.java create mode 100644 src/main/java/org/traccar/protocol/H02ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/H02ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/HaicomProtocol.java create mode 100644 src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/HomtecsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/HuaShengFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/HuaShengProtocol.java create mode 100644 src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/HuabaoFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/HuabaoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/HunterProProtocol.java create mode 100644 src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/IdplProtocol.java create mode 100644 src/main/java/org/traccar/protocol/IdplProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/IntellitracFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/IntellitracProtocol.java create mode 100644 src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ItsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ItsProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Ivt401Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/JpKorjarFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/JpKorjarProtocol.java create mode 100644 src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Jt600FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Jt600Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Jt600ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/KenjiProtocol.java create mode 100644 src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/KhdProtocol.java create mode 100644 src/main/java/org/traccar/protocol/KhdProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/KhdProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/L100FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/L100Protocol.java create mode 100644 src/main/java/org/traccar/protocol/L100ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/LaipacProtocol.java create mode 100644 src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/M2cProtocol.java create mode 100644 src/main/java/org/traccar/protocol/M2cProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/M2mProtocol.java create mode 100644 src/main/java/org/traccar/protocol/M2mProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MaestroProtocol.java create mode 100644 src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ManPowerProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MegastekFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MegastekProtocol.java create mode 100644 src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MeiligaoFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MeiligaoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/MeitrackFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MeitrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/MilesmateProtocol.java create mode 100644 src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MiniFinderProtocol.java create mode 100644 src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Mta6Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MtxProtocol.java create mode 100644 src/main/java/org/traccar/protocol/MtxProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MxtFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/MxtProtocol.java create mode 100644 src/main/java/org/traccar/protocol/MxtProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NavigilFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NavigilProtocol.java create mode 100644 src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NavisFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NavisProtocol.java create mode 100644 src/main/java/org/traccar/protocol/NavisProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NeosProtocol.java create mode 100644 src/main/java/org/traccar/protocol/NeosProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NoranProtocol.java create mode 100644 src/main/java/org/traccar/protocol/NoranProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NoranProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/NvsFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NvsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/NvsProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/NyitechProtocol.java create mode 100644 src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ObdDongleProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/OigoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/OigoProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/OkoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/OkoProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/OpenGtsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/OrionFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/OrionProtocol.java create mode 100644 src/main/java/org/traccar/protocol/OrionProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/OsmAndProtocol.java create mode 100644 src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/OwnTracksProtocol.java create mode 100644 src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/PathAwayProtocol.java create mode 100644 src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/PiligrimProtocol.java create mode 100644 src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/PretraceProtocol.java create mode 100644 src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/PricolProtocol.java create mode 100644 src/main/java/org/traccar/protocol/PricolProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/ProgressProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Pt3000Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Pt502FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Pt502Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Pt60Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RaveonProtocol.java create mode 100644 src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RecodaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RetranslatorFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RetranslatorProtocol.java create mode 100644 src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RitiProtocol.java create mode 100644 src/main/java/org/traccar/protocol/RitiProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RoboTrackFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RoboTrackProtocol.java create mode 100644 src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RuptelaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/SabertekFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SabertekProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SanavProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SanavProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SatsolProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SigfoxProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SiwiProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SkypatrolProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SmartSoleProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SmokeyProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SpotProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SpotProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/StarLinkProtocol.java create mode 100644 src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Stl060FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Stl060Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SuntechProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/SupermateProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SviasProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SviasProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/SviasProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/T55Protocol.java create mode 100644 src/main/java/org/traccar/protocol/T55ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/T57FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/T57Protocol.java create mode 100644 src/main/java/org/traccar/protocol/T57ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/T800xProtocol.java create mode 100644 src/main/java/org/traccar/protocol/T800xProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/T800xProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/TaipProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TaipProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TekFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TekProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TekProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TelemaxProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TelicFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TelicProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TelicProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TeltonikaProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TeltonikaProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/ThinkRaceProtocol.java create mode 100644 src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Tk102Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Tk103FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Tk103Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Tlt2hProtocol.java create mode 100644 src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TlvProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TlvProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TmgFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TmgProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TmgProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TopflytechProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TotemFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TotemProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TotemProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TotemProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Tr20Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Tr900Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TrackboxProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TrakMateProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TramigoFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TramigoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TrvProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TrvProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Tt8850Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TytanProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TytanProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/TzoneProtocol.java create mode 100644 src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/UlbotechFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/UlbotechProtocol.java create mode 100644 src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/UproProtocol.java create mode 100644 src/main/java/org/traccar/protocol/UproProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/V680Protocol.java create mode 100644 src/main/java/org/traccar/protocol/V680ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/VisiontekProtocol.java create mode 100644 src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Vt200FrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Vt200Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/VtfmsFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/VtfmsProtocol.java create mode 100644 src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/WatchFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/WatchProtocol.java create mode 100644 src/main/java/org/traccar/protocol/WatchProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/WatchProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/WialonProtocol.java create mode 100644 src/main/java/org/traccar/protocol/WialonProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/WialonProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/WondexFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/WondexProtocol.java create mode 100644 src/main/java/org/traccar/protocol/WondexProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/WondexProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/WristbandProtocol.java create mode 100644 src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/XexunFrameDecoder.java create mode 100644 src/main/java/org/traccar/protocol/XexunProtocol.java create mode 100644 src/main/java/org/traccar/protocol/XexunProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/XexunProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/XirgoProtocol.java create mode 100644 src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/XirgoProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Xrb28Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Xrb28ProtocolEncoder.java create mode 100644 src/main/java/org/traccar/protocol/Xt013Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/Xt2400Protocol.java create mode 100644 src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/YwtProtocol.java create mode 100644 src/main/java/org/traccar/protocol/YwtProtocolDecoder.java create mode 100644 src/main/java/org/traccar/reports/Events.java create mode 100644 src/main/java/org/traccar/reports/ReportUtils.java create mode 100644 src/main/java/org/traccar/reports/Route.java create mode 100644 src/main/java/org/traccar/reports/Stops.java create mode 100644 src/main/java/org/traccar/reports/Summary.java create mode 100644 src/main/java/org/traccar/reports/Trips.java create mode 100644 src/main/java/org/traccar/reports/model/BaseReport.java create mode 100644 src/main/java/org/traccar/reports/model/DeviceReport.java create mode 100644 src/main/java/org/traccar/reports/model/StopReport.java create mode 100644 src/main/java/org/traccar/reports/model/SummaryReport.java create mode 100644 src/main/java/org/traccar/reports/model/TripReport.java create mode 100644 src/main/java/org/traccar/reports/model/TripsConfig.java create mode 100644 src/main/java/org/traccar/sms/HttpSmsClient.java create mode 100644 src/main/java/org/traccar/sms/SmsManager.java create mode 100644 src/main/java/org/traccar/sms/smpp/ClientSmppSessionHandler.java create mode 100644 src/main/java/org/traccar/sms/smpp/EnquireLinkTask.java create mode 100644 src/main/java/org/traccar/sms/smpp/ReconnectionTask.java create mode 100644 src/main/java/org/traccar/sms/smpp/SmppClient.java create mode 100644 src/main/java/org/traccar/sms/smpp/TextMessageEventHandler.java create mode 100644 src/main/java/org/traccar/web/ConsoleServlet.java create mode 100644 src/main/java/org/traccar/web/CsvBuilder.java create mode 100644 src/main/java/org/traccar/web/GpxBuilder.java create mode 100644 src/main/java/org/traccar/web/WebServer.java delete mode 100644 src/org/traccar/BaseDataHandler.java delete mode 100644 src/org/traccar/BaseFrameDecoder.java delete mode 100644 src/org/traccar/BaseHttpProtocolDecoder.java delete mode 100644 src/org/traccar/BasePipelineFactory.java delete mode 100644 src/org/traccar/BaseProtocol.java delete mode 100644 src/org/traccar/BaseProtocolDecoder.java delete mode 100644 src/org/traccar/BaseProtocolEncoder.java delete mode 100644 src/org/traccar/CharacterDelimiterFrameDecoder.java delete mode 100644 src/org/traccar/Context.java delete mode 100644 src/org/traccar/DeviceSession.java delete mode 100644 src/org/traccar/EventLoopGroupFactory.java delete mode 100644 src/org/traccar/ExtendedObjectDecoder.java delete mode 100644 src/org/traccar/GlobalTimer.java delete mode 100644 src/org/traccar/Main.java delete mode 100644 src/org/traccar/MainEventHandler.java delete mode 100644 src/org/traccar/MainModule.java delete mode 100644 src/org/traccar/NetworkMessage.java delete mode 100644 src/org/traccar/PipelineBuilder.java delete mode 100644 src/org/traccar/Protocol.java delete mode 100644 src/org/traccar/ServerManager.java delete mode 100644 src/org/traccar/StringProtocolEncoder.java delete mode 100644 src/org/traccar/TrackerServer.java delete mode 100644 src/org/traccar/WebDataHandler.java delete mode 100644 src/org/traccar/WindowsService.java delete mode 100644 src/org/traccar/WrapperContext.java delete mode 100644 src/org/traccar/WrapperInboundHandler.java delete mode 100644 src/org/traccar/WrapperOutboundHandler.java delete mode 100644 src/org/traccar/api/AsyncSocket.java delete mode 100644 src/org/traccar/api/AsyncSocketServlet.java delete mode 100644 src/org/traccar/api/BaseObjectResource.java delete mode 100644 src/org/traccar/api/BaseResource.java delete mode 100644 src/org/traccar/api/CorsResponseFilter.java delete mode 100644 src/org/traccar/api/ExtendedObjectResource.java delete mode 100644 src/org/traccar/api/MediaFilter.java delete mode 100644 src/org/traccar/api/ObjectMapperProvider.java delete mode 100644 src/org/traccar/api/ResourceErrorHandler.java delete mode 100644 src/org/traccar/api/SecurityRequestFilter.java delete mode 100644 src/org/traccar/api/SimpleObjectResource.java delete mode 100644 src/org/traccar/api/UserPrincipal.java delete mode 100644 src/org/traccar/api/UserSecurityContext.java delete mode 100644 src/org/traccar/api/resource/AttributeResource.java delete mode 100644 src/org/traccar/api/resource/CalendarResource.java delete mode 100644 src/org/traccar/api/resource/CommandResource.java delete mode 100644 src/org/traccar/api/resource/DeviceResource.java delete mode 100644 src/org/traccar/api/resource/DriverResource.java delete mode 100644 src/org/traccar/api/resource/EventResource.java delete mode 100644 src/org/traccar/api/resource/GeofenceResource.java delete mode 100644 src/org/traccar/api/resource/GroupResource.java delete mode 100644 src/org/traccar/api/resource/MaintenanceResource.java delete mode 100644 src/org/traccar/api/resource/NotificationResource.java delete mode 100644 src/org/traccar/api/resource/PermissionsResource.java delete mode 100644 src/org/traccar/api/resource/PositionResource.java delete mode 100644 src/org/traccar/api/resource/ReportResource.java delete mode 100644 src/org/traccar/api/resource/ServerResource.java delete mode 100644 src/org/traccar/api/resource/SessionResource.java delete mode 100644 src/org/traccar/api/resource/StatisticsResource.java delete mode 100644 src/org/traccar/api/resource/UserResource.java delete mode 100644 src/org/traccar/config/Config.java delete mode 100644 src/org/traccar/config/ConfigKey.java delete mode 100644 src/org/traccar/config/ConfigSuffix.java delete mode 100644 src/org/traccar/config/Keys.java delete mode 100644 src/org/traccar/database/ActiveDevice.java delete mode 100644 src/org/traccar/database/AttributesManager.java delete mode 100644 src/org/traccar/database/BaseObjectManager.java delete mode 100644 src/org/traccar/database/CalendarManager.java delete mode 100644 src/org/traccar/database/CommandsManager.java delete mode 100644 src/org/traccar/database/ConnectionManager.java delete mode 100644 src/org/traccar/database/DataManager.java delete mode 100644 src/org/traccar/database/DeviceManager.java delete mode 100644 src/org/traccar/database/DriversManager.java delete mode 100644 src/org/traccar/database/ExtendedObjectManager.java delete mode 100644 src/org/traccar/database/GeofenceManager.java delete mode 100644 src/org/traccar/database/GroupTree.java delete mode 100644 src/org/traccar/database/GroupsManager.java delete mode 100644 src/org/traccar/database/IdentityManager.java delete mode 100644 src/org/traccar/database/LdapProvider.java delete mode 100644 src/org/traccar/database/MailManager.java delete mode 100644 src/org/traccar/database/MaintenancesManager.java delete mode 100644 src/org/traccar/database/ManagableObjects.java delete mode 100644 src/org/traccar/database/MediaManager.java delete mode 100644 src/org/traccar/database/NotificationManager.java delete mode 100644 src/org/traccar/database/PermissionsManager.java delete mode 100644 src/org/traccar/database/QueryBuilder.java delete mode 100644 src/org/traccar/database/QueryExtended.java delete mode 100644 src/org/traccar/database/QueryIgnore.java delete mode 100644 src/org/traccar/database/SimpleObjectManager.java delete mode 100644 src/org/traccar/database/StatisticsManager.java delete mode 100644 src/org/traccar/database/UsersManager.java delete mode 100644 src/org/traccar/geocoder/Address.java delete mode 100644 src/org/traccar/geocoder/AddressFormat.java delete mode 100644 src/org/traccar/geocoder/BanGeocoder.java delete mode 100644 src/org/traccar/geocoder/BingMapsGeocoder.java delete mode 100644 src/org/traccar/geocoder/FactualGeocoder.java delete mode 100644 src/org/traccar/geocoder/GeocodeFarmGeocoder.java delete mode 100644 src/org/traccar/geocoder/GeocodeXyzGeocoder.java delete mode 100644 src/org/traccar/geocoder/Geocoder.java delete mode 100644 src/org/traccar/geocoder/GeocoderException.java delete mode 100644 src/org/traccar/geocoder/GisgraphyGeocoder.java delete mode 100644 src/org/traccar/geocoder/GoogleGeocoder.java delete mode 100644 src/org/traccar/geocoder/HereGeocoder.java delete mode 100644 src/org/traccar/geocoder/JsonGeocoder.java delete mode 100644 src/org/traccar/geocoder/MapQuestGeocoder.java delete mode 100644 src/org/traccar/geocoder/MapmyIndiaGeocoder.java delete mode 100644 src/org/traccar/geocoder/NominatimGeocoder.java delete mode 100644 src/org/traccar/geocoder/OpenCageGeocoder.java delete mode 100644 src/org/traccar/geofence/GeofenceCircle.java delete mode 100644 src/org/traccar/geofence/GeofenceGeometry.java delete mode 100644 src/org/traccar/geofence/GeofencePolygon.java delete mode 100644 src/org/traccar/geofence/GeofencePolyline.java delete mode 100644 src/org/traccar/geolocation/GeolocationException.java delete mode 100644 src/org/traccar/geolocation/GeolocationProvider.java delete mode 100644 src/org/traccar/geolocation/GoogleGeolocationProvider.java delete mode 100644 src/org/traccar/geolocation/MozillaGeolocationProvider.java delete mode 100644 src/org/traccar/geolocation/OpenCellIdGeolocationProvider.java delete mode 100644 src/org/traccar/geolocation/UniversalGeolocationProvider.java delete mode 100644 src/org/traccar/geolocation/UnwiredGeolocationProvider.java delete mode 100644 src/org/traccar/handler/ComputedAttributesHandler.java delete mode 100644 src/org/traccar/handler/CopyAttributesHandler.java delete mode 100644 src/org/traccar/handler/DefaultDataHandler.java delete mode 100644 src/org/traccar/handler/DistanceHandler.java delete mode 100644 src/org/traccar/handler/EngineHoursHandler.java delete mode 100644 src/org/traccar/handler/FilterHandler.java delete mode 100644 src/org/traccar/handler/GeocoderHandler.java delete mode 100644 src/org/traccar/handler/GeolocationHandler.java delete mode 100644 src/org/traccar/handler/HemisphereHandler.java delete mode 100644 src/org/traccar/handler/MotionHandler.java delete mode 100644 src/org/traccar/handler/NetworkMessageHandler.java delete mode 100644 src/org/traccar/handler/OpenChannelHandler.java delete mode 100644 src/org/traccar/handler/RemoteAddressHandler.java delete mode 100644 src/org/traccar/handler/StandardLoggingHandler.java delete mode 100644 src/org/traccar/handler/events/AlertEventHandler.java delete mode 100644 src/org/traccar/handler/events/BaseEventHandler.java delete mode 100644 src/org/traccar/handler/events/CommandResultEventHandler.java delete mode 100644 src/org/traccar/handler/events/DriverEventHandler.java delete mode 100644 src/org/traccar/handler/events/FuelDropEventHandler.java delete mode 100644 src/org/traccar/handler/events/GeofenceEventHandler.java delete mode 100644 src/org/traccar/handler/events/IgnitionEventHandler.java delete mode 100644 src/org/traccar/handler/events/MaintenanceEventHandler.java delete mode 100644 src/org/traccar/handler/events/MotionEventHandler.java delete mode 100644 src/org/traccar/handler/events/OverspeedEventHandler.java delete mode 100644 src/org/traccar/helper/BcdUtil.java delete mode 100644 src/org/traccar/helper/BitBuffer.java delete mode 100644 src/org/traccar/helper/BitUtil.java delete mode 100644 src/org/traccar/helper/BufferUtil.java delete mode 100644 src/org/traccar/helper/Checksum.java delete mode 100644 src/org/traccar/helper/DataConverter.java delete mode 100644 src/org/traccar/helper/DateBuilder.java delete mode 100644 src/org/traccar/helper/DateUtil.java delete mode 100644 src/org/traccar/helper/DistanceCalculator.java delete mode 100644 src/org/traccar/helper/Hashing.java delete mode 100644 src/org/traccar/helper/LocationTree.java delete mode 100644 src/org/traccar/helper/Log.java delete mode 100644 src/org/traccar/helper/LogAction.java delete mode 100644 src/org/traccar/helper/ObdDecoder.java delete mode 100644 src/org/traccar/helper/Parser.java delete mode 100644 src/org/traccar/helper/PatternBuilder.java delete mode 100644 src/org/traccar/helper/PatternUtil.java delete mode 100644 src/org/traccar/helper/SanitizerModule.java delete mode 100644 src/org/traccar/helper/UnitsConverter.java delete mode 100644 src/org/traccar/model/Attribute.java delete mode 100644 src/org/traccar/model/BaseModel.java delete mode 100644 src/org/traccar/model/Calendar.java delete mode 100644 src/org/traccar/model/CellTower.java delete mode 100644 src/org/traccar/model/Command.java delete mode 100644 src/org/traccar/model/Device.java delete mode 100644 src/org/traccar/model/DeviceAccumulators.java delete mode 100644 src/org/traccar/model/DeviceState.java delete mode 100644 src/org/traccar/model/Driver.java delete mode 100644 src/org/traccar/model/Event.java delete mode 100644 src/org/traccar/model/ExtendedModel.java delete mode 100644 src/org/traccar/model/Geofence.java delete mode 100644 src/org/traccar/model/Group.java delete mode 100644 src/org/traccar/model/GroupedModel.java delete mode 100644 src/org/traccar/model/Maintenance.java delete mode 100644 src/org/traccar/model/ManagedUser.java delete mode 100644 src/org/traccar/model/Message.java delete mode 100644 src/org/traccar/model/MiscFormatter.java delete mode 100644 src/org/traccar/model/Network.java delete mode 100644 src/org/traccar/model/Notification.java delete mode 100644 src/org/traccar/model/Permission.java delete mode 100644 src/org/traccar/model/Position.java delete mode 100644 src/org/traccar/model/ScheduledModel.java delete mode 100644 src/org/traccar/model/Server.java delete mode 100644 src/org/traccar/model/Statistics.java delete mode 100644 src/org/traccar/model/Typed.java delete mode 100644 src/org/traccar/model/User.java delete mode 100644 src/org/traccar/model/WifiAccessPoint.java delete mode 100644 src/org/traccar/notification/EventForwarder.java delete mode 100644 src/org/traccar/notification/FullMessage.java delete mode 100644 src/org/traccar/notification/JsonTypeEventForwarder.java delete mode 100644 src/org/traccar/notification/MessageException.java delete mode 100644 src/org/traccar/notification/NotificationFormatter.java delete mode 100644 src/org/traccar/notification/NotificatorManager.java delete mode 100644 src/org/traccar/notification/PropertiesProvider.java delete mode 100644 src/org/traccar/notificators/Notificator.java delete mode 100644 src/org/traccar/notificators/NotificatorFirebase.java delete mode 100644 src/org/traccar/notificators/NotificatorMail.java delete mode 100644 src/org/traccar/notificators/NotificatorNull.java delete mode 100644 src/org/traccar/notificators/NotificatorSms.java delete mode 100644 src/org/traccar/notificators/NotificatorWeb.java delete mode 100644 src/org/traccar/protocol/AdmProtocol.java delete mode 100644 src/org/traccar/protocol/AdmProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AdmProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/AisProtocol.java delete mode 100644 src/org/traccar/protocol/AisProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AlematicsFrameDecoder.java delete mode 100644 src/org/traccar/protocol/AlematicsProtocol.java delete mode 100644 src/org/traccar/protocol/AlematicsProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AnytrekProtocol.java delete mode 100644 src/org/traccar/protocol/AnytrekProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ApelProtocol.java delete mode 100644 src/org/traccar/protocol/ApelProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AplicomFrameDecoder.java delete mode 100644 src/org/traccar/protocol/AplicomProtocol.java delete mode 100644 src/org/traccar/protocol/AplicomProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AppelloProtocol.java delete mode 100644 src/org/traccar/protocol/AppelloProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AppletProtocol.java delete mode 100644 src/org/traccar/protocol/AppletProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AquilaProtocol.java delete mode 100644 src/org/traccar/protocol/AquilaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Ardi01Protocol.java delete mode 100644 src/org/traccar/protocol/Ardi01ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ArknavProtocol.java delete mode 100644 src/org/traccar/protocol/ArknavProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ArknavX8Protocol.java delete mode 100644 src/org/traccar/protocol/ArknavX8ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ArnaviProtocol.java delete mode 100644 src/org/traccar/protocol/ArnaviProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AstraProtocol.java delete mode 100644 src/org/traccar/protocol/AstraProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/At2000FrameDecoder.java delete mode 100644 src/org/traccar/protocol/At2000Protocol.java delete mode 100644 src/org/traccar/protocol/At2000ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AtrackFrameDecoder.java delete mode 100644 src/org/traccar/protocol/AtrackProtocol.java delete mode 100644 src/org/traccar/protocol/AtrackProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AtrackProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/AuroProtocol.java delete mode 100644 src/org/traccar/protocol/AuroProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AustinNbProtocol.java delete mode 100644 src/org/traccar/protocol/AustinNbProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AutoFonFrameDecoder.java delete mode 100644 src/org/traccar/protocol/AutoFonProtocol.java delete mode 100644 src/org/traccar/protocol/AutoFonProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AutoGradeProtocol.java delete mode 100644 src/org/traccar/protocol/AutoGradeProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AutoTrackProtocol.java delete mode 100644 src/org/traccar/protocol/AutoTrackProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/AvemaProtocol.java delete mode 100644 src/org/traccar/protocol/AvemaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Avl301Protocol.java delete mode 100644 src/org/traccar/protocol/Avl301ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/BceFrameDecoder.java delete mode 100644 src/org/traccar/protocol/BceProtocol.java delete mode 100644 src/org/traccar/protocol/BceProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/BceProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/BlackKiteProtocol.java delete mode 100644 src/org/traccar/protocol/BlackKiteProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/BoxProtocol.java delete mode 100644 src/org/traccar/protocol/BoxProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/C2stekProtocol.java delete mode 100644 src/org/traccar/protocol/C2stekProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CalAmpProtocol.java delete mode 100644 src/org/traccar/protocol/CalAmpProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CarTrackProtocol.java delete mode 100644 src/org/traccar/protocol/CarTrackProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CarcellProtocol.java delete mode 100644 src/org/traccar/protocol/CarcellProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CarcellProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/CarscopProtocol.java delete mode 100644 src/org/traccar/protocol/CarscopProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CastelProtocol.java delete mode 100644 src/org/traccar/protocol/CastelProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CastelProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/CautelaProtocol.java delete mode 100644 src/org/traccar/protocol/CautelaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CellocatorFrameDecoder.java delete mode 100644 src/org/traccar/protocol/CellocatorProtocol.java delete mode 100644 src/org/traccar/protocol/CellocatorProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CellocatorProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/CguardProtocol.java delete mode 100644 src/org/traccar/protocol/CguardProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CityeasyProtocol.java delete mode 100644 src/org/traccar/protocol/CityeasyProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CityeasyProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/ContinentalProtocol.java delete mode 100644 src/org/traccar/protocol/ContinentalProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/CradlepointProtocol.java delete mode 100644 src/org/traccar/protocol/CradlepointProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/DishaProtocol.java delete mode 100644 src/org/traccar/protocol/DishaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/DmtHttpProtocol.java delete mode 100644 src/org/traccar/protocol/DmtHttpProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/DmtProtocol.java delete mode 100644 src/org/traccar/protocol/DmtProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/DwayProtocol.java delete mode 100644 src/org/traccar/protocol/DwayProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/EasyTrackProtocol.java delete mode 100644 src/org/traccar/protocol/EasyTrackProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/EelinkProtocol.java delete mode 100644 src/org/traccar/protocol/EelinkProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/EelinkProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/EgtsFrameDecoder.java delete mode 100644 src/org/traccar/protocol/EgtsProtocol.java delete mode 100644 src/org/traccar/protocol/EgtsProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/EnforaProtocol.java delete mode 100644 src/org/traccar/protocol/EnforaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/EnforaProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/EsealProtocol.java delete mode 100644 src/org/traccar/protocol/EsealProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/EsealProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/EskyFrameDecoder.java delete mode 100644 src/org/traccar/protocol/EskyProtocol.java delete mode 100644 src/org/traccar/protocol/EskyProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ExtremTracProtocol.java delete mode 100644 src/org/traccar/protocol/ExtremTracProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/FifotrackProtocol.java delete mode 100644 src/org/traccar/protocol/FifotrackProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/FlespiProtocol.java delete mode 100644 src/org/traccar/protocol/FlespiProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/FlexCommProtocol.java delete mode 100644 src/org/traccar/protocol/FlexCommProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/FlextrackProtocol.java delete mode 100644 src/org/traccar/protocol/FlextrackProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/FoxProtocol.java delete mode 100644 src/org/traccar/protocol/FoxProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/FreedomProtocol.java delete mode 100644 src/org/traccar/protocol/FreedomProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/FreematicsProtocol.java delete mode 100644 src/org/traccar/protocol/FreematicsProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GalileoFrameDecoder.java delete mode 100644 src/org/traccar/protocol/GalileoProtocol.java delete mode 100644 src/org/traccar/protocol/GalileoProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GalileoProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/GatorProtocol.java delete mode 100644 src/org/traccar/protocol/GatorProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GenxProtocol.java delete mode 100644 src/org/traccar/protocol/GenxProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gl100Protocol.java delete mode 100644 src/org/traccar/protocol/Gl100ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gl200BinaryProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gl200FrameDecoder.java delete mode 100644 src/org/traccar/protocol/Gl200Protocol.java delete mode 100644 src/org/traccar/protocol/Gl200ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gl200ProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/Gl200TextProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GlobalSatProtocol.java delete mode 100644 src/org/traccar/protocol/GlobalSatProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GnxProtocol.java delete mode 100644 src/org/traccar/protocol/GnxProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GoSafeProtocol.java delete mode 100644 src/org/traccar/protocol/GoSafeProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GotopProtocol.java delete mode 100644 src/org/traccar/protocol/GotopProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gps056FrameDecoder.java delete mode 100644 src/org/traccar/protocol/Gps056Protocol.java delete mode 100644 src/org/traccar/protocol/Gps056ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gps103Protocol.java delete mode 100644 src/org/traccar/protocol/Gps103ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gps103ProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/GpsGateProtocol.java delete mode 100644 src/org/traccar/protocol/GpsGateProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GpsMarkerProtocol.java delete mode 100644 src/org/traccar/protocol/GpsMarkerProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GpsmtaProtocol.java delete mode 100644 src/org/traccar/protocol/GpsmtaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GranitFrameDecoder.java delete mode 100644 src/org/traccar/protocol/GranitProtocol.java delete mode 100644 src/org/traccar/protocol/GranitProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/GranitProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/GranitProtocolSmsEncoder.java delete mode 100644 src/org/traccar/protocol/Gt02Protocol.java delete mode 100644 src/org/traccar/protocol/Gt02ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gt06FrameDecoder.java delete mode 100644 src/org/traccar/protocol/Gt06Protocol.java delete mode 100644 src/org/traccar/protocol/Gt06ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Gt06ProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/Gt30Protocol.java delete mode 100644 src/org/traccar/protocol/Gt30ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/H02FrameDecoder.java delete mode 100644 src/org/traccar/protocol/H02Protocol.java delete mode 100644 src/org/traccar/protocol/H02ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/H02ProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/HaicomProtocol.java delete mode 100644 src/org/traccar/protocol/HaicomProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/HomtecsProtocol.java delete mode 100644 src/org/traccar/protocol/HomtecsProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/HuaShengFrameDecoder.java delete mode 100644 src/org/traccar/protocol/HuaShengProtocol.java delete mode 100644 src/org/traccar/protocol/HuaShengProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/HuabaoFrameDecoder.java delete mode 100644 src/org/traccar/protocol/HuabaoProtocol.java delete mode 100644 src/org/traccar/protocol/HuabaoProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/HuabaoProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/HunterProProtocol.java delete mode 100644 src/org/traccar/protocol/HunterProProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/IdplProtocol.java delete mode 100644 src/org/traccar/protocol/IdplProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/IntellitracFrameDecoder.java delete mode 100644 src/org/traccar/protocol/IntellitracProtocol.java delete mode 100644 src/org/traccar/protocol/IntellitracProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ItsProtocol.java delete mode 100644 src/org/traccar/protocol/ItsProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Ivt401Protocol.java delete mode 100644 src/org/traccar/protocol/Ivt401ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/JpKorjarFrameDecoder.java delete mode 100644 src/org/traccar/protocol/JpKorjarProtocol.java delete mode 100644 src/org/traccar/protocol/JpKorjarProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Jt600FrameDecoder.java delete mode 100644 src/org/traccar/protocol/Jt600Protocol.java delete mode 100644 src/org/traccar/protocol/Jt600ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Jt600ProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/KenjiProtocol.java delete mode 100644 src/org/traccar/protocol/KenjiProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/KhdProtocol.java delete mode 100644 src/org/traccar/protocol/KhdProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/KhdProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/L100FrameDecoder.java delete mode 100644 src/org/traccar/protocol/L100Protocol.java delete mode 100644 src/org/traccar/protocol/L100ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/LaipacProtocol.java delete mode 100644 src/org/traccar/protocol/LaipacProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/M2cProtocol.java delete mode 100644 src/org/traccar/protocol/M2cProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/M2mProtocol.java delete mode 100644 src/org/traccar/protocol/M2mProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MaestroProtocol.java delete mode 100644 src/org/traccar/protocol/MaestroProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ManPowerProtocol.java delete mode 100644 src/org/traccar/protocol/ManPowerProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MegastekFrameDecoder.java delete mode 100644 src/org/traccar/protocol/MegastekProtocol.java delete mode 100644 src/org/traccar/protocol/MegastekProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MeiligaoFrameDecoder.java delete mode 100644 src/org/traccar/protocol/MeiligaoProtocol.java delete mode 100644 src/org/traccar/protocol/MeiligaoProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MeiligaoProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/MeitrackFrameDecoder.java delete mode 100644 src/org/traccar/protocol/MeitrackProtocol.java delete mode 100644 src/org/traccar/protocol/MeitrackProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MeitrackProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/MilesmateProtocol.java delete mode 100644 src/org/traccar/protocol/MilesmateProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MiniFinderProtocol.java delete mode 100644 src/org/traccar/protocol/MiniFinderProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MiniFinderProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/Mta6Protocol.java delete mode 100644 src/org/traccar/protocol/Mta6ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MtxProtocol.java delete mode 100644 src/org/traccar/protocol/MtxProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/MxtFrameDecoder.java delete mode 100644 src/org/traccar/protocol/MxtProtocol.java delete mode 100644 src/org/traccar/protocol/MxtProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/NavigilFrameDecoder.java delete mode 100644 src/org/traccar/protocol/NavigilProtocol.java delete mode 100644 src/org/traccar/protocol/NavigilProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/NavisFrameDecoder.java delete mode 100644 src/org/traccar/protocol/NavisProtocol.java delete mode 100644 src/org/traccar/protocol/NavisProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/NeosProtocol.java delete mode 100644 src/org/traccar/protocol/NeosProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/NoranProtocol.java delete mode 100644 src/org/traccar/protocol/NoranProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/NoranProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/NvsFrameDecoder.java delete mode 100644 src/org/traccar/protocol/NvsProtocol.java delete mode 100644 src/org/traccar/protocol/NvsProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/NyitechProtocol.java delete mode 100644 src/org/traccar/protocol/NyitechProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ObdDongleProtocol.java delete mode 100644 src/org/traccar/protocol/ObdDongleProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/OigoProtocol.java delete mode 100644 src/org/traccar/protocol/OigoProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/OkoProtocol.java delete mode 100644 src/org/traccar/protocol/OkoProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/OpenGtsProtocol.java delete mode 100644 src/org/traccar/protocol/OpenGtsProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/OrionFrameDecoder.java delete mode 100644 src/org/traccar/protocol/OrionProtocol.java delete mode 100644 src/org/traccar/protocol/OrionProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/OsmAndProtocol.java delete mode 100644 src/org/traccar/protocol/OsmAndProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/OwnTracksProtocol.java delete mode 100644 src/org/traccar/protocol/OwnTracksProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/PathAwayProtocol.java delete mode 100644 src/org/traccar/protocol/PathAwayProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/PiligrimProtocol.java delete mode 100644 src/org/traccar/protocol/PiligrimProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/PretraceProtocol.java delete mode 100644 src/org/traccar/protocol/PretraceProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/PretraceProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/PricolProtocol.java delete mode 100644 src/org/traccar/protocol/PricolProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/ProgressProtocol.java delete mode 100644 src/org/traccar/protocol/ProgressProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Pt3000Protocol.java delete mode 100644 src/org/traccar/protocol/Pt3000ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Pt502FrameDecoder.java delete mode 100644 src/org/traccar/protocol/Pt502Protocol.java delete mode 100644 src/org/traccar/protocol/Pt502ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Pt502ProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/Pt60Protocol.java delete mode 100644 src/org/traccar/protocol/Pt60ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/RaveonProtocol.java delete mode 100644 src/org/traccar/protocol/RaveonProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/RecodaProtocol.java delete mode 100644 src/org/traccar/protocol/RecodaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/RetranslatorFrameDecoder.java delete mode 100644 src/org/traccar/protocol/RetranslatorProtocol.java delete mode 100644 src/org/traccar/protocol/RetranslatorProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/RitiProtocol.java delete mode 100644 src/org/traccar/protocol/RitiProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/RoboTrackFrameDecoder.java delete mode 100644 src/org/traccar/protocol/RoboTrackProtocol.java delete mode 100644 src/org/traccar/protocol/RoboTrackProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/RuptelaProtocol.java delete mode 100644 src/org/traccar/protocol/RuptelaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/RuptelaProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/SabertekFrameDecoder.java delete mode 100644 src/org/traccar/protocol/SabertekProtocol.java delete mode 100644 src/org/traccar/protocol/SabertekProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SanavProtocol.java delete mode 100644 src/org/traccar/protocol/SanavProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SatsolProtocol.java delete mode 100644 src/org/traccar/protocol/SatsolProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SigfoxProtocol.java delete mode 100644 src/org/traccar/protocol/SigfoxProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SiwiProtocol.java delete mode 100644 src/org/traccar/protocol/SiwiProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SkypatrolProtocol.java delete mode 100644 src/org/traccar/protocol/SkypatrolProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SmartSoleProtocol.java delete mode 100644 src/org/traccar/protocol/SmartSoleProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SmokeyProtocol.java delete mode 100644 src/org/traccar/protocol/SmokeyProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SpotProtocol.java delete mode 100644 src/org/traccar/protocol/SpotProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/StarLinkProtocol.java delete mode 100644 src/org/traccar/protocol/StarLinkProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Stl060FrameDecoder.java delete mode 100644 src/org/traccar/protocol/Stl060Protocol.java delete mode 100644 src/org/traccar/protocol/Stl060ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SuntechProtocol.java delete mode 100644 src/org/traccar/protocol/SuntechProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SuntechProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/SupermateProtocol.java delete mode 100644 src/org/traccar/protocol/SupermateProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SviasProtocol.java delete mode 100644 src/org/traccar/protocol/SviasProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/SviasProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/T55Protocol.java delete mode 100644 src/org/traccar/protocol/T55ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/T57FrameDecoder.java delete mode 100644 src/org/traccar/protocol/T57Protocol.java delete mode 100644 src/org/traccar/protocol/T57ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/T800xProtocol.java delete mode 100644 src/org/traccar/protocol/T800xProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/T800xProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/TaipProtocol.java delete mode 100644 src/org/traccar/protocol/TaipProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TekFrameDecoder.java delete mode 100644 src/org/traccar/protocol/TekProtocol.java delete mode 100644 src/org/traccar/protocol/TekProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TelemaxProtocol.java delete mode 100644 src/org/traccar/protocol/TelemaxProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TelicFrameDecoder.java delete mode 100644 src/org/traccar/protocol/TelicProtocol.java delete mode 100644 src/org/traccar/protocol/TelicProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TeltonikaFrameDecoder.java delete mode 100644 src/org/traccar/protocol/TeltonikaProtocol.java delete mode 100644 src/org/traccar/protocol/TeltonikaProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TeltonikaProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/ThinkRaceProtocol.java delete mode 100644 src/org/traccar/protocol/ThinkRaceProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Tk102Protocol.java delete mode 100644 src/org/traccar/protocol/Tk102ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Tk103FrameDecoder.java delete mode 100644 src/org/traccar/protocol/Tk103Protocol.java delete mode 100644 src/org/traccar/protocol/Tk103ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Tk103ProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/Tlt2hProtocol.java delete mode 100644 src/org/traccar/protocol/Tlt2hProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TlvProtocol.java delete mode 100644 src/org/traccar/protocol/TlvProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TmgFrameDecoder.java delete mode 100644 src/org/traccar/protocol/TmgProtocol.java delete mode 100644 src/org/traccar/protocol/TmgProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TopflytechProtocol.java delete mode 100644 src/org/traccar/protocol/TopflytechProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TotemFrameDecoder.java delete mode 100644 src/org/traccar/protocol/TotemProtocol.java delete mode 100644 src/org/traccar/protocol/TotemProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TotemProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/Tr20Protocol.java delete mode 100644 src/org/traccar/protocol/Tr20ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Tr900Protocol.java delete mode 100644 src/org/traccar/protocol/Tr900ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TrackboxProtocol.java delete mode 100644 src/org/traccar/protocol/TrackboxProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TrakMateProtocol.java delete mode 100644 src/org/traccar/protocol/TrakMateProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TramigoFrameDecoder.java delete mode 100644 src/org/traccar/protocol/TramigoProtocol.java delete mode 100644 src/org/traccar/protocol/TramigoProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TrvProtocol.java delete mode 100644 src/org/traccar/protocol/TrvProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Tt8850Protocol.java delete mode 100644 src/org/traccar/protocol/Tt8850ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TytanProtocol.java delete mode 100644 src/org/traccar/protocol/TytanProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/TzoneProtocol.java delete mode 100644 src/org/traccar/protocol/TzoneProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/UlbotechFrameDecoder.java delete mode 100644 src/org/traccar/protocol/UlbotechProtocol.java delete mode 100644 src/org/traccar/protocol/UlbotechProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/UproProtocol.java delete mode 100644 src/org/traccar/protocol/UproProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/V680Protocol.java delete mode 100644 src/org/traccar/protocol/V680ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/VisiontekProtocol.java delete mode 100644 src/org/traccar/protocol/VisiontekProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Vt200FrameDecoder.java delete mode 100644 src/org/traccar/protocol/Vt200Protocol.java delete mode 100644 src/org/traccar/protocol/Vt200ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/VtfmsFrameDecoder.java delete mode 100644 src/org/traccar/protocol/VtfmsProtocol.java delete mode 100644 src/org/traccar/protocol/VtfmsProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/WatchFrameDecoder.java delete mode 100644 src/org/traccar/protocol/WatchProtocol.java delete mode 100644 src/org/traccar/protocol/WatchProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/WatchProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/WialonProtocol.java delete mode 100644 src/org/traccar/protocol/WialonProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/WialonProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/WondexFrameDecoder.java delete mode 100644 src/org/traccar/protocol/WondexProtocol.java delete mode 100644 src/org/traccar/protocol/WondexProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/WondexProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/WristbandProtocol.java delete mode 100644 src/org/traccar/protocol/WristbandProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/XexunFrameDecoder.java delete mode 100644 src/org/traccar/protocol/XexunProtocol.java delete mode 100644 src/org/traccar/protocol/XexunProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/XexunProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/XirgoProtocol.java delete mode 100644 src/org/traccar/protocol/XirgoProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/XirgoProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/Xrb28Protocol.java delete mode 100644 src/org/traccar/protocol/Xrb28ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Xrb28ProtocolEncoder.java delete mode 100644 src/org/traccar/protocol/Xt013Protocol.java delete mode 100644 src/org/traccar/protocol/Xt013ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/Xt2400Protocol.java delete mode 100644 src/org/traccar/protocol/Xt2400ProtocolDecoder.java delete mode 100644 src/org/traccar/protocol/YwtProtocol.java delete mode 100644 src/org/traccar/protocol/YwtProtocolDecoder.java delete mode 100644 src/org/traccar/reports/Events.java delete mode 100644 src/org/traccar/reports/ReportUtils.java delete mode 100644 src/org/traccar/reports/Route.java delete mode 100644 src/org/traccar/reports/Stops.java delete mode 100644 src/org/traccar/reports/Summary.java delete mode 100644 src/org/traccar/reports/Trips.java delete mode 100644 src/org/traccar/reports/model/BaseReport.java delete mode 100644 src/org/traccar/reports/model/DeviceReport.java delete mode 100644 src/org/traccar/reports/model/StopReport.java delete mode 100644 src/org/traccar/reports/model/SummaryReport.java delete mode 100644 src/org/traccar/reports/model/TripReport.java delete mode 100644 src/org/traccar/reports/model/TripsConfig.java delete mode 100644 src/org/traccar/sms/HttpSmsClient.java delete mode 100644 src/org/traccar/sms/SmsManager.java delete mode 100644 src/org/traccar/sms/smpp/ClientSmppSessionHandler.java delete mode 100644 src/org/traccar/sms/smpp/EnquireLinkTask.java delete mode 100644 src/org/traccar/sms/smpp/ReconnectionTask.java delete mode 100644 src/org/traccar/sms/smpp/SmppClient.java delete mode 100644 src/org/traccar/sms/smpp/TextMessageEventHandler.java delete mode 100644 src/org/traccar/web/ConsoleServlet.java delete mode 100644 src/org/traccar/web/CsvBuilder.java delete mode 100644 src/org/traccar/web/GpxBuilder.java delete mode 100644 src/org/traccar/web/WebServer.java create mode 100644 src/test/java/org/traccar/BaseTest.java create mode 100644 src/test/java/org/traccar/ProtocolTest.java create mode 100644 src/test/java/org/traccar/TestIdentityManager.java create mode 100644 src/test/java/org/traccar/WebDataHandlerTest.java create mode 100644 src/test/java/org/traccar/calendar/CalendarTest.java create mode 100644 src/test/java/org/traccar/config/ConfigTest.java create mode 100644 src/test/java/org/traccar/database/DataManagerTest.java create mode 100644 src/test/java/org/traccar/database/GroupTreeTest.java create mode 100644 src/test/java/org/traccar/geocoder/AddressFormatTest.java create mode 100644 src/test/java/org/traccar/geocoder/GeocoderTest.java create mode 100644 src/test/java/org/traccar/geofence/GeofenceCircleTest.java create mode 100644 src/test/java/org/traccar/geofence/GeofencePolygonTest.java create mode 100644 src/test/java/org/traccar/geofence/GeofencePolylineTest.java create mode 100644 src/test/java/org/traccar/geolocation/GeolocationProviderTest.java create mode 100644 src/test/java/org/traccar/handler/ComputedAttributesTest.java create mode 100644 src/test/java/org/traccar/handler/DistanceHandlerTest.java create mode 100644 src/test/java/org/traccar/handler/FilterHandlerTest.java create mode 100644 src/test/java/org/traccar/handler/MotionHandlerTest.java create mode 100644 src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java create mode 100644 src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java create mode 100644 src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java create mode 100644 src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java create mode 100644 src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java create mode 100644 src/test/java/org/traccar/helper/BcdUtilTest.java create mode 100644 src/test/java/org/traccar/helper/BitBufferTest.java create mode 100644 src/test/java/org/traccar/helper/BitUtilTest.java create mode 100644 src/test/java/org/traccar/helper/ChecksumTest.java create mode 100644 src/test/java/org/traccar/helper/DateBuilderTest.java create mode 100644 src/test/java/org/traccar/helper/DateUtilTest.java create mode 100644 src/test/java/org/traccar/helper/DistanceCalculatorTest.java create mode 100644 src/test/java/org/traccar/helper/LocationTreeTest.java create mode 100644 src/test/java/org/traccar/helper/LogTest.java create mode 100644 src/test/java/org/traccar/helper/ObdDecoderTest.java create mode 100644 src/test/java/org/traccar/helper/PatternBuilderTest.java create mode 100644 src/test/java/org/traccar/helper/PatternUtilTest.java create mode 100644 src/test/java/org/traccar/model/MiscFormatterTest.java create mode 100644 src/test/java/org/traccar/notification/NotificiationMailTest.java create mode 100644 src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AppletProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ArnaviProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/H02FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java create mode 100755 src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/L100FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java create mode 100755 src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/T57FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TekFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java create mode 100644 src/test/java/org/traccar/reports/ReportUtilsTest.java create mode 100644 src/test/java/org/traccar/web/WebServerTest.java (limited to 'src') diff --git a/src/main/java/org/traccar/BaseDataHandler.java b/src/main/java/org/traccar/BaseDataHandler.java new file mode 100644 index 000000000..48794b0d7 --- /dev/null +++ b/src/main/java/org/traccar/BaseDataHandler.java @@ -0,0 +1,38 @@ +/* + * 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. + * 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 io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.traccar.model.Position; + +public abstract class BaseDataHandler extends ChannelInboundHandlerAdapter { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof Position) { + Position position = handlePosition((Position) msg); + if (position != null) { + ctx.fireChannelRead(position); + } + } else { + super.channelRead(ctx, msg); + } + } + + protected abstract Position handlePosition(Position position); + +} diff --git a/src/main/java/org/traccar/BaseFrameDecoder.java b/src/main/java/org/traccar/BaseFrameDecoder.java new file mode 100644 index 000000000..f90f90e4b --- /dev/null +++ b/src/main/java/org/traccar/BaseFrameDecoder.java @@ -0,0 +1,37 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; + +public abstract class BaseFrameDecoder extends ByteToMessageDecoder { + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + Object decoded = decode(ctx, ctx != null ? ctx.channel() : null, in); + if (decoded != null) { + out.add(decoded); + } + } + + protected abstract Object decode(ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception; + +} diff --git a/src/main/java/org/traccar/BaseHttpProtocolDecoder.java b/src/main/java/org/traccar/BaseHttpProtocolDecoder.java new file mode 100644 index 000000000..57a68acac --- /dev/null +++ b/src/main/java/org/traccar/BaseHttpProtocolDecoder.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; + +public abstract class BaseHttpProtocolDecoder extends BaseProtocolDecoder { + + public BaseHttpProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public void sendResponse(Channel channel, HttpResponseStatus status) { + if (channel != null) { + HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status); + response.headers().add(HttpHeaderNames.CONTENT_LENGTH, 0); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + +} diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java new file mode 100644 index 000000000..b3d37f689 --- /dev/null +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -0,0 +1,169 @@ +/* + * Copyright 2012 - 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. + * 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 io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOutboundHandler; +import io.netty.channel.ChannelPipeline; +import io.netty.handler.timeout.IdleStateHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Keys; +import org.traccar.handler.DefaultDataHandler; +import org.traccar.handler.events.AlertEventHandler; +import org.traccar.handler.events.CommandResultEventHandler; +import org.traccar.handler.events.DriverEventHandler; +import org.traccar.handler.events.FuelDropEventHandler; +import org.traccar.handler.events.GeofenceEventHandler; +import org.traccar.handler.events.IgnitionEventHandler; +import org.traccar.handler.events.MaintenanceEventHandler; +import org.traccar.handler.events.MotionEventHandler; +import org.traccar.handler.events.OverspeedEventHandler; +import org.traccar.handler.ComputedAttributesHandler; +import org.traccar.handler.CopyAttributesHandler; +import org.traccar.handler.DistanceHandler; +import org.traccar.handler.EngineHoursHandler; +import org.traccar.handler.FilterHandler; +import org.traccar.handler.GeocoderHandler; +import org.traccar.handler.GeolocationHandler; +import org.traccar.handler.HemisphereHandler; +import org.traccar.handler.MotionHandler; +import org.traccar.handler.NetworkMessageHandler; +import org.traccar.handler.OpenChannelHandler; +import org.traccar.handler.RemoteAddressHandler; +import org.traccar.handler.StandardLoggingHandler; + +import java.util.Map; + +public abstract class BasePipelineFactory extends ChannelInitializer { + + private static final Logger LOGGER = LoggerFactory.getLogger(BasePipelineFactory.class); + + private final TrackerServer server; + private boolean eventsEnabled; + private int timeout; + + public BasePipelineFactory(TrackerServer server, String protocol) { + this.server = server; + eventsEnabled = Context.getConfig().getBoolean(Keys.EVENT_ENABLE); + timeout = Context.getConfig().getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol)); + if (timeout == 0) { + timeout = Context.getConfig().getInteger(Keys.SERVER_TIMEOUT); + } + } + + protected abstract void addProtocolHandlers(PipelineBuilder pipeline); + + @SafeVarargs + private final void addHandlers(ChannelPipeline pipeline, Class... handlerClasses) { + for (Class handlerClass : handlerClasses) { + if (handlerClass != null) { + pipeline.addLast(Main.getInjector().getInstance(handlerClass)); + } + } + } + + public static T getHandler(ChannelPipeline pipeline, Class clazz) { + for (Map.Entry handlerEntry : pipeline) { + ChannelHandler handler = handlerEntry.getValue(); + if (handler instanceof WrapperInboundHandler) { + handler = ((WrapperInboundHandler) handler).getWrappedHandler(); + } else if (handler instanceof WrapperOutboundHandler) { + handler = ((WrapperOutboundHandler) handler).getWrappedHandler(); + } + if (clazz.isAssignableFrom(handler.getClass())) { + return (T) handler; + } + } + return null; + } + + @Override + protected void initChannel(Channel channel) { + final ChannelPipeline pipeline = channel.pipeline(); + + if (timeout > 0 && !server.isDatagram()) { + pipeline.addLast(new IdleStateHandler(timeout, 0, 0)); + } + pipeline.addLast(new OpenChannelHandler(server)); + pipeline.addLast(new NetworkMessageHandler()); + pipeline.addLast(new StandardLoggingHandler()); + + addProtocolHandlers(handler -> { + if (!(handler instanceof BaseProtocolDecoder || handler instanceof BaseProtocolEncoder)) { + if (handler instanceof ChannelInboundHandler) { + handler = new WrapperInboundHandler((ChannelInboundHandler) handler); + } else { + handler = new WrapperOutboundHandler((ChannelOutboundHandler) handler); + } + } + pipeline.addLast(handler); + }); + + addHandlers( + pipeline, + GeolocationHandler.class, + HemisphereHandler.class, + DistanceHandler.class, + RemoteAddressHandler.class); + + addDynamicHandlers(pipeline); + + addHandlers( + pipeline, + FilterHandler.class, + GeocoderHandler.class, + MotionHandler.class, + EngineHoursHandler.class, + CopyAttributesHandler.class, + ComputedAttributesHandler.class, + WebDataHandler.class, + DefaultDataHandler.class); + + if (eventsEnabled) { + addHandlers( + pipeline, + CommandResultEventHandler.class, + OverspeedEventHandler.class, + FuelDropEventHandler.class, + MotionEventHandler.class, + GeofenceEventHandler.class, + AlertEventHandler.class, + IgnitionEventHandler.class, + MaintenanceEventHandler.class, + DriverEventHandler.class); + } + + pipeline.addLast(new MainEventHandler()); + } + + private void addDynamicHandlers(ChannelPipeline pipeline) { + String handlers = Context.getConfig().getString(Keys.EXTRA_HANDLERS); + if (handlers != null) { + for (String handler : handlers.split(",")) { + try { + pipeline.addLast((ChannelHandler) Class.forName(handler).getDeclaredConstructor().newInstance()); + } catch (ReflectiveOperationException error) { + LOGGER.warn("Dynamic handler error", error); + } + } + } + } + +} diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java new file mode 100644 index 000000000..c0fd1e27f --- /dev/null +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -0,0 +1,131 @@ +/* + * 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. + * 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 io.netty.buffer.Unpooled; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.database.ActiveDevice; +import org.traccar.helper.DataConverter; +import org.traccar.model.Command; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public abstract class BaseProtocol implements Protocol { + + private final String name; + private final Set supportedDataCommands = new HashSet<>(); + private final Set supportedTextCommands = new HashSet<>(); + private final List serverList = new LinkedList<>(); + + private StringProtocolEncoder textCommandEncoder = null; + + public static String nameFromClass(Class clazz) { + String className = clazz.getSimpleName(); + return className.substring(0, className.length() - 8).toLowerCase(); + } + + public BaseProtocol() { + name = nameFromClass(getClass()); + } + + @Override + public String getName() { + return name; + } + + protected void addServer(TrackerServer server) { + serverList.add(server); + } + + @Override + public Collection getServerList() { + return serverList; + } + + public void setSupportedDataCommands(String... commands) { + supportedDataCommands.addAll(Arrays.asList(commands)); + } + + public void setSupportedTextCommands(String... commands) { + supportedTextCommands.addAll(Arrays.asList(commands)); + } + + public void setSupportedCommands(String... commands) { + supportedDataCommands.addAll(Arrays.asList(commands)); + supportedTextCommands.addAll(Arrays.asList(commands)); + } + + @Override + public Collection getSupportedDataCommands() { + Set commands = new HashSet<>(supportedDataCommands); + commands.add(Command.TYPE_CUSTOM); + return commands; + } + + @Override + public Collection getSupportedTextCommands() { + Set commands = new HashSet<>(supportedTextCommands); + commands.add(Command.TYPE_CUSTOM); + return commands; + } + + @Override + public void sendDataCommand(ActiveDevice activeDevice, Command command) { + if (supportedDataCommands.contains(command.getType())) { + activeDevice.write(command); + } else if (command.getType().equals(Command.TYPE_CUSTOM)) { + String data = command.getString(Command.KEY_DATA); + if (BasePipelineFactory.getHandler(activeDevice.getChannel().pipeline(), StringEncoder.class) != null) { + activeDevice.write(data); + } else { + activeDevice.write(Unpooled.wrappedBuffer(DataConverter.parseHex(data))); + } + } else { + throw new RuntimeException("Command " + command.getType() + " is not supported in protocol " + getName()); + } + } + + public void setTextCommandEncoder(StringProtocolEncoder textCommandEncoder) { + this.textCommandEncoder = textCommandEncoder; + } + + @Override + public void sendTextCommand(String destAddress, Command command) throws Exception { + if (Context.getSmsManager() != null) { + if (command.getType().equals(Command.TYPE_CUSTOM)) { + Context.getSmsManager().sendMessageSync(destAddress, command.getString(Command.KEY_DATA), true); + } else if (supportedTextCommands.contains(command.getType()) && textCommandEncoder != null) { + String encodedCommand = (String) textCommandEncoder.encodeCommand(command); + if (encodedCommand != null) { + Context.getSmsManager().sendMessageSync(destAddress, encodedCommand, true); + } else { + throw new RuntimeException("Failed to encode command"); + } + } else { + throw new RuntimeException( + "Command " + command.getType() + " is not supported in protocol " + getName()); + } + } else { + throw new RuntimeException("SMS is not enabled"); + } + } + +} diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java new file mode 100644 index 000000000..aa5be612e --- /dev/null +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -0,0 +1,255 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import io.netty.channel.socket.DatagramChannel; +import io.netty.handler.codec.http.HttpRequestDecoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.database.ConnectionManager; +import org.traccar.database.IdentityManager; +import org.traccar.database.StatisticsManager; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Device; +import org.traccar.model.Position; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.TimeZone; + +public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(BaseProtocolDecoder.class); + + private static final String PROTOCOL_UNKNOWN = "unknown"; + + private final Config config = Context.getConfig(); + private final IdentityManager identityManager = Context.getIdentityManager(); + private final ConnectionManager connectionManager = Context.getConnectionManager(); + private final StatisticsManager statisticsManager; + private final Protocol protocol; + + public BaseProtocolDecoder(Protocol protocol) { + this.protocol = protocol; + statisticsManager = Main.getInjector() != null ? Main.getInjector().getInstance(StatisticsManager.class) : null; + } + + public String getProtocolName() { + return protocol != null ? protocol.getName() : PROTOCOL_UNKNOWN; + } + + public String getServer(Channel channel, char delimiter) { + String server = config.getString(getProtocolName() + ".server"); + if (server == null && channel != null) { + InetSocketAddress address = (InetSocketAddress) channel.localAddress(); + server = address.getAddress().getHostAddress() + ":" + address.getPort(); + } + return server != null ? server.replace(':', delimiter) : null; + } + + protected double convertSpeed(double value, String defaultUnits) { + switch (config.getString(getProtocolName() + ".speed", defaultUnits)) { + case "kmh": + return UnitsConverter.knotsFromKph(value); + case "mps": + return UnitsConverter.knotsFromMps(value); + case "mph": + return UnitsConverter.knotsFromMph(value); + case "kn": + default: + return value; + } + } + + protected TimeZone getTimeZone(long deviceId) { + return getTimeZone(deviceId, "UTC"); + } + + protected TimeZone getTimeZone(long deviceId, String defaultTimeZone) { + TimeZone result = TimeZone.getTimeZone(defaultTimeZone); + String timeZoneName = identityManager.lookupAttributeString(deviceId, "decoder.timezone", null, true); + if (timeZoneName != null) { + result = TimeZone.getTimeZone(timeZoneName); + } else { + int timeZoneOffset = config.getInteger(getProtocolName() + ".timezone", 0); + if (timeZoneOffset != 0) { + result.setRawOffset(timeZoneOffset * 1000); + LOGGER.warn("Config parameter " + getProtocolName() + ".timezone is deprecated"); + } + } + return result; + } + + private DeviceSession channelDeviceSession; // connection-based protocols + private Map addressDeviceSessions = new HashMap<>(); // connectionless protocols + + private long findDeviceId(SocketAddress remoteAddress, String... uniqueIds) { + if (uniqueIds.length > 0) { + long deviceId = 0; + Device device = null; + try { + for (String uniqueId : uniqueIds) { + if (uniqueId != null) { + device = identityManager.getByUniqueId(uniqueId); + if (device != null) { + deviceId = device.getId(); + break; + } + } + } + } catch (Exception e) { + LOGGER.warn("Find device error", e); + } + if (deviceId == 0 && config.getBoolean("database.registerUnknown")) { + return identityManager.addUnknownDevice(uniqueIds[0]); + } + if (device != null && !device.getDisabled() || config.getBoolean("database.storeDisabled")) { + return deviceId; + } + StringBuilder message = new StringBuilder(); + if (deviceId == 0) { + message.append("Unknown device -"); + } else { + message.append("Disabled device -"); + } + for (String uniqueId : uniqueIds) { + message.append(" ").append(uniqueId); + } + if (remoteAddress != null) { + message.append(" (").append(((InetSocketAddress) remoteAddress).getHostString()).append(")"); + } + LOGGER.warn(message.toString()); + } + return 0; + } + + public DeviceSession getDeviceSession(Channel channel, SocketAddress remoteAddress, String... uniqueIds) { + if (channel != null && BasePipelineFactory.getHandler(channel.pipeline(), HttpRequestDecoder.class) != null + || config.getBoolean("decoder.ignoreSessionCache")) { + long deviceId = findDeviceId(remoteAddress, uniqueIds); + if (deviceId != 0) { + if (connectionManager != null) { + connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress); + } + return new DeviceSession(deviceId); + } else { + return null; + } + } + if (channel instanceof DatagramChannel) { + long deviceId = findDeviceId(remoteAddress, uniqueIds); + DeviceSession deviceSession = addressDeviceSessions.get(remoteAddress); + if (deviceSession != null && (deviceSession.getDeviceId() == deviceId || uniqueIds.length == 0)) { + return deviceSession; + } else if (deviceId != 0) { + deviceSession = new DeviceSession(deviceId); + addressDeviceSessions.put(remoteAddress, deviceSession); + if (connectionManager != null) { + connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress); + } + return deviceSession; + } else { + return null; + } + } else { + if (channelDeviceSession == null) { + long deviceId = findDeviceId(remoteAddress, uniqueIds); + if (deviceId != 0) { + channelDeviceSession = new DeviceSession(deviceId); + if (connectionManager != null) { + connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress); + } + } + } + return channelDeviceSession; + } + } + + public void getLastLocation(Position position, Date deviceTime) { + if (position.getDeviceId() != 0) { + position.setOutdated(true); + + Position last = identityManager.getLastPosition(position.getDeviceId()); + if (last != null) { + position.setFixTime(last.getFixTime()); + position.setValid(last.getValid()); + position.setLatitude(last.getLatitude()); + position.setLongitude(last.getLongitude()); + position.setAltitude(last.getAltitude()); + position.setSpeed(last.getSpeed()); + position.setCourse(last.getCourse()); + position.setAccuracy(last.getAccuracy()); + } else { + position.setFixTime(new Date(0)); + } + + if (deviceTime != null) { + position.setDeviceTime(deviceTime); + } else { + position.setDeviceTime(new Date()); + } + } + } + + @Override + protected void onMessageEvent( + Channel channel, SocketAddress remoteAddress, Object originalMessage, Object decodedMessage) { + if (statisticsManager != null) { + statisticsManager.registerMessageReceived(); + } + Position position = null; + if (decodedMessage != null) { + if (decodedMessage instanceof Position) { + position = (Position) decodedMessage; + } else if (decodedMessage instanceof Collection) { + Collection positions = (Collection) decodedMessage; + if (!positions.isEmpty()) { + position = (Position) positions.iterator().next(); + } + } + } + if (position != null) { + connectionManager.updateDevice( + position.getDeviceId(), Device.STATUS_ONLINE, new Date()); + } else { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession != null) { + connectionManager.updateDevice( + deviceSession.getDeviceId(), Device.STATUS_ONLINE, new Date()); + } + } + } + + @Override + protected Object handleEmptyMessage(Channel channel, SocketAddress remoteAddress, Object msg) { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (config.getBoolean("database.saveEmpty") && deviceSession != null) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, null); + return position; + } else { + return null; + } + } + +} diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java new file mode 100644 index 000000000..d7625e4b8 --- /dev/null +++ b/src/main/java/org/traccar/BaseProtocolEncoder.java @@ -0,0 +1,85 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.model.Command; +import org.traccar.model.Device; + +public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(BaseProtocolEncoder.class); + + protected String getUniqueId(long deviceId) { + return Context.getIdentityManager().getById(deviceId).getUniqueId(); + } + + protected void initDevicePassword(Command command, String defaultPassword) { + if (!command.getAttributes().containsKey(Command.KEY_DEVICE_PASSWORD)) { + Device device = Context.getIdentityManager().getById(command.getDeviceId()); + String password = device.getString(Command.KEY_DEVICE_PASSWORD); + if (password != null) { + command.set(Command.KEY_DEVICE_PASSWORD, password); + } else { + command.set(Command.KEY_DEVICE_PASSWORD, defaultPassword); + } + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + + NetworkMessage networkMessage = (NetworkMessage) msg; + + if (networkMessage.getMessage() instanceof Command) { + + Command command = (Command) networkMessage.getMessage(); + Object encodedCommand = encodeCommand(ctx.channel(), command); + + StringBuilder s = new StringBuilder(); + s.append("[").append(ctx.channel().id().asShortText()).append("] "); + s.append("id: ").append(getUniqueId(command.getDeviceId())).append(", "); + s.append("command type: ").append(command.getType()).append(" "); + if (encodedCommand != null) { + s.append("sent"); + } else { + s.append("not sent"); + } + LOGGER.info(s.toString()); + + ctx.write(new NetworkMessage(encodedCommand, networkMessage.getRemoteAddress()), promise); + + } else { + + super.write(ctx, msg, promise); + + } + } + + protected Object encodeCommand(Channel channel, Command command) { + return encodeCommand(command); + } + + protected Object encodeCommand(Command command) { + return null; + } + +} diff --git a/src/main/java/org/traccar/CharacterDelimiterFrameDecoder.java b/src/main/java/org/traccar/CharacterDelimiterFrameDecoder.java new file mode 100644 index 000000000..eeb8834dc --- /dev/null +++ b/src/main/java/org/traccar/CharacterDelimiterFrameDecoder.java @@ -0,0 +1,65 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.DelimiterBasedFrameDecoder; + +public class CharacterDelimiterFrameDecoder extends DelimiterBasedFrameDecoder { + + private static ByteBuf createDelimiter(char delimiter) { + byte[] buf = {(byte) delimiter}; + return Unpooled.wrappedBuffer(buf); + } + + private static ByteBuf createDelimiter(String delimiter) { + byte[] buf = new byte[delimiter.length()]; + for (int i = 0; i < delimiter.length(); i++) { + buf[i] = (byte) delimiter.charAt(i); + } + return Unpooled.wrappedBuffer(buf); + } + + private static ByteBuf[] convertDelimiters(String[] delimiters) { + ByteBuf[] result = new ByteBuf[delimiters.length]; + for (int i = 0; i < delimiters.length; i++) { + result[i] = createDelimiter(delimiters[i]); + } + return result; + } + + public CharacterDelimiterFrameDecoder(int maxFrameLength, char delimiter) { + super(maxFrameLength, createDelimiter(delimiter)); + } + + public CharacterDelimiterFrameDecoder(int maxFrameLength, String delimiter) { + super(maxFrameLength, createDelimiter(delimiter)); + } + + public CharacterDelimiterFrameDecoder(int maxFrameLength, boolean stripDelimiter, String delimiter) { + super(maxFrameLength, stripDelimiter, createDelimiter(delimiter)); + } + + public CharacterDelimiterFrameDecoder(int maxFrameLength, String... delimiters) { + super(maxFrameLength, convertDelimiters(delimiters)); + } + + public CharacterDelimiterFrameDecoder(int maxFrameLength, boolean stripDelimiter, String... delimiters) { + super(maxFrameLength, stripDelimiter, convertDelimiters(delimiters)); + } + +} diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java new file mode 100644 index 000000000..9c20db9e4 --- /dev/null +++ b/src/main/java/org/traccar/Context.java @@ -0,0 +1,410 @@ +/* + * Copyright 2015 - 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. + * 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 com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr353.JSR353Module; +import org.apache.velocity.app.VelocityEngine; +import org.eclipse.jetty.util.URIUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.database.AttributesManager; +import org.traccar.database.BaseObjectManager; +import org.traccar.database.CalendarManager; +import org.traccar.database.CommandsManager; +import org.traccar.database.ConnectionManager; +import org.traccar.database.DataManager; +import org.traccar.database.DeviceManager; +import org.traccar.database.DriversManager; +import org.traccar.database.GeofenceManager; +import org.traccar.database.GroupsManager; +import org.traccar.database.IdentityManager; +import org.traccar.database.LdapProvider; +import org.traccar.database.MailManager; +import org.traccar.database.MaintenancesManager; +import org.traccar.database.MediaManager; +import org.traccar.database.NotificationManager; +import org.traccar.database.PermissionsManager; +import org.traccar.database.UsersManager; +import org.traccar.geocoder.Geocoder; +import org.traccar.helper.Log; +import org.traccar.helper.SanitizerModule; +import org.traccar.model.Attribute; +import org.traccar.model.BaseModel; +import org.traccar.model.Calendar; +import org.traccar.model.Command; +import org.traccar.model.Device; +import org.traccar.model.Driver; +import org.traccar.model.Geofence; +import org.traccar.model.Group; +import org.traccar.model.Maintenance; +import org.traccar.model.Notification; +import org.traccar.model.User; +import org.traccar.notification.EventForwarder; +import org.traccar.notification.JsonTypeEventForwarder; +import org.traccar.notification.NotificatorManager; +import org.traccar.reports.model.TripsConfig; +import org.traccar.sms.SmsManager; +import org.traccar.sms.smpp.SmppClient; +import org.traccar.web.WebServer; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.ext.ContextResolver; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Properties; + +public final class Context { + + private static final Logger LOGGER = LoggerFactory.getLogger(Context.class); + + private Context() { + } + + private static Config config; + + public static Config getConfig() { + return config; + } + + private static ObjectMapper objectMapper; + + public static ObjectMapper getObjectMapper() { + return objectMapper; + } + + private static IdentityManager identityManager; + + public static IdentityManager getIdentityManager() { + return identityManager; + } + + private static DataManager dataManager; + + public static DataManager getDataManager() { + return dataManager; + } + + private static LdapProvider ldapProvider; + + public static LdapProvider getLdapProvider() { + return ldapProvider; + } + + private static MailManager mailManager; + + public static MailManager getMailManager() { + return mailManager; + } + + private static MediaManager mediaManager; + + public static MediaManager getMediaManager() { + return mediaManager; + } + + private static UsersManager usersManager; + + public static UsersManager getUsersManager() { + return usersManager; + } + + private static GroupsManager groupsManager; + + public static GroupsManager getGroupsManager() { + return groupsManager; + } + + private static DeviceManager deviceManager; + + public static DeviceManager getDeviceManager() { + return deviceManager; + } + + private static ConnectionManager connectionManager; + + public static ConnectionManager getConnectionManager() { + return connectionManager; + } + + private static PermissionsManager permissionsManager; + + public static PermissionsManager getPermissionsManager() { + return permissionsManager; + } + + public static Geocoder getGeocoder() { + return Main.getInjector() != null ? Main.getInjector().getInstance(Geocoder.class) : null; + } + + private static WebServer webServer; + + public static WebServer getWebServer() { + return webServer; + } + + private static ServerManager serverManager; + + public static ServerManager getServerManager() { + return serverManager; + } + + private static GeofenceManager geofenceManager; + + public static GeofenceManager getGeofenceManager() { + return geofenceManager; + } + + private static CalendarManager calendarManager; + + public static CalendarManager getCalendarManager() { + return calendarManager; + } + + private static NotificationManager notificationManager; + + public static NotificationManager getNotificationManager() { + return notificationManager; + } + + private static NotificatorManager notificatorManager; + + public static NotificatorManager getNotificatorManager() { + return notificatorManager; + } + + private static VelocityEngine velocityEngine; + + public static VelocityEngine getVelocityEngine() { + return velocityEngine; + } + + private static Client client = ClientBuilder.newClient(); + + public static Client getClient() { + return client; + } + + private static EventForwarder eventForwarder; + + public static EventForwarder getEventForwarder() { + return eventForwarder; + } + + private static AttributesManager attributesManager; + + public static AttributesManager getAttributesManager() { + return attributesManager; + } + + private static DriversManager driversManager; + + public static DriversManager getDriversManager() { + return driversManager; + } + + private static CommandsManager commandsManager; + + public static CommandsManager getCommandsManager() { + return commandsManager; + } + + private static MaintenancesManager maintenancesManager; + + public static MaintenancesManager getMaintenancesManager() { + return maintenancesManager; + } + + private static SmsManager smsManager; + + public static SmsManager getSmsManager() { + return smsManager; + } + + private static TripsConfig tripsConfig; + + public static TripsConfig getTripsConfig() { + return tripsConfig; + } + + public static TripsConfig initTripsConfig() { + return new TripsConfig( + config.getLong("report.trip.minimalTripDistance", 500), + config.getLong("report.trip.minimalTripDuration", 300) * 1000, + config.getLong("report.trip.minimalParkingDuration", 300) * 1000, + config.getLong("report.trip.minimalNoDataDuration", 3600) * 1000, + config.getBoolean("report.trip.useIgnition"), + config.getBoolean("event.motion.processInvalidPositions"), + config.getDouble("event.motion.speedThreshold", 0.01)); + } + + private static class ObjectMapperContextResolver implements ContextResolver { + + @Override + public ObjectMapper getContext(Class clazz) { + return objectMapper; + } + + } + + public static void init(String configFile) throws Exception { + + try { + config = new Config(configFile); + } catch (Exception e) { + config = new Config(); + Log.setupDefaultLogger(); + throw e; + } + + if (config.getBoolean("logger.enable")) { + Log.setupLogger(config); + } + + objectMapper = new ObjectMapper(); + objectMapper.registerModule(new SanitizerModule()); + objectMapper.registerModule(new JSR353Module()); + objectMapper.setConfig( + objectMapper.getSerializationConfig().without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)); + if (Context.getConfig().getBoolean("mapper.prettyPrintedJson")) { + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + } + + client = ClientBuilder.newClient().register(new ObjectMapperContextResolver()); + + if (config.hasKey("database.url")) { + dataManager = new DataManager(config); + } + + if (config.getBoolean("ldap.enable")) { + ldapProvider = new LdapProvider(config); + } + + mailManager = new MailManager(); + + mediaManager = new MediaManager(config.getString("media.path")); + + if (dataManager != null) { + usersManager = new UsersManager(dataManager); + groupsManager = new GroupsManager(dataManager); + deviceManager = new DeviceManager(dataManager); + } + + identityManager = deviceManager; + + if (config.getBoolean("web.enable")) { + webServer = new WebServer(config); + } + + permissionsManager = new PermissionsManager(dataManager, usersManager); + + connectionManager = new ConnectionManager(); + + tripsConfig = initTripsConfig(); + + if (config.getBoolean("sms.enable")) { + final String smsManagerClass = config.getString("sms.manager.class", SmppClient.class.getCanonicalName()); + try { + smsManager = (SmsManager) Class.forName(smsManagerClass).newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + LOGGER.warn("Error loading SMS Manager class : " + smsManagerClass, e); + } + } + + if (config.getBoolean("event.enable")) { + initEventsModule(); + } + + serverManager = new ServerManager(); + + if (config.getBoolean("event.forward.enable")) { + eventForwarder = new JsonTypeEventForwarder(); + } + + attributesManager = new AttributesManager(dataManager); + + driversManager = new DriversManager(dataManager); + + commandsManager = new CommandsManager(dataManager, config.getBoolean("commands.queueing")); + + } + + private static void initEventsModule() { + + geofenceManager = new GeofenceManager(dataManager); + calendarManager = new CalendarManager(dataManager); + maintenancesManager = new MaintenancesManager(dataManager); + notificationManager = new NotificationManager(dataManager); + notificatorManager = new NotificatorManager(); + Properties velocityProperties = new Properties(); + velocityProperties.setProperty("file.resource.loader.path", + Context.getConfig().getString("templates.rootPath", "templates") + "/"); + velocityProperties.setProperty("runtime.log.logsystem.class", + "org.apache.velocity.runtime.log.NullLogChute"); + + String address; + try { + address = config.getString("web.address", InetAddress.getLocalHost().getHostAddress()); + } catch (UnknownHostException e) { + address = "localhost"; + } + + String webUrl = URIUtil.newURI("http", address, config.getInteger("web.port", 8082), "", ""); + webUrl = Context.getConfig().getString("web.url", webUrl); + velocityProperties.setProperty("web.url", webUrl); + + velocityEngine = new VelocityEngine(); + velocityEngine.init(velocityProperties); + } + + public static void init(IdentityManager testIdentityManager, MediaManager testMediaManager) { + config = new Config(); + objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JSR353Module()); + client = ClientBuilder.newClient().register(new ObjectMapperContextResolver()); + identityManager = testIdentityManager; + mediaManager = testMediaManager; + } + + public static BaseObjectManager getManager(Class clazz) { + if (clazz.equals(Device.class)) { + return (BaseObjectManager) deviceManager; + } else if (clazz.equals(Group.class)) { + return (BaseObjectManager) groupsManager; + } else if (clazz.equals(User.class)) { + return (BaseObjectManager) usersManager; + } else if (clazz.equals(Calendar.class)) { + return (BaseObjectManager) calendarManager; + } else if (clazz.equals(Attribute.class)) { + return (BaseObjectManager) attributesManager; + } else if (clazz.equals(Geofence.class)) { + return (BaseObjectManager) geofenceManager; + } else if (clazz.equals(Driver.class)) { + return (BaseObjectManager) driversManager; + } else if (clazz.equals(Command.class)) { + return (BaseObjectManager) commandsManager; + } else if (clazz.equals(Maintenance.class)) { + return (BaseObjectManager) maintenancesManager; + } else if (clazz.equals(Notification.class)) { + return (BaseObjectManager) notificationManager; + } + return null; + } + +} diff --git a/src/main/java/org/traccar/DeviceSession.java b/src/main/java/org/traccar/DeviceSession.java new file mode 100644 index 000000000..322381807 --- /dev/null +++ b/src/main/java/org/traccar/DeviceSession.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016 - 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. + * 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 java.util.TimeZone; + +public class DeviceSession { + + private final long deviceId; + + public DeviceSession(long deviceId) { + this.deviceId = deviceId; + } + + public long getDeviceId() { + return deviceId; + } + + private TimeZone timeZone; + + public void setTimeZone(TimeZone timeZone) { + this.timeZone = timeZone; + } + + public TimeZone getTimeZone() { + return timeZone; + } + +} diff --git a/src/main/java/org/traccar/EventLoopGroupFactory.java b/src/main/java/org/traccar/EventLoopGroupFactory.java new file mode 100644 index 000000000..482559253 --- /dev/null +++ b/src/main/java/org/traccar/EventLoopGroupFactory.java @@ -0,0 +1,37 @@ +/* + * 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. + * 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 io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; + +public final class EventLoopGroupFactory { + + private static EventLoopGroup bossGroup = new NioEventLoopGroup(); + private static EventLoopGroup workerGroup = new NioEventLoopGroup(); + + private EventLoopGroupFactory() { + } + + public static EventLoopGroup getBossGroup() { + return bossGroup; + } + + public static EventLoopGroup getWorkerGroup() { + return workerGroup; + } + +} diff --git a/src/main/java/org/traccar/ExtendedObjectDecoder.java b/src/main/java/org/traccar/ExtendedObjectDecoder.java new file mode 100644 index 000000000..681924e87 --- /dev/null +++ b/src/main/java/org/traccar/ExtendedObjectDecoder.java @@ -0,0 +1,82 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.ReferenceCountUtil; +import org.traccar.helper.DataConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Collection; + +public abstract class ExtendedObjectDecoder extends ChannelInboundHandlerAdapter { + + private void saveOriginal(Object decodedMessage, Object originalMessage) { + if (Context.getConfig().getBoolean("database.saveOriginal") && decodedMessage instanceof Position) { + Position position = (Position) decodedMessage; + if (originalMessage instanceof ByteBuf) { + ByteBuf buf = (ByteBuf) originalMessage; + position.set(Position.KEY_ORIGINAL, ByteBufUtil.hexDump(buf)); + } else if (originalMessage instanceof String) { + position.set(Position.KEY_ORIGINAL, DataConverter.printHex( + ((String) originalMessage).getBytes(StandardCharsets.US_ASCII))); + } + } + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + NetworkMessage networkMessage = (NetworkMessage) msg; + Object originalMessage = networkMessage.getMessage(); + try { + Object decodedMessage = decode(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage); + onMessageEvent(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage, decodedMessage); + if (decodedMessage == null) { + decodedMessage = handleEmptyMessage(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage); + } + if (decodedMessage != null) { + if (decodedMessage instanceof Collection) { + for (Object o : (Collection) decodedMessage) { + saveOriginal(o, originalMessage); + ctx.fireChannelRead(o); + } + } else { + saveOriginal(decodedMessage, originalMessage); + ctx.fireChannelRead(decodedMessage); + } + } + } finally { + ReferenceCountUtil.release(originalMessage); + } + } + + protected void onMessageEvent( + Channel channel, SocketAddress remoteAddress, Object originalMessage, Object decodedMessage) { + } + + protected Object handleEmptyMessage(Channel channel, SocketAddress remoteAddress, Object msg) { + return null; + } + + protected abstract Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception; + +} diff --git a/src/main/java/org/traccar/GlobalTimer.java b/src/main/java/org/traccar/GlobalTimer.java new file mode 100644 index 000000000..a97321ba2 --- /dev/null +++ b/src/main/java/org/traccar/GlobalTimer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012 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. + * 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 io.netty.util.HashedWheelTimer; +import io.netty.util.Timer; + +public final class GlobalTimer { + + private static Timer instance = null; + + private GlobalTimer() { + } + + public static void release() { + if (instance != null) { + instance.stop(); + } + instance = null; + } + + public static Timer getTimer() { + if (instance == null) { + instance = new HashedWheelTimer(); + } + return instance; + } + +} diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java new file mode 100644 index 000000000..6ebd1d399 --- /dev/null +++ b/src/main/java/org/traccar/Main.java @@ -0,0 +1,156 @@ +/* + * Copyright 2012 - 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. + * 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 com.google.inject.Guice; +import com.google.inject.Injector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.OperatingSystemMXBean; +import java.lang.management.RuntimeMXBean; +import java.nio.charset.Charset; +import java.sql.SQLException; +import java.util.Timer; +import java.util.TimerTask; +import java.util.Locale; + +public final class Main { + + private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); + + private static final long CLEAN_PERIOD = 24 * 60 * 60 * 1000; + + private static Injector injector; + + public static Injector getInjector() { + return injector; + } + + private Main() { + } + + public static void logSystemInfo() { + try { + OperatingSystemMXBean operatingSystemBean = ManagementFactory.getOperatingSystemMXBean(); + LOGGER.info("Operating system" + + " name: " + operatingSystemBean.getName() + + " version: " + operatingSystemBean.getVersion() + + " architecture: " + operatingSystemBean.getArch()); + + RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); + LOGGER.info("Java runtime" + + " name: " + runtimeBean.getVmName() + + " vendor: " + runtimeBean.getVmVendor() + + " version: " + runtimeBean.getVmVersion()); + + MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); + LOGGER.info("Memory limit" + + " heap: " + memoryBean.getHeapMemoryUsage().getMax() / (1024 * 1024) + "mb" + + " non-heap: " + memoryBean.getNonHeapMemoryUsage().getMax() / (1024 * 1024) + "mb"); + + LOGGER.info("Character encoding: " + + System.getProperty("file.encoding") + " charset: " + Charset.defaultCharset()); + + } catch (Exception error) { + LOGGER.warn("Failed to get system info"); + } + } + + public static void main(String[] args) throws Exception { + Locale.setDefault(Locale.ENGLISH); + + if (args.length <= 0) { + throw new RuntimeException("Configuration file is not provided"); + } + + final String configFile = args[args.length - 1]; + + if (args[0].startsWith("--")) { + WindowsService windowsService = new WindowsService("traccar") { + @Override + public void run() { + Main.run(configFile); + } + }; + switch (args[0]) { + case "--install": + windowsService.install("traccar", null, null, null, null, configFile); + return; + case "--uninstall": + windowsService.uninstall(); + return; + case "--service": + default: + windowsService.init(); + break; + } + } else { + run(configFile); + } + } + + public static void run(String configFile) { + try { + Context.init(configFile); + injector = Guice.createInjector(new MainModule()); + logSystemInfo(); + LOGGER.info("Version: " + Main.class.getPackage().getImplementationVersion()); + LOGGER.info("Starting server..."); + + Context.getServerManager().start(); + if (Context.getWebServer() != null) { + Context.getWebServer().start(); + } + + new Timer().scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + Context.getDataManager().clearHistory(); + } catch (SQLException error) { + LOGGER.warn("Clear history error", error); + } + } + }, 0, CLEAN_PERIOD); + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + LOGGER.error("Thread exception", e); + } + }); + + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + LOGGER.info("Shutting down server..."); + + if (Context.getWebServer() != null) { + Context.getWebServer().stop(); + } + Context.getServerManager().stop(); + } + }); + } catch (Exception e) { + LOGGER.error("Main method error", e); + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java new file mode 100644 index 000000000..a8b53ff60 --- /dev/null +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -0,0 +1,161 @@ +/* + * Copyright 2012 - 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. + * 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 io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.socket.DatagramChannel; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.timeout.IdleStateEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.database.StatisticsManager; +import org.traccar.helper.DateUtil; +import org.traccar.model.Position; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +public class MainEventHandler extends ChannelInboundHandlerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(MainEventHandler.class); + + private static final String DEFAULT_LOGGER_ATTRIBUTES = "time,position,speed,course,accuracy,result"; + + private final Set connectionlessProtocols = new HashSet<>(); + private final Set logAttributes = new LinkedHashSet<>(); + + public MainEventHandler() { + String connectionlessProtocolList = Context.getConfig().getString("status.ignoreOffline"); + if (connectionlessProtocolList != null) { + connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split(","))); + } + logAttributes.addAll(Arrays.asList( + Context.getConfig().getString("logger.attributes", DEFAULT_LOGGER_ATTRIBUTES).split(","))); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (msg instanceof Position) { + + Position position = (Position) msg; + try { + Context.getDeviceManager().updateLatestPosition(position); + } catch (SQLException error) { + LOGGER.warn("Failed to update device", error); + } + + String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId(); + + StringBuilder builder = new StringBuilder(); + builder.append(formatChannel(ctx.channel())).append(" "); + builder.append("id: ").append(uniqueId); + for (String attribute : logAttributes) { + switch (attribute) { + case "time": + builder.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false)); + break; + case "position": + builder.append(", lat: ").append(String.format("%.5f", position.getLatitude())); + builder.append(", lon: ").append(String.format("%.5f", position.getLongitude())); + break; + case "speed": + if (position.getSpeed() > 0) { + builder.append(", speed: ").append(String.format("%.1f", position.getSpeed())); + } + break; + case "course": + builder.append(", course: ").append(String.format("%.1f", position.getCourse())); + break; + case "accuracy": + if (position.getAccuracy() > 0) { + builder.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy())); + } + break; + case "outdated": + if (position.getOutdated()) { + builder.append(", outdated"); + } + break; + case "invalid": + if (!position.getValid()) { + builder.append(", invalid"); + } + break; + default: + Object value = position.getAttributes().get(attribute); + if (value != null) { + builder.append(", ").append(attribute).append(": ").append(value); + } + break; + } + } + LOGGER.info(builder.toString()); + + Main.getInjector().getInstance(StatisticsManager.class).registerMessageStored(position.getDeviceId()); + } + } + + private static String formatChannel(Channel channel) { + return String.format("[%s]", channel.id().asShortText()); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + if (!(ctx.channel() instanceof DatagramChannel)) { + LOGGER.info(formatChannel(ctx.channel()) + " connected"); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + LOGGER.info(formatChannel(ctx.channel()) + " disconnected"); + closeChannel(ctx.channel()); + + if (BasePipelineFactory.getHandler(ctx.pipeline(), HttpRequestDecoder.class) == null + && !connectionlessProtocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName())) { + Context.getConnectionManager().removeActiveDevice(ctx.channel()); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + while (cause.getCause() != null && cause.getCause() != cause) { + cause = cause.getCause(); + } + LOGGER.warn(formatChannel(ctx.channel()) + " error", cause); + closeChannel(ctx.channel()); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { + if (evt instanceof IdleStateEvent) { + LOGGER.info(formatChannel(ctx.channel()) + " timed out"); + closeChannel(ctx.channel()); + } + } + + private void closeChannel(Channel channel) { + if (!(channel instanceof DatagramChannel)) { + channel.close(); + } + } + +} diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java new file mode 100644 index 000000000..6fe8bad1c --- /dev/null +++ b/src/main/java/org/traccar/MainModule.java @@ -0,0 +1,373 @@ +/* + * Copyright 2018 - 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. + * 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 com.fasterxml.jackson.databind.ObjectMapper; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.AttributesManager; +import org.traccar.database.CalendarManager; +import org.traccar.database.DataManager; +import org.traccar.database.DeviceManager; +import org.traccar.database.GeofenceManager; +import org.traccar.database.IdentityManager; +import org.traccar.database.MaintenancesManager; +import org.traccar.database.StatisticsManager; +import org.traccar.geocoder.AddressFormat; +import org.traccar.geocoder.BanGeocoder; +import org.traccar.geocoder.BingMapsGeocoder; +import org.traccar.geocoder.FactualGeocoder; +import org.traccar.geocoder.GeocodeFarmGeocoder; +import org.traccar.geocoder.GeocodeXyzGeocoder; +import org.traccar.geocoder.Geocoder; +import org.traccar.geocoder.GisgraphyGeocoder; +import org.traccar.geocoder.GoogleGeocoder; +import org.traccar.geocoder.HereGeocoder; +import org.traccar.geocoder.MapQuestGeocoder; +import org.traccar.geocoder.MapmyIndiaGeocoder; +import org.traccar.geocoder.NominatimGeocoder; +import org.traccar.geocoder.OpenCageGeocoder; +import org.traccar.geolocation.GeolocationProvider; +import org.traccar.geolocation.GoogleGeolocationProvider; +import org.traccar.geolocation.MozillaGeolocationProvider; +import org.traccar.geolocation.OpenCellIdGeolocationProvider; +import org.traccar.geolocation.UnwiredGeolocationProvider; +import org.traccar.handler.ComputedAttributesHandler; +import org.traccar.handler.CopyAttributesHandler; +import org.traccar.handler.DefaultDataHandler; +import org.traccar.handler.DistanceHandler; +import org.traccar.handler.EngineHoursHandler; +import org.traccar.handler.FilterHandler; +import org.traccar.handler.GeocoderHandler; +import org.traccar.handler.GeolocationHandler; +import org.traccar.handler.HemisphereHandler; +import org.traccar.handler.MotionHandler; +import org.traccar.handler.RemoteAddressHandler; +import org.traccar.handler.events.AlertEventHandler; +import org.traccar.handler.events.CommandResultEventHandler; +import org.traccar.handler.events.DriverEventHandler; +import org.traccar.handler.events.FuelDropEventHandler; +import org.traccar.handler.events.GeofenceEventHandler; +import org.traccar.handler.events.IgnitionEventHandler; +import org.traccar.handler.events.MaintenanceEventHandler; +import org.traccar.handler.events.MotionEventHandler; +import org.traccar.handler.events.OverspeedEventHandler; +import org.traccar.reports.model.TripsConfig; + +import javax.annotation.Nullable; +import javax.ws.rs.client.Client; + +public class MainModule extends AbstractModule { + + @Provides + public static ObjectMapper provideObjectMapper() { + return Context.getObjectMapper(); + } + + @Provides + public static Config provideConfig() { + return Context.getConfig(); + } + + @Provides + public static DataManager provideDataManager() { + return Context.getDataManager(); + } + + @Provides + public static IdentityManager provideIdentityManager() { + return Context.getIdentityManager(); + } + + @Provides + public static Client provideClient() { + return Context.getClient(); + } + + @Provides + public static TripsConfig provideTripsConfig() { + return Context.getTripsConfig(); + } + + @Provides + public static DeviceManager provideDeviceManager() { + return Context.getDeviceManager(); + } + + @Provides + public static GeofenceManager provideGeofenceManager() { + return Context.getGeofenceManager(); + } + + @Provides + public static CalendarManager provideCalendarManager() { + return Context.getCalendarManager(); + } + + @Provides + public static AttributesManager provideAttributesManager() { + return Context.getAttributesManager(); + } + + @Provides + public static MaintenancesManager provideMaintenancesManager() { + return Context.getMaintenancesManager(); + } + + @Singleton + @Provides + public static StatisticsManager provideStatisticsManager(Config config, DataManager dataManager, Client client) { + return new StatisticsManager(config, dataManager, client); + } + + @Singleton + @Provides + public static Geocoder provideGeocoder(Config config) { + if (config.getBoolean(Keys.GEOCODER_ENABLE)) { + String type = config.getString(Keys.GEOCODER_TYPE, "google"); + String url = config.getString(Keys.GEOCODER_URL); + String id = config.getString(Keys.GEOCODER_ID); + String key = config.getString(Keys.GEOCODER_KEY); + String language = config.getString(Keys.GEOCODER_LANGUAGE); + String formatString = config.getString(Keys.GEOCODER_FORMAT); + AddressFormat addressFormat = formatString != null ? new AddressFormat(formatString) : new AddressFormat(); + + int cacheSize = config.getInteger(Keys.GEOCODER_CACHE_SIZE); + switch (type) { + case "nominatim": + return new NominatimGeocoder(url, key, language, cacheSize, addressFormat); + case "gisgraphy": + return new GisgraphyGeocoder(url, cacheSize, addressFormat); + case "mapquest": + return new MapQuestGeocoder(url, key, cacheSize, addressFormat); + case "opencage": + return new OpenCageGeocoder(url, key, cacheSize, addressFormat); + case "bingmaps": + return new BingMapsGeocoder(url, key, cacheSize, addressFormat); + case "factual": + return new FactualGeocoder(url, key, cacheSize, addressFormat); + case "geocodefarm": + return new GeocodeFarmGeocoder(key, language, cacheSize, addressFormat); + case "geocodexyz": + return new GeocodeXyzGeocoder(key, cacheSize, addressFormat); + case "ban": + return new BanGeocoder(cacheSize, addressFormat); + case "here": + return new HereGeocoder(id, key, language, cacheSize, addressFormat); + case "mapmyindia": + return new MapmyIndiaGeocoder(url, key, cacheSize, addressFormat); + default: + return new GoogleGeocoder(key, language, cacheSize, addressFormat); + } + } + return null; + } + + @Singleton + @Provides + public static GeolocationProvider provideGeolocationProvider(Config config) { + if (config.getBoolean(Keys.GEOLOCATION_ENABLE)) { + String type = config.getString(Keys.GEOLOCATION_TYPE, "mozilla"); + String url = config.getString(Keys.GEOLOCATION_URL); + String key = config.getString(Keys.GEOLOCATION_KEY); + switch (type) { + case "google": + return new GoogleGeolocationProvider(key); + case "opencellid": + return new OpenCellIdGeolocationProvider(key); + case "unwired": + return new UnwiredGeolocationProvider(url, key); + default: + return new MozillaGeolocationProvider(key); + } + } + return null; + } + + @Singleton + @Provides + public static DistanceHandler provideDistanceHandler(Config config, IdentityManager identityManager) { + return new DistanceHandler(config, identityManager); + } + + @Singleton + @Provides + public static FilterHandler provideFilterHandler(Config config) { + if (config.getBoolean(Keys.FILTER_ENABLE)) { + return new FilterHandler(config); + } + return null; + } + + @Singleton + @Provides + public static HemisphereHandler provideHemisphereHandler(Config config) { + if (config.hasKey(Keys.LOCATION_LATITUDE_HEMISPHERE) || config.hasKey(Keys.LOCATION_LONGITUDE_HEMISPHERE)) { + return new HemisphereHandler(config); + } + return null; + } + + @Singleton + @Provides + public static RemoteAddressHandler provideRemoteAddressHandler(Config config) { + if (config.getBoolean(Keys.PROCESSING_REMOTE_ADDRESS_ENABLE)) { + return new RemoteAddressHandler(); + } + return null; + } + + @Singleton + @Provides + public static WebDataHandler provideWebDataHandler( + Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) { + if (config.getBoolean(Keys.FORWARD_ENABLE)) { + return new WebDataHandler(config, identityManager, objectMapper, client); + } + return null; + } + + @Singleton + @Provides + public static GeolocationHandler provideGeolocationHandler( + Config config, @Nullable GeolocationProvider geolocationProvider, StatisticsManager statisticsManager) { + if (geolocationProvider != null) { + return new GeolocationHandler(config, geolocationProvider, statisticsManager); + } + return null; + } + + @Singleton + @Provides + public static GeocoderHandler provideGeocoderHandler( + Config config, @Nullable Geocoder geocoder, IdentityManager identityManager, + StatisticsManager statisticsManager) { + if (geocoder != null) { + return new GeocoderHandler(config, geocoder, identityManager, statisticsManager); + } + return null; + } + + @Singleton + @Provides + public static MotionHandler provideMotionHandler(TripsConfig tripsConfig) { + return new MotionHandler(tripsConfig.getSpeedThreshold()); + } + + @Singleton + @Provides + public static EngineHoursHandler provideEngineHoursHandler(Config config, IdentityManager identityManager) { + if (config.getBoolean(Keys.PROCESSING_ENGINE_HOURS_ENABLE)) { + return new EngineHoursHandler(identityManager); + } + return null; + } + + @Singleton + @Provides + public static CopyAttributesHandler provideCopyAttributesHandler(Config config, IdentityManager identityManager) { + if (config.getBoolean(Keys.PROCESSING_COPY_ATTRIBUTES_ENABLE)) { + return new CopyAttributesHandler(identityManager); + } + return null; + } + + @Singleton + @Provides + public static ComputedAttributesHandler provideComputedAttributesHandler( + Config config, IdentityManager identityManager, AttributesManager attributesManager) { + if (config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_ENABLE)) { + return new ComputedAttributesHandler(config, identityManager, attributesManager); + } + return null; + } + + @Singleton + @Provides + public static DefaultDataHandler provideDefaultDataHandler(@Nullable DataManager dataManager) { + if (dataManager != null) { + return new DefaultDataHandler(dataManager); + } + return null; + } + + @Singleton + @Provides + public static CommandResultEventHandler provideCommandResultEventHandler() { + return new CommandResultEventHandler(); + } + + @Singleton + @Provides + public static OverspeedEventHandler provideOverspeedEventHandler( + Config config, DeviceManager deviceManager, GeofenceManager geofenceManager) { + return new OverspeedEventHandler(config, deviceManager, geofenceManager); + } + + @Singleton + @Provides + public static FuelDropEventHandler provideFuelDropEventHandler(IdentityManager identityManager) { + return new FuelDropEventHandler(identityManager); + } + + @Singleton + @Provides + public static MotionEventHandler provideMotionEventHandler( + IdentityManager identityManager, DeviceManager deviceManager, TripsConfig tripsConfig) { + return new MotionEventHandler(identityManager, deviceManager, tripsConfig); + } + + @Singleton + @Provides + public static GeofenceEventHandler provideGeofenceEventHandler( + IdentityManager identityManager, GeofenceManager geofenceManager, CalendarManager calendarManager) { + return new GeofenceEventHandler(identityManager, geofenceManager, calendarManager); + } + + @Singleton + @Provides + public static AlertEventHandler provideAlertEventHandler(Config config, IdentityManager identityManager) { + return new AlertEventHandler(config, identityManager); + } + + @Singleton + @Provides + public static IgnitionEventHandler provideIgnitionEventHandler(IdentityManager identityManager) { + return new IgnitionEventHandler(identityManager); + } + + @Singleton + @Provides + public static MaintenanceEventHandler provideMaintenanceEventHandler( + IdentityManager identityManager, MaintenancesManager maintenancesManager) { + return new MaintenanceEventHandler(identityManager, maintenancesManager); + } + + @Singleton + @Provides + public static DriverEventHandler provideDriverEventHandler(IdentityManager identityManager) { + return new DriverEventHandler(identityManager); + } + + @Override + protected void configure() { + binder().requireExplicitBindings(); + } + +} diff --git a/src/main/java/org/traccar/NetworkMessage.java b/src/main/java/org/traccar/NetworkMessage.java new file mode 100644 index 000000000..14a397e69 --- /dev/null +++ b/src/main/java/org/traccar/NetworkMessage.java @@ -0,0 +1,38 @@ +/* + * Copyright 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. + * 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 java.net.SocketAddress; + +public class NetworkMessage { + + private final SocketAddress remoteAddress; + private final Object message; + + public NetworkMessage(Object message, SocketAddress remoteAddress) { + this.message = message; + this.remoteAddress = remoteAddress; + } + + public SocketAddress getRemoteAddress() { + return remoteAddress; + } + + public Object getMessage() { + return message; + } + +} diff --git a/src/main/java/org/traccar/PipelineBuilder.java b/src/main/java/org/traccar/PipelineBuilder.java new file mode 100644 index 000000000..3334040b1 --- /dev/null +++ b/src/main/java/org/traccar/PipelineBuilder.java @@ -0,0 +1,24 @@ +/* + * Copyright 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. + * 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 io.netty.channel.ChannelHandler; + +public interface PipelineBuilder { + + void addLast(ChannelHandler handler); + +} diff --git a/src/main/java/org/traccar/Protocol.java b/src/main/java/org/traccar/Protocol.java new file mode 100644 index 000000000..3b66f2598 --- /dev/null +++ b/src/main/java/org/traccar/Protocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 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. + * 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.database.ActiveDevice; +import org.traccar.model.Command; + +import java.util.Collection; + +public interface Protocol { + + String getName(); + + Collection getServerList(); + + Collection getSupportedDataCommands(); + + void sendDataCommand(ActiveDevice activeDevice, Command command); + + Collection getSupportedTextCommands(); + + void sendTextCommand(String destAddress, Command command) throws Exception; + +} diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java new file mode 100644 index 000000000..6a3273402 --- /dev/null +++ b/src/main/java/org/traccar/ServerManager.java @@ -0,0 +1,103 @@ +/* + * 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. + * 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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.net.BindException; +import java.net.URI; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class ServerManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ServerManager.class); + + private final List serverList = new LinkedList<>(); + private final Map protocolList = new ConcurrentHashMap<>(); + + public ServerManager() throws Exception { + + List names = new LinkedList<>(); + String packageName = "org.traccar.protocol"; + String packagePath = packageName.replace('.', '/'); + URL packageUrl = getClass().getClassLoader().getResource(packagePath); + + if (packageUrl.getProtocol().equals("jar")) { + String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8.name()); + try (JarFile jf = new JarFile(jarFileName.substring(5, jarFileName.indexOf("!")))) { + Enumeration jarEntries = jf.entries(); + while (jarEntries.hasMoreElements()) { + String entryName = jarEntries.nextElement().getName(); + if (entryName.startsWith(packagePath) && entryName.length() > packagePath.length() + 5) { + names.add(entryName.substring(packagePath.length() + 1, entryName.lastIndexOf('.'))); + } + } + } + } else { + File folder = new File(new URI(packageUrl.toString())); + File[] files = folder.listFiles(); + if (files != null) { + for (File actual: files) { + String entryName = actual.getName(); + names.add(entryName.substring(0, entryName.lastIndexOf('.'))); + } + } + } + + for (String name : names) { + Class protocolClass = Class.forName(packageName + '.' + name); + if (BaseProtocol.class.isAssignableFrom(protocolClass) + && Context.getConfig().hasKey(BaseProtocol.nameFromClass(protocolClass) + ".port")) { + BaseProtocol protocol = (BaseProtocol) protocolClass.newInstance(); + serverList.addAll(protocol.getServerList()); + protocolList.put(protocol.getName(), protocol); + } + } + } + + public BaseProtocol getProtocol(String name) { + return protocolList.get(name); + } + + public void start() throws Exception { + for (TrackerServer server: serverList) { + try { + server.start(); + } catch (BindException e) { + LOGGER.warn("Port {} is disabled due to conflict", server.getPort()); + } + } + } + + public void stop() { + for (TrackerServer server: serverList) { + server.stop(); + } + GlobalTimer.release(); + } + +} diff --git a/src/main/java/org/traccar/StringProtocolEncoder.java b/src/main/java/org/traccar/StringProtocolEncoder.java new file mode 100644 index 000000000..1945ae174 --- /dev/null +++ b/src/main/java/org/traccar/StringProtocolEncoder.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015 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. + * 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.model.Command; + +import java.util.Map; + +public abstract class StringProtocolEncoder extends BaseProtocolEncoder { + + public interface ValueFormatter { + String formatValue(String key, Object value); + } + + protected String formatCommand(Command command, String format, ValueFormatter valueFormatter, String... keys) { + + String result = String.format(format, (Object[]) keys); + + result = result.replaceAll("\\{" + Command.KEY_UNIQUE_ID + "}", getUniqueId(command.getDeviceId())); + for (Map.Entry entry : command.getAttributes().entrySet()) { + String value = null; + if (valueFormatter != null) { + value = valueFormatter.formatValue(entry.getKey(), entry.getValue()); + } + if (value == null) { + value = entry.getValue().toString(); + } + result = result.replaceAll("\\{" + entry.getKey() + "}", value); + } + + return result; + } + + protected String formatCommand(Command command, String format, String... keys) { + return formatCommand(command, format, null, keys); + } + +} diff --git a/src/main/java/org/traccar/TrackerServer.java b/src/main/java/org/traccar/TrackerServer.java new file mode 100644 index 000000000..3a1e1c4e8 --- /dev/null +++ b/src/main/java/org/traccar/TrackerServer.java @@ -0,0 +1,115 @@ +/* + * 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. + * 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 io.netty.bootstrap.AbstractBootstrap; +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.group.ChannelGroup; +import io.netty.channel.group.DefaultChannelGroup; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.util.concurrent.GlobalEventExecutor; + +import java.net.InetSocketAddress; + +public abstract class TrackerServer { + + private final boolean datagram; + private final AbstractBootstrap bootstrap; + + public boolean isDatagram() { + return datagram; + } + + public TrackerServer(boolean datagram, String protocol) { + this.datagram = datagram; + + address = Context.getConfig().getString(protocol + ".address"); + port = Context.getConfig().getInteger(protocol + ".port"); + + BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, protocol) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + TrackerServer.this.addProtocolHandlers(pipeline); + } + }; + + if (datagram) { + + this.bootstrap = new Bootstrap() + .group(EventLoopGroupFactory.getWorkerGroup()) + .channel(NioDatagramChannel.class) + .handler(pipelineFactory); + + } else { + + this.bootstrap = new ServerBootstrap() + .group(EventLoopGroupFactory.getBossGroup(), EventLoopGroupFactory.getWorkerGroup()) + .channel(NioServerSocketChannel.class) + .childHandler(pipelineFactory); + + } + } + + protected abstract void addProtocolHandlers(PipelineBuilder pipeline); + + private int port; + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + private String address; + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + private final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + + public ChannelGroup getChannelGroup() { + return channelGroup; + } + + public void start() throws Exception { + InetSocketAddress endpoint; + if (address == null) { + endpoint = new InetSocketAddress(port); + } else { + endpoint = new InetSocketAddress(address, port); + } + + Channel channel = bootstrap.bind(endpoint).sync().channel(); + if (channel != null) { + getChannelGroup().add(channel); + } + } + + public void stop() { + channelGroup.close().awaitUninterruptibly(); + } + +} diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java new file mode 100644 index 000000000..64396de03 --- /dev/null +++ b/src/main/java/org/traccar/WebDataHandler.java @@ -0,0 +1,201 @@ +/* + * Copyright 2015 - 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. + * 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 com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.netty.channel.ChannelHandler; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.IdentityManager; +import org.traccar.helper.Checksum; +import org.traccar.model.Device; +import org.traccar.model.Position; +import org.traccar.model.Group; + +import javax.inject.Inject; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import java.util.HashMap; +import java.util.Map; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Calendar; +import java.util.Formatter; +import java.util.Locale; +import java.util.TimeZone; + +@ChannelHandler.Sharable +public class WebDataHandler extends BaseDataHandler { + + private static final String KEY_POSITION = "position"; + private static final String KEY_DEVICE = "device"; + + private final IdentityManager identityManager; + private final ObjectMapper objectMapper; + private final Client client; + + private final String url; + private final String header; + private final boolean json; + + @Inject + public WebDataHandler( + Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) { + this.identityManager = identityManager; + this.objectMapper = objectMapper; + this.client = client; + this.url = config.getString(Keys.FORWARD_URL); + this.header = config.getString(Keys.FORWARD_HEADER); + this.json = config.getBoolean(Keys.FORWARD_JSON); + } + + private static String formatSentence(Position position) { + + StringBuilder s = new StringBuilder("$GPRMC,"); + + try (Formatter f = new Formatter(s, Locale.ENGLISH)) { + + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ENGLISH); + calendar.setTimeInMillis(position.getFixTime().getTime()); + + f.format("%1$tH%1$tM%1$tS.%1$tL,A,", calendar); + + double lat = position.getLatitude(); + double lon = position.getLongitude(); + + f.format("%02d%07.4f,%c,", (int) Math.abs(lat), Math.abs(lat) % 1 * 60, lat < 0 ? 'S' : 'N'); + f.format("%03d%07.4f,%c,", (int) Math.abs(lon), Math.abs(lon) % 1 * 60, lon < 0 ? 'W' : 'E'); + + f.format("%.2f,%.2f,", position.getSpeed(), position.getCourse()); + f.format("%1$td%1$tm%1$ty,,", calendar); + } + + s.append(Checksum.nmea(s.toString())); + + return s.toString(); + } + + private String calculateStatus(Position position) { + if (position.getAttributes().containsKey(Position.KEY_ALARM)) { + return "0xF841"; // STATUS_PANIC_ON + } else if (position.getSpeed() < 1.0) { + return "0xF020"; // STATUS_LOCATION + } else { + return "0xF11C"; // STATUS_MOTION_MOVING + } + } + + public String formatRequest(Position position) throws UnsupportedEncodingException, JsonProcessingException { + + Device device = identityManager.getById(position.getDeviceId()); + + String request = url + .replace("{name}", URLEncoder.encode(device.getName(), StandardCharsets.UTF_8.name())) + .replace("{uniqueId}", device.getUniqueId()) + .replace("{status}", device.getStatus()) + .replace("{deviceId}", String.valueOf(position.getDeviceId())) + .replace("{protocol}", String.valueOf(position.getProtocol())) + .replace("{deviceTime}", String.valueOf(position.getDeviceTime().getTime())) + .replace("{fixTime}", String.valueOf(position.getFixTime().getTime())) + .replace("{valid}", String.valueOf(position.getValid())) + .replace("{latitude}", String.valueOf(position.getLatitude())) + .replace("{longitude}", String.valueOf(position.getLongitude())) + .replace("{altitude}", String.valueOf(position.getAltitude())) + .replace("{speed}", String.valueOf(position.getSpeed())) + .replace("{course}", String.valueOf(position.getCourse())) + .replace("{accuracy}", String.valueOf(position.getAccuracy())) + .replace("{statusCode}", calculateStatus(position)); + + if (position.getAddress() != null) { + request = request.replace( + "{address}", URLEncoder.encode(position.getAddress(), StandardCharsets.UTF_8.name())); + } + + if (request.contains("{attributes}")) { + String attributes = objectMapper.writeValueAsString(position.getAttributes()); + request = request.replace( + "{attributes}", URLEncoder.encode(attributes, StandardCharsets.UTF_8.name())); + } + + if (request.contains("{gprmc}")) { + request = request.replace("{gprmc}", formatSentence(position)); + } + + if (request.contains("{group}")) { + String deviceGroupName = ""; + if (device.getGroupId() != 0) { + Group group = Context.getGroupsManager().getById(device.getGroupId()); + if (group != null) { + deviceGroupName = group.getName(); + } + } + + request = request.replace("{group}", URLEncoder.encode(deviceGroupName, StandardCharsets.UTF_8.name())); + } + + return request; + } + + @Override + protected Position handlePosition(Position position) { + + String url; + if (json) { + url = this.url; + } else { + try { + url = formatRequest(position); + } catch (UnsupportedEncodingException | JsonProcessingException e) { + throw new RuntimeException("Forwarding formatting error", e); + } + } + + Invocation.Builder requestBuilder = client.target(url).request(); + + if (header != null && !header.isEmpty()) { + for (String line: header.split("\\r?\\n")) { + String[] values = line.split(":", 2); + requestBuilder.header(values[0].trim(), values[1].trim()); + } + } + + if (json) { + requestBuilder.async().post(Entity.json(prepareJsonPayload(position))); + } else { + requestBuilder.async().get(); + } + + return position; + } + + private Map prepareJsonPayload(Position position) { + + Map data = new HashMap<>(); + Device device = identityManager.getById(position.getDeviceId()); + + data.put(KEY_POSITION, position); + + if (device != null) { + data.put(KEY_DEVICE, device); + } + + return data; + } + +} diff --git a/src/main/java/org/traccar/WindowsService.java b/src/main/java/org/traccar/WindowsService.java new file mode 100644 index 000000000..4a8955608 --- /dev/null +++ b/src/main/java/org/traccar/WindowsService.java @@ -0,0 +1,231 @@ +/* + * Copyright 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. + * 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 com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Advapi32; +import com.sun.jna.platform.win32.WinError; +import com.sun.jna.platform.win32.WinNT; +import com.sun.jna.platform.win32.Winsvc; +import com.sun.jna.platform.win32.Winsvc.HandlerEx; +import com.sun.jna.platform.win32.Winsvc.SC_HANDLE; +import com.sun.jna.platform.win32.Winsvc.SERVICE_DESCRIPTION; +import com.sun.jna.platform.win32.Winsvc.SERVICE_MAIN_FUNCTION; +import com.sun.jna.platform.win32.Winsvc.SERVICE_STATUS; +import com.sun.jna.platform.win32.Winsvc.SERVICE_STATUS_HANDLE; +import com.sun.jna.platform.win32.Winsvc.SERVICE_TABLE_ENTRY; +import jnr.posix.POSIXFactory; + +import java.io.File; +import java.net.URISyntaxException; + +public abstract class WindowsService { + + private static final Advapi32 ADVAPI_32 = Advapi32.INSTANCE; + + private final Object waitObject = new Object(); + + private String serviceName; + private ServiceMain serviceMain; + private ServiceControl serviceControl; + private SERVICE_STATUS_HANDLE serviceStatusHandle; + + public WindowsService(String serviceName) { + this.serviceName = serviceName; + } + + public boolean install( + String displayName, String description, String[] dependencies, + String account, String password, String config) throws URISyntaxException { + + String javaHome = System.getProperty("java.home"); + String javaBinary = javaHome + "\\bin\\java.exe"; + + File jar = new File(WindowsService.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + String command = javaBinary + + " -Duser.dir=\"" + jar.getParentFile().getAbsolutePath() + "\"" + + " -jar \"" + jar.getAbsolutePath() + "\"" + + " --service \"" + config + "\""; + + boolean success = false; + StringBuilder dep = new StringBuilder(); + + if (dependencies != null) { + for (String s : dependencies) { + dep.append(s); + dep.append("\0"); + } + } + dep.append("\0"); + + SERVICE_DESCRIPTION desc = new SERVICE_DESCRIPTION(); + desc.lpDescription = description; + + SC_HANDLE serviceManager = openServiceControlManager(null, Winsvc.SC_MANAGER_ALL_ACCESS); + + if (serviceManager != null) { + SC_HANDLE service = ADVAPI_32.CreateService(serviceManager, serviceName, displayName, + Winsvc.SERVICE_ALL_ACCESS, WinNT.SERVICE_WIN32_OWN_PROCESS, WinNT.SERVICE_AUTO_START, + WinNT.SERVICE_ERROR_NORMAL, + command, + null, null, dep.toString(), account, password); + + if (service != null) { + success = ADVAPI_32.ChangeServiceConfig2(service, Winsvc.SERVICE_CONFIG_DESCRIPTION, desc); + ADVAPI_32.CloseServiceHandle(service); + } + ADVAPI_32.CloseServiceHandle(serviceManager); + } + return success; + } + + public boolean uninstall() { + boolean success = false; + + SC_HANDLE serviceManager = openServiceControlManager(null, Winsvc.SC_MANAGER_ALL_ACCESS); + + if (serviceManager != null) { + SC_HANDLE service = ADVAPI_32.OpenService(serviceManager, serviceName, Winsvc.SERVICE_ALL_ACCESS); + + if (service != null) { + success = ADVAPI_32.DeleteService(service); + ADVAPI_32.CloseServiceHandle(service); + } + ADVAPI_32.CloseServiceHandle(serviceManager); + } + return success; + } + + public boolean start() { + boolean success = false; + + SC_HANDLE serviceManager = openServiceControlManager(null, WinNT.GENERIC_EXECUTE); + + if (serviceManager != null) { + SC_HANDLE service = ADVAPI_32.OpenService(serviceManager, serviceName, WinNT.GENERIC_EXECUTE); + + if (service != null) { + success = ADVAPI_32.StartService(service, 0, null); + ADVAPI_32.CloseServiceHandle(service); + } + ADVAPI_32.CloseServiceHandle(serviceManager); + } + + return success; + } + + public boolean stop() { + boolean success = false; + + SC_HANDLE serviceManager = openServiceControlManager(null, WinNT.GENERIC_EXECUTE); + + if (serviceManager != null) { + SC_HANDLE service = Advapi32.INSTANCE.OpenService(serviceManager, serviceName, WinNT.GENERIC_EXECUTE); + + if (service != null) { + SERVICE_STATUS serviceStatus = new SERVICE_STATUS(); + success = Advapi32.INSTANCE.ControlService(service, Winsvc.SERVICE_CONTROL_STOP, serviceStatus); + Advapi32.INSTANCE.CloseServiceHandle(service); + } + Advapi32.INSTANCE.CloseServiceHandle(serviceManager); + } + + return success; + } + + public void init() throws URISyntaxException { + String path = new File( + WindowsService.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); + + POSIXFactory.getPOSIX().chdir(path); + + serviceMain = new ServiceMain(); + SERVICE_TABLE_ENTRY entry = new SERVICE_TABLE_ENTRY(); + entry.lpServiceName = serviceName; + entry.lpServiceProc = serviceMain; + + Advapi32.INSTANCE.StartServiceCtrlDispatcher((SERVICE_TABLE_ENTRY[]) entry.toArray(2)); + } + + private SC_HANDLE openServiceControlManager(String machine, int access) { + return ADVAPI_32.OpenSCManager(machine, null, access); + } + + private void reportStatus(int status, int win32ExitCode, int waitHint) { + SERVICE_STATUS serviceStatus = new SERVICE_STATUS(); + serviceStatus.dwServiceType = WinNT.SERVICE_WIN32_OWN_PROCESS; + serviceStatus.dwControlsAccepted = Winsvc.SERVICE_ACCEPT_STOP | Winsvc.SERVICE_ACCEPT_SHUTDOWN; + serviceStatus.dwWin32ExitCode = win32ExitCode; + serviceStatus.dwWaitHint = waitHint; + serviceStatus.dwCurrentState = status; + + ADVAPI_32.SetServiceStatus(serviceStatusHandle, serviceStatus); + } + + public abstract void run(); + + private class ServiceMain implements SERVICE_MAIN_FUNCTION { + + public void callback(int dwArgc, Pointer lpszArgv) { + serviceControl = new ServiceControl(); + serviceStatusHandle = ADVAPI_32.RegisterServiceCtrlHandlerEx(serviceName, serviceControl, null); + + reportStatus(Winsvc.SERVICE_START_PENDING, WinError.NO_ERROR, 3000); + reportStatus(Winsvc.SERVICE_RUNNING, WinError.NO_ERROR, 0); + + Thread.currentThread().setContextClassLoader(WindowsService.class.getClassLoader()); + + run(); + + try { + synchronized (waitObject) { + waitObject.wait(); + } + } catch (InterruptedException ex) { + } + + reportStatus(Winsvc.SERVICE_STOPPED, WinError.NO_ERROR, 0); + + // Avoid returning from ServiceMain, which will cause a crash + // See http://support.microsoft.com/kb/201349, which recommends + // having init() wait for this thread. + // Waiting on this thread in init() won't fix the crash, though. + + System.exit(0); + } + + } + + private class ServiceControl implements HandlerEx { + + public int callback(int dwControl, int dwEventType, Pointer lpEventData, Pointer lpContext) { + switch (dwControl) { + case Winsvc.SERVICE_CONTROL_STOP: + case Winsvc.SERVICE_CONTROL_SHUTDOWN: + reportStatus(Winsvc.SERVICE_STOP_PENDING, WinError.NO_ERROR, 5000); + synchronized (waitObject) { + waitObject.notifyAll(); + } + break; + default: + break; + } + return WinError.NO_ERROR; + } + + } + +} diff --git a/src/main/java/org/traccar/WrapperContext.java b/src/main/java/org/traccar/WrapperContext.java new file mode 100644 index 000000000..372d3c60d --- /dev/null +++ b/src/main/java/org/traccar/WrapperContext.java @@ -0,0 +1,255 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelProgressivePromise; +import io.netty.channel.ChannelPromise; +import io.netty.util.Attribute; +import io.netty.util.AttributeKey; +import io.netty.util.concurrent.EventExecutor; + +import java.net.SocketAddress; + +public class WrapperContext implements ChannelHandlerContext { + + private ChannelHandlerContext context; + private SocketAddress remoteAddress; + + public WrapperContext(ChannelHandlerContext context, SocketAddress remoteAddress) { + this.context = context; + this.remoteAddress = remoteAddress; + } + + @Override + public Channel channel() { + return context.channel(); + } + + @Override + public EventExecutor executor() { + return context.executor(); + } + + @Override + public String name() { + return context.name(); + } + + @Override + public ChannelHandler handler() { + return context.handler(); + } + + @Override + public boolean isRemoved() { + return context.isRemoved(); + } + + @Override + public ChannelHandlerContext fireChannelRegistered() { + return context.fireChannelRegistered(); + } + + @Override + public ChannelHandlerContext fireChannelUnregistered() { + return context.fireChannelUnregistered(); + } + + @Override + public ChannelHandlerContext fireChannelActive() { + return context.fireChannelActive(); + } + + @Override + public ChannelHandlerContext fireChannelInactive() { + return context.fireChannelInactive(); + } + + @Override + public ChannelHandlerContext fireExceptionCaught(Throwable cause) { + return context.fireExceptionCaught(cause); + } + + @Override + public ChannelHandlerContext fireUserEventTriggered(Object evt) { + return context.fireUserEventTriggered(evt); + } + + @Override + public ChannelHandlerContext fireChannelRead(Object msg) { + if (!(msg instanceof NetworkMessage)) { + msg = new NetworkMessage(msg, remoteAddress); + } + return context.fireChannelRead(msg); + } + + @Override + public ChannelHandlerContext fireChannelReadComplete() { + return context.fireChannelReadComplete(); + } + + @Override + public ChannelHandlerContext fireChannelWritabilityChanged() { + return context.fireChannelWritabilityChanged(); + } + + @Override + public ChannelFuture bind(SocketAddress localAddress) { + return context.bind(localAddress); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress) { + return context.connect(remoteAddress); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { + return context.connect(remoteAddress, localAddress); + } + + @Override + public ChannelFuture disconnect() { + return context.disconnect(); + } + + @Override + public ChannelFuture close() { + return context.close(); + } + + @Override + public ChannelFuture deregister() { + return context.deregister(); + } + + @Override + public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { + return context.bind(localAddress, promise); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { + return context.connect(remoteAddress, promise); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { + return context.connect(remoteAddress, localAddress, promise); + } + + @Override + public ChannelFuture disconnect(ChannelPromise promise) { + return context.disconnect(promise); + } + + @Override + public ChannelFuture close(ChannelPromise promise) { + return context.close(promise); + } + + @Override + public ChannelFuture deregister(ChannelPromise promise) { + return context.deregister(promise); + } + + @Override + public ChannelHandlerContext read() { + return context.read(); + } + + @Override + public ChannelFuture write(Object msg) { + return context.write(msg); + } + + @Override + public ChannelFuture write(Object msg, ChannelPromise promise) { + if (!(msg instanceof NetworkMessage)) { + msg = new NetworkMessage(msg, remoteAddress); + } + return context.write(msg, promise); + } + + @Override + public ChannelHandlerContext flush() { + return context.flush(); + } + + @Override + public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { + return context.writeAndFlush(msg, promise); + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + return context.writeAndFlush(msg); + } + + @Override + public ChannelPromise newPromise() { + return context.newPromise(); + } + + @Override + public ChannelProgressivePromise newProgressivePromise() { + return context.newProgressivePromise(); + } + + @Override + public ChannelFuture newSucceededFuture() { + return context.newSucceededFuture(); + } + + @Override + public ChannelFuture newFailedFuture(Throwable cause) { + return context.newFailedFuture(cause); + } + + @Override + public ChannelPromise voidPromise() { + return context.voidPromise(); + } + + @Override + public ChannelPipeline pipeline() { + return context.pipeline(); + } + + @Override + public ByteBufAllocator alloc() { + return context.alloc(); + } + + @SuppressWarnings("deprecation") + @Override + public Attribute attr(AttributeKey key) { + return context.attr(key); + } + + @SuppressWarnings("deprecation") + @Override + public boolean hasAttr(AttributeKey key) { + return context.hasAttr(key); + } + +} diff --git a/src/main/java/org/traccar/WrapperInboundHandler.java b/src/main/java/org/traccar/WrapperInboundHandler.java new file mode 100644 index 000000000..ca33d021f --- /dev/null +++ b/src/main/java/org/traccar/WrapperInboundHandler.java @@ -0,0 +1,94 @@ +/* + * Copyright 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. + * 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 io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandler; + +public class WrapperInboundHandler implements ChannelInboundHandler { + + private ChannelInboundHandler handler; + + public ChannelInboundHandler getWrappedHandler() { + return handler; + } + + public WrapperInboundHandler(ChannelInboundHandler handler) { + this.handler = handler; + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + handler.channelRegistered(ctx); + } + + @Override + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { + handler.channelUnregistered(ctx); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + handler.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + handler.channelInactive(ctx); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof NetworkMessage) { + NetworkMessage nm = (NetworkMessage) msg; + handler.channelRead(new WrapperContext(ctx, nm.getRemoteAddress()), nm.getMessage()); + } else { + handler.channelRead(ctx, msg); + } + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + handler.channelReadComplete(ctx); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + handler.userEventTriggered(ctx, evt); + } + + @Override + public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { + handler.channelWritabilityChanged(ctx); + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + handler.handlerAdded(ctx); + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + handler.handlerRemoved(ctx); + } + + @SuppressWarnings("deprecation") + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + handler.exceptionCaught(ctx, cause); + } + +} diff --git a/src/main/java/org/traccar/WrapperOutboundHandler.java b/src/main/java/org/traccar/WrapperOutboundHandler.java new file mode 100644 index 000000000..0136c5b22 --- /dev/null +++ b/src/main/java/org/traccar/WrapperOutboundHandler.java @@ -0,0 +1,99 @@ +/* + * Copyright 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. + * 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 io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandler; +import io.netty.channel.ChannelPromise; + +import java.net.SocketAddress; + +public class WrapperOutboundHandler implements ChannelOutboundHandler { + + private ChannelOutboundHandler handler; + + public ChannelOutboundHandler getWrappedHandler() { + return handler; + } + + public WrapperOutboundHandler(ChannelOutboundHandler handler) { + this.handler = handler; + } + + @Override + public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception { + handler.bind(ctx, localAddress, promise); + } + + @Override + public void connect( + ChannelHandlerContext ctx, SocketAddress remoteAddress, + SocketAddress localAddress, ChannelPromise promise) throws Exception { + handler.connect(ctx, remoteAddress, localAddress, promise); + } + + @Override + public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + handler.disconnect(ctx, promise); + } + + @Override + public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + handler.close(ctx, promise); + } + + @Override + public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + handler.deregister(ctx, promise); + } + + @Override + public void read(ChannelHandlerContext ctx) throws Exception { + handler.read(ctx); + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if (msg instanceof NetworkMessage) { + NetworkMessage nm = (NetworkMessage) msg; + handler.write(new WrapperContext(ctx, nm.getRemoteAddress()), nm.getMessage(), promise); + } else { + handler.write(ctx, msg, promise); + } + } + + @Override + public void flush(ChannelHandlerContext ctx) throws Exception { + handler.flush(ctx); + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + handler.handlerAdded(ctx); + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + handler.handlerRemoved(ctx); + } + + @SuppressWarnings("deprecation") + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + handler.exceptionCaught(ctx, cause); + } + +} diff --git a/src/main/java/org/traccar/api/AsyncSocket.java b/src/main/java/org/traccar/api/AsyncSocket.java new file mode 100644 index 000000000..906d16b5b --- /dev/null +++ b/src/main/java/org/traccar/api/AsyncSocket.java @@ -0,0 +1,96 @@ +/* + * Copyright 2015 - 2016 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. + * 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.api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.WebSocketAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.database.ConnectionManager; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Position; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.UpdateListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncSocket.class); + + private static final String KEY_DEVICES = "devices"; + private static final String KEY_POSITIONS = "positions"; + private static final String KEY_EVENTS = "events"; + + private long userId; + + public AsyncSocket(long userId) { + this.userId = userId; + } + + @Override + public void onWebSocketConnect(Session session) { + super.onWebSocketConnect(session); + + Map> data = new HashMap<>(); + data.put(KEY_POSITIONS, Context.getDeviceManager().getInitialState(userId)); + sendData(data); + + Context.getConnectionManager().addListener(userId, this); + } + + @Override + public void onWebSocketClose(int statusCode, String reason) { + super.onWebSocketClose(statusCode, reason); + + Context.getConnectionManager().removeListener(userId, this); + } + + @Override + public void onUpdateDevice(Device device) { + Map> data = new HashMap<>(); + data.put(KEY_DEVICES, Collections.singletonList(device)); + sendData(data); + } + + @Override + public void onUpdatePosition(Position position) { + Map> data = new HashMap<>(); + data.put(KEY_POSITIONS, Collections.singletonList(position)); + sendData(data); + } + + @Override + public void onUpdateEvent(Event event) { + Map> data = new HashMap<>(); + data.put(KEY_EVENTS, Collections.singletonList(event)); + sendData(data); + } + + private void sendData(Map> data) { + if (!data.isEmpty() && isConnected()) { + try { + getRemote().sendString(Context.getObjectMapper().writeValueAsString(data), null); + } catch (JsonProcessingException e) { + LOGGER.warn("Socket JSON formatting error", e); + } + } + } +} diff --git a/src/main/java/org/traccar/api/AsyncSocketServlet.java b/src/main/java/org/traccar/api/AsyncSocketServlet.java new file mode 100644 index 000000000..9318b6fc6 --- /dev/null +++ b/src/main/java/org/traccar/api/AsyncSocketServlet.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015 - 2016 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. + * 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.api; + +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; +import org.eclipse.jetty.websocket.servlet.WebSocketCreator; +import org.eclipse.jetty.websocket.servlet.WebSocketServlet; +import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; +import org.traccar.Context; +import org.traccar.api.resource.SessionResource; + +public class AsyncSocketServlet extends WebSocketServlet { + + private static final long ASYNC_TIMEOUT = 10 * 60 * 1000; + + @Override + public void configure(WebSocketServletFactory factory) { + factory.getPolicy().setIdleTimeout(Context.getConfig().getLong("web.timeout", ASYNC_TIMEOUT)); + factory.setCreator(new WebSocketCreator() { + @Override + public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) { + if (req.getSession() != null) { + long userId = (Long) req.getSession().getAttribute(SessionResource.USER_ID_KEY); + return new AsyncSocket(userId); + } else { + return null; + } + } + }); + } + +} diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java new file mode 100644 index 000000000..7de6a3877 --- /dev/null +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -0,0 +1,176 @@ +/* + * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api; + +import java.sql.SQLException; +import java.util.Set; + +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.database.BaseObjectManager; +import org.traccar.database.ExtendedObjectManager; +import org.traccar.database.ManagableObjects; +import org.traccar.database.SimpleObjectManager; +import org.traccar.helper.LogAction; +import org.traccar.model.BaseModel; +import org.traccar.model.Calendar; +import org.traccar.model.Command; +import org.traccar.model.Device; +import org.traccar.model.Group; +import org.traccar.model.GroupedModel; +import org.traccar.model.ScheduledModel; +import org.traccar.model.User; + +public abstract class BaseObjectResource extends BaseResource { + + private Class baseClass; + + public BaseObjectResource(Class baseClass) { + this.baseClass = baseClass; + } + + protected final Class getBaseClass() { + return baseClass; + } + + protected final Set getSimpleManagerItems(BaseObjectManager manager, boolean all, long userId) { + Set result = null; + if (all) { + if (Context.getPermissionsManager().getUserAdmin(getUserId())) { + result = manager.getAllItems(); + } else { + Context.getPermissionsManager().checkManager(getUserId()); + result = ((ManagableObjects) manager).getManagedItems(getUserId()); + } + } else { + if (userId == 0) { + userId = getUserId(); + } + Context.getPermissionsManager().checkUser(getUserId(), userId); + result = ((ManagableObjects) manager).getUserItems(userId); + } + return result; + } + + @POST + public Response add(T entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + if (baseClass.equals(Device.class)) { + Context.getPermissionsManager().checkDeviceReadonly(getUserId()); + Context.getPermissionsManager().checkDeviceLimit(getUserId()); + } else if (baseClass.equals(Command.class)) { + Context.getPermissionsManager().checkLimitCommands(getUserId()); + } else if (entity instanceof GroupedModel && ((GroupedModel) entity).getGroupId() != 0) { + Context.getPermissionsManager().checkPermission( + Group.class, getUserId(), ((GroupedModel) entity).getGroupId()); + } else if (entity instanceof ScheduledModel && ((ScheduledModel) entity).getCalendarId() != 0) { + Context.getPermissionsManager().checkPermission( + Calendar.class, getUserId(), ((ScheduledModel) entity).getCalendarId()); + } + + BaseObjectManager manager = Context.getManager(baseClass); + manager.addItem(entity); + LogAction.create(getUserId(), entity); + + Context.getDataManager().linkObject(User.class, getUserId(), baseClass, entity.getId(), true); + LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId()); + + if (manager instanceof SimpleObjectManager) { + ((SimpleObjectManager) manager).refreshUserItems(); + } else if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) { + Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); + Context.getPermissionsManager().refreshAllExtendedPermissions(); + } + return Response.ok(entity).build(); + } + + @Path("{id}") + @PUT + public Response update(T entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + if (baseClass.equals(Device.class)) { + Context.getPermissionsManager().checkDeviceReadonly(getUserId()); + } else if (baseClass.equals(User.class)) { + User before = Context.getPermissionsManager().getUser(entity.getId()); + Context.getPermissionsManager().checkUserUpdate(getUserId(), before, (User) entity); + } else if (baseClass.equals(Command.class)) { + Context.getPermissionsManager().checkLimitCommands(getUserId()); + } else if (entity instanceof GroupedModel && ((GroupedModel) entity).getGroupId() != 0) { + Context.getPermissionsManager().checkPermission( + Group.class, getUserId(), ((GroupedModel) entity).getGroupId()); + } else if (entity instanceof ScheduledModel && ((ScheduledModel) entity).getCalendarId() != 0) { + Context.getPermissionsManager().checkPermission( + Calendar.class, getUserId(), ((ScheduledModel) entity).getCalendarId()); + } + Context.getPermissionsManager().checkPermission(baseClass, getUserId(), entity.getId()); + + Context.getManager(baseClass).updateItem(entity); + LogAction.edit(getUserId(), entity); + + if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) { + Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); + Context.getPermissionsManager().refreshAllExtendedPermissions(); + } + return Response.ok(entity).build(); + } + + @Path("{id}") + @DELETE + public Response remove(@PathParam("id") long id) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + if (baseClass.equals(Device.class)) { + Context.getPermissionsManager().checkDeviceReadonly(getUserId()); + } else if (baseClass.equals(Command.class)) { + Context.getPermissionsManager().checkLimitCommands(getUserId()); + } + Context.getPermissionsManager().checkPermission(baseClass, getUserId(), id); + + BaseObjectManager manager = Context.getManager(baseClass); + manager.removeItem(id); + LogAction.remove(getUserId(), baseClass, id); + + if (manager instanceof SimpleObjectManager) { + ((SimpleObjectManager) manager).refreshUserItems(); + if (manager instanceof ExtendedObjectManager) { + ((ExtendedObjectManager) manager).refreshExtendedPermissions(); + } + } + if (baseClass.equals(Group.class) || baseClass.equals(Device.class) || baseClass.equals(User.class)) { + if (baseClass.equals(Group.class)) { + Context.getGroupsManager().updateGroupCache(true); + Context.getDeviceManager().updateDeviceCache(true); + } + Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); + if (baseClass.equals(User.class)) { + Context.getPermissionsManager().refreshAllUsersPermissions(); + } else { + Context.getPermissionsManager().refreshAllExtendedPermissions(); + } + } else if (baseClass.equals(Calendar.class)) { + Context.getGeofenceManager().refreshItems(); + Context.getNotificationManager().refreshItems(); + } + return Response.noContent().build(); + } + +} diff --git a/src/main/java/org/traccar/api/BaseResource.java b/src/main/java/org/traccar/api/BaseResource.java new file mode 100644 index 000000000..cc272df9c --- /dev/null +++ b/src/main/java/org/traccar/api/BaseResource.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015 - 2017 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. + * 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.api; + +import javax.ws.rs.core.SecurityContext; + +public class BaseResource { + + @javax.ws.rs.core.Context + private SecurityContext securityContext; + + protected long getUserId() { + UserPrincipal principal = (UserPrincipal) securityContext.getUserPrincipal(); + if (principal != null) { + return principal.getUserId(); + } + return 0; + } +} diff --git a/src/main/java/org/traccar/api/CorsResponseFilter.java b/src/main/java/org/traccar/api/CorsResponseFilter.java new file mode 100644 index 000000000..227f80609 --- /dev/null +++ b/src/main/java/org/traccar/api/CorsResponseFilter.java @@ -0,0 +1,58 @@ +/* + * 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. + * 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.api; + +import io.netty.handler.codec.http.HttpHeaderNames; +import org.traccar.Context; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import java.io.IOException; + +public class CorsResponseFilter implements ContainerResponseFilter { + + private static final String ORIGIN_ALL = "*"; + private static final String HEADERS_ALL = "origin, content-type, accept, authorization"; + private static final String METHODS_ALL = "GET, POST, PUT, DELETE, OPTIONS"; + + @Override + public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { + if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS.toString())) { + response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS.toString(), HEADERS_ALL); + } + + if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_CREDENTIALS.toString())) { + response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_CREDENTIALS.toString(), true); + } + + if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS.toString())) { + response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS.toString(), METHODS_ALL); + } + + if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString())) { + String origin = request.getHeaderString(HttpHeaderNames.ORIGIN.toString()); + String allowed = Context.getConfig().getString("web.origin"); + + if (origin == null) { + response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString(), ORIGIN_ALL); + } else if (allowed == null || allowed.equals(ORIGIN_ALL) || allowed.contains(origin)) { + response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString(), origin); + } + } + } + +} diff --git a/src/main/java/org/traccar/api/ExtendedObjectResource.java b/src/main/java/org/traccar/api/ExtendedObjectResource.java new file mode 100644 index 000000000..007a7b1bd --- /dev/null +++ b/src/main/java/org/traccar/api/ExtendedObjectResource.java @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; + +import org.traccar.Context; +import org.traccar.database.ExtendedObjectManager; +import org.traccar.model.BaseModel; + +public class ExtendedObjectResource extends BaseObjectResource { + + public ExtendedObjectResource(Class baseClass) { + super(baseClass); + } + + @GET + public Collection get( + @QueryParam("all") boolean all, @QueryParam("userId") long userId, @QueryParam("groupId") long groupId, + @QueryParam("deviceId") long deviceId, @QueryParam("refresh") boolean refresh) throws SQLException { + + ExtendedObjectManager manager = (ExtendedObjectManager) Context.getManager(getBaseClass()); + if (refresh) { + manager.refreshItems(); + } + + Set result = new HashSet<>(getSimpleManagerItems(manager, all, userId)); + + if (groupId != 0) { + Context.getPermissionsManager().checkGroup(getUserId(), groupId); + result.retainAll(manager.getGroupItems(groupId)); + } + + if (deviceId != 0) { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + result.retainAll(manager.getDeviceItems(deviceId)); + } + return manager.getItems(result); + + } + +} diff --git a/src/main/java/org/traccar/api/MediaFilter.java b/src/main/java/org/traccar/api/MediaFilter.java new file mode 100644 index 000000000..53539770f --- /dev/null +++ b/src/main/java/org/traccar/api/MediaFilter.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api; + +import java.io.IOException; +import java.sql.SQLException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.traccar.Context; +import org.traccar.Main; +import org.traccar.api.resource.SessionResource; +import org.traccar.database.StatisticsManager; +import org.traccar.helper.Log; +import org.traccar.model.Device; + +public class MediaFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletResponse httpResponse = (HttpServletResponse) response; + try { + HttpSession session = ((HttpServletRequest) request).getSession(false); + Long userId = null; + if (session != null) { + userId = (Long) session.getAttribute(SessionResource.USER_ID_KEY); + if (userId != null) { + Context.getPermissionsManager().checkUserEnabled(userId); + Main.getInjector().getInstance(StatisticsManager.class).registerRequest(userId); + } + } + if (userId == null) { + httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + String path = ((HttpServletRequest) request).getPathInfo(); + String[] parts = path.split("/"); + if (parts.length < 2 || parts.length == 2 && !path.endsWith("/")) { + Context.getPermissionsManager().checkAdmin(userId); + } else { + Device device = Context.getDeviceManager().getByUniqueId(parts[1]); + if (device != null) { + Context.getPermissionsManager().checkDevice(userId, device.getId()); + } else { + httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND); + return; + } + } + + chain.doFilter(request, response); + } catch (SecurityException e) { + httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); + httpResponse.getWriter().println(Log.exceptionStack(e)); + } catch (SQLException e) { + httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST); + httpResponse.getWriter().println(Log.exceptionStack(e)); + } + } + + @Override + public void destroy() { + } + +} diff --git a/src/main/java/org/traccar/api/ObjectMapperProvider.java b/src/main/java/org/traccar/api/ObjectMapperProvider.java new file mode 100644 index 000000000..f81b20917 --- /dev/null +++ b/src/main/java/org/traccar/api/ObjectMapperProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015 - 2016 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. + * 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.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.traccar.Context; + +import javax.ws.rs.ext.ContextResolver; +import javax.ws.rs.ext.Provider; + +@Provider +public class ObjectMapperProvider implements ContextResolver { + + @Override + public ObjectMapper getContext(Class type) { + return Context.getObjectMapper(); + } + +} diff --git a/src/main/java/org/traccar/api/ResourceErrorHandler.java b/src/main/java/org/traccar/api/ResourceErrorHandler.java new file mode 100644 index 000000000..1d618b08d --- /dev/null +++ b/src/main/java/org/traccar/api/ResourceErrorHandler.java @@ -0,0 +1,42 @@ +/* + * Copyright 2015 - 2016 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. + * 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.api; + +import org.traccar.helper.Log; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +public class ResourceErrorHandler implements ExceptionMapper { + + @Override + public Response toResponse(Exception e) { + if (e instanceof WebApplicationException) { + WebApplicationException exception = (WebApplicationException) e; + String message; + if (exception.getCause() != null) { + message = Log.exceptionStack(exception.getCause()); + } else { + message = Log.exceptionStack(exception); + } + return Response.fromResponse(exception.getResponse()).entity(message).build(); + } else { + return Response.status(Response.Status.BAD_REQUEST).entity(Log.exceptionStack(e)).build(); + } + } + +} diff --git a/src/main/java/org/traccar/api/SecurityRequestFilter.java b/src/main/java/org/traccar/api/SecurityRequestFilter.java new file mode 100644 index 000000000..33b6b37df --- /dev/null +++ b/src/main/java/org/traccar/api/SecurityRequestFilter.java @@ -0,0 +1,119 @@ +/* + * Copyright 2015 - 2016 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. + * 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.api; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.Main; +import org.traccar.api.resource.SessionResource; +import org.traccar.database.StatisticsManager; +import org.traccar.helper.DataConverter; +import org.traccar.model.User; + +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.sql.SQLException; + +public class SecurityRequestFilter implements ContainerRequestFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(SecurityRequestFilter.class); + + public static final String AUTHORIZATION_HEADER = "Authorization"; + public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; + public static final String BASIC_REALM = "Basic realm=\"api\""; + public static final String X_REQUESTED_WITH = "X-Requested-With"; + public static final String XML_HTTP_REQUEST = "XMLHttpRequest"; + + public static String[] decodeBasicAuth(String auth) { + auth = auth.replaceFirst("[B|b]asic ", ""); + byte[] decodedBytes = DataConverter.parseBase64(auth); + if (decodedBytes != null && decodedBytes.length > 0) { + return new String(decodedBytes, StandardCharsets.US_ASCII).split(":", 2); + } + return null; + } + + @javax.ws.rs.core.Context + private HttpServletRequest request; + + @javax.ws.rs.core.Context + private ResourceInfo resourceInfo; + + @Override + public void filter(ContainerRequestContext requestContext) { + + if (requestContext.getMethod().equals("OPTIONS")) { + return; + } + + SecurityContext securityContext = null; + + try { + + String authHeader = requestContext.getHeaderString(AUTHORIZATION_HEADER); + if (authHeader != null) { + + try { + String[] auth = decodeBasicAuth(authHeader); + User user = Context.getPermissionsManager().login(auth[0], auth[1]); + if (user != null) { + Main.getInjector().getInstance(StatisticsManager.class).registerRequest(user.getId()); + securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); + } + } catch (SQLException e) { + throw new WebApplicationException(e); + } + + } else if (request.getSession() != null) { + + Long userId = (Long) request.getSession().getAttribute(SessionResource.USER_ID_KEY); + if (userId != null) { + Context.getPermissionsManager().checkUserEnabled(userId); + Main.getInjector().getInstance(StatisticsManager.class).registerRequest(userId); + securityContext = new UserSecurityContext(new UserPrincipal(userId)); + } + + } + + } catch (SecurityException e) { + LOGGER.warn("Authentication error", e); + } + + if (securityContext != null) { + requestContext.setSecurityContext(securityContext); + } else { + Method method = resourceInfo.getResourceMethod(); + if (!method.isAnnotationPresent(PermitAll.class)) { + Response.ResponseBuilder responseBuilder = Response.status(Response.Status.UNAUTHORIZED); + if (!XML_HTTP_REQUEST.equals(request.getHeader(X_REQUESTED_WITH))) { + responseBuilder.header(WWW_AUTHENTICATE, BASIC_REALM); + } + throw new WebApplicationException(responseBuilder.build()); + } + } + + } + +} diff --git a/src/main/java/org/traccar/api/SimpleObjectResource.java b/src/main/java/org/traccar/api/SimpleObjectResource.java new file mode 100644 index 000000000..a7fcae0e7 --- /dev/null +++ b/src/main/java/org/traccar/api/SimpleObjectResource.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api; + +import java.sql.SQLException; +import java.util.Collection; + +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; + +import org.traccar.Context; +import org.traccar.database.BaseObjectManager; +import org.traccar.model.BaseModel; + +public class SimpleObjectResource extends BaseObjectResource { + + public SimpleObjectResource(Class baseClass) { + super(baseClass); + } + + @GET + public Collection get( + @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws SQLException { + + BaseObjectManager manager = Context.getManager(getBaseClass()); + return manager.getItems(getSimpleManagerItems(manager, all, userId)); + } + +} diff --git a/src/main/java/org/traccar/api/UserPrincipal.java b/src/main/java/org/traccar/api/UserPrincipal.java new file mode 100644 index 000000000..80e92c2dd --- /dev/null +++ b/src/main/java/org/traccar/api/UserPrincipal.java @@ -0,0 +1,37 @@ +/* + * Copyright 2015 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. + * 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.api; + +import java.security.Principal; + +public class UserPrincipal implements Principal { + + private long userId; + + public UserPrincipal(long userId) { + this.userId = userId; + } + + public Long getUserId() { + return userId; + } + + @Override + public String getName() { + return null; + } + +} diff --git a/src/main/java/org/traccar/api/UserSecurityContext.java b/src/main/java/org/traccar/api/UserSecurityContext.java new file mode 100644 index 000000000..55c0621bc --- /dev/null +++ b/src/main/java/org/traccar/api/UserSecurityContext.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 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. + * 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.api; + +import javax.ws.rs.core.SecurityContext; +import java.security.Principal; + +public class UserSecurityContext implements SecurityContext { + + private UserPrincipal principal; + + public UserSecurityContext(UserPrincipal principal) { + this.principal = principal; + } + + @Override + public Principal getUserPrincipal() { + return principal; + } + + @Override + public boolean isUserInRole(String role) { + return true; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public String getAuthenticationScheme() { + return BASIC_AUTH; + } + +} diff --git a/src/main/java/org/traccar/api/resource/AttributeResource.java b/src/main/java/org/traccar/api/resource/AttributeResource.java new file mode 100644 index 000000000..de69d871c --- /dev/null +++ b/src/main/java/org/traccar/api/resource/AttributeResource.java @@ -0,0 +1,97 @@ +/* + * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api.resource; + +import java.sql.SQLException; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.api.ExtendedObjectResource; +import org.traccar.model.Attribute; +import org.traccar.model.Position; +import org.traccar.handler.ComputedAttributesHandler; + +@Path("attributes/computed") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class AttributeResource extends ExtendedObjectResource { + + public AttributeResource() { + super(Attribute.class); + } + + @POST + @Path("test") + public Response test(@QueryParam("deviceId") long deviceId, Attribute entity) { + Context.getPermissionsManager().checkAdmin(getUserId()); + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + Position last = Context.getIdentityManager().getLastPosition(deviceId); + if (last != null) { + Object result = new ComputedAttributesHandler( + Context.getConfig(), + Context.getIdentityManager(), + Context.getAttributesManager()).computeAttribute(entity, last); + if (result != null) { + switch (entity.getType()) { + case "number": + Number numberValue = (Number) result; + return Response.ok(numberValue).build(); + case "boolean": + Boolean booleanValue = (Boolean) result; + return Response.ok(booleanValue).build(); + default: + return Response.ok(result.toString()).build(); + } + } else { + return Response.noContent().build(); + } + } else { + throw new IllegalArgumentException("Device has no last position"); + } + } + + @POST + public Response add(Attribute entity) throws SQLException { + Context.getPermissionsManager().checkAdmin(getUserId()); + return super.add(entity); + } + + @Path("{id}") + @PUT + public Response update(Attribute entity) throws SQLException { + Context.getPermissionsManager().checkAdmin(getUserId()); + return super.update(entity); + } + + @Path("{id}") + @DELETE + public Response remove(@PathParam("id") long id) throws SQLException { + Context.getPermissionsManager().checkAdmin(getUserId()); + return super.remove(id); + } + +} diff --git a/src/main/java/org/traccar/api/resource/CalendarResource.java b/src/main/java/org/traccar/api/resource/CalendarResource.java new file mode 100644 index 000000000..9399c34a5 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/CalendarResource.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api.resource; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.traccar.api.SimpleObjectResource; +import org.traccar.model.Calendar; + +@Path("calendars") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class CalendarResource extends SimpleObjectResource { + + public CalendarResource() { + super(Calendar.class); + } + +} diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java new file mode 100644 index 000000000..703638701 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -0,0 +1,89 @@ +/* + * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api.resource; + +import org.traccar.Context; +import org.traccar.api.ExtendedObjectResource; +import org.traccar.database.CommandsManager; +import org.traccar.model.Command; +import org.traccar.model.Typed; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@Path("commands") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class CommandResource extends ExtendedObjectResource { + + public CommandResource() { + super(Command.class); + } + + @GET + @Path("send") + public Collection get(@QueryParam("deviceId") long deviceId) throws SQLException { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + CommandsManager commandsManager = Context.getCommandsManager(); + Set result = new HashSet<>(commandsManager.getUserItems(getUserId())); + result.retainAll(commandsManager.getSupportedCommands(deviceId)); + return commandsManager.getItems(result); + } + + @POST + @Path("send") + public Response send(Command entity) throws Exception { + Context.getPermissionsManager().checkReadonly(getUserId()); + long deviceId = entity.getDeviceId(); + long id = entity.getId(); + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + if (id != 0) { + Context.getPermissionsManager().checkPermission(Command.class, getUserId(), id); + Context.getPermissionsManager().checkUserDeviceCommand(getUserId(), deviceId, id); + } else { + Context.getPermissionsManager().checkLimitCommands(getUserId()); + } + if (!Context.getCommandsManager().sendCommand(entity)) { + return Response.accepted(entity).build(); + } + return Response.ok(entity).build(); + } + + @GET + @Path("types") + public Collection get(@QueryParam("deviceId") long deviceId, + @QueryParam("textChannel") boolean textChannel) { + if (deviceId != 0) { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + return Context.getCommandsManager().getCommandTypes(deviceId, textChannel); + } else { + return Context.getCommandsManager().getAllCommandTypes(); + } + } +} diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java new file mode 100644 index 000000000..f9c9a139d --- /dev/null +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -0,0 +1,100 @@ +/* + * 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. + * 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.api.resource; + +import org.traccar.Context; +import org.traccar.api.BaseObjectResource; +import org.traccar.database.DeviceManager; +import org.traccar.helper.LogAction; +import org.traccar.model.Device; +import org.traccar.model.DeviceAccumulators; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Path("devices") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class DeviceResource extends BaseObjectResource { + + public DeviceResource() { + super(Device.class); + } + + @GET + public Collection get( + @QueryParam("all") boolean all, @QueryParam("userId") long userId, + @QueryParam("uniqueId") List uniqueIds, + @QueryParam("id") List deviceIds) throws SQLException { + DeviceManager deviceManager = Context.getDeviceManager(); + Set result = null; + if (all) { + if (Context.getPermissionsManager().getUserAdmin(getUserId())) { + result = deviceManager.getAllItems(); + } else { + Context.getPermissionsManager().checkManager(getUserId()); + result = deviceManager.getManagedItems(getUserId()); + } + } else if (uniqueIds.isEmpty() && deviceIds.isEmpty()) { + if (userId == 0) { + userId = getUserId(); + } + Context.getPermissionsManager().checkUser(getUserId(), userId); + if (Context.getPermissionsManager().getUserAdmin(getUserId())) { + result = deviceManager.getAllUserItems(userId); + } else { + result = deviceManager.getUserItems(userId); + } + } else { + result = new HashSet<>(); + for (String uniqueId : uniqueIds) { + Device device = deviceManager.getByUniqueId(uniqueId); + Context.getPermissionsManager().checkDevice(getUserId(), device.getId()); + result.add(device.getId()); + } + for (Long deviceId : deviceIds) { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + result.add(deviceId); + } + } + return deviceManager.getItems(result); + } + + @Path("{id}/accumulators") + @PUT + public Response updateAccumulators(DeviceAccumulators entity) throws SQLException { + if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { + Context.getPermissionsManager().checkManager(getUserId()); + Context.getPermissionsManager().checkPermission(Device.class, getUserId(), entity.getDeviceId()); + } + Context.getDeviceManager().resetDeviceAccumulators(entity); + LogAction.resetDeviceAccumulators(getUserId(), entity.getDeviceId()); + return Response.noContent().build(); + } + +} diff --git a/src/main/java/org/traccar/api/resource/DriverResource.java b/src/main/java/org/traccar/api/resource/DriverResource.java new file mode 100644 index 000000000..91aa54c5e --- /dev/null +++ b/src/main/java/org/traccar/api/resource/DriverResource.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api.resource; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.traccar.api.ExtendedObjectResource; +import org.traccar.model.Driver; + +@Path("drivers") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class DriverResource extends ExtendedObjectResource { + + public DriverResource() { + super(Driver.class); + } + +} diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java new file mode 100644 index 000000000..e0ccf7020 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/EventResource.java @@ -0,0 +1,38 @@ +package org.traccar.api.resource; + +import java.sql.SQLException; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.model.Event; +import org.traccar.model.Geofence; +import org.traccar.model.Maintenance; + +@Path("events") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) + +public class EventResource extends BaseResource { + + @Path("{id}") + @GET + public Event get(@PathParam("id") long id) throws SQLException { + Event event = Context.getDataManager().getObject(Event.class, id); + Context.getPermissionsManager().checkDevice(getUserId(), event.getDeviceId()); + if (event.getGeofenceId() != 0) { + Context.getPermissionsManager().checkPermission(Geofence.class, getUserId(), event.getGeofenceId()); + } + if (event.getMaintenanceId() != 0) { + Context.getPermissionsManager().checkPermission(Maintenance.class, getUserId(), event.getMaintenanceId()); + } + return event; + } + +} diff --git a/src/main/java/org/traccar/api/resource/GeofenceResource.java b/src/main/java/org/traccar/api/resource/GeofenceResource.java new file mode 100644 index 000000000..58f2c188c --- /dev/null +++ b/src/main/java/org/traccar/api/resource/GeofenceResource.java @@ -0,0 +1,35 @@ +/* + * Copyright 2016 - 2017 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. + * 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.api.resource; + +import org.traccar.api.ExtendedObjectResource; +import org.traccar.model.Geofence; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("geofences") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class GeofenceResource extends ExtendedObjectResource { + + public GeofenceResource() { + super(Geofence.class); + } + +} diff --git a/src/main/java/org/traccar/api/resource/GroupResource.java b/src/main/java/org/traccar/api/resource/GroupResource.java new file mode 100644 index 000000000..fcea15d0a --- /dev/null +++ b/src/main/java/org/traccar/api/resource/GroupResource.java @@ -0,0 +1,35 @@ +/* + * Copyright 2016 - 2017 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. + * 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.api.resource; + +import org.traccar.api.SimpleObjectResource; +import org.traccar.model.Group; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("groups") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class GroupResource extends SimpleObjectResource { + + public GroupResource() { + super(Group.class); + } + +} diff --git a/src/main/java/org/traccar/api/resource/MaintenanceResource.java b/src/main/java/org/traccar/api/resource/MaintenanceResource.java new file mode 100644 index 000000000..fa1b359ce --- /dev/null +++ b/src/main/java/org/traccar/api/resource/MaintenanceResource.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api.resource; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.traccar.api.ExtendedObjectResource; +import org.traccar.model.Maintenance; + +@Path("maintenance") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class MaintenanceResource extends ExtendedObjectResource { + + public MaintenanceResource() { + super(Maintenance.class); + } + +} diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java new file mode 100644 index 000000000..9631a52b7 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/NotificationResource.java @@ -0,0 +1,76 @@ +/* + * Copyright 2016 - 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. + * 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.api.resource; + +import java.util.Collection; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.api.ExtendedObjectResource; +import org.traccar.model.Event; +import org.traccar.model.Notification; +import org.traccar.model.Typed; +import org.traccar.notification.MessageException; + + +@Path("notifications") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class NotificationResource extends ExtendedObjectResource { + + public NotificationResource() { + super(Notification.class); + } + + @GET + @Path("types") + public Collection get() { + return Context.getNotificationManager().getAllNotificationTypes(); + } + + @GET + @Path("notificators") + public Collection getNotificators() { + return Context.getNotificatorManager().getAllNotificatorTypes(); + } + + @POST + @Path("test") + public Response testMessage() throws MessageException, InterruptedException { + for (Typed method : Context.getNotificatorManager().getAllNotificatorTypes()) { + Context.getNotificatorManager() + .getNotificator(method.getType()).sendSync(getUserId(), new Event("test", 0), null); + } + return Response.noContent().build(); + } + + @POST + @Path("test/{notificator}") + public Response testMessage(@PathParam("notificator") String notificator) + throws MessageException, InterruptedException { + Context.getNotificatorManager().getNotificator(notificator).sendSync(getUserId(), new Event("test", 0), null); + return Response.noContent().build(); + } + +} diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java new file mode 100644 index 000000000..b89d9d376 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java @@ -0,0 +1,84 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api.resource; + +import java.sql.SQLException; +import java.util.LinkedHashMap; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.helper.LogAction; +import org.traccar.model.Device; +import org.traccar.model.Permission; +import org.traccar.model.User; + +@Path("permissions") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class PermissionsResource extends BaseResource { + + private void checkPermission(Permission permission, boolean link) { + if (!link && permission.getOwnerClass().equals(User.class) + && permission.getPropertyClass().equals(Device.class)) { + if (getUserId() != permission.getOwnerId()) { + Context.getPermissionsManager().checkUser(getUserId(), permission.getOwnerId()); + } else { + Context.getPermissionsManager().checkAdmin(getUserId()); + } + } else { + Context.getPermissionsManager().checkPermission( + permission.getOwnerClass(), getUserId(), permission.getOwnerId()); + } + Context.getPermissionsManager().checkPermission( + permission.getPropertyClass(), getUserId(), permission.getPropertyId()); + } + + @POST + public Response add(LinkedHashMap entity) throws SQLException, ClassNotFoundException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Permission permission = new Permission(entity); + checkPermission(permission, true); + Context.getDataManager().linkObject(permission.getOwnerClass(), permission.getOwnerId(), + permission.getPropertyClass(), permission.getPropertyId(), true); + LogAction.link(getUserId(), permission.getOwnerClass(), permission.getOwnerId(), + permission.getPropertyClass(), permission.getPropertyId()); + Context.getPermissionsManager().refreshPermissions(permission); + return Response.noContent().build(); + } + + @DELETE + public Response remove(LinkedHashMap entity) throws SQLException, ClassNotFoundException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Permission permission = new Permission(entity); + checkPermission(permission, false); + Context.getDataManager().linkObject(permission.getOwnerClass(), permission.getOwnerId(), + permission.getPropertyClass(), permission.getPropertyId(), false); + LogAction.unlink(getUserId(), permission.getOwnerClass(), permission.getOwnerId(), + permission.getPropertyClass(), permission.getPropertyId()); + Context.getPermissionsManager().refreshPermissions(permission); + return Response.noContent().build(); + } + +} diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java new file mode 100644 index 000000000..c031b842f --- /dev/null +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -0,0 +1,96 @@ +/* + * Copyright 2015 - 2016 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. + * 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.api.resource; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.helper.DateUtil; +import org.traccar.model.Position; +import org.traccar.web.CsvBuilder; +import org.traccar.web.GpxBuilder; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@Path("positions") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class PositionResource extends BaseResource { + + public static final String TEXT_CSV = "text/csv"; + public static final String CONTENT_DISPOSITION_VALUE_CSV = "attachment; filename=positions.csv"; + public static final String GPX = "application/gpx+xml"; + public static final String CONTENT_DISPOSITION_VALUE_GPX = "attachment; filename=positions.gpx"; + + @GET + public Collection getJson( + @QueryParam("deviceId") long deviceId, @QueryParam("id") List positionIds, + @QueryParam("from") String from, @QueryParam("to") String to) + throws SQLException { + if (!positionIds.isEmpty()) { + ArrayList positions = new ArrayList<>(); + for (Long positionId : positionIds) { + Position position = Context.getDataManager().getObject(Position.class, positionId); + Context.getPermissionsManager().checkDevice(getUserId(), position.getDeviceId()); + positions.add(position); + } + return positions; + } else if (deviceId == 0) { + return Context.getDeviceManager().getInitialState(getUserId()); + } else { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + return Context.getDataManager().getPositions( + deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to)); + } + } + + @GET + @Produces(TEXT_CSV) + public Response getCsv( + @QueryParam("deviceId") long deviceId, @QueryParam("from") String from, @QueryParam("to") String to) + throws SQLException { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + CsvBuilder csv = new CsvBuilder(); + csv.addHeaderLine(new Position()); + csv.addArray(Context.getDataManager().getPositions( + deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to))); + return Response.ok(csv.build()).header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_CSV).build(); + } + + @GET + @Produces(GPX) + public Response getGpx( + @QueryParam("deviceId") long deviceId, @QueryParam("from") String from, @QueryParam("to") String to) + throws SQLException { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + GpxBuilder gpx = new GpxBuilder(Context.getIdentityManager().getById(deviceId).getName()); + gpx.addPositions(Context.getDataManager().getPositions( + deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to))); + return Response.ok(gpx.build()).header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_GPX).build(); + } + +} diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java new file mode 100644 index 000000000..d371cf987 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -0,0 +1,210 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.api.resource; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; + +import javax.activation.DataHandler; +import javax.mail.MessagingException; +import javax.mail.internet.MimeBodyPart; +import javax.mail.util.ByteArrayDataSource; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.helper.DateUtil; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.reports.Events; +import org.traccar.reports.Summary; +import org.traccar.reports.Trips; +import org.traccar.reports.model.StopReport; +import org.traccar.reports.model.SummaryReport; +import org.traccar.reports.model.TripReport; +import org.traccar.reports.Route; +import org.traccar.reports.Stops; + +@Path("reports") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class ReportResource extends BaseResource { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReportResource.class); + + private static final String XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + private static final String CONTENT_DISPOSITION_VALUE_XLSX = "attachment; filename=report.xlsx"; + + private interface ReportExecutor { + void execute(ByteArrayOutputStream stream) throws SQLException, IOException; + } + + private Response executeReport( + long userId, boolean mail, ReportExecutor executor) throws SQLException, IOException { + final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + if (mail) { + new Thread(() -> { + try { + executor.execute(stream); + + MimeBodyPart attachment = new MimeBodyPart(); + + attachment.setFileName("report.xlsx"); + attachment.setDataHandler(new DataHandler(new ByteArrayDataSource( + stream.toByteArray(), "application/octet-stream"))); + + Context.getMailManager().sendMessage( + userId, "Report", "The report is in the attachment.", attachment); + } catch (SQLException | IOException | MessagingException e) { + LOGGER.warn("Report failed", e); + } + }).start(); + return Response.noContent().build(); + } else { + executor.execute(stream); + return Response.ok(stream.toByteArray()) + .header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_XLSX).build(); + } + } + + @Path("route") + @GET + public Collection getRoute( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { + return Route.getObjects(getUserId(), deviceIds, groupIds, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + } + + @Path("route") + @GET + @Produces(XLSX) + public Response getRouteExcel( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) + throws SQLException, IOException { + return executeReport(getUserId(), mail, stream -> { + Route.getExcel(stream, getUserId(), deviceIds, groupIds, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + }); + } + + @Path("events") + @GET + public Collection getEvents( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("type") final List types, + @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { + return Events.getObjects(getUserId(), deviceIds, groupIds, types, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + } + + @Path("events") + @GET + @Produces(XLSX) + public Response getEventsExcel( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("type") final List types, + @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) + throws SQLException, IOException { + return executeReport(getUserId(), mail, stream -> { + Events.getExcel(stream, getUserId(), deviceIds, groupIds, types, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + }); + } + + @Path("summary") + @GET + public Collection getSummary( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { + return Summary.getObjects(getUserId(), deviceIds, groupIds, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + } + + @Path("summary") + @GET + @Produces(XLSX) + public Response getSummaryExcel( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) + throws SQLException, IOException { + return executeReport(getUserId(), mail, stream -> { + Summary.getExcel(stream, getUserId(), deviceIds, groupIds, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + }); + } + + @Path("trips") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Collection getTrips( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { + return Trips.getObjects(getUserId(), deviceIds, groupIds, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + } + + @Path("trips") + @GET + @Produces(XLSX) + public Response getTripsExcel( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) + throws SQLException, IOException { + return executeReport(getUserId(), mail, stream -> { + Trips.getExcel(stream, getUserId(), deviceIds, groupIds, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + }); + } + + @Path("stops") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Collection getStops( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { + return Stops.getObjects(getUserId(), deviceIds, groupIds, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + } + + @Path("stops") + @GET + @Produces(XLSX) + public Response getStopsExcel( + @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, + @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) + throws SQLException, IOException { + return executeReport(getUserId(), mail, stream -> { + Stops.getExcel(stream, getUserId(), deviceIds, groupIds, + DateUtil.parseDate(from), DateUtil.parseDate(to)); + }); + } + +} diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java new file mode 100644 index 000000000..e7cad2a0c --- /dev/null +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -0,0 +1,63 @@ +/* + * Copyright 2015 - 2017 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. + * 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.api.resource; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.helper.LogAction; +import org.traccar.model.Server; + +import javax.annotation.security.PermitAll; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.sql.SQLException; + +@Path("server") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class ServerResource extends BaseResource { + + @PermitAll + @GET + public Server get() throws SQLException { + return Context.getPermissionsManager().getServer(); + } + + @PUT + public Response update(Server entity) throws SQLException { + Context.getPermissionsManager().checkAdmin(getUserId()); + Context.getPermissionsManager().updateServer(entity); + LogAction.edit(getUserId(), entity); + return Response.ok(entity).build(); + } + + @Path("geocode") + @GET + public String geocode(@QueryParam("latitude") double latitude, @QueryParam("longitude") double longitude) { + if (Context.getGeocoder() != null) { + return Context.getGeocoder().getAddress(latitude, longitude, null); + } else { + throw new RuntimeException("Reverse geocoding is not enabled"); + } + } + +} diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java new file mode 100644 index 000000000..fd331c766 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -0,0 +1,120 @@ +/* + * Copyright 2015 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. + * 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.api.resource; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.helper.DataConverter; +import org.traccar.helper.LogAction; +import org.traccar.model.User; + +import javax.annotation.security.PermitAll; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.sql.SQLException; + +@Path("session") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_FORM_URLENCODED) +public class SessionResource extends BaseResource { + + public static final String USER_ID_KEY = "userId"; + public static final String USER_COOKIE_KEY = "user"; + public static final String PASS_COOKIE_KEY = "password"; + + @javax.ws.rs.core.Context + private HttpServletRequest request; + + @PermitAll + @GET + public User get(@QueryParam("token") String token) throws SQLException, UnsupportedEncodingException { + Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY); + if (userId == null) { + Cookie[] cookies = request.getCookies(); + String email = null, password = null; + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals(USER_COOKIE_KEY)) { + byte[] emailBytes = DataConverter.parseBase64( + URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name())); + email = new String(emailBytes, StandardCharsets.UTF_8); + } else if (cookie.getName().equals(PASS_COOKIE_KEY)) { + byte[] passwordBytes = DataConverter.parseBase64( + URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name())); + password = new String(passwordBytes, StandardCharsets.UTF_8); + } + } + } + if (email != null && password != null) { + User user = Context.getPermissionsManager().login(email, password); + if (user != null) { + userId = user.getId(); + request.getSession().setAttribute(USER_ID_KEY, userId); + } + } else if (token != null) { + User user = Context.getUsersManager().getUserByToken(token); + if (user != null) { + userId = user.getId(); + request.getSession().setAttribute(USER_ID_KEY, userId); + } + } + } + + if (userId != null) { + Context.getPermissionsManager().checkUserEnabled(userId); + return Context.getPermissionsManager().getUser(userId); + } else { + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); + } + } + + @PermitAll + @POST + public User add( + @FormParam("email") String email, @FormParam("password") String password) throws SQLException { + User user = Context.getPermissionsManager().login(email, password); + if (user != null) { + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId()); + return user; + } else { + throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); + } + } + + @DELETE + public Response remove() { + LogAction.logout(getUserId()); + request.getSession().removeAttribute(USER_ID_KEY); + return Response.noContent().build(); + } + +} diff --git a/src/main/java/org/traccar/api/resource/StatisticsResource.java b/src/main/java/org/traccar/api/resource/StatisticsResource.java new file mode 100644 index 000000000..e801d4ff3 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/StatisticsResource.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016 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. + * 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.api.resource; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.helper.DateUtil; +import org.traccar.model.Statistics; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.sql.SQLException; +import java.util.Collection; + +@Path("statistics") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class StatisticsResource extends BaseResource { + + @GET + public Collection get( + @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { + Context.getPermissionsManager().checkAdmin(getUserId()); + return Context.getDataManager().getStatistics(DateUtil.parseDate(from), DateUtil.parseDate(to)); + } + +} diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java new file mode 100644 index 000000000..0b42d8d92 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -0,0 +1,94 @@ +/* + * Copyright 2015 - 2017 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. + * 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.api.resource; + +import org.traccar.Context; +import org.traccar.api.BaseObjectResource; +import org.traccar.database.UsersManager; +import org.traccar.helper.LogAction; +import org.traccar.model.ManagedUser; +import org.traccar.model.User; + +import javax.annotation.security.PermitAll; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Date; +import java.util.Set; + +@Path("users") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class UserResource extends BaseObjectResource { + + public UserResource() { + super(User.class); + } + + @GET + public Collection get(@QueryParam("userId") long userId) throws SQLException { + UsersManager usersManager = Context.getUsersManager(); + Set result = null; + if (Context.getPermissionsManager().getUserAdmin(getUserId())) { + if (userId != 0) { + result = usersManager.getUserItems(userId); + } else { + result = usersManager.getAllItems(); + } + } else if (Context.getPermissionsManager().getUserManager(getUserId())) { + result = usersManager.getManagedItems(getUserId()); + } else { + throw new SecurityException("Admin or manager access required"); + } + return usersManager.getItems(result); + } + + @Override + @PermitAll + @POST + public Response add(User entity) throws SQLException { + if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { + Context.getPermissionsManager().checkUserUpdate(getUserId(), new User(), entity); + if (Context.getPermissionsManager().getUserManager(getUserId())) { + Context.getPermissionsManager().checkUserLimit(getUserId()); + } else { + Context.getPermissionsManager().checkRegistration(getUserId()); + entity.setDeviceLimit(Context.getConfig().getInteger("users.defaultDeviceLimit", -1)); + int expirationDays = Context.getConfig().getInteger("users.defaultExpirationDays"); + if (expirationDays > 0) { + entity.setExpirationTime( + new Date(System.currentTimeMillis() + (long) expirationDays * 24 * 3600 * 1000)); + } + } + } + Context.getUsersManager().addItem(entity); + LogAction.create(getUserId(), entity); + if (Context.getPermissionsManager().getUserManager(getUserId())) { + Context.getDataManager().linkObject(User.class, getUserId(), ManagedUser.class, entity.getId(), true); + LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId()); + } + Context.getUsersManager().refreshUserItems(); + return Response.ok(entity).build(); + } + +} diff --git a/src/main/java/org/traccar/config/Config.java b/src/main/java/org/traccar/config/Config.java new file mode 100644 index 000000000..d8f2a0e99 --- /dev/null +++ b/src/main/java/org/traccar/config/Config.java @@ -0,0 +1,166 @@ +/* + * Copyright 2015 - 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. + * 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.config; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.InvalidPropertiesFormatException; +import java.util.Properties; + +public class Config { + + private final Properties properties = new Properties(); + + private boolean useEnvironmentVariables; + + public Config() { + } + + public Config(String file) throws IOException { + try { + Properties mainProperties = new Properties(); + try (InputStream inputStream = new FileInputStream(file)) { + mainProperties.loadFromXML(inputStream); + } + + String defaultConfigFile = mainProperties.getProperty("config.default"); + if (defaultConfigFile != null) { + try (InputStream inputStream = new FileInputStream(defaultConfigFile)) { + properties.loadFromXML(inputStream); + } + } + + properties.putAll(mainProperties); // override defaults + + useEnvironmentVariables = Boolean.parseBoolean(System.getenv("CONFIG_USE_ENVIRONMENT_VARIABLES")) + || Boolean.parseBoolean(properties.getProperty("config.useEnvironmentVariables")); + } catch (InvalidPropertiesFormatException e) { + throw new RuntimeException("Configuration file is not a valid XML document", e); + } + } + + public boolean hasKey(ConfigKey key) { + return hasKey(key.getKey()); + } + + @Deprecated + public boolean hasKey(String key) { + return useEnvironmentVariables && System.getenv().containsKey(getEnvironmentVariableName(key)) + || properties.containsKey(key); + } + + public String getString(ConfigKey key) { + return getString(key.getKey()); + } + + @Deprecated + public String getString(String key) { + if (useEnvironmentVariables) { + String value = System.getenv(getEnvironmentVariableName(key)); + if (value != null && !value.isEmpty()) { + return value; + } + } + return properties.getProperty(key); + } + + public String getString(ConfigKey key, String defaultValue) { + return getString(key.getKey(), defaultValue); + } + + @Deprecated + public String getString(String key, String defaultValue) { + return hasKey(key) ? getString(key) : defaultValue; + } + + public boolean getBoolean(ConfigKey key) { + return getBoolean(key.getKey()); + } + + @Deprecated + public boolean getBoolean(String key) { + return Boolean.parseBoolean(getString(key)); + } + + public int getInteger(ConfigKey key) { + return getInteger(key.getKey()); + } + + @Deprecated + public int getInteger(String key) { + return getInteger(key, 0); + } + + public int getInteger(ConfigKey key, int defaultValue) { + return getInteger(key.getKey(), defaultValue); + } + + @Deprecated + public int getInteger(String key, int defaultValue) { + return hasKey(key) ? Integer.parseInt(getString(key)) : defaultValue; + } + + public long getLong(ConfigKey key) { + return getLong(key.getKey()); + } + + @Deprecated + public long getLong(String key) { + return getLong(key, 0); + } + + public long getLong(ConfigKey key, long defaultValue) { + return getLong(key.getKey(), defaultValue); + } + + @Deprecated + public long getLong(String key, long defaultValue) { + return hasKey(key) ? Long.parseLong(getString(key)) : defaultValue; + } + + public double getDouble(ConfigKey key) { + return getDouble(key.getKey()); + } + + @Deprecated + public double getDouble(String key) { + return getDouble(key, 0.0); + } + + public double getDouble(ConfigKey key, double defaultValue) { + return getDouble(key.getKey(), defaultValue); + } + + @Deprecated + public double getDouble(String key, double defaultValue) { + return hasKey(key) ? Double.parseDouble(getString(key)) : defaultValue; + } + + public void setString(ConfigKey key, String value) { + setString(key.getKey(), value); + } + + @Deprecated + public void setString(String key, String value) { + properties.put(key, value); + } + + static String getEnvironmentVariableName(String key) { + return key.replaceAll("\\.", "_").replaceAll("(\\p{Lu})", "_$1").toUpperCase(); + } + +} diff --git a/src/main/java/org/traccar/config/ConfigKey.java b/src/main/java/org/traccar/config/ConfigKey.java new file mode 100644 index 000000000..2e54ad392 --- /dev/null +++ b/src/main/java/org/traccar/config/ConfigKey.java @@ -0,0 +1,36 @@ +/* + * Copyright 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. + * 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.config; + +public class ConfigKey { + + private final String key; + private final Class clazz; + + ConfigKey(String key, Class clazz) { + this.key = key; + this.clazz = clazz; + } + + String getKey() { + return key; + } + + Class getValueClass() { + return clazz; + } + +} diff --git a/src/main/java/org/traccar/config/ConfigSuffix.java b/src/main/java/org/traccar/config/ConfigSuffix.java new file mode 100644 index 000000000..149b2cd00 --- /dev/null +++ b/src/main/java/org/traccar/config/ConfigSuffix.java @@ -0,0 +1,28 @@ +/* + * Copyright 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. + * 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.config; + +public class ConfigSuffix extends ConfigKey { + + ConfigSuffix(String key, Class clazz) { + super(key, clazz); + } + + public ConfigKey withPrefix(String prefix) { + return new ConfigKey(prefix + getKey(), getValueClass()); + } + +} diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java new file mode 100644 index 000000000..48cf3e558 --- /dev/null +++ b/src/main/java/org/traccar/config/Keys.java @@ -0,0 +1,356 @@ +/* + * Copyright 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. + * 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.config; + +public final class Keys { + + /** + * Connection timeout value in seconds. Because sometimes there is no way to detect lost TCP connection old + * connections stay in open state. On most systems there is a limit on number of open connection, so this leads to + * problems with establishing new connections when number of devices is high or devices data connections are + * unstable. + */ + public static final ConfigSuffix PROTOCOL_TIMEOUT = new ConfigSuffix( + ".timeout", Integer.class); + + /** + * Server wide connection timeout value in seconds. See protocol timeout for more information. + */ + public static final ConfigKey SERVER_TIMEOUT = new ConfigKey( + "server.timeout", Integer.class); + + /** + * Address for uploading aggregated anonymous usage statistics. Uploaded information is the same you can see on the + * statistics screen in the web app. It does not include any sensitive (e.g. locations). + */ + public static final ConfigKey SERVER_STATISTICS = new ConfigKey( + "server.statistics", Boolean.class); + + /** + * Enable events subsystem. Flag to enable all events handlers. + */ + public static final ConfigKey EVENT_ENABLE = new ConfigKey( + "event.enable", Boolean.class); + + /** + * If true, the event is generated once at the beginning of overspeeding period. + */ + public static final ConfigKey EVENT_OVERSPEED_NOT_REPEAT = new ConfigKey( + "event.overspeed.notRepeat", Boolean.class); + + /** + * Minimal over speed duration to trigger the event. Value in seconds. + */ + public static final ConfigKey EVENT_OVERSPEED_MINIMAL_DURATION = new ConfigKey( + "event.overspeed.minimalDuration", Long.class); + + /** + * Relevant only for geofence speed limits. Use lowest speed limits from all geofences. + */ + public static final ConfigKey EVENT_OVERSPEED_PREFER_LOWEST = new ConfigKey( + "event.overspeed.preferLowest", Boolean.class); + + /** + * Do not generate alert event if same alert was present in last known location. + */ + public static final ConfigKey EVENT_IGNORE_DUPLICATE_ALERTS = new ConfigKey( + "event.ignoreDuplicateAlerts", Boolean.class); + + /** + * List of external handler classes to use in Netty pipeline. + */ + public static final ConfigKey EXTRA_HANDLERS = new ConfigKey( + "extra.handlers", String.class); + + /** + * Enable positions forwarding to other web server. + */ + public static final ConfigKey FORWARD_ENABLE = new ConfigKey( + "forward.enable", Boolean.class); + + /** + * URL to forward positions. Data is passed through URL parameters. For example, {uniqueId} for device identifier, + * {latitude} and {longitude} for coordinates. + */ + public static final ConfigKey FORWARD_URL = new ConfigKey( + "forward.url", String.class); + + /** + * Additional HTTP header, can be used for authorization. + */ + public static final ConfigKey FORWARD_HEADER = new ConfigKey( + "forward.header", String.class); + + /** + * Boolean value to enable forwarding in JSON format. + */ + public static final ConfigKey FORWARD_JSON = new ConfigKey( + "forward.json", Boolean.class); + + /** + * Boolean flag to enable or disable position filtering. + */ + public static final ConfigKey FILTER_ENABLE = new ConfigKey( + "filter.enable", Boolean.class); + + /** + * Filter invalid (valid field is set to false) positions. + */ + public static final ConfigKey FILTER_INVALID = new ConfigKey( + "filter.invalid", Boolean.class); + + /** + * Filter zero coordinates. Zero latitude and longitude are theoretically valid values, but it practice it usually + * indicates invalid GPS data. + */ + public static final ConfigKey FILTER_ZERO = new ConfigKey( + "filter.zero", Boolean.class); + + /** + * Filter duplicate records (duplicates are detected by time value). + */ + public static final ConfigKey FILTER_DUPLICATE = new ConfigKey( + "filter.duplicate", Boolean.class); + + /** + * Filter records with fix time in future. The values is specified in seconds. Records that have fix time more than + * specified number of seconds later than current server time would be filtered out. + */ + public static final ConfigKey FILTER_FUTURE = new ConfigKey( + "filter.future", Long.class); + + /** + * Filter positions with accuracy less than specified value in meters. + */ + public static final ConfigKey FILTER_ACCURACY = new ConfigKey( + "filter.accuracy", Integer.class); + + /** + * Filter cell and wifi locations that are coming from geolocation provider. + */ + public static final ConfigKey FILTER_APPROXIMATE = new ConfigKey( + "filter.approximate", Boolean.class); + + /** + * Filter positions with exactly zero speed values. + */ + public static final ConfigKey FILTER_STATIC = new ConfigKey( + "filter.static", Boolean.class); + + /** + * Filter records by distance. The values is specified in meters. If the new position is less far than this value + * from the last one it gets filtered out. + */ + public static final ConfigKey FILTER_DISTANCE = new ConfigKey( + "filter.distance", Integer.class); + + /** + * Filter records by Maximum Speed value in knots. Can be used to filter jumps to far locations even if they're + * marked as valid. Shouldn't be too low. Start testing with values at about 25000. + */ + public static final ConfigKey FILTER_MAX_SPEED = new ConfigKey( + "filter.maxSpeed", Integer.class); + + /** + * Filter position if time from previous position is less than specified value in seconds. + */ + public static final ConfigKey FILTER_MIN_PERIOD = new ConfigKey( + "filter.minPeriod", Integer.class); + + /** + * Time limit for the filtering in seconds. If the time difference between last position and a new one is more than + * this limit, the new position will not be filtered out. + */ + public static final ConfigKey FILTER_SKIP_LIMIT = new ConfigKey( + "filter.skipLimit", Long.class); + + /** + * Enable attributes skipping. Attribute skipping can be enabled in the config or device attributes. + */ + public static final ConfigKey FILTER_SKIP_ATTRIBUTES_ENABLE = new ConfigKey( + "filter.skipAttributes.enable", Boolean.class); + + /** + * Replaces coordinates with last known if change is less than a 'coordinates.error' meters. Helps to avoid + * coordinates jumps during parking period. + */ + public static final ConfigKey COORDINATES_FILTER = new ConfigKey( + "coordinates.filter", Boolean.class); + + /** + * Distance in meters. Distances below this value gets handled like explained in 'coordinates.filter'. + */ + public static final ConfigKey COORDINATES_MIN_ERROR = new ConfigKey( + "coordinates.minError", Integer.class); + + /** + * Distance in meters. Distances above this value gets handled like explained in 'coordinates.filter', but only if + * Position is also marked as 'invalid'. + */ + public static final ConfigKey COORDINATES_MAX_ERROR = new ConfigKey( + "filter.maxError", Integer.class); + + /** + * Enable to save device IP addresses information. Disabled by default. + */ + public static final ConfigKey PROCESSING_REMOTE_ADDRESS_ENABLE = new ConfigKey( + "processing.remoteAddress.enable", Boolean.class); + + /** + * Enable engine hours calculation on the server side. It uses ignition value to determine engine state. + */ + public static final ConfigKey PROCESSING_ENGINE_HOURS_ENABLE = new ConfigKey( + "processing.engineHours.enable", Boolean.class); + + /** + * Enable copying of missing attributes from last position to the current one. Might be useful if device doesn't + * send some values in every message. + */ + public static final ConfigKey PROCESSING_COPY_ATTRIBUTES_ENABLE = new ConfigKey( + "processing.copyAttributes.enable", Boolean.class); + + /** + * Enable computed attributes processing. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_ENABLE = new ConfigKey( + "processing.computedAttributes.enable", Boolean.class); + + /** + * Enable computed attributes processing. + */ + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new ConfigKey( + "processing.computedAttributes.deviceAttributes", Boolean.class); + + /** + * Boolean flag to enable or disable reverse geocoder. + */ + public static final ConfigKey GEOCODER_ENABLE = new ConfigKey( + "geocoder.enable", Boolean.class); + + /** + * Reverse geocoder type. Check reverse geocoding documentation for more info. By default (if the value is not + * specified) server uses Google API. + */ + public static final ConfigKey GEOCODER_TYPE = new ConfigKey( + "geocoder.type", String.class); + + /** + * Geocoder server URL. Applicable only to Nominatim and Gisgraphy providers. + */ + public static final ConfigKey GEOCODER_URL = new ConfigKey( + "geocoder.url", String.class); + + /** + * App id for use with Here provider. + */ + public static final ConfigKey GEOCODER_ID = new ConfigKey( + "geocoder.id", String.class); + + /** + * Provider API key. Most providers require API keys. + */ + public static final ConfigKey GEOCODER_KEY = new ConfigKey( + "geocoder.key", String.class); + + /** + * Language parameter for providers that support localization (e.g. Google and Nominatim). + */ + public static final ConfigKey GEOCODER_LANGUAGE = new ConfigKey( + "geocoder.language", String.class); + + /** + * Address format string. Default value is %h %r, %t, %s, %c. See AddressFormat for more info. + */ + public static final ConfigKey GEOCODER_FORMAT = new ConfigKey( + "geocoder.format", String.class); + + /** + * Cache size for geocoding results. + */ + public static final ConfigKey GEOCODER_CACHE_SIZE = new ConfigKey( + "geocoder.cacheSize", Integer.class); + + /** + * Disable automatic reverse geocoding requests for all positions. + */ + public static final ConfigKey GEOCODER_IGNORE_POSITIONS = new ConfigKey( + "geocoder.ignorePositions", Boolean.class); + + /** + * Boolean flag to apply reverse geocoding to invalid positions. + */ + public static final ConfigKey GEOCODER_PROCESS_INVALID_POSITIONS = new ConfigKey( + "geocoder.processInvalidPositions", Boolean.class); + + /** + * Optional parameter to specify minimum distance for new reverse geocoding request. If distance is less than + * specified value (in meters), then Traccar will reuse last known address. + */ + public static final ConfigKey GEOCODER_REUSE_DISTANCE = new ConfigKey( + "geocoder.reuseDistance", Integer.class); + + /** + * Boolean flag to enable LBS location resolution. Some devices send cell towers information and WiFi point when GPS + * location is not available. Traccar can determine coordinates based on that information using third party + * services. Default value is false. + */ + public static final ConfigKey GEOLOCATION_ENABLE = new ConfigKey( + "geolocation.enable", Boolean.class); + + /** + * Provider to use for LBS location. Available options: google, mozilla and opencellid. By default opencellid is + * used. You have to supply a key that you get from corresponding provider. For more information see LBS geolocation + * documentation. + */ + public static final ConfigKey GEOLOCATION_TYPE = new ConfigKey( + "geolocation.type", String.class); + + /** + * Geolocation provider API URL address. Not required for most providers. + */ + public static final ConfigKey GEOLOCATION_URL = new ConfigKey( + "geolocation.url", String.class); + + /** + * Provider API key. OpenCellID service requires API key. + */ + public static final ConfigKey GEOLOCATION_KEY = new ConfigKey( + "geolocation.key", String.class); + + /** + * Boolean flag to apply geolocation to invalid positions. + */ + public static final ConfigKey GEOLOCATION_PROCESS_INVALID_POSITIONS = new ConfigKey( + "geolocation.processInvalidPositions", Boolean.class); + + /** + * Override latitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can be + * N for North or S for South. + */ + public static final ConfigKey LOCATION_LATITUDE_HEMISPHERE = new ConfigKey( + "location.latitudeHemisphere", Boolean.class); + + /** + * Override longitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can + * be E for East or W for West. + */ + public static final ConfigKey LOCATION_LONGITUDE_HEMISPHERE = new ConfigKey( + "location.longitudeHemisphere", Boolean.class); + + private Keys() { + } + +} diff --git a/src/main/java/org/traccar/database/ActiveDevice.java b/src/main/java/org/traccar/database/ActiveDevice.java new file mode 100644 index 000000000..207fc454b --- /dev/null +++ b/src/main/java/org/traccar/database/ActiveDevice.java @@ -0,0 +1,55 @@ +/* + * 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. + * 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.database; + +import io.netty.channel.Channel; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.model.Command; + +import java.net.SocketAddress; + +public class ActiveDevice { + + private final long deviceId; + private final Protocol protocol; + private final Channel channel; + private final SocketAddress remoteAddress; + + public ActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) { + this.deviceId = deviceId; + this.protocol = protocol; + this.channel = channel; + this.remoteAddress = remoteAddress; + } + + public Channel getChannel() { + return channel; + } + + public long getDeviceId() { + return deviceId; + } + + public void sendCommand(Command command) { + protocol.sendDataCommand(this, command); + } + + public void write(Object message) { + channel.writeAndFlush(new NetworkMessage(message, remoteAddress)); + } + +} diff --git a/src/main/java/org/traccar/database/AttributesManager.java b/src/main/java/org/traccar/database/AttributesManager.java new file mode 100644 index 000000000..28816645a --- /dev/null +++ b/src/main/java/org/traccar/database/AttributesManager.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import org.traccar.model.Attribute; + +public class AttributesManager extends ExtendedObjectManager { + + public AttributesManager(DataManager dataManager) { + super(dataManager, Attribute.class); + } + + @Override + public void updateCachedItem(Attribute attribute) { + Attribute cachedAttribute = getById(attribute.getId()); + cachedAttribute.setDescription(attribute.getDescription()); + cachedAttribute.setAttribute(attribute.getAttribute()); + cachedAttribute.setExpression(attribute.getExpression()); + cachedAttribute.setType(attribute.getType()); + } + +} diff --git a/src/main/java/org/traccar/database/BaseObjectManager.java b/src/main/java/org/traccar/database/BaseObjectManager.java new file mode 100644 index 000000000..8bf9ef860 --- /dev/null +++ b/src/main/java/org/traccar/database/BaseObjectManager.java @@ -0,0 +1,127 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.model.BaseModel; + +public class BaseObjectManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(BaseObjectManager.class); + + private final DataManager dataManager; + + private Map items; + private Class baseClass; + + protected BaseObjectManager(DataManager dataManager, Class baseClass) { + this.dataManager = dataManager; + this.baseClass = baseClass; + refreshItems(); + } + + protected final DataManager getDataManager() { + return dataManager; + } + + protected final Class getBaseClass() { + return baseClass; + } + + public T getById(long itemId) { + return items.get(itemId); + } + + public void refreshItems() { + if (dataManager != null) { + try { + Collection databaseItems = dataManager.getObjects(baseClass); + if (items == null) { + items = new ConcurrentHashMap<>(databaseItems.size()); + } + Set databaseItemIds = new HashSet<>(); + for (T item : databaseItems) { + databaseItemIds.add(item.getId()); + if (items.containsKey(item.getId())) { + updateCachedItem(item); + } else { + addNewItem(item); + } + } + for (Long cachedItemId : items.keySet()) { + if (!databaseItemIds.contains(cachedItemId)) { + removeCachedItem(cachedItemId); + } + } + } catch (SQLException error) { + LOGGER.warn("Error refreshing items", error); + } + } + } + + protected void addNewItem(T item) { + items.put(item.getId(), item); + } + + public void addItem(T item) throws SQLException { + dataManager.addObject(item); + addNewItem(item); + } + + protected void updateCachedItem(T item) { + items.put(item.getId(), item); + } + + public void updateItem(T item) throws SQLException { + dataManager.updateObject(item); + updateCachedItem(item); + } + + protected void removeCachedItem(long itemId) { + items.remove(itemId); + } + + public void removeItem(long itemId) throws SQLException { + BaseModel item = getById(itemId); + if (item != null) { + dataManager.removeObject(baseClass, itemId); + removeCachedItem(itemId); + } + } + + public final Collection getItems(Set itemIds) { + Collection result = new LinkedList<>(); + for (long itemId : itemIds) { + result.add(getById(itemId)); + } + return result; + } + + public Set getAllItems() { + return items.keySet(); + } + +} diff --git a/src/main/java/org/traccar/database/CalendarManager.java b/src/main/java/org/traccar/database/CalendarManager.java new file mode 100644 index 000000000..44ced1082 --- /dev/null +++ b/src/main/java/org/traccar/database/CalendarManager.java @@ -0,0 +1,27 @@ +/* + * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import org.traccar.model.Calendar; + +public class CalendarManager extends SimpleObjectManager { + + public CalendarManager(DataManager dataManager) { + super(dataManager, Calendar.class); + } + +} diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java new file mode 100644 index 000000000..d6fdd66ca --- /dev/null +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -0,0 +1,157 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseProtocol; +import org.traccar.Context; +import org.traccar.model.Command; +import org.traccar.model.Typed; +import org.traccar.model.Position; + +public class CommandsManager extends ExtendedObjectManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(CommandsManager.class); + + private final Map> deviceQueues = new ConcurrentHashMap<>(); + + private boolean queueing; + + public CommandsManager(DataManager dataManager, boolean queueing) { + super(dataManager, Command.class); + this.queueing = queueing; + } + + public boolean checkDeviceCommand(long deviceId, long commandId) { + return !getAllDeviceItems(deviceId).contains(commandId); + } + + public boolean sendCommand(Command command) throws Exception { + long deviceId = command.getDeviceId(); + if (command.getId() != 0) { + command = getById(command.getId()).clone(); + command.setDeviceId(deviceId); + } + if (command.getTextChannel()) { + Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); + String phone = Context.getIdentityManager().getById(deviceId).getPhone(); + if (lastPosition != null) { + BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); + protocol.sendTextCommand(phone, command); + } else if (command.getType().equals(Command.TYPE_CUSTOM)) { + if (Context.getSmsManager() != null) { + Context.getSmsManager().sendMessageSync(phone, command.getString(Command.KEY_DATA), true); + } else { + throw new RuntimeException("SMS is not enabled"); + } + } else { + throw new RuntimeException("Command " + command.getType() + " is not supported"); + } + } else { + ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId); + if (activeDevice != null) { + activeDevice.sendCommand(command); + } else if (!queueing) { + throw new RuntimeException("Device is not online"); + } else { + getDeviceQueue(deviceId).add(command); + return false; + } + } + return true; + } + + public Collection getSupportedCommands(long deviceId) { + List result = new ArrayList<>(); + Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); + for (long commandId : getAllDeviceItems(deviceId)) { + Command command = getById(commandId); + if (lastPosition != null) { + BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); + if (command.getTextChannel() && protocol.getSupportedTextCommands().contains(command.getType()) + || !command.getTextChannel() + && protocol.getSupportedDataCommands().contains(command.getType())) { + result.add(commandId); + } + } else if (command.getType().equals(Command.TYPE_CUSTOM)) { + result.add(commandId); + } + } + return result; + } + + public Collection getCommandTypes(long deviceId, boolean textChannel) { + List result = new ArrayList<>(); + Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); + if (lastPosition != null) { + BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); + Collection commands; + commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands(); + for (String commandKey : commands) { + result.add(new Typed(commandKey)); + } + } else { + result.add(new Typed(Command.TYPE_CUSTOM)); + } + return result; + } + + public Collection getAllCommandTypes() { + List result = new ArrayList<>(); + Field[] fields = Command.class.getDeclaredFields(); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) { + try { + result.add(new Typed(field.get(null).toString())); + } catch (IllegalArgumentException | IllegalAccessException error) { + LOGGER.warn("Get command types error", error); + } + } + } + return result; + } + + private Queue getDeviceQueue(long deviceId) { + if (!deviceQueues.containsKey(deviceId)) { + deviceQueues.put(deviceId, new ConcurrentLinkedQueue()); + } + return deviceQueues.get(deviceId); + } + + public void sendQueuedCommands(ActiveDevice activeDevice) { + Queue deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); + if (deviceQueue != null) { + Command command = deviceQueue.poll(); + while (command != null) { + activeDevice.sendCommand(command); + command = deviceQueue.poll(); + } + } + } + +} diff --git a/src/main/java/org/traccar/database/ConnectionManager.java b/src/main/java/org/traccar/database/ConnectionManager.java new file mode 100644 index 000000000..8bae1ea93 --- /dev/null +++ b/src/main/java/org/traccar/database/ConnectionManager.java @@ -0,0 +1,218 @@ +/* + * 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. + * 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.database; + +import io.netty.channel.Channel; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.GlobalTimer; +import org.traccar.Main; +import org.traccar.Protocol; +import org.traccar.handler.events.MotionEventHandler; +import org.traccar.handler.events.OverspeedEventHandler; +import org.traccar.model.Device; +import org.traccar.model.DeviceState; +import org.traccar.model.Event; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.sql.SQLException; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +public class ConnectionManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class); + + private static final long DEFAULT_TIMEOUT = 600; + + private final long deviceTimeout; + private final boolean enableStatusEvents; + private final boolean updateDeviceState; + + private final Map activeDevices = new ConcurrentHashMap<>(); + private final Map> listeners = new ConcurrentHashMap<>(); + private final Map timeouts = new ConcurrentHashMap<>(); + + public ConnectionManager() { + deviceTimeout = Context.getConfig().getLong("status.timeout", DEFAULT_TIMEOUT) * 1000; + enableStatusEvents = Context.getConfig().getBoolean("event.enable"); + updateDeviceState = Context.getConfig().getBoolean("status.updateDeviceState"); + } + + public void addActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) { + activeDevices.put(deviceId, new ActiveDevice(deviceId, protocol, channel, remoteAddress)); + } + + public void removeActiveDevice(Channel channel) { + for (ActiveDevice activeDevice : activeDevices.values()) { + if (activeDevice.getChannel() == channel) { + updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, null); + activeDevices.remove(activeDevice.getDeviceId()); + break; + } + } + } + + public ActiveDevice getActiveDevice(long deviceId) { + return activeDevices.get(deviceId); + } + + public void updateDevice(final long deviceId, String status, Date time) { + Device device = Context.getIdentityManager().getById(deviceId); + if (device == null) { + return; + } + + String oldStatus = device.getStatus(); + device.setStatus(status); + + if (enableStatusEvents && !status.equals(oldStatus)) { + String eventType; + Map events = new HashMap<>(); + switch (status) { + case Device.STATUS_ONLINE: + eventType = Event.TYPE_DEVICE_ONLINE; + break; + case Device.STATUS_UNKNOWN: + eventType = Event.TYPE_DEVICE_UNKNOWN; + if (updateDeviceState) { + events.putAll(updateDeviceState(deviceId)); + } + break; + default: + eventType = Event.TYPE_DEVICE_OFFLINE; + if (updateDeviceState) { + events.putAll(updateDeviceState(deviceId)); + } + break; + } + events.put(new Event(eventType, deviceId), null); + Context.getNotificationManager().updateEvents(events); + } + + Timeout timeout = timeouts.remove(deviceId); + if (timeout != null) { + timeout.cancel(); + } + + if (time != null) { + device.setLastUpdate(time); + } + + if (status.equals(Device.STATUS_ONLINE)) { + timeouts.put(deviceId, GlobalTimer.getTimer().newTimeout(new TimerTask() { + @Override + public void run(Timeout timeout) { + if (!timeout.isCancelled()) { + updateDevice(deviceId, Device.STATUS_UNKNOWN, null); + } + } + }, deviceTimeout, TimeUnit.MILLISECONDS)); + } + + try { + Context.getDeviceManager().updateDeviceStatus(device); + } catch (SQLException error) { + LOGGER.warn("Update device status error", error); + } + + updateDevice(device); + + if (status.equals(Device.STATUS_ONLINE) && !oldStatus.equals(Device.STATUS_ONLINE)) { + Context.getCommandsManager().sendQueuedCommands(getActiveDevice(deviceId)); + } + } + + public Map updateDeviceState(long deviceId) { + DeviceState deviceState = Context.getDeviceManager().getDeviceState(deviceId); + Map result = new HashMap<>(); + + Map event = Main.getInjector() + .getInstance(MotionEventHandler.class).updateMotionState(deviceState); + if (event != null) { + result.putAll(event); + } + + event = Main.getInjector().getInstance(OverspeedEventHandler.class) + .updateOverspeedState(deviceState, Context.getDeviceManager(). + lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, false)); + if (event != null) { + result.putAll(event); + } + + return result; + } + + public synchronized void updateDevice(Device device) { + for (long userId : Context.getPermissionsManager().getDeviceUsers(device.getId())) { + if (listeners.containsKey(userId)) { + for (UpdateListener listener : listeners.get(userId)) { + listener.onUpdateDevice(device); + } + } + } + } + + public synchronized void updatePosition(Position position) { + long deviceId = position.getDeviceId(); + + for (long userId : Context.getPermissionsManager().getDeviceUsers(deviceId)) { + if (listeners.containsKey(userId)) { + for (UpdateListener listener : listeners.get(userId)) { + listener.onUpdatePosition(position); + } + } + } + } + + public synchronized void updateEvent(long userId, Event event) { + if (listeners.containsKey(userId)) { + for (UpdateListener listener : listeners.get(userId)) { + listener.onUpdateEvent(event); + } + } + } + + public interface UpdateListener { + void onUpdateDevice(Device device); + void onUpdatePosition(Position position); + void onUpdateEvent(Event event); + } + + public synchronized void addListener(long userId, UpdateListener listener) { + if (!listeners.containsKey(userId)) { + listeners.put(userId, new HashSet()); + } + listeners.get(userId).add(listener); + } + + public synchronized void removeListener(long userId, UpdateListener listener) { + if (!listeners.containsKey(userId)) { + listeners.put(userId, new HashSet()); + } + listeners.get(userId).remove(listener); + } + +} diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java new file mode 100644 index 000000000..8e9071736 --- /dev/null +++ b/src/main/java/org/traccar/database/DataManager.java @@ -0,0 +1,478 @@ +/* + * Copyright 2012 - 2017 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. + * 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.database; + +import java.beans.Introspector; +import java.io.File; +import java.lang.reflect.Method; +import java.net.URL; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import javax.naming.InitialContext; +import javax.sql.DataSource; + +import liquibase.Contexts; +import liquibase.Liquibase; +import liquibase.database.Database; +import liquibase.database.DatabaseFactory; +import liquibase.exception.LiquibaseException; +import liquibase.resource.FileSystemResourceAccessor; +import liquibase.resource.ResourceAccessor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.Context; +import org.traccar.helper.DateUtil; +import org.traccar.model.Attribute; +import org.traccar.model.Device; +import org.traccar.model.Driver; +import org.traccar.model.Event; +import org.traccar.model.Geofence; +import org.traccar.model.Group; +import org.traccar.model.Maintenance; +import org.traccar.model.ManagedUser; +import org.traccar.model.Notification; +import org.traccar.model.Permission; +import org.traccar.model.BaseModel; +import org.traccar.model.Calendar; +import org.traccar.model.Command; +import org.traccar.model.Position; +import org.traccar.model.Server; +import org.traccar.model.Statistics; +import org.traccar.model.User; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +public class DataManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataManager.class); + + public static final String ACTION_SELECT_ALL = "selectAll"; + public static final String ACTION_SELECT = "select"; + public static final String ACTION_INSERT = "insert"; + public static final String ACTION_UPDATE = "update"; + public static final String ACTION_DELETE = "delete"; + + private final Config config; + + private DataSource dataSource; + + private boolean generateQueries; + + private boolean forceLdap; + + public DataManager(Config config) throws Exception { + this.config = config; + + forceLdap = config.getBoolean("ldap.force"); + + initDatabase(); + initDatabaseSchema(); + } + + private void initDatabase() throws Exception { + + String jndiName = config.getString("database.jndi"); + + if (jndiName != null) { + + dataSource = (DataSource) new InitialContext().lookup(jndiName); + + } else { + + String driverFile = config.getString("database.driverFile"); + if (driverFile != null) { + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + try { + Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class); + method.setAccessible(true); + method.invoke(classLoader, new File(driverFile).toURI().toURL()); + } catch (NoSuchMethodException e) { + Method method = classLoader.getClass() + .getDeclaredMethod("appendToClassPathForInstrumentation", String.class); + method.setAccessible(true); + method.invoke(classLoader, driverFile); + } + } + + String driver = config.getString("database.driver"); + if (driver != null) { + Class.forName(driver); + } + + HikariConfig hikariConfig = new HikariConfig(); + hikariConfig.setDriverClassName(config.getString("database.driver")); + hikariConfig.setJdbcUrl(config.getString("database.url")); + hikariConfig.setUsername(config.getString("database.user")); + hikariConfig.setPassword(config.getString("database.password")); + hikariConfig.setConnectionInitSql(config.getString("database.checkConnection", "SELECT 1")); + hikariConfig.setIdleTimeout(600000); + + int maxPoolSize = config.getInteger("database.maxPoolSize"); + + if (maxPoolSize != 0) { + hikariConfig.setMaximumPoolSize(maxPoolSize); + } + + generateQueries = config.getBoolean("database.generateQueries"); + + dataSource = new HikariDataSource(hikariConfig); + + } + } + + public static String constructObjectQuery(String action, Class clazz, boolean extended) { + switch (action) { + case ACTION_INSERT: + case ACTION_UPDATE: + StringBuilder result = new StringBuilder(); + StringBuilder fields = new StringBuilder(); + StringBuilder values = new StringBuilder(); + + Set methods = new HashSet<>(Arrays.asList(clazz.getMethods())); + methods.removeAll(Arrays.asList(Object.class.getMethods())); + methods.removeAll(Arrays.asList(BaseModel.class.getMethods())); + for (Method method : methods) { + boolean skip; + if (extended) { + skip = !method.isAnnotationPresent(QueryExtended.class); + } else { + skip = method.isAnnotationPresent(QueryIgnore.class) + || method.isAnnotationPresent(QueryExtended.class) && !action.equals(ACTION_INSERT); + } + if (!skip && method.getName().startsWith("get") && method.getParameterTypes().length == 0) { + String name = Introspector.decapitalize(method.getName().substring(3)); + if (action.equals(ACTION_INSERT)) { + fields.append(name).append(", "); + values.append(":").append(name).append(", "); + } else { + fields.append(name).append(" = :").append(name).append(", "); + } + } + } + fields.setLength(fields.length() - 2); + if (action.equals(ACTION_INSERT)) { + values.setLength(values.length() - 2); + result.append("INSERT INTO ").append(getObjectsTableName(clazz)).append(" ("); + result.append(fields).append(") "); + result.append("VALUES (").append(values).append(")"); + } else { + result.append("UPDATE ").append(getObjectsTableName(clazz)).append(" SET "); + result.append(fields); + result.append(" WHERE id = :id"); + } + return result.toString(); + case ACTION_SELECT_ALL: + return "SELECT * FROM " + getObjectsTableName(clazz); + case ACTION_SELECT: + return "SELECT * FROM " + getObjectsTableName(clazz) + " WHERE id = :id"; + case ACTION_DELETE: + return "DELETE FROM " + getObjectsTableName(clazz) + " WHERE id = :id"; + default: + throw new IllegalArgumentException("Unknown action"); + } + } + + public static String constructPermissionQuery(String action, Class owner, Class property) { + switch (action) { + case ACTION_SELECT_ALL: + return "SELECT " + makeNameId(owner) + ", " + makeNameId(property) + " FROM " + + getPermissionsTableName(owner, property); + case ACTION_INSERT: + return "INSERT INTO " + getPermissionsTableName(owner, property) + + " (" + makeNameId(owner) + ", " + makeNameId(property) + ") VALUES (:" + + makeNameId(owner) + ", :" + makeNameId(property) + ")"; + case ACTION_DELETE: + return "DELETE FROM " + getPermissionsTableName(owner, property) + + " WHERE " + makeNameId(owner) + " = :" + makeNameId(owner) + + " AND " + makeNameId(property) + " = :" + makeNameId(property); + default: + throw new IllegalArgumentException("Unknown action"); + } + } + + private String getQuery(String key) { + String query = config.getString(key); + if (query == null) { + LOGGER.info("Query not provided: " + key); + } + return query; + } + + public String getQuery(String action, Class clazz) { + return getQuery(action, clazz, false); + } + + public String getQuery(String action, Class clazz, boolean extended) { + String queryName; + if (action.equals(ACTION_SELECT_ALL)) { + queryName = "database.select" + clazz.getSimpleName() + "s"; + } else { + queryName = "database." + action.toLowerCase() + clazz.getSimpleName(); + if (extended) { + queryName += "Extended"; + } + } + String query = config.getString(queryName); + if (query == null) { + if (generateQueries) { + query = constructObjectQuery(action, clazz, extended); + config.setString(queryName, query); + } else { + LOGGER.info("Query not provided: " + queryName); + } + } + + return query; + } + + public String getQuery(String action, Class owner, Class property) { + String queryName; + switch (action) { + case ACTION_SELECT_ALL: + queryName = "database.select" + owner.getSimpleName() + property.getSimpleName() + "s"; + break; + case ACTION_INSERT: + queryName = "database.link" + owner.getSimpleName() + property.getSimpleName(); + break; + default: + queryName = "database.unlink" + owner.getSimpleName() + property.getSimpleName(); + break; + } + String query = config.getString(queryName); + if (query == null) { + if (generateQueries) { + query = constructPermissionQuery(action, owner, + property.equals(User.class) ? ManagedUser.class : property); + config.setString(queryName, query); + } else { + LOGGER.info("Query not provided: " + queryName); + } + } + + return query; + } + + private static String getPermissionsTableName(Class owner, Class property) { + String propertyName = property.getSimpleName(); + if (propertyName.equals("ManagedUser")) { + propertyName = "User"; + } + return "tc_" + Introspector.decapitalize(owner.getSimpleName()) + + "_" + Introspector.decapitalize(propertyName); + } + + private static String getObjectsTableName(Class clazz) { + String result = "tc_" + Introspector.decapitalize(clazz.getSimpleName()); + // Add "s" ending if object name is not plural already + if (!result.endsWith("s")) { + result += "s"; + } + return result; + } + + private void initDatabaseSchema() throws SQLException, LiquibaseException { + + if (config.hasKey("database.changelog")) { + + ResourceAccessor resourceAccessor = new FileSystemResourceAccessor(); + + Database database = DatabaseFactory.getInstance().openDatabase( + config.getString("database.url"), + config.getString("database.user"), + config.getString("database.password"), + config.getString("database.driver"), + null, null, null, resourceAccessor); + + Liquibase liquibase = new Liquibase( + config.getString("database.changelog"), resourceAccessor, database); + + liquibase.clearCheckSums(); + + liquibase.update(new Contexts()); + } + } + + public User login(String email, String password) throws SQLException { + User user = QueryBuilder.create(dataSource, getQuery("database.loginUser")) + .setString("email", email.trim()) + .executeQuerySingle(User.class); + LdapProvider ldapProvider = Context.getLdapProvider(); + if (user != null) { + if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) + || !forceLdap && user.isPasswordValid(password)) { + return user; + } + } else { + if (ldapProvider != null && ldapProvider.login(email, password)) { + user = ldapProvider.getUser(email); + Context.getUsersManager().addItem(user); + return user; + } + } + return null; + } + + public void updateDeviceStatus(Device device) throws SQLException { + QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, Device.class, true)) + .setObject(device) + .executeUpdate(); + } + + public Collection getPositions(long deviceId, Date from, Date to) throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectPositions")) + .setLong("deviceId", deviceId) + .setDate("from", from) + .setDate("to", to) + .executeQuery(Position.class); + } + + public void updateLatestPosition(Position position) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.updateLatestPosition")) + .setDate("now", new Date()) + .setObject(position) + .executeUpdate(); + } + + public Collection getLatestPositions() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectLatestPositions")) + .executeQuery(Position.class); + } + + public void clearHistory() throws SQLException { + long historyDays = config.getInteger("database.historyDays"); + if (historyDays != 0) { + Date timeLimit = new Date(System.currentTimeMillis() - historyDays * 24 * 3600 * 1000); + LOGGER.info("Clearing history earlier than " + DateUtil.formatDate(timeLimit, false)); + QueryBuilder.create(dataSource, getQuery("database.deletePositions")) + .setDate("serverTime", timeLimit) + .executeUpdate(); + QueryBuilder.create(dataSource, getQuery("database.deleteEvents")) + .setDate("serverTime", timeLimit) + .executeUpdate(); + } + } + + public Server getServer() throws SQLException { + return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, Server.class)) + .executeQuerySingle(Server.class); + } + + public Collection getEvents(long deviceId, Date from, Date to) throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectEvents")) + .setLong("deviceId", deviceId) + .setDate("from", from) + .setDate("to", to) + .executeQuery(Event.class); + } + + public Collection getStatistics(Date from, Date to) throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectStatistics")) + .setDate("from", from) + .setDate("to", to) + .executeQuery(Statistics.class); + } + + public static Class getClassByName(String name) throws ClassNotFoundException { + switch (name.toLowerCase().replace("id", "")) { + case "device": + return Device.class; + case "group": + return Group.class; + case "user": + return User.class; + case "manageduser": + return ManagedUser.class; + case "geofence": + return Geofence.class; + case "driver": + return Driver.class; + case "attribute": + return Attribute.class; + case "calendar": + return Calendar.class; + case "command": + return Command.class; + case "maintenance": + return Maintenance.class; + case "notification": + return Notification.class; + default: + throw new ClassNotFoundException(); + } + } + + private static String makeNameId(Class clazz) { + String name = clazz.getSimpleName(); + return Introspector.decapitalize(name) + (!name.contains("Id") ? "Id" : ""); + } + + public Collection getPermissions(Class owner, Class property) + throws SQLException, ClassNotFoundException { + return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, owner, property)) + .executePermissionsQuery(); + } + + public void linkObject(Class owner, long ownerId, Class property, long propertyId, boolean link) + throws SQLException { + QueryBuilder.create(dataSource, getQuery(link ? ACTION_INSERT : ACTION_DELETE, owner, property)) + .setLong(makeNameId(owner), ownerId) + .setLong(makeNameId(property), propertyId) + .executeUpdate(); + } + + public T getObject(Class clazz, long entityId) throws SQLException { + return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT, clazz)) + .setLong("id", entityId) + .executeQuerySingle(clazz); + } + + public Collection getObjects(Class clazz) throws SQLException { + return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, clazz)) + .executeQuery(clazz); + } + + public void addObject(BaseModel entity) throws SQLException { + entity.setId(QueryBuilder.create(dataSource, getQuery(ACTION_INSERT, entity.getClass()), true) + .setObject(entity) + .executeUpdate()); + } + + public void updateObject(BaseModel entity) throws SQLException { + QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, entity.getClass())) + .setObject(entity) + .executeUpdate(); + if (entity instanceof User && ((User) entity).getHashedPassword() != null) { + QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, User.class, true)) + .setObject(entity) + .executeUpdate(); + } + } + + public void removeObject(Class clazz, long entityId) throws SQLException { + QueryBuilder.create(dataSource, getQuery(ACTION_DELETE, clazz)) + .setLong("id", entityId) + .executeUpdate(); + } + +} diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java new file mode 100644 index 000000000..de4607d1f --- /dev/null +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -0,0 +1,419 @@ +/* + * Copyright 2016 - 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. + * 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.database; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.DeviceState; +import org.traccar.model.DeviceAccumulators; +import org.traccar.model.Group; +import org.traccar.model.Position; +import org.traccar.model.Server; + +public class DeviceManager extends BaseObjectManager implements IdentityManager, ManagableObjects { + + private static final Logger LOGGER = LoggerFactory.getLogger(DeviceManager.class); + + public static final long DEFAULT_REFRESH_DELAY = 300; + + private final Config config; + private final long dataRefreshDelay; + private boolean lookupGroupsAttribute; + + private Map devicesByUniqueId; + private Map devicesByPhone; + private AtomicLong devicesLastUpdate = new AtomicLong(); + + private final Map positions = new ConcurrentHashMap<>(); + + private final Map deviceStates = new ConcurrentHashMap<>(); + + public DeviceManager(DataManager dataManager) { + super(dataManager, Device.class); + this.config = Context.getConfig(); + if (devicesByPhone == null) { + devicesByPhone = new ConcurrentHashMap<>(); + } + if (devicesByUniqueId == null) { + devicesByUniqueId = new ConcurrentHashMap<>(); + } + dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000; + lookupGroupsAttribute = config.getBoolean("deviceManager.lookupGroupsAttribute"); + refreshLastPositions(); + } + + @Override + public long addUnknownDevice(String uniqueId) { + Device device = new Device(); + device.setName(uniqueId); + device.setUniqueId(uniqueId); + device.setCategory(Context.getConfig().getString("database.registerUnknown.defaultCategory")); + + long defaultGroupId = Context.getConfig().getLong("database.registerUnknown.defaultGroupId"); + if (defaultGroupId != 0) { + device.setGroupId(defaultGroupId); + } + + try { + addItem(device); + + LOGGER.info("Automatically registered device " + uniqueId); + + if (defaultGroupId != 0) { + Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); + Context.getPermissionsManager().refreshAllExtendedPermissions(); + } + + return device.getId(); + } catch (SQLException e) { + LOGGER.warn("Automatic device registration error", e); + return 0; + } + } + + public void updateDeviceCache(boolean force) throws SQLException { + long lastUpdate = devicesLastUpdate.get(); + if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) + && devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { + refreshItems(); + } + } + + @Override + public Device getByUniqueId(String uniqueId) throws SQLException { + boolean forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); + + updateDeviceCache(forceUpdate); + + return devicesByUniqueId.get(uniqueId); + } + + public Device getDeviceByPhone(String phone) { + return devicesByPhone.get(phone); + } + + @Override + public Set getAllItems() { + Set result = super.getAllItems(); + if (result.isEmpty()) { + try { + updateDeviceCache(true); + } catch (SQLException e) { + LOGGER.warn("Update device cache error", e); + } + result = super.getAllItems(); + } + return result; + } + + public Collection getAllDevices() { + return getItems(getAllItems()); + } + + public Set getAllUserItems(long userId) { + return Context.getPermissionsManager().getDevicePermissions(userId); + } + + @Override + public Set getUserItems(long userId) { + if (Context.getPermissionsManager() != null) { + Set result = new HashSet<>(); + for (long deviceId : Context.getPermissionsManager().getDevicePermissions(userId)) { + Device device = getById(deviceId); + if (device != null && !device.getDisabled()) { + result.add(deviceId); + } + } + return result; + } else { + return new HashSet<>(); + } + } + + public Set getAllManagedItems(long userId) { + Set result = new HashSet<>(); + result.addAll(getAllUserItems(userId)); + for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { + result.addAll(getAllUserItems(managedUserId)); + } + return result; + } + + @Override + public Set getManagedItems(long userId) { + Set result = new HashSet<>(); + result.addAll(getUserItems(userId)); + for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { + result.addAll(getUserItems(managedUserId)); + } + return result; + } + + private void putUniqueDeviceId(Device device) { + if (devicesByUniqueId == null) { + devicesByUniqueId = new ConcurrentHashMap<>(getAllItems().size()); + } + devicesByUniqueId.put(device.getUniqueId(), device); + } + + private void putPhone(Device device) { + if (devicesByPhone == null) { + devicesByPhone = new ConcurrentHashMap<>(getAllItems().size()); + } + devicesByPhone.put(device.getPhone(), device); + } + + @Override + protected void addNewItem(Device device) { + super.addNewItem(device); + putUniqueDeviceId(device); + if (device.getPhone() != null && !device.getPhone().isEmpty()) { + putPhone(device); + } + if (Context.getGeofenceManager() != null) { + Position lastPosition = getLastPosition(device.getId()); + if (lastPosition != null) { + device.setGeofenceIds(Context.getGeofenceManager().getCurrentDeviceGeofences(lastPosition)); + } + } + } + + @Override + protected void updateCachedItem(Device device) { + Device cachedDevice = getById(device.getId()); + cachedDevice.setName(device.getName()); + cachedDevice.setGroupId(device.getGroupId()); + cachedDevice.setCategory(device.getCategory()); + cachedDevice.setContact(device.getContact()); + cachedDevice.setModel(device.getModel()); + cachedDevice.setDisabled(device.getDisabled()); + cachedDevice.setAttributes(device.getAttributes()); + if (!device.getUniqueId().equals(cachedDevice.getUniqueId())) { + devicesByUniqueId.remove(cachedDevice.getUniqueId()); + cachedDevice.setUniqueId(device.getUniqueId()); + putUniqueDeviceId(cachedDevice); + } + if (device.getPhone() != null && !device.getPhone().isEmpty() + && !device.getPhone().equals(cachedDevice.getPhone())) { + String phone = cachedDevice.getPhone(); + if (phone != null && !phone.isEmpty()) { + devicesByPhone.remove(phone); + } + cachedDevice.setPhone(device.getPhone()); + putPhone(cachedDevice); + } + } + + @Override + protected void removeCachedItem(long deviceId) { + Device cachedDevice = getById(deviceId); + if (cachedDevice != null) { + String deviceUniqueId = cachedDevice.getUniqueId(); + String phone = cachedDevice.getPhone(); + super.removeCachedItem(deviceId); + devicesByUniqueId.remove(deviceUniqueId); + if (phone != null && !phone.isEmpty()) { + devicesByPhone.remove(phone); + } + } + positions.remove(deviceId); + } + + public void updateDeviceStatus(Device device) throws SQLException { + getDataManager().updateDeviceStatus(device); + Device cachedDevice = getById(device.getId()); + if (cachedDevice != null) { + cachedDevice.setStatus(device.getStatus()); + } + } + + private void refreshLastPositions() { + if (getDataManager() != null) { + try { + for (Position position : getDataManager().getLatestPositions()) { + positions.put(position.getDeviceId(), position); + } + } catch (SQLException error) { + LOGGER.warn("Load latest positions error", error); + } + } + } + + public boolean isLatestPosition(Position position) { + Position lastPosition = getLastPosition(position.getDeviceId()); + return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0; + } + + public void updateLatestPosition(Position position) throws SQLException { + + if (isLatestPosition(position)) { + + getDataManager().updateLatestPosition(position); + + Device device = getById(position.getDeviceId()); + if (device != null) { + device.setPositionId(position.getId()); + } + + positions.put(position.getDeviceId(), position); + + if (Context.getConnectionManager() != null) { + Context.getConnectionManager().updatePosition(position); + } + } + } + + @Override + public Position getLastPosition(long deviceId) { + return positions.get(deviceId); + } + + public Collection getInitialState(long userId) { + + List result = new LinkedList<>(); + + if (Context.getPermissionsManager() != null) { + for (long deviceId : Context.getPermissionsManager().getUserAdmin(userId) + ? getAllUserItems(userId) : getUserItems(userId)) { + if (positions.containsKey(deviceId)) { + result.add(positions.get(deviceId)); + } + } + } + + return result; + } + + @Override + public boolean lookupAttributeBoolean( + long deviceId, String attributeName, boolean defaultValue, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + if (result != null) { + return result instanceof String ? Boolean.parseBoolean((String) result) : (Boolean) result; + } + return defaultValue; + } + + @Override + public String lookupAttributeString( + long deviceId, String attributeName, String defaultValue, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + return result != null ? (String) result : defaultValue; + } + + @Override + public int lookupAttributeInteger(long deviceId, String attributeName, int defaultValue, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + if (result != null) { + return result instanceof String ? Integer.parseInt((String) result) : ((Number) result).intValue(); + } + return defaultValue; + } + + @Override + public long lookupAttributeLong( + long deviceId, String attributeName, long defaultValue, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + if (result != null) { + return result instanceof String ? Long.parseLong((String) result) : ((Number) result).longValue(); + } + return defaultValue; + } + + public double lookupAttributeDouble( + long deviceId, String attributeName, double defaultValue, boolean lookupConfig) { + Object result = lookupAttribute(deviceId, attributeName, lookupConfig); + if (result != null) { + return result instanceof String ? Double.parseDouble((String) result) : ((Number) result).doubleValue(); + } + return defaultValue; + } + + private Object lookupAttribute(long deviceId, String attributeName, boolean lookupConfig) { + Object result = null; + Device device = getById(deviceId); + if (device != null) { + result = device.getAttributes().get(attributeName); + if (result == null && lookupGroupsAttribute) { + long groupId = device.getGroupId(); + while (groupId != 0) { + Group group = Context.getGroupsManager().getById(groupId); + if (group != null) { + result = group.getAttributes().get(attributeName); + if (result != null) { + break; + } + groupId = group.getGroupId(); + } else { + groupId = 0; + } + } + } + if (result == null) { + if (lookupConfig) { + result = Context.getConfig().getString(attributeName); + } else { + Server server = Context.getPermissionsManager().getServer(); + result = server.getAttributes().get(attributeName); + } + } + } + return result; + } + + public void resetDeviceAccumulators(DeviceAccumulators deviceAccumulators) throws SQLException { + Position last = positions.get(deviceAccumulators.getDeviceId()); + if (last != null) { + if (deviceAccumulators.getTotalDistance() != null) { + last.getAttributes().put(Position.KEY_TOTAL_DISTANCE, deviceAccumulators.getTotalDistance()); + } + if (deviceAccumulators.getHours() != null) { + last.getAttributes().put(Position.KEY_HOURS, deviceAccumulators.getHours()); + } + getDataManager().addObject(last); + updateLatestPosition(last); + } else { + throw new IllegalArgumentException(); + } + } + + public DeviceState getDeviceState(long deviceId) { + DeviceState deviceState = deviceStates.get(deviceId); + if (deviceState == null) { + deviceState = new DeviceState(); + deviceStates.put(deviceId, deviceState); + } + return deviceState; + } + + public void setDeviceState(long deviceId, DeviceState deviceState) { + deviceStates.put(deviceId, deviceState); + } + +} diff --git a/src/main/java/org/traccar/database/DriversManager.java b/src/main/java/org/traccar/database/DriversManager.java new file mode 100644 index 000000000..930951460 --- /dev/null +++ b/src/main/java/org/traccar/database/DriversManager.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.traccar.model.Driver; + +public class DriversManager extends ExtendedObjectManager { + + private Map driversByUniqueId; + + public DriversManager(DataManager dataManager) { + super(dataManager, Driver.class); + if (driversByUniqueId == null) { + driversByUniqueId = new ConcurrentHashMap<>(); + } + } + + private void putUniqueDriverId(Driver driver) { + if (driversByUniqueId == null) { + driversByUniqueId = new ConcurrentHashMap<>(getAllItems().size()); + } + driversByUniqueId.put(driver.getUniqueId(), driver); + } + + @Override + protected void addNewItem(Driver driver) { + super.addNewItem(driver); + putUniqueDriverId(driver); + } + + @Override + protected void updateCachedItem(Driver driver) { + Driver cachedDriver = getById(driver.getId()); + cachedDriver.setName(driver.getName()); + if (!driver.getUniqueId().equals(cachedDriver.getUniqueId())) { + driversByUniqueId.remove(cachedDriver.getUniqueId()); + cachedDriver.setUniqueId(driver.getUniqueId()); + putUniqueDriverId(cachedDriver); + } + cachedDriver.setAttributes(driver.getAttributes()); + } + + @Override + protected void removeCachedItem(long driverId) { + Driver cachedDriver = getById(driverId); + if (cachedDriver != null) { + String driverUniqueId = cachedDriver.getUniqueId(); + super.removeCachedItem(driverId); + driversByUniqueId.remove(driverUniqueId); + } + } + + public Driver getDriverByUniqueId(String uniqueId) { + return driversByUniqueId.get(uniqueId); + } +} diff --git a/src/main/java/org/traccar/database/ExtendedObjectManager.java b/src/main/java/org/traccar/database/ExtendedObjectManager.java new file mode 100644 index 000000000..ceb85b537 --- /dev/null +++ b/src/main/java/org/traccar/database/ExtendedObjectManager.java @@ -0,0 +1,115 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Group; +import org.traccar.model.Permission; +import org.traccar.model.BaseModel; + +public abstract class ExtendedObjectManager extends SimpleObjectManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExtendedObjectManager.class); + + private final Map> deviceItems = new ConcurrentHashMap<>(); + private final Map> deviceItemsWithGroups = new ConcurrentHashMap<>(); + private final Map> groupItems = new ConcurrentHashMap<>(); + + protected ExtendedObjectManager(DataManager dataManager, Class baseClass) { + super(dataManager, baseClass); + refreshExtendedPermissions(); + } + + public final Set getGroupItems(long groupId) { + if (!groupItems.containsKey(groupId)) { + groupItems.put(groupId, new HashSet()); + } + return groupItems.get(groupId); + } + + public final Set getDeviceItems(long deviceId) { + if (!deviceItems.containsKey(deviceId)) { + deviceItems.put(deviceId, new HashSet()); + } + return deviceItems.get(deviceId); + } + + public Set getAllDeviceItems(long deviceId) { + if (!deviceItemsWithGroups.containsKey(deviceId)) { + deviceItemsWithGroups.put(deviceId, new HashSet()); + } + return deviceItemsWithGroups.get(deviceId); + } + + @Override + public void removeItem(long itemId) throws SQLException { + super.removeItem(itemId); + refreshExtendedPermissions(); + } + + public void refreshExtendedPermissions() { + if (getDataManager() != null) { + try { + + Collection databaseGroupPermissions = + getDataManager().getPermissions(Group.class, getBaseClass()); + + groupItems.clear(); + for (Permission groupPermission : databaseGroupPermissions) { + getGroupItems(groupPermission.getOwnerId()).add(groupPermission.getPropertyId()); + } + + Collection databaseDevicePermissions = + getDataManager().getPermissions(Device.class, getBaseClass()); + + deviceItems.clear(); + deviceItemsWithGroups.clear(); + + for (Permission devicePermission : databaseDevicePermissions) { + getDeviceItems(devicePermission.getOwnerId()).add(devicePermission.getPropertyId()); + getAllDeviceItems(devicePermission.getOwnerId()).add(devicePermission.getPropertyId()); + } + + for (Device device : Context.getDeviceManager().getAllDevices()) { + long groupId = device.getGroupId(); + while (groupId != 0) { + getAllDeviceItems(device.getId()).addAll(getGroupItems(groupId)); + Group group = Context.getGroupsManager().getById(groupId); + if (group != null) { + groupId = group.getGroupId(); + } else { + groupId = 0; + } + } + } + + } catch (SQLException | ClassNotFoundException error) { + LOGGER.warn("Refresh permissions error", error); + } + } + } +} diff --git a/src/main/java/org/traccar/database/GeofenceManager.java b/src/main/java/org/traccar/database/GeofenceManager.java new file mode 100644 index 000000000..a32847cf9 --- /dev/null +++ b/src/main/java/org/traccar/database/GeofenceManager.java @@ -0,0 +1,66 @@ +/* + * Copyright 2016 - 2017 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. + * 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.database; + +import java.util.ArrayList; +import java.util.List; + +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Geofence; +import org.traccar.model.Position; + +public class GeofenceManager extends ExtendedObjectManager { + + public GeofenceManager(DataManager dataManager) { + super(dataManager, Geofence.class); + } + + @Override + public final void refreshExtendedPermissions() { + super.refreshExtendedPermissions(); + recalculateDevicesGeofences(); + } + + public List getCurrentDeviceGeofences(Position position) { + List result = new ArrayList<>(); + for (long geofenceId : getAllDeviceItems(position.getDeviceId())) { + Geofence geofence = getById(geofenceId); + if (geofence != null && geofence.getGeometry() + .containsPoint(position.getLatitude(), position.getLongitude())) { + result.add(geofenceId); + } + } + return result; + } + + public void recalculateDevicesGeofences() { + for (Device device : Context.getDeviceManager().getAllDevices()) { + List deviceGeofenceIds = device.getGeofenceIds(); + if (deviceGeofenceIds == null) { + deviceGeofenceIds = new ArrayList<>(); + } else { + deviceGeofenceIds.clear(); + } + Position lastPosition = Context.getIdentityManager().getLastPosition(device.getId()); + if (lastPosition != null && getAllDeviceItems(device.getId()) != null) { + deviceGeofenceIds.addAll(getCurrentDeviceGeofences(lastPosition)); + } + device.setGeofenceIds(deviceGeofenceIds); + } + } + +} diff --git a/src/main/java/org/traccar/database/GroupTree.java b/src/main/java/org/traccar/database/GroupTree.java new file mode 100644 index 000000000..8798f55bc --- /dev/null +++ b/src/main/java/org/traccar/database/GroupTree.java @@ -0,0 +1,151 @@ +/* + * Copyright 2016 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. + * 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.database; + +import org.traccar.model.Device; +import org.traccar.model.Group; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class GroupTree { + + private static class TreeNode { + + private Group group; + private Device device; + private Collection children = new HashSet<>(); + + TreeNode(Group group) { + this.group = group; + } + + TreeNode(Device device) { + this.device = device; + } + + @Override + public int hashCode() { + if (group != null) { + return (int) group.getId(); + } else { + return (int) device.getId(); + } + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TreeNode)) { + return false; + } + TreeNode other = (TreeNode) obj; + if (other == this) { + return true; + } + if (group != null && other.group != null) { + return group.getId() == other.group.getId(); + } else if (device != null && other.device != null) { + return device.getId() == other.device.getId(); + } + return false; + } + + public Group getGroup() { + return group; + } + + public Device getDevice() { + return device; + } + + public void setParent(TreeNode parent) { + if (parent != null) { + parent.children.add(this); + } + } + + public Collection getChildren() { + return children; + } + + } + + private final Map groupMap = new HashMap<>(); + + public GroupTree(Collection groups, Collection devices) { + + for (Group group : groups) { + groupMap.put(group.getId(), new TreeNode(group)); + } + + for (TreeNode node : groupMap.values()) { + if (node.getGroup().getGroupId() != 0) { + node.setParent(groupMap.get(node.getGroup().getGroupId())); + } + } + + Map deviceMap = new HashMap<>(); + + for (Device device : devices) { + deviceMap.put(device.getId(), new TreeNode(device)); + } + + for (TreeNode node : deviceMap.values()) { + if (node.getDevice().getGroupId() != 0) { + node.setParent(groupMap.get(node.getDevice().getGroupId())); + } + } + + } + + public Collection getGroups(long groupId) { + Set results = new HashSet<>(); + getNodes(results, groupMap.get(groupId)); + Collection groups = new ArrayList<>(); + for (TreeNode node : results) { + if (node.getGroup() != null) { + groups.add(node.getGroup()); + } + } + return groups; + } + + public Collection getDevices(long groupId) { + Set results = new HashSet<>(); + getNodes(results, groupMap.get(groupId)); + Collection devices = new ArrayList<>(); + for (TreeNode node : results) { + if (node.getDevice() != null) { + devices.add(node.getDevice()); + } + } + return devices; + } + + private void getNodes(Set results, TreeNode node) { + if (node != null) { + for (TreeNode child : node.getChildren()) { + results.add(child); + getNodes(results, child); + } + } + } + +} diff --git a/src/main/java/org/traccar/database/GroupsManager.java b/src/main/java/org/traccar/database/GroupsManager.java new file mode 100644 index 000000000..d8404c614 --- /dev/null +++ b/src/main/java/org/traccar/database/GroupsManager.java @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Group; + +public class GroupsManager extends BaseObjectManager implements ManagableObjects { + + private static final Logger LOGGER = LoggerFactory.getLogger(GroupsManager.class); + + private AtomicLong groupsLastUpdate = new AtomicLong(); + private final long dataRefreshDelay; + + public GroupsManager(DataManager dataManager) { + super(dataManager, Group.class); + dataRefreshDelay = Context.getConfig().getLong("database.refreshDelay", + DeviceManager.DEFAULT_REFRESH_DELAY) * 1000; + } + + private void checkGroupCycles(Group group) { + Set groups = new HashSet<>(); + while (group != null) { + if (groups.contains(group.getId())) { + throw new IllegalArgumentException("Cycle in group hierarchy"); + } + groups.add(group.getId()); + group = getById(group.getGroupId()); + } + } + + public void updateGroupCache(boolean force) throws SQLException { + long lastUpdate = groupsLastUpdate.get(); + if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) + && groupsLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { + refreshItems(); + } + } + + @Override + public Set getAllItems() { + Set result = super.getAllItems(); + if (result.isEmpty()) { + try { + updateGroupCache(true); + } catch (SQLException e) { + LOGGER.warn("Update group cache error", e); + } + result = super.getAllItems(); + } + return result; + } + + @Override + protected void addNewItem(Group group) { + checkGroupCycles(group); + super.addNewItem(group); + } + + @Override + public void updateItem(Group group) throws SQLException { + checkGroupCycles(group); + super.updateItem(group); + } + + @Override + public Set getUserItems(long userId) { + if (Context.getPermissionsManager() != null) { + return Context.getPermissionsManager().getGroupPermissions(userId); + } else { + return new HashSet<>(); + } + } + + @Override + public Set getManagedItems(long userId) { + Set result = new HashSet<>(); + result.addAll(getUserItems(userId)); + for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { + result.addAll(getUserItems(managedUserId)); + } + return result; + } + +} diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java new file mode 100644 index 000000000..6228a0f75 --- /dev/null +++ b/src/main/java/org/traccar/database/IdentityManager.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015 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. + * 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.database; + +import org.traccar.model.Device; +import org.traccar.model.Position; + +public interface IdentityManager { + + long addUnknownDevice(String uniqueId); + + Device getById(long id); + + Device getByUniqueId(String uniqueId) throws Exception; + + Position getLastPosition(long deviceId); + + boolean isLatestPosition(Position position); + + boolean lookupAttributeBoolean(long deviceId, String attributeName, boolean defaultValue, boolean lookupConfig); + + String lookupAttributeString(long deviceId, String attributeName, String defaultValue, boolean lookupConfig); + + int lookupAttributeInteger(long deviceId, String attributeName, int defaultValue, boolean lookupConfig); + + long lookupAttributeLong(long deviceId, String attributeName, long defaultValue, boolean lookupConfig); + + double lookupAttributeDouble(long deviceId, String attributeName, double defaultValue, boolean lookupConfig); + +} diff --git a/src/main/java/org/traccar/database/LdapProvider.java b/src/main/java/org/traccar/database/LdapProvider.java new file mode 100644 index 000000000..d8b5c9f52 --- /dev/null +++ b/src/main/java/org/traccar/database/LdapProvider.java @@ -0,0 +1,179 @@ +/* + * Copyright 2017 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. + * 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.database; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.model.User; + +import java.util.Hashtable; + +public class LdapProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(LdapProvider.class); + + private String url; + private String searchBase; + private String idAttribute; + private String nameAttribute; + private String mailAttribute; + private String searchFilter; + private String adminFilter; + private String serviceUser; + private String servicePassword; + + public LdapProvider(Config config) { + String url = config.getString("ldap.url"); + if (url != null) { + this.url = url; + } else { + this.url = "ldap://" + config.getString("ldap.server") + ":" + config.getInteger("ldap.port", 389); + } + this.searchBase = config.getString("ldap.base"); + this.idAttribute = config.getString("ldap.idAttribute", "uid"); + this.nameAttribute = config.getString("ldap.nameAttribute", "cn"); + this.mailAttribute = config.getString("ldap.mailAttribute", "mail"); + this.searchFilter = config.getString("ldap.searchFilter", "(" + idAttribute + "=:login)"); + String adminGroup = config.getString("ldap.adminGroup"); + this.adminFilter = config.getString("ldap.adminFilter"); + if (this.adminFilter == null && adminGroup != null) { + this.adminFilter = "(&(" + idAttribute + "=:login)(memberOf=" + adminGroup + "))"; + } + this.serviceUser = config.getString("ldap.user"); + this.servicePassword = config.getString("ldap.password"); + } + + private InitialDirContext auth(String accountName, String password) throws NamingException { + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, url); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, accountName); + env.put(Context.SECURITY_CREDENTIALS, password); + + return new InitialDirContext(env); + } + + private boolean isAdmin(String accountName) { + if (this.adminFilter != null) { + try { + InitialDirContext context = initContext(); + String searchString = adminFilter.replace(":login", accountName); + SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + NamingEnumeration results = context.search(searchBase, searchString, searchControls); + if (results.hasMoreElements()) { + results.nextElement(); + if (results.hasMoreElements()) { + LOGGER.warn("Matched multiple users for the accountName: " + accountName); + return false; + } + return true; + } + } catch (NamingException e) { + return false; + } + } + return false; + } + + public InitialDirContext initContext() throws NamingException { + return auth(serviceUser, servicePassword); + } + + private SearchResult lookupUser(String accountName) throws NamingException { + InitialDirContext context = initContext(); + + String searchString = searchFilter.replace(":login", accountName); + + SearchControls searchControls = new SearchControls(); + String[] attributeFilter = {idAttribute, nameAttribute, mailAttribute}; + searchControls.setReturningAttributes(attributeFilter); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + + NamingEnumeration results = context.search(searchBase, searchString, searchControls); + + SearchResult searchResult = null; + if (results.hasMoreElements()) { + searchResult = results.nextElement(); + if (results.hasMoreElements()) { + LOGGER.warn("Matched multiple users for the accountName: " + accountName); + return null; + } + } + + return searchResult; + } + + public User getUser(String accountName) { + SearchResult ldapUser; + User user = new User(); + try { + ldapUser = lookupUser(accountName); + if (ldapUser != null) { + Attribute attribute = ldapUser.getAttributes().get(idAttribute); + if (attribute != null) { + user.setLogin((String) attribute.get()); + } else { + user.setLogin(accountName); + } + attribute = ldapUser.getAttributes().get(nameAttribute); + if (attribute != null) { + user.setName((String) attribute.get()); + } else { + user.setName(accountName); + } + attribute = ldapUser.getAttributes().get(mailAttribute); + if (attribute != null) { + user.setEmail((String) attribute.get()); + } else { + user.setEmail(accountName); + } + } + user.setAdministrator(isAdmin(accountName)); + } catch (NamingException e) { + user.setLogin(accountName); + user.setName(accountName); + user.setEmail(accountName); + LOGGER.warn("User lookup error", e); + } + return user; + } + + public boolean login(String username, String password) { + try { + SearchResult ldapUser = lookupUser(username); + if (ldapUser != null) { + auth(ldapUser.getNameInNamespace(), password).close(); + return true; + } + } catch (NamingException e) { + return false; + } + return false; + } + +} diff --git a/src/main/java/org/traccar/database/MailManager.java b/src/main/java/org/traccar/database/MailManager.java new file mode 100644 index 000000000..8a2f002cd --- /dev/null +++ b/src/main/java/org/traccar/database/MailManager.java @@ -0,0 +1,147 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.Main; +import org.traccar.model.User; +import org.traccar.notification.PropertiesProvider; + +import javax.mail.BodyPart; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import java.util.Date; +import java.util.Properties; + +public final class MailManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(MailManager.class); + + private static Properties getProperties(PropertiesProvider provider) { + Properties properties = new Properties(); + String host = provider.getString("mail.smtp.host"); + if (host != null) { + properties.put("mail.transport.protocol", provider.getString("mail.transport.protocol", "smtp")); + properties.put("mail.smtp.host", host); + properties.put("mail.smtp.port", String.valueOf(provider.getInteger("mail.smtp.port", 25))); + + Boolean starttlsEnable = provider.getBoolean("mail.smtp.starttls.enable"); + if (starttlsEnable != null) { + properties.put("mail.smtp.starttls.enable", String.valueOf(starttlsEnable)); + } + Boolean starttlsRequired = provider.getBoolean("mail.smtp.starttls.required"); + if (starttlsRequired != null) { + properties.put("mail.smtp.starttls.required", String.valueOf(starttlsRequired)); + } + + Boolean sslEnable = provider.getBoolean("mail.smtp.ssl.enable"); + if (sslEnable != null) { + properties.put("mail.smtp.ssl.enable", String.valueOf(sslEnable)); + } + String sslTrust = provider.getString("mail.smtp.ssl.trust"); + if (sslTrust != null) { + properties.put("mail.smtp.ssl.trust", sslTrust); + } + + String sslProtocols = provider.getString("mail.smtp.ssl.protocols"); + if (sslProtocols != null) { + properties.put("mail.smtp.ssl.protocols", sslProtocols); + } + + String username = provider.getString("mail.smtp.username"); + if (username != null) { + properties.put("mail.smtp.username", username); + } + String password = provider.getString("mail.smtp.password"); + if (password != null) { + properties.put("mail.smtp.password", password); + } + String from = provider.getString("mail.smtp.from"); + if (from != null) { + properties.put("mail.smtp.from", from); + } + } + return properties; + } + + public void sendMessage( + long userId, String subject, String body) throws MessagingException { + sendMessage(userId, subject, body, null); + } + + public void sendMessage( + long userId, String subject, String body, MimeBodyPart attachment) throws MessagingException { + User user = Context.getPermissionsManager().getUser(userId); + + Properties properties = null; + if (!Context.getConfig().getBoolean("mail.smtp.ignoreUserConfig")) { + properties = getProperties(new PropertiesProvider(user)); + } + if (properties == null || !properties.containsKey("mail.smtp.host")) { + properties = getProperties(new PropertiesProvider(Context.getConfig())); + } + if (!properties.containsKey("mail.smtp.host")) { + LOGGER.warn("No SMTP configuration found"); + return; + } + + Session session = Session.getInstance(properties); + + MimeMessage message = new MimeMessage(session); + + String from = properties.getProperty("mail.smtp.from"); + if (from != null) { + message.setFrom(new InternetAddress(from)); + } + + message.addRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail())); + message.setSubject(subject); + message.setSentDate(new Date()); + + if (attachment != null) { + Multipart multipart = new MimeMultipart(); + + BodyPart messageBodyPart = new MimeBodyPart(); + messageBodyPart.setContent(body, "text/html; charset=utf-8"); + multipart.addBodyPart(messageBodyPart); + multipart.addBodyPart(attachment); + + message.setContent(multipart); + } else { + message.setContent(body, "text/html; charset=utf-8"); + } + + try (Transport transport = session.getTransport()) { + Main.getInjector().getInstance(StatisticsManager.class).registerMail(); + transport.connect( + properties.getProperty("mail.smtp.host"), + properties.getProperty("mail.smtp.username"), + properties.getProperty("mail.smtp.password")); + transport.sendMessage(message, message.getAllRecipients()); + } + } + +} diff --git a/src/main/java/org/traccar/database/MaintenancesManager.java b/src/main/java/org/traccar/database/MaintenancesManager.java new file mode 100644 index 000000000..4e266cb78 --- /dev/null +++ b/src/main/java/org/traccar/database/MaintenancesManager.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import org.traccar.model.Maintenance; + +public class MaintenancesManager extends ExtendedObjectManager { + + public MaintenancesManager(DataManager dataManager) { + super(dataManager, Maintenance.class); + } + +} diff --git a/src/main/java/org/traccar/database/ManagableObjects.java b/src/main/java/org/traccar/database/ManagableObjects.java new file mode 100644 index 000000000..ec9549493 --- /dev/null +++ b/src/main/java/org/traccar/database/ManagableObjects.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.util.Set; + +public interface ManagableObjects { + + Set getUserItems(long userId); + + Set getManagedItems(long userId); + +} diff --git a/src/main/java/org/traccar/database/MediaManager.java b/src/main/java/org/traccar/database/MediaManager.java new file mode 100644 index 000000000..edade5766 --- /dev/null +++ b/src/main/java/org/traccar/database/MediaManager.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017 - 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. + * 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.database; + +import io.netty.buffer.ByteBuf; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class MediaManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(MediaManager.class); + + private String path; + + public MediaManager(String path) { + this.path = path; + } + + private File createFile(String uniqueId, String name) throws IOException { + Path filePath = Paths.get(path, uniqueId, name); + Path directoryPath = filePath.getParent(); + if (directoryPath != null) { + Files.createDirectories(directoryPath); + } + return filePath.toFile(); + } + + public String writeFile(String uniqueId, ByteBuf buf, String extension) { + if (path != null) { + int size = buf.readableBytes(); + String name = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "." + extension; + try (FileOutputStream output = new FileOutputStream(createFile(uniqueId, name)); + FileChannel fileChannel = output.getChannel()) { + ByteBuffer byteBuffer = buf.nioBuffer(); + int written = 0; + while (written < size) { + written += fileChannel.write(byteBuffer); + } + fileChannel.force(false); + return name; + } catch (IOException e) { + LOGGER.warn("Save media file error", e); + } + } + return null; + } + +} diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java new file mode 100644 index 000000000..09df4c571 --- /dev/null +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -0,0 +1,135 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.sql.SQLException; +import java.util.Date; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Calendar; +import org.traccar.model.Event; +import org.traccar.model.Notification; +import org.traccar.model.Position; +import org.traccar.model.Typed; + +public class NotificationManager extends ExtendedObjectManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificationManager.class); + + private boolean geocodeOnRequest; + + public NotificationManager(DataManager dataManager) { + super(dataManager, Notification.class); + geocodeOnRequest = Context.getConfig().getBoolean("geocoder.onRequest"); + } + + private Set getEffectiveNotifications(long userId, long deviceId, Date time) { + Set result = new HashSet<>(); + Set deviceNotifications = getAllDeviceItems(deviceId); + for (long itemId : getUserItems(userId)) { + if (getById(itemId).getAlways() || deviceNotifications.contains(itemId)) { + long calendarId = getById(itemId).getCalendarId(); + Calendar calendar = calendarId != 0 ? Context.getCalendarManager().getById(calendarId) : null; + if (calendar == null || calendar.checkMoment(time)) { + result.add(itemId); + } + } + } + return result; + } + + public void updateEvent(Event event, Position position) { + try { + getDataManager().addObject(event); + } catch (SQLException error) { + LOGGER.warn("Event save error", error); + } + + if (position != null && geocodeOnRequest && Context.getGeocoder() != null && position.getAddress() == null) { + position.setAddress(Context.getGeocoder() + .getAddress(position.getLatitude(), position.getLongitude(), null)); + } + + long deviceId = event.getDeviceId(); + Set users = Context.getPermissionsManager().getDeviceUsers(deviceId); + Set usersToForward = null; + if (Context.getEventForwarder() != null) { + usersToForward = new HashSet<>(); + } + for (long userId : users) { + if ((event.getGeofenceId() == 0 + || Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId())) + && (event.getMaintenanceId() == 0 + || Context.getMaintenancesManager().checkItemPermission(userId, event.getMaintenanceId()))) { + if (usersToForward != null) { + usersToForward.add(userId); + } + final Set notificators = new HashSet<>(); + for (long notificationId : getEffectiveNotifications(userId, deviceId, event.getServerTime())) { + Notification notification = getById(notificationId); + if (getById(notificationId).getType().equals(event.getType())) { + boolean filter = false; + if (event.getType().equals(Event.TYPE_ALARM)) { + String alarms = notification.getString("alarms"); + if (alarms == null || !alarms.contains(event.getString(Position.KEY_ALARM))) { + filter = true; + } + } + if (!filter) { + notificators.addAll(notification.getNotificatorsTypes()); + } + } + } + for (String notificator : notificators) { + Context.getNotificatorManager().getNotificator(notificator).sendAsync(userId, event, position); + } + } + } + if (Context.getEventForwarder() != null) { + Context.getEventForwarder().forwardEvent(event, position, usersToForward); + } + } + + public void updateEvents(Map events) { + for (Entry event : events.entrySet()) { + updateEvent(event.getKey(), event.getValue()); + } + } + + public Set getAllNotificationTypes() { + Set types = new HashSet<>(); + Field[] fields = Event.class.getDeclaredFields(); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) { + try { + types.add(new Typed(field.get(null).toString())); + } catch (IllegalArgumentException | IllegalAccessException error) { + LOGGER.warn("Get event types error", error); + } + } + } + return types; + } +} diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java new file mode 100644 index 000000000..ced0df1c0 --- /dev/null +++ b/src/main/java/org/traccar/database/PermissionsManager.java @@ -0,0 +1,459 @@ +/* + * 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. + * 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.database; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Attribute; +import org.traccar.model.BaseModel; +import org.traccar.model.Calendar; +import org.traccar.model.Command; +import org.traccar.model.Device; +import org.traccar.model.Driver; +import org.traccar.model.Geofence; +import org.traccar.model.Group; +import org.traccar.model.Maintenance; +import org.traccar.model.ManagedUser; +import org.traccar.model.Notification; +import org.traccar.model.Permission; +import org.traccar.model.Server; +import org.traccar.model.User; + +import java.sql.SQLException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class PermissionsManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(PermissionsManager.class); + + private final DataManager dataManager; + private final UsersManager usersManager; + + private volatile Server server; + + private final Map> groupPermissions = new HashMap<>(); + private final Map> devicePermissions = new HashMap<>(); + private final Map> deviceUsers = new HashMap<>(); + private final Map> groupDevices = new HashMap<>(); + + public PermissionsManager(DataManager dataManager, UsersManager usersManager) { + this.dataManager = dataManager; + this.usersManager = usersManager; + refreshServer(); + refreshDeviceAndGroupPermissions(); + } + + public User getUser(long userId) { + return usersManager.getById(userId); + } + + public Set getGroupPermissions(long userId) { + if (!groupPermissions.containsKey(userId)) { + groupPermissions.put(userId, new HashSet<>()); + } + return groupPermissions.get(userId); + } + + public Set getDevicePermissions(long userId) { + if (!devicePermissions.containsKey(userId)) { + devicePermissions.put(userId, new HashSet<>()); + } + return devicePermissions.get(userId); + } + + private Set getAllDeviceUsers(long deviceId) { + if (!deviceUsers.containsKey(deviceId)) { + deviceUsers.put(deviceId, new HashSet<>()); + } + return deviceUsers.get(deviceId); + } + + public Set getDeviceUsers(long deviceId) { + Device device = Context.getIdentityManager().getById(deviceId); + if (device != null && !device.getDisabled()) { + return getAllDeviceUsers(deviceId); + } else { + Set result = new HashSet<>(); + for (long userId : getAllDeviceUsers(deviceId)) { + if (getUserAdmin(userId)) { + result.add(userId); + } + } + return result; + } + } + + public Set getGroupDevices(long groupId) { + if (!groupDevices.containsKey(groupId)) { + groupDevices.put(groupId, new HashSet<>()); + } + return groupDevices.get(groupId); + } + + public void refreshServer() { + try { + server = dataManager.getServer(); + } catch (SQLException error) { + LOGGER.warn("Refresh server config error", error); + } + } + + public final void refreshDeviceAndGroupPermissions() { + groupPermissions.clear(); + devicePermissions.clear(); + try { + GroupTree groupTree = new GroupTree(Context.getGroupsManager().getItems( + Context.getGroupsManager().getAllItems()), + Context.getDeviceManager().getAllDevices()); + for (Permission groupPermission : dataManager.getPermissions(User.class, Group.class)) { + Set userGroupPermissions = getGroupPermissions(groupPermission.getOwnerId()); + Set userDevicePermissions = getDevicePermissions(groupPermission.getOwnerId()); + userGroupPermissions.add(groupPermission.getPropertyId()); + for (Group group : groupTree.getGroups(groupPermission.getPropertyId())) { + userGroupPermissions.add(group.getId()); + } + for (Device device : groupTree.getDevices(groupPermission.getPropertyId())) { + userDevicePermissions.add(device.getId()); + } + } + + for (Permission devicePermission : dataManager.getPermissions(User.class, Device.class)) { + getDevicePermissions(devicePermission.getOwnerId()).add(devicePermission.getPropertyId()); + } + + groupDevices.clear(); + for (long groupId : Context.getGroupsManager().getAllItems()) { + for (Device device : groupTree.getDevices(groupId)) { + getGroupDevices(groupId).add(device.getId()); + } + } + + } catch (SQLException | ClassNotFoundException error) { + LOGGER.warn("Refresh device permissions error", error); + } + + deviceUsers.clear(); + for (Map.Entry> entry : devicePermissions.entrySet()) { + for (long deviceId : entry.getValue()) { + getAllDeviceUsers(deviceId).add(entry.getKey()); + } + } + } + + public boolean getUserAdmin(long userId) { + User user = getUser(userId); + return user != null && user.getAdministrator(); + } + + public void checkAdmin(long userId) throws SecurityException { + if (!getUserAdmin(userId)) { + throw new SecurityException("Admin access required"); + } + } + + public boolean getUserManager(long userId) { + User user = getUser(userId); + return user != null && user.getUserLimit() != 0; + } + + public void checkManager(long userId) throws SecurityException { + if (!getUserManager(userId)) { + throw new SecurityException("Manager access required"); + } + } + + public void checkManager(long userId, long managedUserId) throws SecurityException { + checkManager(userId); + if (!usersManager.getUserItems(userId).contains(managedUserId)) { + throw new SecurityException("User access denied"); + } + } + + public void checkUserLimit(long userId) throws SecurityException { + int userLimit = getUser(userId).getUserLimit(); + if (userLimit != -1 && usersManager.getUserItems(userId).size() >= userLimit) { + throw new SecurityException("Manager user limit reached"); + } + } + + public void checkDeviceLimit(long userId) throws SecurityException { + int deviceLimit = getUser(userId).getDeviceLimit(); + if (deviceLimit != -1) { + int deviceCount = 0; + if (getUserManager(userId)) { + deviceCount = Context.getDeviceManager().getAllManagedItems(userId).size(); + } else { + deviceCount = Context.getDeviceManager().getAllUserItems(userId).size(); + } + if (deviceCount >= deviceLimit) { + throw new SecurityException("User device limit reached"); + } + } + } + + public boolean getUserReadonly(long userId) { + User user = getUser(userId); + return user != null && user.getReadonly(); + } + + public boolean getUserDeviceReadonly(long userId) { + User user = getUser(userId); + return user != null && user.getDeviceReadonly(); + } + + public boolean getUserLimitCommands(long userId) { + User user = getUser(userId); + return user != null && user.getLimitCommands(); + } + + public void checkReadonly(long userId) throws SecurityException { + if (!getUserAdmin(userId) && (server.getReadonly() || getUserReadonly(userId))) { + throw new SecurityException("Account is readonly"); + } + } + + public void checkDeviceReadonly(long userId) throws SecurityException { + if (!getUserAdmin(userId) && (server.getDeviceReadonly() || getUserDeviceReadonly(userId))) { + throw new SecurityException("Account is device readonly"); + } + } + + public void checkLimitCommands(long userId) throws SecurityException { + if (!getUserAdmin(userId) && (server.getLimitCommands() || getUserLimitCommands(userId))) { + throw new SecurityException("Account has limit sending commands"); + } + } + + public void checkUserDeviceCommand(long userId, long deviceId, long commandId) throws SecurityException { + if (!getUserAdmin(userId) && Context.getCommandsManager().checkDeviceCommand(deviceId, commandId)) { + throw new SecurityException("Command can not be sent to this device"); + } + } + + public void checkUserEnabled(long userId) throws SecurityException { + User user = getUser(userId); + if (user == null) { + throw new SecurityException("Unknown account"); + } + if (user.getDisabled()) { + throw new SecurityException("Account is disabled"); + } + if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) { + throw new SecurityException("Account has expired"); + } + } + + public void checkUserUpdate(long userId, User before, User after) throws SecurityException { + if (before.getAdministrator() != after.getAdministrator() + || before.getDeviceLimit() != after.getDeviceLimit() + || before.getUserLimit() != after.getUserLimit()) { + checkAdmin(userId); + } + User user = getUser(userId); + if (user != null && user.getExpirationTime() != null + && (after.getExpirationTime() == null + || user.getExpirationTime().compareTo(after.getExpirationTime()) < 0)) { + checkAdmin(userId); + } + if (before.getReadonly() != after.getReadonly() + || before.getDeviceReadonly() != after.getDeviceReadonly() + || before.getDisabled() != after.getDisabled() + || before.getLimitCommands() != after.getLimitCommands()) { + if (userId == after.getId()) { + checkAdmin(userId); + } + if (!getUserAdmin(userId)) { + checkManager(userId); + } + } + } + + public void checkUser(long userId, long managedUserId) throws SecurityException { + if (userId != managedUserId && !getUserAdmin(userId)) { + checkManager(userId, managedUserId); + } + } + + public void checkGroup(long userId, long groupId) throws SecurityException { + if (!getGroupPermissions(userId).contains(groupId) && !getUserAdmin(userId)) { + checkManager(userId); + for (long managedUserId : usersManager.getUserItems(userId)) { + if (getGroupPermissions(managedUserId).contains(groupId)) { + return; + } + } + throw new SecurityException("Group access denied"); + } + } + + public void checkDevice(long userId, long deviceId) throws SecurityException { + if (!Context.getDeviceManager().getUserItems(userId).contains(deviceId) && !getUserAdmin(userId)) { + checkManager(userId); + for (long managedUserId : usersManager.getUserItems(userId)) { + if (Context.getDeviceManager().getUserItems(managedUserId).contains(deviceId)) { + return; + } + } + throw new SecurityException("Device access denied"); + } + } + + public void checkRegistration(long userId) { + if (!server.getRegistration() && !getUserAdmin(userId)) { + throw new SecurityException("Registration disabled"); + } + } + + public void checkPermission(Class object, long userId, long objectId) + throws SecurityException { + SimpleObjectManager manager = null; + + if (object.equals(Device.class)) { + checkDevice(userId, objectId); + } else if (object.equals(Group.class)) { + checkGroup(userId, objectId); + } else if (object.equals(User.class) || object.equals(ManagedUser.class)) { + checkUser(userId, objectId); + } else if (object.equals(Geofence.class)) { + manager = Context.getGeofenceManager(); + } else if (object.equals(Attribute.class)) { + manager = Context.getAttributesManager(); + } else if (object.equals(Driver.class)) { + manager = Context.getDriversManager(); + } else if (object.equals(Calendar.class)) { + manager = Context.getCalendarManager(); + } else if (object.equals(Command.class)) { + manager = Context.getCommandsManager(); + } else if (object.equals(Maintenance.class)) { + manager = Context.getMaintenancesManager(); + } else if (object.equals(Notification.class)) { + manager = Context.getNotificationManager(); + } else { + throw new IllegalArgumentException("Unknown object type"); + } + + if (manager != null && !manager.checkItemPermission(userId, objectId) && !getUserAdmin(userId)) { + checkManager(userId); + for (long managedUserId : usersManager.getManagedItems(userId)) { + if (manager.checkItemPermission(managedUserId, objectId)) { + return; + } + } + throw new SecurityException("Type " + object + " access denied"); + } + } + + public void refreshAllUsersPermissions() { + if (Context.getGeofenceManager() != null) { + Context.getGeofenceManager().refreshUserItems(); + } + Context.getCalendarManager().refreshUserItems(); + Context.getDriversManager().refreshUserItems(); + Context.getAttributesManager().refreshUserItems(); + Context.getCommandsManager().refreshUserItems(); + Context.getMaintenancesManager().refreshUserItems(); + if (Context.getNotificationManager() != null) { + Context.getNotificationManager().refreshUserItems(); + } + } + + public void refreshAllExtendedPermissions() { + if (Context.getGeofenceManager() != null) { + Context.getGeofenceManager().refreshExtendedPermissions(); + } + Context.getDriversManager().refreshExtendedPermissions(); + Context.getAttributesManager().refreshExtendedPermissions(); + Context.getCommandsManager().refreshExtendedPermissions(); + Context.getMaintenancesManager().refreshExtendedPermissions(); + } + + public void refreshPermissions(Permission permission) { + if (permission.getOwnerClass().equals(User.class)) { + if (permission.getPropertyClass().equals(Device.class) + || permission.getPropertyClass().equals(Group.class)) { + refreshDeviceAndGroupPermissions(); + refreshAllExtendedPermissions(); + } else if (permission.getPropertyClass().equals(ManagedUser.class)) { + usersManager.refreshUserItems(); + } else if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) { + Context.getGeofenceManager().refreshUserItems(); + } else if (permission.getPropertyClass().equals(Driver.class)) { + Context.getDriversManager().refreshUserItems(); + } else if (permission.getPropertyClass().equals(Attribute.class)) { + Context.getAttributesManager().refreshUserItems(); + } else if (permission.getPropertyClass().equals(Calendar.class)) { + Context.getCalendarManager().refreshUserItems(); + } else if (permission.getPropertyClass().equals(Command.class)) { + Context.getCommandsManager().refreshUserItems(); + } else if (permission.getPropertyClass().equals(Maintenance.class)) { + Context.getMaintenancesManager().refreshUserItems(); + } else if (permission.getPropertyClass().equals(Notification.class) + && Context.getNotificationManager() != null) { + Context.getNotificationManager().refreshUserItems(); + } + } else if (permission.getOwnerClass().equals(Device.class) || permission.getOwnerClass().equals(Group.class)) { + if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) { + Context.getGeofenceManager().refreshExtendedPermissions(); + } else if (permission.getPropertyClass().equals(Driver.class)) { + Context.getDriversManager().refreshExtendedPermissions(); + } else if (permission.getPropertyClass().equals(Attribute.class)) { + Context.getAttributesManager().refreshExtendedPermissions(); + } else if (permission.getPropertyClass().equals(Command.class)) { + Context.getCommandsManager().refreshExtendedPermissions(); + } else if (permission.getPropertyClass().equals(Maintenance.class)) { + Context.getMaintenancesManager().refreshExtendedPermissions(); + } else if (permission.getPropertyClass().equals(Notification.class) + && Context.getNotificationManager() != null) { + Context.getNotificationManager().refreshExtendedPermissions(); + } + } + } + + public Server getServer() { + return server; + } + + public void updateServer(Server server) throws SQLException { + dataManager.updateObject(server); + this.server = server; + } + + public User login(String email, String password) throws SQLException { + User user = dataManager.login(email, password); + if (user != null) { + checkUserEnabled(user.getId()); + return getUser(user.getId()); + } + return null; + } + + public Object lookupAttribute(long userId, String key, Object defaultValue) { + Object preference; + Object serverPreference = server.getAttributes().get(key); + Object userPreference = getUser(userId).getAttributes().get(key); + if (server.getForceSettings()) { + preference = serverPreference != null ? serverPreference : userPreference; + } else { + preference = userPreference != null ? userPreference : serverPreference; + } + return preference != null ? preference : defaultValue; + } + +} diff --git a/src/main/java/org/traccar/database/QueryBuilder.java b/src/main/java/org/traccar/database/QueryBuilder.java new file mode 100644 index 000000000..5528b2320 --- /dev/null +++ b/src/main/java/org/traccar/database/QueryBuilder.java @@ -0,0 +1,519 @@ +/* + * Copyright 2015 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. + * 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.database; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.MiscFormatter; +import org.traccar.model.Permission; + +import javax.sql.DataSource; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public final class QueryBuilder { + + private static final Logger LOGGER = LoggerFactory.getLogger(QueryBuilder.class); + + private final Map> indexMap = new HashMap<>(); + private Connection connection; + private PreparedStatement statement; + private final String query; + private final boolean returnGeneratedKeys; + + private QueryBuilder(DataSource dataSource, String query, boolean returnGeneratedKeys) throws SQLException { + this.query = query; + this.returnGeneratedKeys = returnGeneratedKeys; + if (query != null) { + connection = dataSource.getConnection(); + String parsedQuery = parse(query.trim(), indexMap); + try { + if (returnGeneratedKeys) { + statement = connection.prepareStatement(parsedQuery, Statement.RETURN_GENERATED_KEYS); + } else { + statement = connection.prepareStatement(parsedQuery); + } + } catch (SQLException error) { + connection.close(); + throw error; + } + } + } + + private static String parse(String query, Map> paramMap) { + + int length = query.length(); + StringBuilder parsedQuery = new StringBuilder(length); + boolean inSingleQuote = false; + boolean inDoubleQuote = false; + int index = 1; + + for (int i = 0; i < length; i++) { + + char c = query.charAt(i); + + // String end + if (inSingleQuote) { + if (c == '\'') { + inSingleQuote = false; + } + } else if (inDoubleQuote) { + if (c == '"') { + inDoubleQuote = false; + } + } else { + + // String begin + if (c == '\'') { + inSingleQuote = true; + } else if (c == '"') { + inDoubleQuote = true; + } else if (c == ':' && i + 1 < length + && Character.isJavaIdentifierStart(query.charAt(i + 1))) { + + // Identifier name + int j = i + 2; + while (j < length && Character.isJavaIdentifierPart(query.charAt(j))) { + j++; + } + + String name = query.substring(i + 1, j); + c = '?'; + i += name.length(); + name = name.toLowerCase(); + + // Add to list + List indexList = paramMap.get(name); + if (indexList == null) { + indexList = new LinkedList<>(); + paramMap.put(name, indexList); + } + indexList.add(index); + + index++; + } + } + + parsedQuery.append(c); + } + + return parsedQuery.toString(); + } + + public static QueryBuilder create(DataSource dataSource, String query) throws SQLException { + return new QueryBuilder(dataSource, query, false); + } + + public static QueryBuilder create( + DataSource dataSource, String query, boolean returnGeneratedKeys) throws SQLException { + return new QueryBuilder(dataSource, query, returnGeneratedKeys); + } + + private List indexes(String name) { + name = name.toLowerCase(); + List result = indexMap.get(name); + if (result == null) { + result = new LinkedList<>(); + } + return result; + } + + public QueryBuilder setBoolean(String name, boolean value) throws SQLException { + for (int i : indexes(name)) { + try { + statement.setBoolean(i, value); + } catch (SQLException error) { + statement.close(); + connection.close(); + throw error; + } + } + return this; + } + + public QueryBuilder setInteger(String name, int value) throws SQLException { + for (int i : indexes(name)) { + try { + statement.setInt(i, value); + } catch (SQLException error) { + statement.close(); + connection.close(); + throw error; + } + } + return this; + } + + public QueryBuilder setLong(String name, long value) throws SQLException { + return setLong(name, value, false); + } + + public QueryBuilder setLong(String name, long value, boolean nullIfZero) throws SQLException { + for (int i : indexes(name)) { + try { + if (value == 0 && nullIfZero) { + statement.setNull(i, Types.INTEGER); + } else { + statement.setLong(i, value); + } + } catch (SQLException error) { + statement.close(); + connection.close(); + throw error; + } + } + return this; + } + + public QueryBuilder setDouble(String name, double value) throws SQLException { + for (int i : indexes(name)) { + try { + statement.setDouble(i, value); + } catch (SQLException error) { + statement.close(); + connection.close(); + throw error; + } + } + return this; + } + + public QueryBuilder setString(String name, String value) throws SQLException { + for (int i : indexes(name)) { + try { + if (value == null) { + statement.setNull(i, Types.VARCHAR); + } else { + statement.setString(i, value); + } + } catch (SQLException error) { + statement.close(); + connection.close(); + throw error; + } + } + return this; + } + + public QueryBuilder setDate(String name, Date value) throws SQLException { + for (int i : indexes(name)) { + try { + if (value == null) { + statement.setNull(i, Types.TIMESTAMP); + } else { + statement.setTimestamp(i, new Timestamp(value.getTime())); + } + } catch (SQLException error) { + statement.close(); + connection.close(); + throw error; + } + } + return this; + } + + public QueryBuilder setBlob(String name, byte[] value) throws SQLException { + for (int i : indexes(name)) { + try { + if (value == null) { + statement.setNull(i, Types.BLOB); + } else { + statement.setBytes(i, value); + } + } catch (SQLException error) { + statement.close(); + connection.close(); + throw error; + } + } + return this; + } + + public QueryBuilder setObject(Object object) throws SQLException { + + Method[] methods = object.getClass().getMethods(); + + for (Method method : methods) { + if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 + && !method.isAnnotationPresent(QueryIgnore.class)) { + String name = method.getName().substring(3); + try { + if (method.getReturnType().equals(boolean.class)) { + setBoolean(name, (Boolean) method.invoke(object)); + } else if (method.getReturnType().equals(int.class)) { + setInteger(name, (Integer) method.invoke(object)); + } else if (method.getReturnType().equals(long.class)) { + setLong(name, (Long) method.invoke(object), name.endsWith("Id")); + } else if (method.getReturnType().equals(double.class)) { + setDouble(name, (Double) method.invoke(object)); + } else if (method.getReturnType().equals(String.class)) { + setString(name, (String) method.invoke(object)); + } else if (method.getReturnType().equals(Date.class)) { + setDate(name, (Date) method.invoke(object)); + } else if (method.getReturnType().equals(byte[].class)) { + setBlob(name, (byte[]) method.invoke(object)); + } else { + if (method.getReturnType().equals(Map.class) + && Context.getConfig().getBoolean("database.xml")) { + setString(name, MiscFormatter.toXmlString((Map) method.invoke(object))); + } else { + setString(name, Context.getObjectMapper().writeValueAsString(method.invoke(object))); + } + } + } catch (IllegalAccessException | InvocationTargetException | JsonProcessingException error) { + LOGGER.warn("Get property error", error); + } + } + } + + return this; + } + + private interface ResultSetProcessor { + void process(T object, ResultSet resultSet) throws SQLException; + } + + public T executeQuerySingle(Class clazz) throws SQLException { + Collection result = executeQuery(clazz); + if (!result.isEmpty()) { + return result.iterator().next(); + } else { + return null; + } + } + + private void addProcessors( + List> processors, + final Class parameterType, final Method method, final String name) { + + if (parameterType.equals(boolean.class)) { + processors.add(new ResultSetProcessor() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + try { + method.invoke(object, resultSet.getBoolean(name)); + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Set property error", error); + } + } + }); + } else if (parameterType.equals(int.class)) { + processors.add(new ResultSetProcessor() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + try { + method.invoke(object, resultSet.getInt(name)); + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Set property error", error); + } + } + }); + } else if (parameterType.equals(long.class)) { + processors.add(new ResultSetProcessor() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + try { + method.invoke(object, resultSet.getLong(name)); + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Set property error", error); + } + } + }); + } else if (parameterType.equals(double.class)) { + processors.add(new ResultSetProcessor() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + try { + method.invoke(object, resultSet.getDouble(name)); + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Set property error", error); + } + } + }); + } else if (parameterType.equals(String.class)) { + processors.add(new ResultSetProcessor() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + try { + method.invoke(object, resultSet.getString(name)); + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Set property error", error); + } + } + }); + } else if (parameterType.equals(Date.class)) { + processors.add(new ResultSetProcessor() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + try { + Timestamp timestamp = resultSet.getTimestamp(name); + if (timestamp != null) { + method.invoke(object, new Date(timestamp.getTime())); + } + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Set property error", error); + } + } + }); + } else if (parameterType.equals(byte[].class)) { + processors.add(new ResultSetProcessor() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + try { + method.invoke(object, resultSet.getBytes(name)); + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Set property error", error); + } + } + }); + } else { + processors.add(new ResultSetProcessor() { + @Override + public void process(T object, ResultSet resultSet) throws SQLException { + String value = resultSet.getString(name); + if (value != null && !value.isEmpty()) { + try { + method.invoke(object, Context.getObjectMapper().readValue(value, parameterType)); + } catch (InvocationTargetException | IllegalAccessException | IOException error) { + LOGGER.warn("Set property error", error); + } + } + } + }); + } + } + + public Collection executeQuery(Class clazz) throws SQLException { + List result = new LinkedList<>(); + + if (query != null) { + + try { + + try (ResultSet resultSet = statement.executeQuery()) { + + ResultSetMetaData resultMetaData = resultSet.getMetaData(); + + List> processors = new LinkedList<>(); + + Method[] methods = clazz.getMethods(); + + for (final Method method : methods) { + if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 + && !method.isAnnotationPresent(QueryIgnore.class)) { + + final String name = method.getName().substring(3); + + // Check if column exists + boolean column = false; + for (int i = 1; i <= resultMetaData.getColumnCount(); i++) { + if (name.equalsIgnoreCase(resultMetaData.getColumnLabel(i))) { + column = true; + break; + } + } + if (!column) { + continue; + } + + addProcessors(processors, method.getParameterTypes()[0], method, name); + } + } + + while (resultSet.next()) { + try { + T object = clazz.newInstance(); + for (ResultSetProcessor processor : processors) { + processor.process(object, resultSet); + } + result.add(object); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException(); + } + } + } + + } finally { + statement.close(); + connection.close(); + } + } + + return result; + } + + public long executeUpdate() throws SQLException { + + if (query != null) { + try { + statement.execute(); + if (returnGeneratedKeys) { + ResultSet resultSet = statement.getGeneratedKeys(); + if (resultSet.next()) { + return resultSet.getLong(1); + } + } + } finally { + statement.close(); + connection.close(); + } + } + return 0; + } + + public Collection executePermissionsQuery() throws SQLException, ClassNotFoundException { + List result = new LinkedList<>(); + if (query != null) { + try { + try (ResultSet resultSet = statement.executeQuery()) { + ResultSetMetaData resultMetaData = resultSet.getMetaData(); + while (resultSet.next()) { + LinkedHashMap map = new LinkedHashMap<>(); + for (int i = 1; i <= resultMetaData.getColumnCount(); i++) { + String label = resultMetaData.getColumnLabel(i); + map.put(label, resultSet.getLong(label)); + } + result.add(new Permission(map)); + } + } + } finally { + statement.close(); + connection.close(); + } + } + + return result; + } + +} diff --git a/src/main/java/org/traccar/database/QueryExtended.java b/src/main/java/org/traccar/database/QueryExtended.java new file mode 100644 index 000000000..07bc2c211 --- /dev/null +++ b/src/main/java/org/traccar/database/QueryExtended.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface QueryExtended { +} diff --git a/src/main/java/org/traccar/database/QueryIgnore.java b/src/main/java/org/traccar/database/QueryIgnore.java new file mode 100644 index 000000000..ac835cf2f --- /dev/null +++ b/src/main/java/org/traccar/database/QueryIgnore.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017 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. + * 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.database; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface QueryIgnore { +} diff --git a/src/main/java/org/traccar/database/SimpleObjectManager.java b/src/main/java/org/traccar/database/SimpleObjectManager.java new file mode 100644 index 000000000..15dda4520 --- /dev/null +++ b/src/main/java/org/traccar/database/SimpleObjectManager.java @@ -0,0 +1,94 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.BaseModel; +import org.traccar.model.Permission; +import org.traccar.model.User; + +public abstract class SimpleObjectManager extends BaseObjectManager + implements ManagableObjects { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleObjectManager.class); + + private Map> userItems; + + protected SimpleObjectManager(DataManager dataManager, Class baseClass) { + super(dataManager, baseClass); + } + + @Override + public final Set getUserItems(long userId) { + if (!userItems.containsKey(userId)) { + userItems.put(userId, new HashSet()); + } + return userItems.get(userId); + } + + @Override + public Set getManagedItems(long userId) { + Set result = new HashSet<>(); + result.addAll(getUserItems(userId)); + for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { + result.addAll(getUserItems(managedUserId)); + } + return result; + } + + public final boolean checkItemPermission(long userId, long itemId) { + return getUserItems(userId).contains(itemId); + } + + @Override + public void refreshItems() { + super.refreshItems(); + refreshUserItems(); + } + + public final void refreshUserItems() { + if (getDataManager() != null) { + try { + if (userItems != null) { + userItems.clear(); + } else { + userItems = new ConcurrentHashMap<>(); + } + for (Permission permission : getDataManager().getPermissions(User.class, getBaseClass())) { + getUserItems(permission.getOwnerId()).add(permission.getPropertyId()); + } + } catch (SQLException | ClassNotFoundException error) { + LOGGER.warn("Error getting permissions", error); + } + } + } + + @Override + public void removeItem(long itemId) throws SQLException { + super.removeItem(itemId); + refreshUserItems(); + } + +} diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java new file mode 100644 index 000000000..e59f8e767 --- /dev/null +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -0,0 +1,160 @@ +/* + * Copyright 2016 - 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. + * 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.database; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.helper.DateUtil; +import org.traccar.model.Statistics; + +import javax.inject.Inject; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Form; +import java.sql.SQLException; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +public class StatisticsManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsManager.class); + + private static final int SPLIT_MODE = Calendar.DAY_OF_MONTH; + + private final Config config; + private final DataManager dataManager; + private final Client client; + + private AtomicInteger lastUpdate = new AtomicInteger(Calendar.getInstance().get(SPLIT_MODE)); + + private Set users = new HashSet<>(); + private Set devices = new HashSet<>(); + + private int requests; + private int messagesReceived; + private int messagesStored; + private int mailSent; + private int smsSent; + private int geocoderRequests; + private int geolocationRequests; + + @Inject + public StatisticsManager(Config config, DataManager dataManager, Client client) { + this.config = config; + this.dataManager = dataManager; + this.client = client; + } + + private void checkSplit() { + int currentUpdate = Calendar.getInstance().get(SPLIT_MODE); + if (lastUpdate.getAndSet(currentUpdate) != currentUpdate) { + Statistics statistics = new Statistics(); + statistics.setCaptureTime(new Date()); + statistics.setActiveUsers(users.size()); + statistics.setActiveDevices(devices.size()); + statistics.setRequests(requests); + statistics.setMessagesReceived(messagesReceived); + statistics.setMessagesStored(messagesStored); + statistics.setMailSent(mailSent); + statistics.setSmsSent(smsSent); + statistics.setGeocoderRequests(geocoderRequests); + statistics.setGeolocationRequests(geolocationRequests); + + try { + dataManager.addObject(statistics); + } catch (SQLException e) { + LOGGER.warn("Error saving statistics", e); + } + + String url = config.getString(Keys.SERVER_STATISTICS); + if (url != null) { + String time = DateUtil.formatDate(statistics.getCaptureTime()); + + Form form = new Form(); + form.param("version", getClass().getPackage().getImplementationVersion()); + form.param("captureTime", time); + form.param("activeUsers", String.valueOf(statistics.getActiveUsers())); + form.param("activeDevices", String.valueOf(statistics.getActiveDevices())); + form.param("requests", String.valueOf(statistics.getRequests())); + form.param("messagesReceived", String.valueOf(statistics.getMessagesReceived())); + form.param("messagesStored", String.valueOf(statistics.getMessagesStored())); + form.param("mailSent", String.valueOf(statistics.getMailSent())); + form.param("smsSent", String.valueOf(statistics.getSmsSent())); + form.param("geocoderRequests", String.valueOf(statistics.getGeocoderRequests())); + form.param("geolocationRequests", String.valueOf(statistics.getGeolocationRequests())); + + client.target(url).request().async().post(Entity.form(form)); + } + + users.clear(); + devices.clear(); + requests = 0; + messagesReceived = 0; + messagesStored = 0; + mailSent = 0; + smsSent = 0; + geocoderRequests = 0; + geolocationRequests = 0; + } + } + + public synchronized void registerRequest(long userId) { + checkSplit(); + requests += 1; + if (userId != 0) { + users.add(userId); + } + } + + public synchronized void registerMessageReceived() { + checkSplit(); + messagesReceived += 1; + } + + public synchronized void registerMessageStored(long deviceId) { + checkSplit(); + messagesStored += 1; + if (deviceId != 0) { + devices.add(deviceId); + } + } + + public synchronized void registerMail() { + checkSplit(); + mailSent += 1; + } + + public synchronized void registerSms() { + checkSplit(); + smsSent += 1; + } + + public synchronized void registerGeocoderRequest() { + checkSplit(); + geocoderRequests += 1; + } + + public synchronized void registerGeolocationRequest() { + checkSplit(); + geolocationRequests += 1; + } + +} diff --git a/src/main/java/org/traccar/database/UsersManager.java b/src/main/java/org/traccar/database/UsersManager.java new file mode 100644 index 000000000..576a9e6c7 --- /dev/null +++ b/src/main/java/org/traccar/database/UsersManager.java @@ -0,0 +1,86 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.database; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.traccar.model.User; + +public class UsersManager extends SimpleObjectManager { + + private Map usersTokens; + + public UsersManager(DataManager dataManager) { + super(dataManager, User.class); + if (usersTokens == null) { + usersTokens = new ConcurrentHashMap<>(); + } + } + + private void putToken(User user) { + if (usersTokens == null) { + usersTokens = new ConcurrentHashMap<>(); + } + if (user.getToken() != null) { + usersTokens.put(user.getToken(), user); + } + } + + @Override + protected void addNewItem(User user) { + super.addNewItem(user); + putToken(user); + } + + @Override + protected void updateCachedItem(User user) { + User cachedUser = getById(user.getId()); + super.updateCachedItem(user); + putToken(user); + if (cachedUser.getToken() != null && !cachedUser.getToken().equals(user.getToken())) { + usersTokens.remove(cachedUser.getToken()); + } + } + + @Override + protected void removeCachedItem(long userId) { + User cachedUser = getById(userId); + if (cachedUser != null) { + String userToken = cachedUser.getToken(); + super.removeCachedItem(userId); + if (userToken != null) { + usersTokens.remove(userToken); + } + } + } + + @Override + public Set getManagedItems(long userId) { + Set result = new HashSet<>(); + result.addAll(getUserItems(userId)); + result.add(userId); + return result; + } + + public User getUserByToken(String token) { + return usersTokens.get(token); + } + +} diff --git a/src/main/java/org/traccar/geocoder/Address.java b/src/main/java/org/traccar/geocoder/Address.java new file mode 100644 index 000000000..fe39da8e1 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/Address.java @@ -0,0 +1,110 @@ +/* + * Copyright 2015 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. + * 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.geocoder; + +public class Address { + + private String postcode; + + public String getPostcode() { + return postcode; + } + + public void setPostcode(String postcode) { + this.postcode = postcode; + } + + private String country; + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + private String state; + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + private String district; + + public String getDistrict() { + return district; + } + + public void setDistrict(String district) { + this.district = district; + } + + private String settlement; + + public String getSettlement() { + return settlement; + } + + public void setSettlement(String settlement) { + this.settlement = settlement; + } + + private String suburb; + + public String getSuburb() { + return suburb; + } + + public void setSuburb(String suburb) { + this.suburb = suburb; + } + + private String street; + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + private String house; + + public String getHouse() { + return house; + } + + public void setHouse(String house) { + this.house = house; + } + + private String formattedAddress; + + public String getFormattedAddress() { + return formattedAddress; + } + + public void setFormattedAddress(String formattedAddress) { + this.formattedAddress = formattedAddress; + } + +} diff --git a/src/main/java/org/traccar/geocoder/AddressFormat.java b/src/main/java/org/traccar/geocoder/AddressFormat.java new file mode 100644 index 000000000..ad19432b9 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/AddressFormat.java @@ -0,0 +1,82 @@ +/* + * Copyright 2015 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. + * 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.geocoder; + +import java.text.FieldPosition; +import java.text.Format; +import java.text.ParsePosition; + +/** + * Available parameters: + * + * %p - postcode + * %c - country + * %s - state + * %d - district + * %t - settlement (town) + * %u - suburb + * %r - street (road) + * %h - house + * %f - formatted address + * + */ +public class AddressFormat extends Format { + + private final String format; + + public AddressFormat() { + this("%h %r, %t, %s, %c"); + } + + public AddressFormat(String format) { + this.format = format; + } + + private static String replace(String s, String key, String value) { + if (value != null) { + s = s.replace(key, value); + } else { + s = s.replaceAll("[, ]*" + key, ""); + } + return s; + } + + @Override + public StringBuffer format(Object o, StringBuffer stringBuffer, FieldPosition fieldPosition) { + Address address = (Address) o; + String result = format; + + result = replace(result, "%p", address.getPostcode()); + result = replace(result, "%c", address.getCountry()); + result = replace(result, "%s", address.getState()); + result = replace(result, "%d", address.getDistrict()); + result = replace(result, "%t", address.getSettlement()); + result = replace(result, "%u", address.getSuburb()); + result = replace(result, "%r", address.getStreet()); + result = replace(result, "%h", address.getHouse()); + result = replace(result, "%f", address.getFormattedAddress()); + + result = result.replaceAll("^[, ]*", ""); + + return stringBuffer.append(result); + } + + @Override + public Address parseObject(String s, ParsePosition parsePosition) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/org/traccar/geocoder/BanGeocoder.java b/src/main/java/org/traccar/geocoder/BanGeocoder.java new file mode 100644 index 000000000..b1f0900a4 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/BanGeocoder.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 Olivier Girondel (olivier@biniou.info) + * Copyright 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. + * 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.geocoder; + +/* + * API documentation: https://adresse.data.gouv.fr/api + */ + +import javax.json.JsonArray; +import javax.json.JsonObject; + +public class BanGeocoder extends JsonGeocoder { + + public BanGeocoder(int cacheSize, AddressFormat addressFormat) { + super("https://api-adresse.data.gouv.fr/reverse/?lat=%f&lon=%f", cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonArray result = json.getJsonArray("features"); + + if (result != null && !result.isEmpty()) { + JsonObject location = result.getJsonObject(0).getJsonObject("properties"); + Address address = new Address(); + + address.setCountry("FR"); + if (location.containsKey("postcode")) { + address.setPostcode(location.getString("postcode")); + } + if (location.containsKey("context")) { + address.setDistrict(location.getString("context")); + } + if (location.containsKey("name")) { + address.setStreet(location.getString("name")); + } + if (location.containsKey("city")) { + address.setSettlement(location.getString("city")); + } + if (location.containsKey("housenumber")) { + address.setHouse(location.getString("housenumber")); + } + if (location.containsKey("label")) { + address.setFormattedAddress(location.getString("label")); + } + + return address; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java new file mode 100644 index 000000000..32a26ee0c --- /dev/null +++ b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) + * Copyright 2017 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. + * 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.geocoder; + +import javax.json.JsonArray; +import javax.json.JsonObject; + +public class BingMapsGeocoder extends JsonGeocoder { + + public BingMapsGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { + super(url + "/Locations/%f,%f?key=" + key + "&include=ciso2", cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonArray result = json.getJsonArray("resourceSets"); + if (result != null) { + JsonObject location = + result.getJsonObject(0).getJsonArray("resources").getJsonObject(0).getJsonObject("address"); + if (location != null) { + Address address = new Address(); + if (location.containsKey("addressLine")) { + address.setStreet(location.getString("addressLine")); + } + if (location.containsKey("locality")) { + address.setSettlement(location.getString("locality")); + } + if (location.containsKey("adminDistrict2")) { + address.setDistrict(location.getString("adminDistrict2")); + } + if (location.containsKey("adminDistrict")) { + address.setState(location.getString("adminDistrict")); + } + if (location.containsKey("countryRegionIso2")) { + address.setCountry(location.getString("countryRegionIso2").toUpperCase()); + } + if (location.containsKey("postalCode")) { + address.setPostcode(location.getString("postalCode")); + } + if (location.containsKey("formattedAddress")) { + address.setFormattedAddress(location.getString("formattedAddress")); + } + return address; + } + } + return null; + } + +} diff --git a/src/main/java/org/traccar/geocoder/FactualGeocoder.java b/src/main/java/org/traccar/geocoder/FactualGeocoder.java new file mode 100644 index 000000000..c7a68c293 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/FactualGeocoder.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) + * Copyright 2017 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. + * 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.geocoder; + +import javax.json.JsonObject; + +public class FactualGeocoder extends JsonGeocoder { + + public FactualGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { + super(url + "?latitude=%f&longitude=%f&KEY=" + key, cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonObject result = json.getJsonObject("response").getJsonObject("data"); + if (result != null) { + Address address = new Address(); + if (result.getJsonObject("street_number") != null) { + address.setHouse(result.getJsonObject("street_number").getString("name")); + } + if (result.getJsonObject("street_name") != null) { + address.setStreet(result.getJsonObject("street_name").getString("name")); + } + if (result.getJsonObject("locality") != null) { + address.setSettlement(result.getJsonObject("locality").getString("name")); + } + if (result.getJsonObject("county") != null) { + address.setDistrict(result.getJsonObject("county").getString("name")); + } + if (result.getJsonObject("region") != null) { + address.setState(result.getJsonObject("region").getString("name")); + } + if (result.getJsonObject("country") != null) { + address.setCountry(result.getJsonObject("country").getString("name")); + } + if (result.getJsonObject("postcode") != null) { + address.setPostcode(result.getJsonObject("postcode").getString("name")); + } + return address; + } + return null; + } + +} diff --git a/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java new file mode 100644 index 000000000..39a3300a0 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016 - 2017 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. + * 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.geocoder; + +import javax.json.JsonObject; + +public class GeocodeFarmGeocoder extends JsonGeocoder { + + private static String formatUrl(String key, String language) { + String url = "https://www.geocode.farm/v3/json/reverse/"; + url += "?lat=%f&lon=%f&country=us&count=1"; + if (key != null) { + url += "&key=" + key; + } + if (language != null) { + url += "&lang=" + language; + } + return url; + } + public GeocodeFarmGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) { + super(formatUrl(key, language), cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + Address address = new Address(); + + JsonObject result = json + .getJsonObject("geocoding_results") + .getJsonArray("RESULTS") + .getJsonObject(0); + + JsonObject resultAddress = result.getJsonObject("ADDRESS"); + + if (result.containsKey("formatted_address")) { + address.setFormattedAddress(result.getString("formatted_address")); + } + if (resultAddress.containsKey("street_number")) { + address.setStreet(resultAddress.getString("street_number")); + } + if (resultAddress.containsKey("street_name")) { + address.setStreet(resultAddress.getString("street_name")); + } + if (resultAddress.containsKey("locality")) { + address.setSettlement(resultAddress.getString("locality")); + } + if (resultAddress.containsKey("admin_1")) { + address.setState(resultAddress.getString("admin_1")); + } + if (resultAddress.containsKey("country")) { + address.setCountry(resultAddress.getString("country")); + } + + return address; + } + +} diff --git a/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java new file mode 100644 index 000000000..aca360c3d --- /dev/null +++ b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java @@ -0,0 +1,60 @@ +/* + * Copyright 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. + * 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.geocoder; + +import javax.json.JsonObject; + +public class GeocodeXyzGeocoder extends JsonGeocoder { + + private static String formatUrl(String key) { + String url = "https://geocode.xyz/%f,%f?geoit=JSON"; + if (key != null) { + url += "&key=" + key; + } + return url; + } + + public GeocodeXyzGeocoder(String key, int cacheSize, AddressFormat addressFormat) { + super(formatUrl(key), cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + Address address = new Address(); + + if (json.containsKey("stnumber")) { + address.setHouse(json.getString("stnumber")); + } + if (json.containsKey("staddress")) { + address.setStreet(json.getString("staddress")); + } + if (json.containsKey("city")) { + address.setSettlement(json.getString("city")); + } + if (json.containsKey("region")) { + address.setState(json.getString("region")); + } + if (json.containsKey("prov")) { + address.setCountry(json.getString("prov")); + } + if (json.containsKey("postal")) { + address.setPostcode(json.getString("postal")); + } + + return address; + } + +} diff --git a/src/main/java/org/traccar/geocoder/Geocoder.java b/src/main/java/org/traccar/geocoder/Geocoder.java new file mode 100644 index 000000000..587a27520 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/Geocoder.java @@ -0,0 +1,30 @@ +/* + * Copyright 2012 - 2017 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. + * 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.geocoder; + +public interface Geocoder { + + interface ReverseGeocoderCallback { + + void onSuccess(String address); + + void onFailure(Throwable e); + + } + + String getAddress(double latitude, double longitude, ReverseGeocoderCallback callback); + +} diff --git a/src/main/java/org/traccar/geocoder/GeocoderException.java b/src/main/java/org/traccar/geocoder/GeocoderException.java new file mode 100644 index 000000000..608916641 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/GeocoderException.java @@ -0,0 +1,24 @@ +/* + * Copyright 2016 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. + * 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.geocoder; + +public class GeocoderException extends RuntimeException { + + public GeocoderException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java new file mode 100644 index 000000000..3a173f985 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java @@ -0,0 +1,55 @@ +/* + * Copyright 2015 - 2017 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. + * 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.geocoder; + +import javax.json.JsonObject; + +public class GisgraphyGeocoder extends JsonGeocoder { + + public GisgraphyGeocoder(AddressFormat addressFormat) { + this("http://services.gisgraphy.com/reversegeocoding/search", 0, addressFormat); + } + + public GisgraphyGeocoder(String url, int cacheSize, AddressFormat addressFormat) { + super(url + "?format=json&lat=%f&lng=%f&from=1&to=1", cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + Address address = new Address(); + + JsonObject result = json.getJsonArray("result").getJsonObject(0); + + if (result.containsKey("streetName")) { + address.setStreet(result.getString("streetName")); + } + if (result.containsKey("city")) { + address.setSettlement(result.getString("city")); + } + if (result.containsKey("state")) { + address.setState(result.getString("state")); + } + if (result.containsKey("countryCode")) { + address.setCountry(result.getString("countryCode")); + } + if (result.containsKey("formatedFull")) { + address.setFormattedAddress(result.getString("formatedFull")); + } + + return address; + } + +} diff --git a/src/main/java/org/traccar/geocoder/GoogleGeocoder.java b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java new file mode 100644 index 000000000..9494cab45 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java @@ -0,0 +1,98 @@ +/* + * Copyright 2012 - 2017 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. + * 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.geocoder; + +import javax.json.JsonArray; +import javax.json.JsonObject; +import javax.json.JsonString; + +public class GoogleGeocoder extends JsonGeocoder { + + private static String formatUrl(String key, String language) { + String url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f"; + if (key != null) { + url += "&key=" + key; + } + if (language != null) { + url += "&language=" + language; + } + return url; + } + + public GoogleGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) { + super(formatUrl(key, language), cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonArray results = json.getJsonArray("results"); + + if (!results.isEmpty()) { + Address address = new Address(); + + JsonObject result = (JsonObject) results.get(0); + JsonArray components = result.getJsonArray("address_components"); + + if (result.containsKey("formatted_address")) { + address.setFormattedAddress(result.getString("formatted_address")); + } + + for (JsonObject component : components.getValuesAs(JsonObject.class)) { + + String value = component.getString("short_name"); + + typesLoop: for (JsonString type : component.getJsonArray("types").getValuesAs(JsonString.class)) { + + switch (type.getString()) { + case "street_number": + address.setHouse(value); + break typesLoop; + case "route": + address.setStreet(value); + break typesLoop; + case "locality": + address.setSettlement(value); + break typesLoop; + case "administrative_area_level_2": + address.setDistrict(value); + break typesLoop; + case "administrative_area_level_1": + address.setState(value); + break typesLoop; + case "country": + address.setCountry(value); + break typesLoop; + case "postal_code": + address.setPostcode(value); + break typesLoop; + default: + break; + } + } + } + + return address; + } + + return null; + } + + @Override + protected String parseError(JsonObject json) { + return json.getString("error_message"); + } + +} diff --git a/src/main/java/org/traccar/geocoder/HereGeocoder.java b/src/main/java/org/traccar/geocoder/HereGeocoder.java new file mode 100644 index 000000000..756260b52 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/HereGeocoder.java @@ -0,0 +1,84 @@ +/* + * Copyright 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. + * 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.geocoder; + +import javax.json.JsonObject; + +public class HereGeocoder extends JsonGeocoder { + + private static String formatUrl(String id, String key, String language) { + String url = "https://reverse.geocoder.api.here.com/6.2/reversegeocode.json"; + url += "?mode=retrieveAddresses&maxresults=1"; + url += "&prox=%f,%f,0"; + url += "&app_id=" + id; + url += "&app_code=" + key; + if (language != null) { + url += "&language=" + language; + } + return url; + } + + public HereGeocoder(String id, String key, String language, int cacheSize, AddressFormat addressFormat) { + super(formatUrl(id, key, language), cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonObject result = json + .getJsonObject("Response") + .getJsonArray("View") + .getJsonObject(0) + .getJsonArray("Result") + .getJsonObject(0) + .getJsonObject("Location") + .getJsonObject("Address"); + + if (result != null) { + Address address = new Address(); + + if (json.containsKey("Label")) { + address.setFormattedAddress(json.getString("Label")); + } + + if (result.containsKey("HouseNumber")) { + address.setHouse(result.getString("HouseNumber")); + } + if (result.containsKey("Street")) { + address.setStreet(result.getString("Street")); + } + if (result.containsKey("City")) { + address.setSettlement(result.getString("City")); + } + if (result.containsKey("District")) { + address.setDistrict(result.getString("District")); + } + if (result.containsKey("State")) { + address.setState(result.getString("State")); + } + if (result.containsKey("Country")) { + address.setCountry(result.getString("Country").toUpperCase()); + } + if (result.containsKey("PostalCode")) { + address.setPostcode(result.getString("PostalCode")); + } + + return address; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/geocoder/JsonGeocoder.java b/src/main/java/org/traccar/geocoder/JsonGeocoder.java new file mode 100644 index 000000000..ed59a1d8d --- /dev/null +++ b/src/main/java/org/traccar/geocoder/JsonGeocoder.java @@ -0,0 +1,121 @@ +/* + * 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. + * 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.geocoder; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; + +import javax.json.JsonObject; +import javax.ws.rs.ClientErrorException; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.InvocationCallback; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +public abstract class JsonGeocoder implements Geocoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(JsonGeocoder.class); + + private final String url; + private final AddressFormat addressFormat; + + private Map, String> cache; + + public JsonGeocoder(String url, final int cacheSize, AddressFormat addressFormat) { + this.url = url; + this.addressFormat = addressFormat; + if (cacheSize > 0) { + this.cache = Collections.synchronizedMap(new LinkedHashMap, String>() { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > cacheSize; + } + }); + } + } + + private String handleResponse( + double latitude, double longitude, JsonObject json, ReverseGeocoderCallback callback) { + + Address address = parseAddress(json); + if (address != null) { + String formattedAddress = addressFormat.format(address); + if (cache != null) { + cache.put(new AbstractMap.SimpleImmutableEntry<>(latitude, longitude), formattedAddress); + } + if (callback != null) { + callback.onSuccess(formattedAddress); + } + return formattedAddress; + } else { + String msg = "Empty address. Error: " + parseError(json); + if (callback != null) { + callback.onFailure(new GeocoderException(msg)); + } else { + LOGGER.warn(msg); + } + } + return null; + } + + @Override + public String getAddress( + final double latitude, final double longitude, final ReverseGeocoderCallback callback) { + + if (cache != null) { + String cachedAddress = cache.get(new AbstractMap.SimpleImmutableEntry<>(latitude, longitude)); + if (cachedAddress != null) { + if (callback != null) { + callback.onSuccess(cachedAddress); + } + return cachedAddress; + } + } + + Invocation.Builder request = Context.getClient().target(String.format(url, latitude, longitude)).request(); + + if (callback != null) { + request.async().get(new InvocationCallback() { + @Override + public void completed(JsonObject json) { + handleResponse(latitude, longitude, json, callback); + } + + @Override + public void failed(Throwable throwable) { + callback.onFailure(throwable); + } + }); + } else { + try { + return handleResponse(latitude, longitude, request.get(JsonObject.class), null); + } catch (ClientErrorException e) { + LOGGER.warn("Geocoder network error", e); + } + } + return null; + } + + public abstract Address parseAddress(JsonObject json); + + protected String parseError(JsonObject json) { + return null; + } + +} diff --git a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java new file mode 100644 index 000000000..4029e3f07 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) + * Copyright 2017 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. + * 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.geocoder; + +import javax.json.JsonArray; +import javax.json.JsonObject; + +public class MapQuestGeocoder extends JsonGeocoder { + + public MapQuestGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { + super(url + "?key=" + key + "&location=%f,%f", cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonArray result = json.getJsonArray("results"); + if (result != null) { + JsonArray locations = result.getJsonObject(0).getJsonArray("locations"); + if (locations != null) { + JsonObject location = locations.getJsonObject(0); + + Address address = new Address(); + + if (location.containsKey("street")) { + address.setStreet(location.getString("street")); + } + if (location.containsKey("adminArea5")) { + address.setSettlement(location.getString("adminArea5")); + } + if (location.containsKey("adminArea4")) { + address.setDistrict(location.getString("adminArea4")); + } + if (location.containsKey("adminArea3")) { + address.setState(location.getString("adminArea3")); + } + if (location.containsKey("adminArea1")) { + address.setCountry(location.getString("adminArea1").toUpperCase()); + } + if (location.containsKey("postalCode")) { + address.setPostcode(location.getString("postalCode")); + } + + return address; + } + } + return null; + } + +} diff --git a/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java new file mode 100644 index 000000000..2b70708a1 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java @@ -0,0 +1,82 @@ +/* + * Copyright 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. + * 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.geocoder; + +import javax.json.JsonArray; +import javax.json.JsonObject; + +public class MapmyIndiaGeocoder extends JsonGeocoder { + + public MapmyIndiaGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { + super(url + "/" + key + "/rev_geocode?lat=%f&lng=%f", cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonArray results = json.getJsonArray("results"); + + if (!results.isEmpty()) { + Address address = new Address(); + + JsonObject result = (JsonObject) results.get(0); + + if (result.containsKey("formatted_address")) { + address.setFormattedAddress(result.getString("formatted_address")); + } + + if (result.containsKey("house_number") && !result.getString("house_number").isEmpty()) { + address.setHouse(result.getString("house_number")); + } else if (result.containsKey("house_name") && !result.getString("house_name").isEmpty()) { + address.setHouse(result.getString("house_name")); + } + + if (result.containsKey("street")) { + address.setStreet(result.getString("street")); + } + + if (result.containsKey("locality") && !result.getString("locality").isEmpty()) { + address.setSuburb(result.getString("locality")); + } else if (result.containsKey("sublocality") && !result.getString("sublocality").isEmpty()) { + address.setSuburb(result.getString("sublocality")); + } else if (result.containsKey("subsublocality") && !result.getString("subsublocality").isEmpty()) { + address.setSuburb(result.getString("subsublocality")); + } + + if (result.containsKey("city") && !result.getString("city").isEmpty()) { + address.setSettlement(result.getString("city")); + } else if (result.containsKey("village") && !result.getString("village").isEmpty()) { + address.setSettlement(result.getString("village")); + } + + if (result.containsKey("district")) { + address.setDistrict(result.getString("district")); + } else if (result.containsKey("subDistrict")) { + address.setDistrict(result.getString("subDistrict")); + } + + if (result.containsKey("state")) { + address.setState(result.getString("state")); + } + + if (result.containsKey("pincode")) { + address.setPostcode(result.getString("pincode")); + } + + return address; + } + return null; + } +} diff --git a/src/main/java/org/traccar/geocoder/NominatimGeocoder.java b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java new file mode 100644 index 000000000..8db25bf15 --- /dev/null +++ b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java @@ -0,0 +1,91 @@ +/* + * Copyright 2014 - 2017 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. + * 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.geocoder; + +import javax.json.JsonObject; + +public class NominatimGeocoder extends JsonGeocoder { + + private static String formatUrl(String url, String key, String language) { + if (url == null) { + url = "https://nominatim.openstreetmap.org/reverse"; + } + url += "?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1"; + if (key != null) { + url += "&key=" + key; + } + if (language != null) { + url += "&accept-language=" + language; + } + return url; + } + + public NominatimGeocoder(String url, String key, String language, int cacheSize, AddressFormat addressFormat) { + super(formatUrl(url, key, language), cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonObject result = json.getJsonObject("address"); + + if (result != null) { + Address address = new Address(); + + if (json.containsKey("display_name")) { + address.setFormattedAddress(json.getString("display_name")); + } + + if (result.containsKey("house_number")) { + address.setHouse(result.getString("house_number")); + } + if (result.containsKey("road")) { + address.setStreet(result.getString("road")); + } + if (result.containsKey("suburb")) { + address.setSuburb(result.getString("suburb")); + } + + if (result.containsKey("village")) { + address.setSettlement(result.getString("village")); + } else if (result.containsKey("town")) { + address.setSettlement(result.getString("town")); + } else if (result.containsKey("city")) { + address.setSettlement(result.getString("city")); + } + + if (result.containsKey("state_district")) { + address.setDistrict(result.getString("state_district")); + } else if (result.containsKey("region")) { + address.setDistrict(result.getString("region")); + } + + if (result.containsKey("state")) { + address.setState(result.getString("state")); + } + if (result.containsKey("country_code")) { + address.setCountry(result.getString("country_code").toUpperCase()); + } + if (result.containsKey("postcode")) { + address.setPostcode(result.getString("postcode")); + } + + return address; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java new file mode 100644 index 000000000..822b6e91e --- /dev/null +++ b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java @@ -0,0 +1,76 @@ +/* + * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) + * Copyright 2017 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. + * 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.geocoder; + +import javax.json.JsonArray; +import javax.json.JsonObject; + +public class OpenCageGeocoder extends JsonGeocoder { + + public OpenCageGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { + super(url + "/json?q=%f,%f&no_annotations=1&key=" + key, cacheSize, addressFormat); + } + + @Override + public Address parseAddress(JsonObject json) { + JsonArray result = json.getJsonArray("results"); + if (result != null) { + JsonObject location = result.getJsonObject(0).getJsonObject("components"); + if (location != null) { + Address address = new Address(); + + if (result.getJsonObject(0).containsKey("formatted")) { + address.setFormattedAddress(result.getJsonObject(0).getString("formatted")); + } + if (location.containsKey("building")) { + address.setHouse(location.getString("building")); + } + if (location.containsKey("house_number")) { + address.setHouse(location.getString("house_number")); + } + if (location.containsKey("road")) { + address.setStreet(location.getString("road")); + } + if (location.containsKey("suburb")) { + address.setSuburb(location.getString("suburb")); + } + if (location.containsKey("city")) { + address.setSettlement(location.getString("city")); + } + if (location.containsKey("city_district")) { + address.setSettlement(location.getString("city_district")); + } + if (location.containsKey("county")) { + address.setDistrict(location.getString("county")); + } + if (location.containsKey("state")) { + address.setState(location.getString("state")); + } + if (location.containsKey("country_code")) { + address.setCountry(location.getString("country_code").toUpperCase()); + } + if (location.containsKey("postcode")) { + address.setPostcode(location.getString("postcode")); + } + + return address; + } + } + return null; + } + +} diff --git a/src/main/java/org/traccar/geofence/GeofenceCircle.java b/src/main/java/org/traccar/geofence/GeofenceCircle.java new file mode 100644 index 000000000..f6fca63ca --- /dev/null +++ b/src/main/java/org/traccar/geofence/GeofenceCircle.java @@ -0,0 +1,98 @@ +/* + * Copyright 2016 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. + * 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.geofence; + +import java.text.DecimalFormat; +import java.text.ParseException; + +import org.traccar.helper.DistanceCalculator; + +public class GeofenceCircle extends GeofenceGeometry { + + private double centerLatitude; + private double centerLongitude; + private double radius; + + public GeofenceCircle() { + } + + public GeofenceCircle(String wkt) throws ParseException { + fromWkt(wkt); + } + + public GeofenceCircle(double latitude, double longitude, double radius) { + this.centerLatitude = latitude; + this.centerLongitude = longitude; + this.radius = radius; + } + + public double distanceFromCenter(double latitude, double longitude) { + return DistanceCalculator.distance(centerLatitude, centerLongitude, latitude, longitude); + } + + @Override + public boolean containsPoint(double latitude, double longitude) { + return distanceFromCenter(latitude, longitude) <= radius; + } + + @Override + public String toWkt() { + String wkt = ""; + wkt = "CIRCLE ("; + wkt += String.valueOf(centerLatitude); + wkt += " "; + wkt += String.valueOf(centerLongitude); + wkt += ", "; + DecimalFormat format = new DecimalFormat("0.#"); + wkt += format.format(radius); + wkt += ")"; + return wkt; + } + + @Override + public void fromWkt(String wkt) throws ParseException { + if (!wkt.startsWith("CIRCLE")) { + throw new ParseException("Mismatch geometry type", 0); + } + String content = wkt.substring(wkt.indexOf("(") + 1, wkt.indexOf(")")); + if (content == null || content.equals("")) { + throw new ParseException("No content", 0); + } + String[] commaTokens = content.split(","); + if (commaTokens.length != 2) { + throw new ParseException("Not valid content", 0); + } + String[] tokens = commaTokens[0].split("\\s"); + if (tokens.length != 2) { + throw new ParseException("Too much or less coordinates", 0); + } + try { + centerLatitude = Double.parseDouble(tokens[0]); + } catch (NumberFormatException e) { + throw new ParseException(tokens[0] + " is not a double", 0); + } + try { + centerLongitude = Double.parseDouble(tokens[1]); + } catch (NumberFormatException e) { + throw new ParseException(tokens[1] + " is not a double", 0); + } + try { + radius = Double.parseDouble(commaTokens[1]); + } catch (NumberFormatException e) { + throw new ParseException(commaTokens[1] + " is not a double", 0); + } + } +} diff --git a/src/main/java/org/traccar/geofence/GeofenceGeometry.java b/src/main/java/org/traccar/geofence/GeofenceGeometry.java new file mode 100644 index 000000000..857ba3414 --- /dev/null +++ b/src/main/java/org/traccar/geofence/GeofenceGeometry.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016 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. + * 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.geofence; + +import java.text.ParseException; + +public abstract class GeofenceGeometry { + + public abstract boolean containsPoint(double latitude, double longitude); + + public abstract String toWkt(); + + public abstract void fromWkt(String wkt) throws ParseException; + + public static class Coordinate { + + private double lat; + private double lon; + + public double getLat() { + return lat; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public double getLon() { + return lon; + } + + public void setLon(double lon) { + this.lon = lon; + } + } + +} diff --git a/src/main/java/org/traccar/geofence/GeofencePolygon.java b/src/main/java/org/traccar/geofence/GeofencePolygon.java new file mode 100644 index 000000000..2048ba26d --- /dev/null +++ b/src/main/java/org/traccar/geofence/GeofencePolygon.java @@ -0,0 +1,164 @@ +/* + * Copyright 2016 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. + * 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.geofence; + +import java.text.ParseException; +import java.util.ArrayList; + +public class GeofencePolygon extends GeofenceGeometry { + + public GeofencePolygon() { + } + + public GeofencePolygon(String wkt) throws ParseException { + fromWkt(wkt); + } + + private ArrayList coordinates; + + private double[] constant; + private double[] multiple; + + private boolean needNormalize = false; + + private void precalc() { + if (coordinates == null) { + return; + } + + int polyCorners = coordinates.size(); + int i; + int j = polyCorners - 1; + + if (constant != null) { + constant = null; + } + if (multiple != null) { + multiple = null; + } + + constant = new double[polyCorners]; + multiple = new double[polyCorners]; + + boolean hasNegative = false; + boolean hasPositive = false; + for (i = 0; i < polyCorners; i++) { + if (coordinates.get(i).getLon() > 90) { + hasPositive = true; + } else if (coordinates.get(i).getLon() < -90) { + hasNegative = true; + } + } + needNormalize = hasPositive && hasNegative; + + for (i = 0; i < polyCorners; j = i++) { + if (normalizeLon(coordinates.get(j).getLon()) == normalizeLon(coordinates.get(i).getLon())) { + constant[i] = coordinates.get(i).getLat(); + multiple[i] = 0; + } else { + constant[i] = coordinates.get(i).getLat() + - (normalizeLon(coordinates.get(i).getLon()) * coordinates.get(j).getLat()) + / (normalizeLon(coordinates.get(j).getLon()) - normalizeLon(coordinates.get(i).getLon())) + + (normalizeLon(coordinates.get(i).getLon()) * coordinates.get(i).getLat()) + / (normalizeLon(coordinates.get(j).getLon()) - normalizeLon(coordinates.get(i).getLon())); + multiple[i] = (coordinates.get(j).getLat() - coordinates.get(i).getLat()) + / (normalizeLon(coordinates.get(j).getLon()) - normalizeLon(coordinates.get(i).getLon())); + } + } + } + + private double normalizeLon(double lon) { + if (needNormalize && lon < -90) { + return lon + 360; + } + return lon; + } + + @Override + public boolean containsPoint(double latitude, double longitude) { + + int polyCorners = coordinates.size(); + int i; + int j = polyCorners - 1; + double longitudeNorm = normalizeLon(longitude); + boolean oddNodes = false; + + for (i = 0; i < polyCorners; j = i++) { + if (normalizeLon(coordinates.get(i).getLon()) < longitudeNorm + && normalizeLon(coordinates.get(j).getLon()) >= longitudeNorm + || normalizeLon(coordinates.get(j).getLon()) < longitudeNorm + && normalizeLon(coordinates.get(i).getLon()) >= longitudeNorm) { + oddNodes ^= longitudeNorm * multiple[i] + constant[i] < latitude; + } + } + return oddNodes; + } + + @Override + public String toWkt() { + StringBuilder buf = new StringBuilder(); + buf.append("POLYGON (("); + for (Coordinate coordinate : coordinates) { + buf.append(String.valueOf(coordinate.getLat())); + buf.append(" "); + buf.append(String.valueOf(coordinate.getLon())); + buf.append(", "); + } + return buf.substring(0, buf.length() - 2) + "))"; + } + + @Override + public void fromWkt(String wkt) throws ParseException { + if (coordinates == null) { + coordinates = new ArrayList<>(); + } else { + coordinates.clear(); + } + + if (!wkt.startsWith("POLYGON")) { + throw new ParseException("Mismatch geometry type", 0); + } + String content = wkt.substring(wkt.indexOf("((") + 2, wkt.indexOf("))")); + if (content.isEmpty()) { + throw new ParseException("No content", 0); + } + String[] commaTokens = content.split(","); + if (commaTokens.length < 3) { + throw new ParseException("Not valid content", 0); + } + + for (String commaToken : commaTokens) { + String[] tokens = commaToken.trim().split("\\s"); + if (tokens.length != 2) { + throw new ParseException("Here must be two coordinates: " + commaToken, 0); + } + Coordinate coordinate = new Coordinate(); + try { + coordinate.setLat(Double.parseDouble(tokens[0])); + } catch (NumberFormatException e) { + throw new ParseException(tokens[0] + " is not a double", 0); + } + try { + coordinate.setLon(Double.parseDouble(tokens[1])); + } catch (NumberFormatException e) { + throw new ParseException(tokens[1] + " is not a double", 0); + } + coordinates.add(coordinate); + } + precalc(); + } + +} diff --git a/src/main/java/org/traccar/geofence/GeofencePolyline.java b/src/main/java/org/traccar/geofence/GeofencePolyline.java new file mode 100644 index 000000000..d84f512e3 --- /dev/null +++ b/src/main/java/org/traccar/geofence/GeofencePolyline.java @@ -0,0 +1,107 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.geofence; + +import java.text.ParseException; +import java.util.ArrayList; + +import org.traccar.helper.DistanceCalculator; + +public class GeofencePolyline extends GeofenceGeometry { + + private ArrayList coordinates; + private double distance; + + public GeofencePolyline() { + } + + public GeofencePolyline(String wkt, double distance) throws ParseException { + fromWkt(wkt); + this.distance = distance; + } + + @Override + public boolean containsPoint(double latitude, double longitude) { + for (int i = 1; i < coordinates.size(); i++) { + if (DistanceCalculator.distanceToLine( + latitude, longitude, coordinates.get(i - 1).getLat(), coordinates.get(i - 1).getLon(), + coordinates.get(i).getLat(), coordinates.get(i).getLon()) <= distance) { + return true; + } + } + return false; + } + + @Override + public String toWkt() { + StringBuilder buf = new StringBuilder(); + buf.append("LINESTRING ("); + for (Coordinate coordinate : coordinates) { + buf.append(String.valueOf(coordinate.getLat())); + buf.append(" "); + buf.append(String.valueOf(coordinate.getLon())); + buf.append(", "); + } + return buf.substring(0, buf.length() - 2) + ")"; + } + + @Override + public void fromWkt(String wkt) throws ParseException { + if (coordinates == null) { + coordinates = new ArrayList<>(); + } else { + coordinates.clear(); + } + + if (!wkt.startsWith("LINESTRING")) { + throw new ParseException("Mismatch geometry type", 0); + } + String content = wkt.substring(wkt.indexOf("(") + 1, wkt.indexOf(")")); + if (content.isEmpty()) { + throw new ParseException("No content", 0); + } + String[] commaTokens = content.split(","); + if (commaTokens.length < 2) { + throw new ParseException("Not valid content", 0); + } + + for (String commaToken : commaTokens) { + String[] tokens = commaToken.trim().split("\\s"); + if (tokens.length != 2) { + throw new ParseException("Here must be two coordinates: " + commaToken, 0); + } + Coordinate coordinate = new Coordinate(); + try { + coordinate.setLat(Double.parseDouble(tokens[0])); + } catch (NumberFormatException e) { + throw new ParseException(tokens[0] + " is not a double", 0); + } + try { + coordinate.setLon(Double.parseDouble(tokens[1])); + } catch (NumberFormatException e) { + throw new ParseException(tokens[1] + " is not a double", 0); + } + coordinates.add(coordinate); + } + + } + + public void setDistance(double distance) { + this.distance = distance; + } + +} diff --git a/src/main/java/org/traccar/geolocation/GeolocationException.java b/src/main/java/org/traccar/geolocation/GeolocationException.java new file mode 100644 index 000000000..5847cc807 --- /dev/null +++ b/src/main/java/org/traccar/geolocation/GeolocationException.java @@ -0,0 +1,24 @@ +/* + * Copyright 2016 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. + * 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.geolocation; + +public class GeolocationException extends RuntimeException { + + public GeolocationException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/traccar/geolocation/GeolocationProvider.java b/src/main/java/org/traccar/geolocation/GeolocationProvider.java new file mode 100644 index 000000000..d9dec6bbb --- /dev/null +++ b/src/main/java/org/traccar/geolocation/GeolocationProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015 - 2016 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. + * 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.geolocation; + +import org.traccar.model.Network; + +public interface GeolocationProvider { + + interface LocationProviderCallback { + + void onSuccess(double latitude, double longitude, double accuracy); + + void onFailure(Throwable e); + + } + + void getLocation(Network network, LocationProviderCallback callback); + +} diff --git a/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java b/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java new file mode 100644 index 000000000..5901b47cd --- /dev/null +++ b/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright 2016 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. + * 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.geolocation; + +public class GoogleGeolocationProvider extends UniversalGeolocationProvider { + + private static final String URL = "https://www.googleapis.com/geolocation/v1/geolocate"; + + public GoogleGeolocationProvider(String key) { + super(URL, key); + } + +} diff --git a/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java b/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java new file mode 100644 index 000000000..c6a73a52b --- /dev/null +++ b/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright 2015 - 2016 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. + * 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.geolocation; + +public class MozillaGeolocationProvider extends UniversalGeolocationProvider { + + private static final String URL = "https://location.services.mozilla.com/v1/geolocate"; + + public MozillaGeolocationProvider(String key) { + super(URL, key != null ? key : "test"); + } + +} diff --git a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java new file mode 100644 index 000000000..768aaf6a2 --- /dev/null +++ b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java @@ -0,0 +1,68 @@ +/* + * 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. + * 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.geolocation; + +import org.traccar.Context; +import org.traccar.model.CellTower; +import org.traccar.model.Network; + +import javax.json.JsonObject; +import javax.ws.rs.client.InvocationCallback; + +public class OpenCellIdGeolocationProvider implements GeolocationProvider { + + private String url; + + public OpenCellIdGeolocationProvider(String key) { + this("http://opencellid.org/cell/get", key); + } + + public OpenCellIdGeolocationProvider(String url, String key) { + this.url = url + "?format=json&mcc=%d&mnc=%d&lac=%d&cellid=%d&key=" + key; + } + + @Override + public void getLocation(Network network, final LocationProviderCallback callback) { + if (network.getCellTowers() != null && !network.getCellTowers().isEmpty()) { + + CellTower cellTower = network.getCellTowers().iterator().next(); + String request = String.format(url, cellTower.getMobileCountryCode(), cellTower.getMobileNetworkCode(), + cellTower.getLocationAreaCode(), cellTower.getCellId()); + + Context.getClient().target(request).request().async().get(new InvocationCallback() { + @Override + public void completed(JsonObject json) { + if (json.containsKey("lat") && json.containsKey("lon")) { + callback.onSuccess( + json.getJsonNumber("lat").doubleValue(), + json.getJsonNumber("lon").doubleValue(), 0); + } else { + callback.onFailure(new GeolocationException("Coordinates are missing")); + } + } + + @Override + public void failed(Throwable throwable) { + callback.onFailure(throwable); + } + }); + + } else { + callback.onFailure(new GeolocationException("No network information")); + } + } + +} diff --git a/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java b/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java new file mode 100644 index 000000000..f71620d8a --- /dev/null +++ b/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 - 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. + * 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.geolocation; + +import org.traccar.Context; +import org.traccar.model.Network; + +import javax.json.JsonObject; +import javax.ws.rs.client.AsyncInvoker; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.InvocationCallback; + +public class UniversalGeolocationProvider implements GeolocationProvider { + + private String url; + + public UniversalGeolocationProvider(String url, String key) { + this.url = url + "?key=" + key; + } + + @Override + public void getLocation(Network network, final LocationProviderCallback callback) { + AsyncInvoker invoker = Context.getClient().target(url).request().async(); + invoker.post(Entity.json(network), new InvocationCallback() { + @Override + public void completed(JsonObject json) { + if (json.containsKey("error")) { + callback.onFailure(new GeolocationException(json.getJsonObject("error").getString("message"))); + } else { + JsonObject location = json.getJsonObject("location"); + callback.onSuccess( + location.getJsonNumber("lat").doubleValue(), + location.getJsonNumber("lng").doubleValue(), + json.getJsonNumber("accuracy").doubleValue()); + } + } + + @Override + public void failed(Throwable throwable) { + callback.onFailure(throwable); + } + }); + } + +} diff --git a/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java b/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java new file mode 100644 index 000000000..963bcb688 --- /dev/null +++ b/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java @@ -0,0 +1,111 @@ +/* + * Copyright 2017 - 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. + * 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.geolocation; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.traccar.Context; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.WifiAccessPoint; + +import javax.json.JsonObject; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.InvocationCallback; +import java.util.Collection; + +public class UnwiredGeolocationProvider implements GeolocationProvider { + + private String url; + private String key; + + private ObjectMapper objectMapper; + + private abstract static class NetworkMixIn { + @JsonProperty("mcc") + abstract Integer getHomeMobileCountryCode(); + @JsonProperty("mnc") + abstract Integer getHomeMobileNetworkCode(); + @JsonProperty("radio") + abstract String getRadioType(); + @JsonIgnore + abstract String getCarrier(); + @JsonIgnore + abstract Boolean getConsiderIp(); + @JsonProperty("cells") + abstract Collection getCellTowers(); + @JsonProperty("wifi") + abstract Collection getWifiAccessPoints(); + } + + private abstract static class CellTowerMixIn { + @JsonProperty("radio") + abstract String getRadioType(); + @JsonProperty("mcc") + abstract Integer getMobileCountryCode(); + @JsonProperty("mnc") + abstract Integer getMobileNetworkCode(); + @JsonProperty("lac") + abstract Integer getLocationAreaCode(); + @JsonProperty("cid") + abstract Long getCellId(); + } + + private abstract static class WifiAccessPointMixIn { + @JsonProperty("bssid") + abstract String getMacAddress(); + @JsonProperty("signal") + abstract Integer getSignalStrength(); + } + + public UnwiredGeolocationProvider(String url, String key) { + this.url = url; + this.key = key; + + objectMapper = new ObjectMapper(); + objectMapper.addMixIn(Network.class, NetworkMixIn.class); + objectMapper.addMixIn(CellTower.class, CellTowerMixIn.class); + objectMapper.addMixIn(WifiAccessPoint.class, WifiAccessPointMixIn.class); + } + + @Override + public void getLocation(Network network, final LocationProviderCallback callback) { + ObjectNode json = objectMapper.valueToTree(network); + json.put("token", key); + + Context.getClient().target(url).request().async().post(Entity.json(json), new InvocationCallback() { + @Override + public void completed(JsonObject json) { + if (json.getString("status").equals("error")) { + callback.onFailure(new GeolocationException(json.getString("message"))); + } else { + callback.onSuccess( + json.getJsonNumber("lat").doubleValue(), + json.getJsonNumber("lon").doubleValue(), + json.getJsonNumber("accuracy").doubleValue()); + } + } + + @Override + public void failed(Throwable throwable) { + callback.onFailure(throwable); + } + }); + } + +} diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java new file mode 100644 index 000000000..153da29b9 --- /dev/null +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -0,0 +1,140 @@ +/* + * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import io.netty.channel.ChannelHandler; +import org.apache.commons.jexl2.JexlEngine; +import org.apache.commons.jexl2.JexlException; +import org.apache.commons.jexl2.MapContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseDataHandler; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.AttributesManager; +import org.traccar.database.IdentityManager; +import org.traccar.model.Attribute; +import org.traccar.model.Device; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class ComputedAttributesHandler extends BaseDataHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(ComputedAttributesHandler.class); + + private final IdentityManager identityManager; + private final AttributesManager attributesManager; + + private final JexlEngine engine; + + private final boolean includeDeviceAttributes; + + public ComputedAttributesHandler( + Config config, IdentityManager identityManager, AttributesManager attributesManager) { + this.identityManager = identityManager; + this.attributesManager = attributesManager; + engine = new JexlEngine(); + engine.setStrict(true); + engine.setFunctions(Collections.singletonMap("math", Math.class)); + includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES); + } + + private MapContext prepareContext(Position position) { + MapContext result = new MapContext(); + if (includeDeviceAttributes) { + Device device = identityManager.getById(position.getDeviceId()); + if (device != null) { + for (Object key : device.getAttributes().keySet()) { + result.set((String) key, device.getAttributes().get(key)); + } + } + } + Set methods = new HashSet<>(Arrays.asList(position.getClass().getMethods())); + methods.removeAll(Arrays.asList(Object.class.getMethods())); + for (Method method : methods) { + if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { + String name = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4); + + try { + if (!method.getReturnType().equals(Map.class)) { + result.set(name, method.invoke(position)); + } else { + for (Object key : ((Map) method.invoke(position)).keySet()) { + result.set((String) key, ((Map) method.invoke(position)).get(key)); + } + } + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Attribute reflection error", error); + } + } + } + return result; + } + + /** + * @deprecated logic needs to be extracted to be used in API resource + */ + @Deprecated + public Object computeAttribute(Attribute attribute, Position position) throws JexlException { + return engine.createExpression(attribute.getExpression()).evaluate(prepareContext(position)); + } + + @Override + protected Position handlePosition(Position position) { + Collection attributes = attributesManager.getItems( + attributesManager.getAllDeviceItems(position.getDeviceId())); + for (Attribute attribute : attributes) { + if (attribute.getAttribute() != null) { + Object result = null; + try { + result = computeAttribute(attribute, position); + } catch (JexlException error) { + LOGGER.warn("Attribute computation error", error); + } + if (result != null) { + try { + switch (attribute.getType()) { + case "number": + Number numberValue = (Number) result; + position.getAttributes().put(attribute.getAttribute(), numberValue); + break; + case "boolean": + Boolean booleanValue = (Boolean) result; + position.getAttributes().put(attribute.getAttribute(), booleanValue); + break; + default: + position.getAttributes().put(attribute.getAttribute(), result.toString()); + } + } catch (ClassCastException error) { + LOGGER.warn("Attribute cast error", error); + } + } + } + } + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java new file mode 100644 index 000000000..6a0966d33 --- /dev/null +++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java @@ -0,0 +1,53 @@ +/* + * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler; + +import io.netty.channel.ChannelHandler; +import org.traccar.BaseDataHandler; +import org.traccar.database.IdentityManager; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class CopyAttributesHandler extends BaseDataHandler { + + private IdentityManager identityManager; + + public CopyAttributesHandler(IdentityManager identityManager) { + this.identityManager = identityManager; + } + + @Override + protected Position handlePosition(Position position) { + String attributesString = identityManager.lookupAttributeString( + position.getDeviceId(), "processing.copyAttributes", "", true); + if (attributesString.isEmpty()) { + attributesString = Position.KEY_DRIVER_UNIQUE_ID; + } else { + attributesString += "," + Position.KEY_DRIVER_UNIQUE_ID; + } + Position last = identityManager.getLastPosition(position.getDeviceId()); + if (last != null) { + for (String attribute : attributesString.split("[ ,]")) { + if (last.getAttributes().containsKey(attribute) && !position.getAttributes().containsKey(attribute)) { + position.getAttributes().put(attribute, last.getAttributes().get(attribute)); + } + } + } + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/DefaultDataHandler.java b/src/main/java/org/traccar/handler/DefaultDataHandler.java new file mode 100644 index 000000000..9d8ea044d --- /dev/null +++ b/src/main/java/org/traccar/handler/DefaultDataHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015 - 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. + * 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.handler; + +import io.netty.channel.ChannelHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseDataHandler; +import org.traccar.database.DataManager; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class DefaultDataHandler extends BaseDataHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDataHandler.class); + + private final DataManager dataManager; + + public DefaultDataHandler(DataManager dataManager) { + this.dataManager = dataManager; + } + + @Override + protected Position handlePosition(Position position) { + + try { + dataManager.addObject(position); + } catch (Exception error) { + LOGGER.warn("Failed to store position", error); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java new file mode 100644 index 000000000..a336a884e --- /dev/null +++ b/src/main/java/org/traccar/handler/DistanceHandler.java @@ -0,0 +1,82 @@ +/* + * Copyright 2015 Amila Silva + * Copyright 2016 - 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. + * 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.handler; + +import io.netty.channel.ChannelHandler; +import org.traccar.BaseDataHandler; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.IdentityManager; +import org.traccar.helper.DistanceCalculator; +import org.traccar.model.Position; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +@ChannelHandler.Sharable +public class DistanceHandler extends BaseDataHandler { + + private final IdentityManager identityManager; + + private final boolean filter; + private final int coordinatesMinError; + private final int coordinatesMaxError; + + public DistanceHandler(Config config, IdentityManager identityManager) { + this.identityManager = identityManager; + this.filter = config.getBoolean(Keys.COORDINATES_FILTER); + this.coordinatesMinError = config.getInteger(Keys.COORDINATES_MIN_ERROR); + this.coordinatesMaxError = config.getInteger(Keys.COORDINATES_MAX_ERROR); + } + + @Override + protected Position handlePosition(Position position) { + + double distance = 0.0; + if (position.getAttributes().containsKey(Position.KEY_DISTANCE)) { + distance = position.getDouble(Position.KEY_DISTANCE); + } + double totalDistance = 0.0; + + Position last = identityManager != null ? identityManager.getLastPosition(position.getDeviceId()) : null; + if (last != null) { + totalDistance = last.getDouble(Position.KEY_TOTAL_DISTANCE); + if (!position.getAttributes().containsKey(Position.KEY_DISTANCE)) { + distance = DistanceCalculator.distance( + position.getLatitude(), position.getLongitude(), + last.getLatitude(), last.getLongitude()); + distance = BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); + } + if (filter && last.getValid() && last.getLatitude() != 0 && last.getLongitude() != 0) { + boolean satisfiesMin = coordinatesMinError == 0 || distance > coordinatesMinError; + boolean satisfiesMax = coordinatesMaxError == 0 + || distance < coordinatesMaxError || position.getValid(); + if (!satisfiesMin || !satisfiesMax) { + position.setLatitude(last.getLatitude()); + position.setLongitude(last.getLongitude()); + distance = 0; + } + } + } + position.set(Position.KEY_DISTANCE, distance); + totalDistance = BigDecimal.valueOf(totalDistance + distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); + position.set(Position.KEY_TOTAL_DISTANCE, totalDistance); + + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java new file mode 100644 index 000000000..92da84e6b --- /dev/null +++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler; + +import io.netty.channel.ChannelHandler; +import org.traccar.BaseDataHandler; +import org.traccar.database.IdentityManager; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class EngineHoursHandler extends BaseDataHandler { + + private final IdentityManager identityManager; + + public EngineHoursHandler(IdentityManager identityManager) { + this.identityManager = identityManager; + } + + @Override + protected Position handlePosition(Position position) { + if (!position.getAttributes().containsKey(Position.KEY_HOURS)) { + Position last = identityManager.getLastPosition(position.getDeviceId()); + if (last != null) { + long hours = last.getLong(Position.KEY_HOURS); + if (last.getBoolean(Position.KEY_IGNITION) && position.getBoolean(Position.KEY_IGNITION)) { + hours += position.getFixTime().getTime() - last.getFixTime().getTime(); + } + if (hours != 0) { + position.set(Position.KEY_HOURS, hours); + } + } + } + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java new file mode 100644 index 000000000..dceaede01 --- /dev/null +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -0,0 +1,206 @@ +/* + * Copyright 2014 - 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. + * 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.handler; + +import io.netty.channel.ChannelHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseDataHandler; +import org.traccar.Context; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class FilterHandler extends BaseDataHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(FilterHandler.class); + + private boolean filterInvalid; + private boolean filterZero; + private boolean filterDuplicate; + private long filterFuture; + private boolean filterApproximate; + private int filterAccuracy; + private boolean filterStatic; + private int filterDistance; + private int filterMaxSpeed; + private long filterMinPeriod; + private long skipLimit; + private boolean skipAttributes; + + public FilterHandler(Config config) { + filterInvalid = config.getBoolean(Keys.FILTER_INVALID); + filterZero = config.getBoolean(Keys.FILTER_ZERO); + filterDuplicate = config.getBoolean(Keys.FILTER_DUPLICATE); + filterFuture = config.getLong(Keys.FILTER_FUTURE) * 1000; + filterAccuracy = config.getInteger(Keys.FILTER_ACCURACY); + filterApproximate = config.getBoolean(Keys.FILTER_APPROXIMATE); + filterStatic = config.getBoolean(Keys.FILTER_STATIC); + filterDistance = config.getInteger(Keys.FILTER_DISTANCE); + filterMaxSpeed = config.getInteger(Keys.FILTER_MAX_SPEED); + filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000; + skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000; + skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE); + } + + private boolean filterInvalid(Position position) { + return filterInvalid && (!position.getValid() + || position.getLatitude() > 90 || position.getLongitude() > 180 + || position.getLatitude() < -90 || position.getLongitude() < -180); + } + + private boolean filterZero(Position position) { + return filterZero && position.getLatitude() == 0.0 && position.getLongitude() == 0.0; + } + + private boolean filterDuplicate(Position position, Position last) { + if (filterDuplicate && last != null && position.getFixTime().equals(last.getFixTime())) { + for (String key : position.getAttributes().keySet()) { + if (!last.getAttributes().containsKey(key)) { + return false; + } + } + return true; + } + return false; + } + + private boolean filterFuture(Position position) { + return filterFuture != 0 && position.getFixTime().getTime() > System.currentTimeMillis() + filterFuture; + } + + private boolean filterAccuracy(Position position) { + return filterAccuracy != 0 && position.getAccuracy() > filterAccuracy; + } + + private boolean filterApproximate(Position position) { + return filterApproximate && position.getBoolean(Position.KEY_APPROXIMATE); + } + + private boolean filterStatic(Position position) { + return filterStatic && position.getSpeed() == 0.0; + } + + private boolean filterDistance(Position position, Position last) { + if (filterDistance != 0 && last != null) { + return position.getDouble(Position.KEY_DISTANCE) < filterDistance; + } + return false; + } + + private boolean filterMaxSpeed(Position position, Position last) { + if (filterMaxSpeed != 0 && last != null) { + double distance = position.getDouble(Position.KEY_DISTANCE); + double time = position.getFixTime().getTime() - last.getFixTime().getTime(); + return UnitsConverter.knotsFromMps(distance / (time / 1000)) > filterMaxSpeed; + } + return false; + } + + private boolean filterMinPeriod(Position position, Position last) { + if (filterMinPeriod != 0 && last != null) { + long time = position.getFixTime().getTime() - last.getFixTime().getTime(); + return time > 0 && time < filterMinPeriod; + } + return false; + } + + private boolean skipLimit(Position position, Position last) { + if (skipLimit != 0 && last != null) { + return (position.getServerTime().getTime() - last.getServerTime().getTime()) > skipLimit; + } + return false; + } + + private boolean skipAttributes(Position position) { + if (skipAttributes) { + String attributesString = Context.getIdentityManager().lookupAttributeString( + position.getDeviceId(), "filter.skipAttributes", "", true); + for (String attribute : attributesString.split("[ ,]")) { + if (position.getAttributes().containsKey(attribute)) { + return true; + } + } + } + return false; + } + + private boolean filter(Position position) { + + StringBuilder filterType = new StringBuilder(); + + Position last = null; + if (Context.getIdentityManager() != null) { + last = Context.getIdentityManager().getLastPosition(position.getDeviceId()); + } + + if (filterInvalid(position)) { + filterType.append("Invalid "); + } + if (filterZero(position)) { + filterType.append("Zero "); + } + if (filterDuplicate(position, last) && !skipLimit(position, last) && !skipAttributes(position)) { + filterType.append("Duplicate "); + } + if (filterFuture(position)) { + filterType.append("Future "); + } + if (filterAccuracy(position)) { + filterType.append("Accuracy "); + } + if (filterApproximate(position)) { + filterType.append("Approximate "); + } + if (filterStatic(position) && !skipLimit(position, last) && !skipAttributes(position)) { + filterType.append("Static "); + } + if (filterDistance(position, last) && !skipLimit(position, last) && !skipAttributes(position)) { + filterType.append("Distance "); + } + if (filterMaxSpeed(position, last)) { + filterType.append("MaxSpeed "); + } + if (filterMinPeriod(position, last)) { + filterType.append("MinPeriod "); + } + + if (filterType.length() > 0) { + + StringBuilder message = new StringBuilder(); + message.append("Position filtered by "); + message.append(filterType.toString()); + message.append("filters from device: "); + message.append(Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId()); + + LOGGER.info(message.toString()); + return true; + } + + return false; + } + + @Override + protected Position handlePosition(Position position) { + if (filter(position)) { + return null; + } + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/GeocoderHandler.java b/src/main/java/org/traccar/handler/GeocoderHandler.java new file mode 100644 index 000000000..b96f01b3a --- /dev/null +++ b/src/main/java/org/traccar/handler/GeocoderHandler.java @@ -0,0 +1,94 @@ +/* + * Copyright 2012 - 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. + * 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.handler; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.IdentityManager; +import org.traccar.database.StatisticsManager; +import org.traccar.geocoder.Geocoder; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class GeocoderHandler extends ChannelInboundHandlerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(GeocoderHandler.class); + + private final Geocoder geocoder; + private final IdentityManager identityManager; + private final StatisticsManager statisticsManager; + private final boolean ignorePositions; + private final boolean processInvalidPositions; + private final int geocoderReuseDistance; + + public GeocoderHandler( + Config config, Geocoder geocoder, IdentityManager identityManager, StatisticsManager statisticsManager) { + this.geocoder = geocoder; + this.identityManager = identityManager; + this.statisticsManager = statisticsManager; + ignorePositions = Context.getConfig().getBoolean(Keys.GEOCODER_IGNORE_POSITIONS); + processInvalidPositions = config.getBoolean(Keys.GEOCODER_PROCESS_INVALID_POSITIONS); + geocoderReuseDistance = config.getInteger(Keys.GEOCODER_REUSE_DISTANCE, 0); + } + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object message) { + if (message instanceof Position && !ignorePositions) { + final Position position = (Position) message; + if (processInvalidPositions || position.getValid()) { + if (geocoderReuseDistance != 0) { + Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + if (lastPosition != null && lastPosition.getAddress() != null + && position.getDouble(Position.KEY_DISTANCE) <= geocoderReuseDistance) { + position.setAddress(lastPosition.getAddress()); + ctx.fireChannelRead(position); + return; + } + } + + if (statisticsManager != null) { + statisticsManager.registerGeocoderRequest(); + } + + geocoder.getAddress(position.getLatitude(), position.getLongitude(), + new Geocoder.ReverseGeocoderCallback() { + @Override + public void onSuccess(String address) { + position.setAddress(address); + ctx.fireChannelRead(position); + } + + @Override + public void onFailure(Throwable e) { + LOGGER.warn("Geocoding failed", e); + ctx.fireChannelRead(position); + } + }); + } else { + ctx.fireChannelRead(position); + } + } else { + ctx.fireChannelRead(message); + } + } + +} diff --git a/src/main/java/org/traccar/handler/GeolocationHandler.java b/src/main/java/org/traccar/handler/GeolocationHandler.java new file mode 100644 index 000000000..c7b39e491 --- /dev/null +++ b/src/main/java/org/traccar/handler/GeolocationHandler.java @@ -0,0 +1,86 @@ +/* + * 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. + * 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.handler; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.StatisticsManager; +import org.traccar.geolocation.GeolocationProvider; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class GeolocationHandler extends ChannelInboundHandlerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(GeolocationHandler.class); + + private final GeolocationProvider geolocationProvider; + private final StatisticsManager statisticsManager; + private final boolean processInvalidPositions; + + public GeolocationHandler( + Config config, GeolocationProvider geolocationProvider, StatisticsManager statisticsManager) { + this.geolocationProvider = geolocationProvider; + this.statisticsManager = statisticsManager; + this.processInvalidPositions = config.getBoolean(Keys.GEOLOCATION_PROCESS_INVALID_POSITIONS); + } + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object message) { + if (message instanceof Position) { + final Position position = (Position) message; + if ((position.getOutdated() || processInvalidPositions && !position.getValid()) + && position.getNetwork() != null) { + if (statisticsManager != null) { + statisticsManager.registerGeolocationRequest(); + } + + geolocationProvider.getLocation(position.getNetwork(), + new GeolocationProvider.LocationProviderCallback() { + @Override + public void onSuccess(double latitude, double longitude, double accuracy) { + position.set(Position.KEY_APPROXIMATE, true); + position.setValid(true); + position.setFixTime(position.getDeviceTime()); + position.setLatitude(latitude); + position.setLongitude(longitude); + position.setAccuracy(accuracy); + position.setAltitude(0); + position.setSpeed(0); + position.setCourse(0); + position.set(Position.KEY_RSSI, 0); + ctx.fireChannelRead(position); + } + + @Override + public void onFailure(Throwable e) { + LOGGER.warn("Geolocation network error", e); + ctx.fireChannelRead(position); + } + }); + } else { + ctx.fireChannelRead(position); + } + } else { + ctx.fireChannelRead(message); + } + } + +} diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java new file mode 100644 index 000000000..aff3d8a64 --- /dev/null +++ b/src/main/java/org/traccar/handler/HemisphereHandler.java @@ -0,0 +1,60 @@ +/* + * Copyright 2016 - 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. + * 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.handler; + +import io.netty.channel.ChannelHandler; +import org.traccar.BaseDataHandler; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class HemisphereHandler extends BaseDataHandler { + + private int latitudeFactor; + private int longitudeFactor; + + public HemisphereHandler(Config config) { + String latitudeHemisphere = config.getString(Keys.LOCATION_LATITUDE_HEMISPHERE); + if (latitudeHemisphere != null) { + if (latitudeHemisphere.equalsIgnoreCase("N")) { + latitudeFactor = 1; + } else if (latitudeHemisphere.equalsIgnoreCase("S")) { + latitudeFactor = -1; + } + } + String longitudeHemisphere = config.getString(Keys.LOCATION_LATITUDE_HEMISPHERE); + if (longitudeHemisphere != null) { + if (longitudeHemisphere.equalsIgnoreCase("E")) { + longitudeFactor = 1; + } else if (longitudeHemisphere.equalsIgnoreCase("W")) { + longitudeFactor = -1; + } + } + } + + @Override + protected Position handlePosition(Position position) { + if (latitudeFactor != 0) { + position.setLatitude(Math.abs(position.getLatitude()) * latitudeFactor); + } + if (longitudeFactor != 0) { + position.setLongitude(Math.abs(position.getLongitude()) * longitudeFactor); + } + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/MotionHandler.java b/src/main/java/org/traccar/handler/MotionHandler.java new file mode 100644 index 000000000..e8051dd75 --- /dev/null +++ b/src/main/java/org/traccar/handler/MotionHandler.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler; + +import io.netty.channel.ChannelHandler; +import org.traccar.BaseDataHandler; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class MotionHandler extends BaseDataHandler { + + private double speedThreshold; + + public MotionHandler(double speedThreshold) { + this.speedThreshold = speedThreshold; + } + + @Override + protected Position handlePosition(Position position) { + if (!position.getAttributes().containsKey(Position.KEY_MOTION)) { + position.set(Position.KEY_MOTION, position.getSpeed() > speedThreshold); + } + return position; + } + +} diff --git a/src/main/java/org/traccar/handler/NetworkMessageHandler.java b/src/main/java/org/traccar/handler/NetworkMessageHandler.java new file mode 100644 index 000000000..b1d926bfa --- /dev/null +++ b/src/main/java/org/traccar/handler/NetworkMessageHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright 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. + * 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.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.DatagramPacket; +import org.traccar.NetworkMessage; + +import java.net.InetSocketAddress; + +public class NetworkMessageHandler extends ChannelDuplexHandler { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (ctx.channel() instanceof DatagramChannel) { + DatagramPacket packet = (DatagramPacket) msg; + ctx.fireChannelRead(new NetworkMessage(packet.content(), packet.sender())); + } else if (msg instanceof ByteBuf) { + ByteBuf buffer = (ByteBuf) msg; + ctx.fireChannelRead(new NetworkMessage(buffer, ctx.channel().remoteAddress())); + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { + if (msg instanceof NetworkMessage) { + NetworkMessage message = (NetworkMessage) msg; + if (ctx.channel() instanceof DatagramChannel) { + InetSocketAddress recipient = (InetSocketAddress) message.getRemoteAddress(); + InetSocketAddress sender = (InetSocketAddress) ctx.channel().localAddress(); + ctx.write(new DatagramPacket((ByteBuf) message.getMessage(), recipient, sender), promise); + } else { + ctx.write(message.getMessage(), promise); + } + } else { + ctx.write(msg, promise); + } + } + +} diff --git a/src/main/java/org/traccar/handler/OpenChannelHandler.java b/src/main/java/org/traccar/handler/OpenChannelHandler.java new file mode 100644 index 000000000..d09d617ab --- /dev/null +++ b/src/main/java/org/traccar/handler/OpenChannelHandler.java @@ -0,0 +1,42 @@ +/* + * Copyright 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. + * 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.handler; + +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.TrackerServer; + +public class OpenChannelHandler extends ChannelDuplexHandler { + + private final TrackerServer server; + + public OpenChannelHandler(TrackerServer server) { + this.server = server; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + super.channelActive(ctx); + server.getChannelGroup().add(ctx.channel()); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelInactive(ctx); + server.getChannelGroup().remove(ctx.channel()); + } + +} diff --git a/src/main/java/org/traccar/handler/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/RemoteAddressHandler.java new file mode 100644 index 000000000..c09b8c39a --- /dev/null +++ b/src/main/java/org/traccar/handler/RemoteAddressHandler.java @@ -0,0 +1,42 @@ +/* + * 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. + * 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.handler; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.traccar.model.Position; + +import java.net.InetSocketAddress; + +@ChannelHandler.Sharable +public class RemoteAddressHandler extends ChannelInboundHandlerAdapter { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + + InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); + String hostAddress = remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : null; + + if (msg instanceof Position) { + Position position = (Position) msg; + position.set(Position.KEY_IP, hostAddress); + } + + ctx.fireChannelRead(msg); + } + +} diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/StandardLoggingHandler.java new file mode 100644 index 000000000..88010458f --- /dev/null +++ b/src/main/java/org/traccar/handler/StandardLoggingHandler.java @@ -0,0 +1,81 @@ +/* + * Copyright 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. + * 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.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.NetworkMessage; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +public class StandardLoggingHandler extends ChannelDuplexHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(StandardLoggingHandler.class); + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + log(ctx, false, msg); + super.channelRead(ctx, msg); + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + log(ctx, true, msg); + super.write(ctx, msg, promise); + } + + public void log(ChannelHandlerContext ctx, boolean downstream, Object o) { + if (o instanceof NetworkMessage) { + NetworkMessage networkMessage = (NetworkMessage) o; + if (networkMessage.getMessage() instanceof ByteBuf) { + log(ctx, downstream, networkMessage.getRemoteAddress(), (ByteBuf) networkMessage.getMessage()); + } + } else if (o instanceof ByteBuf) { + log(ctx, downstream, ctx.channel().remoteAddress(), (ByteBuf) o); + } + } + + public void log(ChannelHandlerContext ctx, boolean downstream, SocketAddress remoteAddress, ByteBuf buf) { + StringBuilder message = new StringBuilder(); + + message.append("[").append(ctx.channel().id().asShortText()).append(": "); + message.append(((InetSocketAddress) ctx.channel().localAddress()).getPort()); + if (downstream) { + message.append(" > "); + } else { + message.append(" < "); + } + + if (remoteAddress instanceof InetSocketAddress) { + message.append(((InetSocketAddress) remoteAddress).getHostString()); + } else { + message.append("unknown"); + } + message.append("]"); + + message.append(" HEX: "); + message.append(ByteBufUtil.hexDump(buf)); + + LOGGER.info(message.toString()); + } + +} diff --git a/src/main/java/org/traccar/handler/events/AlertEventHandler.java b/src/main/java/org/traccar/handler/events/AlertEventHandler.java new file mode 100644 index 000000000..0b7c8d23e --- /dev/null +++ b/src/main/java/org/traccar/handler/events/AlertEventHandler.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 - 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. + * 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.handler.events; + +import java.util.Collections; +import java.util.Map; + +import io.netty.channel.ChannelHandler; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.IdentityManager; +import org.traccar.model.Event; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class AlertEventHandler extends BaseEventHandler { + + private final IdentityManager identityManager; + private final boolean ignoreDuplicateAlerts; + + public AlertEventHandler(Config config, IdentityManager identityManager) { + this.identityManager = identityManager; + ignoreDuplicateAlerts = config.getBoolean(Keys.EVENT_IGNORE_DUPLICATE_ALERTS); + } + + @Override + protected Map analyzePosition(Position position) { + Object alarm = position.getAttributes().get(Position.KEY_ALARM); + if (alarm != null) { + boolean ignoreAlert = false; + if (ignoreDuplicateAlerts) { + Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + if (lastPosition != null && alarm.equals(lastPosition.getAttributes().get(Position.KEY_ALARM))) { + ignoreAlert = true; + } + } + if (!ignoreAlert) { + Event event = new Event(Event.TYPE_ALARM, position.getDeviceId(), position.getId()); + event.set(Position.KEY_ALARM, (String) alarm); + return Collections.singletonMap(event, position); + } + } + return null; + } + +} diff --git a/src/main/java/org/traccar/handler/events/BaseEventHandler.java b/src/main/java/org/traccar/handler/events/BaseEventHandler.java new file mode 100644 index 000000000..41f677f6c --- /dev/null +++ b/src/main/java/org/traccar/handler/events/BaseEventHandler.java @@ -0,0 +1,38 @@ +/* + * Copyright 2016 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. + * 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.handler.events; + +import java.util.Map; + +import org.traccar.BaseDataHandler; +import org.traccar.Context; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public abstract class BaseEventHandler extends BaseDataHandler { + + @Override + protected Position handlePosition(Position position) { + Map events = analyzePosition(position); + if (events != null && Context.getNotificationManager() != null) { + Context.getNotificationManager().updateEvents(events); + } + return position; + } + + protected abstract Map analyzePosition(Position position); + +} diff --git a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java new file mode 100644 index 000000000..cfe676653 --- /dev/null +++ b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 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. + * 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.handler.events; + +import java.util.Collections; +import java.util.Map; + +import io.netty.channel.ChannelHandler; +import org.traccar.model.Event; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class CommandResultEventHandler extends BaseEventHandler { + + @Override + protected Map analyzePosition(Position position) { + Object commandResult = position.getAttributes().get(Position.KEY_RESULT); + if (commandResult != null) { + Event event = new Event(Event.TYPE_COMMAND_RESULT, position.getDeviceId(), position.getId()); + event.set(Position.KEY_RESULT, (String) commandResult); + return Collections.singletonMap(event, position); + } + return null; + } + +} diff --git a/src/main/java/org/traccar/handler/events/DriverEventHandler.java b/src/main/java/org/traccar/handler/events/DriverEventHandler.java new file mode 100644 index 000000000..994df93fa --- /dev/null +++ b/src/main/java/org/traccar/handler/events/DriverEventHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler.events; + +import java.util.Collections; +import java.util.Map; + +import io.netty.channel.ChannelHandler; +import org.traccar.database.IdentityManager; +import org.traccar.model.Event; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class DriverEventHandler extends BaseEventHandler { + + private final IdentityManager identityManager; + + public DriverEventHandler(IdentityManager identityManager) { + this.identityManager = identityManager; + } + + @Override + protected Map analyzePosition(Position position) { + if (!identityManager.isLatestPosition(position)) { + return null; + } + String driverUniqueId = position.getString(Position.KEY_DRIVER_UNIQUE_ID); + if (driverUniqueId != null) { + String oldDriverUniqueId = null; + Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + if (lastPosition != null) { + oldDriverUniqueId = lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); + } + if (!driverUniqueId.equals(oldDriverUniqueId)) { + Event event = new Event(Event.TYPE_DRIVER_CHANGED, position.getDeviceId(), position.getId()); + event.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId); + return Collections.singletonMap(event, position); + } + } + return null; + } + +} diff --git a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java new file mode 100644 index 000000000..59de61bba --- /dev/null +++ b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java @@ -0,0 +1,70 @@ +/* + * Copyright 2017 - 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. + * 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.handler.events; + +import io.netty.channel.ChannelHandler; +import org.traccar.database.IdentityManager; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Position; + +import java.util.Collections; +import java.util.Map; + +@ChannelHandler.Sharable +public class FuelDropEventHandler extends BaseEventHandler { + + public static final String ATTRIBUTE_FUEL_DROP_THRESHOLD = "fuelDropThreshold"; + + private final IdentityManager identityManager; + + public FuelDropEventHandler(IdentityManager identityManager) { + this.identityManager = identityManager; + } + + @Override + protected Map analyzePosition(Position position) { + + Device device = identityManager.getById(position.getDeviceId()); + if (device == null) { + return null; + } + if (!identityManager.isLatestPosition(position)) { + return null; + } + + double fuelDropThreshold = identityManager + .lookupAttributeDouble(device.getId(), ATTRIBUTE_FUEL_DROP_THRESHOLD, 0, false); + + if (fuelDropThreshold > 0) { + Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + if (position.getAttributes().containsKey(Position.KEY_FUEL_LEVEL) + && lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_FUEL_LEVEL)) { + + double drop = lastPosition.getDouble(Position.KEY_FUEL_LEVEL) + - position.getDouble(Position.KEY_FUEL_LEVEL); + if (drop >= fuelDropThreshold) { + Event event = new Event(Event.TYPE_DEVICE_FUEL_DROP, position.getDeviceId(), position.getId()); + event.set(ATTRIBUTE_FUEL_DROP_THRESHOLD, fuelDropThreshold); + return Collections.singletonMap(event, position); + } + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java new file mode 100644 index 000000000..067c97957 --- /dev/null +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -0,0 +1,89 @@ +/* + * Copyright 2016 - 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. + * 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.handler.events; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.netty.channel.ChannelHandler; +import org.traccar.database.CalendarManager; +import org.traccar.database.GeofenceManager; +import org.traccar.database.IdentityManager; +import org.traccar.model.Calendar; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class GeofenceEventHandler extends BaseEventHandler { + + private final IdentityManager identityManager; + private final GeofenceManager geofenceManager; + private final CalendarManager calendarManager; + + public GeofenceEventHandler( + IdentityManager identityManager, GeofenceManager geofenceManager, CalendarManager calendarManager) { + this.identityManager = identityManager; + this.geofenceManager = geofenceManager; + this.calendarManager = calendarManager; + } + + @Override + protected Map analyzePosition(Position position) { + Device device = identityManager.getById(position.getDeviceId()); + if (device == null) { + return null; + } + if (!identityManager.isLatestPosition(position) || !position.getValid()) { + return null; + } + + List currentGeofences = geofenceManager.getCurrentDeviceGeofences(position); + List oldGeofences = new ArrayList<>(); + if (device.getGeofenceIds() != null) { + oldGeofences.addAll(device.getGeofenceIds()); + } + List newGeofences = new ArrayList<>(currentGeofences); + newGeofences.removeAll(oldGeofences); + oldGeofences.removeAll(currentGeofences); + + device.setGeofenceIds(currentGeofences); + + Map events = new HashMap<>(); + for (long geofenceId : oldGeofences) { + long calendarId = geofenceManager.getById(geofenceId).getCalendarId(); + Calendar calendar = calendarId != 0 ? calendarManager.getById(calendarId) : null; + if (calendar == null || calendar.checkMoment(position.getFixTime())) { + Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position.getDeviceId(), position.getId()); + event.setGeofenceId(geofenceId); + events.put(event, position); + } + } + for (long geofenceId : newGeofences) { + long calendarId = geofenceManager.getById(geofenceId).getCalendarId(); + Calendar calendar = calendarId != 0 ? calendarManager.getById(calendarId) : null; + if (calendar == null || calendar.checkMoment(position.getFixTime())) { + Event event = new Event(Event.TYPE_GEOFENCE_ENTER, position.getDeviceId(), position.getId()); + event.setGeofenceId(geofenceId); + events.put(event, position); + } + } + return events; + } + +} diff --git a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java new file mode 100644 index 000000000..ec133bafc --- /dev/null +++ b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java @@ -0,0 +1,65 @@ +/* + * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler.events; + +import java.util.Collections; +import java.util.Map; + +import io.netty.channel.ChannelHandler; +import org.traccar.database.IdentityManager; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class IgnitionEventHandler extends BaseEventHandler { + + private final IdentityManager identityManager; + + public IgnitionEventHandler(IdentityManager identityManager) { + this.identityManager = identityManager; + } + + @Override + protected Map analyzePosition(Position position) { + Device device = identityManager.getById(position.getDeviceId()); + if (device == null || !identityManager.isLatestPosition(position)) { + return null; + } + + Map result = null; + + if (position.getAttributes().containsKey(Position.KEY_IGNITION)) { + boolean ignition = position.getBoolean(Position.KEY_IGNITION); + + Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + if (lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_IGNITION)) { + boolean oldIgnition = lastPosition.getBoolean(Position.KEY_IGNITION); + + if (ignition && !oldIgnition) { + result = Collections.singletonMap( + new Event(Event.TYPE_IGNITION_ON, position.getDeviceId(), position.getId()), position); + } else if (!ignition && oldIgnition) { + result = Collections.singletonMap( + new Event(Event.TYPE_IGNITION_OFF, position.getDeviceId(), position.getId()), position); + } + } + } + return result; + } + +} diff --git a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java new file mode 100644 index 000000000..93ae74142 --- /dev/null +++ b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler.events; + +import java.util.HashMap; +import java.util.Map; + +import io.netty.channel.ChannelHandler; +import org.traccar.database.IdentityManager; +import org.traccar.database.MaintenancesManager; +import org.traccar.model.Event; +import org.traccar.model.Maintenance; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class MaintenanceEventHandler extends BaseEventHandler { + + private final IdentityManager identityManager; + private final MaintenancesManager maintenancesManager; + + public MaintenanceEventHandler(IdentityManager identityManager, MaintenancesManager maintenancesManager) { + this.identityManager = identityManager; + this.maintenancesManager = maintenancesManager; + } + + @Override + protected Map analyzePosition(Position position) { + if (identityManager.getById(position.getDeviceId()) == null + || !identityManager.isLatestPosition(position)) { + return null; + } + + Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + if (lastPosition == null) { + return null; + } + + Map events = new HashMap<>(); + for (long maintenanceId : maintenancesManager.getAllDeviceItems(position.getDeviceId())) { + Maintenance maintenance = maintenancesManager.getById(maintenanceId); + if (maintenance.getPeriod() != 0) { + double oldValue = lastPosition.getDouble(maintenance.getType()); + double newValue = position.getDouble(maintenance.getType()); + if (oldValue != 0.0 && newValue != 0.0 + && (long) ((oldValue - maintenance.getStart()) / maintenance.getPeriod()) + < (long) ((newValue - maintenance.getStart()) / maintenance.getPeriod())) { + Event event = new Event(Event.TYPE_MAINTENANCE, position.getDeviceId(), position.getId()); + event.setMaintenanceId(maintenanceId); + event.set(maintenance.getType(), newValue); + events.put(event, position); + } + } + } + + return events; + } + +} diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java new file mode 100644 index 000000000..9ec02ccfb --- /dev/null +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -0,0 +1,135 @@ +/* + * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler.events; + +import java.util.Collections; +import java.util.Map; + +import io.netty.channel.ChannelHandler; +import org.traccar.database.DeviceManager; +import org.traccar.database.IdentityManager; +import org.traccar.model.Device; +import org.traccar.model.DeviceState; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.reports.ReportUtils; +import org.traccar.reports.model.TripsConfig; + +@ChannelHandler.Sharable +public class MotionEventHandler extends BaseEventHandler { + + private final IdentityManager identityManager; + private final DeviceManager deviceManager; + private final TripsConfig tripsConfig; + + public MotionEventHandler(IdentityManager identityManager, DeviceManager deviceManager, TripsConfig tripsConfig) { + this.identityManager = identityManager; + this.deviceManager = deviceManager; + this.tripsConfig = tripsConfig; + } + + private Map newEvent(DeviceState deviceState, boolean newMotion) { + String eventType = newMotion ? Event.TYPE_DEVICE_MOVING : Event.TYPE_DEVICE_STOPPED; + Position position = deviceState.getMotionPosition(); + Event event = new Event(eventType, position.getDeviceId(), position.getId()); + deviceState.setMotionState(newMotion); + deviceState.setMotionPosition(null); + return Collections.singletonMap(event, position); + } + + public Map updateMotionState(DeviceState deviceState) { + Map result = null; + if (deviceState.getMotionState() != null && deviceState.getMotionPosition() != null) { + boolean newMotion = !deviceState.getMotionState(); + Position motionPosition = deviceState.getMotionPosition(); + long currentTime = System.currentTimeMillis(); + long motionTime = motionPosition.getFixTime().getTime() + + (newMotion ? tripsConfig.getMinimalTripDuration() : tripsConfig.getMinimalParkingDuration()); + if (motionTime <= currentTime) { + result = newEvent(deviceState, newMotion); + } + } + return result; + } + + public Map updateMotionState(DeviceState deviceState, Position position) { + return updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION)); + } + + public Map updateMotionState(DeviceState deviceState, Position position, boolean newMotion) { + Map result = null; + Boolean oldMotion = deviceState.getMotionState(); + + long currentTime = position.getFixTime().getTime(); + if (newMotion != oldMotion) { + if (deviceState.getMotionPosition() == null) { + deviceState.setMotionPosition(position); + } + } else { + deviceState.setMotionPosition(null); + } + + Position motionPosition = deviceState.getMotionPosition(); + if (motionPosition != null) { + long motionTime = motionPosition.getFixTime().getTime(); + double distance = ReportUtils.calculateDistance(motionPosition, position, false); + Boolean ignition = null; + if (tripsConfig.getUseIgnition() + && position.getAttributes().containsKey(Position.KEY_IGNITION)) { + ignition = position.getBoolean(Position.KEY_IGNITION); + } + if (newMotion) { + if (motionTime + tripsConfig.getMinimalTripDuration() <= currentTime + || distance >= tripsConfig.getMinimalTripDistance()) { + result = newEvent(deviceState, newMotion); + } + } else { + if (motionTime + tripsConfig.getMinimalParkingDuration() <= currentTime + || ignition != null && !ignition) { + result = newEvent(deviceState, newMotion); + } + } + } + return result; + } + + @Override + protected Map analyzePosition(Position position) { + + long deviceId = position.getDeviceId(); + Device device = identityManager.getById(deviceId); + if (device == null) { + return null; + } + if (!identityManager.isLatestPosition(position) + || !tripsConfig.getProcessInvalidPositions() && !position.getValid()) { + return null; + } + + Map result = null; + DeviceState deviceState = deviceManager.getDeviceState(deviceId); + + if (deviceState.getMotionState() == null) { + deviceState.setMotionState(position.getBoolean(Position.KEY_MOTION)); + } else { + result = updateMotionState(deviceState, position); + } + deviceManager.setDeviceState(deviceId, deviceState); + return result; + } + +} diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java new file mode 100644 index 000000000..157bb64e0 --- /dev/null +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -0,0 +1,164 @@ +/* + * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.handler.events; + +import java.util.Collections; +import java.util.Map; + +import io.netty.channel.ChannelHandler; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.DeviceManager; +import org.traccar.database.GeofenceManager; +import org.traccar.model.Device; +import org.traccar.model.DeviceState; +import org.traccar.model.Event; +import org.traccar.model.Geofence; +import org.traccar.model.Position; + +@ChannelHandler.Sharable +public class OverspeedEventHandler extends BaseEventHandler { + + public static final String ATTRIBUTE_SPEED = "speed"; + public static final String ATTRIBUTE_SPEED_LIMIT = "speedLimit"; + + private final DeviceManager deviceManager; + private final GeofenceManager geofenceManager; + + private final boolean notRepeat; + private final long minimalDuration; + private final boolean preferLowest; + + public OverspeedEventHandler(Config config, DeviceManager deviceManager, GeofenceManager geofenceManager) { + this.deviceManager = deviceManager; + this.geofenceManager = geofenceManager; + notRepeat = config.getBoolean(Keys.EVENT_OVERSPEED_NOT_REPEAT); + minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000; + preferLowest = config.getBoolean(Keys.EVENT_OVERSPEED_PREFER_LOWEST); + } + + private Map newEvent(DeviceState deviceState, double speedLimit) { + Position position = deviceState.getOverspeedPosition(); + Event event = new Event(Event.TYPE_DEVICE_OVERSPEED, position.getDeviceId(), position.getId()); + event.set(ATTRIBUTE_SPEED, deviceState.getOverspeedPosition().getSpeed()); + event.set(ATTRIBUTE_SPEED_LIMIT, speedLimit); + event.setGeofenceId(deviceState.getOverspeedGeofenceId()); + deviceState.setOverspeedState(notRepeat); + deviceState.setOverspeedPosition(null); + deviceState.setOverspeedGeofenceId(0); + return Collections.singletonMap(event, position); + } + + public Map updateOverspeedState(DeviceState deviceState, double speedLimit) { + Map result = null; + if (deviceState.getOverspeedState() != null && !deviceState.getOverspeedState() + && deviceState.getOverspeedPosition() != null && speedLimit != 0) { + long currentTime = System.currentTimeMillis(); + Position overspeedPosition = deviceState.getOverspeedPosition(); + long overspeedTime = overspeedPosition.getFixTime().getTime(); + if (overspeedTime + minimalDuration <= currentTime) { + result = newEvent(deviceState, speedLimit); + } + } + return result; + } + + public Map updateOverspeedState( + DeviceState deviceState, Position position, double speedLimit, long geofenceId) { + Map result = null; + + Boolean oldOverspeed = deviceState.getOverspeedState(); + + long currentTime = position.getFixTime().getTime(); + boolean newOverspeed = position.getSpeed() > speedLimit; + if (newOverspeed && !oldOverspeed) { + if (deviceState.getOverspeedPosition() == null) { + deviceState.setOverspeedPosition(position); + deviceState.setOverspeedGeofenceId(geofenceId); + } + } else if (oldOverspeed && !newOverspeed) { + deviceState.setOverspeedState(false); + deviceState.setOverspeedPosition(null); + deviceState.setOverspeedGeofenceId(0); + } else { + deviceState.setOverspeedPosition(null); + deviceState.setOverspeedGeofenceId(0); + } + Position overspeedPosition = deviceState.getOverspeedPosition(); + if (overspeedPosition != null) { + long overspeedTime = overspeedPosition.getFixTime().getTime(); + if (newOverspeed && overspeedTime + minimalDuration <= currentTime) { + result = newEvent(deviceState, speedLimit); + } + } + return result; + } + + @Override + protected Map analyzePosition(Position position) { + + long deviceId = position.getDeviceId(); + Device device = deviceManager.getById(deviceId); + if (device == null) { + return null; + } + if (!deviceManager.isLatestPosition(position) || !position.getValid()) { + return null; + } + + double speedLimit = deviceManager.lookupAttributeDouble(deviceId, ATTRIBUTE_SPEED_LIMIT, 0, false); + + double geofenceSpeedLimit = 0; + long overspeedGeofenceId = 0; + + if (geofenceManager != null && device.getGeofenceIds() != null) { + for (long geofenceId : device.getGeofenceIds()) { + Geofence geofence = geofenceManager.getById(geofenceId); + if (geofence != null) { + double currentSpeedLimit = geofence.getDouble(ATTRIBUTE_SPEED_LIMIT); + if (currentSpeedLimit > 0 && geofenceSpeedLimit == 0 + || preferLowest && currentSpeedLimit < geofenceSpeedLimit + || !preferLowest && currentSpeedLimit > geofenceSpeedLimit) { + geofenceSpeedLimit = currentSpeedLimit; + overspeedGeofenceId = geofenceId; + } + } + } + } + if (geofenceSpeedLimit > 0) { + speedLimit = geofenceSpeedLimit; + } + + if (speedLimit == 0) { + return null; + } + + Map result = null; + DeviceState deviceState = deviceManager.getDeviceState(deviceId); + + if (deviceState.getOverspeedState() == null) { + deviceState.setOverspeedState(position.getSpeed() > speedLimit); + deviceState.setOverspeedGeofenceId(position.getSpeed() > speedLimit ? overspeedGeofenceId : 0); + } else { + result = updateOverspeedState(deviceState, position, speedLimit, overspeedGeofenceId); + } + + deviceManager.setDeviceState(deviceId, deviceState); + return result; + } + +} diff --git a/src/main/java/org/traccar/helper/BcdUtil.java b/src/main/java/org/traccar/helper/BcdUtil.java new file mode 100644 index 000000000..c87529e32 --- /dev/null +++ b/src/main/java/org/traccar/helper/BcdUtil.java @@ -0,0 +1,63 @@ +/* + * 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. + * 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.helper; + +import io.netty.buffer.ByteBuf; + +public final class BcdUtil { + + private BcdUtil() { + } + + public static int readInteger(ByteBuf buf, int digits) { + int result = 0; + + for (int i = 0; i < digits / 2; i++) { + int b = buf.readUnsignedByte(); + result *= 10; + result += b >>> 4; + result *= 10; + result += b & 0x0f; + } + + if (digits % 2 != 0) { + int b = buf.getUnsignedByte(buf.readerIndex()); + result *= 10; + result += b >>> 4; + } + + return result; + } + + public static double readCoordinate(ByteBuf buf) { + int b1 = buf.readUnsignedByte(); + int b2 = buf.readUnsignedByte(); + int b3 = buf.readUnsignedByte(); + int b4 = buf.readUnsignedByte(); + + double value = (b2 & 0xf) * 10 + (b3 >> 4); + value += (((b3 & 0xf) * 10 + (b4 >> 4)) * 10 + (b4 & 0xf)) / 1000.0; + value /= 60; + value += ((b1 >> 4 & 0x7) * 10 + (b1 & 0xf)) * 10 + (b2 >> 4); + + if ((b1 & 0x80) != 0) { + value = -value; + } + + return value; + } + +} diff --git a/src/main/java/org/traccar/helper/BitBuffer.java b/src/main/java/org/traccar/helper/BitBuffer.java new file mode 100644 index 000000000..f30a4557b --- /dev/null +++ b/src/main/java/org/traccar/helper/BitBuffer.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016 - 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. + * 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.helper; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +public class BitBuffer { + + private final ByteBuf buffer; + + private int writeByte; + private int writeCount; + + private int readByte; + private int readCount; + + public BitBuffer() { + buffer = Unpooled.buffer(); + } + + public BitBuffer(ByteBuf buffer) { + this.buffer = buffer; + } + + public void writeEncoded(byte[] bytes) { + for (byte b : bytes) { + b -= 48; + if (b > 40) { + b -= 8; + } + write(b); + } + } + + public void write(int b) { + if (writeCount == 0) { + writeByte |= b; + writeCount = 6; + } else { + int remaining = 8 - writeCount; + writeByte <<= remaining; + writeByte |= b >> (6 - remaining); + buffer.writeByte(writeByte); + writeByte = b & ((1 << (6 - remaining)) - 1); + writeCount = 6 - remaining; + } + } + + public int readUnsigned(int length) { + int result = 0; + + while (length > 0) { + if (readCount == 0) { + readByte = buffer.readUnsignedByte(); + readCount = 8; + } + if (readCount >= length) { + result <<= length; + result |= readByte >> (readCount - length); + readByte &= (1 << (readCount - length)) - 1; + readCount -= length; + length = 0; + } else { + result <<= readCount; + result |= readByte; + length -= readCount; + readByte = 0; + readCount = 0; + } + } + + return result; + } + + public int readSigned(int length) { + int result = readUnsigned(length); + int signBit = 1 << (length - 1); + if ((result & signBit) == 0) { + return result; + } else { + result &= signBit - 1; + result += ~(signBit - 1); + return result; + } + } + +} diff --git a/src/main/java/org/traccar/helper/BitUtil.java b/src/main/java/org/traccar/helper/BitUtil.java new file mode 100644 index 000000000..b6108edff --- /dev/null +++ b/src/main/java/org/traccar/helper/BitUtil.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015 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. + * 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.helper; + +public final class BitUtil { + + private BitUtil() { + } + + public static boolean check(long number, int index) { + return (number & (1 << index)) != 0; + } + + public static int between(int number, int from, int to) { + return (number >> from) & ((1 << to - from) - 1); + } + + public static int from(int number, int from) { + return number >> from; + } + + public static int to(int number, int to) { + return between(number, 0, to); + } + + public static long between(long number, int from, int to) { + return (number >> from) & ((1L << to - from) - 1L); + } + + public static long from(long number, int from) { + return number >> from; + } + + public static long to(long number, int to) { + return between(number, 0, to); + } + +} diff --git a/src/main/java/org/traccar/helper/BufferUtil.java b/src/main/java/org/traccar/helper/BufferUtil.java new file mode 100644 index 000000000..15c619ec5 --- /dev/null +++ b/src/main/java/org/traccar/helper/BufferUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.helper; + +import java.nio.charset.StandardCharsets; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; + +public final class BufferUtil { + + private BufferUtil() { + } + + public static int indexOf(String needle, ByteBuf haystack) { + ByteBuf needleBuffer = Unpooled.wrappedBuffer(needle.getBytes(StandardCharsets.US_ASCII)); + try { + return ByteBufUtil.indexOf(needleBuffer, haystack); + } finally { + needleBuffer.release(); + } + } + + public static int indexOf(String needle, ByteBuf haystack, int startIndex, int endIndex) { + ByteBuf wrappedHaystack = Unpooled.wrappedBuffer(haystack); + wrappedHaystack.readerIndex(startIndex - haystack.readerIndex()); + wrappedHaystack.writerIndex(endIndex - haystack.readerIndex()); + int result = indexOf(needle, wrappedHaystack); + return result < 0 ? result : haystack.readerIndex() + result; + } + +} diff --git a/src/main/java/org/traccar/helper/Checksum.java b/src/main/java/org/traccar/helper/Checksum.java new file mode 100644 index 000000000..adfa697c5 --- /dev/null +++ b/src/main/java/org/traccar/helper/Checksum.java @@ -0,0 +1,200 @@ +/* + * 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. + * 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.helper; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.zip.CRC32; + +public final class Checksum { + + private Checksum() { + } + + public static class Algorithm { + + private int poly; + private int init; + private boolean refIn; + private boolean refOut; + private int xorOut; + private int[] table; + + public Algorithm(int bits, int poly, int init, boolean refIn, boolean refOut, int xorOut) { + this.poly = poly; + this.init = init; + this.refIn = refIn; + this.refOut = refOut; + this.xorOut = xorOut; + this.table = bits == 8 ? initTable8() : initTable16(); + } + + private int[] initTable8() { + int[] table = new int[256]; + int crc; + for (int i = 0; i < 256; i++) { + crc = i; + for (int j = 0; j < 8; j++) { + boolean bit = (crc & 0x80) != 0; + crc <<= 1; + if (bit) { + crc ^= poly; + } + } + table[i] = crc & 0xFF; + } + return table; + } + + private int[] initTable16() { + int[] table = new int[256]; + int crc; + for (int i = 0; i < 256; i++) { + crc = i << 8; + for (int j = 0; j < 8; j++) { + boolean bit = (crc & 0x8000) != 0; + crc <<= 1; + if (bit) { + crc ^= poly; + } + } + table[i] = crc & 0xFFFF; + } + return table; + } + + } + + private static int reverse(int value, int bits) { + int result = 0; + for (int i = 0; i < bits; i++) { + result = (result << 1) | (value & 1); + value >>= 1; + } + return result; + } + + public static int crc8(Algorithm algorithm, ByteBuffer buf) { + int crc = algorithm.init; + while (buf.hasRemaining()) { + int b = buf.get() & 0xFF; + if (algorithm.refIn) { + b = reverse(b, 8); + } + crc = algorithm.table[(crc & 0xFF) ^ b]; + } + if (algorithm.refOut) { + crc = reverse(crc, 8); + } + return (crc ^ algorithm.xorOut) & 0xFF; + } + + public static int crc16(Algorithm algorithm, ByteBuffer buf) { + int crc = algorithm.init; + while (buf.hasRemaining()) { + int b = buf.get() & 0xFF; + if (algorithm.refIn) { + b = reverse(b, 8); + } + crc = (crc << 8) ^ algorithm.table[((crc >> 8) & 0xFF) ^ b]; + } + if (algorithm.refOut) { + crc = reverse(crc, 16); + } + return (crc ^ algorithm.xorOut) & 0xFFFF; + } + + public static final Algorithm CRC8_EGTS = new Algorithm(8, 0x31, 0xFF, false, false, 0x00); + public static final Algorithm CRC8_ROHC = new Algorithm(8, 0x07, 0xFF, true, true, 0x00); + + public static final Algorithm CRC16_IBM = new Algorithm(16, 0x8005, 0x0000, true, true, 0x0000); + public static final Algorithm CRC16_X25 = new Algorithm(16, 0x1021, 0xFFFF, true, true, 0xFFFF); + public static final Algorithm CRC16_MODBUS = new Algorithm(16, 0x8005, 0xFFFF, true, true, 0x0000); + public static final Algorithm CRC16_CCITT_FALSE = new Algorithm(16, 0x1021, 0xFFFF, false, false, 0x0000); + public static final Algorithm CRC16_KERMIT = new Algorithm(16, 0x1021, 0x0000, true, true, 0x0000); + public static final Algorithm CRC16_XMODEM = new Algorithm(16, 0x1021, 0x0000, false, false, 0x0000); + + public static int crc32(ByteBuffer buf) { + CRC32 checksum = new CRC32(); + while (buf.hasRemaining()) { + checksum.update(buf.get()); + } + return (int) checksum.getValue(); + } + + public static int xor(ByteBuffer buf) { + int checksum = 0; + while (buf.hasRemaining()) { + checksum ^= buf.get(); + } + return checksum; + } + + public static int xor(String string) { + byte checksum = 0; + for (byte b : string.getBytes(StandardCharsets.US_ASCII)) { + checksum ^= b; + } + return checksum; + } + + public static String nmea(String msg) { + int checksum = 0; + byte[] bytes = msg.getBytes(StandardCharsets.US_ASCII); + for (int i = 1; i < bytes.length; i++) { + checksum ^= bytes[i]; + } + return String.format("*%02x", checksum).toUpperCase(); + } + + public static int sum(ByteBuffer buf) { + byte checksum = 0; + while (buf.hasRemaining()) { + checksum += buf.get(); + } + return checksum; + } + + public static String sum(String msg) { + byte checksum = 0; + for (byte b : msg.getBytes(StandardCharsets.US_ASCII)) { + checksum += b; + } + return String.format("%02X", checksum).toUpperCase(); + } + + public static long luhn(long imei) { + long checksum = 0; + long remain = imei; + + for (int i = 0; remain != 0; i++) { + long digit = remain % 10; + + if (i % 2 == 0) { + digit *= 2; + if (digit >= 10) { + digit = 1 + (digit % 10); + } + } + + checksum += digit; + remain /= 10; + } + + return (10 - (checksum % 10)) % 10; + } + +} diff --git a/src/main/java/org/traccar/helper/DataConverter.java b/src/main/java/org/traccar/helper/DataConverter.java new file mode 100644 index 000000000..7abd4ae93 --- /dev/null +++ b/src/main/java/org/traccar/helper/DataConverter.java @@ -0,0 +1,47 @@ +/* + * Copyright 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. + * 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.helper; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.Hex; + +public final class DataConverter { + + private DataConverter() { + } + + public static byte[] parseHex(String string) { + try { + return Hex.decodeHex(string); + } catch (DecoderException e) { + throw new RuntimeException(e); + } + } + + public static String printHex(byte[] data) { + return Hex.encodeHexString(data); + } + + public static byte[] parseBase64(String string) { + return Base64.decodeBase64(string); + } + + public static String printBase64(byte[] data) { + return Base64.encodeBase64String(data); + } + +} diff --git a/src/main/java/org/traccar/helper/DateBuilder.java b/src/main/java/org/traccar/helper/DateBuilder.java new file mode 100644 index 000000000..6e1b779f0 --- /dev/null +++ b/src/main/java/org/traccar/helper/DateBuilder.java @@ -0,0 +1,126 @@ +/* + * Copyright 2015 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. + * 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.helper; + +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +public class DateBuilder { + + private Calendar calendar; + + public DateBuilder() { + this(TimeZone.getTimeZone("UTC")); + } + + public DateBuilder(Date time) { + this(time, TimeZone.getTimeZone("UTC")); + } + + public DateBuilder(TimeZone timeZone) { + this(new Date(0), timeZone); + } + + public DateBuilder(Date time, TimeZone timeZone) { + calendar = Calendar.getInstance(timeZone); + calendar.clear(); + calendar.setTimeInMillis(time.getTime()); + } + + public DateBuilder setYear(int year) { + if (year < 100) { + year += 2000; + } + calendar.set(Calendar.YEAR, year); + return this; + } + + public DateBuilder setMonth(int month) { + calendar.set(Calendar.MONTH, month - 1); + return this; + } + + public DateBuilder setDay(int day) { + calendar.set(Calendar.DAY_OF_MONTH, day); + return this; + } + + public DateBuilder setDate(int year, int month, int day) { + return setYear(year).setMonth(month).setDay(day); + } + + public DateBuilder setDateReverse(int day, int month, int year) { + return setDate(year, month, day); + } + + public DateBuilder setCurrentDate() { + Calendar now = Calendar.getInstance(calendar.getTimeZone()); + return setYear(now.get(Calendar.YEAR)).setMonth(now.get(Calendar.MONTH)).setDay(now.get(Calendar.DAY_OF_MONTH)); + } + + public DateBuilder setHour(int hour) { + calendar.set(Calendar.HOUR_OF_DAY, hour); + return this; + } + + public DateBuilder setMinute(int minute) { + calendar.set(Calendar.MINUTE, minute); + return this; + } + + public DateBuilder addMinute(int minute) { + calendar.add(Calendar.MINUTE, minute); + return this; + } + + public DateBuilder setSecond(int second) { + calendar.set(Calendar.SECOND, second); + return this; + } + + public DateBuilder addSeconds(long seconds) { + calendar.setTimeInMillis(calendar.getTimeInMillis() + seconds * 1000); + return this; + } + + public DateBuilder setMillis(int millis) { + calendar.set(Calendar.MILLISECOND, millis); + return this; + } + + public DateBuilder addMillis(long millis) { + calendar.setTimeInMillis(calendar.getTimeInMillis() + millis); + return this; + } + + public DateBuilder setTime(int hour, int minute, int second) { + return setHour(hour).setMinute(minute).setSecond(second); + } + + public DateBuilder setTimeReverse(int second, int minute, int hour) { + return setHour(hour).setMinute(minute).setSecond(second); + } + + public DateBuilder setTime(int hour, int minute, int second, int millis) { + return setHour(hour).setMinute(minute).setSecond(second).setMillis(millis); + } + + public Date getDate() { + return calendar.getTime(); + } + +} diff --git a/src/main/java/org/traccar/helper/DateUtil.java b/src/main/java/org/traccar/helper/DateUtil.java new file mode 100644 index 000000000..20a483e3c --- /dev/null +++ b/src/main/java/org/traccar/helper/DateUtil.java @@ -0,0 +1,78 @@ +/* + * Copyright 2016 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. + * 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.helper; + +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Calendar; +import java.util.Date; + +public final class DateUtil { + + private DateUtil() { + } + + public static Date correctDay(Date guess) { + return correctDate(new Date(), guess, Calendar.DAY_OF_MONTH); + } + + public static Date correctYear(Date guess) { + return correctDate(new Date(), guess, Calendar.YEAR); + } + + public static Date correctDate(Date now, Date guess, int field) { + + if (guess.getTime() > now.getTime()) { + Date previous = dateAdd(guess, field, -1); + if (now.getTime() - previous.getTime() < guess.getTime() - now.getTime()) { + return previous; + } + } else if (guess.getTime() < now.getTime()) { + Date next = dateAdd(guess, field, 1); + if (next.getTime() - now.getTime() < now.getTime() - guess.getTime()) { + return next; + } + } + + return guess; + } + + private static Date dateAdd(Date guess, int field, int amount) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(guess); + calendar.add(field, amount); + return calendar.getTime(); + } + + public static Date parseDate(String value) { + return Date.from(Instant.from(DateTimeFormatter.ISO_ZONED_DATE_TIME.parse(value))); + } + + public static String formatDate(Date date) { + return formatDate(date, true); + } + + public static String formatDate(Date date, boolean zoned) { + if (zoned) { + return DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault()).format(date.toInstant()); + } else { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); + } + } + +} diff --git a/src/main/java/org/traccar/helper/DistanceCalculator.java b/src/main/java/org/traccar/helper/DistanceCalculator.java new file mode 100644 index 000000000..88d4ef8a4 --- /dev/null +++ b/src/main/java/org/traccar/helper/DistanceCalculator.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.helper; + +public final class DistanceCalculator { + + private DistanceCalculator() { + } + + private static final double EQUATORIAL_EARTH_RADIUS = 6378.1370; + private static final double DEG_TO_RAD = Math.PI / 180; + + public static double distance(double lat1, double lon1, double lat2, double lon2) { + double dlong = (lon2 - lon1) * DEG_TO_RAD; + double dlat = (lat2 - lat1) * DEG_TO_RAD; + double a = Math.pow(Math.sin(dlat / 2), 2) + + Math.cos(lat1 * DEG_TO_RAD) * Math.cos(lat2 * DEG_TO_RAD) * Math.pow(Math.sin(dlong / 2), 2); + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + double d = EQUATORIAL_EARTH_RADIUS * c; + return d * 1000; + } + + public static double distanceToLine( + double pointLat, double pointLon, double lat1, double lon1, double lat2, double lon2) { + double d0 = distance(pointLat, pointLon, lat1, lon1); + double d1 = distance(lat1, lon1, lat2, lon2); + double d2 = distance(lat2, lon2, pointLat, pointLon); + if (Math.pow(d0, 2) > Math.pow(d1, 2) + Math.pow(d2, 2)) { + return d2; + } + if (Math.pow(d2, 2) > Math.pow(d1, 2) + Math.pow(d0, 2)) { + return d0; + } + double halfP = (d0 + d1 + d2) * 0.5; + double area = Math.sqrt(halfP * (halfP - d0) * (halfP - d1) * (halfP - d2)); + return 2 * area / d1; + } + +} diff --git a/src/main/java/org/traccar/helper/Hashing.java b/src/main/java/org/traccar/helper/Hashing.java new file mode 100644 index 000000000..e91310eda --- /dev/null +++ b/src/main/java/org/traccar/helper/Hashing.java @@ -0,0 +1,100 @@ +/* + * Copyright 2015 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. + * 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.helper; + +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; + +public final class Hashing { + + public static final int ITERATIONS = 1000; + public static final int SALT_SIZE = 24; + public static final int HASH_SIZE = 24; + + private static SecretKeyFactory factory; + static { + try { + factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + public static class HashingResult { + + private final String hash; + private final String salt; + + public HashingResult(String hash, String salt) { + this.hash = hash; + this.salt = salt; + } + + public String getHash() { + return hash; + } + + public String getSalt() { + return salt; + } + } + + private Hashing() { + } + + private static byte[] function(char[] password, byte[] salt) { + try { + PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, HASH_SIZE * Byte.SIZE); + return factory.generateSecret(spec).getEncoded(); + } catch (InvalidKeySpecException e) { + throw new SecurityException(e); + } + } + + private static final SecureRandom RANDOM = new SecureRandom(); + + public static HashingResult createHash(String password) { + byte[] salt = new byte[SALT_SIZE]; + RANDOM.nextBytes(salt); + byte[] hash = function(password.toCharArray(), salt); + return new HashingResult( + DataConverter.printHex(hash), + DataConverter.printHex(salt)); + } + + public static boolean validatePassword(String password, String hashHex, String saltHex) { + byte[] hash = DataConverter.parseHex(hashHex); + byte[] salt = DataConverter.parseHex(saltHex); + return slowEquals(hash, function(password.toCharArray(), salt)); + } + + /** + * Compares two byte arrays in length-constant time. This comparison method + * is used so that password hashes cannot be extracted from an on-line + * system using a timing attack and then attacked off-line. + */ + private static boolean slowEquals(byte[] a, byte[] b) { + int diff = a.length ^ b.length; + for (int i = 0; i < a.length && i < b.length; i++) { + diff |= a[i] ^ b[i]; + } + return diff == 0; + } + +} diff --git a/src/main/java/org/traccar/helper/LocationTree.java b/src/main/java/org/traccar/helper/LocationTree.java new file mode 100644 index 000000000..3aff3ce33 --- /dev/null +++ b/src/main/java/org/traccar/helper/LocationTree.java @@ -0,0 +1,125 @@ +/* + * Copyright 2016 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. + * 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.helper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class LocationTree { + + public static class Item { + + private Item left, right; + private float x, y; + private String data; + + public Item(float x, float y) { + this(x, y, null); + } + + public Item(float x, float y, String data) { + this.x = x; + this.y = y; + this.data = data; + } + + public String getData() { + return data; + } + + private float squaredDistance(Item item) { + return (x - item.x) * (x - item.x) + (y - item.y) * (y - item.y); + } + + private float axisSquaredDistance(Item item, int axis) { + if (axis == 0) { + return (x - item.x) * (x - item.x); + } else { + return (y - item.y) * (y - item.y); + } + } + + } + + private Item root; + + private ArrayList> comparators = new ArrayList<>(); + + public LocationTree(List items) { + comparators.add(new Comparator() { + @Override + public int compare(Item o1, Item o2) { + return Float.compare(o1.x, o2.x); + } + }); + comparators.add(new Comparator() { + @Override + public int compare(Item o1, Item o2) { + return Float.compare(o1.y, o2.y); + } + }); + root = createTree(items, 0); + } + + private Item createTree(List items, int depth) { + if (items.isEmpty()) { + return null; + } + Collections.sort(items, comparators.get(depth % 2)); + int currentIndex = items.size() / 2; + Item median = items.get(currentIndex); + median.left = createTree(new ArrayList<>(items.subList(0, currentIndex)), depth + 1); + median.right = createTree(new ArrayList<>(items.subList(currentIndex + 1, items.size())), depth + 1); + return median; + } + + public Item findNearest(Item search) { + return findNearest(root, search, 0); + } + + private Item findNearest(Item current, Item search, int depth) { + int direction = comparators.get(depth % 2).compare(search, current); + + Item next, other; + if (direction < 0) { + next = current.left; + other = current.right; + } else { + next = current.right; + other = current.left; + } + + Item best = current; + if (next != null) { + best = findNearest(next, search, depth + 1); + } + + if (current.squaredDistance(search) < best.squaredDistance(search)) { + best = current; + } + if (other != null && current.axisSquaredDistance(search, depth % 2) < best.squaredDistance(search)) { + Item possibleBest = findNearest(other, search, depth + 1); + if (possibleBest.squaredDistance(search) < best.squaredDistance(search)) { + best = possibleBest; + } + } + + return best; + } + +} diff --git a/src/main/java/org/traccar/helper/Log.java b/src/main/java/org/traccar/helper/Log.java new file mode 100644 index 000000000..f328e8ce9 --- /dev/null +++ b/src/main/java/org/traccar/helper/Log.java @@ -0,0 +1,265 @@ +/* + * Copyright 2012 - 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. + * 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.helper; + +import org.traccar.config.Config; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.ConsoleHandler; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +public final class Log { + + private Log() { + } + + private static final String STACK_PACKAGE = "org.traccar"; + private static final int STACK_LIMIT = 3; + + private static class RollingFileHandler extends Handler { + + private String name; + private String suffix; + private Writer writer; + private boolean rotate; + + RollingFileHandler(String name, boolean rotate) { + this.name = name; + this.rotate = rotate; + } + + @Override + public synchronized void publish(LogRecord record) { + if (isLoggable(record)) { + try { + String suffix = ""; + if (rotate) { + suffix = new SimpleDateFormat("yyyyMMdd").format(new Date(record.getMillis())); + if (writer != null && !suffix.equals(this.suffix)) { + writer.close(); + writer = null; + if (!new File(name).renameTo(new File(name + "." + this.suffix))) { + throw new RuntimeException("Log file renaming failed"); + } + } + } + if (writer == null) { + this.suffix = suffix; + writer = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(name, true), StandardCharsets.UTF_8)); + } + writer.write(getFormatter().format(record)); + writer.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public synchronized void flush() { + if (writer != null) { + try { + writer.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public synchronized void close() throws SecurityException { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + } + + public static class LogFormatter extends Formatter { + + private boolean fullStackTraces; + + LogFormatter(boolean fullStackTraces) { + this.fullStackTraces = fullStackTraces; + } + + private static String formatLevel(Level level) { + switch (level.getName()) { + case "FINEST": + return "TRACE"; + case "FINER": + case "FINE": + case "CONFIG": + return "DEBUG"; + case "INFO": + return "INFO"; + case "WARNING": + return "WARN"; + case "SEVERE": + default: + return "ERROR"; + } + } + + @Override + public String format(LogRecord record) { + StringBuilder message = new StringBuilder(); + + if (record.getMessage() != null) { + message.append(record.getMessage()); + } + + if (record.getThrown() != null) { + if (message.length() > 0) { + message.append(" - "); + } + if (fullStackTraces) { + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + record.getThrown().printStackTrace(printWriter); + message.append(System.lineSeparator()).append(stringWriter.toString()); + } else { + message.append(exceptionStack(record.getThrown())); + } + } + + return String.format("%1$tF %1$tT %2$5s: %3$s%n", + new Date(record.getMillis()), formatLevel(record.getLevel()), message.toString()); + } + + } + + public static void setupDefaultLogger() { + String path = null; + URL url = ClassLoader.getSystemClassLoader().getResource("."); + if (url != null) { + File jarPath = new File(url.getPath()); + File logsPath = new File(jarPath, "logs"); + if (!logsPath.exists() || !logsPath.isDirectory()) { + logsPath = jarPath; + } + path = new File(logsPath, "tracker-server.log").getPath(); + } + setupLogger(path == null, path, Level.WARNING.getName(), false, true); + } + + public static void setupLogger(Config config) { + setupLogger( + config.getBoolean("logger.console"), + config.getString("logger.file"), + config.getString("logger.level"), + config.getBoolean("logger.fullStackTraces"), + config.getBoolean("logger.rotate")); + } + + private static void setupLogger( + boolean console, String file, String levelString, boolean fullStackTraces, boolean rotate) { + + Logger rootLogger = Logger.getLogger(""); + for (Handler handler : rootLogger.getHandlers()) { + rootLogger.removeHandler(handler); + } + + Handler handler; + if (console) { + handler = new ConsoleHandler(); + } else { + handler = new RollingFileHandler(file, rotate); + } + + handler.setFormatter(new LogFormatter(fullStackTraces)); + + Level level = Level.parse(levelString.toUpperCase()); + rootLogger.setLevel(level); + handler.setLevel(level); + handler.setFilter(record -> record != null && !record.getLoggerName().startsWith("sun")); + + rootLogger.addHandler(handler); + } + + public static String exceptionStack(Throwable exception) { + StringBuilder s = new StringBuilder(); + String exceptionMsg = exception.getMessage(); + if (exceptionMsg != null) { + s.append(exceptionMsg); + s.append(" - "); + } + s.append(exception.getClass().getSimpleName()); + StackTraceElement[] stack = exception.getStackTrace(); + + if (stack.length > 0) { + int count = STACK_LIMIT; + boolean first = true; + boolean skip = false; + String file = ""; + s.append(" ("); + for (StackTraceElement element : stack) { + if (count > 0 && element.getClassName().startsWith(STACK_PACKAGE)) { + if (!first) { + s.append(" < "); + } else { + first = false; + } + + if (skip) { + s.append("... < "); + skip = false; + } + + if (file.equals(element.getFileName())) { + s.append("*"); + } else { + file = element.getFileName(); + s.append(file, 0, file.length() - 5); // remove ".java" + count -= 1; + } + s.append(":").append(element.getLineNumber()); + } else { + skip = true; + } + } + if (skip) { + if (!first) { + s.append(" < "); + } + s.append("..."); + } + s.append(")"); + } + return s.toString(); + } + +} diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java new file mode 100644 index 000000000..db13337b8 --- /dev/null +++ b/src/main/java/org/traccar/helper/LogAction.java @@ -0,0 +1,99 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.helper; + +import java.beans.Introspector; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.model.BaseModel; + +public final class LogAction { + + private static final Logger LOGGER = LoggerFactory.getLogger(LogAction.class); + + private LogAction() { + } + + private static final String ACTION_CREATE = "create"; + private static final String ACTION_EDIT = "edit"; + private static final String ACTION_REMOVE = "remove"; + + private static final String ACTION_LINK = "link"; + private static final String ACTION_UNLINK = "unlink"; + + private static final String ACTION_LOGIN = "login"; + private static final String ACTION_LOGOUT = "logout"; + + private static final String ACTION_DEVICE_ACCUMULATORS = "resetDeviceAccumulators"; + + private static final String PATTERN_OBJECT = "user: %d, action: %s, object: %s, id: %d"; + private static final String PATTERN_LINK = "user: %d, action: %s, owner: %s, id: %d, property: %s, id: %d"; + private static final String PATTERN_LOGIN = "user: %d, action: %s"; + private static final String PATTERN_DEVICE_ACCUMULATORS = "user: %d, action: %s, deviceId: %d"; + + public static void create(long userId, BaseModel object) { + logObjectAction(ACTION_CREATE, userId, object.getClass(), object.getId()); + } + + public static void edit(long userId, BaseModel object) { + logObjectAction(ACTION_EDIT, userId, object.getClass(), object.getId()); + } + + public static void remove(long userId, Class clazz, long objectId) { + logObjectAction(ACTION_REMOVE, userId, clazz, objectId); + } + + public static void link(long userId, Class owner, long ownerId, Class property, long propertyId) { + logLinkAction(ACTION_LINK, userId, owner, ownerId, property, propertyId); + } + + public static void unlink(long userId, Class owner, long ownerId, Class property, long propertyId) { + logLinkAction(ACTION_UNLINK, userId, owner, ownerId, property, propertyId); + } + + public static void login(long userId) { + logLoginAction(ACTION_LOGIN, userId); + } + + public static void logout(long userId) { + logLoginAction(ACTION_LOGOUT, userId); + } + + public static void resetDeviceAccumulators(long userId, long deviceId) { + LOGGER.info(String.format( + PATTERN_DEVICE_ACCUMULATORS, userId, ACTION_DEVICE_ACCUMULATORS, deviceId)); + } + + private static void logObjectAction(String action, long userId, Class clazz, long objectId) { + LOGGER.info(String.format( + PATTERN_OBJECT, userId, action, Introspector.decapitalize(clazz.getSimpleName()), objectId)); + } + + private static void logLinkAction(String action, long userId, + Class owner, long ownerId, Class property, long propertyId) { + LOGGER.info(String.format( + PATTERN_LINK, userId, action, + Introspector.decapitalize(owner.getSimpleName()), ownerId, + Introspector.decapitalize(property.getSimpleName()), propertyId)); + } + + private static void logLoginAction(String action, long userId) { + LOGGER.info(String.format(PATTERN_LOGIN, userId, action)); + } + +} diff --git a/src/main/java/org/traccar/helper/ObdDecoder.java b/src/main/java/org/traccar/helper/ObdDecoder.java new file mode 100644 index 000000000..1bdcce352 --- /dev/null +++ b/src/main/java/org/traccar/helper/ObdDecoder.java @@ -0,0 +1,105 @@ +/* + * 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. + * 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.helper; + +import org.traccar.model.Position; + +import java.util.AbstractMap; +import java.util.Map; + +public final class ObdDecoder { + + private ObdDecoder() { + } + + private static final int MODE_CURRENT = 0x01; + private static final int MODE_FREEZE_FRAME = 0x02; + private static final int MODE_CODES = 0x03; + + public static Map.Entry decode(int mode, String value) { + switch (mode) { + case MODE_CURRENT: + case MODE_FREEZE_FRAME: + return decodeData( + Integer.parseInt(value.substring(0, 2), 16), + Integer.parseInt(value.substring(2), 16), true); + case MODE_CODES: + return decodeCodes(value); + default: + return null; + } + } + + private static Map.Entry createEntry(String key, Object value) { + return new AbstractMap.SimpleEntry<>(key, value); + } + + public static Map.Entry decodeCodes(String value) { + StringBuilder codes = new StringBuilder(); + for (int i = 0; i < value.length() / 4; i++) { + int numValue = Integer.parseInt(value.substring(i * 4, (i + 1) * 4), 16); + codes.append(' '); + switch (numValue >> 14) { + case 1: + codes.append('C'); + break; + case 2: + codes.append('B'); + break; + case 3: + codes.append('U'); + break; + default: + codes.append('P'); + break; + } + codes.append(String.format("%04X", numValue & 0x3FFF)); + } + if (codes.length() > 0) { + return createEntry(Position.KEY_DTCS, codes.toString().trim()); + } else { + return null; + } + } + + public static Map.Entry decodeData(int pid, int value, boolean convert) { + switch (pid) { + case 0x04: + return createEntry(Position.KEY_ENGINE_LOAD, convert ? value * 100 / 255 : value); + case 0x05: + return createEntry(Position.KEY_COOLANT_TEMP, convert ? value - 40 : value); + case 0x0B: + return createEntry("mapIntake", value); + case 0x0C: + return createEntry(Position.KEY_RPM, convert ? value / 4 : value); + case 0x0D: + return createEntry(Position.KEY_OBD_SPEED, value); + case 0x0F: + return createEntry("intakeTemp", convert ? value - 40 : value); + case 0x11: + return createEntry(Position.KEY_THROTTLE, convert ? value * 100 / 255 : value); + case 0x21: + return createEntry("milDistance", value); + case 0x2F: + return createEntry(Position.KEY_FUEL_LEVEL, convert ? value * 100 / 255 : value); + case 0x31: + return createEntry("clearedDistance", value); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/helper/Parser.java b/src/main/java/org/traccar/helper/Parser.java new file mode 100644 index 000000000..1471ec237 --- /dev/null +++ b/src/main/java/org/traccar/helper/Parser.java @@ -0,0 +1,348 @@ +/* + * Copyright 2015 - 2017 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. + * 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.helper; + +import java.util.Date; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Parser { + + private int position; + private final Matcher matcher; + + public Parser(Pattern pattern, String input) { + matcher = pattern.matcher(input); + } + + public boolean matches() { + position = 1; + return matcher.matches(); + } + + public boolean find() { + position = 1; + return matcher.find(); + } + + public void skip(int number) { + position += number; + } + + public boolean hasNext() { + return hasNext(1); + } + + public boolean hasNext(int number) { + String value = matcher.group(position); + if (value != null && !value.isEmpty()) { + return true; + } else { + position += number; + return false; + } + } + + public String next() { + return matcher.group(position++); + } + + public Integer nextInt() { + if (hasNext()) { + return Integer.parseInt(next()); + } else { + return null; + } + } + + public int nextInt(int defaultValue) { + if (hasNext()) { + return Integer.parseInt(next()); + } else { + return defaultValue; + } + } + + public Integer nextHexInt() { + if (hasNext()) { + return Integer.parseInt(next(), 16); + } else { + return null; + } + } + + public int nextHexInt(int defaultValue) { + if (hasNext()) { + return Integer.parseInt(next(), 16); + } else { + return defaultValue; + } + } + + public Integer nextBinInt() { + if (hasNext()) { + return Integer.parseInt(next(), 2); + } else { + return null; + } + } + + public int nextBinInt(int defaultValue) { + if (hasNext()) { + return Integer.parseInt(next(), 2); + } else { + return defaultValue; + } + } + + public Long nextLong() { + if (hasNext()) { + return Long.parseLong(next()); + } else { + return null; + } + } + + public Long nextHexLong() { + if (hasNext()) { + return Long.parseLong(next(), 16); + } else { + return null; + } + } + + public long nextLong(long defaultValue) { + return nextLong(10, defaultValue); + } + + public long nextLong(int radix, long defaultValue) { + if (hasNext()) { + return Long.parseLong(next(), radix); + } else { + return defaultValue; + } + } + + public Double nextDouble() { + if (hasNext()) { + return Double.parseDouble(next()); + } else { + return null; + } + } + + public double nextDouble(double defaultValue) { + if (hasNext()) { + return Double.parseDouble(next()); + } else { + return defaultValue; + } + } + + public enum CoordinateFormat { + DEG_DEG, + DEG_HEM, + DEG_MIN_MIN, + DEG_MIN_HEM, + DEG_MIN_MIN_HEM, + HEM_DEG_MIN_MIN, + HEM_DEG, + HEM_DEG_MIN, + HEM_DEG_MIN_HEM + } + + public double nextCoordinate(CoordinateFormat format) { + double coordinate; + String hemisphere = null; + + switch (format) { + case DEG_DEG: + coordinate = Double.parseDouble(next() + '.' + next()); + break; + case DEG_HEM: + coordinate = nextDouble(0); + hemisphere = next(); + break; + case DEG_MIN_MIN: + coordinate = nextInt(0); + coordinate += Double.parseDouble(next() + '.' + next()) / 60; + break; + case DEG_MIN_MIN_HEM: + coordinate = nextInt(0); + coordinate += Double.parseDouble(next() + '.' + next()) / 60; + hemisphere = next(); + break; + case HEM_DEG: + hemisphere = next(); + coordinate = nextDouble(0); + break; + case HEM_DEG_MIN: + hemisphere = next(); + coordinate = nextInt(0); + coordinate += nextDouble(0) / 60; + break; + case HEM_DEG_MIN_HEM: + hemisphere = next(); + coordinate = nextInt(0); + coordinate += nextDouble(0) / 60; + if (hasNext()) { + hemisphere = next(); + } + break; + case HEM_DEG_MIN_MIN: + hemisphere = next(); + coordinate = nextInt(0); + coordinate += Double.parseDouble(next() + '.' + next()) / 60; + break; + case DEG_MIN_HEM: + default: + coordinate = nextInt(0); + coordinate += nextDouble(0) / 60; + hemisphere = next(); + break; + } + + if (hemisphere != null && (hemisphere.equals("S") || hemisphere.equals("W") || hemisphere.equals("-"))) { + coordinate = -Math.abs(coordinate); + } + + return coordinate; + } + + public double nextCoordinate() { + return nextCoordinate(CoordinateFormat.DEG_MIN_HEM); + } + + public enum DateTimeFormat { + HMS, + SMH, + HMS_YMD, + HMS_DMY, + SMH_YMD, + SMH_DMY, + DMY_HMS, + DMY_HMSS, + YMD_HMS, + YMD_HMSS, + } + + public Date nextDateTime(DateTimeFormat format, String timeZone) { + int year = 0, month = 0, day = 0; + int hour = 0, minute = 0, second = 0, millisecond = 0; + + switch (format) { + case HMS: + hour = nextInt(0); + minute = nextInt(0); + second = nextInt(0); + break; + case SMH: + second = nextInt(0); + minute = nextInt(0); + hour = nextInt(0); + break; + case HMS_YMD: + hour = nextInt(0); + minute = nextInt(0); + second = nextInt(0); + year = nextInt(0); + month = nextInt(0); + day = nextInt(0); + break; + case HMS_DMY: + hour = nextInt(0); + minute = nextInt(0); + second = nextInt(0); + day = nextInt(0); + month = nextInt(0); + year = nextInt(0); + break; + case SMH_YMD: + second = nextInt(0); + minute = nextInt(0); + hour = nextInt(0); + year = nextInt(0); + month = nextInt(0); + day = nextInt(0); + break; + case SMH_DMY: + second = nextInt(0); + minute = nextInt(0); + hour = nextInt(0); + day = nextInt(0); + month = nextInt(0); + year = nextInt(0); + break; + case DMY_HMS: + case DMY_HMSS: + day = nextInt(0); + month = nextInt(0); + year = nextInt(0); + hour = nextInt(0); + minute = nextInt(0); + second = nextInt(0); + break; + case YMD_HMS: + case YMD_HMSS: + default: + year = nextInt(0); + month = nextInt(0); + day = nextInt(0); + hour = nextInt(0); + minute = nextInt(0); + second = nextInt(0); + break; + } + + if (format == DateTimeFormat.YMD_HMSS || format == DateTimeFormat.DMY_HMSS) { + millisecond = nextInt(0); // (ddd) + } + + if (year >= 0 && year < 100) { + year += 2000; + } + + DateBuilder dateBuilder; + if (format != DateTimeFormat.HMS && format != DateTimeFormat.SMH) { + if (timeZone != null) { + dateBuilder = new DateBuilder(TimeZone.getTimeZone(timeZone)); + } else { + dateBuilder = new DateBuilder(); + } + dateBuilder.setDate(year, month, day); + } else { + if (timeZone != null) { + dateBuilder = new DateBuilder(new Date(), TimeZone.getTimeZone(timeZone)); + } else { + dateBuilder = new DateBuilder(new Date()); + } + } + + dateBuilder.setTime(hour, minute, second, millisecond); + + return dateBuilder.getDate(); + } + + public Date nextDateTime(DateTimeFormat format) { + return nextDateTime(format, null); + } + + public Date nextDateTime() { + return nextDateTime(DateTimeFormat.YMD_HMS, null); + } + +} diff --git a/src/main/java/org/traccar/helper/PatternBuilder.java b/src/main/java/org/traccar/helper/PatternBuilder.java new file mode 100644 index 000000000..5c4638189 --- /dev/null +++ b/src/main/java/org/traccar/helper/PatternBuilder.java @@ -0,0 +1,98 @@ +/* + * Copyright 2015 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. + * 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.helper; + +import java.util.ArrayList; +import java.util.regex.Pattern; + +public class PatternBuilder { + + private final ArrayList fragments = new ArrayList<>(); + + public PatternBuilder optional() { + return optional(1); + } + + public PatternBuilder optional(int count) { + fragments.add(fragments.size() - count, "(?:"); + fragments.add(")?"); + return this; + } + + public PatternBuilder expression(String s) { + s = s.replaceAll("\\|$", "\\\\|"); // special case for delimiter + + fragments.add(s); + return this; + } + + public PatternBuilder text(String s) { + fragments.add(s.replaceAll("([\\\\\\.\\[\\{\\(\\)\\*\\+\\?\\^\\$\\|])", "\\\\$1")); + return this; + } + + public PatternBuilder number(String s) { + s = s.replace("dddd", "d{4}").replace("ddd", "d{3}").replace("dd", "d{2}"); + s = s.replace("xxxx", "x{4}").replace("xxx", "x{3}").replace("xx", "x{2}"); + + s = s.replace("d", "\\d").replace("x", "[0-9a-fA-F]").replaceAll("([\\.])", "\\\\$1"); + s = s.replaceAll("\\|$", "\\\\|").replaceAll("^\\|", "\\\\|"); // special case for delimiter + + fragments.add(s); + return this; + } + + public PatternBuilder any() { + fragments.add(".*"); + return this; + } + + public PatternBuilder binary(String s) { + fragments.add(s.replaceAll("(\\p{XDigit}{2})", "\\\\$1")); + return this; + } + + public PatternBuilder or() { + fragments.add("|"); + return this; + } + + public PatternBuilder groupBegin() { + return expression("(?:"); + } + + public PatternBuilder groupEnd() { + return expression(")"); + } + + public PatternBuilder groupEnd(String s) { + return expression(")" + s); + } + + public Pattern compile() { + return Pattern.compile(toString(), Pattern.DOTALL); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (String fragment : fragments) { + builder.append(fragment); + } + return builder.toString(); + } + +} diff --git a/src/main/java/org/traccar/helper/PatternUtil.java b/src/main/java/org/traccar/helper/PatternUtil.java new file mode 100644 index 000000000..74813e1d9 --- /dev/null +++ b/src/main/java/org/traccar/helper/PatternUtil.java @@ -0,0 +1,81 @@ +/* + * Copyright 2015 - 2017 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. + * 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.helper; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.management.ManagementFactory; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public final class PatternUtil { + + private static final Logger LOGGER = LoggerFactory.getLogger(PatternUtil.class); + + private PatternUtil() { + } + + public static class MatchResult { + private String patternMatch; + private String patternTail; + private String stringMatch; + private String stringTail; + + public String getPatternMatch() { + return patternMatch; + } + + public String getPatternTail() { + return patternTail; + } + + public String getStringMatch() { + return stringMatch; + } + + public String getStringTail() { + return stringTail; + } + } + + public static MatchResult checkPattern(String pattern, String input) { + + if (!ManagementFactory.getRuntimeMXBean().getInputArguments().toString().contains("-agentlib:jdwp")) { + throw new RuntimeException("PatternUtil usage detected"); + } + + MatchResult result = new MatchResult(); + + for (int i = 0; i < pattern.length(); i++) { + try { + Matcher matcher = Pattern.compile("(" + pattern.substring(0, i) + ").*").matcher(input); + if (matcher.matches()) { + result.patternMatch = pattern.substring(0, i); + result.patternTail = pattern.substring(i); + result.stringMatch = matcher.group(1); + result.stringTail = input.substring(matcher.group(1).length()); + } + } catch (PatternSyntaxException error) { + LOGGER.warn("Pattern matching error", error); + } + } + + return result; + } + +} diff --git a/src/main/java/org/traccar/helper/SanitizerModule.java b/src/main/java/org/traccar/helper/SanitizerModule.java new file mode 100644 index 000000000..af9ac5c2b --- /dev/null +++ b/src/main/java/org/traccar/helper/SanitizerModule.java @@ -0,0 +1,45 @@ +/* + * Copyright 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. + * 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.helper; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.owasp.encoder.Encode; + +import java.io.IOException; + +public class SanitizerModule extends SimpleModule { + + public static class SanitizerSerializer extends StdSerializer { + + protected SanitizerSerializer() { + super(String.class); + } + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeString(Encode.forHtml(value)); + } + + } + + public SanitizerModule() { + addSerializer(new SanitizerSerializer()); + } + +} diff --git a/src/main/java/org/traccar/helper/UnitsConverter.java b/src/main/java/org/traccar/helper/UnitsConverter.java new file mode 100644 index 000000000..3dd435df4 --- /dev/null +++ b/src/main/java/org/traccar/helper/UnitsConverter.java @@ -0,0 +1,88 @@ +/* + * Copyright 2015 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. + * 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.helper; + +public final class UnitsConverter { + + private static final double KNOTS_TO_KPH_RATIO = 0.539957; + private static final double KNOTS_TO_MPH_RATIO = 0.868976; + private static final double KNOTS_TO_MPS_RATIO = 1.94384; + private static final double KNOTS_TO_CPS_RATIO = 0.0194384449; + private static final double METERS_TO_FEET_RATIO = 0.3048; + private static final double METERS_TO_MILE_RATIO = 1609.34; + private static final long MILLISECONDS_TO_HOURS_RATIO = 3600000; + private static final long MILLISECONDS_TO_MINUTES_RATIO = 60000; + + private UnitsConverter() { + } + + public static double knotsFromKph(double value) { // km/h + return value * KNOTS_TO_KPH_RATIO; + } + + public static double kphFromKnots(double value) { + return value / KNOTS_TO_KPH_RATIO; + } + + public static double knotsFromMph(double value) { + return value * KNOTS_TO_MPH_RATIO; + } + + public static double mphFromKnots(double value) { + return value / KNOTS_TO_MPH_RATIO; + } + + public static double knotsFromMps(double value) { // m/s + return value * KNOTS_TO_MPS_RATIO; + } + + public static double mpsFromKnots(double value) { + return value / KNOTS_TO_MPS_RATIO; + } + + public static double knotsFromCps(double value) { // cm/s + return value * KNOTS_TO_CPS_RATIO; + } + + public static double feetFromMeters(double value) { + return value / METERS_TO_FEET_RATIO; + } + + public static double metersFromFeet(double value) { + return value * METERS_TO_FEET_RATIO; + } + + public static double milesFromMeters(double value) { + return value / METERS_TO_MILE_RATIO; + } + + public static double metersFromMiles(double value) { + return value * METERS_TO_MILE_RATIO; + } + + public static long msFromHours(long value) { + return value * MILLISECONDS_TO_HOURS_RATIO; + } + + public static long msFromHours(double value) { + return (long) (value * MILLISECONDS_TO_HOURS_RATIO); + } + + public static long msFromMinutes(long value) { + return value * MILLISECONDS_TO_MINUTES_RATIO; + } + +} diff --git a/src/main/java/org/traccar/model/Attribute.java b/src/main/java/org/traccar/model/Attribute.java new file mode 100644 index 000000000..45d40b3ec --- /dev/null +++ b/src/main/java/org/traccar/model/Attribute.java @@ -0,0 +1,61 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class Attribute extends BaseModel { + + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + private String attribute; + + public String getAttribute() { + return attribute; + } + + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + private String expression; + + public String getExpression() { + return expression; + } + + public void setExpression(String expression) { + this.expression = expression; + } + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + +} diff --git a/src/main/java/org/traccar/model/BaseModel.java b/src/main/java/org/traccar/model/BaseModel.java new file mode 100644 index 000000000..8bdb916e8 --- /dev/null +++ b/src/main/java/org/traccar/model/BaseModel.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class BaseModel { + + private long id; + + public final long getId() { + return id; + } + + public final void setId(long id) { + this.id = id; + } + +} diff --git a/src/main/java/org/traccar/model/Calendar.java b/src/main/java/org/traccar/model/Calendar.java new file mode 100644 index 000000000..56d3eb74c --- /dev/null +++ b/src/main/java/org/traccar/model/Calendar.java @@ -0,0 +1,82 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import net.fortuna.ical4j.data.CalendarBuilder; +import net.fortuna.ical4j.data.ParserException; +import net.fortuna.ical4j.filter.Filter; +import net.fortuna.ical4j.filter.PeriodRule; +import net.fortuna.ical4j.model.DateTime; +import net.fortuna.ical4j.model.Dur; +import net.fortuna.ical4j.model.Period; +import net.fortuna.ical4j.model.component.CalendarComponent; +import org.apache.commons.collections4.Predicate; +import org.traccar.database.QueryIgnore; + +public class Calendar extends ExtendedModel { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private byte[] data; + + public byte[] getData() { + return data.clone(); + } + + public void setData(byte[] data) throws IOException, ParserException { + CalendarBuilder builder = new CalendarBuilder(); + calendar = builder.build(new ByteArrayInputStream(data)); + this.data = data.clone(); + } + + private net.fortuna.ical4j.model.Calendar calendar; + + @QueryIgnore + @JsonIgnore + public net.fortuna.ical4j.model.Calendar getCalendar() { + return calendar; + } + + public boolean checkMoment(Date date) { + if (calendar != null) { + Period period = new Period(new DateTime(date), new Dur(0, 0, 0, 0)); + Predicate periodRule = new PeriodRule<>(period); + Filter filter = new Filter<>(new Predicate[] {periodRule}, Filter.MATCH_ANY); + Collection events = filter.filter(calendar.getComponents(CalendarComponent.VEVENT)); + if (events != null && !events.isEmpty()) { + return true; + } + } + return false; + } + +} diff --git a/src/main/java/org/traccar/model/CellTower.java b/src/main/java/org/traccar/model/CellTower.java new file mode 100644 index 000000000..6d1dfbd7f --- /dev/null +++ b/src/main/java/org/traccar/model/CellTower.java @@ -0,0 +1,115 @@ +/* + * Copyright 2016 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. + * 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.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import org.traccar.Context; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class CellTower { + + public static CellTower from(int mcc, int mnc, int lac, long cid) { + CellTower cellTower = new CellTower(); + cellTower.setMobileCountryCode(mcc); + cellTower.setMobileNetworkCode(mnc); + cellTower.setLocationAreaCode(lac); + cellTower.setCellId(cid); + return cellTower; + } + + public static CellTower from(int mcc, int mnc, int lac, long cid, int rssi) { + CellTower cellTower = CellTower.from(mcc, mnc, lac, cid); + cellTower.setSignalStrength(rssi); + return cellTower; + } + + public static CellTower fromLacCid(int lac, long cid) { + return from( + Context.getConfig().getInteger("geolocation.mcc"), + Context.getConfig().getInteger("geolocation.mnc"), lac, cid); + } + + public static CellTower fromCidLac(long cid, int lac) { + return fromLacCid(lac, cid); + } + + private String radioType; + + public String getRadioType() { + return radioType; + } + + public void setRadioType(String radioType) { + this.radioType = radioType; + } + + private Long cellId; + + public Long getCellId() { + return cellId; + } + + public void setCellId(Long cellId) { + this.cellId = cellId; + } + + private Integer locationAreaCode; + + public Integer getLocationAreaCode() { + return locationAreaCode; + } + + public void setLocationAreaCode(Integer locationAreaCode) { + this.locationAreaCode = locationAreaCode; + } + + private Integer mobileCountryCode; + + public Integer getMobileCountryCode() { + return mobileCountryCode; + } + + public void setMobileCountryCode(Integer mobileCountryCode) { + this.mobileCountryCode = mobileCountryCode; + } + + private Integer mobileNetworkCode; + + public Integer getMobileNetworkCode() { + return mobileNetworkCode; + } + + public void setMobileNetworkCode(Integer mobileNetworkCode) { + this.mobileNetworkCode = mobileNetworkCode; + } + + private Integer signalStrength; + + public Integer getSignalStrength() { + return signalStrength; + } + + public void setSignalStrength(Integer signalStrength) { + this.signalStrength = signalStrength; + } + + public void setOperator(long operator) { + String operatorString = String.valueOf(operator); + mobileCountryCode = Integer.parseInt(operatorString.substring(0, 3)); + mobileNetworkCode = Integer.parseInt(operatorString.substring(3)); + } + +} diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java new file mode 100644 index 000000000..336fc61f4 --- /dev/null +++ b/src/main/java/org/traccar/model/Command.java @@ -0,0 +1,113 @@ +/* + * Copyright 2015 - 2017 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. + * 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.model; + +import org.traccar.database.QueryIgnore; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Command extends Message implements Cloneable { + + public static final String TYPE_CUSTOM = "custom"; + public static final String TYPE_IDENTIFICATION = "deviceIdentification"; + public static final String TYPE_POSITION_SINGLE = "positionSingle"; + public static final String TYPE_POSITION_PERIODIC = "positionPeriodic"; + public static final String TYPE_POSITION_STOP = "positionStop"; + public static final String TYPE_ENGINE_STOP = "engineStop"; + public static final String TYPE_ENGINE_RESUME = "engineResume"; + public static final String TYPE_ALARM_ARM = "alarmArm"; + public static final String TYPE_ALARM_DISARM = "alarmDisarm"; + public static final String TYPE_SET_TIMEZONE = "setTimezone"; + public static final String TYPE_REQUEST_PHOTO = "requestPhoto"; + public static final String TYPE_POWER_OFF = "powerOff"; + public static final String TYPE_REBOOT_DEVICE = "rebootDevice"; + public static final String TYPE_SEND_SMS = "sendSms"; + public static final String TYPE_SEND_USSD = "sendUssd"; + public static final String TYPE_SOS_NUMBER = "sosNumber"; + public static final String TYPE_SILENCE_TIME = "silenceTime"; + public static final String TYPE_SET_PHONEBOOK = "setPhonebook"; + public static final String TYPE_MESSAGE = "message"; + public static final String TYPE_VOICE_MESSAGE = "voiceMessage"; + public static final String TYPE_OUTPUT_CONTROL = "outputControl"; + public static final String TYPE_VOICE_MONITORING = "voiceMonitoring"; + public static final String TYPE_SET_AGPS = "setAgps"; + public static final String TYPE_SET_INDICATOR = "setIndicator"; + public static final String TYPE_CONFIGURATION = "configuration"; + public static final String TYPE_GET_VERSION = "getVersion"; + public static final String TYPE_FIRMWARE_UPDATE = "firmwareUpdate"; + public static final String TYPE_SET_CONNECTION = "setConnection"; + public static final String TYPE_SET_ODOMETER = "setOdometer"; + public static final String TYPE_GET_MODEM_STATUS = "getModemStatus"; + public static final String TYPE_GET_DEVICE_STATUS = "getDeviceStatus"; + + public static final String TYPE_MODE_POWER_SAVING = "modePowerSaving"; + public static final String TYPE_MODE_DEEP_SLEEP = "modeDeepSleep"; + + public static final String TYPE_ALARM_GEOFENCE = "movementAlarm"; + public static final String TYPE_ALARM_BATTERY = "alarmBattery"; + public static final String TYPE_ALARM_SOS = "alarmSos"; + public static final String TYPE_ALARM_REMOVE = "alarmRemove"; + public static final String TYPE_ALARM_CLOCK = "alarmClock"; + public static final String TYPE_ALARM_SPEED = "alarmSpeed"; + public static final String TYPE_ALARM_FALL = "alarmFall"; + public static final String TYPE_ALARM_VIBRATION = "alarmVibration"; + + public static final String KEY_UNIQUE_ID = "uniqueId"; + public static final String KEY_FREQUENCY = "frequency"; + public static final String KEY_TIMEZONE = "timezone"; + public static final String KEY_DEVICE_PASSWORD = "devicePassword"; + public static final String KEY_RADIUS = "radius"; + public static final String KEY_MESSAGE = "message"; + public static final String KEY_ENABLE = "enable"; + public static final String KEY_DATA = "data"; + public static final String KEY_INDEX = "index"; + public static final String KEY_PHONE = "phone"; + public static final String KEY_SERVER = "server"; + public static final String KEY_PORT = "port"; + + @Override + public Command clone() throws CloneNotSupportedException { + return (Command) super.clone(); + } + + private boolean textChannel; + + public boolean getTextChannel() { + return textChannel; + } + + public void setTextChannel(boolean textChannel) { + this.textChannel = textChannel; + } + + @QueryIgnore + @Override + public long getDeviceId() { + return super.getDeviceId(); + } + + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java new file mode 100644 index 000000000..0c9be932d --- /dev/null +++ b/src/main/java/org/traccar/model/Device.java @@ -0,0 +1,152 @@ +/* + * 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. + * 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.model; + +import java.util.Date; +import java.util.List; + +import org.traccar.database.QueryExtended; +import org.traccar.database.QueryIgnore; + +public class Device extends GroupedModel { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private String uniqueId; + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public static final String STATUS_UNKNOWN = "unknown"; + public static final String STATUS_ONLINE = "online"; + public static final String STATUS_OFFLINE = "offline"; + + private String status; + + @QueryIgnore + public String getStatus() { + return status != null ? status : STATUS_OFFLINE; + } + + public void setStatus(String status) { + this.status = status; + } + + private Date lastUpdate; + + @QueryExtended + public Date getLastUpdate() { + if (lastUpdate != null) { + return new Date(lastUpdate.getTime()); + } else { + return null; + } + } + + public void setLastUpdate(Date lastUpdate) { + if (lastUpdate != null) { + this.lastUpdate = new Date(lastUpdate.getTime()); + } else { + this.lastUpdate = null; + } + } + + private long positionId; + + @QueryIgnore + public long getPositionId() { + return positionId; + } + + public void setPositionId(long positionId) { + this.positionId = positionId; + } + + private List geofenceIds; + + @QueryIgnore + public List getGeofenceIds() { + return geofenceIds; + } + + public void setGeofenceIds(List geofenceIds) { + this.geofenceIds = geofenceIds; + } + + private String phone; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + private String model; + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + private String contact; + + public String getContact() { + return contact; + } + + public void setContact(String contact) { + this.contact = contact; + } + + private String category; + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + private boolean disabled; + + public boolean getDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + +} diff --git a/src/main/java/org/traccar/model/DeviceAccumulators.java b/src/main/java/org/traccar/model/DeviceAccumulators.java new file mode 100644 index 000000000..8a90826c4 --- /dev/null +++ b/src/main/java/org/traccar/model/DeviceAccumulators.java @@ -0,0 +1,51 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class DeviceAccumulators { + + private long deviceId; + + public long getDeviceId() { + return deviceId; + } + + public void setDeviceId(long deviceId) { + this.deviceId = deviceId; + } + + private Double totalDistance; + + public Double getTotalDistance() { + return totalDistance; + } + + public void setTotalDistance(Double totalDistance) { + this.totalDistance = totalDistance; + } + + private Long hours; + + public Long getHours() { + return hours; + } + + public void setHours(Long hours) { + this.hours = hours; + } + +} diff --git a/src/main/java/org/traccar/model/DeviceState.java b/src/main/java/org/traccar/model/DeviceState.java new file mode 100644 index 000000000..75d6726ee --- /dev/null +++ b/src/main/java/org/traccar/model/DeviceState.java @@ -0,0 +1,71 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class DeviceState { + + private Boolean motionState; + + public void setMotionState(boolean motionState) { + this.motionState = motionState; + } + + public Boolean getMotionState() { + return motionState; + } + + private Position motionPosition; + + public void setMotionPosition(Position motionPosition) { + this.motionPosition = motionPosition; + } + + public Position getMotionPosition() { + return motionPosition; + } + + private Boolean overspeedState; + + public void setOverspeedState(boolean overspeedState) { + this.overspeedState = overspeedState; + } + + public Boolean getOverspeedState() { + return overspeedState; + } + + private Position overspeedPosition; + + public void setOverspeedPosition(Position overspeedPosition) { + this.overspeedPosition = overspeedPosition; + } + + public Position getOverspeedPosition() { + return overspeedPosition; + } + + private long overspeedGeofenceId; + + public void setOverspeedGeofenceId(long overspeedGeofenceId) { + this.overspeedGeofenceId = overspeedGeofenceId; + } + + public long getOverspeedGeofenceId() { + return overspeedGeofenceId; + } + +} diff --git a/src/main/java/org/traccar/model/Driver.java b/src/main/java/org/traccar/model/Driver.java new file mode 100644 index 000000000..05f52fd4d --- /dev/null +++ b/src/main/java/org/traccar/model/Driver.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class Driver extends ExtendedModel { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private String uniqueId; + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } +} diff --git a/src/main/java/org/traccar/model/Event.java b/src/main/java/org/traccar/model/Event.java new file mode 100644 index 000000000..ee7fcc679 --- /dev/null +++ b/src/main/java/org/traccar/model/Event.java @@ -0,0 +1,104 @@ +/* + * Copyright 2016 - 2017 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. + * 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.model; + +import java.util.Date; + +public class Event extends Message { + + public Event(String type, long deviceId, long positionId) { + this(type, deviceId); + setPositionId(positionId); + } + + public Event(String type, long deviceId) { + setType(type); + setDeviceId(deviceId); + this.serverTime = new Date(); + } + + public Event() { + } + + public static final String ALL_EVENTS = "allEvents"; + + public static final String TYPE_COMMAND_RESULT = "commandResult"; + + public static final String TYPE_DEVICE_ONLINE = "deviceOnline"; + public static final String TYPE_DEVICE_UNKNOWN = "deviceUnknown"; + public static final String TYPE_DEVICE_OFFLINE = "deviceOffline"; + + public static final String TYPE_DEVICE_MOVING = "deviceMoving"; + public static final String TYPE_DEVICE_STOPPED = "deviceStopped"; + + public static final String TYPE_DEVICE_OVERSPEED = "deviceOverspeed"; + public static final String TYPE_DEVICE_FUEL_DROP = "deviceFuelDrop"; + + public static final String TYPE_GEOFENCE_ENTER = "geofenceEnter"; + public static final String TYPE_GEOFENCE_EXIT = "geofenceExit"; + + public static final String TYPE_ALARM = "alarm"; + + public static final String TYPE_IGNITION_ON = "ignitionOn"; + public static final String TYPE_IGNITION_OFF = "ignitionOff"; + + public static final String TYPE_MAINTENANCE = "maintenance"; + + public static final String TYPE_TEXT_MESSAGE = "textMessage"; + + public static final String TYPE_DRIVER_CHANGED = "driverChanged"; + + private Date serverTime; + + public Date getServerTime() { + return serverTime; + } + + public void setServerTime(Date serverTime) { + this.serverTime = serverTime; + } + + private long positionId; + + public long getPositionId() { + return positionId; + } + + public void setPositionId(long positionId) { + this.positionId = positionId; + } + + private long geofenceId = 0; + + public long getGeofenceId() { + return geofenceId; + } + + public void setGeofenceId(long geofenceId) { + this.geofenceId = geofenceId; + } + + private long maintenanceId = 0; + + public long getMaintenanceId() { + return maintenanceId; + } + + public void setMaintenanceId(long maintenanceId) { + this.maintenanceId = maintenanceId; + } + +} diff --git a/src/main/java/org/traccar/model/ExtendedModel.java b/src/main/java/org/traccar/model/ExtendedModel.java new file mode 100644 index 000000000..8353d0e66 --- /dev/null +++ b/src/main/java/org/traccar/model/ExtendedModel.java @@ -0,0 +1,127 @@ +/* + * Copyright 2016 - 2017 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. + * 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.model; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class ExtendedModel extends BaseModel { + + private Map attributes = new LinkedHashMap<>(); + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public void set(String key, Boolean value) { + if (value != null) { + attributes.put(key, value); + } + } + + public void set(String key, Byte value) { + if (value != null) { + attributes.put(key, value.intValue()); + } + } + + public void set(String key, Short value) { + if (value != null) { + attributes.put(key, value.intValue()); + } + } + + public void set(String key, Integer value) { + if (value != null) { + attributes.put(key, value); + } + } + + public void set(String key, Long value) { + if (value != null) { + attributes.put(key, value); + } + } + + public void set(String key, Float value) { + if (value != null) { + attributes.put(key, value.doubleValue()); + } + } + + public void set(String key, Double value) { + if (value != null) { + attributes.put(key, value); + } + } + + public void set(String key, String value) { + if (value != null && !value.isEmpty()) { + attributes.put(key, value); + } + } + + public void add(Map.Entry entry) { + if (entry != null && entry.getValue() != null) { + attributes.put(entry.getKey(), entry.getValue()); + } + } + + public String getString(String key) { + if (attributes.containsKey(key)) { + return (String) attributes.get(key); + } else { + return null; + } + } + + public double getDouble(String key) { + if (attributes.containsKey(key)) { + return ((Number) attributes.get(key)).doubleValue(); + } else { + return 0.0; + } + } + + public boolean getBoolean(String key) { + if (attributes.containsKey(key)) { + return (Boolean) attributes.get(key); + } else { + return false; + } + } + + public int getInteger(String key) { + if (attributes.containsKey(key)) { + return ((Number) attributes.get(key)).intValue(); + } else { + return 0; + } + } + + public long getLong(String key) { + if (attributes.containsKey(key)) { + return ((Number) attributes.get(key)).longValue(); + } else { + return 0; + } + } + +} diff --git a/src/main/java/org/traccar/model/Geofence.java b/src/main/java/org/traccar/model/Geofence.java new file mode 100644 index 000000000..8560d22e9 --- /dev/null +++ b/src/main/java/org/traccar/model/Geofence.java @@ -0,0 +1,92 @@ +/* + * Copyright 2016 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. + * 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.model; + +import java.text.ParseException; + +import org.traccar.Context; +import org.traccar.database.QueryIgnore; +import org.traccar.geofence.GeofenceCircle; +import org.traccar.geofence.GeofenceGeometry; +import org.traccar.geofence.GeofencePolygon; +import org.traccar.geofence.GeofencePolyline; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class Geofence extends ScheduledModel { + + public static final String TYPE_GEOFENCE_CILCLE = "geofenceCircle"; + public static final String TYPE_GEOFENCE_POLYGON = "geofencePolygon"; + public static final String TYPE_GEOFENCE_POLYLINE = "geofencePolyline"; + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + private String area; + + public String getArea() { + return area; + } + + public void setArea(String area) throws ParseException { + + if (area.startsWith("CIRCLE")) { + geometry = new GeofenceCircle(area); + } else if (area.startsWith("POLYGON")) { + geometry = new GeofencePolygon(area); + } else if (area.startsWith("LINESTRING")) { + final double distance = getDouble("polylineDistance"); + geometry = new GeofencePolyline(area, distance > 0 ? distance + : Context.getConfig().getDouble("geofence.polylineDistance", 25)); + } else { + throw new ParseException("Unknown geometry type", 0); + } + + this.area = area; + } + + private GeofenceGeometry geometry; + + @QueryIgnore + @JsonIgnore + public GeofenceGeometry getGeometry() { + return geometry; + } + + @QueryIgnore + @JsonIgnore + public void setGeometry(GeofenceGeometry geometry) { + area = geometry.toWkt(); + this.geometry = geometry; + } +} diff --git a/src/main/java/org/traccar/model/Group.java b/src/main/java/org/traccar/model/Group.java new file mode 100644 index 000000000..91ea2319d --- /dev/null +++ b/src/main/java/org/traccar/model/Group.java @@ -0,0 +1,30 @@ +/* + * Copyright 2016 - 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. + * 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.model; + +public class Group extends GroupedModel { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/org/traccar/model/GroupedModel.java b/src/main/java/org/traccar/model/GroupedModel.java new file mode 100644 index 000000000..6b1aa75b1 --- /dev/null +++ b/src/main/java/org/traccar/model/GroupedModel.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class GroupedModel extends ExtendedModel { + + private long groupId; + + public long getGroupId() { + return groupId; + } + + public void setGroupId(long groupId) { + this.groupId = groupId; + } + +} diff --git a/src/main/java/org/traccar/model/Maintenance.java b/src/main/java/org/traccar/model/Maintenance.java new file mode 100644 index 000000000..73f67ea96 --- /dev/null +++ b/src/main/java/org/traccar/model/Maintenance.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class Maintenance extends ExtendedModel { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + private double start; + + public double getStart() { + return start; + } + + public void setStart(double start) { + this.start = start; + } + + private double period; + + public double getPeriod() { + return period; + } + + public void setPeriod(double period) { + this.period = period; + } + +} diff --git a/src/main/java/org/traccar/model/ManagedUser.java b/src/main/java/org/traccar/model/ManagedUser.java new file mode 100644 index 000000000..03c5ef48d --- /dev/null +++ b/src/main/java/org/traccar/model/ManagedUser.java @@ -0,0 +1,21 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class ManagedUser extends User { + +} diff --git a/src/main/java/org/traccar/model/Message.java b/src/main/java/org/traccar/model/Message.java new file mode 100644 index 000000000..dad9c20f0 --- /dev/null +++ b/src/main/java/org/traccar/model/Message.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013 - 2016 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. + * 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.model; + +public class Message extends ExtendedModel { + + private long deviceId; + + public long getDeviceId() { + return deviceId; + } + + public void setDeviceId(long deviceId) { + this.deviceId = deviceId; + } + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + +} diff --git a/src/main/java/org/traccar/model/MiscFormatter.java b/src/main/java/org/traccar/model/MiscFormatter.java new file mode 100644 index 000000000..c6511f063 --- /dev/null +++ b/src/main/java/org/traccar/model/MiscFormatter.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013 - 2016 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. + * 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.model; + + +import java.text.DecimalFormat; +import java.util.Map; + +public final class MiscFormatter { + + private MiscFormatter() { + } + + private static final String XML_ROOT_NODE = "info"; + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##"); + + private static String format(Object value) { + if (value instanceof Double || value instanceof Float) { + return DECIMAL_FORMAT.format(value); + } else { + return value.toString(); + } + } + + public static String toXmlString(Map attributes) { + StringBuilder result = new StringBuilder(); + + result.append("<").append(XML_ROOT_NODE).append(">"); + + for (Map.Entry entry : attributes.entrySet()) { + + result.append("<").append(entry.getKey()).append(">"); + result.append(format(entry.getValue())); + result.append(""); + } + + result.append(""); + + return result.toString(); + } + +} diff --git a/src/main/java/org/traccar/model/Network.java b/src/main/java/org/traccar/model/Network.java new file mode 100644 index 000000000..2d56950f1 --- /dev/null +++ b/src/main/java/org/traccar/model/Network.java @@ -0,0 +1,117 @@ +/* + * Copyright 2016 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. + * 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.model; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.util.ArrayList; +import java.util.Collection; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Network { + + public Network() { + } + + public Network(CellTower cellTower) { + addCellTower(cellTower); + } + + private Integer homeMobileCountryCode; + + public Integer getHomeMobileCountryCode() { + return homeMobileCountryCode; + } + + public void setHomeMobileCountryCode(Integer homeMobileCountryCode) { + this.homeMobileCountryCode = homeMobileCountryCode; + } + + private Integer homeMobileNetworkCode; + + public Integer getHomeMobileNetworkCode() { + return homeMobileNetworkCode; + } + + public void setHomeMobileNetworkCode(Integer homeMobileNetworkCode) { + this.homeMobileNetworkCode = homeMobileNetworkCode; + } + + private String radioType = "gsm"; + + public String getRadioType() { + return radioType; + } + + public void setRadioType(String radioType) { + this.radioType = radioType; + } + + private String carrier; + + public String getCarrier() { + return carrier; + } + + public void setCarrier(String carrier) { + this.carrier = carrier; + } + + private Boolean considerIp = false; + + public Boolean getConsiderIp() { + return considerIp; + } + + public void setConsiderIp(Boolean considerIp) { + this.considerIp = considerIp; + } + + private Collection cellTowers; + + public Collection getCellTowers() { + return cellTowers; + } + + public void setCellTowers(Collection cellTowers) { + this.cellTowers = cellTowers; + } + + public void addCellTower(CellTower cellTower) { + if (cellTowers == null) { + cellTowers = new ArrayList<>(); + } + cellTowers.add(cellTower); + } + + private Collection wifiAccessPoints; + + public Collection getWifiAccessPoints() { + return wifiAccessPoints; + } + + public void setWifiAccessPoints(Collection wifiAccessPoints) { + this.wifiAccessPoints = wifiAccessPoints; + } + + public void addWifiAccessPoint(WifiAccessPoint wifiAccessPoint) { + if (wifiAccessPoints == null) { + wifiAccessPoints = new ArrayList<>(); + } + wifiAccessPoints.add(wifiAccessPoint); + } + +} diff --git a/src/main/java/org/traccar/model/Notification.java b/src/main/java/org/traccar/model/Notification.java new file mode 100644 index 000000000..f1983a03a --- /dev/null +++ b/src/main/java/org/traccar/model/Notification.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016 - 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. + * 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.model; + +import java.util.HashSet; +import java.util.Set; + +import org.traccar.database.QueryIgnore; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class Notification extends ScheduledModel { + + private boolean always; + + public boolean getAlways() { + return always; + } + + public void setAlways(boolean always) { + this.always = always; + } + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + + private String notificators; + + public String getNotificators() { + return notificators; + } + + public void setNotificators(String transports) { + this.notificators = transports; + } + + + @JsonIgnore + @QueryIgnore + public Set getNotificatorsTypes() { + final Set result = new HashSet<>(); + if (notificators != null) { + final String[] transportsList = notificators.split(","); + for (String transport : transportsList) { + result.add(transport.trim()); + } + } + return result; + } + +} diff --git a/src/main/java/org/traccar/model/Permission.java b/src/main/java/org/traccar/model/Permission.java new file mode 100644 index 000000000..1006b1c47 --- /dev/null +++ b/src/main/java/org/traccar/model/Permission.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.traccar.database.DataManager; + +public class Permission { + + private Class ownerClass; + private long ownerId; + private Class propertyClass; + private long propertyId; + + public Permission(LinkedHashMap permissionMap) throws ClassNotFoundException { + Iterator> iterator = permissionMap.entrySet().iterator(); + String owner = iterator.next().getKey(); + ownerClass = DataManager.getClassByName(owner); + String property = iterator.next().getKey(); + propertyClass = DataManager.getClassByName(property); + ownerId = permissionMap.get(owner); + propertyId = permissionMap.get(property); + } + + public Class getOwnerClass() { + return ownerClass; + } + + public long getOwnerId() { + return ownerId; + } + + public Class getPropertyClass() { + return propertyClass; + } + + public long getPropertyId() { + return propertyId; + } +} diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java new file mode 100644 index 000000000..4b327cbd2 --- /dev/null +++ b/src/main/java/org/traccar/model/Position.java @@ -0,0 +1,302 @@ +/* + * Copyright 2012 - 2016 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. + * 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.model; + +import java.util.Date; + +import org.traccar.database.QueryIgnore; + +public class Position extends Message { + + public static final String KEY_ORIGINAL = "raw"; + public static final String KEY_INDEX = "index"; + public static final String KEY_HDOP = "hdop"; + public static final String KEY_VDOP = "vdop"; + public static final String KEY_PDOP = "pdop"; + public static final String KEY_SATELLITES = "sat"; // in use + public static final String KEY_SATELLITES_VISIBLE = "satVisible"; + public static final String KEY_RSSI = "rssi"; + public static final String KEY_GPS = "gps"; + public static final String KEY_ROAMING = "roaming"; + public static final String KEY_EVENT = "event"; + public static final String KEY_ALARM = "alarm"; + public static final String KEY_STATUS = "status"; + public static final String KEY_ODOMETER = "odometer"; // meters + public static final String KEY_ODOMETER_SERVICE = "serviceOdometer"; // meters + public static final String KEY_ODOMETER_TRIP = "tripOdometer"; // meters + public static final String KEY_HOURS = "hours"; + public static final String KEY_STEPS = "steps"; + public static final String KEY_HEART_RATE = "heartRate"; + public static final String KEY_INPUT = "input"; + public static final String KEY_OUTPUT = "output"; + public static final String KEY_IMAGE = "image"; + public static final String KEY_VIDEO = "video"; + public static final String KEY_AUDIO = "audio"; + + // The units for the below four KEYs currently vary. + // The preferred units of measure are specified in the comment for each. + public static final String KEY_POWER = "power"; // volts + public static final String KEY_BATTERY = "battery"; // volts + public static final String KEY_BATTERY_LEVEL = "batteryLevel"; // percentage + public static final String KEY_FUEL_LEVEL = "fuel"; // liters + public static final String KEY_FUEL_USED = "fuelUsed"; // liters + public static final String KEY_FUEL_CONSUMPTION = "fuelConsumption"; // liters/hour + + public static final String KEY_VERSION_FW = "versionFw"; + public static final String KEY_VERSION_HW = "versionHw"; + public static final String KEY_TYPE = "type"; + public static final String KEY_IGNITION = "ignition"; + public static final String KEY_FLAGS = "flags"; + public static final String KEY_ANTENNA = "antenna"; + public static final String KEY_CHARGE = "charge"; + public static final String KEY_IP = "ip"; + public static final String KEY_ARCHIVE = "archive"; + public static final String KEY_DISTANCE = "distance"; // meters + public static final String KEY_TOTAL_DISTANCE = "totalDistance"; // meters + public static final String KEY_RPM = "rpm"; + public static final String KEY_VIN = "vin"; + public static final String KEY_APPROXIMATE = "approximate"; + public static final String KEY_THROTTLE = "throttle"; + public static final String KEY_MOTION = "motion"; + public static final String KEY_ARMED = "armed"; + public static final String KEY_GEOFENCE = "geofence"; + public static final String KEY_ACCELERATION = "acceleration"; + public static final String KEY_DEVICE_TEMP = "deviceTemp"; // celsius + public static final String KEY_COOLANT_TEMP = "coolantTemp"; // celsius + public static final String KEY_ENGINE_LOAD = "engineLoad"; + public static final String KEY_OPERATOR = "operator"; + public static final String KEY_COMMAND = "command"; + public static final String KEY_BLOCKED = "blocked"; + public static final String KEY_DOOR = "door"; + public static final String KEY_AXLE_WEIGHT = "axleWeight"; + + public static final String KEY_DTCS = "dtcs"; + public static final String KEY_OBD_SPEED = "obdSpeed"; // knots + public static final String KEY_OBD_ODOMETER = "obdOdometer"; // meters + + public static final String KEY_RESULT = "result"; + + public static final String KEY_DRIVER_UNIQUE_ID = "driverUniqueId"; + + // Start with 1 not 0 + public static final String PREFIX_TEMP = "temp"; + public static final String PREFIX_ADC = "adc"; + public static final String PREFIX_IO = "io"; + public static final String PREFIX_COUNT = "count"; + public static final String PREFIX_IN = "in"; + public static final String PREFIX_OUT = "out"; + + public static final String ALARM_GENERAL = "general"; + public static final String ALARM_SOS = "sos"; + public static final String ALARM_VIBRATION = "vibration"; + public static final String ALARM_MOVEMENT = "movement"; + public static final String ALARM_LOW_SPEED = "lowspeed"; + public static final String ALARM_OVERSPEED = "overspeed"; + public static final String ALARM_FALL_DOWN = "fallDown"; + public static final String ALARM_LOW_POWER = "lowPower"; + public static final String ALARM_LOW_BATTERY = "lowBattery"; + public static final String ALARM_FAULT = "fault"; + public static final String ALARM_POWER_OFF = "powerOff"; + public static final String ALARM_POWER_ON = "powerOn"; + public static final String ALARM_DOOR = "door"; + public static final String ALARM_LOCK = "lock"; + public static final String ALARM_UNLOCK = "unlock"; + public static final String ALARM_GEOFENCE = "geofence"; + public static final String ALARM_GEOFENCE_ENTER = "geofenceEnter"; + public static final String ALARM_GEOFENCE_EXIT = "geofenceExit"; + public static final String ALARM_GPS_ANTENNA_CUT = "gpsAntennaCut"; + public static final String ALARM_ACCIDENT = "accident"; + public static final String ALARM_TOW = "tow"; + public static final String ALARM_IDLE = "idle"; + public static final String ALARM_HIGH_RPM = "highRpm"; + public static final String ALARM_ACCELERATION = "hardAcceleration"; + public static final String ALARM_BRAKING = "hardBraking"; + public static final String ALARM_CORNERING = "hardCornering"; + public static final String ALARM_LANE_CHANGE = "laneChange"; + public static final String ALARM_FATIGUE_DRIVING = "fatigueDriving"; + public static final String ALARM_POWER_CUT = "powerCut"; + public static final String ALARM_POWER_RESTORED = "powerRestored"; + public static final String ALARM_JAMMING = "jamming"; + public static final String ALARM_TEMPERATURE = "temperature"; + public static final String ALARM_PARKING = "parking"; + public static final String ALARM_SHOCK = "shock"; + public static final String ALARM_BONNET = "bonnet"; + public static final String ALARM_FOOT_BRAKE = "footBrake"; + public static final String ALARM_FUEL_LEAK = "fuelLeak"; + public static final String ALARM_TAMPERING = "tampering"; + public static final String ALARM_REMOVING = "removing"; + + public Position() { + } + + public Position(String protocol) { + this.protocol = protocol; + this.serverTime = new Date(); + } + + private String protocol; + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + private Date serverTime; + + public Date getServerTime() { + return serverTime; + } + + public void setServerTime(Date serverTime) { + this.serverTime = serverTime; + } + + private Date deviceTime; + + public Date getDeviceTime() { + return deviceTime; + } + + public void setDeviceTime(Date deviceTime) { + this.deviceTime = deviceTime; + } + + private Date fixTime; + + public Date getFixTime() { + return fixTime; + } + + public void setFixTime(Date fixTime) { + this.fixTime = fixTime; + } + + public void setTime(Date time) { + setDeviceTime(time); + setFixTime(time); + } + + private boolean outdated; + + @QueryIgnore + public boolean getOutdated() { + return outdated; + } + + public void setOutdated(boolean outdated) { + this.outdated = outdated; + } + + private boolean valid; + + public boolean getValid() { + return valid; + } + + public void setValid(boolean valid) { + this.valid = valid; + } + + private double latitude; + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + private double longitude; + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + private double altitude; // value in meters + + public double getAltitude() { + return altitude; + } + + public void setAltitude(double altitude) { + this.altitude = altitude; + } + + private double speed; // value in knots + + public double getSpeed() { + return speed; + } + + public void setSpeed(double speed) { + this.speed = speed; + } + + private double course; + + public double getCourse() { + return course; + } + + public void setCourse(double course) { + this.course = course; + } + + private String address; + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + private double accuracy; + + public double getAccuracy() { + return accuracy; + } + + public void setAccuracy(double accuracy) { + this.accuracy = accuracy; + } + + private Network network; + + public Network getNetwork() { + return network; + } + + public void setNetwork(Network network) { + this.network = network; + } + + @Override + @QueryIgnore + public String getType() { + return super.getType(); + } + +} diff --git a/src/main/java/org/traccar/model/ScheduledModel.java b/src/main/java/org/traccar/model/ScheduledModel.java new file mode 100644 index 000000000..9e6a4b9a6 --- /dev/null +++ b/src/main/java/org/traccar/model/ScheduledModel.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.model; + +public class ScheduledModel extends ExtendedModel { + + private long calendarId; + + public long getCalendarId() { + return calendarId; + } + + public void setCalendarId(long calendarId) { + this.calendarId = calendarId; + } +} diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java new file mode 100644 index 000000000..ad37e7078 --- /dev/null +++ b/src/main/java/org/traccar/model/Server.java @@ -0,0 +1,169 @@ +/* + * Copyright 2015 - 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. + * 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.model; + +import org.traccar.database.QueryIgnore; + +public class Server extends ExtendedModel { + + @QueryIgnore + public String getVersion() { + return getClass().getPackage().getImplementationVersion(); + } + + public void setVersion(String version) { + } + + private boolean registration; + + public boolean getRegistration() { + return registration; + } + + public void setRegistration(boolean registration) { + this.registration = registration; + } + + private boolean readonly; + + public boolean getReadonly() { + return readonly; + } + + public void setReadonly(boolean readonly) { + this.readonly = readonly; + } + + private boolean deviceReadonly; + + public boolean getDeviceReadonly() { + return deviceReadonly; + } + + public void setDeviceReadonly(boolean deviceReadonly) { + this.deviceReadonly = deviceReadonly; + } + + private String map; + + public String getMap() { + return map; + } + + public void setMap(String map) { + this.map = map; + } + + private String bingKey; + + public String getBingKey() { + return bingKey; + } + + public void setBingKey(String bingKey) { + this.bingKey = bingKey; + } + + private String mapUrl; + + public String getMapUrl() { + return mapUrl; + } + + public void setMapUrl(String mapUrl) { + this.mapUrl = mapUrl; + } + + private double latitude; + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + private double longitude; + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + private int zoom; + + public int getZoom() { + return zoom; + } + + public void setZoom(int zoom) { + this.zoom = zoom; + } + + private boolean twelveHourFormat; + + public boolean getTwelveHourFormat() { + return twelveHourFormat; + } + + public void setTwelveHourFormat(boolean twelveHourFormat) { + this.twelveHourFormat = twelveHourFormat; + } + + private boolean forceSettings; + + public boolean getForceSettings() { + return forceSettings; + } + + public void setForceSettings(boolean forceSettings) { + this.forceSettings = forceSettings; + } + + private String coordinateFormat; + + public String getCoordinateFormat() { + return coordinateFormat; + } + + public void setCoordinateFormat(String coordinateFormat) { + this.coordinateFormat = coordinateFormat; + } + + private boolean limitCommands; + + public boolean getLimitCommands() { + return limitCommands; + } + + public void setLimitCommands(boolean limitCommands) { + this.limitCommands = limitCommands; + } + + private String poiLayer; + + public String getPoiLayer() { + return poiLayer; + } + + public void setPoiLayer(String poiLayer) { + this.poiLayer = poiLayer; + } +} diff --git a/src/main/java/org/traccar/model/Statistics.java b/src/main/java/org/traccar/model/Statistics.java new file mode 100644 index 000000000..cb72c91dd --- /dev/null +++ b/src/main/java/org/traccar/model/Statistics.java @@ -0,0 +1,122 @@ +/* + * Copyright 2016 - 2017 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. + * 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.model; + +import java.util.Date; + +public class Statistics extends ExtendedModel { + + private Date captureTime; + + public Date getCaptureTime() { + return captureTime; + } + + public void setCaptureTime(Date captureTime) { + this.captureTime = captureTime; + } + + private int activeUsers; + + public int getActiveUsers() { + return activeUsers; + } + + public void setActiveUsers(int activeUsers) { + this.activeUsers = activeUsers; + } + + private int activeDevices; + + public int getActiveDevices() { + return activeDevices; + } + + public void setActiveDevices(int activeDevices) { + this.activeDevices = activeDevices; + } + + private int requests; + + public int getRequests() { + return requests; + } + + public void setRequests(int requests) { + this.requests = requests; + } + + private int messagesReceived; + + public int getMessagesReceived() { + return messagesReceived; + } + + public void setMessagesReceived(int messagesReceived) { + this.messagesReceived = messagesReceived; + } + + private int messagesStored; + + public int getMessagesStored() { + return messagesStored; + } + + public void setMessagesStored(int messagesStored) { + this.messagesStored = messagesStored; + } + + private int mailSent; + + public int getMailSent() { + return mailSent; + } + + public void setMailSent(int mailSent) { + this.mailSent = mailSent; + } + + private int smsSent; + + public int getSmsSent() { + return smsSent; + } + + public void setSmsSent(int smsSent) { + this.smsSent = smsSent; + } + + private int geocoderRequests; + + public int getGeocoderRequests() { + return geocoderRequests; + } + + public void setGeocoderRequests(int geocoderRequests) { + this.geocoderRequests = geocoderRequests; + } + + private int geolocationRequests; + + public int getGeolocationRequests() { + return geolocationRequests; + } + + public void setGeolocationRequests(int geolocationRequests) { + this.geolocationRequests = geolocationRequests; + } + +} diff --git a/src/main/java/org/traccar/model/Typed.java b/src/main/java/org/traccar/model/Typed.java new file mode 100644 index 000000000..313ec7bcd --- /dev/null +++ b/src/main/java/org/traccar/model/Typed.java @@ -0,0 +1,33 @@ +/* + * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@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.model; + +public class Typed { + + private String type; + + public Typed(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java new file mode 100644 index 000000000..976b6aac0 --- /dev/null +++ b/src/main/java/org/traccar/model/User.java @@ -0,0 +1,276 @@ +/* + * Copyright 2013 - 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. + * 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.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import org.traccar.database.QueryExtended; +import org.traccar.database.QueryIgnore; +import org.traccar.helper.Hashing; + +import java.util.Date; + +public class User extends ExtendedModel { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private String login; + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + private String email; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email.trim(); + } + + private String phone; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + private boolean readonly; + + public boolean getReadonly() { + return readonly; + } + + public void setReadonly(boolean readonly) { + this.readonly = readonly; + } + + private boolean administrator; + + public boolean getAdministrator() { + return administrator; + } + + public void setAdministrator(boolean administrator) { + this.administrator = administrator; + } + + private String map; + + public String getMap() { + return map; + } + + public void setMap(String map) { + this.map = map; + } + + private double latitude; + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + private double longitude; + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + private int zoom; + + public int getZoom() { + return zoom; + } + + public void setZoom(int zoom) { + this.zoom = zoom; + } + + private boolean twelveHourFormat; + + public boolean getTwelveHourFormat() { + return twelveHourFormat; + } + + public void setTwelveHourFormat(boolean twelveHourFormat) { + this.twelveHourFormat = twelveHourFormat; + } + + private String coordinateFormat; + + public String getCoordinateFormat() { + return coordinateFormat; + } + + public void setCoordinateFormat(String coordinateFormat) { + this.coordinateFormat = coordinateFormat; + } + + private boolean disabled; + + public boolean getDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + + private Date expirationTime; + + public Date getExpirationTime() { + return expirationTime; + } + + public void setExpirationTime(Date expirationTime) { + this.expirationTime = expirationTime; + } + + private int deviceLimit; + + public int getDeviceLimit() { + return deviceLimit; + } + + public void setDeviceLimit(int deviceLimit) { + this.deviceLimit = deviceLimit; + } + + private int userLimit; + + public int getUserLimit() { + return userLimit; + } + + public void setUserLimit(int userLimit) { + this.userLimit = userLimit; + } + + private boolean deviceReadonly; + + public boolean getDeviceReadonly() { + return deviceReadonly; + } + + public void setDeviceReadonly(boolean deviceReadonly) { + this.deviceReadonly = deviceReadonly; + } + + private String token; + + public String getToken() { + return token; + } + + public void setToken(String token) { + if (token != null && !token.isEmpty()) { + if (!token.matches("^[a-zA-Z0-9-]{16,}$")) { + throw new IllegalArgumentException("Illegal token"); + } + this.token = token; + } else { + this.token = null; + } + } + + private boolean limitCommands; + + public boolean getLimitCommands() { + return limitCommands; + } + + public void setLimitCommands(boolean limitCommands) { + this.limitCommands = limitCommands; + } + + private String poiLayer; + + public String getPoiLayer() { + return poiLayer; + } + + public void setPoiLayer(String poiLayer) { + this.poiLayer = poiLayer; + } + + @QueryIgnore + public String getPassword() { + return null; + } + + public void setPassword(String password) { + if (password != null && !password.isEmpty()) { + Hashing.HashingResult hashingResult = Hashing.createHash(password); + hashedPassword = hashingResult.getHash(); + salt = hashingResult.getSalt(); + } + } + + private String hashedPassword; + + @JsonIgnore + @QueryExtended + public String getHashedPassword() { + return hashedPassword; + } + + public void setHashedPassword(String hashedPassword) { + this.hashedPassword = hashedPassword; + } + + private String salt; + + @JsonIgnore + @QueryExtended + public String getSalt() { + return salt; + } + + public void setSalt(String salt) { + this.salt = salt; + } + + public boolean isPasswordValid(String password) { + return Hashing.validatePassword(password, hashedPassword, salt); + } + +} diff --git a/src/main/java/org/traccar/model/WifiAccessPoint.java b/src/main/java/org/traccar/model/WifiAccessPoint.java new file mode 100644 index 000000000..87a77f3c0 --- /dev/null +++ b/src/main/java/org/traccar/model/WifiAccessPoint.java @@ -0,0 +1,66 @@ +/* + * Copyright 2016 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. + * 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.model; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class WifiAccessPoint { + + public static WifiAccessPoint from(String macAddress, int signalStrength) { + WifiAccessPoint wifiAccessPoint = new WifiAccessPoint(); + wifiAccessPoint.setMacAddress(macAddress); + wifiAccessPoint.setSignalStrength(signalStrength); + return wifiAccessPoint; + } + + public static WifiAccessPoint from(String macAddress, int signalStrength, int channel) { + WifiAccessPoint wifiAccessPoint = from(macAddress, signalStrength); + wifiAccessPoint.setChannel(channel); + return wifiAccessPoint; + } + + private String macAddress; + + public String getMacAddress() { + return macAddress; + } + + public void setMacAddress(String macAddress) { + this.macAddress = macAddress; + } + + private Integer signalStrength; + + public Integer getSignalStrength() { + return signalStrength; + } + + public void setSignalStrength(Integer signalStrength) { + this.signalStrength = signalStrength; + } + + private Integer channel; + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + +} diff --git a/src/main/java/org/traccar/notification/EventForwarder.java b/src/main/java/org/traccar/notification/EventForwarder.java new file mode 100644 index 000000000..c0010ebbd --- /dev/null +++ b/src/main/java/org/traccar/notification/EventForwarder.java @@ -0,0 +1,91 @@ +/* + * Copyright 2016 - 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. + * 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.notification; + +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Geofence; +import org.traccar.model.Maintenance; +import org.traccar.model.Position; + +import javax.ws.rs.client.AsyncInvoker; +import javax.ws.rs.client.Invocation; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public abstract class EventForwarder { + + private final String url; + private final String header; + + public EventForwarder() { + url = Context.getConfig().getString("event.forward.url", "http://localhost/"); + header = Context.getConfig().getString("event.forward.header"); + } + + private static final String KEY_POSITION = "position"; + private static final String KEY_EVENT = "event"; + private static final String KEY_GEOFENCE = "geofence"; + private static final String KEY_DEVICE = "device"; + private static final String KEY_MAINTENANCE = "maintenance"; + private static final String KEY_USERS = "users"; + + public final void forwardEvent(Event event, Position position, Set users) { + + Invocation.Builder requestBuilder = Context.getClient().target(url).request(); + + if (header != null && !header.isEmpty()) { + for (String line: header.split("\\r?\\n")) { + String[] values = line.split(":", 2); + requestBuilder.header(values[0].trim(), values[1].trim()); + } + } + + executeRequest(event, position, users, requestBuilder.async()); + } + + protected Map preparePayload(Event event, Position position, Set users) { + Map data = new HashMap<>(); + data.put(KEY_EVENT, event); + if (position != null) { + data.put(KEY_POSITION, position); + } + Device device = Context.getIdentityManager().getById(event.getDeviceId()); + if (device != null) { + data.put(KEY_DEVICE, device); + } + if (event.getGeofenceId() != 0) { + Geofence geofence = Context.getGeofenceManager().getById(event.getGeofenceId()); + if (geofence != null) { + data.put(KEY_GEOFENCE, geofence); + } + } + if (event.getMaintenanceId() != 0) { + Maintenance maintenance = Context.getMaintenancesManager().getById(event.getMaintenanceId()); + if (maintenance != null) { + data.put(KEY_MAINTENANCE, maintenance); + } + } + data.put(KEY_USERS, Context.getUsersManager().getItems(users)); + return data; + } + + protected abstract void executeRequest( + Event event, Position position, Set users, AsyncInvoker invoker); + +} diff --git a/src/main/java/org/traccar/notification/FullMessage.java b/src/main/java/org/traccar/notification/FullMessage.java new file mode 100644 index 000000000..f66537c6e --- /dev/null +++ b/src/main/java/org/traccar/notification/FullMessage.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notification; + +public class FullMessage { + + private String subject; + private String body; + + public FullMessage(String subject, String body) { + this.subject = subject; + this.body = body; + } + + public String getSubject() { + return subject; + } + + public String getBody() { + return body; + } +} diff --git a/src/main/java/org/traccar/notification/JsonTypeEventForwarder.java b/src/main/java/org/traccar/notification/JsonTypeEventForwarder.java new file mode 100644 index 000000000..55d926fc8 --- /dev/null +++ b/src/main/java/org/traccar/notification/JsonTypeEventForwarder.java @@ -0,0 +1,18 @@ +package org.traccar.notification; + +import java.util.Set; + +import org.traccar.model.Event; +import org.traccar.model.Position; + +import javax.ws.rs.client.AsyncInvoker; +import javax.ws.rs.client.Entity; + +public class JsonTypeEventForwarder extends EventForwarder { + + @Override + protected void executeRequest(Event event, Position position, Set users, AsyncInvoker invoker) { + invoker.post(Entity.json(preparePayload(event, position, users))); + } + +} diff --git a/src/main/java/org/traccar/notification/MessageException.java b/src/main/java/org/traccar/notification/MessageException.java new file mode 100644 index 000000000..710b927b0 --- /dev/null +++ b/src/main/java/org/traccar/notification/MessageException.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notification; + +public class MessageException extends Exception { + + public MessageException(Throwable cause) { + super(cause); + } + + public MessageException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/traccar/notification/NotificationFormatter.java b/src/main/java/org/traccar/notification/NotificationFormatter.java new file mode 100644 index 000000000..2f8100226 --- /dev/null +++ b/src/main/java/org/traccar/notification/NotificationFormatter.java @@ -0,0 +1,118 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notification; + +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Locale; + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.tools.generic.DateTool; +import org.apache.velocity.tools.generic.NumberTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.model.User; +import org.traccar.reports.ReportUtils; + +public final class NotificationFormatter { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificationFormatter.class); + + private NotificationFormatter() { + } + + public static VelocityContext prepareContext(long userId, Event event, Position position) { + + User user = Context.getPermissionsManager().getUser(userId); + Device device = Context.getIdentityManager().getById(event.getDeviceId()); + + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("user", user); + velocityContext.put("device", device); + velocityContext.put("event", event); + if (position != null) { + velocityContext.put("position", position); + velocityContext.put("speedUnit", ReportUtils.getSpeedUnit(userId)); + velocityContext.put("distanceUnit", ReportUtils.getDistanceUnit(userId)); + velocityContext.put("volumeUnit", ReportUtils.getVolumeUnit(userId)); + } + if (event.getGeofenceId() != 0) { + velocityContext.put("geofence", Context.getGeofenceManager().getById(event.getGeofenceId())); + } + if (event.getMaintenanceId() != 0) { + velocityContext.put("maintenance", Context.getMaintenancesManager().getById(event.getMaintenanceId())); + } + String driverUniqueId = event.getString(Position.KEY_DRIVER_UNIQUE_ID); + if (driverUniqueId != null) { + velocityContext.put("driver", Context.getDriversManager().getDriverByUniqueId(driverUniqueId)); + } + velocityContext.put("webUrl", Context.getVelocityEngine().getProperty("web.url")); + velocityContext.put("dateTool", new DateTool()); + velocityContext.put("numberTool", new NumberTool()); + velocityContext.put("timezone", ReportUtils.getTimezone(userId)); + velocityContext.put("locale", Locale.getDefault()); + return velocityContext; + } + + public static Template getTemplate(Event event, String path) { + + String templateFilePath; + Template template; + + try { + templateFilePath = Paths.get(path, event.getType() + ".vm").toString(); + template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); + } catch (ResourceNotFoundException error) { + LOGGER.warn("Notification template error", error); + templateFilePath = Paths.get(path, "unknown.vm").toString(); + template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); + } + return template; + } + + public static FullMessage formatFullMessage(long userId, Event event, Position position) { + VelocityContext velocityContext = prepareContext(userId, event, position); + String formattedMessage = formatMessage(velocityContext, userId, event, position, "full"); + + return new FullMessage((String) velocityContext.get("subject"), formattedMessage); + } + + public static String formatShortMessage(long userId, Event event, Position position) { + return formatMessage(null, userId, event, position, "short"); + } + + private static String formatMessage(VelocityContext vc, Long userId, Event event, Position position, + String templatePath) { + + VelocityContext velocityContext = vc; + if (velocityContext == null) { + velocityContext = prepareContext(userId, event, position); + } + StringWriter writer = new StringWriter(); + getTemplate(event, templatePath).merge(velocityContext, writer); + + return writer.toString(); + } + +} diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java new file mode 100644 index 000000000..a4080a38d --- /dev/null +++ b/src/main/java/org/traccar/notification/NotificatorManager.java @@ -0,0 +1,90 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notification; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Typed; +import org.traccar.notificators.NotificatorFirebase; +import org.traccar.notificators.NotificatorMail; +import org.traccar.notificators.NotificatorNull; +import org.traccar.notificators.Notificator; +import org.traccar.notificators.NotificatorSms; +import org.traccar.notificators.NotificatorWeb; + +public final class NotificatorManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorManager.class); + + private static final Notificator NULL_NOTIFICATOR = new NotificatorNull(); + + private final Map notificators = new HashMap<>(); + + public NotificatorManager() { + final String[] types = Context.getConfig().getString("notificator.types", "").split(","); + for (String type : types) { + String defaultNotificator = ""; + switch (type) { + case "web": + defaultNotificator = NotificatorWeb.class.getCanonicalName(); + break; + case "mail": + defaultNotificator = NotificatorMail.class.getCanonicalName(); + break; + case "sms": + defaultNotificator = NotificatorSms.class.getCanonicalName(); + break; + case "firebase": + defaultNotificator = NotificatorFirebase.class.getCanonicalName(); + break; + default: + break; + } + final String className = Context.getConfig() + .getString("notificator." + type + ".class", defaultNotificator); + try { + notificators.put(type, (Notificator) Class.forName(className).newInstance()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + LOGGER.warn("Unable to load notificator class for " + type + " " + className + " " + e.getMessage()); + } + } + } + + public Notificator getNotificator(String type) { + final Notificator notificator = notificators.get(type); + if (notificator == null) { + LOGGER.warn("No notificator configured for type : " + type); + return NULL_NOTIFICATOR; + } + return notificator; + } + + public Set getAllNotificatorTypes() { + Set result = new HashSet<>(); + for (String notificator : notificators.keySet()) { + result.add(new Typed(notificator)); + } + return result; + } + +} diff --git a/src/main/java/org/traccar/notification/PropertiesProvider.java b/src/main/java/org/traccar/notification/PropertiesProvider.java new file mode 100644 index 000000000..f0078feef --- /dev/null +++ b/src/main/java/org/traccar/notification/PropertiesProvider.java @@ -0,0 +1,81 @@ +/* + * Copyright 2016 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. + * 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.notification; + +import org.traccar.config.Config; +import org.traccar.model.ExtendedModel; + +public class PropertiesProvider { + + private Config config; + + private ExtendedModel extendedModel; + + public PropertiesProvider(Config config) { + this.config = config; + } + + public PropertiesProvider(ExtendedModel extendedModel) { + this.extendedModel = extendedModel; + } + + public String getString(String key) { + if (config != null) { + return config.getString(key); + } else { + return extendedModel.getString(key); + } + } + + public String getString(String key, String defaultValue) { + String value = getString(key); + if (value == null) { + value = defaultValue; + } + return value; + } + + public int getInteger(String key, int defaultValue) { + if (config != null) { + return config.getInteger(key, defaultValue); + } else { + Object result = extendedModel.getAttributes().get(key); + if (result != null) { + return result instanceof String ? Integer.parseInt((String) result) : (Integer) result; + } else { + return defaultValue; + } + } + } + + public Boolean getBoolean(String key) { + if (config != null) { + if (config.hasKey(key)) { + return config.getBoolean(key); + } else { + return null; + } + } else { + Object result = extendedModel.getAttributes().get(key); + if (result != null) { + return result instanceof String ? Boolean.valueOf((String) result) : (Boolean) result; + } else { + return null; + } + } + } + +} diff --git a/src/main/java/org/traccar/notificators/Notificator.java b/src/main/java/org/traccar/notificators/Notificator.java new file mode 100644 index 000000000..5e40971c6 --- /dev/null +++ b/src/main/java/org/traccar/notificators/Notificator.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notificators; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.notification.MessageException; + +public abstract class Notificator { + + private static final Logger LOGGER = LoggerFactory.getLogger(Notificator.class); + + public void sendAsync(final long userId, final Event event, final Position position) { + new Thread(new Runnable() { + public void run() { + try { + sendSync(userId, event, position); + } catch (MessageException | InterruptedException error) { + LOGGER.warn("Event send error", error); + } + } + }).start(); + } + + public abstract void sendSync(long userId, Event event, Position position) + throws MessageException, InterruptedException; + +} diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java new file mode 100644 index 000000000..75d325de2 --- /dev/null +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -0,0 +1,87 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notificators; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.model.User; +import org.traccar.notification.NotificationFormatter; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.InvocationCallback; + +public class NotificatorFirebase extends Notificator { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class); + + private static final String URL = "https://fcm.googleapis.com/fcm/send"; + + private String key; + + public static class Notification { + @JsonProperty("body") + private String body; + } + + public static class Message { + @JsonProperty("registration_ids") + private String[] tokens; + @JsonProperty("notification") + private Notification notification; + } + + public NotificatorFirebase() { + key = Context.getConfig().getString("notificator.firebase.key"); + } + + @Override + public void sendSync(long userId, Event event, Position position) { + final User user = Context.getPermissionsManager().getUser(userId); + if (user.getAttributes().containsKey("notificationTokens")) { + + Notification notification = new Notification(); + notification.body = NotificationFormatter.formatShortMessage(userId, event, position).trim(); + + Message message = new Message(); + message.tokens = user.getString("notificationTokens").split("[, ]"); + message.notification = notification; + + Context.getClient().target(URL).request() + .header("Authorization", "key=" + key) + .async().post(Entity.json(message), new InvocationCallback() { + @Override + public void completed(Object o) { + } + + @Override + public void failed(Throwable throwable) { + LOGGER.warn("Firebase notification error", throwable); + } + }); + } + } + + @Override + public void sendAsync(long userId, Event event, Position position) { + sendSync(userId, event, position); + } + +} diff --git a/src/main/java/org/traccar/notificators/NotificatorMail.java b/src/main/java/org/traccar/notificators/NotificatorMail.java new file mode 100644 index 000000000..6b9774c58 --- /dev/null +++ b/src/main/java/org/traccar/notificators/NotificatorMail.java @@ -0,0 +1,40 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notificators; + +import org.traccar.Context; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.notification.FullMessage; +import org.traccar.notification.MessageException; +import org.traccar.notification.NotificationFormatter; + +import javax.mail.MessagingException; + +public final class NotificatorMail extends Notificator { + + @Override + public void sendSync(long userId, Event event, Position position) throws MessageException { + try { + FullMessage message = NotificationFormatter.formatFullMessage(userId, event, position); + Context.getMailManager().sendMessage(userId, message.getSubject(), message.getBody()); + } catch (MessagingException e) { + throw new MessageException(e); + } + } + +} diff --git a/src/main/java/org/traccar/notificators/NotificatorNull.java b/src/main/java/org/traccar/notificators/NotificatorNull.java new file mode 100644 index 000000000..9364336be --- /dev/null +++ b/src/main/java/org/traccar/notificators/NotificatorNull.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notificators; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public final class NotificatorNull extends Notificator { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorNull.class); + + @Override + public void sendAsync(long userId, Event event, Position position) { + LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent"); + } + + @Override + public void sendSync(long userId, Event event, Position position) { + LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent"); + } + +} diff --git a/src/main/java/org/traccar/notificators/NotificatorSms.java b/src/main/java/org/traccar/notificators/NotificatorSms.java new file mode 100644 index 000000000..d5c791eae --- /dev/null +++ b/src/main/java/org/traccar/notificators/NotificatorSms.java @@ -0,0 +1,62 @@ +/* + * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notificators; + +import org.traccar.Context; +import org.traccar.Main; +import org.traccar.database.StatisticsManager; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.model.User; +import org.traccar.notification.MessageException; +import org.traccar.notification.NotificationFormatter; +import org.traccar.sms.SmsManager; + +public final class NotificatorSms extends Notificator { + + private final SmsManager smsManager; + + public NotificatorSms() throws ClassNotFoundException, InstantiationException, IllegalAccessException { + final String smsClass = Context.getConfig().getString("notificator.sms.manager.class", ""); + if (smsClass.length() > 0) { + smsManager = (SmsManager) Class.forName(smsClass).newInstance(); + } else { + smsManager = Context.getSmsManager(); + } + } + + @Override + public void sendAsync(long userId, Event event, Position position) { + final User user = Context.getPermissionsManager().getUser(userId); + if (user.getPhone() != null) { + Main.getInjector().getInstance(StatisticsManager.class).registerSms(); + smsManager.sendMessageAsync(user.getPhone(), + NotificationFormatter.formatShortMessage(userId, event, position), false); + } + } + + @Override + public void sendSync(long userId, Event event, Position position) throws MessageException, InterruptedException { + final User user = Context.getPermissionsManager().getUser(userId); + if (user.getPhone() != null) { + Main.getInjector().getInstance(StatisticsManager.class).registerSms(); + smsManager.sendMessageSync(user.getPhone(), + NotificationFormatter.formatShortMessage(userId, event, position), false); + } + } + +} diff --git a/src/main/java/org/traccar/notificators/NotificatorWeb.java b/src/main/java/org/traccar/notificators/NotificatorWeb.java new file mode 100644 index 000000000..1d11c0b46 --- /dev/null +++ b/src/main/java/org/traccar/notificators/NotificatorWeb.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.notificators; + +import org.traccar.Context; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public final class NotificatorWeb extends Notificator { + + @Override + public void sendSync(long userId, Event event, Position position) { + Context.getConnectionManager().updateEvent(userId, event); + } + +} diff --git a/src/main/java/org/traccar/protocol/AdmProtocol.java b/src/main/java/org/traccar/protocol/AdmProtocol.java new file mode 100644 index 000000000..08f932ceb --- /dev/null +++ b/src/main/java/org/traccar/protocol/AdmProtocol.java @@ -0,0 +1,44 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +import java.nio.ByteOrder; + +public class AdmProtocol extends BaseProtocol { + + public AdmProtocol() { + setSupportedDataCommands( + Command.TYPE_GET_DEVICE_STATUS, + Command.TYPE_CUSTOM); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 1, -3, 0, true)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new AdmProtocolEncoder()); + pipeline.addLast(new AdmProtocolDecoder(AdmProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java b/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java new file mode 100644 index 000000000..52d1439ed --- /dev/null +++ b/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java @@ -0,0 +1,198 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class AdmProtocolDecoder extends BaseProtocolDecoder { + + public AdmProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int CMD_RESPONSE_SIZE = 0x84; + public static final int MSG_IMEI = 0x03; + public static final int MSG_PHOTO = 0x0A; + public static final int MSG_ADM5 = 0x01; + + private Position decodeData(Channel channel, SocketAddress remoteAddress, ByteBuf buf, int type) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + if (BitUtil.to(type, 2) == 0) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); + position.set(Position.KEY_INDEX, buf.readUnsignedShortLE()); + + int status = buf.readUnsignedShortLE(); + position.set(Position.KEY_STATUS, status); + position.setValid(!BitUtil.check(status, 5)); + position.setLatitude(buf.readFloatLE()); + position.setLongitude(buf.readFloatLE()); + position.setCourse(buf.readUnsignedShortLE() * 0.1); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE() * 0.1)); + + position.set(Position.KEY_ACCELERATION, buf.readUnsignedByte() * 0.1); + position.setAltitude(buf.readShortLE()); + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte() & 0x0f); + + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + + if (BitUtil.check(type, 2)) { + buf.readUnsignedByte(); // vib + buf.readUnsignedByte(); // vib_count + + int out = buf.readUnsignedByte(); + for (int i = 0; i <= 3; i++) { + position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(out, i) ? 1 : 0); + } + + buf.readUnsignedByte(); // in_alarm + } + + if (BitUtil.check(type, 3)) { + for (int i = 1; i <= 6; i++) { + position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE() * 0.001); + } + } + + if (BitUtil.check(type, 4)) { + for (int i = 1; i <= 2; i++) { + position.set(Position.PREFIX_COUNT + i, buf.readUnsignedIntLE()); + } + } + + if (BitUtil.check(type, 5)) { + for (int i = 1; i <= 3; i++) { + buf.readUnsignedShortLE(); // fuel level + } + for (int i = 1; i <= 3; i++) { + position.set(Position.PREFIX_TEMP + i, buf.readUnsignedByte()); + } + } + + if (BitUtil.check(type, 6)) { + int endIndex = buf.readerIndex() + buf.readUnsignedByte(); + while (buf.readerIndex() < endIndex) { + int mask = buf.readUnsignedByte(); + long value; + switch (BitUtil.from(mask, 6)) { + case 3: + value = buf.readLongLE(); + break; + case 2: + value = buf.readUnsignedIntLE(); + break; + case 1: + value = buf.readUnsignedShortLE(); + break; + default: + value = buf.readUnsignedByte(); + break; + } + int index = BitUtil.to(mask, 6); + switch (index) { + case 1: + position.set(Position.PREFIX_TEMP + 1, value); + break; + case 2: + position.set("humidity", value); + break; + case 3: + position.set("illumination", value); + break; + case 4: + position.set(Position.KEY_BATTERY, value); + break; + default: + position.set("can" + index, value); + break; + } + } + } + + if (BitUtil.check(type, 7)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + } + + return position; + } + + return null; + } + + private Position parseCommandResponse(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + int responseTextLength = buf.bytesBefore((byte) 0); + if (responseTextLength < 0) { + responseTextLength = CMD_RESPONSE_SIZE - 3; + } + position.set(Position.KEY_RESULT, buf.readSlice(responseTextLength).toString(StandardCharsets.UTF_8)); + + return position; + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedShortLE(); // device id + + int size = buf.readUnsignedByte(); + if (size != CMD_RESPONSE_SIZE) { + int type = buf.readUnsignedByte(); + if (type == MSG_IMEI) { + getDeviceSession(channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.UTF_8)); + } else { + return decodeData(channel, remoteAddress, buf, type); + } + } else { + return parseCommandResponse(channel, remoteAddress, buf); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java b/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java new file mode 100644 index 000000000..e76bc2ddc --- /dev/null +++ b/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Anatoliy Golubev (darth.naihil@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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class AdmProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_GET_DEVICE_STATUS: + return formatCommand(command, "STATUS\r\n"); + + case Command.TYPE_CUSTOM: + return formatCommand(command, "{%s}\r\n", Command.KEY_DATA); + + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/AisProtocol.java b/src/main/java/org/traccar/protocol/AisProtocol.java new file mode 100644 index 000000000..3b9cad7c8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AisProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AisProtocol extends BaseProtocol { + + public AisProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new AisProtocolDecoder(AisProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AisProtocolDecoder.java b/src/main/java/org/traccar/protocol/AisProtocolDecoder.java new file mode 100644 index 000000000..8970f3d4a --- /dev/null +++ b/src/main/java/org/traccar/protocol/AisProtocolDecoder.java @@ -0,0 +1,140 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitBuffer; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +public class AisProtocolDecoder extends BaseProtocolDecoder { + + public AisProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("!AIVDM,") + .number("(d+),") // count + .number("(d+),") // index + .number("(d+)?,") // id + .expression(".,") // radio channel + .expression("([^,]+),") // payload + .any() + .compile(); + + private Position decodePayload(Channel channel, SocketAddress remoteAddress, BitBuffer buf) { + + int type = buf.readUnsigned(6); + if (type == 1 || type == 2 || type == 3 || type == 18) { + + buf.readUnsigned(2); + int mmsi = buf.readUnsigned(30); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(mmsi)); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date()); + + if (type == 18) { + buf.readUnsigned(8); // reserved + } else { + position.set(Position.KEY_STATUS, buf.readUnsigned(4)); + position.set("turn", buf.readSigned(8)); + } + + position.setSpeed(buf.readUnsigned(10) * 0.1); + position.setValid(buf.readUnsigned(1) != 0); + position.setLongitude(buf.readSigned(28) * 0.0001 / 60.0); + position.setLatitude(buf.readSigned(27) * 0.0001 / 60.0); + position.setCourse(buf.readUnsigned(12) * 0.1); + + position.set("heading", buf.readUnsigned(9)); + + return position; + + } + + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String[] sentences = ((String) msg).split("\\r\\n"); + + List positions = new ArrayList<>(); + Map buffers = new HashMap<>(); + + for (String sentence : sentences) { + if (!sentence.isEmpty()) { + Parser parser = new Parser(PATTERN, sentence); + if (parser.matches()) { + + int count = parser.nextInt(0); + int index = parser.nextInt(0); + int id = parser.nextInt(0); + + Position position = null; + + if (count == 1) { + BitBuffer bits = new BitBuffer(); + bits.writeEncoded(parser.next().getBytes(StandardCharsets.US_ASCII)); + position = decodePayload(channel, remoteAddress, bits); + } else { + BitBuffer bits = buffers.get(id); + if (bits == null) { + bits = new BitBuffer(); + buffers.put(id, bits); + } + bits.writeEncoded(parser.next().getBytes(StandardCharsets.US_ASCII)); + if (count == index) { + position = decodePayload(channel, remoteAddress, bits); + buffers.remove(id); + } + } + + if (position != null) { + positions.add(position); + } + + } + } + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/AlematicsFrameDecoder.java b/src/main/java/org/traccar/protocol/AlematicsFrameDecoder.java new file mode 100644 index 000000000..be7666657 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AlematicsFrameDecoder.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.LineBasedFrameDecoder; +import org.traccar.NetworkMessage; + +public class AlematicsFrameDecoder extends LineBasedFrameDecoder { + + private static final int MESSAGE_MINIMUM_LENGTH = 2; + + public AlematicsFrameDecoder(int maxFrameLength) { + super(maxFrameLength); + } + + // example of heartbeat: FA F8 00 07 00 03 15 AD 4E 78 3A D2 + + @Override + protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { + return null; + } + + if (buf.getUnsignedShort(buf.readerIndex()) == 0xFAF8) { + ByteBuf heartbeat = buf.readRetainedSlice(12); + if (ctx != null && ctx.channel() != null) { + ctx.channel().writeAndFlush(new NetworkMessage(heartbeat, ctx.channel().remoteAddress())); + } + } + + return super.decode(ctx, buf); + } + +} diff --git a/src/main/java/org/traccar/protocol/AlematicsProtocol.java b/src/main/java/org/traccar/protocol/AlematicsProtocol.java new file mode 100644 index 000000000..8da2356b9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AlematicsProtocol.java @@ -0,0 +1,38 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AlematicsProtocol extends BaseProtocol { + + public AlematicsProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new AlematicsFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new AlematicsProtocolDecoder(AlematicsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java new file mode 100644 index 000000000..25ccf6856 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java @@ -0,0 +1,157 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class AlematicsProtocolDecoder extends BaseProtocolDecoder { + + public AlematicsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$T,") + .number("(d+),") // type + .number("(d+),") // index + .number("(d+),") // id + .number("(dddd)(dd)(dd)") // gps date + .number("(dd)(dd)(dd),") // gps time + .number("(dddd)(dd)(dd)") // device date + .number("(dd)(dd)(dd),") // device time + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(-?d+),") // altitude + .number("(d+.d),") // hdop + .number("(d+),") // satellites + .number("(d+),") // input + .number("(d+),") // output + .number("(d+.d+),") // adc + .number("(d+.d+),") // power + .number("(d+),") // odometer + .groupBegin() + .text("0,$S,") + .expression("(.*)") // text message + .or() + .number("(d+),") // extra mask + .expression("(.*)") // extra data + .or() + .any() + .groupEnd() + .compile(); + + private void decodeExtras(Position position, Parser parser) { + + int mask = parser.nextInt(); + String[] data = parser.next().split(","); + + int index = 0; + + if (BitUtil.check(mask, 0)) { + index++; // pulse counter 3 + } + + if (BitUtil.check(mask, 1)) { + position.set(Position.KEY_POWER, Integer.parseInt(data[index++])); + } + + if (BitUtil.check(mask, 2)) { + position.set(Position.KEY_BATTERY, Integer.parseInt(data[index++])); + } + + if (BitUtil.check(mask, 3)) { + position.set(Position.KEY_OBD_SPEED, Integer.parseInt(data[index++])); + } + + if (BitUtil.check(mask, 4)) { + position.set(Position.KEY_RPM, Integer.parseInt(data[index++])); + } + + if (BitUtil.check(mask, 5)) { + position.set(Position.KEY_RSSI, Integer.parseInt(data[index++])); + } + + if (BitUtil.check(mask, 6)) { + index++; // pulse counter 2 + } + + if (BitUtil.check(mask, 7)) { + index++; // magnetic rotation sensor rpm + } + + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_TYPE, parser.nextInt()); + position.set(Position.KEY_INDEX, parser.nextInt()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setFixTime(parser.nextDateTime()); + position.setDeviceTime(parser.nextDateTime()); + + position.setValid(true); + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); + position.setCourse(parser.nextInt(0)); + position.setAltitude(parser.nextInt(0)); + + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_INPUT, parser.nextInt()); + position.set(Position.KEY_OUTPUT, parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextInt()); + + if (parser.hasNext()) { + position.set("text", parser.next()); + } else if (parser.hasNext()) { + decodeExtras(position, parser); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/AnytrekProtocol.java b/src/main/java/org/traccar/protocol/AnytrekProtocol.java new file mode 100644 index 000000000..4ab5833f7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AnytrekProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AnytrekProtocol extends BaseProtocol { + + public AnytrekProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, 2, 0)); + pipeline.addLast(new AnytrekProtocolDecoder(AnytrekProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java b/src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java new file mode 100644 index 000000000..c48f59c90 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java @@ -0,0 +1,120 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class AnytrekProtocolDecoder extends BaseProtocolDecoder { + + public AnytrekProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private void sendResponse(Channel channel, SocketAddress remoteAddress, int type) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(0x7878); + response.writeShortLE(1 + 1 + 2 + 1 + 2); // length + response.writeByte(type); + response.writeByte(0); // error + response.writeShortLE(0); // report interval + response.writeByte(0); // clear alarm + response.writeShortLE(0); // checksum + response.writeByte('\r'); + response.writeByte('\n'); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.readUnsignedShortLE(); // size + int type = buf.readUnsignedByte(); + + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(2); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_VERSION_FW, buf.readUnsignedShortLE()); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_SATELLITES, BitUtil.to(buf.readUnsignedByte(), 4)); + + double latitude = buf.readUnsignedIntLE() / 1800000.0; + double longitude = buf.readUnsignedIntLE() / 1800000.0; + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + int flags = buf.readUnsignedShortLE(); + position.setCourse(BitUtil.to(flags, 10)); + position.setValid(BitUtil.check(flags, 12)); + + if (!BitUtil.check(flags, 10)) { + latitude = -latitude; + } + if (BitUtil.check(flags, 11)) { + longitude = -longitude; + } + + position.setLatitude(latitude); + position.setLongitude(longitude); + + buf.readUnsignedIntLE(); // info index + buf.readUnsignedIntLE(); // setting index + + flags = buf.readUnsignedByte(); + position.set(Position.KEY_CHARGE, BitUtil.check(flags, 0)); + position.set(Position.KEY_IGNITION, BitUtil.check(flags, 1)); + position.set(Position.KEY_ALARM, BitUtil.check(flags, 4) ? Position.ALARM_GENERAL : null); + + buf.readUnsignedShortLE(); // charge current + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + + sendResponse(channel, remoteAddress, type); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ApelProtocol.java b/src/main/java/org/traccar/protocol/ApelProtocol.java new file mode 100644 index 000000000..382aa16af --- /dev/null +++ b/src/main/java/org/traccar/protocol/ApelProtocol.java @@ -0,0 +1,36 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; +public class ApelProtocol extends BaseProtocol { + + public ApelProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, 4, 0, true)); + pipeline.addLast(new ApelProtocolDecoder(ApelProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java b/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java new file mode 100644 index 000000000..c95a0366a --- /dev/null +++ b/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java @@ -0,0 +1,210 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class ApelProtocolDecoder extends BaseProtocolDecoder { + + private long lastIndex; + private long newIndex; + + public ApelProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final short MSG_NULL = 0; + public static final short MSG_REQUEST_TRACKER_ID = 10; + public static final short MSG_TRACKER_ID = 11; + public static final short MSG_TRACKER_ID_EXT = 12; + public static final short MSG_DISCONNECT = 20; + public static final short MSG_REQUEST_PASSWORD = 30; + public static final short MSG_PASSWORD = 31; + public static final short MSG_REQUEST_STATE_FULL_INFO = 90; + public static final short MSG_STATE_FULL_INFO_T104 = 92; + public static final short MSG_REQUEST_CURRENT_GPS_DATA = 100; + public static final short MSG_CURRENT_GPS_DATA = 101; + public static final short MSG_REQUEST_SENSORS_STATE = 110; + public static final short MSG_SENSORS_STATE = 111; + public static final short MSG_SENSORS_STATE_T100 = 112; + public static final short MSG_SENSORS_STATE_T100_4 = 113; + public static final short MSG_REQUEST_LAST_LOG_INDEX = 120; + public static final short MSG_LAST_LOG_INDEX = 121; + public static final short MSG_REQUEST_LOG_RECORDS = 130; + public static final short MSG_LOG_RECORDS = 131; + public static final short MSG_EVENT = 141; + public static final short MSG_TEXT = 150; + public static final short MSG_ACK_ALARM = 160; + public static final short MSG_SET_TRACKER_MODE = 170; + public static final short MSG_GPRS_COMMAND = 180; + + private void sendSimpleMessage(Channel channel, short type) { + ByteBuf request = Unpooled.buffer(8); + request.writeShortLE(type); + request.writeShortLE(0); + request.writeIntLE(Checksum.crc32(request.nioBuffer(0, 4))); + channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress())); + } + + private void requestArchive(Channel channel) { + if (lastIndex == 0) { + lastIndex = newIndex; + } else if (newIndex > lastIndex) { + ByteBuf request = Unpooled.buffer(14); + request.writeShortLE(MSG_REQUEST_LOG_RECORDS); + request.writeShortLE(6); + request.writeIntLE((int) lastIndex); + request.writeShortLE(512); + request.writeIntLE(Checksum.crc32(request.nioBuffer(0, 10))); + channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + int type = buf.readUnsignedShortLE(); + boolean alarm = (type & 0x8000) != 0; + type = type & 0x7FFF; + buf.readUnsignedShortLE(); // length + + if (alarm) { + sendSimpleMessage(channel, MSG_ACK_ALARM); + } + + if (type == MSG_TRACKER_ID) { + return null; // unsupported authentication type + } + + if (type == MSG_TRACKER_ID_EXT) { + + buf.readUnsignedIntLE(); // id + int length = buf.readUnsignedShortLE(); + buf.skipBytes(length); + length = buf.readUnsignedShortLE(); + getDeviceSession(channel, remoteAddress, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); + + } else if (type == MSG_LAST_LOG_INDEX) { + + long index = buf.readUnsignedIntLE(); + if (index > 0) { + newIndex = index; + requestArchive(channel); + } + + } else if (type == MSG_CURRENT_GPS_DATA || type == MSG_STATE_FULL_INFO_T104 || type == MSG_LOG_RECORDS) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + int recordCount = 1; + if (type == MSG_LOG_RECORDS) { + recordCount = buf.readUnsignedShortLE(); + } + + for (int j = 0; j < recordCount; j++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + int subtype = type; + if (type == MSG_LOG_RECORDS) { + position.set(Position.KEY_ARCHIVE, true); + lastIndex = buf.readUnsignedIntLE() + 1; + position.set(Position.KEY_INDEX, lastIndex); + + subtype = buf.readUnsignedShortLE(); + if (subtype != MSG_CURRENT_GPS_DATA && subtype != MSG_STATE_FULL_INFO_T104) { + buf.skipBytes(buf.readUnsignedShortLE()); + continue; + } + buf.readUnsignedShortLE(); // length + } + + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + position.setLatitude(buf.readIntLE() * 180.0 / 0x7FFFFFFF); + position.setLongitude(buf.readIntLE() * 180.0 / 0x7FFFFFFF); + + if (subtype == MSG_STATE_FULL_INFO_T104) { + int speed = buf.readUnsignedByte(); + position.setValid(speed != 255); + position.setSpeed(UnitsConverter.knotsFromKph(speed)); + position.set(Position.KEY_HDOP, buf.readByte()); + } else { + int speed = buf.readShortLE(); + position.setValid(speed != -1); + position.setSpeed(UnitsConverter.knotsFromKph(speed * 0.01)); + } + + position.setCourse(buf.readShortLE() * 0.01); + position.setAltitude(buf.readShortLE()); + + if (subtype == MSG_STATE_FULL_INFO_T104) { + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + + for (int i = 1; i <= 8; i++) { + position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE()); + } + + position.set(Position.PREFIX_COUNT + 1, buf.readUnsignedIntLE()); + position.set(Position.PREFIX_COUNT + 2, buf.readUnsignedIntLE()); + position.set(Position.PREFIX_COUNT + 3, buf.readUnsignedIntLE()); + } + + positions.add(position); + } + + buf.readUnsignedIntLE(); // crc + + if (type == MSG_LOG_RECORDS) { + requestArchive(channel); + } else { + sendSimpleMessage(channel, MSG_REQUEST_LAST_LOG_INDEX); + } + + return positions; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/AplicomFrameDecoder.java b/src/main/java/org/traccar/protocol/AplicomFrameDecoder.java new file mode 100644 index 000000000..56fca27c7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AplicomFrameDecoder.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class AplicomFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + // Skip Alive message + while (buf.isReadable() && Character.isDigit(buf.getByte(buf.readerIndex()))) { + buf.readByte(); + } + + // Check minimum length + if (buf.readableBytes() < 11) { + return null; + } + + // Read flags + int version = buf.getUnsignedByte(buf.readerIndex() + 1); + int offset = 1 + 1 + 3; + if ((version & 0x80) != 0) { + offset += 4; + } + + // Get data length + int length = buf.getUnsignedShort(buf.readerIndex() + offset); + offset += 2; + if ((version & 0x40) != 0) { + offset += 3; + } + length += offset; // add header + + // Return buffer + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/AplicomProtocol.java b/src/main/java/org/traccar/protocol/AplicomProtocol.java new file mode 100644 index 000000000..2b9dbf97c --- /dev/null +++ b/src/main/java/org/traccar/protocol/AplicomProtocol.java @@ -0,0 +1,34 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AplicomProtocol extends BaseProtocol { + + public AplicomProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new AplicomFrameDecoder()); + pipeline.addLast(new AplicomProtocolDecoder(AplicomProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java b/src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java new file mode 100644 index 000000000..215aa0211 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java @@ -0,0 +1,702 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Date; + +public class AplicomProtocolDecoder extends BaseProtocolDecoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(AplicomProtocolDecoder.class); + + public AplicomProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final long IMEI_BASE_TC65_V20 = 0x1437207000000L; + private static final long IMEI_BASE_TC65_V28 = 358244010000000L; + private static final long IMEI_BASE_TC65I_V11 = 0x14143B4000000L; + + private static boolean validateImei(long imei) { + return Checksum.luhn(imei / 10) == imei % 10; + } + + private static long imeiFromUnitId(long unitId) { + + if (unitId == 0) { + + return 0; + + } else { + + // Try TC65i + long imei = IMEI_BASE_TC65I_V11 + unitId; + if (validateImei(imei)) { + return imei; + } + + // Try TC65 v2.8 + imei = IMEI_BASE_TC65_V28 + ((unitId + 0xA8180) & 0xFFFFFF); + if (validateImei(imei)) { + return imei; + } + + // Try TC65 v2.0 + imei = IMEI_BASE_TC65_V20 + unitId; + if (validateImei(imei)) { + return imei; + } + + } + + return unitId; + } + + private static final int DEFAULT_SELECTOR_D = 0x0002fC; + private static final int DEFAULT_SELECTOR_E = 0x007ffc; + private static final int DEFAULT_SELECTOR_F = 0x0007fd; + + private static final int EVENT_DATA = 119; + + private void decodeEventData(Position position, ByteBuf buf, int event) { + switch (event) { + case 2: + case 40: + buf.readUnsignedByte(); + break; + case 9: + buf.readUnsignedMedium(); + break; + case 31: + case 32: + buf.readUnsignedShort(); + break; + case 38: + buf.skipBytes(4 * 9); + break; + case 113: + buf.readUnsignedInt(); + buf.readUnsignedByte(); + break; + case 119: + position.set("eventData", ByteBufUtil.hexDump( + buf, buf.readerIndex(), Math.min(buf.readableBytes(), 1024))); + break; + case 121: + case 142: + buf.readLong(); + break; + case 130: + buf.readUnsignedInt(); // incorrect + break; + case 188: + decodeEB(position, buf); + break; + default: + break; + } + } + + private void decodeCanData(ByteBuf buf, Position position) { + + buf.readUnsignedMedium(); // packet identifier + position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); + int count = buf.readUnsignedByte(); + buf.readUnsignedByte(); // batch count + buf.readUnsignedShort(); // selector bit + buf.readUnsignedInt(); // timestamp + + buf.skipBytes(8); + + ArrayList values = new ArrayList<>(count); + + for (int i = 0; i < count; i++) { + values.add(buf.readSlice(8)); + } + + for (int i = 0; i < count; i++) { + ByteBuf value = values.get(i); + switch (buf.readInt()) { + case 0x20D: + position.set(Position.KEY_RPM, value.readShortLE()); + position.set("dieselTemperature", value.readShortLE() * 0.1); + position.set("batteryVoltage", value.readShortLE() * 0.01); + position.set("supplyAirTempDep1", value.readShortLE() * 0.1); + break; + case 0x30D: + position.set("activeAlarm", ByteBufUtil.hexDump(value)); + break; + case 0x40C: + position.set("airTempDep1", value.readShortLE() * 0.1); + position.set("airTempDep2", value.readShortLE() * 0.1); + break; + case 0x40D: + position.set("coldUnitState", ByteBufUtil.hexDump(value)); + break; + case 0x50C: + position.set("defrostTempDep1", value.readShortLE() * 0.1); + position.set("defrostTempDep2", value.readShortLE() * 0.1); + break; + case 0x50D: + position.set("condenserPressure", value.readShortLE() * 0.1); + position.set("suctionPressure", value.readShortLE() * 0.1); + break; + case 0x58C: + value.readByte(); + value.readShort(); // index + switch (value.readByte()) { + case 0x01: + position.set("setpointZone1", value.readIntLE() * 0.1); + break; + case 0x02: + position.set("setpointZone2", value.readIntLE() * 0.1); + break; + case 0x05: + position.set("unitType", value.readIntLE()); + break; + case 0x13: + position.set("dieselHours", value.readIntLE() / 60 / 60); + break; + case 0x14: + position.set("electricHours", value.readIntLE() / 60 / 60); + break; + case 0x17: + position.set("serviceIndicator", value.readIntLE()); + break; + case 0x18: + position.set("softwareVersion", value.readIntLE() * 0.01); + break; + default: + break; + } + break; + default: + LOGGER.warn("Aplicom CAN decoding error", new UnsupportedOperationException()); + break; + } + } + } + + private void decodeD(Position position, ByteBuf buf, int selector, int event) { + + if ((selector & 0x0008) != 0) { + position.setValid((buf.readUnsignedByte() & 0x40) != 0); + } else { + getLastLocation(position, null); + } + + if ((selector & 0x0004) != 0) { + position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000)); + } + + if ((selector & 0x0008) != 0) { + position.setFixTime(new Date(buf.readUnsignedInt() * 1000)); + if (position.getDeviceTime() == null) { + position.setDeviceTime(position.getFixTime()); + } + position.setLatitude(buf.readInt() / 1000000.0); + position.setLongitude(buf.readInt() / 1000000.0); + position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); + } + + if ((selector & 0x0010) != 0) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.set("maximumSpeed", buf.readUnsignedByte()); + position.setCourse(buf.readUnsignedByte() * 2.0); + } + + if ((selector & 0x0040) != 0) { + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + } + + if ((selector & 0x0020) != 0) { + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShort()); + } + + if ((selector & 0x8000) != 0) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); + } + + // Pulse rate 1 + if ((selector & 0x10000) != 0) { + buf.readUnsignedShort(); + buf.readUnsignedInt(); + } + + // Pulse rate 2 + if ((selector & 0x20000) != 0) { + buf.readUnsignedShort(); + buf.readUnsignedInt(); + } + + if ((selector & 0x0080) != 0) { + position.set("trip1", buf.readUnsignedInt()); + } + + if ((selector & 0x0100) != 0) { + position.set("trip2", buf.readUnsignedInt()); + } + + if ((selector & 0x0040) != 0) { + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + } + + if ((selector & 0x0200) != 0) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, + String.valueOf(((long) buf.readUnsignedShort()) << 32) + buf.readUnsignedInt()); + } + + if ((selector & 0x0400) != 0) { + buf.readUnsignedByte(); // Keypad + } + + if ((selector & 0x0800) != 0) { + position.setAltitude(buf.readShort()); + } + + if ((selector & 0x2000) != 0) { + buf.readUnsignedShort(); // snapshot counter + } + + if ((selector & 0x4000) != 0) { + buf.skipBytes(8); // state flags + } + + if ((selector & 0x80000) != 0) { + buf.skipBytes(11); // cell info + } + + if ((selector & 0x1000) != 0) { + decodeEventData(position, buf, event); + } + + if (Context.getConfig().getBoolean(getProtocolName() + ".can") + && buf.isReadable() && (selector & 0x1000) != 0 && event == EVENT_DATA) { + decodeCanData(buf, position); + } + } + + private void decodeE(Position position, ByteBuf buf, int selector) { + + if ((selector & 0x0008) != 0) { + position.set("tachographEvent", buf.readUnsignedShort()); + } + + if ((selector & 0x0004) != 0) { + getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); + } else { + getLastLocation(position, null); + } + + if ((selector & 0x0010) != 0) { + String time = buf.readUnsignedByte() + "s " + buf.readUnsignedByte() + "m " + buf.readUnsignedByte() + "h " + + buf.readUnsignedByte() + "M " + buf.readUnsignedByte() + "D " + buf.readUnsignedByte() + "Y " + + buf.readByte() + "m " + buf.readByte() + "h"; + position.set("tachographTime", time); + } + + position.set("workState", buf.readUnsignedByte()); + position.set("driver1State", buf.readUnsignedByte()); + position.set("driver2State", buf.readUnsignedByte()); + + if ((selector & 0x0020) != 0) { + position.set("tachographStatus", buf.readUnsignedByte()); + } + + if ((selector & 0x0040) != 0) { + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() / 256.0); + } + + if ((selector & 0x0080) != 0) { + position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 5); + } + + if ((selector & 0x0100) != 0) { + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt() * 5); + } + + if ((selector & 0x8000) != 0) { + position.set("kFactor", buf.readUnsignedShort() * 0.001 + " pulses/m"); + } + + if ((selector & 0x0200) != 0) { + position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); + } + + if ((selector & 0x0400) != 0) { + position.set("extraInfo", buf.readUnsignedShort()); + } + + if ((selector & 0x0800) != 0) { + position.set(Position.KEY_VIN, buf.readSlice(18).toString(StandardCharsets.US_ASCII).trim()); + } + + if ((selector & 0x2000) != 0) { + buf.readUnsignedByte(); // card 1 type + buf.readUnsignedByte(); // card 1 country code + String card = buf.readSlice(20).toString(StandardCharsets.US_ASCII).trim(); + if (!card.isEmpty()) { + position.set("card1", card); + } + } + + if ((selector & 0x4000) != 0) { + buf.readUnsignedByte(); // card 2 type + buf.readUnsignedByte(); // card 2 country code + String card = buf.readSlice(20).toString(StandardCharsets.US_ASCII).trim(); + if (!card.isEmpty()) { + position.set("card2", card); + } + } + + if ((selector & 0x10000) != 0) { + int count = buf.readUnsignedByte(); + for (int i = 1; i <= count; i++) { + position.set("driver" + i, buf.readSlice(22).toString(StandardCharsets.US_ASCII).trim()); + position.set("driverTime" + i, buf.readUnsignedInt()); + } + } + } + + private void decodeH(Position position, ByteBuf buf, int selector) { + + if ((selector & 0x0004) != 0) { + getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); + } else { + getLastLocation(position, null); + } + + if ((selector & 0x0040) != 0) { + buf.readUnsignedInt(); // reset time + } + + if ((selector & 0x2000) != 0) { + buf.readUnsignedShort(); // snapshot counter + } + + int index = 1; + while (buf.readableBytes() > 0) { + + position.set("h" + index + "Index", buf.readUnsignedByte()); + + buf.readUnsignedShort(); // length + + int n = buf.readUnsignedByte(); + int m = buf.readUnsignedByte(); + + position.set("h" + index + "XLength", n); + position.set("h" + index + "YLength", m); + + if ((selector & 0x0008) != 0) { + position.set("h" + index + "XType", buf.readUnsignedByte()); + position.set("h" + index + "YType", buf.readUnsignedByte()); + position.set("h" + index + "Parameters", buf.readUnsignedByte()); + } + + boolean percentageFormat = (selector & 0x0020) != 0; + + StringBuilder data = new StringBuilder(); + for (int i = 0; i < n * m; i++) { + if (percentageFormat) { + data.append(buf.readUnsignedByte() * 0.5).append("%").append(" "); + } else { + data.append(buf.readUnsignedShort()).append(" "); + } + } + + position.set("h" + index + "Data", data.toString().trim()); + + position.set("h" + index + "Total", buf.readUnsignedInt()); + + if ((selector & 0x0010) != 0) { + int k = buf.readUnsignedByte(); + + data = new StringBuilder(); + for (int i = 1; i < n; i++) { + if (k == 1) { + data.append(buf.readByte()).append(" "); + } else if (k == 2) { + data.append(buf.readShort()).append(" "); + } + } + position.set("h" + index + "XLimits", data.toString().trim()); + + data = new StringBuilder(); + for (int i = 1; i < m; i++) { + if (k == 1) { + data.append(buf.readByte()).append(" "); + } else if (k == 2) { + data.append(buf.readShort()).append(" "); + } + } + position.set("h" + index + "YLimits", data.toString().trim()); + } + + index += 1; + } + } + + private void decodeEB(Position position, ByteBuf buf) { + + if (buf.readByte() != (byte) 'E' || buf.readByte() != (byte) 'B') { + return; + } + + position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + position.set("dataValidity", buf.readUnsignedByte()); + position.set("towed", buf.readUnsignedByte()); + buf.readUnsignedShort(); // length + + while (buf.readableBytes() > 0) { + buf.readUnsignedByte(); // towed position + int type = buf.readUnsignedByte(); + int length = buf.readUnsignedByte(); + int end = buf.readerIndex() + length; + + switch (type) { + case 0x01: + position.set("brakeFlags", ByteBufUtil.hexDump(buf.readSlice(length))); + break; + case 0x02: + position.set("wheelSpeed", buf.readUnsignedShort() / 256.0); + position.set("wheelSpeedDifference", buf.readUnsignedShort() / 256.0 - 125.0); + position.set("lateralAcceleration", buf.readUnsignedByte() / 10.0 - 12.5); + position.set("vehicleSpeed", buf.readUnsignedShort() / 256.0); + break; + case 0x03: + position.set(Position.KEY_AXLE_WEIGHT, buf.readUnsignedShort() * 2); + break; + case 0x04: + position.set("tyrePressure", buf.readUnsignedByte() * 10); + position.set("pneumaticPressure", buf.readUnsignedByte() * 5); + break; + case 0x05: + position.set("brakeLining", buf.readUnsignedByte() * 0.4); + position.set("brakeTemperature", buf.readUnsignedByte() * 10); + break; + case 0x06: + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 5L); + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt() * 5L); + position.set(Position.KEY_ODOMETER_SERVICE, (buf.readUnsignedInt() - 2105540607) * 5L); + break; + case 0x0A: + position.set("absStatusCounter", buf.readUnsignedShort()); + position.set("atvbStatusCounter", buf.readUnsignedShort()); + position.set("vdcActiveCounter", buf.readUnsignedShort()); + break; + case 0x0B: + position.set("brakeMinMaxData", ByteBufUtil.hexDump(buf.readSlice(length))); + break; + case 0x0C: + position.set("missingPgn", ByteBufUtil.hexDump(buf.readSlice(length))); + break; + case 0x0D: + buf.readUnsignedByte(); + position.set("towedDetectionStatus", buf.readUnsignedInt()); + buf.skipBytes(17); // vin + break; + case 0x0E: + default: + break; + } + + buf.readerIndex(end); + } + } + + private void decodeF(Position position, ByteBuf buf, int selector) { + + Date deviceTime = null; + + if ((selector & 0x0004) != 0) { + deviceTime = new Date(buf.readUnsignedInt() * 1000); + } + + getLastLocation(position, deviceTime); + + buf.readUnsignedByte(); // data validity + + if ((selector & 0x0008) != 0) { + position.set(Position.KEY_RPM, buf.readUnsignedShort()); + position.set("rpmMax", buf.readUnsignedShort()); + position.set("rpmMin", buf.readUnsignedShort()); + } + + if ((selector & 0x0010) != 0) { + position.set("engineTemp", buf.readShort()); + position.set("engineTempMax", buf.readShort()); + position.set("engineTempMin", buf.readShort()); + } + + if ((selector & 0x0020) != 0) { + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(buf.readUnsignedInt())); + position.set("serviceDistance", buf.readInt()); + position.set("driverActivity", buf.readUnsignedByte()); + position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); + } + + if ((selector & 0x0040) != 0) { + position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt()); + } + + if ((selector & 0x0080) != 0) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + } + + if ((selector & 0x0100) != 0) { + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); + position.set("speedMax", buf.readUnsignedByte()); + position.set("speedMin", buf.readUnsignedByte()); + position.set("hardBraking", buf.readUnsignedByte()); + } + + if ((selector & 0x0200) != 0) { + position.set("tachographSpeed", buf.readUnsignedByte()); + position.set("driver1State", buf.readUnsignedByte()); + position.set("driver2State", buf.readUnsignedByte()); + position.set("tachographStatus", buf.readUnsignedByte()); + position.set("overspeedCount", buf.readUnsignedByte()); + } + + if ((selector & 0x0800) != 0) { + position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 0.05); + position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() / 256.0); + position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.5); + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); + } + + if ((selector & 0x1000) != 0) { + position.set("ambientTemperature", buf.readUnsignedShort() * 0.03125 - 273); + buf.readUnsignedShort(); // fuel rate + position.set("fuelEconomy", buf.readUnsignedShort() / 512.0); + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt() * 0.001); + buf.readUnsignedByte(); // pto drive engagement + } + + if ((selector & 0x2000) != 0) { + buf.skipBytes(buf.readUnsignedByte()); // driver identification + } + + if ((selector & 0x4000) != 0) { + position.set("torque", buf.readUnsignedByte()); + position.set("brakePressure1", buf.readUnsignedByte() * 8); + position.set("brakePressure2", buf.readUnsignedByte() * 8); + position.set("grossWeight", buf.readUnsignedShort() * 10); + position.set("exhaustFluid", buf.readUnsignedByte() * 0.4); + buf.readUnsignedByte(); // retarder torque mode + position.set("retarderTorque", buf.readUnsignedByte()); + position.set("retarderSelection", buf.readUnsignedByte() * 0.4); + buf.skipBytes(8); // tell tale status block 1 + buf.skipBytes(8); // tell tale status block 2 + buf.skipBytes(8); // tell tale status block 3 + buf.skipBytes(8); // tell tale status block 4 + } + + if ((selector & 0x8000) != 0) { + position.set("parkingBrakeStatus", buf.readUnsignedByte()); + position.set("doorStatus", buf.readUnsignedByte()); + buf.skipBytes(8); // status per door + position.set("alternatorStatus", buf.readUnsignedByte()); + position.set("selectedGear", buf.readUnsignedByte()); + position.set("currentGear", buf.readUnsignedByte()); + buf.skipBytes(4 * 2); // air suspension pressure + } + + if ((selector & 0x0400) != 0) { + int count = buf.readUnsignedByte(); + for (int i = 0; i < count; i++) { + position.set("axle" + i, buf.readUnsignedShort()); + } + } + + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + char protocol = (char) buf.readByte(); + int version = buf.readUnsignedByte(); + + String imei; + if ((version & 0x80) != 0) { + imei = String.valueOf((buf.readUnsignedInt() << (3 * 8)) | buf.readUnsignedMedium()); + } else { + imei = String.valueOf(imeiFromUnitId(buf.readUnsignedMedium())); + } + + buf.readUnsignedShort(); // length + + int selector = DEFAULT_SELECTOR_D; + if (protocol == 'E') { + selector = DEFAULT_SELECTOR_E; + } else if (protocol == 'F') { + selector = DEFAULT_SELECTOR_F; + } + if ((version & 0x40) != 0) { + selector = buf.readUnsignedMedium(); + } + + Position position = new Position(getProtocolName()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + int event = buf.readUnsignedByte(); + position.set(Position.KEY_EVENT, event); + position.set("eventInfo", buf.readUnsignedByte()); + + if (protocol == 'D') { + decodeD(position, buf, selector, event); + } else if (protocol == 'E') { + decodeE(position, buf, selector); + } else if (protocol == 'H') { + decodeH(position, buf, selector); + } else if (protocol == 'F') { + decodeF(position, buf, selector); + } else { + return null; + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/AppelloProtocol.java b/src/main/java/org/traccar/protocol/AppelloProtocol.java new file mode 100644 index 000000000..1ca4168e4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AppelloProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AppelloProtocol extends BaseProtocol { + + public AppelloProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new AppelloProtocolDecoder(AppelloProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java b/src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java new file mode 100644 index 000000000..47e329234 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java @@ -0,0 +1,92 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class AppelloProtocolDecoder extends BaseProtocolDecoder { + + public AppelloProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("FOLLOWIT,") // brand + .number("(d+),") // imei + .groupBegin() + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .or() + .text("UTCTIME,") + .groupEnd() + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+),") // satellites + .number("(-?d+),") // altitude + .expression("([FL]),") // gps state + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + String imei = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.hasNext(6)) { + position.setTime(parser.nextDateTime()); + } else { + getLastLocation(position, null); + } + + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + + position.setAltitude(parser.nextDouble(0)); + + position.setValid(parser.next().equals("F")); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/AppletProtocol.java b/src/main/java/org/traccar/protocol/AppletProtocol.java new file mode 100644 index 000000000..2297dca03 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AppletProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AppletProtocol extends BaseProtocol { + + public AppletProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new AppletProtocolDecoder(AppletProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AppletProtocolDecoder.java b/src/main/java/org/traccar/protocol/AppletProtocolDecoder.java new file mode 100644 index 000000000..7a995cc24 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AppletProtocolDecoder.java @@ -0,0 +1,48 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; + +import java.net.SocketAddress; + +public class AppletProtocolDecoder extends BaseHttpProtocolDecoder { + + public AppletProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, request.headers().get("From")); + if (deviceSession != null) { + sendResponse(channel, HttpResponseStatus.OK); + } else { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/AquilaProtocol.java b/src/main/java/org/traccar/protocol/AquilaProtocol.java new file mode 100644 index 000000000..5ca1ec091 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AquilaProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AquilaProtocol extends BaseProtocol { + + public AquilaProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new AquilaProtocolDecoder(AquilaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java b/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java new file mode 100644 index 000000000..57af5e366 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java @@ -0,0 +1,403 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class AquilaProtocolDecoder extends BaseProtocolDecoder { + + public AquilaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_A = new PatternBuilder() + .text("$$") + .expression("[^,]*,") // client + .number("(d+),") // device serial number + .number("(d+),") // event + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .groupBegin() + .number("(d+),") // gsm + .number("(d+),") // speed + .number("(d+),") // distance + .groupBegin() + .number("d+,") // driver code + .number("(d+),") // fuel + .number("([01]),") // io 1 + .number("[01],") // case open switch + .number("[01],") // over speed start + .number("[01],") // over speed end + .number("(?:d+,){3}") // reserved + .number("([01]),") // power status + .number("([01]),") // io 2 + .number("d+,") // reserved + .number("([01]),") // ignition + .number("[01],") // ignition off event + .number("(?:d+,){7}") // reserved + .number("[01],") // corner packet + .number("(?:d+,){8}") // reserved + .number("([01]),") // course bit 0 + .number("([01]),") // course bit 1 + .number("([01]),") // course bit 2 + .number("([01]),") // course bit 3 + .or() + .number("(d+),") // course + .number("(?:d+,){3}") // reserved + .number("[01],") // over speed start + .number("[01],") // over speed end + .number("(?:d+,){3}") // reserved + .number("([01]),") // power status + .number("(?:d+,){2}") // reserved + .number("[01],") // ignition on event + .number("([01]),") // ignition + .number("[01],") // ignition off event + .number("(?:d+,){5}") // reserved + .number("[01],") // low battery + .number("[01],") // corner packet + .number("(?:d+,){6}") // reserved + .number("[01],") // hard acceleration + .number("[01],") // hard braking + .number("[01],[01],[01],[01],") // course bits + .number("(d+),") // external voltage + .number("(d+),") // internal voltage + .number("(?:d+,){6}") // reserved + .expression("P([^,]+),") // obd + .expression("D([^,]+),") // dtcs + .number("-?d+,") // accelerometer x + .number("-?d+,") // accelerometer y + .number("-?d+,") // accelerometer z + .number("d+,") // delta distance + .or() + .number("(d+),") // course + .number("(d+),") // satellites + .number("(d+.d+),") // hdop + .number("(?:d+,){2}") // reserved + .number("(d+),") // adc 1 + .number("([01]),") // di 1 + .number("[01],") // case open + .number("[01],") // over speed start + .number("[01],") // over speed end + .number("(?:[01],){2}") // reserved + .number("[01],") // immobilizer + .number("([01]),") // power status + .number("([01]),") // di 2 + .number("(?:[01],){2}") // reserved + .number("([01]),") // ignition + .number("(?:[01],){6}") // reserved + .number("[01],") // low battery + .number("[01],") // corner packet + .number("(?:[01],){4}") // reserved + .number("[01],") // do 1 + .number("[01],") // reserved + .number("[01],") // hard acceleration + .number("[01],") // hard braking + .number("(?:[01],){4}") // reserved + .number("(d+),") // external voltage + .number("(d+),") // internal voltage + .groupEnd() + .or() + .number("(d+),") // sensor id + .expression("([^,]+),") // sensor data + .groupEnd() + .text("*") + .number("xx") // checksum + .compile(); + + private Position decodeA(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_A, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, parser.nextInt(0)); + + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + + position.setTime(parser.nextDateTime()); + + position.setValid(parser.next().equals("A")); + + if (parser.hasNext(3)) { + position.set(Position.KEY_RSSI, parser.nextInt(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + } + + if (parser.hasNext(9)) { + + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); + position.set(Position.PREFIX_IN + 1, parser.next()); + position.set(Position.KEY_CHARGE, parser.next().equals("1")); + position.set(Position.PREFIX_IN + 2, parser.next()); + + position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); + + int course = (parser.nextInt(0) << 3) + (parser.nextInt(0) << 2) + + (parser.nextInt(0) << 1) + parser.nextInt(0); + if (course > 0 && course <= 8) { + position.setCourse((course - 1) * 45); + } + + } else if (parser.hasNext(7)) { + + position.setCourse(parser.nextInt(0)); + + position.set(Position.KEY_CHARGE, parser.next().equals("1")); + position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); + position.set(Position.KEY_POWER, parser.nextInt(0)); + position.set(Position.KEY_BATTERY, parser.nextInt(0)); + + String obd = parser.next(); + position.set("obd", obd.substring(1, obd.length() - 1)); + + String dtcs = parser.next(); + position.set(Position.KEY_DTCS, dtcs.substring(1, dtcs.length() - 1).replace('|', ' ')); + + } else if (parser.hasNext(10)) { + + position.setCourse(parser.nextInt(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_HDOP, parser.nextDouble(0)); + position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); + position.set(Position.PREFIX_IN + 1, parser.nextInt(0)); + position.set(Position.KEY_CHARGE, parser.next().equals("1")); + position.set(Position.PREFIX_IN + 2, parser.nextInt(0)); + position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); + position.set(Position.KEY_POWER, parser.nextInt(0)); + position.set(Position.KEY_BATTERY, parser.nextInt(0)); + + } else if (parser.hasNext(2)) { + + position.set("sensorId", parser.nextInt()); + position.set("sensorData", parser.next()); + + } + + return position; + } + + private static final Pattern PATTERN_B_1 = new PatternBuilder() + .text("$") + .expression("[^,]+,") // header + .expression("[^,]+,") // client + .expression("[^,]+,") // firmware version + .expression(".{2},") // packet type + .number("d+,") // message id + .expression("[LH],") // status + .number("(d+),") // imei + .expression("[^,]+,") // registration number + .number("([01]),") // validity + .number("(dd)(dd)(dddd),") // date (ddmmyyyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // latitude + .expression("([NS]),") + .number("(-?d+.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+),") // speed + .number("(d+),") // course + .number("(d+),") // satellites + .number("(-?d+.d+),") // altitude + .number("(d+.d+),") // pdop + .number("(d+.d+),") // hdop + .expression("[^,]+,") // operator + .number("([01]),") // ignition + .number("([01]),") // charge + .number("(d+.d+),") // power + .number("(d+.d+),") // battery + .number("([01]),") // emergency + .expression("[CO],") // tamper + .number("(d+),") // rssi + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(x+),") // lac + .number("(x+),") // cid + .number("(d+),(x+),(x+),") // cell 1 + .number("(d+),(x+),(x+),") // cell 2 + .number("(d+),(x+),(x+),") // cell 3 + .number("(d+),(x+),(x+),") // cell 4 + .number("([01])+,") // inputs + .number("([01])+,") // outputs + .number("d+,") // frame number + .number("(d+.d+),") // adc1 + .number("(d+.d+),") // adc2 + .number("d+,") // delta distance + .any() + .compile(); + + private static final Pattern PATTERN_B_2 = new PatternBuilder() + .text("$") + .expression("[^,]+,") // header + .expression("[^,]+,") // client + .expression("(.{3}),") // message type + .number("(d+),") // imei + .expression(".{2},") // packet type + .number("(dd)(dd)(dddd)") // date (ddmmyyyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .number("(-?d+.d+),") // latitude + .expression("([NS]),") + .number("(-?d+.d+),") // longitude + .expression("([EW]),") + .number("(-?d+.d+),") // altitude + .number("(d+.d+),") // speed + .any() + .compile(); + + private Position decodeB2(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_B_2, sentence); + if (!parser.matches()) { + return null; + } + + String type = parser.next(); + String id = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setAltitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + + if (type.equals("EMR") && channel != null) { + String password = Context.getIdentityManager().lookupAttributeString( + deviceSession.getDeviceId(), getProtocolName() + ".password", "aquila123", true); + channel.writeAndFlush(new NetworkMessage( + "#set$" + id + "@" + password + "#EMR_MODE:0*", remoteAddress)); + } + + return position; + } + + private Position decodeB1(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_B_1, sentence); + if (!parser.matches()) { + return null; + } + + String id = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.nextInt() == 1); + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextInt()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + position.setAltitude(parser.nextDouble()); + + position.set(Position.KEY_PDOP, parser.nextDouble()); + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + position.set(Position.KEY_CHARGE, parser.nextInt() == 1); + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + + if (parser.nextInt() == 1) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + + Network network = new Network(); + + int rssi = parser.nextInt(); + int mcc = parser.nextInt(); + int mnc = parser.nextInt(); + + network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt(), rssi)); + for (int i = 0; i < 4; i++) { + rssi = parser.nextInt(); + network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt(), rssi)); + } + + position.setNetwork(network); + + position.set(Position.KEY_INPUT, parser.nextBinInt()); + position.set(Position.KEY_OUTPUT, parser.nextBinInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); + + return position; + } + + private Position decodeB(Channel channel, SocketAddress remoteAddress, String sentence) { + if (sentence.contains("EMR") || sentence.contains("SEM")) { + return decodeB2(channel, remoteAddress, sentence); + } else { + return decodeB1(channel, remoteAddress, sentence); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("$$")) { + return decodeA(channel, remoteAddress, sentence); + } else { + return decodeB(channel, remoteAddress, sentence); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Ardi01Protocol.java b/src/main/java/org/traccar/protocol/Ardi01Protocol.java new file mode 100644 index 000000000..f7826430f --- /dev/null +++ b/src/main/java/org/traccar/protocol/Ardi01Protocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Ardi01Protocol extends BaseProtocol { + + public Ardi01Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Ardi01ProtocolDecoder(Ardi01Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java new file mode 100644 index 000000000..85e9ecfde --- /dev/null +++ b/src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java @@ -0,0 +1,87 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Ardi01ProtocolDecoder extends BaseProtocolDecoder { + + public Ardi01ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+),") // imei + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(-?d+.?d*),") // altitude + .number("(d+),") // satellites + .number("(d+),") // event + .number("(d+),") // battery + .number("(-?d+)") // temperature + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setLongitude(parser.nextDouble(0)); + position.setLatitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + int satellites = parser.nextInt(0); + position.setValid(satellites >= 3); + position.set(Position.KEY_SATELLITES, satellites); + + position.set(Position.KEY_EVENT, parser.next()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); + position.set(Position.PREFIX_TEMP + 1, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ArknavProtocol.java b/src/main/java/org/traccar/protocol/ArknavProtocol.java new file mode 100644 index 000000000..3b485e4a5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArknavProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ArknavProtocol extends BaseProtocol { + + public ArknavProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new ArknavProtocolDecoder(ArknavProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java new file mode 100644 index 000000000..4982e02fc --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java @@ -0,0 +1,83 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class ArknavProtocolDecoder extends BaseProtocolDecoder { + + public ArknavProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+),") // imei + .expression(".{6},") // id code + .number("ddd,") // status + .number("Lddd,") // version + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(d+.?d*),") // hdop + .number("(dd):(dd):(dd) ") // time (hh:mm:ss) + .number("(dd)-(dd)-(dd),") // date (dd-mm-yy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_HDOP, parser.nextDouble(0)); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ArknavX8Protocol.java b/src/main/java/org/traccar/protocol/ArknavX8Protocol.java new file mode 100644 index 000000000..a29bc1ad3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArknavX8Protocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ArknavX8Protocol extends BaseProtocol { + + public ArknavX8Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new ArknavX8ProtocolDecoder(ArknavX8Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java new file mode 100644 index 000000000..b570f5423 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java @@ -0,0 +1,139 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class ArknavX8ProtocolDecoder extends BaseProtocolDecoder { + + public ArknavX8ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_1G = new PatternBuilder() + .expression("(..),") // type + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+)([NS]),") // latitude + .number("(d+)(dd.d+)([EW]),") // longitude + .number("(d+.d+),") // speed + .number("(d+),") // course + .number("(d+.d+),") // hdop + .number("(d+)") // status + .compile(); + + private static final Pattern PATTERN_2G = new PatternBuilder() + .expression("..,") // type + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d+),") // satellites + .number("(d+.d+),") // altitude + .number("(d+.d+),") // power + .number("(d+.d+),") // battery + .number("(d+.d+)") // odometer + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.charAt(2) != ',') { + getDeviceSession(channel, remoteAddress, sentence.substring(0, 15)); + return null; + } + + switch (sentence.substring(0, 2)) { + case "1G": + case "1R": + case "1M": + return decode1G(channel, remoteAddress, sentence); + case "2G": + return decode2G(channel, remoteAddress, sentence); + default: + return null; + } + } + + private Position decode1G(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_1G, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_TYPE, parser.next()); + + position.setTime(parser.nextDateTime()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_HDOP, parser.nextDouble(0)); + position.set(Position.KEY_STATUS, parser.next()); + + return position; + } + + private Position decode2G(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_2G, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, parser.nextDateTime()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.setAltitude(parser.nextDouble()); + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1852 / 3600); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocol.java b/src/main/java/org/traccar/protocol/ArnaviProtocol.java new file mode 100644 index 000000000..afe491865 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArnaviProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ArnaviProtocol extends BaseProtocol { + + public ArnaviProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new ArnaviProtocolDecoder(ArnaviProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java new file mode 100644 index 000000000..7996cf429 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java @@ -0,0 +1,105 @@ +/* + * Copyright 2015 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class ArnaviProtocolDecoder extends BaseProtocolDecoder { + + public ArnaviProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$AV,") + .number("Vd,") // type + .number("(d+),") // device id + .number("(d+),") // index + .number("(d+),") // power + .number("(d+),") // battery + .number("-?d+,") + .expression("[01],") // movement + .expression("([01]),") // ignition + .number("(d+),") // input + .number("d+,d+,") // input 1 + .number("d+,d+,").optional() // input 2 + .expression("[01],") // fix type + .number("(d+),") // satellites + .groupBegin() + .number("(d+.d+)?,") // altitude + .number("(?:d+.d+)?,") // geoid height + .groupEnd("?") + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd.d+)([NS]),") // latitude + .number("(ddd)(dd.d+)([EW]),") // longitude + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, parser.nextInt()); + position.set(Position.KEY_POWER, parser.nextInt() * 0.01); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.01); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + position.set(Position.KEY_INPUT, parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + position.setAltitude(parser.nextDouble(0)); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/AstraProtocol.java b/src/main/java/org/traccar/protocol/AstraProtocol.java new file mode 100644 index 000000000..12b0dfb68 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AstraProtocol.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AstraProtocol extends BaseProtocol { + + public AstraProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2, -3, 0)); + pipeline.addLast(new AstraProtocolDecoder(AstraProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new AstraProtocolDecoder(AstraProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java b/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java new file mode 100644 index 000000000..e6f546b9f --- /dev/null +++ b/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java @@ -0,0 +1,129 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; + +public class AstraProtocolDecoder extends BaseProtocolDecoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(AstraProtocolDecoder.class); + + public AstraProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_HEARTBEAT = 0x1A; + public static final int MSG_DATA = 0x10; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(new byte[] {0x06}), remoteAddress)); + } + + buf.readUnsignedByte(); // protocol + buf.readUnsignedShort(); // length + + String imei = String.format("%08d", buf.readUnsignedInt()) + String.format("%07d", buf.readUnsignedMedium()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + while (buf.readableBytes() > 2) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedByte(); // index + + position.setValid(true); + position.setLatitude(buf.readInt() * 0.000001); + position.setLongitude(buf.readInt() * 0.000001); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(1980, 1, 6).addMillis(buf.readUnsignedInt() * 1000L); + position.setTime(dateBuilder.getDate()); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte() * 2)); + position.setCourse(buf.readUnsignedByte() * 2); + + int reason = buf.readUnsignedMedium(); + position.set(Position.KEY_EVENT, reason); + + int status = buf.readUnsignedShort(); + position.set(Position.KEY_STATUS, status); + + position.set(Position.PREFIX_IO + 1, buf.readUnsignedByte()); + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); + position.set(Position.KEY_POWER, buf.readUnsignedByte()); + + buf.readUnsignedByte(); // max journey speed + buf.skipBytes(6); // accelerometer + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShort()); + buf.readUnsignedShort(); // journey idle time + + position.setAltitude(buf.readUnsignedByte() * 20); + + int quality = buf.readUnsignedByte(); + position.set(Position.KEY_SATELLITES, quality & 0xf); + position.set(Position.KEY_RSSI, quality >> 4); + + buf.readUnsignedByte(); // geofence events + + if (BitUtil.check(status, 8)) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, buf.readSlice(7).toString(StandardCharsets.US_ASCII)); + position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium() * 1000); + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(buf.readUnsignedShort())); + } + + if (BitUtil.check(status, 6)) { + LOGGER.warn("Extension data is not supported"); + return position; + } + + positions.add(position); + + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/At2000FrameDecoder.java b/src/main/java/org/traccar/protocol/At2000FrameDecoder.java new file mode 100644 index 000000000..5fa82a5f7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/At2000FrameDecoder.java @@ -0,0 +1,81 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; +import org.traccar.NetworkMessage; + +public class At2000FrameDecoder extends BaseFrameDecoder { + + private static final int BLOCK_LENGTH = 16; + private static final int ACK_LENGTH = 496; + + private boolean firstPacket = true; + + private ByteBuf currentBuffer; + private int acknowledgedBytes; + + private void sendResponse(Channel channel) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(2 * BLOCK_LENGTH); + response.writeByte(At2000ProtocolDecoder.MSG_ACKNOWLEDGEMENT); + response.writeMedium(1); + response.writeByte(0x00); // success + response.writerIndex(2 * BLOCK_LENGTH); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 5) { + return null; + } + + int length; + if (firstPacket) { + firstPacket = false; + length = buf.getUnsignedMediumLE(buf.readerIndex() + 2); + } else { + length = buf.getUnsignedMediumLE(buf.readerIndex() + 1); + } + + length += BLOCK_LENGTH; + if (length % BLOCK_LENGTH != 0) { + length = (length / BLOCK_LENGTH + 1) * BLOCK_LENGTH; + } + + if ((buf.readableBytes() >= length || buf.readableBytes() % ACK_LENGTH == 0) + && (buf != currentBuffer || buf.readableBytes() > acknowledgedBytes)) { + sendResponse(channel); + currentBuffer = buf; + acknowledgedBytes = buf.readableBytes(); + } + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/At2000Protocol.java b/src/main/java/org/traccar/protocol/At2000Protocol.java new file mode 100644 index 000000000..5894f3eab --- /dev/null +++ b/src/main/java/org/traccar/protocol/At2000Protocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 2016 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class At2000Protocol extends BaseProtocol { + + public At2000Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new At2000FrameDecoder()); + pipeline.addLast(new At2000ProtocolDecoder(At2000Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java b/src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java new file mode 100644 index 000000000..43798eb67 --- /dev/null +++ b/src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java @@ -0,0 +1,171 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DataConverter; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class At2000ProtocolDecoder extends BaseProtocolDecoder { + + private static final int BLOCK_LENGTH = 16; + + public At2000ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_ACKNOWLEDGEMENT = 0x00; + public static final int MSG_DEVICE_ID = 0x01; + public static final int MSG_TRACK_REQUEST = 0x88; + public static final int MSG_TRACK_RESPONSE = 0x89; + public static final int MSG_SESSION_END = 0x0c; + + private Cipher cipher; + + private static void sendRequest(Channel channel) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(BLOCK_LENGTH); + response.writeByte(MSG_TRACK_REQUEST); + response.writeMedium(0); + response.writerIndex(BLOCK_LENGTH); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (buf.getUnsignedByte(buf.readerIndex()) == 0x01) { + buf.readUnsignedByte(); // codec id + } + + int type = buf.readUnsignedByte(); + buf.readUnsignedMediumLE(); // length + buf.skipBytes(BLOCK_LENGTH - 1 - 3); + + if (type == MSG_DEVICE_ID) { + + String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); + if (getDeviceSession(channel, remoteAddress, imei) != null) { + + byte[] iv = new byte[BLOCK_LENGTH]; + buf.readBytes(iv); + IvParameterSpec ivSpec = new IvParameterSpec(iv); + + SecretKeySpec keySpec = new SecretKeySpec( + DataConverter.parseHex("000102030405060708090a0b0c0d0e0f"), "AES"); + + cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); + + byte[] data = new byte[BLOCK_LENGTH]; + buf.readBytes(data); + cipher.update(data); + + } + + } else if (type == MSG_TRACK_RESPONSE) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + if (buf.capacity() <= BLOCK_LENGTH) { + return null; // empty message + } + + List positions = new LinkedList<>(); + + byte[] data = new byte[buf.capacity() - BLOCK_LENGTH]; + buf.readBytes(data); + buf = Unpooled.wrappedBuffer(cipher.update(data)); + try { + while (buf.readableBytes() >= 63) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedShortLE(); // index + buf.readUnsignedShortLE(); // reserved + + position.setValid(true); + + position.setTime(new Date(buf.readLongLE() * 1000)); + + position.setLatitude(buf.readFloatLE()); + position.setLongitude(buf.readFloatLE()); + position.setAltitude(buf.readFloatLE()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readFloatLE())); + position.setCourse(buf.readFloatLE()); + + buf.readUnsignedIntLE(); // geozone event + buf.readUnsignedIntLE(); // io events + buf.readUnsignedIntLE(); // geozone value + buf.readUnsignedIntLE(); // io values + buf.readUnsignedShortLE(); // operator + + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); + + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); + + buf.readUnsignedShortLE(); // cid + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + buf.readUnsignedByte(); // current profile + + position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); + position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte()); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + positions.add(position); + + } + } finally { + buf.release(); + } + + return positions; + + } + + if (type == MSG_DEVICE_ID) { + sendRequest(channel); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/AtrackFrameDecoder.java b/src/main/java/org/traccar/protocol/AtrackFrameDecoder.java new file mode 100644 index 000000000..f071e2d97 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AtrackFrameDecoder.java @@ -0,0 +1,80 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; +import org.traccar.helper.BufferUtil; + +import java.nio.charset.StandardCharsets; + +public class AtrackFrameDecoder extends BaseFrameDecoder { + + private static final int KEEPALIVE_LENGTH = 12; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() >= 2) { + + if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) { + + if (buf.readableBytes() >= KEEPALIVE_LENGTH) { + return buf.readRetainedSlice(KEEPALIVE_LENGTH); + } + + } else if (buf.getUnsignedShort(buf.readerIndex()) == 0x4050 && buf.getByte(buf.readerIndex() + 2) != ',') { + + if (buf.readableBytes() > 6) { + int length = buf.getUnsignedShort(buf.readerIndex() + 4) + 4 + 2; + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } + + } else { + + int lengthStart = buf.indexOf(buf.readerIndex() + 3, buf.writerIndex(), (byte) ',') + 1; + if (lengthStart > 0) { + int lengthEnd = buf.indexOf(lengthStart, buf.writerIndex(), (byte) ','); + if (lengthEnd > 0) { + int length = lengthEnd + Integer.parseInt(buf.toString( + lengthStart, lengthEnd - lengthStart, StandardCharsets.US_ASCII)); + if (buf.readableBytes() > length && buf.getByte(buf.readerIndex() + length) == '\n') { + length += 1; + } + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } + } else { + int endIndex = BufferUtil.indexOf("\r\n", buf); + if (endIndex > 0) { + return buf.readRetainedSlice(endIndex - buf.readerIndex() + 2); + } + } + + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/AtrackProtocol.java b/src/main/java/org/traccar/protocol/AtrackProtocol.java new file mode 100644 index 000000000..8e5cfe9ff --- /dev/null +++ b/src/main/java/org/traccar/protocol/AtrackProtocol.java @@ -0,0 +1,45 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class AtrackProtocol extends BaseProtocol { + + public AtrackProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new AtrackFrameDecoder()); + pipeline.addLast(new AtrackProtocolEncoder()); + pipeline.addLast(new AtrackProtocolDecoder(AtrackProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new AtrackProtocolEncoder()); + pipeline.addLast(new AtrackProtocolDecoder(AtrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java new file mode 100644 index 000000000..71bb6791c --- /dev/null +++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java @@ -0,0 +1,586 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AtrackProtocolDecoder extends BaseProtocolDecoder { + + private static final int MIN_DATA_LENGTH = 40; + + private boolean longDate; + private boolean decimalFuel; + private boolean custom; + private String form; + + private final Map alarmMap = new HashMap<>(); + + public AtrackProtocolDecoder(Protocol protocol) { + super(protocol); + + longDate = Context.getConfig().getBoolean(getProtocolName() + ".longDate"); + decimalFuel = Context.getConfig().getBoolean(getProtocolName() + ".decimalFuel"); + + custom = Context.getConfig().getBoolean(getProtocolName() + ".custom"); + form = Context.getConfig().getString(getProtocolName() + ".form"); + if (form != null) { + custom = true; + } + + for (String pair : Context.getConfig().getString(getProtocolName() + ".alarmMap", "").split(",")) { + if (!pair.isEmpty()) { + alarmMap.put( + Integer.parseInt(pair.substring(0, pair.indexOf('='))), pair.substring(pair.indexOf('=') + 1)); + } + } + } + + public void setLongDate(boolean longDate) { + this.longDate = longDate; + } + + public void setCustom(boolean custom) { + this.custom = custom; + } + + private static void sendResponse(Channel channel, SocketAddress remoteAddress, long rawId, int index) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(12); + response.writeShort(0xfe02); + response.writeLong(rawId); + response.writeShort(index); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private static String readString(ByteBuf buf) { + String result = null; + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0); + if (index > buf.readerIndex()) { + result = buf.readSlice(index - buf.readerIndex()).toString(StandardCharsets.US_ASCII); + } + buf.readByte(); + return result; + } + + private void readTextCustomData(Position position, String data, String form) { + CellTower cellTower = new CellTower(); + String[] keys = form.substring(1).split("%"); + String[] values = data.split(",|\r\n"); + for (int i = 0; i < Math.min(keys.length, values.length); i++) { + switch (keys[i]) { + case "SA": + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[i])); + break; + case "MV": + position.set(Position.KEY_POWER, Integer.parseInt(values[i]) * 0.1); + break; + case "BV": + position.set(Position.KEY_BATTERY, Integer.parseInt(values[i]) * 0.1); + break; + case "GQ": + cellTower.setSignalStrength(Integer.parseInt(values[i])); + break; + case "CE": + cellTower.setCellId(Long.parseLong(values[i])); + break; + case "LC": + cellTower.setLocationAreaCode(Integer.parseInt(values[i])); + break; + case "CN": + if (values[i].length() > 3) { + cellTower.setMobileCountryCode(Integer.parseInt(values[i].substring(0, 3))); + cellTower.setMobileNetworkCode(Integer.parseInt(values[i].substring(3))); + } + break; + case "PC": + position.set(Position.PREFIX_COUNT + 1, Integer.parseInt(values[i])); + break; + case "AT": + position.setAltitude(Integer.parseInt(values[i])); + break; + case "RP": + position.set(Position.KEY_RPM, Integer.parseInt(values[i])); + break; + case "GS": + position.set(Position.KEY_RSSI, Integer.parseInt(values[i])); + break; + case "DT": + position.set(Position.KEY_ARCHIVE, Integer.parseInt(values[i]) == 1); + break; + case "VN": + position.set(Position.KEY_VIN, values[i]); + break; + case "TR": + position.set(Position.KEY_THROTTLE, Integer.parseInt(values[i])); + break; + case "ET": + position.set(Position.PREFIX_TEMP + 1, Integer.parseInt(values[i])); + break; + case "FL": + position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(values[i])); + break; + case "FC": + position.set(Position.KEY_FUEL_CONSUMPTION, Integer.parseInt(values[i])); + break; + case "AV1": + position.set(Position.PREFIX_ADC + 1, Integer.parseInt(values[i])); + break; + default: + break; + } + } + + if (cellTower.getMobileCountryCode() != null + && cellTower.getMobileNetworkCode() != null + && cellTower.getCellId() != null + && cellTower.getLocationAreaCode() != null) { + position.setNetwork(new Network(cellTower)); + } else if (cellTower.getSignalStrength() != null) { + position.set(Position.KEY_RSSI, cellTower.getSignalStrength()); + } + } + + private void readBinaryCustomData(Position position, ByteBuf buf, String form) { + CellTower cellTower = new CellTower(); + String[] keys = form.substring(1).split("%"); + for (String key : keys) { + switch (key) { + case "SA": + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case "MV": + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); + break; + case "BV": + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.1); + break; + case "GQ": + cellTower.setSignalStrength((int) buf.readUnsignedByte()); + break; + case "CE": + cellTower.setCellId(buf.readUnsignedInt()); + break; + case "LC": + cellTower.setLocationAreaCode(buf.readUnsignedShort()); + break; + case "CN": + int combinedMobileCodes = (int) (buf.readUnsignedInt() % 100000); // cccnn + cellTower.setMobileCountryCode(combinedMobileCodes / 100); + cellTower.setMobileNetworkCode(combinedMobileCodes % 100); + break; + case "RL": + buf.readUnsignedByte(); // rxlev + break; + case "PC": + position.set(Position.PREFIX_COUNT + 1, buf.readUnsignedInt()); + break; + case "AT": + position.setAltitude(buf.readUnsignedInt()); + break; + case "RP": + position.set(Position.KEY_RPM, buf.readUnsignedShort()); + break; + case "GS": + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; + case "DT": + position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() == 1); + break; + case "VN": + position.set(Position.KEY_VIN, readString(buf)); + break; + case "MF": + buf.readUnsignedShort(); // mass air flow rate + break; + case "EL": + buf.readUnsignedByte(); // engine load + break; + case "TR": + position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); + break; + case "ET": + position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort()); + break; + case "FL": + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); + break; + case "ML": + buf.readUnsignedByte(); // mil status + break; + case "FC": + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt()); + break; + case "CI": + readString(buf); // format string + break; + case "AV1": + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + break; + case "NC": + readString(buf); // gsm neighbor cell info + break; + case "SM": + buf.readUnsignedShort(); // max speed between reports + break; + case "GL": + readString(buf); // google link + break; + case "MA": + readString(buf); // mac address + break; + case "PD": + buf.readUnsignedByte(); // pending code status + break; + case "CD": + readString(buf); // sim cid + break; + case "CM": + buf.readLong(); // imsi + break; + case "GN": + buf.skipBytes(60); // g sensor data + break; + case "GV": + buf.skipBytes(6); // maximum g force + break; + case "ME": + buf.readLong(); // imei + break; + case "IA": + buf.readUnsignedByte(); // intake air temperature + break; + case "MP": + buf.readUnsignedByte(); // manifold absolute pressure + break; + default: + break; + } + } + + if (cellTower.getMobileCountryCode() != null + && cellTower.getMobileNetworkCode() != null + && cellTower.getCellId() != null && cellTower.getCellId() != 0 + && cellTower.getLocationAreaCode() != null) { + position.setNetwork(new Network(cellTower)); + } else if (cellTower.getSignalStrength() != null) { + position.set(Position.KEY_RSSI, cellTower.getSignalStrength()); + } + } + + private static final Pattern PATTERN_INFO = new PatternBuilder() + .text("$INFO=") + .number("(d+),") // unit id + .expression("([^,]+),") // model + .expression("([^,]+),") // firmware version + .number("d+,") // imei + .number("d+,") // imsi + .number("d+,") // sim card id + .number("(d+),") // power + .number("(d+),") // battery + .number("(d+),") // satellites + .number("d+,") // gsm status + .number("(d+),") // rssi + .number("d+,") // connection status + .number("d+") // antenna status + .any() + .compile(); + + private Position decodeInfo(Channel channel, SocketAddress remoteAddress, String sentence) { + + Position position = new Position(getProtocolName()); + + getLastLocation(position, null); + + DeviceSession deviceSession; + + if (sentence.startsWith("$INFO")) { + + Parser parser = new Parser(PATTERN_INFO, sentence); + if (!parser.matches()) { + return null; + } + + deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + + position.set("model", parser.next()); + position.set(Position.KEY_VERSION_FW, parser.next()); + position.set(Position.KEY_POWER, parser.nextInt() * 0.1); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextInt()); + + } else { + + deviceSession = getDeviceSession(channel, remoteAddress); + + position.set(Position.KEY_RESULT, sentence); + + } + + if (deviceSession == null) { + return null; + } else { + position.setDeviceId(deviceSession.getDeviceId()); + return position; + } + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+),") // date and time + .number("d+,") // rtc date and time + .number("d+,") // device date and time + .number("(-?d+),") // longitude + .number("(-?d+),") // latitude + .number("(d+),") // course + .number("(d+),") // report id + .number("(d+.?d*),") // odometer + .number("(d+),") // hdop + .number("(d+),") // inputs + .number("(d+),") // speed + .number("(d+),") // outputs + .number("(d+),") // adc + .number("([^,]+)?,") // driver + .number("(d+),") // temp1 + .number("(d+),") // temp2 + .expression("[^,]*,") // text message + .expression("(.*)") // custom data + .optional(2) + .compile(); + + private List decodeText(Channel channel, SocketAddress remoteAddress, String sentence) { + + int startIndex = 0; + for (int i = 0; i < 4; i++) { + startIndex = sentence.indexOf(',', startIndex + 1); + } + int endIndex = sentence.indexOf(',', startIndex + 1); + + String imei = sentence.substring(startIndex + 1, endIndex); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + String[] lines = sentence.substring(endIndex + 1).split("\r\n"); + + for (String line : lines) { + Position position = decodeTextLine(deviceSession, line); + if (position != null) { + positions.add(position); + } + } + + return positions; + } + + + private Position decodeTextLine(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + + String time = parser.next(); + if (time.length() >= 14) { + try { + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(time)); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } else { + position.setTime(new Date(Long.parseLong(time) * 1000)); + } + + position.setLongitude(parser.nextInt() * 0.000001); + position.setLatitude(parser.nextInt() * 0.000001); + position.setCourse(parser.nextInt()); + + position.set(Position.KEY_EVENT, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 100); + position.set(Position.KEY_HDOP, parser.nextInt() * 0.1); + position.set(Position.KEY_INPUT, parser.nextInt()); + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + + position.set(Position.KEY_OUTPUT, parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextInt()); + + if (parser.hasNext()) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + } + + position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 2, parser.nextInt()); + + if (custom) { + String data = parser.next(); + String form = this.form; + if (form == null) { + form = data.substring(0, data.indexOf(',')).substring("%CI".length()); + data = data.substring(data.indexOf(',') + 1); + } + readTextCustomData(position, data, form); + } + + return position; + } + + private List decodeBinary(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + buf.skipBytes(2); // prefix + buf.readUnsignedShort(); // checksum + buf.readUnsignedShort(); // length + int index = buf.readUnsignedShort(); + + long id = buf.readLong(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + + sendResponse(channel, remoteAddress, id, index); + + List positions = new LinkedList<>(); + + while (buf.readableBytes() >= MIN_DATA_LENGTH) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (longDate) { + + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedShort(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + buf.skipBytes(7 + 7); + + } else { + position.setFixTime(new Date(buf.readUnsignedInt() * 1000)); + position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000)); + buf.readUnsignedInt(); // send time + } + + position.setValid(true); + position.setLongitude(buf.readInt() * 0.000001); + position.setLatitude(buf.readInt() * 0.000001); + position.setCourse(buf.readUnsignedShort()); + + int type = buf.readUnsignedByte(); + position.set(Position.KEY_TYPE, type); + position.set(Position.KEY_ALARM, alarmMap.get(type)); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); + position.set(Position.KEY_HDOP, buf.readUnsignedShort() * 0.1); + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.001); + + position.set(Position.KEY_DRIVER_UNIQUE_ID, readString(buf)); + + position.set(Position.PREFIX_TEMP + 1, buf.readShort() * 0.1); + position.set(Position.PREFIX_TEMP + 2, buf.readShort() * 0.1); + + String message = readString(buf); + if (message != null && !message.isEmpty()) { + Pattern pattern = Pattern.compile("FULS:F=(\\p{XDigit}+) t=(\\p{XDigit}+) N=(\\p{XDigit}+)"); + Matcher matcher = pattern.matcher(message); + if (matcher.find()) { + int value = Integer.parseInt(matcher.group(3), decimalFuel ? 10 : 16); + position.set(Position.KEY_FUEL_LEVEL, value * 0.1); + } else { + position.set("message", message); + } + } + + if (custom) { + String form = this.form; + if (form == null) { + form = readString(buf).trim().substring("%CI".length()); + } + readBinaryCustomData(position, buf, form); + } + + positions.add(position); + + } + + return positions; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(buf.retain(), remoteAddress)); // keep-alive message + } + return null; + } else if (buf.getByte(buf.readerIndex()) == '$') { + return decodeInfo(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim()); + } else if (buf.getByte(buf.readerIndex() + 2) == ',') { + return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim()); + } else { + return decodeBinary(channel, remoteAddress, buf); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolEncoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolEncoder.java new file mode 100644 index 000000000..1e085cb26 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AtrackProtocolEncoder.java @@ -0,0 +1,38 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class AtrackProtocolEncoder extends BaseProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return Unpooled.copiedBuffer( + command.getString(Command.KEY_DATA) + "\r\n", StandardCharsets.US_ASCII); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/AuroProtocol.java b/src/main/java/org/traccar/protocol/AuroProtocol.java new file mode 100644 index 000000000..b8ebdaa75 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AuroProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AuroProtocol extends BaseProtocol { + + public AuroProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new AuroProtocolDecoder(AuroProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AuroProtocolDecoder.java b/src/main/java/org/traccar/protocol/AuroProtocolDecoder.java new file mode 100644 index 000000000..d7916147b --- /dev/null +++ b/src/main/java/org/traccar/protocol/AuroProtocolDecoder.java @@ -0,0 +1,91 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class AuroProtocolDecoder extends BaseProtocolDecoder { + + public AuroProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("M(dddd)") // index + .number("Td+") // phone + .number("I(d+)") // imei + .number("Ed+W") + .text("*****") + .number("d{8}d{4}") // local time + .expression(".{8}#.{8}") + .number("d{10}") // status + .number("([-+])(ddd)(dd)(dddd)") // longitude + .number("([-+])(ddd)(dd)(dddd)") // latitude + .number("(dd)(dd)(dddd)") // date (ddmmyyyy) + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("(ddd)") // course + .number("d{6}") + .number("(ddd)") // speed + .number("d") + .number("(dd)") // battery + .expression("([01])") // charging + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_INDEX, parser.nextInt(0)); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setCourse(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + + position.set(Position.KEY_BATTERY, parser.nextInt(0)); + position.set(Position.KEY_CHARGE, parser.nextInt(0) == 1); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/AustinNbProtocol.java b/src/main/java/org/traccar/protocol/AustinNbProtocol.java new file mode 100644 index 000000000..32bfc0aae --- /dev/null +++ b/src/main/java/org/traccar/protocol/AustinNbProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AustinNbProtocol extends BaseProtocol { + + public AustinNbProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new AustinNbProtocolDecoder(AustinNbProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java b/src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java new file mode 100644 index 000000000..dc6f3d280 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java @@ -0,0 +1,81 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.TimeZone; +import java.util.regex.Pattern; + +public class AustinNbProtocolDecoder extends BaseProtocolDecoder { + + public AustinNbProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+);") // imei + .number("(dddd)-(dd)-(dd) ") // date + .number("(dd):(dd):(dd);") // time + .number("(-?d+,d+);") // latitude + .number("(-?d+,d+);") // longitude + .number("(d+);") // azimuth + .number("(d+);") // angle + .number("(d+);") // range + .number("(d+);") // out of range + .expression("(.*)") // operator + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS, TimeZone.getDefault().getID())); + + position.setValid(true); + position.setLatitude(Double.parseDouble(parser.next().replace(',', '.'))); + position.setLongitude(Double.parseDouble(parser.next().replace(',', '.'))); + position.setCourse(parser.nextInt()); + position.set("angle", parser.nextInt()); + position.set("range", parser.nextInt()); + position.set("outOfRange", parser.nextInt()); + position.set("carrier", parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/AutoFonFrameDecoder.java b/src/main/java/org/traccar/protocol/AutoFonFrameDecoder.java new file mode 100644 index 000000000..69f28133f --- /dev/null +++ b/src/main/java/org/traccar/protocol/AutoFonFrameDecoder.java @@ -0,0 +1,65 @@ +/* + * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2015 Vitaly Litvak (vitavaque@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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class AutoFonFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + // Check minimum length + if (buf.readableBytes() < 12) { + return null; + } + + int length; + switch (buf.getUnsignedByte(buf.readerIndex())) { + case AutoFonProtocolDecoder.MSG_LOGIN: + length = 12; + break; + case AutoFonProtocolDecoder.MSG_LOCATION: + length = 78; + break; + case AutoFonProtocolDecoder.MSG_HISTORY: + length = 257; + break; + case AutoFonProtocolDecoder.MSG_45_LOGIN: + length = 19; + break; + case AutoFonProtocolDecoder.MSG_45_LOCATION: + length = 34; + break; + default: + length = 0; + break; + } + + // Check length and return buffer + if (length != 0 && buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/AutoFonProtocol.java b/src/main/java/org/traccar/protocol/AutoFonProtocol.java new file mode 100644 index 000000000..08b5edc7d --- /dev/null +++ b/src/main/java/org/traccar/protocol/AutoFonProtocol.java @@ -0,0 +1,34 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AutoFonProtocol extends BaseProtocol { + + public AutoFonProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new AutoFonFrameDecoder()); + pipeline.addLast(new AutoFonProtocolDecoder(AutoFonProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java b/src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java new file mode 100644 index 000000000..aa05ca2d7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java @@ -0,0 +1,215 @@ +/* + * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2015 Vitaly Litvak (vitavaque@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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; + +public class AutoFonProtocolDecoder extends BaseProtocolDecoder { + + public AutoFonProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 0x10; + public static final int MSG_LOCATION = 0x11; + public static final int MSG_HISTORY = 0x12; + + public static final int MSG_45_LOGIN = 0x41; + public static final int MSG_45_LOCATION = 0x02; + + private static double convertCoordinate(int raw) { + int degrees = raw / 1000000; + double minutes = (raw % 1000000) / 10000.0; + return degrees + minutes / 60; + } + + private static double convertCoordinate(short degrees, int minutes) { + double value = degrees + BitUtil.from(minutes, 4) / 600000.0; + if (BitUtil.check(minutes, 0)) { + return value; + } else { + return -value; + } + } + + private Position decodePosition(DeviceSession deviceSession, ByteBuf buf, boolean history) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (!history) { + buf.readUnsignedByte(); // interval + buf.skipBytes(8); // settings + } + position.set(Position.KEY_STATUS, buf.readUnsignedByte()); + if (!history) { + buf.readUnsignedShort(); + } + position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); + buf.skipBytes(6); // time + + if (!history) { + for (int i = 0; i < 2; i++) { + buf.skipBytes(5); // time + buf.readUnsignedShort(); // interval + buf.skipBytes(5); // mode + } + } + + position.set(Position.PREFIX_TEMP + 1, buf.readByte()); + + int rssi = buf.readUnsignedByte(); + CellTower cellTower = CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedShort(), + buf.readUnsignedShort(), buf.readUnsignedShort(), rssi); + position.setNetwork(new Network(cellTower)); + + int valid = buf.readUnsignedByte(); + position.setValid((valid & 0xc0) != 0); + position.set(Position.KEY_SATELLITES, valid & 0x3f); + + DateBuilder dateBuilder = new DateBuilder() + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + position.setLatitude(convertCoordinate(buf.readInt())); + position.setLongitude(convertCoordinate(buf.readInt())); + position.setAltitude(buf.readShort()); + position.setSpeed(buf.readUnsignedByte()); + position.setCourse(buf.readUnsignedByte() * 2.0); + + position.set(Position.KEY_HDOP, buf.readUnsignedShort()); + + buf.readUnsignedShort(); // reserved + buf.readUnsignedByte(); // checksum + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int type = buf.readUnsignedByte(); + + if (type == MSG_LOGIN || type == MSG_45_LOGIN) { + + if (type == MSG_LOGIN) { + buf.readUnsignedByte(); // hardware version + buf.readUnsignedByte(); // software version + } + + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + + if (deviceSession != null && channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeBytes("resp_crc=".getBytes(StandardCharsets.US_ASCII)); + response.writeByte(buf.getByte(buf.writerIndex() - 1)); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + return null; + + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + if (type == MSG_LOCATION) { + + return decodePosition(deviceSession, buf, false); + + } else if (type == MSG_HISTORY) { + + int count = buf.readUnsignedByte() & 0x0f; + buf.readUnsignedShort(); // total count + List positions = new LinkedList<>(); + + for (int i = 0; i < count; i++) { + positions.add(decodePosition(deviceSession, buf, true)); + } + + return positions; + + } else if (type == MSG_45_LOCATION) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + short status = buf.readUnsignedByte(); + if (BitUtil.check(status, 7)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + position.set(Position.KEY_BATTERY, BitUtil.to(status, 7)); + + buf.skipBytes(2); // remaining time + + position.set(Position.PREFIX_TEMP + 1, buf.readByte()); + + buf.skipBytes(2); // timer (interval and units) + buf.readByte(); // mode + buf.readByte(); // gprs sending interval + + buf.skipBytes(6); // mcc, mnc, lac, cid + + int valid = buf.readUnsignedByte(); + position.setValid(BitUtil.from(valid, 6) != 0); + position.set(Position.KEY_SATELLITES, BitUtil.from(valid, 6)); + + int time = buf.readUnsignedMedium(); + int date = buf.readUnsignedMedium(); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(time / 10000, time / 100 % 100, time % 100) + .setDateReverse(date / 10000, date / 100 % 100, date % 100); + position.setTime(dateBuilder.getDate()); + + position.setLatitude(convertCoordinate(buf.readUnsignedByte(), buf.readUnsignedMedium())); + position.setLongitude(convertCoordinate(buf.readUnsignedByte(), buf.readUnsignedMedium())); + position.setSpeed(buf.readUnsignedByte()); + position.setCourse(buf.readUnsignedShort()); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/AutoGradeProtocol.java b/src/main/java/org/traccar/protocol/AutoGradeProtocol.java new file mode 100644 index 000000000..c6dbb681e --- /dev/null +++ b/src/main/java/org/traccar/protocol/AutoGradeProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AutoGradeProtocol extends BaseProtocol { + + public AutoGradeProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new AutoGradeProtocolDecoder(AutoGradeProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java b/src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java new file mode 100644 index 000000000..5052450b5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java @@ -0,0 +1,107 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class AutoGradeProtocolDecoder extends BaseProtocolDecoder { + + public AutoGradeProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("(") + .number("d{12}") // index + .number("(d{15})") // imei + .number("(dd)(dd)(dd)") // date (ddmmyy) + .expression("([AV])") // validity + .number("(d+)(dd.d+)([NS])") // latitude + .number("(d+)(dd.d+)([EW])") // longitude + .number("([d.]{5})") // speed + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("([d.]{6})") // course + .expression("(.)") // status + .number("A(xxxx)") + .number("B(xxxx)") + .number("C(xxxx)") + .number("D(xxxx)") + .number("E(xxxx)") + .number("K(xxxx)") + .number("L(xxxx)") + .number("M(xxxx)") + .number("N(xxxx)") + .number("O(xxxx)") + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + + dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.setCourse(parser.nextDouble(0)); + + int status = parser.next().charAt(0); + position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); + + for (int i = 1; i <= 5; i++) { + position.set(Position.PREFIX_ADC + i, parser.next()); + } + + for (int i = 1; i <= 5; i++) { + position.set("can" + i, parser.next()); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/AutoTrackProtocol.java b/src/main/java/org/traccar/protocol/AutoTrackProtocol.java new file mode 100644 index 000000000..6aa7558bf --- /dev/null +++ b/src/main/java/org/traccar/protocol/AutoTrackProtocol.java @@ -0,0 +1,36 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; +public class AutoTrackProtocol extends BaseProtocol { + + public AutoTrackProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 5, 2, 2, 0, true)); + pipeline.addLast(new AutoTrackProtocolDecoder(AutoTrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java new file mode 100644 index 000000000..3c1fd256b --- /dev/null +++ b/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java @@ -0,0 +1,138 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; + +public class AutoTrackProtocolDecoder extends BaseProtocolDecoder { + + public AutoTrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN_REQUEST = 51; + public static final int MSG_LOGIN_CONFIRM = 101; + public static final int MSG_TELEMETRY_1 = 52; + public static final int MSG_TELEMETRY_2 = 66; + public static final int MSG_TELEMETRY_3 = 67; + public static final int MSG_KEEP_ALIVE = 114; + public static final int MSG_TELEMETRY_CONFIRM = 123; + + private Position decodeTelemetry( + Channel channel, SocketAddress remoteAddress, DeviceSession deviceSession, ByteBuf buf) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(1009843200000L + buf.readUnsignedIntLE() * 1000)); // seconds since 2002 + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set(Position.KEY_FUEL_USED, buf.readUnsignedIntLE()); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + buf.readUnsignedShortLE(); // max speed + + position.set(Position.KEY_INPUT, buf.readUnsignedShortLE()); + buf.readUnsignedIntLE(); // di 3 count + buf.readUnsignedIntLE(); // di 4 count + + for (int i = 0; i < 5; i++) { + position.set(Position.PREFIX_ADC + (i + 1), buf.readUnsignedShortLE()); + } + + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_STATUS, buf.readUnsignedShortLE()); + position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, buf.readLongLE()); + + int index = buf.readUnsignedShortLE(); + + buf.readUnsignedShortLE(); // checksum + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeInt(0xF1F1F1F1); // sync + response.writeByte(MSG_TELEMETRY_CONFIRM); + response.writeShortLE(2); // length + response.writeShortLE(index); + response.writeShort(Checksum.crc16(Checksum.CRC16_XMODEM, response.nioBuffer())); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(4); // sync + int type = buf.readUnsignedByte(); + buf.readUnsignedShortLE(); // length + + switch (type) { + case MSG_LOGIN_REQUEST: + String imei = ByteBufUtil.hexDump(buf.readBytes(8)); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + int fuelConst = buf.readUnsignedShortLE(); + int tripConst = buf.readUnsignedShortLE(); + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeInt(0xF1F1F1F1); // sync + response.writeByte(MSG_LOGIN_CONFIRM); + response.writeShortLE(12); // length + response.writeBytes(ByteBufUtil.decodeHexDump(imei)); + response.writeShortLE(fuelConst); + response.writeShortLE(tripConst); + response.writeShort(Checksum.crc16(Checksum.CRC16_XMODEM, response.nioBuffer())); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + return null; + case MSG_TELEMETRY_1: + case MSG_TELEMETRY_2: + case MSG_TELEMETRY_3: + deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + return decodeTelemetry(channel, remoteAddress, deviceSession, buf); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/AvemaProtocol.java b/src/main/java/org/traccar/protocol/AvemaProtocol.java new file mode 100644 index 000000000..dbfab4dea --- /dev/null +++ b/src/main/java/org/traccar/protocol/AvemaProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class AvemaProtocol extends BaseProtocol { + + public AvemaProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new AvemaProtocolDecoder(AvemaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java b/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java new file mode 100644 index 000000000..16a31162a --- /dev/null +++ b/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java @@ -0,0 +1,107 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class AvemaProtocolDecoder extends BaseProtocolDecoder { + + public AvemaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+),") // device id + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(-?d+),") // altitude + .number("(d+),") // satellites + .number("(d+),") // event + .number("(d+.d+),") // odometer + .number("(d+),") // input + .number("(d+.d+)V,") // adc 1 + .number("(d+.d+)V,") // adc 2 + .number("(d+),") // output + .number("(d),") // roaming + .number("(d+),") // rssi + .number("d,") // communication system + .number("(ddd)") // mcc + .number("(dd),") // mnc + .number("(x+),") // lac + .number("(x+),") // cid + .number("([^,]+)?") // rfid + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(parser.nextDateTime()); + position.setLongitude(parser.nextDouble()); + position.setLatitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setCourse(parser.nextInt()); + position.setAltitude(parser.nextInt()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_EVENT, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + position.set(Position.KEY_INPUT, parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); + position.set(Position.KEY_OUTPUT, parser.nextInt()); + position.set(Position.KEY_ROAMING, parser.nextInt() == 1); + + int rssi = parser.nextInt(); + position.setNetwork(new Network(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi))); + + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Avl301Protocol.java b/src/main/java/org/traccar/protocol/Avl301Protocol.java new file mode 100644 index 000000000..71fc7cb26 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Avl301Protocol.java @@ -0,0 +1,35 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Avl301Protocol extends BaseProtocol { + + public Avl301Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, -3, 0)); + pipeline.addLast(new Avl301ProtocolDecoder(Avl301Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java new file mode 100644 index 000000000..f6b7db2d6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java @@ -0,0 +1,145 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class Avl301ProtocolDecoder extends BaseProtocolDecoder { + + public Avl301ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private String readImei(ByteBuf buf) { + int b = buf.readUnsignedByte(); + StringBuilder imei = new StringBuilder(); + imei.append(b & 0x0F); + for (int i = 0; i < 7; i++) { + b = buf.readUnsignedByte(); + imei.append((b & 0xF0) >> 4); + imei.append(b & 0x0F); + } + return imei.toString(); + } + + public static final int MSG_LOGIN = 'L'; + public static final int MSG_STATUS = 'H'; + public static final int MSG_GPS_LBS_STATUS = '$'; + + private void sendResponse(Channel channel, int type) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(5); + response.writeByte('$'); + response.writeByte(type); + response.writeByte('#'); + response.writeByte('\r'); response.writeByte('\n'); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(1); // header + int type = buf.readUnsignedByte(); + buf.readUnsignedByte(); // length + + if (type == MSG_LOGIN) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, readImei(buf)); + if (deviceSession == null) { + sendResponse(channel, type); + } + + } else if (type == MSG_STATUS) { + + sendResponse(channel, type); + + } else if (type == MSG_GPS_LBS_STATUS) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + int gpsLength = buf.readUnsignedByte(); // gps len and sat + position.set(Position.KEY_SATELLITES, gpsLength & 0xf); + + position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); // satellites + + double latitude = buf.readUnsignedInt() / 600000.0; + double longitude = buf.readUnsignedInt() / 600000.0; + position.setSpeed(buf.readUnsignedByte()); + + int union = buf.readUnsignedShort(); // course and flags + position.setCourse(union & 0x03FF); + position.setValid((union & 0x1000) != 0); + if ((union & 0x0400) != 0) { + latitude = -latitude; + } + if ((union & 0x0800) != 0) { + longitude = -longitude; + } + + position.setLatitude(latitude); + position.setLongitude(longitude); + + if ((union & 0x4000) != 0) { + position.set("acc", (union & 0x8000) != 0); + } + + position.setNetwork(new Network( + CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedMedium()))); + + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + int flags = buf.readUnsignedByte(); + position.set("acc", (flags & 0x2) != 0); + + // parse other flags + + position.set(Position.KEY_POWER, buf.readUnsignedByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/BceFrameDecoder.java b/src/main/java/org/traccar/protocol/BceFrameDecoder.java new file mode 100644 index 000000000..381a97696 --- /dev/null +++ b/src/main/java/org/traccar/protocol/BceFrameDecoder.java @@ -0,0 +1,59 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class BceFrameDecoder extends BaseFrameDecoder { + + private static final int HANDSHAKE_LENGTH = 7; // "#BCE#\r\n" + + private boolean header = true; + + private static byte checksum(ByteBuf buf, int end) { + byte result = 0; + for (int i = 0; i < end; i++) { + result += buf.getByte(buf.readerIndex() + i); + } + return result; + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (header && buf.readableBytes() >= HANDSHAKE_LENGTH) { + buf.skipBytes(HANDSHAKE_LENGTH); + header = false; + } + + int end = 8; // IMEI + + while (buf.readableBytes() >= end + 2 + 1 + 1 + 1) { + end += buf.getUnsignedShortLE(buf.readerIndex() + end) + 2; + + if (buf.readableBytes() > end && checksum(buf, end) == buf.getByte(buf.readerIndex() + end)) { + return buf.readRetainedSlice(end + 1); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/BceProtocol.java b/src/main/java/org/traccar/protocol/BceProtocol.java new file mode 100644 index 000000000..6453a05a9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/BceProtocol.java @@ -0,0 +1,38 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class BceProtocol extends BaseProtocol { + + public BceProtocol() { + setSupportedDataCommands( + Command.TYPE_OUTPUT_CONTROL); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new BceFrameDecoder()); + pipeline.addLast(new BceProtocolEncoder()); + pipeline.addLast(new BceProtocolDecoder(BceProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java new file mode 100644 index 000000000..ed810bebb --- /dev/null +++ b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java @@ -0,0 +1,175 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class BceProtocolDecoder extends BaseProtocolDecoder { + + public BceProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final int DATA_TYPE = 7; + + public static final int MSG_ASYNC_STACK = 0xA5; + public static final int MSG_STACK_COFIRM = 0x19; + public static final int MSG_TIME_TRIGGERED = 0xA0; + public static final int MSG_OUTPUT_CONTROL = 0x41; + public static final int MSG_OUTPUT_CONTROL_ACK = 0xC1; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + String imei = String.format("%015d", buf.readLongLE()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + while (buf.readableBytes() > 1) { + + int dataEnd = buf.readUnsignedShortLE() + buf.readerIndex(); + int type = buf.readUnsignedByte(); + + if (type != MSG_ASYNC_STACK && type != MSG_TIME_TRIGGERED) { + return null; + } + + int confirmKey = buf.readUnsignedByte() & 0x7F; + + while (buf.readerIndex() < dataEnd) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + int structEnd = buf.readUnsignedByte() + buf.readerIndex(); + + long time = buf.readUnsignedIntLE(); + if ((time & 0x0f) == DATA_TYPE) { + + time = time >> 4 << 1; + time += 0x47798280; // 01/01/2008 + position.setTime(new Date(time * 1000)); + + // Read masks + int mask; + List masks = new LinkedList<>(); + do { + mask = buf.readUnsignedShortLE(); + masks.add(mask); + } while (BitUtil.check(mask, 15)); + + mask = masks.get(0); + + if (BitUtil.check(mask, 0)) { + position.setValid(true); + position.setLongitude(buf.readFloatLE()); + position.setLatitude(buf.readFloatLE()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + int status = buf.readUnsignedByte(); + position.set(Position.KEY_SATELLITES, BitUtil.to(status, 4)); + position.set(Position.KEY_HDOP, BitUtil.from(status, 4)); + + position.setCourse(buf.readUnsignedByte() * 2); + position.setAltitude(buf.readUnsignedShortLE()); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + } + + if (BitUtil.check(mask, 1)) { + position.set(Position.KEY_INPUT, buf.readUnsignedShortLE()); + } + + for (int i = 1; i <= 8; i++) { + if (BitUtil.check(mask, i + 1)) { + position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE()); + } + } + + if (BitUtil.check(mask, 10)) { + buf.skipBytes(4); + } + if (BitUtil.check(mask, 11)) { + buf.skipBytes(4); + } + if (BitUtil.check(mask, 12)) { + buf.skipBytes(2); + } + if (BitUtil.check(mask, 13)) { + buf.skipBytes(2); + } + + if (BitUtil.check(mask, 14)) { + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShortLE(), buf.readUnsignedByte(), + buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), + buf.readUnsignedByte()))); + buf.readUnsignedByte(); + } + + if (BitUtil.check(mask, 0)) { + positions.add(position); + } + } + + buf.readerIndex(structEnd); + } + + // Send response + if (type == MSG_ASYNC_STACK && channel != null) { + ByteBuf response = Unpooled.buffer(8 + 2 + 2 + 1); + response.writeLongLE(Long.parseLong(imei)); + response.writeShortLE(2); + response.writeByte(MSG_STACK_COFIRM); + response.writeByte(confirmKey); + + int checksum = 0; + for (int i = 0; i < response.writerIndex(); i++) { + checksum += response.getUnsignedByte(i); + } + response.writeByte(checksum); + + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/BceProtocolEncoder.java b/src/main/java/org/traccar/protocol/BceProtocolEncoder.java new file mode 100644 index 000000000..1bbf3db12 --- /dev/null +++ b/src/main/java/org/traccar/protocol/BceProtocolEncoder.java @@ -0,0 +1,47 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +public class BceProtocolEncoder extends BaseProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + if (command.getType().equals(Command.TYPE_OUTPUT_CONTROL)) { + ByteBuf buf = Unpooled.buffer(); + + buf.writeLongLE(Long.parseLong(getUniqueId(command.getDeviceId()))); + buf.writeShortLE(1 + 1 + 3 + 1); // length + buf.writeByte(BceProtocolDecoder.MSG_OUTPUT_CONTROL); + buf.writeByte(command.getInteger(Command.KEY_INDEX) == 1 ? 0x0A : 0x0B); + buf.writeByte(0xFF); // index + buf.writeByte(0x00); // form id + buf.writeShortLE(Integer.parseInt(command.getString(Command.KEY_DATA)) > 0 ? 0x0055 : 0x0000); + buf.writeByte(Checksum.sum(buf.nioBuffer())); + + return buf; + } else { + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/BlackKiteProtocol.java b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java new file mode 100644 index 000000000..617a24d7a --- /dev/null +++ b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 2015 Vijay Kumar (vijaykumar@zilogic.com) + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class BlackKiteProtocol extends BaseProtocol { + + public BlackKiteProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new GalileoFrameDecoder()); + pipeline.addLast(new BlackKiteProtocolDecoder(BlackKiteProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java b/src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java new file mode 100644 index 000000000..dca4b908a --- /dev/null +++ b/src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java @@ -0,0 +1,195 @@ +/* + * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2015 Vijay Kumar (vijaykumar@zilogic.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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class BlackKiteProtocolDecoder extends BaseProtocolDecoder { + + public BlackKiteProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final int TAG_IMEI = 0x03; + private static final int TAG_DATE = 0x20; + private static final int TAG_COORDINATES = 0x30; + private static final int TAG_SPEED_COURSE = 0x33; + private static final int TAG_ALTITUDE = 0x34; + private static final int TAG_STATUS = 0x40; + private static final int TAG_DIGITAL_OUTPUTS = 0x45; + private static final int TAG_DIGITAL_INPUTS = 0x46; + private static final int TAG_INPUT_VOLTAGE1 = 0x50; + private static final int TAG_INPUT_VOLTAGE2 = 0x51; + private static final int TAG_INPUT_VOLTAGE3 = 0x52; + private static final int TAG_INPUT_VOLTAGE4 = 0x53; + private static final int TAG_XT1 = 0x60; + private static final int TAG_XT2 = 0x61; + private static final int TAG_XT3 = 0x62; + + private void sendReply(Channel channel, int checksum) { + if (channel != null) { + ByteBuf reply = Unpooled.buffer(3); + reply.writeByte(0x02); + reply.writeShortLE((short) checksum); + channel.writeAndFlush(new NetworkMessage(reply, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // header + int length = (buf.readUnsignedShortLE() & 0x7fff) + 3; + + List positions = new LinkedList<>(); + Set tags = new HashSet<>(); + boolean hasLocation = false; + Position position = new Position(getProtocolName()); + + while (buf.readerIndex() < length) { + + // Check if new message started + int tag = buf.readUnsignedByte(); + if (tags.contains(tag)) { + if (hasLocation && position.getFixTime() != null) { + positions.add(position); + } + tags.clear(); + hasLocation = false; + position = new Position(getProtocolName()); + } + tags.add(tag); + + switch (tag) { + + case TAG_IMEI: + getDeviceSession(channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII)); + break; + + case TAG_DATE: + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + break; + + case TAG_COORDINATES: + hasLocation = true; + position.setValid((buf.readUnsignedByte() & 0xf0) == 0x00); + position.setLatitude(buf.readIntLE() / 1000000.0); + position.setLongitude(buf.readIntLE() / 1000000.0); + break; + + case TAG_SPEED_COURSE: + position.setSpeed(buf.readUnsignedShortLE() * 0.0539957); + position.setCourse(buf.readUnsignedShortLE() * 0.1); + break; + + case TAG_ALTITUDE: + position.setAltitude(buf.readShortLE()); + break; + + case TAG_STATUS: + int status = buf.readUnsignedShortLE(); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 9)); + if (BitUtil.check(status, 15)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + position.set(Position.KEY_CHARGE, BitUtil.check(status, 2)); + break; + + case TAG_DIGITAL_INPUTS: + int input = buf.readUnsignedShortLE(); + for (int i = 0; i < 16; i++) { + position.set(Position.PREFIX_IO + (i + 1), BitUtil.check(input, i)); + } + break; + + case TAG_DIGITAL_OUTPUTS: + int output = buf.readUnsignedShortLE(); + for (int i = 0; i < 16; i++) { + position.set(Position.PREFIX_IO + (i + 17), BitUtil.check(output, i)); + } + break; + + case TAG_INPUT_VOLTAGE1: + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE() / 1000.0); + break; + + case TAG_INPUT_VOLTAGE2: + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE() / 1000.0); + break; + + case TAG_INPUT_VOLTAGE3: + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShortLE() / 1000.0); + break; + + case TAG_INPUT_VOLTAGE4: + position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShortLE() / 1000.0); + break; + + case TAG_XT1: + case TAG_XT2: + case TAG_XT3: + buf.skipBytes(16); + break; + + default: + break; + + } + } + + if (hasLocation && position.getFixTime() != null) { + positions.add(position); + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + sendReply(channel, buf.readUnsignedShortLE()); + + for (Position p : positions) { + p.setDeviceId(deviceSession.getDeviceId()); + } + + if (positions.isEmpty()) { + return null; + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/BoxProtocol.java b/src/main/java/org/traccar/protocol/BoxProtocol.java new file mode 100644 index 000000000..dfea15938 --- /dev/null +++ b/src/main/java/org/traccar/protocol/BoxProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class BoxProtocol extends BaseProtocol { + + public BoxProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new BoxProtocolDecoder(BoxProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/BoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/BoxProtocolDecoder.java new file mode 100644 index 000000000..3635c29e5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/BoxProtocolDecoder.java @@ -0,0 +1,108 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class BoxProtocolDecoder extends BaseProtocolDecoder { + + public BoxProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("L,") + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .text("G,") + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(d+.?d*),") // distance + .number("(d+),") // event + .number("(d+)") // status + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("H,")) { + + int index = sentence.indexOf(',', 2) + 1; + String id = sentence.substring(index, sentence.indexOf(',', index)); + getDeviceSession(channel, remoteAddress, id); + + } else if (sentence.startsWith("E,")) { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("A," + sentence.substring(2) + "\r", remoteAddress)); + } + + } else if (sentence.startsWith("L,")) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + + position.set(Position.KEY_ODOMETER_TRIP, parser.nextDouble() * 1000); + position.set(Position.KEY_EVENT, parser.next()); + + int status = parser.nextInt(); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); + position.set(Position.KEY_MOTION, BitUtil.check(status, 1)); + position.setValid(!BitUtil.check(status, 2)); + position.set(Position.KEY_STATUS, status); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/C2stekProtocol.java b/src/main/java/org/traccar/protocol/C2stekProtocol.java new file mode 100644 index 000000000..804621fd3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/C2stekProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class C2stekProtocol extends BaseProtocol { + + public C2stekProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, false, "$AP")); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new C2stekProtocolDecoder(C2stekProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java b/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java new file mode 100644 index 000000000..6a31cb2f4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java @@ -0,0 +1,121 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class C2stekProtocolDecoder extends BaseProtocolDecoder { + + public C2stekProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("PA$") + .number("(d+)") // imei + .text("$") + .expression(".#") // data type + .number("(dd)(dd)(dd)#") // date (yymmdd) + .number("(dd)(dd)(dd)#") // time (hhmmss) + .number("([01])#") // valid + .number("([+-]?d+.d+)#") // latitude + .number("([+-]?d+.d+)#") // longitude + .number("(d+.d+)#") // speed + .number("(d+.d+)#") // course + .number("(-?d+.d+)#") // altitude + .number("(d+)#") // battery + .number("d+#") // geo area alarm + .number("(x+)#") // alarm + .number("([01])") // armed + .number("([01])") // door + .number("([01])#") // ignition + .any() + .text("$AP") + .compile(); + + private String decodeAlarm(int alarm) { + switch (alarm) { + case 0x2: + return Position.ALARM_SHOCK; + case 0x3: + return Position.ALARM_POWER_CUT; + case 0x4: + return Position.ALARM_OVERSPEED; + case 0x5: + return Position.ALARM_SOS; + case 0x6: + return Position.ALARM_DOOR; + case 0xA: + return Position.ALARM_LOW_BATTERY; + case 0xB: + return Position.ALARM_FAULT; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + if (sentence.contains("$20$") && channel != null) { + channel.writeAndFlush(new NetworkMessage(sentence, remoteAddress)); + } + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + position.setValid(parser.nextInt() > 0); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + position.setAltitude(parser.nextDouble()); + + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); + position.set(Position.KEY_ALARM, decodeAlarm(parser.nextHexInt())); + + position.set(Position.KEY_ARMED, parser.nextInt() > 0); + position.set(Position.KEY_DOOR, parser.nextInt() > 0); + position.set(Position.KEY_IGNITION, parser.nextInt() > 0); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/CalAmpProtocol.java b/src/main/java/org/traccar/protocol/CalAmpProtocol.java new file mode 100644 index 000000000..232e72a8c --- /dev/null +++ b/src/main/java/org/traccar/protocol/CalAmpProtocol.java @@ -0,0 +1,33 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class CalAmpProtocol extends BaseProtocol { + + public CalAmpProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CalAmpProtocolDecoder(CalAmpProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java b/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java new file mode 100644 index 000000000..31416d7f1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java @@ -0,0 +1,202 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; + +public class CalAmpProtocolDecoder extends BaseProtocolDecoder { + + public CalAmpProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_NULL = 0; + public static final int MSG_ACK = 1; + public static final int MSG_EVENT_REPORT = 2; + public static final int MSG_ID_REPORT = 3; + public static final int MSG_USER_DATA = 4; + public static final int MSG_APP_DATA = 5; + public static final int MSG_CONFIG = 6; + public static final int MSG_UNIT_REQUEST = 7; + public static final int MSG_LOCATE_REPORT = 8; + public static final int MSG_USER_DATA_ACC = 9; + public static final int MSG_MINI_EVENT_REPORT = 10; + public static final int MSG_MINI_USER_DATA = 11; + + public static final int SERVICE_UNACKNOWLEDGED = 0; + public static final int SERVICE_ACKNOWLEDGED = 1; + public static final int SERVICE_RESPONSE = 2; + + private void sendResponse(Channel channel, SocketAddress remoteAddress, int type, int index, int result) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(10); + response.writeByte(SERVICE_RESPONSE); + response.writeByte(MSG_ACK); + response.writeShort(index); + response.writeByte(type); + response.writeByte(result); + response.writeByte(0); + response.writeMedium(0); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private Position decodePosition(DeviceSession deviceSession, int type, ByteBuf buf) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + if (type != MSG_MINI_EVENT_REPORT) { + buf.readUnsignedInt(); // fix time + } + position.setLatitude(buf.readInt() * 0.0000001); + position.setLongitude(buf.readInt() * 0.0000001); + if (type != MSG_MINI_EVENT_REPORT) { + position.setAltitude(buf.readInt() * 0.01); + position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedInt())); + } + position.setCourse(buf.readShort()); + if (type == MSG_MINI_EVENT_REPORT) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + } + + if (type == MSG_MINI_EVENT_REPORT) { + position.set(Position.KEY_SATELLITES, buf.getUnsignedByte(buf.readerIndex()) & 0xf); + position.setValid((buf.readUnsignedByte() & 0x20) == 0); + } else { + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.setValid((buf.readUnsignedByte() & 0x08) == 0); + } + + if (type != MSG_MINI_EVENT_REPORT) { + position.set("carrier", buf.readUnsignedShort()); + position.set(Position.KEY_RSSI, buf.readShort()); + } + + position.set("modem", buf.readUnsignedByte()); + + if (type != MSG_MINI_EVENT_REPORT) { + position.set(Position.KEY_HDOP, buf.readUnsignedByte()); + } + + int input = buf.readUnsignedByte(); + position.set(Position.KEY_INPUT, input); + position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); + + if (type != MSG_MINI_EVENT_REPORT) { + position.set(Position.KEY_STATUS, buf.readUnsignedByte()); + } + + if (type == MSG_EVENT_REPORT || type == MSG_MINI_EVENT_REPORT) { + if (type != MSG_MINI_EVENT_REPORT) { + buf.readUnsignedByte(); // event index + } + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + } + + int accType = BitUtil.from(buf.getUnsignedByte(buf.readerIndex()), 6); + int accCount = BitUtil.to(buf.readUnsignedByte(), 6); + + if (type != MSG_MINI_EVENT_REPORT) { + position.set("append", buf.readUnsignedByte()); + } + + if (accType == 1) { + buf.readUnsignedInt(); // threshold + buf.readUnsignedInt(); // mask + } + + for (int i = 0; i < accCount; i++) { + if (buf.readableBytes() >= 4) { + position.set("acc" + i, buf.readUnsignedInt()); + } + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (BitUtil.check(buf.getByte(buf.readerIndex()), 7)) { + + int content = buf.readUnsignedByte(); + + if (BitUtil.check(content, 0)) { + String id = ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())); + getDeviceSession(channel, remoteAddress, id); + } + + if (BitUtil.check(content, 1)) { + buf.skipBytes(buf.readUnsignedByte()); // identifier type + } + + if (BitUtil.check(content, 2)) { + buf.skipBytes(buf.readUnsignedByte()); // authentication + } + + if (BitUtil.check(content, 3)) { + buf.skipBytes(buf.readUnsignedByte()); // routing + } + + if (BitUtil.check(content, 4)) { + buf.skipBytes(buf.readUnsignedByte()); // forwarding + } + + if (BitUtil.check(content, 5)) { + buf.skipBytes(buf.readUnsignedByte()); // response redirection + } + + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + int service = buf.readUnsignedByte(); + int type = buf.readUnsignedByte(); + int index = buf.readUnsignedShort(); + + if (service == SERVICE_ACKNOWLEDGED) { + sendResponse(channel, remoteAddress, type, index, 0); + } + + if (type == MSG_EVENT_REPORT || type == MSG_LOCATE_REPORT || type == MSG_MINI_EVENT_REPORT) { + return decodePosition(deviceSession, type, buf); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/CarTrackProtocol.java b/src/main/java/org/traccar/protocol/CarTrackProtocol.java new file mode 100644 index 000000000..e340fba25 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CarTrackProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class CarTrackProtocol extends BaseProtocol { + + public CarTrackProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new CarTrackProtocolDecoder(CarTrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java new file mode 100644 index 000000000..ce3345826 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java @@ -0,0 +1,108 @@ +/* + * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2014 Rohit + * + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class CarTrackProtocolDecoder extends BaseProtocolDecoder { + + public CarTrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$$") // header + .number("(d+)") // device id + .text("?").expression("*") + .text("&A") + .number("(dddd)") // command + .text("&B") + .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) + .expression("([AV]),") // validity + .number("(dd)(dd.dddd),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.dddd),") // longitude + .expression("([EW]),") + .number("(d+.d*)?,") // speed + .number("(d+.d*)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .expression("&C([^&]*)") // io + .expression("&D([^&]*)") // odometer + .expression("&E([^&]*)") // alarm + .expression("&Y([^&]*)").optional() // adc + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_COMMAND, parser.next()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.set(Position.PREFIX_IO + 1, parser.next()); + + String odometer = parser.next(); + odometer = odometer.replace(":", "A"); + odometer = odometer.replace(";", "B"); + odometer = odometer.replace("<", "C"); + odometer = odometer.replace("=", "D"); + odometer = odometer.replace(">", "E"); + odometer = odometer.replace("?", "F"); + position.set(Position.KEY_ODOMETER, Integer.parseInt(odometer, 16)); + + parser.next(); // there is no meaningful alarms + position.set(Position.PREFIX_ADC + 1, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/CarcellProtocol.java b/src/main/java/org/traccar/protocol/CarcellProtocol.java new file mode 100644 index 000000000..0c305efcb --- /dev/null +++ b/src/main/java/org/traccar/protocol/CarcellProtocol.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class CarcellProtocol extends BaseProtocol { + + public CarcellProtocol() { + setSupportedDataCommands( + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new CarcellProtocolEncoder()); + pipeline.addLast(new CarcellProtocolDecoder(CarcellProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java b/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java new file mode 100644 index 000000000..344b2f1ea --- /dev/null +++ b/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java @@ -0,0 +1,164 @@ +/* + * Copyright 2016 - 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. + * 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.net.SocketAddress; +import java.util.regex.Pattern; + +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.Parser.CoordinateFormat; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +public class CarcellProtocolDecoder extends BaseProtocolDecoder { + + public CarcellProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("([$%])") // memory flag + .number("(d+),") // imei + .groupBegin() + .number("([NS])(dd)(dd).(dddd),") // latitude + .number("([EW])(ddd)(dd).(dddd),") // longitude + .or() + .text("CEL,") + .number("([NS])(d+.d+),") // latitude + .number("([EW])(d+.d+),") // longitude + .groupEnd() + .number("(d+),") // speed + .number("(d+),") // course + .groupBegin() + .number("([-+]ddd)([-+]ddd)([-+]ddd),") // x,y,z + .or() + .number("(d+),") // accel + .groupEnd() + .number("(d+),") // battery + .number("(d+),") // csq + .number("(d),") // jamming + .number("(d+),") // hdop + .expression("([CG]),?") // clock type + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d),") // block + .number("(d),") // ignition + .groupBegin() + .number("(d),") // cloned + .expression("([AF])") // panic + .number("(d),") // painel + .number("(d+),") // battery voltage + .or() + .number("(dd),") // time until delivery + .expression("([AF])") // panic + .number("(d),") // aux + .number("(d{2,4}),") // battery voltage + .number("(d{20}),") // ccid + .groupEnd() + .number("(xx)") // crc + .any() // full format + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.set(Position.KEY_ARCHIVE, parser.next().equals("%")); + position.setValid(true); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.hasNext(8)) { + position.setLatitude(parser.nextCoordinate(CoordinateFormat.HEM_DEG_MIN_MIN)); + position.setLongitude(parser.nextCoordinate(CoordinateFormat.HEM_DEG_MIN_MIN)); + } + + if (parser.hasNext(4)) { + position.setLatitude(parser.nextCoordinate(CoordinateFormat.HEM_DEG)); + position.setLongitude(parser.nextCoordinate(CoordinateFormat.HEM_DEG)); + } + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); + position.setCourse(parser.nextInt(0)); + + if (parser.hasNext(3)) { + position.set("x", parser.nextInt(0)); + position.set("y", parser.nextInt(0)); + position.set("z", parser.nextInt(0)); + } + + if (parser.hasNext(1)) { + position.set(Position.KEY_ACCELERATION, parser.nextInt(0)); + } + + Double internalBattery = (parser.nextDouble(0) + 100d) * 0.0294d; + position.set(Position.KEY_BATTERY, internalBattery); + position.set(Position.KEY_RSSI, parser.nextInt(0)); + position.set("jamming", parser.next().equals("1")); + position.set(Position.KEY_GPS, parser.nextInt(0)); + + position.set("clockType", parser.next()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.set("blocked", parser.next().equals("1")); + position.set(Position.KEY_IGNITION, parser.next().equals("1")); + + if (parser.hasNext(4)) { + position.set("cloned", parser.next().equals("1")); + + parser.next(); // panic button status + + String painelStatus = parser.next(); + if (painelStatus.equals("1")) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + position.set("painel", painelStatus.equals("2")); + + Double mainVoltage = parser.nextDouble(0) / 100d; + position.set(Position.KEY_POWER, mainVoltage); + } + + if (parser.hasNext(5)) { + position.set("timeUntilDelivery", parser.nextInt(0)); + parser.next(); // panic button status + position.set(Position.KEY_INPUT, parser.next()); + + Double mainVoltage = parser.nextDouble(0) / 100d; + position.set(Position.KEY_POWER, mainVoltage); + + position.set("iccid", parser.next()); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java b/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java new file mode 100644 index 000000000..e8f0081a0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class CarcellProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, "$SRVCMD,{%s},BA#\r\n", Command.KEY_UNIQUE_ID); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, "$SRVCMD,{%s},BD#\r\n", Command.KEY_UNIQUE_ID); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/CarscopProtocol.java b/src/main/java/org/traccar/protocol/CarscopProtocol.java new file mode 100644 index 000000000..2c754a97f --- /dev/null +++ b/src/main/java/org/traccar/protocol/CarscopProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class CarscopProtocol extends BaseProtocol { + + public CarscopProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '^')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new CarscopProtocolDecoder(CarscopProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java b/src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java new file mode 100644 index 000000000..161666adc --- /dev/null +++ b/src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java @@ -0,0 +1,101 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class CarscopProtocolDecoder extends BaseProtocolDecoder { + + public CarscopProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("*") + .any() + .number("(dd)(dd)(dd)") // time (hhmmss) + .expression("([AV])") // validity + .number("(dd)(dd.dddd)") // latitude + .expression("([NS])") + .number("(ddd)(dd.dddd)") // longitude + .expression("([EW])") + .number("(ddd.d)") // speed + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(ddd.dd)") // course + .groupBegin() + .number("(d{8})") // state + .number("L(d{6})") // odometer + .groupEnd("?") + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + DeviceSession deviceSession; + int index = sentence.indexOf("UB05"); + if (index != -1) { + String imei = sentence.substring(index + 4, index + 4 + 15); + deviceSession = getDeviceSession(channel, remoteAddress, imei); + } else { + deviceSession = getDeviceSession(channel, remoteAddress); + } + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + + dateBuilder.setDate(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.setCourse(parser.nextDouble(0)); + + if (parser.hasNext(2)) { + position.set(Position.KEY_STATUS, parser.next()); + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/CastelProtocol.java b/src/main/java/org/traccar/protocol/CastelProtocol.java new file mode 100644 index 000000000..9b854afc3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CastelProtocol.java @@ -0,0 +1,48 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +import java.nio.ByteOrder; +public class CastelProtocol extends BaseProtocol { + + public CastelProtocol() { + setSupportedDataCommands( + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, -4, 0, true)); + pipeline.addLast(new CastelProtocolEncoder()); + pipeline.addLast(new CastelProtocolDecoder(CastelProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CastelProtocolEncoder()); + pipeline.addLast(new CastelProtocolDecoder(CastelProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java new file mode 100644 index 000000000..0541adf6f --- /dev/null +++ b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java @@ -0,0 +1,573 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.ObdDecoder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +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; + +public class CastelProtocolDecoder extends BaseProtocolDecoder { + + private static final Map PID_LENGTH_MAP = new HashMap<>(); + + static { + int[] l1 = { + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0b, 0x0d, + 0x0e, 0x0f, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x2c, + 0x2d, 0x2e, 0x2f, 0x30, 0x33, 0x43, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x51, 0x52, + 0x5a + }; + int[] l2 = { + 0x02, 0x03, 0x0a, 0x0c, 0x10, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1f, 0x21, 0x22, + 0x23, 0x31, 0x32, 0x3c, 0x3d, 0x3e, 0x3f, 0x42, + 0x44, 0x4d, 0x4e, 0x50, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59 + }; + int[] l4 = { + 0x00, 0x01, 0x20, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x40, 0x41, 0x4f + }; + for (int i : l1) { + PID_LENGTH_MAP.put(i, 1); + } + for (int i : l2) { + PID_LENGTH_MAP.put(i, 2); + } + for (int i : l4) { + PID_LENGTH_MAP.put(i, 4); + } + } + + public CastelProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final short MSG_SC_LOGIN = 0x1001; + public static final short MSG_SC_LOGIN_RESPONSE = (short) 0x9001; + public static final short MSG_SC_LOGOUT = 0x1002; + public static final short MSG_SC_HEARTBEAT = 0x1003; + public static final short MSG_SC_HEARTBEAT_RESPONSE = (short) 0x9003; + public static final short MSG_SC_GPS = 0x4001; + public static final short MSG_SC_PID_DATA = 0x4002; + public static final short MSG_SC_SUPPORTED_PID = 0x4004; + public static final short MSG_SC_OBD_DATA = 0x4005; + public static final short MSG_SC_DTCS_PASSENGER = 0x4006; + public static final short MSG_SC_DTCS_COMMERCIAL = 0x400B; + public static final short MSG_SC_ALARM = 0x4007; + public static final short MSG_SC_CELL = 0x4008; + public static final short MSG_SC_GPS_SLEEP = 0x4009; + public static final short MSG_SC_FUEL = 0x400E; + public static final short MSG_SC_AGPS_REQUEST = 0x5101; + public static final short MSG_SC_QUERY_RESPONSE = (short) 0xA002; + public static final short MSG_SC_CURRENT_LOCATION = (short) 0xB001; + + public static final short MSG_CC_LOGIN = 0x4001; + public static final short MSG_CC_LOGIN_RESPONSE = (short) 0x8001; + public static final short MSG_CC_HEARTBEAT = 0x4206; + public static final short MSG_CC_PETROL_CONTROL = 0x4583; + public static final short MSG_CC_HEARTBEAT_RESPONSE = (short) 0x8206; + + private Position readPosition(DeviceSession deviceSession, ByteBuf buf) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + double lat = buf.readUnsignedIntLE() / 3600000.0; + double lon = buf.readUnsignedIntLE() / 3600000.0; + position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedShortLE() * 0.1); + + int flags = buf.readUnsignedByte(); + if ((flags & 0x02) == 0) { + lat = -lat; + } + if ((flags & 0x01) == 0) { + lon = -lon; + } + position.setLatitude(lat); + position.setLongitude(lon); + position.setValid((flags & 0x0C) > 0); + position.set(Position.KEY_SATELLITES, flags >> 4); + + return position; + } + + private Position createPosition(DeviceSession deviceSession) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + return position; + } + + private void decodeObd(Position position, ByteBuf buf, boolean groups) { + + int count = buf.readUnsignedByte(); + + int[] pids = new int[count]; + for (int i = 0; i < count; i++) { + pids[i] = buf.readUnsignedShortLE() & 0xff; + } + + if (groups) { + buf.readUnsignedByte(); // group count + buf.readUnsignedByte(); // group size + } + + for (int i = 0; i < count; i++) { + int value; + switch (PID_LENGTH_MAP.get(pids[i])) { + case 1: + value = buf.readUnsignedByte(); + break; + case 2: + value = buf.readUnsignedShortLE(); + break; + case 4: + value = buf.readIntLE(); + break; + default: + value = 0; + break; + } + position.add(ObdDecoder.decodeData(pids[i], value, false)); + } + } + + private void decodeStat(Position position, ByteBuf buf) { + + buf.readUnsignedIntLE(); // ACC ON time + buf.readUnsignedIntLE(); // UTC time + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedIntLE()); + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedIntLE()); + buf.readUnsignedShortLE(); // current fuel consumption + position.set(Position.KEY_STATUS, buf.readUnsignedIntLE()); + buf.skipBytes(8); + } + + private void sendResponse( + Channel channel, SocketAddress remoteAddress, + int version, ByteBuf id, short type, ByteBuf content) { + + if (channel != null) { + int length = 2 + 2 + 1 + id.readableBytes() + 2 + 2 + 2; + if (content != null) { + length += content.readableBytes(); + } + + ByteBuf response = Unpooled.buffer(length); + response.writeByte('@'); response.writeByte('@'); + response.writeShortLE(length); + response.writeByte(version); + response.writeBytes(id); + response.writeShort(type); + if (content != null) { + response.writeBytes(content); + content.release(); + } + response.writeShortLE( + Checksum.crc16(Checksum.CRC16_X25, response.nioBuffer(0, response.writerIndex()))); + response.writeByte(0x0D); response.writeByte(0x0A); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private void sendResponse( + Channel channel, SocketAddress remoteAddress, ByteBuf id, short type) { + + if (channel != null) { + int length = 2 + 2 + id.readableBytes() + 2 + 4 + 8 + 2 + 2; + + ByteBuf response = Unpooled.buffer(length); + response.writeByte('@'); response.writeByte('@'); + response.writeShortLE(length); + response.writeBytes(id); + response.writeShort(type); + response.writeIntLE(0); + for (int i = 0; i < 8; i++) { + response.writeByte(0xff); + } + response.writeShortLE( + Checksum.crc16(Checksum.CRC16_X25, response.nioBuffer(0, response.writerIndex()))); + response.writeByte(0x0D); response.writeByte(0x0A); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private void decodeAlarm(Position position, int alarm) { + switch (alarm) { + case 0x01: + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + break; + case 0x02: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + break; + case 0x03: + position.set(Position.KEY_ALARM, Position.ALARM_TEMPERATURE); + break; + case 0x04: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 0x05: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 0x06: + position.set(Position.KEY_ALARM, Position.ALARM_IDLE); + break; + case 0x07: + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + break; + case 0x08: + position.set(Position.KEY_ALARM, Position.ALARM_HIGH_RPM); + break; + case 0x09: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_ON); + break; + case 0x0B: + position.set(Position.KEY_ALARM, Position.ALARM_LANE_CHANGE); + break; + case 0x0C: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + case 0x0E: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); + break; + case 0x16: + position.set(Position.KEY_IGNITION, true); + break; + case 0x17: + position.set(Position.KEY_IGNITION, false); + break; + default: + break; + } + } + + private Object decodeSc( + Channel channel, SocketAddress remoteAddress, ByteBuf buf, + int version, ByteBuf id, short type, DeviceSession deviceSession) { + + if (type == MSG_SC_HEARTBEAT) { + + sendResponse(channel, remoteAddress, version, id, MSG_SC_HEARTBEAT_RESPONSE, null); + + } else if (type == MSG_SC_LOGIN || type == MSG_SC_LOGOUT || type == MSG_SC_GPS + || type == MSG_SC_ALARM || type == MSG_SC_CURRENT_LOCATION || type == MSG_SC_FUEL) { + + if (type == MSG_SC_LOGIN) { + ByteBuf response = Unpooled.buffer(10); + response.writeIntLE(0xFFFFFFFF); + response.writeShortLE(0); + response.writeIntLE((int) (System.currentTimeMillis() / 1000)); + sendResponse(channel, remoteAddress, version, id, MSG_SC_LOGIN_RESPONSE, response); + } + + if (type == MSG_SC_GPS) { + buf.readUnsignedByte(); // historical + } else if (type == MSG_SC_ALARM) { + buf.readUnsignedIntLE(); // alarm + } else if (type == MSG_SC_CURRENT_LOCATION) { + buf.readUnsignedShortLE(); + } + + buf.readUnsignedIntLE(); // ACC ON time + buf.readUnsignedIntLE(); // UTC time + long odometer = buf.readUnsignedIntLE(); + long tripOdometer = buf.readUnsignedIntLE(); + long fuelConsumption = buf.readUnsignedIntLE(); + buf.readUnsignedShortLE(); // current fuel consumption + long status = buf.readUnsignedIntLE(); + buf.skipBytes(8); + + int count = buf.readUnsignedByte(); + + List positions = new LinkedList<>(); + + for (int i = 0; i < count; i++) { + Position position = readPosition(deviceSession, buf); + position.set(Position.KEY_ODOMETER, odometer); + position.set(Position.KEY_ODOMETER_TRIP, tripOdometer); + position.set(Position.KEY_FUEL_CONSUMPTION, fuelConsumption); + position.set(Position.KEY_STATUS, status); + positions.add(position); + } + + if (type == MSG_SC_ALARM) { + int alarmCount = buf.readUnsignedByte(); + for (int i = 0; i < alarmCount; i++) { + if (buf.readUnsignedByte() != 0) { + int alarm = buf.readUnsignedByte(); + for (Position position : positions) { + decodeAlarm(position, alarm); + } + buf.readUnsignedShortLE(); // description + buf.readUnsignedShortLE(); // threshold + } + } + } else if (type == MSG_SC_FUEL) { + for (Position position : positions) { + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); + } + } + + if (!positions.isEmpty()) { + return positions; + } + + } else if (type == MSG_SC_GPS_SLEEP) { + + buf.readUnsignedIntLE(); // device time + + return readPosition(deviceSession, buf); + + } else if (type == MSG_SC_AGPS_REQUEST) { + + return readPosition(deviceSession, buf); + + } else if (type == MSG_SC_PID_DATA) { + + Position position = createPosition(deviceSession); + + decodeStat(position, buf); + + buf.readUnsignedShortLE(); // sample rate + decodeObd(position, buf, true); + + return position; + + } else if (type == MSG_SC_DTCS_PASSENGER) { + + Position position = createPosition(deviceSession); + + decodeStat(position, buf); + + buf.readUnsignedByte(); // flag + position.add(ObdDecoder.decodeCodes(ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())))); + + return position; + + } else if (type == MSG_SC_OBD_DATA) { + + Position position = createPosition(deviceSession); + + decodeStat(position, buf); + + buf.readUnsignedByte(); // flag + decodeObd(position, buf, false); + + return position; + + } else if (type == MSG_SC_CELL) { + + Position position = createPosition(deviceSession); + + decodeStat(position, buf); + + position.setNetwork(new Network( + CellTower.fromLacCid(buf.readUnsignedShortLE(), buf.readUnsignedShortLE()))); + + return position; + + } else if (type == MSG_SC_QUERY_RESPONSE) { + + Position position = createPosition(deviceSession); + + buf.readUnsignedShortLE(); // index + buf.readUnsignedByte(); // response count + buf.readUnsignedByte(); // response index + + int failureCount = buf.readUnsignedByte(); + for (int i = 0; i < failureCount; i++) { + buf.readUnsignedShortLE(); // tag + } + + int successCount = buf.readUnsignedByte(); + for (int i = 0; i < successCount; i++) { + buf.readUnsignedShortLE(); // tag + position.set(Position.KEY_RESULT, + buf.readSlice(buf.readUnsignedShortLE()).toString(StandardCharsets.US_ASCII)); + } + + return position; + + } + + return null; + } + + private Object decodeCc( + Channel channel, SocketAddress remoteAddress, ByteBuf buf, + int version, ByteBuf id, short type, DeviceSession deviceSession) { + + if (type == MSG_CC_HEARTBEAT) { + + sendResponse(channel, remoteAddress, version, id, MSG_CC_HEARTBEAT_RESPONSE, null); + + buf.readUnsignedByte(); // 0x01 for history + int count = buf.readUnsignedByte(); + + List positions = new LinkedList<>(); + + for (int i = 0; i < count; i++) { + Position position = readPosition(deviceSession, buf); + + position.set(Position.KEY_STATUS, buf.readUnsignedIntLE()); + position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + + buf.readUnsignedByte(); // geo-fencing id + buf.readUnsignedByte(); // geo-fencing flags + buf.readUnsignedByte(); // additional flags + + position.setNetwork(new Network( + CellTower.fromLacCid(buf.readUnsignedShortLE(), buf.readUnsignedShortLE()))); + + positions.add(position); + } + + return positions; + + } else if (type == MSG_CC_LOGIN) { + + sendResponse(channel, remoteAddress, version, id, MSG_CC_LOGIN_RESPONSE, null); + + Position position = readPosition(deviceSession, buf); + + position.set(Position.KEY_STATUS, buf.readUnsignedIntLE()); + position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + + buf.readUnsignedByte(); // geo-fencing id + buf.readUnsignedByte(); // geo-fencing flags + buf.readUnsignedByte(); // additional flags + + // GSM_CELL_CODE + // STR_Z - firmware version + // STR_Z - hardware version + + return position; + + } + + return null; + } + + private Object decodeMpip( + Channel channel, SocketAddress remoteAddress, ByteBuf buf, + int version, ByteBuf id, short type, DeviceSession deviceSession) { + + if (type == 0x4001) { + + sendResponse(channel, remoteAddress, version, id, (short) type, null); + + return readPosition(deviceSession, buf); + + } else if (type == 0x2001) { + + sendResponse(channel, remoteAddress, id, (short) 0x1001); + + buf.readUnsignedIntLE(); // index + buf.readUnsignedIntLE(); // unix time + buf.readUnsignedByte(); + + return readPosition(deviceSession, buf); + + } else if (type == 0x4201 || type == 0x4202 || type == 0x4206) { + + return readPosition(deviceSession, buf); + + } else if (type == 0x4204) { + + List positions = new LinkedList<>(); + + for (int i = 0; i < 8; i++) { + Position position = readPosition(deviceSession, buf); + buf.skipBytes(31); + positions.add(position); + } + + return positions; + + } + + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int header = buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); // length + + int version = -1; + if (header == 0x4040) { + version = buf.readUnsignedByte(); + } + + ByteBuf id = buf.readSlice(20); + short type = buf.readShort(); + + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, id.toString(StandardCharsets.US_ASCII).trim()); + if (deviceSession == null) { + return null; + } + + switch (version) { + case -1: + return decodeMpip(channel, remoteAddress, buf, version, id, type, deviceSession); + case 3: + case 4: + return decodeSc(channel, remoteAddress, buf, version, id, type, deviceSession); + default: + return decodeCc(channel, remoteAddress, buf, version, id, type, deviceSession); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java b/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java new file mode 100644 index 000000000..e1f78e7c1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java @@ -0,0 +1,70 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Context; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class CastelProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeContent(long deviceId, short type, ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(0); + String uniqueId = Context.getIdentityManager().getById(deviceId).getUniqueId(); + + buf.writeByte('@'); + buf.writeByte('@'); + + buf.writeShortLE(2 + 2 + 1 + 20 + 2 + content.readableBytes() + 2 + 2); // length + + buf.writeByte(1); // protocol version + + buf.writeBytes(uniqueId.getBytes(StandardCharsets.US_ASCII)); + buf.writeZero(20 - uniqueId.length()); + + buf.writeShort(type); + buf.writeBytes(content); + + buf.writeShortLE(Checksum.crc16(Checksum.CRC16_X25, buf.nioBuffer())); + + buf.writeByte('\r'); + buf.writeByte('\n'); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + ByteBuf content = Unpooled.buffer(0); + switch (command.getType()) { + case Command.TYPE_ENGINE_STOP: + content.writeByte(1); + return encodeContent(command.getDeviceId(), CastelProtocolDecoder.MSG_CC_PETROL_CONTROL, content); + case Command.TYPE_ENGINE_RESUME: + content.writeByte(0); + return encodeContent(command.getDeviceId(), CastelProtocolDecoder.MSG_CC_PETROL_CONTROL, content); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/CautelaProtocol.java b/src/main/java/org/traccar/protocol/CautelaProtocol.java new file mode 100644 index 000000000..452bdf8d4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CautelaProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class CautelaProtocol extends BaseProtocol { + + public CautelaProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new CautelaProtocolDecoder(CautelaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java new file mode 100644 index 000000000..bddf19b41 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java @@ -0,0 +1,78 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class CautelaProtocolDecoder extends BaseProtocolDecoder { + + public CautelaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+),") // type + .number("(d+),") // imei + .number("(dd),(dd),(dd),") // date (ddmmyy) + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(dd)(dd),") // time (hhmm) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + parser.next(); // type + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder(); + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(true); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + + dateBuilder.setHour(parser.nextInt()).setMinute(parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/CellocatorFrameDecoder.java b/src/main/java/org/traccar/protocol/CellocatorFrameDecoder.java new file mode 100644 index 000000000..7d5499d92 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CellocatorFrameDecoder.java @@ -0,0 +1,66 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class CellocatorFrameDecoder extends BaseFrameDecoder { + + private static final int MESSAGE_MINIMUM_LENGTH = 15; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { + return null; + } + + int length = 0; + int type = buf.getUnsignedByte(4); + switch (type) { + case CellocatorProtocolDecoder.MSG_CLIENT_STATUS: + length = 70; + break; + case CellocatorProtocolDecoder.MSG_CLIENT_PROGRAMMING: + length = 31; + break; + case CellocatorProtocolDecoder.MSG_CLIENT_SERIAL_LOG: + length = 70; + break; + case CellocatorProtocolDecoder.MSG_CLIENT_SERIAL: + if (buf.readableBytes() >= 19) { + length = 19 + buf.getUnsignedShortLE(16); + } + break; + case CellocatorProtocolDecoder.MSG_CLIENT_MODULAR: + length = 15 + buf.getUnsignedByte(13); + break; + default: + break; + } + + if (length > 0 && buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocol.java b/src/main/java/org/traccar/protocol/CellocatorProtocol.java new file mode 100644 index 000000000..a52170dc9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CellocatorProtocol.java @@ -0,0 +1,45 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class CellocatorProtocol extends BaseProtocol { + + public CellocatorProtocol() { + setSupportedDataCommands( + Command.TYPE_OUTPUT_CONTROL); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CellocatorFrameDecoder()); + pipeline.addLast(new CellocatorProtocolEncoder()); + pipeline.addLast(new CellocatorProtocolDecoder(CellocatorProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CellocatorProtocolEncoder()); + pipeline.addLast(new CellocatorProtocolDecoder(CellocatorProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java new file mode 100644 index 000000000..d23f76a93 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java @@ -0,0 +1,177 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class CellocatorProtocolDecoder extends BaseProtocolDecoder { + + public CellocatorProtocolDecoder(Protocol protocol) { + super(protocol); + } + + static final int MSG_CLIENT_STATUS = 0; + static final int MSG_CLIENT_PROGRAMMING = 3; + static final int MSG_CLIENT_SERIAL_LOG = 7; + static final int MSG_CLIENT_SERIAL = 8; + static final int MSG_CLIENT_MODULAR = 9; + + public static final int MSG_SERVER_ACKNOWLEDGE = 4; + + private byte commandCount; + + private void sendReply(Channel channel, SocketAddress remoteAddress, long deviceId, byte packetNumber) { + if (channel != null) { + ByteBuf reply = Unpooled.buffer(28); + reply.writeByte('M'); + reply.writeByte('C'); + reply.writeByte('G'); + reply.writeByte('P'); + reply.writeByte(MSG_SERVER_ACKNOWLEDGE); + reply.writeIntLE((int) deviceId); + reply.writeByte(commandCount++); + reply.writeIntLE(0); // authentication code + reply.writeByte(0); + reply.writeByte(packetNumber); + reply.writeZero(11); + + byte checksum = 0; + for (int i = 4; i < 27; i++) { + checksum += reply.getByte(i); + } + reply.writeByte(checksum); + + channel.writeAndFlush(new NetworkMessage(reply, remoteAddress)); + } + } + + private String decodeAlarm(short reason) { + switch (reason) { + case 70: + return Position.ALARM_SOS; + case 80: + return Position.ALARM_POWER_CUT; + case 81: + return Position.ALARM_LOW_POWER; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + boolean alternative = buf.getByte(buf.readerIndex() + 3) != 'P'; + + buf.skipBytes(4); // system code + int type = buf.readUnsignedByte(); + long deviceUniqueId = buf.readUnsignedIntLE(); + + if (type != MSG_CLIENT_SERIAL) { + buf.readUnsignedShortLE(); // communication control + } + byte packetNumber = buf.readByte(); + + sendReply(channel, remoteAddress, deviceUniqueId, packetNumber); + + if (type == MSG_CLIENT_STATUS) { + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceUniqueId)); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte()); + position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); + buf.readUnsignedByte(); // protocol version + + position.set(Position.KEY_STATUS, buf.readUnsignedByte() & 0x0f); + + buf.readUnsignedByte(); // operator / configuration flags + buf.readUnsignedByte(); // reason data + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + + position.set("mode", buf.readUnsignedByte()); + position.set(Position.KEY_INPUT, buf.readUnsignedIntLE()); + + if (alternative) { + buf.readUnsignedByte(); // input + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE()); + } else { + buf.readUnsignedByte(); // operator + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedIntLE()); + } + + position.set(Position.KEY_ODOMETER, buf.readUnsignedMediumLE()); + + buf.skipBytes(6); // multi-purpose data + buf.readUnsignedShortLE(); // fix time + buf.readUnsignedByte(); // location status + buf.readUnsignedByte(); // mode 1 + buf.readUnsignedByte(); // mode 2 + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + position.setValid(true); + + if (alternative) { + position.setLongitude(buf.readIntLE() / 10000000.0); + position.setLatitude(buf.readIntLE() / 10000000.0); + } else { + position.setLongitude(buf.readIntLE() / Math.PI * 180 / 100000000); + position.setLatitude(buf.readIntLE() / Math.PI * 180 / 100000000); + } + + position.setAltitude(buf.readIntLE() * 0.01); + + if (alternative) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedIntLE())); + position.setCourse(buf.readUnsignedShortLE() / 1000.0); + } else { + position.setSpeed(UnitsConverter.knotsFromMps(buf.readUnsignedIntLE() * 0.01)); + position.setCourse(buf.readUnsignedShortLE() / Math.PI * 180.0 / 1000.0); + } + + DateBuilder dateBuilder = new DateBuilder() + .setTimeReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedShortLE()); + position.setTime(dateBuilder.getDate()); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/CellocatorProtocolEncoder.java new file mode 100644 index 000000000..0382dbbc7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CellocatorProtocolEncoder.java @@ -0,0 +1,66 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.model.Command; + +public class CellocatorProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeContent(long deviceId, int command, int data1, int data2) { + + ByteBuf buf = Unpooled.buffer(0); + buf.writeByte('M'); + buf.writeByte('C'); + buf.writeByte('G'); + buf.writeByte('P'); + buf.writeByte(0); + buf.writeIntLE(Integer.parseInt(getUniqueId(deviceId))); + buf.writeByte(0); // command numerator + buf.writeIntLE(0); // authentication code + buf.writeByte(command); + buf.writeByte(command); + buf.writeByte(data1); + buf.writeByte(data1); + buf.writeByte(data2); + buf.writeByte(data2); + buf.writeIntLE(0); // command specific data + + byte checksum = 0; + for (int i = 4; i < buf.writerIndex(); i++) { + checksum += buf.getByte(i); + } + buf.writeByte(checksum); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_OUTPUT_CONTROL: + int data = Integer.parseInt(command.getString(Command.KEY_DATA)) << 4 + + command.getInteger(Command.KEY_INDEX); + return encodeContent(command.getDeviceId(), 0x03, data, 0); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/CguardProtocol.java b/src/main/java/org/traccar/protocol/CguardProtocol.java new file mode 100644 index 000000000..9157ca35c --- /dev/null +++ b/src/main/java/org/traccar/protocol/CguardProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class CguardProtocol extends BaseProtocol { + + public CguardProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new CguardProtocolDecoder(CguardProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CguardProtocolDecoder.java b/src/main/java/org/traccar/protocol/CguardProtocolDecoder.java new file mode 100644 index 000000000..d934921f1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CguardProtocolDecoder.java @@ -0,0 +1,147 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class CguardProtocolDecoder extends BaseProtocolDecoder { + + public CguardProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_NV = new PatternBuilder() + .text("NV:") + .number("(dd)(dd)(dd) ") // date (yymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .number(":(-?d+.d+)") // longitude + .number(":(-?d+.d+)") // latitude + .number(":(d+.?d*)") // speed + .number(":(?:NAN|(d+.?d*))") // accuracy + .number(":(?:NAN|(d+.?d*))") // course + .number(":(?:NAN|(d+.?d*))").optional() // altitude + .compile(); + + private static final Pattern PATTERN_BC = new PatternBuilder() + .text("BC:") + .number("(dd)(dd)(dd) ") // date (yymmdd) + .number("(dd)(dd)(dd):") // time (hhmmss) + .expression("(.+)") // data + .compile(); + + private Position decodePosition(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN_NV, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setValid(true); + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + + position.setAccuracy(parser.nextDouble(0)); + + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + return position; + } + + private Position decodeStatus(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN_BC, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, parser.nextDateTime()); + + String[] data = parser.next().split(":"); + for (int i = 0; i < data.length / 2; i++) { + String key = data[i * 2]; + String value = data[i * 2 + 1]; + switch (key) { + case "CSQ1": + position.set(Position.KEY_RSSI, Integer.parseInt(value)); + break; + case "NSQ1": + position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); + break; + case "BAT1": + if (value.contains(".")) { + position.set(Position.KEY_BATTERY, Double.parseDouble(value)); + } else { + position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(value)); + } + break; + case "PWR1": + position.set(Position.KEY_POWER, Double.parseDouble(value)); + break; + default: + position.set(key.toLowerCase(), value); + break; + } + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("ID:") || sentence.startsWith("IDRO:")) { + getDeviceSession(channel, remoteAddress, sentence.substring(sentence.indexOf(':') + 1)); + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + if (sentence.startsWith("NV:")) { + return decodePosition(deviceSession, sentence); + } else if (sentence.startsWith("BC:")) { + return decodeStatus(deviceSession, sentence); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocol.java b/src/main/java/org/traccar/protocol/CityeasyProtocol.java new file mode 100644 index 000000000..f4b49c9ff --- /dev/null +++ b/src/main/java/org/traccar/protocol/CityeasyProtocol.java @@ -0,0 +1,42 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class CityeasyProtocol extends BaseProtocol { + + public CityeasyProtocol() { + setSupportedDataCommands( + Command.TYPE_POSITION_SINGLE, + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_POSITION_STOP, + Command.TYPE_SET_TIMEZONE); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0)); + pipeline.addLast(new CityeasyProtocolEncoder()); + pipeline.addLast(new CityeasyProtocolDecoder(CityeasyProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java b/src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java new file mode 100644 index 000000000..9c4c7e11d --- /dev/null +++ b/src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java @@ -0,0 +1,127 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class CityeasyProtocolDecoder extends BaseProtocolDecoder { + + public CityeasyProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .groupBegin() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("([AV]),") // validity + .number("(d+),") // satellites + .number("([NS]),(d+.d+),") // latitude + .number("([EW]),(d+.d+),") // longitude + .number("(d+.d),") // speed + .number("(d+.d),") // hdop + .number("(d+.d)") // altitude + .groupEnd("?").text(";") + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(d+),") // lac + .number("(d+)") // cell + .any() + .compile(); + + public static final int MSG_ADDRESS_REQUEST = 0x0001; + public static final int MSG_STATUS = 0x0002; + public static final int MSG_LOCATION_REPORT = 0x0003; + public static final int MSG_LOCATION_REQUEST = 0x0004; + public static final int MSG_LOCATION_INTERVAL = 0x0005; + public static final int MSG_PHONE_NUMBER = 0x0006; + public static final int MSG_MONITORING = 0x0007; + public static final int MSG_TIMEZONE = 0x0008; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.readUnsignedShort(); // length + + String imei = ByteBufUtil.hexDump(buf.readSlice(7)); + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, imei, imei + Checksum.luhn(Long.parseLong(imei))); + if (deviceSession == null) { + return null; + } + + int type = buf.readUnsignedShort(); + + if (type == MSG_LOCATION_REPORT || type == MSG_LOCATION_REQUEST) { + + String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 8, StandardCharsets.US_ASCII); + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.hasNext(15)) { + + position.setTime(parser.nextDateTime()); + + position.setValid(parser.next().equals("A")); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + + position.setSpeed(parser.nextDouble(0)); + position.set(Position.KEY_HDOP, parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + } else { + + getLastLocation(position, null); + + } + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)))); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocolEncoder.java b/src/main/java/org/traccar/protocol/CityeasyProtocolEncoder.java new file mode 100644 index 000000000..350fdf0ab --- /dev/null +++ b/src/main/java/org/traccar/protocol/CityeasyProtocolEncoder.java @@ -0,0 +1,73 @@ +/* + * 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. + * 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.TimeZone; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +public class CityeasyProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeContent(int type, ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte('S'); + buf.writeByte('S'); + buf.writeShort(2 + 2 + 2 + content.readableBytes() + 4 + 2 + 2); + buf.writeShort(type); + buf.writeBytes(content); + buf.writeInt(0x0B); + buf.writeShort(Checksum.crc16(Checksum.CRC16_KERMIT, buf.nioBuffer())); + buf.writeByte('\r'); + buf.writeByte('\n'); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + ByteBuf content = Unpooled.buffer(); + + switch (command.getType()) { + case Command.TYPE_POSITION_SINGLE: + return encodeContent(CityeasyProtocolDecoder.MSG_LOCATION_REQUEST, content); + case Command.TYPE_POSITION_PERIODIC: + content.writeShort(command.getInteger(Command.KEY_FREQUENCY)); + return encodeContent(CityeasyProtocolDecoder.MSG_LOCATION_INTERVAL, content); + case Command.TYPE_POSITION_STOP: + content.writeShort(0); + return encodeContent(CityeasyProtocolDecoder.MSG_LOCATION_INTERVAL, content); + case Command.TYPE_SET_TIMEZONE: + int timezone = TimeZone.getTimeZone(command.getString(Command.KEY_TIMEZONE)).getRawOffset() / 60000; + if (timezone < 0) { + content.writeByte(1); + } else { + content.writeByte(0); + } + content.writeShort(Math.abs(timezone)); + return encodeContent(CityeasyProtocolDecoder.MSG_TIMEZONE, content); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/ContinentalProtocol.java b/src/main/java/org/traccar/protocol/ContinentalProtocol.java new file mode 100644 index 000000000..bc7928fba --- /dev/null +++ b/src/main/java/org/traccar/protocol/ContinentalProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ContinentalProtocol extends BaseProtocol { + + public ContinentalProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0)); + pipeline.addLast(new ContinentalProtocolDecoder(ContinentalProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java b/src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java new file mode 100644 index 000000000..471afa0d6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java @@ -0,0 +1,114 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; + +public class ContinentalProtocolDecoder extends BaseProtocolDecoder { + + public ContinentalProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_KEEPALIVE = 0x00; + public static final int MSG_STATUS = 0x02; + public static final int MSG_ACK = 0x06; + public static final int MSG_NACK = 0x15; + + private double readCoordinate(ByteBuf buf, boolean extended) { + long value = buf.readUnsignedInt(); + if (extended ? (value & 0x08000000) != 0 : (value & 0x00800000) != 0) { + value |= extended ? 0xF0000000 : 0xFF000000; + } + return (int) value / (extended ? 360000.0 : 3600.0); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.readUnsignedShort(); // length + buf.readUnsignedByte(); // software version + + long serialNumber = buf.readUnsignedInt(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(serialNumber)); + if (deviceSession == null) { + return null; + } + + buf.readUnsignedByte(); // product + + int type = buf.readUnsignedByte(); + + if (type == MSG_STATUS) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setFixTime(new Date(buf.readUnsignedInt() * 1000L)); + + boolean extended = buf.getUnsignedByte(buf.readerIndex()) != 0; + position.setLatitude(readCoordinate(buf, extended)); + position.setLongitude(readCoordinate(buf, extended)); + + position.setCourse(buf.readUnsignedShort()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + + position.setValid(buf.readUnsignedByte() > 0); + + position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000L)); + + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + + int input = buf.readUnsignedShort(); + position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); + position.set(Position.KEY_INPUT, input); + + position.set(Position.KEY_OUTPUT, buf.readUnsignedShort()); + position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + + buf.readUnsignedShort(); // reserved + + if (buf.readableBytes() > 4) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + } + + if (buf.readableBytes() > 4) { + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(buf.readUnsignedInt())); + } + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/CradlepointProtocol.java b/src/main/java/org/traccar/protocol/CradlepointProtocol.java new file mode 100644 index 000000000..4a09e0311 --- /dev/null +++ b/src/main/java/org/traccar/protocol/CradlepointProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class CradlepointProtocol extends BaseProtocol { + + public CradlepointProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new CradlepointProtocolDecoder(CradlepointProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java b/src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java new file mode 100644 index 000000000..a282131ce --- /dev/null +++ b/src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java @@ -0,0 +1,95 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.regex.Pattern; + +public class CradlepointProtocolDecoder extends BaseProtocolDecoder { + + public CradlepointProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("([^,]+),") // id + .number("(d{1,6}),") // time (hhmmss) + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+)?,") // speed + .number("(d+.d+)?,") // course + .expression("([^,]+)?,") // carrier + .expression("([^,]+)?,") // serdis + .number("(-?d+)?,") // rsrp + .number("(-?d+)?,") // rssi + .number("(-?d+)?,") // rsrq + .expression("([^,]+)?,") // ecio + .expression("([^,]+)?") // wan ip + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + int time = parser.nextInt(); + DateBuilder dateBuilder = new DateBuilder(new Date()); + dateBuilder.setHour(time / 100 / 100); + dateBuilder.setMinute(time / 100 % 100); + dateBuilder.setSecond(time % 100); + position.setTime(dateBuilder.getDate()); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set("carrid", parser.next()); + position.set("serdis", parser.next()); + position.set("rsrp", parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set("rsrq", parser.nextInt()); + position.set("ecio", parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/DishaProtocol.java b/src/main/java/org/traccar/protocol/DishaProtocol.java new file mode 100644 index 000000000..38f49cc05 --- /dev/null +++ b/src/main/java/org/traccar/protocol/DishaProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class DishaProtocol extends BaseProtocol { + + public DishaProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new DishaProtocolDecoder(DishaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/DishaProtocolDecoder.java b/src/main/java/org/traccar/protocol/DishaProtocolDecoder.java new file mode 100644 index 000000000..3223988ab --- /dev/null +++ b/src/main/java/org/traccar/protocol/DishaProtocolDecoder.java @@ -0,0 +1,102 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class DishaProtocolDecoder extends BaseProtocolDecoder { + + public DishaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$A#A#") + .number("(d+)#") // imei + .expression("([AVMX])#") // validity + .number("(dd)(dd)(dd)#") // time (hhmmss) + .number("(dd)(dd)(dd)#") // date (ddmmyy) + .number("(dd)(dd.d+)#") // latitude + .expression("([NS])#") + .number("(ddd)(dd.d+)#") // longitude + .expression("([EW])#") + .number("(d+.d+)#") // speed + .number("(d+.d+)#") // course + .number("(d+)#") // satellites + .number("(d+.d+)#") // hdop + .number("(d+)#") // gsm + .expression("([012])#") // power mode + .number("(d+)#") // battery + .number("(d+)#") // adc 1 + .number("(d+)#") // adc 2 + .number("d+.d+#") // day distance + .number("(d+.d+)#") // odometer + .expression("([01]+)") // digital inputs + .text("*") + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.next().equals("A")); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_RSSI, parser.nextDouble()); + position.set(Position.KEY_CHARGE, parser.nextInt(0) == 2); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); + + position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); + position.set(Position.PREFIX_ADC + 2, parser.nextInt(0)); + + position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); + position.set(Position.KEY_INPUT, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/DmtHttpProtocol.java b/src/main/java/org/traccar/protocol/DmtHttpProtocol.java new file mode 100644 index 000000000..34568128f --- /dev/null +++ b/src/main/java/org/traccar/protocol/DmtHttpProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class DmtHttpProtocol extends BaseProtocol { + + public DmtHttpProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new DmtHttpProtocolDecoder(DmtHttpProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java new file mode 100644 index 000000000..987361baf --- /dev/null +++ b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java @@ -0,0 +1,133 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonObject; +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.TimeZone; + +public class DmtHttpProtocolDecoder extends BaseHttpProtocolDecoder { + + public DmtHttpProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + JsonObject root = Json.createReader( + new StringReader(request.content().toString(StandardCharsets.US_ASCII))).readObject(); + + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, root.getString("IMEI")); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + List positions = new LinkedList<>(); + + JsonArray records = root.getJsonArray("Records"); + + for (int i = 0; i < records.size(); i++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + JsonObject record = records.getJsonObject(i); + + position.set(Position.KEY_INDEX, record.getInt("SeqNo")); + position.set(Position.KEY_EVENT, record.getInt("Reason")); + + position.setDeviceTime(dateFormat.parse(record.getString("DateUTC"))); + + JsonArray fields = record.getJsonArray("Fields"); + + for (int j = 0; j < fields.size(); j++) { + JsonObject field = fields.getJsonObject(j); + switch (field.getInt("FType")) { + case 0: + position.setFixTime(dateFormat.parse(field.getString("GpsUTC"))); + position.setLatitude(field.getJsonNumber("Lat").doubleValue()); + position.setLongitude(field.getJsonNumber("Long").doubleValue()); + position.setAltitude(field.getInt("Alt")); + position.setSpeed(UnitsConverter.knotsFromCps(field.getInt("Spd"))); + position.setCourse(field.getInt("Head")); + position.setAccuracy(field.getInt("PosAcc")); + position.setValid(field.getInt("GpsStat") > 0); + break; + case 2: + int input = field.getInt("DIn"); + int output = field.getInt("DOut"); + + position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); + + position.set(Position.KEY_INPUT, input); + position.set(Position.KEY_OUTPUT, output); + position.set(Position.KEY_STATUS, field.getInt("DevStat")); + break; + case 6: + JsonObject adc = field.getJsonObject("AnalogueData"); + if (adc.containsKey("1")) { + position.set(Position.KEY_BATTERY, adc.getInt("1") * 0.001); + } + if (adc.containsKey("2")) { + position.set(Position.KEY_POWER, adc.getInt("2") * 0.01); + } + if (adc.containsKey("3")) { + position.set(Position.KEY_DEVICE_TEMP, adc.getInt("3") * 0.01); + } + if (adc.containsKey("4")) { + position.set(Position.KEY_RSSI, adc.getInt("4")); + } + if (adc.containsKey("5")) { + position.set("solarPower", adc.getInt("5") * 0.001); + } + break; + default: + break; + } + } + + positions.add(position); + } + + sendResponse(channel, HttpResponseStatus.OK); + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/DmtProtocol.java b/src/main/java/org/traccar/protocol/DmtProtocol.java new file mode 100644 index 000000000..78a5243c0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/DmtProtocol.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; +public class DmtProtocol extends BaseProtocol { + + public DmtProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 3, 2, 0, 0, true)); + pipeline.addLast(new DmtProtocolDecoder(DmtProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java new file mode 100644 index 000000000..c04e90f1d --- /dev/null +++ b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java @@ -0,0 +1,289 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class DmtProtocolDecoder extends BaseProtocolDecoder { + + public DmtProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_HELLO = 0x00; + public static final int MSG_HELLO_RESPONSE = 0x01; + public static final int MSG_DATA_RECORD = 0x04; + public static final int MSG_COMMIT = 0x05; + public static final int MSG_COMMIT_RESPONSE = 0x06; + public static final int MSG_DATA_RECORD_64 = 0x10; + + public static final int MSG_CANNED_REQUEST_1 = 0x14; + public static final int MSG_CANNED_RESPONSE_1 = 0x15; + public static final int MSG_CANNED_REQUEST_2 = 0x22; + public static final int MSG_CANNED_RESPONSE_2 = 0x23; + + private void sendResponse(Channel channel, int type, ByteBuf content) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x02); response.writeByte(0x55); // header + response.writeByte(type); + response.writeShortLE(content != null ? content.readableBytes() : 0); + if (content != null) { + response.writeBytes(content); + content.release(); + } + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + private List decodeFixed64(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + while (buf.readableBytes() >= 64) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readByte(); // type + + position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); + + long time = buf.readUnsignedIntLE(); + position.setTime(new DateBuilder() + .setYear((int) (2000 + (time & 0x3F))) + .setMonth((int) (time >> 6) & 0xF) + .setDay((int) (time >> 10) & 0x1F) + .setHour((int) (time >> 15) & 0x1F) + .setMinute((int) (time >> 20) & 0x3F) + .setSecond((int) (time >> 26) & 0x3F) + .getDate()); + + position.setLongitude(buf.readIntLE() * 0.0000001); + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedByte() * 2); + position.setAltitude(buf.readShortLE()); + + buf.readUnsignedShortLE(); // position accuracy + buf.readUnsignedByte(); // speed accuracy + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + position.setValid(BitUtil.check(buf.readByte(), 0)); + + position.set(Position.KEY_INPUT, buf.readUnsignedIntLE()); + position.set(Position.KEY_OUTPUT, buf.readUnsignedShortLE()); + + for (int i = 1; i <= 5; i++) { + position.set(Position.PREFIX_ADC + i, buf.readShortLE()); + } + + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + + buf.readShortLE(); // accelerometer x + buf.readShortLE(); // accelerometer y + buf.readShortLE(); // accelerometer z + + buf.skipBytes(8); // device id + + position.set(Position.KEY_PDOP, buf.readUnsignedShortLE() * 0.01); + + buf.skipBytes(2); // reserved + + buf.readUnsignedShortLE(); // checksum + + positions.add(position); + } + + return positions; + } + + private List decodeStandard(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + while (buf.isReadable()) { + int recordEnd = buf.readerIndex() + buf.readUnsignedShortLE(); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); + + position.setDeviceTime(new Date(1356998400000L + buf.readUnsignedIntLE() * 1000)); // since 1 Jan 2013 + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + while (buf.readerIndex() < recordEnd) { + + int fieldId = buf.readUnsignedByte(); + int fieldLength = buf.readUnsignedByte(); + int fieldEnd = buf.readerIndex() + (fieldLength == 255 ? buf.readUnsignedShortLE() : fieldLength); + + if (fieldId == 0) { + + position.setFixTime(new Date(1356998400000L + buf.readUnsignedIntLE() * 1000)); + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + position.setAltitude(buf.readShortLE()); + position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE())); + + buf.readUnsignedByte(); // speed accuracy + + position.setCourse(buf.readUnsignedByte() * 2); + + position.set(Position.KEY_PDOP, buf.readUnsignedByte() * 0.1); + + position.setAccuracy(buf.readUnsignedByte()); + position.setValid(buf.readUnsignedByte() != 0); + + } else if (fieldId == 2) { + + int input = buf.readIntLE(); + int output = buf.readUnsignedShortLE(); + int status = buf.readUnsignedShortLE(); + + position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); + + position.set(Position.KEY_INPUT, input); + position.set(Position.KEY_OUTPUT, output); + position.set(Position.KEY_STATUS, status); + + } else if (fieldId == 6) { + + while (buf.readerIndex() < fieldEnd) { + switch (buf.readUnsignedByte()) { + case 1: + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + break; + case 2: + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); + break; + case 3: + position.set(Position.KEY_DEVICE_TEMP, buf.readShortLE() * 0.01); + break; + case 4: + position.set(Position.KEY_RSSI, buf.readUnsignedShortLE()); + break; + case 5: + position.set("solarPower", buf.readUnsignedShortLE() * 0.001); + break; + default: + break; + } + } + + } + + buf.readerIndex(fieldEnd); + + } + + if (position.getFixTime() == null) { + getLastLocation(position, position.getDeviceTime()); + } + + positions.add(position); + } + + return positions; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + + int type = buf.readUnsignedByte(); + int length = buf.readUnsignedShortLE(); + + if (type == MSG_HELLO) { + + buf.readUnsignedIntLE(); // device serial number + + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII)); + + ByteBuf response = Unpooled.buffer(); + if (length == 51) { + response.writeByte(0); // reserved + response.writeIntLE(0); // reserved + } else { + response.writeIntLE((int) ((System.currentTimeMillis() - 1356998400000L) / 1000)); + response.writeIntLE(deviceSession != null ? 0 : 1); // flags + } + + sendResponse(channel, MSG_HELLO_RESPONSE, response); + + } else if (type == MSG_COMMIT) { + + ByteBuf response = Unpooled.buffer(0); + response.writeByte(1); // flags (success) + sendResponse(channel, MSG_COMMIT_RESPONSE, response); + + } else if (type == MSG_CANNED_REQUEST_1) { + + ByteBuf response = Unpooled.buffer(0); + response.writeBytes(new byte[12]); + sendResponse(channel, MSG_CANNED_RESPONSE_1, response); + + } else if (type == MSG_CANNED_REQUEST_2) { + + sendResponse(channel, MSG_CANNED_RESPONSE_2, null); + + } else if (type == MSG_DATA_RECORD_64) { + + return decodeFixed64(channel, remoteAddress, buf); + + } else if (type == MSG_DATA_RECORD) { + + return decodeStandard(channel, remoteAddress, buf); + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/DwayProtocol.java b/src/main/java/org/traccar/protocol/DwayProtocol.java new file mode 100644 index 000000000..05fd8b6e7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/DwayProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class DwayProtocol extends BaseProtocol { + + public DwayProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new DwayProtocolDecoder(DwayProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/DwayProtocolDecoder.java b/src/main/java/org/traccar/protocol/DwayProtocolDecoder.java new file mode 100644 index 000000000..9b02c898e --- /dev/null +++ b/src/main/java/org/traccar/protocol/DwayProtocolDecoder.java @@ -0,0 +1,103 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class DwayProtocolDecoder extends BaseProtocolDecoder { + + public DwayProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("AA55,") + .number("d+,") // index + .number("(d+),") // imei + .number("d+,") // type + .number("(dd)(dd)(dd),") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(-?d+),") // altitude + .number(" ?(d+.d+),") // speed + .number("(d+),") // course + .number("([01]{4}),") // input + .number("([01]{4}),") // output + .number("([01]+),") // flags + .number("(d+),") // battery + .number("(d+),") // adc1 + .number("(d+),") // adc2 + .number("(d+)") // driver + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + if (sentence.equals("AA55,HB")) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("55AA,HB,OK\r\n", remoteAddress)); + } + return null; + } + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(parser.nextDateTime()); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setAltitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_INPUT, parser.nextBinInt()); + position.set(Position.KEY_OUTPUT, parser.nextBinInt()); + + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); + position.set(Position.PREFIX_ADC + 1, parser.nextInt() * 0.001); + position.set(Position.PREFIX_ADC + 2, parser.nextInt() * 0.001); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocol.java b/src/main/java/org/traccar/protocol/EasyTrackProtocol.java new file mode 100644 index 000000000..74c636d06 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EasyTrackProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class EasyTrackProtocol extends BaseProtocol { + + public EasyTrackProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "#", "\r\n")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new EasyTrackProtocolDecoder(EasyTrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java new file mode 100644 index 000000000..2ddb24f5c --- /dev/null +++ b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java @@ -0,0 +1,138 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { + + public EasyTrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("*").expression("..,") // manufacturer + .number("(d+),") // imei + .expression("([^,]{2}),") // command + .expression("([AV]),") // validity + .number("(xx)(xx)(xx),") // date (yymmdd) + .number("(xx)(xx)(xx),") // time (hhmmss) + .number("(x)(x{7}),") // latitude + .number("(x)(x{7}),") // longitude + .number("(x{4}),") // speed + .number("(x{4}),") // course + .number("(x{8}),") // status + .number("(x+),") // signal + .number("(d+),") // power + .number("(x{4}),") // oil + .number("(x+),?") // odometer + .number("(d+)?") // altitude + .any() + .compile(); + + private String decodeAlarm(long status) { + if ((status & 0x02000000) != 0) { + return Position.ALARM_GEOFENCE_ENTER; + } + if ((status & 0x04000000) != 0) { + return Position.ALARM_GEOFENCE_EXIT; + } + if ((status & 0x08000000) != 0) { + return Position.ALARM_LOW_BATTERY; + } + if ((status & 0x20000000) != 0) { + return Position.ALARM_VIBRATION; + } + if ((status & 0x80000000) != 0) { + return Position.ALARM_OVERSPEED; + } + if ((status & 0x00010000) != 0) { + return Position.ALARM_SOS; + } + if ((status & 0x00040000) != 0) { + return Position.ALARM_POWER_CUT; + } + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_COMMAND, parser.next()); + + position.setValid(parser.next().equals("A")); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(parser.nextHexInt(0), parser.nextHexInt(0), parser.nextHexInt(0)) + .setTime(parser.nextHexInt(0), parser.nextHexInt(0), parser.nextHexInt(0)); + position.setTime(dateBuilder.getDate()); + + if (BitUtil.check(parser.nextHexInt(0), 3)) { + position.setLatitude(-parser.nextHexInt(0) / 600000.0); + } else { + position.setLatitude(parser.nextHexInt(0) / 600000.0); + } + + if (BitUtil.check(parser.nextHexInt(0), 3)) { + position.setLongitude(-parser.nextHexInt(0) / 600000.0); + } else { + position.setLongitude(parser.nextHexInt(0) / 600000.0); + } + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextHexInt(0) / 100.0)); + position.setCourse(parser.nextHexInt(0) / 100.0); + + long status = parser.nextHexLong(); + position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_ALARM, decodeAlarm(status)); + + position.set("signal", parser.next()); + position.set(Position.KEY_POWER, parser.nextDouble(0)); + position.set("oil", parser.nextHexInt(0)); + position.set(Position.KEY_ODOMETER, parser.nextHexInt(0) * 100); + + position.setAltitude(parser.nextDouble(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/EelinkProtocol.java b/src/main/java/org/traccar/protocol/EelinkProtocol.java new file mode 100644 index 000000000..de4ea971b --- /dev/null +++ b/src/main/java/org/traccar/protocol/EelinkProtocol.java @@ -0,0 +1,50 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class EelinkProtocol extends BaseProtocol { + + public EelinkProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_REBOOT_DEVICE); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2)); + pipeline.addLast(new EelinkProtocolEncoder(false)); + pipeline.addLast(new EelinkProtocolDecoder(EelinkProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new EelinkProtocolEncoder(true)); + pipeline.addLast(new EelinkProtocolDecoder(EelinkProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java new file mode 100644 index 000000000..2a1db2e32 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java @@ -0,0 +1,441 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.socket.DatagramChannel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.regex.Pattern; + +public class EelinkProtocolDecoder extends BaseProtocolDecoder { + + public EelinkProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 0x01; + public static final int MSG_GPS = 0x02; + public static final int MSG_HEARTBEAT = 0x03; + public static final int MSG_ALARM = 0x04; + public static final int MSG_STATE = 0x05; + public static final int MSG_SMS = 0x06; + public static final int MSG_OBD = 0x07; + public static final int MSG_DOWNLINK = 0x80; + public static final int MSG_DATA = 0x81; + + public static final int MSG_NORMAL = 0x12; + public static final int MSG_WARNING = 0x14; + public static final int MSG_REPORT = 0x15; + public static final int MSG_COMMAND = 0x16; + public static final int MSG_OBD_DATA = 0x17; + public static final int MSG_OBD_BODY = 0x18; + public static final int MSG_OBD_CODE = 0x19; + public static final int MSG_CAMERA_INFO = 0x1E; + public static final int MSG_CAMERA_DATA = 0x1F; + + private String decodeAlarm(Short value) { + switch (value) { + case 0x01: + return Position.ALARM_POWER_OFF; + case 0x02: + return Position.ALARM_SOS; + case 0x03: + return Position.ALARM_LOW_BATTERY; + case 0x04: + return Position.ALARM_VIBRATION; + case 0x08: + case 0x09: + return Position.ALARM_GPS_ANTENNA_CUT; + case 0x81: + return Position.ALARM_LOW_SPEED; + case 0x82: + return Position.ALARM_OVERSPEED; + case 0x83: + return Position.ALARM_GEOFENCE_ENTER; + case 0x84: + return Position.ALARM_GEOFENCE_EXIT; + case 0x85: + return Position.ALARM_ACCIDENT; + case 0x86: + return Position.ALARM_FALL_DOWN; + default: + return null; + } + } + + private void decodeStatus(Position position, int status) { + if (BitUtil.check(status, 1)) { + position.set(Position.KEY_IGNITION, BitUtil.check(status, 2)); + } + if (BitUtil.check(status, 3)) { + position.set(Position.KEY_ARMED, BitUtil.check(status, 4)); + } + if (BitUtil.check(status, 5)) { + position.set(Position.KEY_BLOCKED, !BitUtil.check(status, 6)); + } + if (BitUtil.check(status, 7)) { + position.set(Position.KEY_CHARGE, BitUtil.check(status, 8)); + } + position.set(Position.KEY_STATUS, status); + } + + private Position decodeOld(DeviceSession deviceSession, ByteBuf buf, int type, int index) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, index); + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + position.setLatitude(buf.readInt() / 1800000.0); + position.setLongitude(buf.readInt() / 1800000.0); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedShort()); + + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedMedium()))); + + position.setValid((buf.readUnsignedByte() & 0x01) != 0); + + if (type == MSG_GPS) { + + if (buf.readableBytes() >= 2) { + decodeStatus(position, buf.readUnsignedShort()); + } + + if (buf.readableBytes() >= 2 * 4) { + + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); + + position.set(Position.KEY_RSSI, buf.readUnsignedShort()); + + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + + } + + } else if (type == MSG_ALARM) { + + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + + } else if (type == MSG_STATE) { + + int statusType = buf.readUnsignedByte(); + + position.set(Position.KEY_EVENT, statusType); + + if (statusType == 0x01 || statusType == 0x02 || statusType == 0x03) { + buf.readUnsignedInt(); // device time + if (buf.readableBytes() >= 2) { + decodeStatus(position, buf.readUnsignedShort()); + } + } + + } + + return position; + } + + private Position decodeNew(DeviceSession deviceSession, ByteBuf buf, int type, int index) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, index); + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + + int flags = buf.readUnsignedByte(); + + if (BitUtil.check(flags, 0)) { + position.setLatitude(buf.readInt() / 1800000.0); + position.setLongitude(buf.readInt() / 1800000.0); + position.setAltitude(buf.readShort()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.setCourse(buf.readUnsignedShort()); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + } else { + getLastLocation(position, position.getDeviceTime()); + } + + if (BitUtil.check(flags, 1)) { + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedShort(), + buf.readUnsignedShort(), buf.readUnsignedInt(), buf.readUnsignedByte()))); + } + + if (BitUtil.check(flags, 2)) { + buf.skipBytes(7); // bsid1 + } + + if (BitUtil.check(flags, 3)) { + buf.skipBytes(7); // bsid2 + } + + if (BitUtil.check(flags, 4)) { + buf.skipBytes(7); // bss0 + } + + if (BitUtil.check(flags, 5)) { + buf.skipBytes(7); // bss1 + } + + if (BitUtil.check(flags, 6)) { + buf.skipBytes(7); // bss2 + } + + if (type == MSG_WARNING) { + + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + + } else if (type == MSG_REPORT) { + + buf.readUnsignedByte(); // report type + + } + + if (type == MSG_NORMAL || type == MSG_WARNING || type == MSG_REPORT) { + + int status = buf.readUnsignedShort(); + position.setValid(BitUtil.check(status, 0)); + if (BitUtil.check(status, 1)) { + position.set(Position.KEY_IGNITION, BitUtil.check(status, 2)); + } + position.set(Position.KEY_STATUS, status); + + } + + if (type == MSG_NORMAL) { + + if (buf.readableBytes() >= 2) { + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); + } + + if (buf.readableBytes() >= 4) { + position.set(Position.PREFIX_ADC + 0, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + } + + if (buf.readableBytes() >= 4) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + } + + if (buf.readableBytes() >= 4) { + buf.readUnsignedShort(); // gsm counter + buf.readUnsignedShort(); // gps counter + } + + if (buf.readableBytes() >= 4) { + position.set(Position.KEY_STEPS, buf.readUnsignedShort()); + buf.readUnsignedShort(); // walking time + } + + if (buf.readableBytes() >= 12) { + position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0); + position.set("humidity", buf.readUnsignedShort() * 0.1); + position.set("illuminance", buf.readUnsignedInt() / 256.0); + position.set("co2", buf.readUnsignedInt()); + } + + if (buf.readableBytes() >= 2) { + position.set(Position.PREFIX_TEMP + 2, buf.readShort() / 16.0); + } + + } + + return position; + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("Lat:") + .number("([NS])(d+.d+)") // latitude + .any() + .text("Lon:") + .number("([EW])(d+.d+)") // longitude + .any() + .text("Course:") + .number("(d+.d+)") // course + .any() + .text("Speed:") + .number("(d+.d+)") // speed + .any() + .expression("Date ?Time:") + .number("(dddd)-(dd)-(dd) ") // date + .number("(dd):(dd):(dd)") // time + .compile(); + + private Position decodeResult(DeviceSession deviceSession, ByteBuf buf, int index) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, index); + + buf.readUnsignedByte(); // type + buf.readUnsignedInt(); // uid + + String sentence = buf.toString(StandardCharsets.UTF_8); + + Parser parser = new Parser(PATTERN, sentence); + if (parser.matches()) { + + position.setValid(true); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setCourse(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setTime(parser.nextDateTime()); + + } else { + + getLastLocation(position, null); + + position.set(Position.KEY_RESULT, sentence); + + } + + return position; + } + + private Position decodeObd(DeviceSession deviceSession, ByteBuf buf, int index) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); + + while (buf.readableBytes() > 0) { + int pid = buf.readUnsignedByte(); + int value = buf.readInt(); + switch (pid) { + case 0x89: + position.set(Position.KEY_FUEL_CONSUMPTION, value); + break; + case 0x8a: + position.set(Position.KEY_ODOMETER, value * 1000L); + break; + case 0x8b: + position.set(Position.KEY_FUEL_LEVEL, value / 10); + break; + default: + break; + } + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + String uniqueId = null; + DeviceSession deviceSession; + + if (buf.getByte(0) == 'E' && buf.getByte(1) == 'L') { + buf.skipBytes(2 + 2 + 2); // udp header + uniqueId = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); + } else { + deviceSession = getDeviceSession(channel, remoteAddress); + } + + buf.skipBytes(2); // header + int type = buf.readUnsignedByte(); + buf.readShort(); // length + int index = buf.readUnsignedShort(); + + if (type != MSG_GPS && type != MSG_DATA) { + ByteBuf content = Unpooled.buffer(); + if (type == MSG_LOGIN) { + content.writeInt((int) (System.currentTimeMillis() / 1000)); + content.writeByte(1); // protocol version + content.writeByte(0); // action mask + } + ByteBuf response = EelinkProtocolEncoder.encodeContent( + channel instanceof DatagramChannel, uniqueId, type, index, content); + content.release(); + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + if (type == MSG_LOGIN) { + + if (deviceSession == null) { + getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(buf.readSlice(8)).substring(1)); + } + + } else { + + if (deviceSession == null) { + return null; + } + + if (type == MSG_GPS || type == MSG_ALARM || type == MSG_STATE || type == MSG_SMS) { + + return decodeOld(deviceSession, buf, type, index); + + } else if (type >= MSG_NORMAL && type <= MSG_OBD_CODE) { + + return decodeNew(deviceSession, buf, type, index); + + } else if (type == MSG_HEARTBEAT && buf.readableBytes() >= 2) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + decodeStatus(position, buf.readUnsignedShort()); + + return position; + + } else if (type == MSG_OBD) { + + return decodeObd(deviceSession, buf, index); + + } else if (type == MSG_DOWNLINK) { + + return decodeResult(deviceSession, buf, index); + + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/EelinkProtocolEncoder.java b/src/main/java/org/traccar/protocol/EelinkProtocolEncoder.java new file mode 100644 index 000000000..8f33441fb --- /dev/null +++ b/src/main/java/org/traccar/protocol/EelinkProtocolEncoder.java @@ -0,0 +1,107 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.DataConverter; +import org.traccar.model.Command; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +public class EelinkProtocolEncoder extends BaseProtocolEncoder { + + private boolean connectionless; + + public EelinkProtocolEncoder(boolean connectionless) { + this.connectionless = connectionless; + } + + public static int checksum(ByteBuffer buf) { + int sum = 0; + while (buf.hasRemaining()) { + sum = (((sum << 1) | (sum >> 15)) + (buf.get() & 0xFF)) & 0xFFFF; + } + return sum; + } + + public static ByteBuf encodeContent( + boolean connectionless, String uniqueId, int type, int index, ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + + if (connectionless) { + buf.writeBytes(DataConverter.parseHex('0' + uniqueId)); + } + + buf.writeByte(0x67); + buf.writeByte(0x67); + buf.writeByte(type); + buf.writeShort(2 + (content != null ? content.readableBytes() : 0)); // length + buf.writeShort(index); + + if (content != null) { + buf.writeBytes(content); + } + + ByteBuf result = Unpooled.buffer(); + + if (connectionless) { + result.writeByte('E'); + result.writeByte('L'); + result.writeShort(2 + buf.readableBytes()); // length + result.writeShort(checksum(buf.nioBuffer())); + } + + result.writeBytes(buf); + buf.release(); + + return result; + } + + private ByteBuf encodeContent(long deviceId, String content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte(0x01); // command + buf.writeInt(0); // server id + buf.writeBytes(content.getBytes(StandardCharsets.UTF_8)); + + return encodeContent(connectionless, getUniqueId(deviceId), EelinkProtocolDecoder.MSG_DOWNLINK, 0, buf); + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return encodeContent(command.getDeviceId(), command.getString(Command.KEY_DATA)); + case Command.TYPE_POSITION_SINGLE: + return encodeContent(command.getDeviceId(), "WHERE#"); + case Command.TYPE_ENGINE_STOP: + return encodeContent(command.getDeviceId(), "RELAY,1#"); + case Command.TYPE_ENGINE_RESUME: + return encodeContent(command.getDeviceId(), "RELAY,0#"); + case Command.TYPE_REBOOT_DEVICE: + return encodeContent(command.getDeviceId(), "RESET#"); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/EgtsFrameDecoder.java b/src/main/java/org/traccar/protocol/EgtsFrameDecoder.java new file mode 100644 index 000000000..84f1f11a7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EgtsFrameDecoder.java @@ -0,0 +1,45 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class EgtsFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + int headerLength = buf.getUnsignedByte(buf.readerIndex() + 3); + int frameLength = buf.getUnsignedShortLE(buf.readerIndex() + 5); + + int length = headerLength + frameLength + (frameLength > 0 ? 2 : 0); + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/EgtsProtocol.java b/src/main/java/org/traccar/protocol/EgtsProtocol.java new file mode 100644 index 000000000..5d4638f37 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EgtsProtocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class EgtsProtocol extends BaseProtocol { + + public EgtsProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new EgtsFrameDecoder()); + pipeline.addLast(new EgtsProtocolDecoder(EgtsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java b/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java new file mode 100644 index 000000000..b9fcb2f44 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java @@ -0,0 +1,265 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +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.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class EgtsProtocolDecoder extends BaseProtocolDecoder { + + public EgtsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int PT_RESPONSE = 0; + public static final int PT_APPDATA = 1; + public static final int PT_SIGNED_APPDATA = 2; + + public static final int SERVICE_AUTH = 1; + public static final int SERVICE_TELEDATA = 2; + public static final int SERVICE_COMMANDS = 4; + public static final int SERVICE_FIRMWARE = 9; + public static final int SERVICE_ECALL = 10; + + public static final int MSG_RECORD_RESPONSE = 0; + public static final int MSG_TERM_IDENTITY = 1; + public static final int MSG_MODULE_DATA = 2; + public static final int MSG_VEHICLE_DATA = 3; + public static final int MSG_AUTH_PARAMS = 4; + public static final int MSG_AUTH_INFO = 5; + public static final int MSG_SERVICE_INFO = 6; + public static final int MSG_RESULT_CODE = 7; + public static final int MSG_POS_DATA = 16; + public static final int MSG_EXT_POS_DATA = 17; + public static final int MSG_AD_SENSORS_DATA = 18; + public static final int MSG_COUNTERS_DATA = 19; + public static final int MSG_STATE_DATA = 20; + public static final int MSG_LOOPIN_DATA = 22; + public static final int MSG_ABS_DIG_SENS_DATA = 23; + public static final int MSG_ABS_AN_SENS_DATA = 24; + public static final int MSG_ABS_CNTR_DATA = 25; + public static final int MSG_ABS_LOOPIN_DATA = 26; + public static final int MSG_LIQUID_LEVEL_SENSOR = 27; + public static final int MSG_PASSENGERS_COUNTERS = 28; + + private int packetId; + + private void sendResponse( + Channel channel, int packetType, int index, int serviceType, int type, ByteBuf content) { + if (channel != null) { + + ByteBuf data = Unpooled.buffer(); + data.writeByte(type); + data.writeShortLE(content.readableBytes()); + data.writeBytes(content); + content.release(); + + ByteBuf record = Unpooled.buffer(); + if (packetType == PT_RESPONSE) { + record.writeShortLE(index); + record.writeByte(0); // success + } + record.writeShortLE(data.readableBytes()); + record.writeShortLE(0); + record.writeByte(0); // flags (possibly 1 << 6) + record.writeByte(serviceType); + record.writeByte(serviceType); + record.writeBytes(data); + data.release(); + int recordChecksum = Checksum.crc16(Checksum.CRC16_CCITT_FALSE, record.nioBuffer()); + + ByteBuf response = Unpooled.buffer(); + response.writeByte(1); // protocol version + response.writeByte(0); // security key id + response.writeByte(0); // flags + response.writeByte(5 + 2 + 2 + 2); // header length + response.writeByte(0); // encoding + response.writeShortLE(record.readableBytes()); + response.writeShortLE(packetId++); + response.writeByte(packetType); + response.writeByte(Checksum.crc8(Checksum.CRC8_EGTS, response.nioBuffer())); + response.writeBytes(record); + record.release(); + response.writeShortLE(recordChecksum); + + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int index = buf.getUnsignedShort(buf.readerIndex() + 5 + 2); + buf.skipBytes(buf.getUnsignedByte(buf.readerIndex() + 3)); + + List positions = new LinkedList<>(); + + while (buf.readableBytes() > 2) { + + int length = buf.readUnsignedShortLE(); + int recordIndex = buf.readUnsignedShortLE(); + int recordFlags = buf.readUnsignedByte(); + + if (BitUtil.check(recordFlags, 0)) { + buf.readUnsignedIntLE(); // object id + } + + if (BitUtil.check(recordFlags, 1)) { + buf.readUnsignedIntLE(); // event id + } + if (BitUtil.check(recordFlags, 2)) { + buf.readUnsignedIntLE(); // time + } + + int serviceType = buf.readUnsignedByte(); + buf.readUnsignedByte(); // recipient service type + + int recordEnd = buf.readerIndex() + length; + + Position position = new Position(getProtocolName()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession != null) { + position.setDeviceId(deviceSession.getDeviceId()); + } + + ByteBuf response = Unpooled.buffer(); + response.writeShortLE(recordIndex); + response.writeByte(0); // success + sendResponse(channel, PT_RESPONSE, index, serviceType, MSG_RECORD_RESPONSE, response); + + while (buf.readerIndex() < recordEnd) { + int type = buf.readUnsignedByte(); + int end = buf.readUnsignedShortLE() + buf.readerIndex(); + + if (type == MSG_TERM_IDENTITY) { + + buf.readUnsignedIntLE(); // object id + int flags = buf.readUnsignedByte(); + + if (BitUtil.check(flags, 0)) { + buf.readUnsignedShortLE(); // home dispatcher identifier + } + if (BitUtil.check(flags, 1)) { + getDeviceSession( + channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII).trim()); + } + if (BitUtil.check(flags, 2)) { + getDeviceSession( + channel, remoteAddress, buf.readSlice(16).toString(StandardCharsets.US_ASCII).trim()); + } + if (BitUtil.check(flags, 3)) { + buf.skipBytes(3); // language identifier + } + if (BitUtil.check(flags, 5)) { + buf.skipBytes(3); // network identifier + } + if (BitUtil.check(flags, 6)) { + buf.readUnsignedShortLE(); // buffer size + } + if (BitUtil.check(flags, 7)) { + getDeviceSession( + channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII).trim()); + } + + response = Unpooled.buffer(); + response.writeByte(0); // success + sendResponse(channel, PT_APPDATA, 0, serviceType, MSG_RESULT_CODE, response); + + } else if (type == MSG_POS_DATA) { + + position.setTime(new Date((buf.readUnsignedIntLE() + 1262304000) * 1000)); // since 2010-01-01 + position.setLatitude(buf.readUnsignedIntLE() * 90.0 / 0xFFFFFFFFL); + position.setLongitude(buf.readUnsignedIntLE() * 180.0 / 0xFFFFFFFFL); + + int flags = buf.readUnsignedByte(); + position.setValid(BitUtil.check(flags, 0)); + if (BitUtil.check(flags, 5)) { + position.setLatitude(-position.getLatitude()); + } + if (BitUtil.check(flags, 6)) { + position.setLongitude(-position.getLongitude()); + } + + int speed = buf.readUnsignedShortLE(); + position.setSpeed(UnitsConverter.knotsFromKph(BitUtil.to(speed, 14) * 0.1)); + position.setCourse(buf.readUnsignedByte() + (BitUtil.check(speed, 15) ? 0x100 : 0)); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedMediumLE() * 100); + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + if (BitUtil.check(flags, 7)) { + position.setAltitude(buf.readMediumLE()); + } + + } else if (type == MSG_EXT_POS_DATA) { + + int flags = buf.readUnsignedByte(); + + if (BitUtil.check(flags, 0)) { + position.set(Position.KEY_VDOP, buf.readUnsignedShortLE()); + } + if (BitUtil.check(flags, 1)) { + position.set(Position.KEY_HDOP, buf.readUnsignedShortLE()); + } + if (BitUtil.check(flags, 2)) { + position.set(Position.KEY_PDOP, buf.readUnsignedShortLE()); + } + if (BitUtil.check(flags, 3)) { + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + } + + } else if (type == MSG_AD_SENSORS_DATA) { + + buf.readUnsignedByte(); // inputs flags + + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + + buf.readUnsignedByte(); // adc flags + + } + + buf.readerIndex(end); + } + + if (serviceType == SERVICE_TELEDATA && deviceSession != null) { + positions.add(position); + } + } + + return positions.isEmpty() ? null : positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/EnforaProtocol.java b/src/main/java/org/traccar/protocol/EnforaProtocol.java new file mode 100644 index 000000000..f78e4b377 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EnforaProtocol.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015 - 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class EnforaProtocol extends BaseProtocol { + + public EnforaProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, -2, 2)); + pipeline.addLast(new EnforaProtocolEncoder()); + pipeline.addLast(new EnforaProtocolDecoder(EnforaProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new EnforaProtocolEncoder()); + pipeline.addLast(new EnforaProtocolDecoder(EnforaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java b/src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java new file mode 100644 index 000000000..bfa7a116b --- /dev/null +++ b/src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java @@ -0,0 +1,115 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BufferUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class EnforaProtocolDecoder extends BaseProtocolDecoder { + + public EnforaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("GPRMC,") + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+)?,") // speed + .number("(d+.d+)?,") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .any() + .compile(); + + public static final int IMEI_LENGTH = 15; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + // Find IMEI number + int index = -1; + for (int i = buf.readerIndex(); i < buf.writerIndex() - IMEI_LENGTH; i++) { + index = i; + for (int j = i; j < i + IMEI_LENGTH; j++) { + if (!Character.isDigit((char) buf.getByte(j))) { + index = -1; + break; + } + } + if (index > 0) { + break; + } + } + if (index == -1) { + return null; + } + + String imei = buf.toString(index, IMEI_LENGTH, StandardCharsets.US_ASCII); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + // Find NMEA sentence + int start = BufferUtil.indexOf("GPRMC", buf); + if (start == -1) { + return null; + } + + String sentence = buf.toString(start, buf.readableBytes() - start, StandardCharsets.US_ASCII); + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/EnforaProtocolEncoder.java b/src/main/java/org/traccar/protocol/EnforaProtocolEncoder.java new file mode 100644 index 000000000..a46e6367d --- /dev/null +++ b/src/main/java/org/traccar/protocol/EnforaProtocolEncoder.java @@ -0,0 +1,55 @@ +/* + * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Jose Castellanos + * + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class EnforaProtocolEncoder extends StringProtocolEncoder { + + private ByteBuf encodeContent(String content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeShort(content.length() + 6); + buf.writeShort(0); // index + buf.writeByte(0x04); // command type + buf.writeByte(0); // optional header + buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return encodeContent(command.getString(Command.KEY_DATA)); + case Command.TYPE_ENGINE_STOP: + return encodeContent("AT$IOGP3=1"); + case Command.TYPE_ENGINE_RESUME: + return encodeContent("AT$IOGP3=0"); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/EsealProtocol.java b/src/main/java/org/traccar/protocol/EsealProtocol.java new file mode 100644 index 000000000..7a27c617d --- /dev/null +++ b/src/main/java/org/traccar/protocol/EsealProtocol.java @@ -0,0 +1,45 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class EsealProtocol extends BaseProtocol { + + public EsealProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new EsealProtocolEncoder()); + pipeline.addLast(new EsealProtocolDecoder(EsealProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/EsealProtocolDecoder.java b/src/main/java/org/traccar/protocol/EsealProtocolDecoder.java new file mode 100644 index 000000000..7a1fd7022 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EsealProtocolDecoder.java @@ -0,0 +1,158 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class EsealProtocolDecoder extends BaseProtocolDecoder { + + private String config; + + public EsealProtocolDecoder(Protocol protocol) { + super(protocol); + config = Context.getConfig().getString(getProtocolName() + ".config"); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("##S,") + .expression("[^,]+,") // device type + .number("(d+),") // device id + .number("d+,") // customer id + .expression("[^,]+,") // firmware version + .expression("([^,]+),") // type + .number("(d+),") // index + .number("(dddd)-(dd)-(dd),") // date + .number("(dd):(dd):(dd),") // time + .number("d+,") // interval + .expression("([AV]),") // validity + .number("(d+.d+)([NS]) ") // latitude + .number("(d+.d+)([EW]),") // longitude + .number("(d+),") // course + .number("(d+),") // speed + .expression("([^,]+),") // door + .number("(d+.d+),") // acceleration + .expression("([^,]+),") // nfc + .number("(d+.d+),") // battery + .number("(-?d+),") // rssi + .text("E##") + .compile(); + + private void sendResponse(Channel channel, String prefix, String type, String payload) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + prefix + type + "," + payload + ",E##\r\n", channel.remoteAddress())); + } + } + + private String decodeAlarm(String type) { + switch (type) { + case "Event-Door": + return Position.ALARM_DOOR; + case "Event-Shock": + return Position.ALARM_SHOCK; + case "Event-Drop": + return Position.ALARM_FALL_DOWN; + case "Event-Lock": + return Position.ALARM_LOCK; + case "Event-RC-Unlock": + return Position.ALARM_UNLOCK; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + String type = parser.next(); + String prefix = sentence.substring(0, sentence.indexOf(type)); + int index = parser.nextInt(); + + position.set(Position.KEY_INDEX, index); + position.set(Position.KEY_ALARM, decodeAlarm(type)); + + switch (type) { + case "Startup": + sendResponse(channel, prefix, type + " ACK", index + "," + config); + break; + case "Normal": + case "Button-Normal": + case "Termination": + case "Event-Door": + case "Event-Shock": + case "Event-Drop": + case "Event-Lock": + case "Event-RC-Unlock": + sendResponse(channel, prefix, type + " ACK", String.valueOf(index)); + break; + default: + break; + } + + position.setTime(parser.nextDateTime()); + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setCourse(parser.nextInt()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + + switch (parser.next()) { + case "Open": + position.set(Position.KEY_DOOR, true); + break; + case "Close": + position.set(Position.KEY_DOOR, false); + break; + default: + break; + } + + position.set(Position.KEY_ACCELERATION, parser.nextDouble()); + position.set("nfc", parser.next()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_RSSI, parser.nextInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java b/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java new file mode 100644 index 000000000..b9bcc5b0a --- /dev/null +++ b/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java @@ -0,0 +1,41 @@ +/* + * Copyright 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class EsealProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatCommand( + command, "##S,eSeal,{%s},256,3.0.8,{%s},E##", Command.KEY_UNIQUE_ID, Command.KEY_DATA); + case Command.TYPE_ALARM_ARM: + return formatCommand( + command, "##S,eSeal,{%s},256,3.0.8,RC-Power Control,Power OFF,E##", Command.KEY_UNIQUE_ID); + case Command.TYPE_ALARM_DISARM: + return formatCommand( + command, "##S,eSeal,{%s},256,3.0.8,RC-Unlock,E##", Command.KEY_UNIQUE_ID); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/EskyFrameDecoder.java b/src/main/java/org/traccar/protocol/EskyFrameDecoder.java new file mode 100644 index 000000000..da24c1273 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EskyFrameDecoder.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class EskyFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + buf.readerIndex(buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 'E')); + + int endIndex = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 'E'); + if (endIndex > 0) { + return buf.readRetainedSlice(endIndex - buf.readerIndex()); + } else { + return buf.readRetainedSlice(buf.readableBytes()); // assume full frame + } + } + +} diff --git a/src/main/java/org/traccar/protocol/EskyProtocol.java b/src/main/java/org/traccar/protocol/EskyProtocol.java new file mode 100644 index 000000000..aaa92da58 --- /dev/null +++ b/src/main/java/org/traccar/protocol/EskyProtocol.java @@ -0,0 +1,38 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class EskyProtocol extends BaseProtocol { + + public EskyProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new EskyFrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new EskyProtocolDecoder(EskyProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java new file mode 100644 index 000000000..641b2e28f --- /dev/null +++ b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java @@ -0,0 +1,94 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class EskyProtocolDecoder extends BaseProtocolDecoder { + + public EskyProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("..;") // header + .number("d+;") // index + .number("(d+);") // imei + .text("R;") // data type + .number("(d+)[+;]") // satellites + .number("(dd)(dd)(dd)") // date + .number("(dd)(dd)(dd)[+;]") // time + .number("(-?d+.d+)[+;]") // latitude + .number("(-?d+.d+)[+;]") // longitude + .number("(d+.d+)[+;]") // speed + .number("(d+)[+;]") // course + .groupBegin() + .text("0x").number("(d+)[+;]") // input + .number("(d+)[+;]") // message type + .number("(d+)[+;]") // odometer + .groupEnd("?") + .number("(d+)") // voltage + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + position.setValid(true); + position.setTime(parser.nextDateTime()); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromMps(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + + if (parser.hasNext(3)) { + position.set(Position.KEY_INPUT, parser.nextHexInt()); + position.set(Position.KEY_EVENT, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextInt()); + } + + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ExtremTracProtocol.java b/src/main/java/org/traccar/protocol/ExtremTracProtocol.java new file mode 100644 index 000000000..692fd4e99 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ExtremTracProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ExtremTracProtocol extends BaseProtocol { + + public ExtremTracProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new ExtremTracProtocolDecoder(ExtremTracProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java b/src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java new file mode 100644 index 000000000..9fde6f0a0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java @@ -0,0 +1,83 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class ExtremTracProtocolDecoder extends BaseProtocolDecoder { + + public ExtremTracProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$GPRMC,") + .number("(d+),") // device id + .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocol.java b/src/main/java/org/traccar/protocol/FifotrackProtocol.java new file mode 100644 index 000000000..371e01e55 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FifotrackProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class FifotrackProtocol extends BaseProtocol { + + public FifotrackProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new FifotrackProtocolDecoder(FifotrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java new file mode 100644 index 000000000..beaa34125 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java @@ -0,0 +1,198 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.DataConverter; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class FifotrackProtocolDecoder extends BaseProtocolDecoder { + + private ByteBuf photo; + + public FifotrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$$") + .number("d+,") // length + .number("(d+),") // imei + .number("x+,") // index + .expression("[^,]+,") // type + .number("(d+)?,") // alarm + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("([AV]),") // validity + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(-?d+),") // altitude + .number("(d+),") // odometer + .number("d+,") // runtime + .number("(xxxx),") // status + .number("(x+)?,") // input + .number("(x+)?,") // output + .number("(d+)|") // mcc + .number("(d+)|") // mnc + .number("(x+)|") // lac + .number("(x+),") // cid + .number("([x|]+)") // adc + .expression(",([^,]+)") // rfid + .expression(",([^*]+)").optional(2) // sensors + .any() + .compile(); + + private static final Pattern PATTERN_PHOTO = new PatternBuilder() + .text("$$") + .number("d+,") // length + .number("(d+),") // imei + .any() + .number(",(d+),") // length + .expression("([^*]+)") // photo id + .text("*") + .number("xx") + .compile(); + + private static final Pattern PATTERN_PHOTO_DATA = new PatternBuilder() + .text("$$") + .number("d+,") // length + .number("(d+),") // imei + .expression("([^*]+),") // photo id + .number("(d+),") // offset + .number("(d+),") // size + .number("(x+)") // data + .text("*") + .number("xx") + .compile(); + + private void requestPhoto(Channel channel, SocketAddress socketAddress, String imei, String file) { + if (channel != null) { + String content = "D06," + file + "," + photo.writerIndex() + "," + Math.min(1024, photo.writableBytes()); + int length = 1 + imei.length() + 1 + content.length() + 5; + String response = String.format("@@%02d,%s,%s*", length, imei, content); + response += Checksum.sum(response) + "\r\n"; + channel.writeAndFlush(new NetworkMessage(response, socketAddress)); + } + } + + private Object decodeLocation( + Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_ALARM, parser.next()); + + position.setTime(parser.nextDateTime()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); + position.setCourse(parser.nextInt(0)); + position.setAltitude(parser.nextInt(0)); + + position.set(Position.KEY_ODOMETER, parser.nextLong(0)); + position.set(Position.KEY_STATUS, parser.nextHexInt(0)); + if (parser.hasNext()) { + position.set(Position.KEY_INPUT, parser.nextHexInt(0)); + } + if (parser.hasNext()) { + position.set(Position.KEY_OUTPUT, parser.nextHexInt(0)); + } + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); + + String[] adc = parser.next().split("\\|"); + for (int i = 0; i < adc.length; i++) { + position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(adc[i], 16)); + } + + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + if (parser.hasNext()) { + String[] sensors = parser.next().split("\\|"); + for (int i = 0; i < sensors.length; i++) { + position.set(Position.PREFIX_IO + (i + 1), sensors[i]); + } + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + int typeIndex = sentence.indexOf(',', sentence.indexOf(',', sentence.indexOf(',') + 1) + 1) + 1; + String type = sentence.substring(typeIndex, typeIndex + 3); + + if (type.equals("D05")) { + Parser parser = new Parser(PATTERN_PHOTO, sentence); + if (parser.matches()) { + String imei = parser.next(); + int length = parser.nextInt(); + String photoId = parser.next(); + photo = Unpooled.buffer(length); + requestPhoto(channel, remoteAddress, imei, photoId); + } + } else if (type.equals("D06")) { + Parser parser = new Parser(PATTERN_PHOTO_DATA, sentence); + if (parser.matches()) { + String imei = parser.next(); + String photoId = parser.next(); + parser.nextInt(); // offset + parser.nextInt(); // size + photo.writeBytes(DataConverter.parseHex(parser.next())); + requestPhoto(channel, remoteAddress, imei, photoId); + } + } else { + return decodeLocation(channel, remoteAddress, sentence); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/FlespiProtocol.java b/src/main/java/org/traccar/protocol/FlespiProtocol.java new file mode 100644 index 000000000..2c0729b76 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FlespiProtocol.java @@ -0,0 +1,38 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class FlespiProtocol extends BaseProtocol { + + public FlespiProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE)); + pipeline.addLast(new FlespiProtocolDecoder(FlespiProtocol.this)); + } + }); + } +} diff --git a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java new file mode 100644 index 000000000..86da3943e --- /dev/null +++ b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java @@ -0,0 +1,246 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.model.Position; + +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonNumber; +import javax.json.JsonObject; +import javax.json.JsonString; +import javax.json.JsonValue; +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder { + + public FlespiProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + JsonArray result = Json.createReader(new StringReader(request.content().toString(StandardCharsets.UTF_8))) + .readArray(); + List positions = new LinkedList<>(); + for (int i = 0; i < result.size(); i++) { + JsonObject message = result.getJsonObject(i); + JsonString ident = message.getJsonString("ident"); + if (ident == null) { + continue; + } + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ident.getString()); + if (deviceSession == null) { + continue; + } + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + decodePosition(message, position); + positions.add(position); + } + + sendResponse(channel, HttpResponseStatus.OK); + return positions; + } + + private void decodePosition(JsonObject object, Position position) { + for (Map.Entry param : object.entrySet()) { + String paramName = param.getKey(); + JsonValue paramValue = param.getValue(); + int index = -1; + if (paramName.contains("#")) { + String[] parts = paramName.split("#"); + paramName = parts[0]; + index = Integer.parseInt(parts[1]); + } + if (!decodeParam(paramName, index, paramValue, position)) { + decodeUnknownParam(param.getKey(), param.getValue(), position); + } + } + if (position.getLatitude() == 0 && position.getLongitude() == 0) { + getLastLocation(position, position.getDeviceTime()); + } + } + + private boolean decodeParam(String name, int index, JsonValue value, Position position) { + switch (name) { + case "timestamp": + position.setTime(new Date(((JsonNumber) value).longValue() * 1000)); + return true; + case "position.latitude": + position.setLatitude(((JsonNumber) value).doubleValue()); + return true; + case "position.longitude": + position.setLongitude(((JsonNumber) value).doubleValue()); + return true; + case "position.speed": + position.setSpeed(((JsonNumber) value).doubleValue()); + return true; + case "position.direction": + position.setCourse(((JsonNumber) value).doubleValue()); + return true; + case "position.altitude": + position.setAltitude(((JsonNumber) value).doubleValue()); + return true; + case "position.satellites": + position.set(Position.KEY_SATELLITES, ((JsonNumber) value).intValue()); + return true; + case "position.valid": + position.setValid(value == JsonValue.TRUE); + return true; + case "position.hdop": + position.set(Position.KEY_HDOP, ((JsonNumber) value).doubleValue()); + return true; + case "position.pdop": + position.set(Position.KEY_PDOP, ((JsonNumber) value).doubleValue()); + return true; + case "din": + case "dout": + position.set(name.equals("din") ? Position.KEY_INPUT : Position.KEY_OUTPUT, + ((JsonNumber) value).intValue()); + return true; + case "gps.vehicle.mileage": + position.set(Position.KEY_ODOMETER, ((JsonNumber) value).doubleValue()); + return true; + case "external.powersource.voltage": + position.set(Position.KEY_POWER, ((JsonNumber) value).doubleValue()); + return true; + case "battery.voltage": + position.set(Position.KEY_BATTERY, ((JsonNumber) value).doubleValue()); + return true; + case "fuel.level": + case "can.fuel.level": + position.set(Position.KEY_FUEL_LEVEL, ((JsonNumber) value).doubleValue()); + return true; + case "engine.rpm": + case "can.engine.rpm": + position.set(Position.KEY_RPM, ((JsonNumber) value).doubleValue()); + return true; + case "can.engine.temperature": + position.set(Position.PREFIX_TEMP + (index > 0 ? index : 0), ((JsonNumber) value).doubleValue()); + return true; + case "engine.ignition.status": + position.set(Position.KEY_IGNITION, value == JsonValue.TRUE); + return true; + case "movement.status": + position.set(Position.KEY_MOTION, value == JsonValue.TRUE); + return true; + case "device.temperature": + position.set(Position.KEY_DEVICE_TEMP, ((JsonNumber) value).doubleValue()); + return true; + case "ibutton.code": + position.set(Position.KEY_DRIVER_UNIQUE_ID, ((JsonString) value).getString()); + return true; + case "vehicle.vin": + position.set(Position.KEY_VIN, ((JsonString) value).getString()); + return true; + case "alarm.event.trigger": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + return true; + case "towing.event.trigger": + case "towing.alarm.status": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + } + return true; + case "geofence.event.enter": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER); + } + return true; + case "geofence.event.exit": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT); + } + return true; + case "shock.event.trigger": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_SHOCK); + } + return true; + case "overspeeding.event.trigger": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } + return true; + case "harsh.acceleration.event.trigger": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + } + return true; + case "harsh.braking.event.trigger": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + } + return true; + case "harsh.cornering.event.trigger": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + } + return true; + case "gnss.antenna.cut.status": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); + } + return true; + case "gsm.jamming.event.trigger": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); + } + return true; + case "hood.open.status": + if (value == JsonValue.TRUE) { + position.set(Position.KEY_ALARM, Position.ALARM_BONNET); + } + return true; + default: + return false; + } + } + + private void decodeUnknownParam(String name, JsonValue value, Position position) { + if (value instanceof JsonNumber) { + if (((JsonNumber) value).isIntegral()) { + position.set(name, ((JsonNumber) value).longValue()); + } else { + position.set(name, ((JsonNumber) value).doubleValue()); + } + position.set(name, ((JsonNumber) value).doubleValue()); + } else if (value instanceof JsonString) { + position.set(name, ((JsonString) value).getString()); + } else if (value == JsonValue.TRUE || value == JsonValue.FALSE) { + position.set(name, value == JsonValue.TRUE); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/FlexCommProtocol.java b/src/main/java/org/traccar/protocol/FlexCommProtocol.java new file mode 100644 index 000000000..9343ebeb8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FlexCommProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.FixedLengthFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class FlexCommProtocol extends BaseProtocol { + + public FlexCommProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new FixedLengthFrameDecoder(2 + 2 + 101 + 5)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new FlexCommProtocolDecoder(FlexCommProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java new file mode 100644 index 000000000..068c0a05c --- /dev/null +++ b/src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java @@ -0,0 +1,128 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class FlexCommProtocolDecoder extends BaseProtocolDecoder { + + public FlexCommProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("7E") + .number("(dd)") // status + .number("(d{15})") // imei + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .expression("([01])") // valid + .number("(d{9})") // latitude + .number("(d{10})") // longitude + .number("(d{4})") // altitude + .number("(ddd)") // speed + .number("(ddd)") // course + .number("(dd)") // satellites view + .number("(dd)") // satellites used + .number("(dd)") // rssi + .number("(ddd)") // mcc + .number("(ddd)") // mnc + .number("(x{6})") // lac + .number("(x{6})") // cid + .expression("([01])([01])([01])") // input + .expression("([01])([01])") // output + .number("(ddd)") // fuel + .number("(d{4})") // temperature + .number("(ddd)") // battery + .number("(ddd)") // power + .any() + .compile(); + + private static double parseSignedValue(Parser parser, int decimalPoints) { + String stringValue = parser.next(); + boolean negative = stringValue.charAt(0) == '1'; + double value = Integer.parseInt(stringValue.substring(1)) * Math.pow(10, -decimalPoints); + return negative ? -value : value; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_STATUS, parser.nextInt()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + position.setValid(parser.next().equals("1")); + position.setLatitude(parseSignedValue(parser, 6)); + position.setLongitude(parseSignedValue(parser, 6)); + position.setAltitude(parseSignedValue(parser, 0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextInt()); + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt()))); + + for (int i = 1; i <= 3; i++) { + position.set(Position.PREFIX_IN + i, parser.nextInt()); + } + + for (int i = 1; i <= 2; i++) { + position.set(Position.PREFIX_OUT + i, parser.nextInt()); + } + + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parseSignedValue(parser, 0)); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_POWER, parser.nextInt() * 0.1); + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("{01}", remoteAddress)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/FlextrackProtocol.java b/src/main/java/org/traccar/protocol/FlextrackProtocol.java new file mode 100644 index 000000000..ddd1d58f0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FlextrackProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class FlextrackProtocol extends BaseProtocol { + + public FlextrackProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r")); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new FlextrackProtocolDecoder(FlextrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java new file mode 100644 index 000000000..9dce22ede --- /dev/null +++ b/src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java @@ -0,0 +1,144 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class FlextrackProtocolDecoder extends BaseProtocolDecoder { + + public FlextrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_LOGON = new PatternBuilder() + .number("(-?d+),") // index + .text("LOGON,") + .number("(d+),") // node id + .number("(d+)") // iccid + .compile(); + + private static final Pattern PATTERN = new PatternBuilder() + .number("(-?d+),") // index + .text("UNITSTAT,") + .number("(dddd)(dd)(dd),") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("d+,") // node id + .number("([NS])(d+).(d+.d+),") // latitude + .number("([EW])(d+).(d+.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+),") // satellites + .number("(d+),") // battery + .number("(-?d+),") // gsm + .number("(x+),") // state + .number("(ddd)") // mcc + .number("(dd),") // mnc + .number("(-?d+),") // altitude + .number("(d+),") // hdop + .number("(x+),") // cell + .number("d+,") // gps fix time + .number("(x+),") // lac + .number("(d+)") // odometer + .compile(); + + private void sendAcknowledgement(Channel channel, SocketAddress remoteAddress, String index) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(index + ",ACK\r", remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.contains("LOGON")) { + + Parser parser = new Parser(PATTERN_LOGON, sentence); + if (!parser.matches()) { + return null; + } + + sendAcknowledgement(channel, remoteAddress, parser.next()); + + String id = parser.next(); + String iccid = parser.next(); + + getDeviceSession(channel, remoteAddress, iccid, id); + + } else if (sentence.contains("UNITSTAT")) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + sendAcknowledgement(channel, remoteAddress, parser.next()); + + position.setTime(parser.nextDateTime()); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); + position.setCourse(parser.nextInt(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_BATTERY, parser.nextInt(0)); + int rssi = parser.nextInt(0); + position.set(Position.KEY_STATUS, parser.nextHexInt(0)); + + int mcc = parser.nextInt(0); + int mnc = parser.nextInt(0); + + position.setAltitude(parser.nextInt(0)); + + position.set(Position.KEY_HDOP, parser.nextInt(0) * 0.1); + + position.setNetwork(new Network(CellTower.from( + mcc, mnc, parser.nextHexInt(0), parser.nextHexInt(0), rssi))); + + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/FoxProtocol.java b/src/main/java/org/traccar/protocol/FoxProtocol.java new file mode 100644 index 000000000..9bac773b5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FoxProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class FoxProtocol extends BaseProtocol { + + public FoxProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new FoxProtocolDecoder(FoxProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/FoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/FoxProtocolDecoder.java new file mode 100644 index 000000000..449f00022 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FoxProtocolDecoder.java @@ -0,0 +1,124 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class FoxProtocolDecoder extends BaseProtocolDecoder { + + public FoxProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+),") // status id + .expression("([AV]),") // validity + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .expression("[^,]*,") // cell info + .number("([01]+) ") // input + .number("(d+) ") // power + .number("(d+) ") // temperature + .number("(d+) ") // rpm + .number("(d+) ") // fuel + .number("(d+) ") // adc 1 + .number("(d+) ") // adc 2 + .number("([01]+) ") // output + .number("(d+),") // odometer + .expression("(.+)") // status info + .compile(); + + private String getAttribute(String xml, String key) { + int start = xml.indexOf(key + "=\""); + if (start != -1) { + start += key.length() + 2; + int end = xml.indexOf("\"", start); + if (end != -1) { + return xml.substring(start, end); + } + } + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String xml = (String) msg; + String id = getAttribute(xml, "id"); + String data = getAttribute(xml, "data"); + + if (id != null && data != null) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, data); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_STATUS, parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_INPUT, parser.nextBinInt(0)); + position.set(Position.KEY_POWER, parser.nextDouble(0) * 0.1); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); + position.set(Position.KEY_RPM, parser.nextInt(0)); + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); + position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); + position.set(Position.PREFIX_ADC + 2, parser.nextInt(0)); + position.set(Position.KEY_OUTPUT, parser.nextBinInt(0)); + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + + position.set("statusData", parser.next()); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/FreedomProtocol.java b/src/main/java/org/traccar/protocol/FreedomProtocol.java new file mode 100644 index 000000000..bc6b92d5f --- /dev/null +++ b/src/main/java/org/traccar/protocol/FreedomProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class FreedomProtocol extends BaseProtocol { + + public FreedomProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new FreedomProtocolDecoder(FreedomProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java b/src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java new file mode 100644 index 000000000..1d2dd3133 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class FreedomProtocolDecoder extends BaseProtocolDecoder { + + public FreedomProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("IMEI,") + .number("(d+),") // imei + .number("(dddd)/(dd)/(dd), ") // date (yyyy/dd/mm) + .number("(dd):(dd):(dd), ") // time (hh:mm:ss) + .expression("([NS]), ") + .number("Lat:(dd)(d+.d+), ") // latitude + .expression("([EW]), ") + .number("Lon:(ddd)(d+.d+), ") // longitude + .text("Spd:").number("(d+.d+)") // speed + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + + position.setSpeed(parser.nextDouble(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocol.java b/src/main/java/org/traccar/protocol/FreematicsProtocol.java new file mode 100644 index 000000000..999b075a1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FreematicsProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class FreematicsProtocol extends BaseProtocol { + + public FreematicsProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new FreematicsProtocolDecoder(FreematicsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java new file mode 100644 index 000000000..ba47699c3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java @@ -0,0 +1,184 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class FreematicsProtocolDecoder extends BaseProtocolDecoder { + + public FreematicsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private Object decodeEvent( + Channel channel, SocketAddress remoteAddress, String sentence) { + + DeviceSession deviceSession = null; + String event = null; + String time = null; + + for (String pair : sentence.split(",")) { + String[] data = pair.split("="); + String key = data[0]; + String value = data[1]; + switch (key) { + case "ID": + case "VIN": + if (deviceSession == null) { + deviceSession = getDeviceSession(channel, remoteAddress, value); + } + break; + case "EV": + event = value; + break; + case "TS": + time = value; + break; + default: + break; + } + } + + if (channel != null && deviceSession != null && event != null && time != null) { + String message = String.format("1#EV=%s,RX=1,TS=%s", event, time); + message += '*' + Checksum.sum(message); + channel.writeAndFlush(new NetworkMessage(message, remoteAddress)); + } + + return null; + } + + private Object decodePosition( + Channel channel, SocketAddress remoteAddress, String sentence) throws Exception { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + Position position = null; + DateBuilder dateBuilder = null; + + for (String pair : sentence.split(",")) { + String[] data = pair.split("[=:]"); + int key = Integer.parseInt(data[0], 16); + String value = data[1]; + switch (key) { + case 0x0: + if (position != null) { + position.setTime(dateBuilder.getDate()); + positions.add(position); + } + position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.setValid(true); + dateBuilder = new DateBuilder(new Date()); + break; + case 0x11: + value = ("000000" + value).substring(value.length()); + dateBuilder.setDateReverse( + Integer.parseInt(value.substring(0, 2)), + Integer.parseInt(value.substring(2, 4)), + Integer.parseInt(value.substring(4))); + break; + case 0x10: + value = ("00000000" + value).substring(value.length()); + dateBuilder.setTime( + Integer.parseInt(value.substring(0, 2)), + Integer.parseInt(value.substring(2, 4)), + Integer.parseInt(value.substring(4, 6)), + Integer.parseInt(value.substring(6)) * 10); + break; + case 0xA: + position.setLatitude(Double.parseDouble(value)); + break; + case 0xB: + position.setLongitude(Double.parseDouble(value)); + break; + case 0xC: + position.setAltitude(Double.parseDouble(value)); + break; + case 0xD: + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(value))); + break; + case 0xE: + position.setCourse(Integer.parseInt(value)); + break; + case 0xF: + position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); + break; + case 0x20: + position.set(Position.KEY_ACCELERATION, value); + break; + case 0x24: + position.set(Position.KEY_BATTERY, Integer.parseInt(value) * 0.01); + break; + case 0x81: + position.set(Position.KEY_RSSI, Integer.parseInt(value)); + break; + case 0x82: + position.set(Position.KEY_DEVICE_TEMP, Integer.parseInt(value) * 0.1); + break; + default: + position.set(data[0], value); + break; + } + } + + if (position != null) { + position.setTime(dateBuilder.getDate()); + positions.add(position); + } + + return positions; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + int startIndex = sentence.indexOf('#'); + int endIndex = sentence.indexOf('*'); + + if (startIndex > 0 && endIndex > 0) { + sentence = sentence.substring(startIndex + 1, endIndex); + + if (sentence.startsWith("EV")) { + return decodeEvent(channel, remoteAddress, sentence); + } else { + return decodePosition(channel, remoteAddress, sentence); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java b/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java new file mode 100644 index 000000000..c23d26c83 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java @@ -0,0 +1,43 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class GalileoFrameDecoder extends BaseFrameDecoder { + + private static final int MESSAGE_MINIMUM_LENGTH = 5; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { + return null; + } + + int length = buf.getUnsignedShortLE(buf.readerIndex() + 1) & 0x7fff; + if (buf.readableBytes() >= (length + MESSAGE_MINIMUM_LENGTH)) { + return buf.readRetainedSlice(length + MESSAGE_MINIMUM_LENGTH); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/GalileoProtocol.java b/src/main/java/org/traccar/protocol/GalileoProtocol.java new file mode 100644 index 000000000..9b7fe1a4b --- /dev/null +++ b/src/main/java/org/traccar/protocol/GalileoProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class GalileoProtocol extends BaseProtocol { + + public GalileoProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_OUTPUT_CONTROL); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new GalileoFrameDecoder()); + pipeline.addLast(new GalileoProtocolEncoder()); + pipeline.addLast(new GalileoProtocolDecoder(GalileoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java b/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java new file mode 100644 index 000000000..01c55a9ae --- /dev/null +++ b/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java @@ -0,0 +1,342 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.UnitsConverter; +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.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class GalileoProtocolDecoder extends BaseProtocolDecoder { + + public GalileoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private ByteBuf photo; + + private static final Map TAG_LENGTH_MAP = new HashMap<>(); + + static { + int[] l1 = { + 0x01, 0x02, 0x35, 0x43, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd5, 0x88, 0x8a, 0x8b, 0x8c, + 0xa0, 0xaf, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, + 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae + }; + int[] l2 = { + 0x04, 0x10, 0x34, 0x40, 0x41, 0x42, 0x45, 0x46, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60, 0x61, + 0x62, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, + 0x77, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xd6, 0xd7, 0xd8, 0xd9, 0xda + }; + int[] l3 = { + 0x63, 0x64, 0x6f, 0x5d, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e + }; + int[] l4 = { + 0x20, 0x33, 0x44, 0x90, 0xc0, 0xc2, 0xc3, 0xd3, + 0xd4, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xf0, 0xf9, + 0x5a, 0x47, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xe2, 0xe9 + }; + for (int i : l1) { + TAG_LENGTH_MAP.put(i, 1); + } + for (int i : l2) { + TAG_LENGTH_MAP.put(i, 2); + } + for (int i : l3) { + TAG_LENGTH_MAP.put(i, 3); + } + for (int i : l4) { + TAG_LENGTH_MAP.put(i, 4); + } + TAG_LENGTH_MAP.put(0x5b, 7); // variable length + TAG_LENGTH_MAP.put(0x5c, 68); + } + + private static int getTagLength(int tag) { + Integer length = TAG_LENGTH_MAP.get(tag); + if (length == null) { + throw new IllegalArgumentException("Unknown tag: " + tag); + } + return length; + } + + private void sendReply(Channel channel, int header, int checksum) { + if (channel != null) { + ByteBuf reply = Unpooled.buffer(3); + reply.writeByte(header); + reply.writeShortLE((short) checksum); + channel.writeAndFlush(new NetworkMessage(reply, channel.remoteAddress())); + } + } + + private void decodeTag(Position position, ByteBuf buf, int tag) { + if (tag >= 0x50 && tag <= 0x57) { + position.set(Position.PREFIX_ADC + (tag - 0x50), buf.readUnsignedShortLE()); + } else if (tag >= 0x60 && tag <= 0x62) { + position.set("fuel" + (tag - 0x60), buf.readUnsignedShortLE()); + } else if (tag >= 0xa0 && tag <= 0xaf) { + position.set("can8BitR" + (tag - 0xa0 + 15), buf.readUnsignedByte()); + } else if (tag >= 0xb0 && tag <= 0xb9) { + position.set("can16BitR" + (tag - 0xb0 + 5), buf.readUnsignedShortLE()); + } else if (tag >= 0xc4 && tag <= 0xd2) { + position.set("can8BitR" + (tag - 0xc4), buf.readUnsignedByte()); + } else if (tag >= 0xd6 && tag <= 0xda) { + position.set("can16BitR" + (tag - 0xd6), buf.readUnsignedShortLE()); + } else if (tag >= 0xdb && tag <= 0xdf) { + position.set("can32BitR" + (tag - 0xdb), buf.readUnsignedIntLE()); + } else if (tag >= 0xe2 && tag <= 0xe9) { + position.set("userData" + (tag - 0xe2), buf.readUnsignedIntLE()); + } else if (tag >= 0xf0 && tag <= 0xf9) { + position.set("can32BitR" + (tag - 0xf0 + 5), buf.readUnsignedIntLE()); + } else { + decodeTagOther(position, buf, tag); + } + } + + private void decodeTagOther(Position position, ByteBuf buf, int tag) { + switch (tag) { + case 0x01: + position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte()); + break; + case 0x02: + position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); + break; + case 0x04: + position.set("deviceId", buf.readUnsignedShortLE()); + break; + case 0x10: + position.set(Position.KEY_INDEX, buf.readUnsignedShortLE()); + break; + case 0x20: + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + break; + case 0x33: + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE() * 0.1)); + position.setCourse(buf.readUnsignedShortLE() * 0.1); + break; + case 0x34: + position.setAltitude(buf.readShortLE()); + break; + case 0x35: + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + break; + case 0x40: + position.set(Position.KEY_STATUS, buf.readUnsignedShortLE()); + break; + case 0x41: + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() / 1000.0); + break; + case 0x42: + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() / 1000.0); + break; + case 0x43: + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + break; + case 0x44: + position.set(Position.KEY_ACCELERATION, buf.readUnsignedIntLE()); + break; + case 0x45: + position.set(Position.KEY_OUTPUT, buf.readUnsignedShortLE()); + break; + case 0x46: + position.set(Position.KEY_INPUT, buf.readUnsignedShortLE()); + break; + case 0x48: + position.set("statusExtended", buf.readUnsignedShortLE()); + break; + case 0x58: + position.set("rs2320", buf.readUnsignedShortLE()); + break; + case 0x59: + position.set("rs2321", buf.readUnsignedShortLE()); + break; + case 0x90: + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedIntLE())); + break; + case 0xc0: + position.set("fuelTotal", buf.readUnsignedIntLE() * 0.5); + break; + case 0xc1: + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); + position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte() - 40); + position.set(Position.KEY_RPM, buf.readUnsignedShortLE() * 0.125); + break; + case 0xc2: + position.set("canB0", buf.readUnsignedIntLE()); + break; + case 0xc3: + position.set("canB1", buf.readUnsignedIntLE()); + break; + case 0xd4: + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + break; + case 0xe0: + position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); + break; + case 0xe1: + position.set(Position.KEY_RESULT, + buf.readSlice(buf.readUnsignedByte()).toString(StandardCharsets.US_ASCII)); + break; + case 0xea: + position.set("userDataArray", ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte()))); + position.set("userDataArray", ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte()))); + break; + default: + buf.skipBytes(getTagLength(tag)); + break; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int header = buf.readUnsignedByte(); + if (header == 0x01) { + return decodePositions(channel, remoteAddress, buf); + } else if (header == 0x07) { + return decodePhoto(channel, remoteAddress, buf); + } + + return null; + } + + private Object decodePositions( + Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { + + int length = (buf.readUnsignedShortLE() & 0x7fff) + 3; + + List positions = new LinkedList<>(); + Set tags = new HashSet<>(); + boolean hasLocation = false; + + DeviceSession deviceSession = null; + Position position = new Position(getProtocolName()); + + while (buf.readerIndex() < length) { + + int tag = buf.readUnsignedByte(); + if (tags.contains(tag)) { + if (hasLocation && position.getFixTime() != null) { + positions.add(position); + } + tags.clear(); + hasLocation = false; + position = new Position(getProtocolName()); // new position starts + } + tags.add(tag); + + if (tag == 0x03) { + deviceSession = getDeviceSession( + channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII)); + } else if (tag == 0x30) { + hasLocation = true; + position.setValid((buf.readUnsignedByte() & 0xf0) == 0x00); + position.setLatitude(buf.readIntLE() / 1000000.0); + position.setLongitude(buf.readIntLE() / 1000000.0); + } else { + decodeTag(position, buf, tag); + } + + } + + if (deviceSession == null) { + deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + } + + if (hasLocation && position.getFixTime() != null) { + positions.add(position); + } else if (position.getAttributes().containsKey(Position.KEY_RESULT)) { + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, null); + positions.add(position); + } + + sendReply(channel, 0x02, buf.readUnsignedShortLE()); + + for (Position p : positions) { + p.setDeviceId(deviceSession.getDeviceId()); + } + + return positions.isEmpty() ? null : positions; + } + + private Object decodePhoto( + Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { + + int length = buf.readUnsignedShortLE(); + + Position position = null; + + if (length > 1) { + + if (photo == null) { + photo = Unpooled.buffer(); + } + + buf.readUnsignedByte(); // part number + photo.writeBytes(buf, length - 1); + + } else { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId(); + + position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg")); + photo.release(); + photo = null; + + } + + sendReply(channel, 0x07, buf.readUnsignedShortLE()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/GalileoProtocolEncoder.java b/src/main/java/org/traccar/protocol/GalileoProtocolEncoder.java new file mode 100644 index 000000000..3b2145e74 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GalileoProtocolEncoder.java @@ -0,0 +1,67 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class GalileoProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeText(String uniqueId, String text) { + + ByteBuf buf = Unpooled.buffer(256); + + buf.writeByte(0x01); + buf.writeShortLE(uniqueId.length() + text.length() + 11); + + buf.writeByte(0x03); // imei tag + buf.writeBytes(uniqueId.getBytes(StandardCharsets.US_ASCII)); + + buf.writeByte(0x04); // device id tag + buf.writeShortLE(0); // not needed if imei provided + + buf.writeByte(0xE0); // index tag + buf.writeIntLE(0); // index + + buf.writeByte(0xE1); // command text tag + buf.writeByte(text.length()); + buf.writeBytes(text.getBytes(StandardCharsets.US_ASCII)); + + buf.writeShortLE(Checksum.crc16(Checksum.CRC16_MODBUS, buf.nioBuffer(0, buf.writerIndex()))); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return encodeText(getUniqueId(command.getDeviceId()), command.getString(Command.KEY_DATA)); + case Command.TYPE_OUTPUT_CONTROL: + return encodeText(getUniqueId(command.getDeviceId()), + "Out " + command.getInteger(Command.KEY_INDEX) + "," + command.getString(Command.KEY_DATA)); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java new file mode 100644 index 000000000..ca81caefb --- /dev/null +++ b/src/main/java/org/traccar/protocol/GatorProtocol.java @@ -0,0 +1,41 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GatorProtocol extends BaseProtocol { + + public GatorProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2)); + pipeline.addLast(new GatorProtocolDecoder(GatorProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new GatorProtocolDecoder(GatorProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java new file mode 100644 index 000000000..31500bae6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java @@ -0,0 +1,133 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class GatorProtocolDecoder extends BaseProtocolDecoder { + + public GatorProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_HEARTBEAT = 0x21; + public static final int MSG_POSITION_DATA = 0x80; + public static final int MSG_ROLLCALL_RESPONSE = 0x81; + public static final int MSG_ALARM_DATA = 0x82; + public static final int MSG_TERMINAL_STATUS = 0x83; + public static final int MSG_MESSAGE = 0x84; + public static final int MSG_TERMINAL_ANSWER = 0x85; + public static final int MSG_BLIND_AREA = 0x8E; + public static final int MSG_PICTURE_FRAME = 0x54; + public static final int MSG_CAMERA_RESPONSE = 0x56; + public static final int MSG_PICTURE_DATA = 0x57; + + public static String decodeId(int b1, int b2, int b3, int b4) { + + int d1 = 30 + ((b1 >> 7) << 3) + ((b2 >> 7) << 2) + ((b3 >> 7) << 1) + (b4 >> 7); + int d2 = b1 & 0x7f; + int d3 = b2 & 0x7f; + int d4 = b3 & 0x7f; + int d5 = b4 & 0x7f; + + return String.format("%02d%02d%02d%02d%02d", d1, d2, d3, d4, d5); + } + + private void sendResponse(Channel channel, SocketAddress remoteAddress, byte calibration) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x24); response.writeByte(0x24); // header + response.writeByte(MSG_HEARTBEAT); // size + response.writeShort(5); + response.writeByte(calibration); + response.writeByte(0); // main order + response.writeByte(0); // slave order + response.writeByte(1); // calibration + response.writeByte(0x0D); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + int type = buf.readUnsignedByte(); + buf.readUnsignedShort(); // length + + String id = decodeId( + buf.readUnsignedByte(), buf.readUnsignedByte(), + buf.readUnsignedByte(), buf.readUnsignedByte()); + + sendResponse(channel, remoteAddress, buf.getByte(buf.writerIndex() - 2)); + + if (type == MSG_POSITION_DATA || type == MSG_ROLLCALL_RESPONSE + || type == MSG_ALARM_DATA || type == MSG_BLIND_AREA) { + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, "1" + id, id); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setYear(BcdUtil.readInteger(buf, 2)) + .setMonth(BcdUtil.readInteger(buf, 2)) + .setDay(BcdUtil.readInteger(buf, 2)) + .setHour(BcdUtil.readInteger(buf, 2)) + .setMinute(BcdUtil.readInteger(buf, 2)) + .setSecond(BcdUtil.readInteger(buf, 2)); + position.setTime(dateBuilder.getDate()); + + position.setLatitude(BcdUtil.readCoordinate(buf)); + position.setLongitude(BcdUtil.readCoordinate(buf)); + position.setSpeed(UnitsConverter.knotsFromKph(BcdUtil.readInteger(buf, 4))); + position.setCourse(BcdUtil.readInteger(buf, 4)); + + int flags = buf.readUnsignedByte(); + position.setValid((flags & 0x80) != 0); + position.set(Position.KEY_SATELLITES, flags & 0x0f); + + position.set(Position.KEY_STATUS, buf.readUnsignedByte()); + position.set("key", buf.readUnsignedByte()); + position.set("oil", buf.readUnsignedShort() / 10.0); + position.set(Position.KEY_POWER, buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/GenxProtocol.java b/src/main/java/org/traccar/protocol/GenxProtocol.java new file mode 100644 index 000000000..c87ba946a --- /dev/null +++ b/src/main/java/org/traccar/protocol/GenxProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GenxProtocol extends BaseProtocol { + + public GenxProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new GenxProtocolDecoder(GenxProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GenxProtocolDecoder.java b/src/main/java/org/traccar/protocol/GenxProtocolDecoder.java new file mode 100644 index 000000000..2ae9de7a0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GenxProtocolDecoder.java @@ -0,0 +1,99 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.text.SimpleDateFormat; + +public class GenxProtocolDecoder extends BaseProtocolDecoder { + + private int[] reportColumns; + + public GenxProtocolDecoder(Protocol protocol) { + super(protocol); + setReportColumns(Context.getConfig().getString(getProtocolName() + ".reportColumns", "1,2,3,4")); + } + + public void setReportColumns(String format) { + String[] columns = format.split(","); + reportColumns = new int[columns.length]; + for (int i = 0; i < columns.length; i++) { + reportColumns[i] = Integer.parseInt(columns[i]); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String[] values = ((String) msg).split(","); + + Position position = new Position(getProtocolName()); + position.setValid(true); + + for (int i = 0; i < Math.min(values.length, reportColumns.length); i++) { + switch (reportColumns[i]) { + case 1: + case 28: + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[i]); + if (deviceSession != null) { + position.setDeviceId(deviceSession.getDeviceId()); + } + break; + case 2: + position.setTime(new SimpleDateFormat("MM/dd/yy HH:mm:ss").parse(values[i])); + break; + case 3: + position.setLatitude(Double.parseDouble(values[i])); + break; + case 4: + position.setLongitude(Double.parseDouble(values[i])); + break; + case 11: + position.set(Position.KEY_IGNITION, values[i].equals("ON")); + break; + case 13: + position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(values[i]))); + break; + case 17: + position.setCourse(Integer.parseInt(values[i])); + break; + case 23: + position.set(Position.KEY_ODOMETER, Double.parseDouble(values[i]) * 1000); + break; + case 27: + position.setAltitude(UnitsConverter.metersFromFeet(Integer.parseInt(values[i]))); + break; + case 46: + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[i])); + break; + default: + break; + } + } + + return position.getDeviceId() != 0 ? position : null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gl100Protocol.java b/src/main/java/org/traccar/protocol/Gl100Protocol.java new file mode 100644 index 000000000..063e606db --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gl100Protocol.java @@ -0,0 +1,47 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Gl100Protocol extends BaseProtocol { + + public Gl100Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\0')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Gl100ProtocolDecoder(Gl100Protocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Gl100ProtocolDecoder(Gl100Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java new file mode 100644 index 000000000..ae0383e5c --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java @@ -0,0 +1,97 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Gl100ProtocolDecoder extends BaseProtocolDecoder { + + public Gl100ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("+RESP:") + .expression("GT...,") + .number("(d{15}),") // imei + .groupBegin() + .number("d+,") // number + .number("d,") // reserved / geofence id + .number("d+") // reserved / geofence alert // battery + .or() + .number("[^,]*") // calling number + .groupEnd(",") + .expression("([01]),") // gps fix + .number("(d+.d),") // speed + .number("(d+),") // course + .number("(-?d+.d),") // altitude + .number("d*,") // gps accuracy + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.contains("AT+GTHBD=") && channel != null) { + String response = "+RESP:GTHBD,GPRS ACTIVE,"; + response += sentence.substring(9, sentence.lastIndexOf(',')); + response += '\0'; + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); // heartbeat response + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.nextInt(0) == 0); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setLatitude(parser.nextDouble(0)); + + position.setTime(parser.nextDateTime()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java new file mode 100644 index 000000000..c3339bea5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java @@ -0,0 +1,403 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitBuffer; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class Gl200BinaryProtocolDecoder extends BaseProtocolDecoder { + + public Gl200BinaryProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private Date decodeTime(ByteBuf buf) { + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedShort(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + return dateBuilder.getDate(); + } + + public static final int MSG_RSP_LCB = 3; + public static final int MSG_RSP_GEO = 8; + public static final int MSG_RSP_COMPRESSED = 100; + + private List decodeLocation(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + List positions = new LinkedList<>(); + + int type = buf.readUnsignedByte(); + + buf.readUnsignedInt(); // mask + buf.readUnsignedShort(); // length + buf.readUnsignedByte(); // device type + buf.readUnsignedShort(); // protocol version + buf.readUnsignedShort(); // firmware version + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.format("%015d", buf.readLong())); + if (deviceSession == null) { + return null; + } + + int battery = buf.readUnsignedByte(); + int power = buf.readUnsignedShort(); + + if (type == MSG_RSP_GEO) { + buf.readUnsignedByte(); // reserved + buf.readUnsignedByte(); // reserved + } + + buf.readUnsignedByte(); // motion status + int satellites = buf.readUnsignedByte(); + + if (type != MSG_RSP_COMPRESSED) { + buf.readUnsignedByte(); // index + } + + if (type == MSG_RSP_LCB) { + buf.readUnsignedByte(); // phone length + for (int b = buf.readUnsignedByte();; b = buf.readUnsignedByte()) { + if ((b & 0xf) == 0xf || (b & 0xf0) == 0xf0) { + break; + } + } + } + + if (type == MSG_RSP_COMPRESSED) { + + int count = buf.readUnsignedShort(); + + BitBuffer bits; + int speed = 0; + int heading = 0; + int latitude = 0; + int longitude = 0; + long time = 0; + + for (int i = 0; i < count; i++) { + + if (time > 0) { + time += 1; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + switch (BitUtil.from(buf.getUnsignedByte(buf.readerIndex()), 8 - 2)) { + case 1: + bits = new BitBuffer(buf.readSlice(3)); + bits.readUnsigned(2); // point attribute + bits.readUnsigned(1); // fix type + speed = bits.readUnsigned(12); + heading = bits.readUnsigned(9); + longitude = buf.readInt(); + latitude = buf.readInt(); + if (time == 0) { + time = buf.readUnsignedInt(); + } + break; + case 2: + bits = new BitBuffer(buf.readSlice(5)); + bits.readUnsigned(2); // point attribute + bits.readUnsigned(1); // fix type + speed += bits.readSigned(7); + heading += bits.readSigned(7); + longitude += bits.readSigned(12); + latitude += bits.readSigned(11); + break; + default: + buf.readUnsignedByte(); // invalid or same + continue; + } + + position.setValid(true); + position.setTime(new Date(time * 1000)); + position.setSpeed(UnitsConverter.knotsFromKph(speed * 0.1)); + position.setCourse(heading); + position.setLongitude(longitude * 0.000001); + position.setLatitude(latitude * 0.000001); + + positions.add(position); + + } + + } else { + + int count = buf.readUnsignedByte(); + + for (int i = 0; i < count; i++) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_BATTERY_LEVEL, battery); + position.set(Position.KEY_POWER, power); + position.set(Position.KEY_SATELLITES, satellites); + + int hdop = buf.readUnsignedByte(); + position.setValid(hdop > 0); + position.set(Position.KEY_HDOP, hdop); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedMedium() * 0.1)); + position.setCourse(buf.readUnsignedShort()); + position.setAltitude(buf.readShort()); + position.setLongitude(buf.readInt() * 0.000001); + position.setLatitude(buf.readInt() * 0.000001); + + position.setTime(decodeTime(buf)); + + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedShort(), + buf.readUnsignedShort(), buf.readUnsignedShort()))); + + buf.readUnsignedByte(); // reserved + + positions.add(position); + + } + + } + + return positions; + } + + public static final int MSG_EVT_BPL = 6; + public static final int MSG_EVT_VGN = 45; + public static final int MSG_EVT_VGF = 46; + public static final int MSG_EVT_UPD = 15; + public static final int MSG_EVT_IDF = 17; + public static final int MSG_EVT_GSS = 21; + public static final int MSG_EVT_GES = 26; + public static final int MSG_EVT_GPJ = 31; + public static final int MSG_EVT_RMD = 35; + public static final int MSG_EVT_JDS = 33; + public static final int MSG_EVT_CRA = 23; + public static final int MSG_EVT_UPC = 34; + + private Position decodeEvent(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + Position position = new Position(getProtocolName()); + + int type = buf.readUnsignedByte(); + + buf.readUnsignedInt(); // mask + buf.readUnsignedShort(); // length + buf.readUnsignedByte(); // device type + buf.readUnsignedShort(); // protocol version + + position.set(Position.KEY_VERSION_FW, String.valueOf(buf.readUnsignedShort())); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.format("%015d", buf.readLong())); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set(Position.KEY_POWER, buf.readUnsignedShort()); + + buf.readUnsignedByte(); // motion status + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + switch (type) { + case MSG_EVT_BPL: + buf.readUnsignedShort(); // backup battery voltage + break; + case MSG_EVT_VGN: + case MSG_EVT_VGF: + buf.readUnsignedShort(); // reserved + buf.readUnsignedByte(); // report type + buf.readUnsignedInt(); // ignition duration + break; + case MSG_EVT_UPD: + buf.readUnsignedShort(); // code + buf.readUnsignedByte(); // retry + break; + case MSG_EVT_IDF: + buf.readUnsignedInt(); // idling duration + break; + case MSG_EVT_GSS: + buf.readUnsignedByte(); // gps signal status + buf.readUnsignedInt(); // reserved + break; + case MSG_EVT_GES: + buf.readUnsignedShort(); // trigger geo id + buf.readUnsignedByte(); // trigger geo enable + buf.readUnsignedByte(); // trigger mode + buf.readUnsignedInt(); // radius + buf.readUnsignedInt(); // check interval + break; + case MSG_EVT_GPJ: + buf.readUnsignedByte(); // cw jamming value + buf.readUnsignedByte(); // gps jamming state + break; + case MSG_EVT_RMD: + buf.readUnsignedByte(); // roaming state + break; + case MSG_EVT_JDS: + buf.readUnsignedByte(); // jamming state + break; + case MSG_EVT_CRA: + buf.readUnsignedByte(); // crash counter + break; + case MSG_EVT_UPC: + buf.readUnsignedByte(); // command id + buf.readUnsignedShort(); // result + break; + default: + break; + } + + buf.readUnsignedByte(); // count + + int hdop = buf.readUnsignedByte(); + position.setValid(hdop > 0); + position.set(Position.KEY_HDOP, hdop); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedMedium() * 0.1)); + position.setCourse(buf.readUnsignedShort()); + position.setAltitude(buf.readShort()); + position.setLongitude(buf.readInt() * 0.000001); + position.setLatitude(buf.readInt() * 0.000001); + + position.setTime(decodeTime(buf)); + + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedShort(), + buf.readUnsignedShort(), buf.readUnsignedShort()))); + + buf.readUnsignedByte(); // reserved + + return position; + } + + public static final int MSG_INF_GPS = 2; + public static final int MSG_INF_CID = 4; + public static final int MSG_INF_CSQ = 5; + public static final int MSG_INF_VER = 6; + public static final int MSG_INF_BAT = 7; + public static final int MSG_INF_TMZ = 9; + public static final int MSG_INF_GIR = 10; + + private Position decodeInformation(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + Position position = new Position(getProtocolName()); + + int type = buf.readUnsignedByte(); + + buf.readUnsignedInt(); // mask + buf.readUnsignedShort(); // length + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.format("%015d", buf.readLong())); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedByte(); // device type + buf.readUnsignedShort(); // protocol version + + position.set(Position.KEY_VERSION_FW, String.valueOf(buf.readUnsignedShort())); + + if (type == MSG_INF_VER) { + buf.readUnsignedShort(); // hardware version + buf.readUnsignedShort(); // mcu version + buf.readUnsignedShort(); // reserved + } + + buf.readUnsignedByte(); // motion status + buf.readUnsignedByte(); // reserved + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + buf.readUnsignedByte(); // mode + buf.skipBytes(7); // last fix time + buf.readUnsignedByte(); // reserved + buf.readUnsignedByte(); + buf.readUnsignedShort(); // response report mask + buf.readUnsignedShort(); // ign interval + buf.readUnsignedShort(); // igf interval + buf.readUnsignedInt(); // reserved + buf.readUnsignedByte(); // reserved + + if (type == MSG_INF_BAT) { + position.set(Position.KEY_CHARGE, buf.readUnsignedByte() != 0); + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + } + + buf.skipBytes(10); // iccid + + if (type == MSG_INF_CSQ) { + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + buf.readUnsignedByte(); + } + + buf.readUnsignedByte(); // time zone flags + buf.readUnsignedShort(); // time zone offset + + if (type == MSG_INF_GIR) { + buf.readUnsignedByte(); // gir trigger + buf.readUnsignedByte(); // cell number + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedShort(), + buf.readUnsignedShort(), buf.readUnsignedShort()))); + buf.readUnsignedByte(); // ta + buf.readUnsignedByte(); // rx level + } + + getLastLocation(position, decodeTime(buf)); + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + switch (buf.readSlice(4).toString(StandardCharsets.US_ASCII)) { + case "+RSP": + return decodeLocation(channel, remoteAddress, buf); + case "+INF": + return decodeInformation(channel, remoteAddress, buf); + case "+EVT": + return decodeEvent(channel, remoteAddress, buf); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Gl200FrameDecoder.java b/src/main/java/org/traccar/protocol/Gl200FrameDecoder.java new file mode 100644 index 000000000..c192cc28d --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gl200FrameDecoder.java @@ -0,0 +1,97 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseFrameDecoder; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class Gl200FrameDecoder extends BaseFrameDecoder { + + private static final int MINIMUM_LENGTH = 11; + + private static final Set BINARY_HEADERS = new HashSet<>( + Arrays.asList("+RSP", "+BSP", "+EVT", "+BVT", "+INF", "+BNF", "+HBD", "+CRD", "+BRD")); + + public static boolean isBinary(ByteBuf buf) { + String header = buf.toString(buf.readerIndex(), 4, StandardCharsets.US_ASCII); + if (header.equals("+ACK")) { + return buf.getByte(buf.readerIndex() + header.length()) != (byte) ':'; + } else { + return BINARY_HEADERS.contains(header); + } + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < MINIMUM_LENGTH) { + return null; + } + + if (isBinary(buf)) { + + int length; + switch (buf.toString(buf.readerIndex(), 4, StandardCharsets.US_ASCII)) { + case "+ACK": + length = buf.getUnsignedByte(buf.readerIndex() + 6); + break; + case "+INF": + case "+BNF": + length = buf.getUnsignedShort(buf.readerIndex() + 7); + break; + case "+HBD": + length = buf.getUnsignedByte(buf.readerIndex() + 5); + break; + case "+CRD": + case "+BRD": + length = buf.getUnsignedShort(buf.readerIndex() + 6); + break; + default: + length = buf.getUnsignedShort(buf.readerIndex() + 9); + break; + } + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + } else { + + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '$'); + if (endIndex < 0) { + endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0); + } + if (endIndex > 0) { + ByteBuf frame = buf.readRetainedSlice(endIndex - buf.readerIndex()); + buf.readByte(); // delimiter + return frame; + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gl200Protocol.java b/src/main/java/org/traccar/protocol/Gl200Protocol.java new file mode 100644 index 000000000..c5343dae0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gl200Protocol.java @@ -0,0 +1,53 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +import io.netty.handler.codec.string.StringEncoder; + +public class Gl200Protocol extends BaseProtocol { + + public Gl200Protocol() { + setSupportedDataCommands( + Command.TYPE_POSITION_SINGLE, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_IDENTIFICATION, + Command.TYPE_REBOOT_DEVICE); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Gl200FrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Gl200ProtocolEncoder()); + pipeline.addLast(new Gl200ProtocolDecoder(Gl200Protocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Gl200ProtocolEncoder()); + pipeline.addLast(new Gl200ProtocolDecoder(Gl200Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java new file mode 100644 index 000000000..ca1df7a13 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseProtocolDecoder; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.Protocol; + +import java.net.SocketAddress; + +public class Gl200ProtocolDecoder extends BaseProtocolDecoder { + + private final Gl200TextProtocolDecoder textProtocolDecoder; + private final Gl200BinaryProtocolDecoder binaryProtocolDecoder; + + public Gl200ProtocolDecoder(Protocol protocol) { + super(protocol); + textProtocolDecoder = new Gl200TextProtocolDecoder(protocol); + binaryProtocolDecoder = new Gl200BinaryProtocolDecoder(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (Gl200FrameDecoder.isBinary(buf)) { + return binaryProtocolDecoder.decode(channel, remoteAddress, msg); + } else { + return textProtocolDecoder.decode(channel, remoteAddress, msg); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java new file mode 100644 index 000000000..285106c67 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2016 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class Gl200ProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + initDevicePassword(command, ""); + + switch (command.getType()) { + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, "AT+GTRTO={%s},1,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, "AT+GTOUT={%s},1,,,0,0,0,0,0,0,0,,,,,,,FFFF$", + Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, "AT+GTOUT={%s},0,,,0,0,0,0,0,0,0,,,,,,,FFFF$", + Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_IDENTIFICATION: + return formatCommand(command, "AT+GTRTO={%s},8,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_REBOOT_DEVICE: + return formatCommand(command, "AT+GTRTO={%s},3,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java new file mode 100644 index 000000000..aeb57a116 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -0,0 +1,1266 @@ +/* + * 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. + * 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 org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { + + private boolean ignoreFixTime; + + public Gl200TextProtocolDecoder(Protocol protocol) { + super(protocol); + + ignoreFixTime = Context.getConfig().getBoolean(getProtocolName() + ".ignoreFixTime"); + } + + private static final Pattern PATTERN_ACK = new PatternBuilder() + .text("+ACK:GT") + .expression("...,") // type + .number("([0-9A-Z]{2}xxxx),") // protocol version + .number("(d{15}|x{14}),") // imei + .any().text(",") + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(xxxx)") // counter + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_INF = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTINF,") + .number("[0-9A-Z]{2}xxxx,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:[0-9A-Z]{17},)?") // vin + .expression("(?:[^,]+)?,") // device name + .number("(xx),") // state + .expression("(?:[0-9Ff]{20})?,") // iccid + .number("(d{1,2}),") // rssi + .number("d{1,2},") + .expression("[01],") // external power + .number("([d.]+)?,") // odometer or external power + .number("d*,") // backup battery or lightness + .number("(d+.d+),") // battery + .expression("([01]),") // charging + .number("(?:d),") // led + .number("(?:d)?,") // gps on need + .number("(?:d)?,") // gps antenna type + .number("(?:d)?,").optional() // gps antenna state + .number("d{14},") // last fix time + .groupBegin() + .number("(d+),") // battery percentage + .number("[d.]*,") // flash type / power + .number("(-?[d.]+)?,,,") // temperature + .or() + .expression("(?:[01])?,").optional() // pin15 mode + .number("(d+)?,") // adc1 + .number("(d+)?,").optional() // adc2 + .number("(xx)?,") // digital input + .number("(xx)?,") // digital output + .number("[-+]dddd,") // timezone + .expression("[01],") // daylight saving + .groupEnd() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(xxxx)") // counter + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_VER = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTVER,") + .number("[0-9A-Z]{2}xxxx,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .expression("([^,]*),") // device type + .number("(xxxx),") // firmware version + .number("(xxxx),") // hardware version + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(xxxx)") // counter + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_LOCATION = new PatternBuilder() + .number("(d{1,2})?,") // hdop + .number("(d{1,3}.d)?,") // speed + .number("(d{1,3})?,") // course + .number("(-?d{1,5}.d)?,") // altitude + .number("(-?d{1,3}.d{6})?,") // longitude + .number("(-?d{1,2}.d{6})?,") // latitude + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(d+)?,") // mcc + .number("(d+)?,") // mnc + .groupBegin() + .number("(d+),") // lac + .number("(d+),") // cid + .or() + .number("(x+)?,") // lac + .number("(x+)?,") // cid + .groupEnd() + .number("(?:d+|(d+.d))?,") // odometer + .compile(); + + private static final Pattern PATTERN_OBD = new PatternBuilder() + .text("+RESP:GTOBD,") + .number("[0-9A-Z]{2}xxxx,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:[0-9A-Z]{17})?,") // vin + .expression("[^,]{0,20},") // device name + .expression("[01],") // report type + .number("x{1,8},") // report mask + .expression("(?:[0-9A-Z]{17})?,") // vin + .number("[01],") // obd connect + .number("(?:d{1,5})?,") // obd voltage + .number("(?:x{8})?,") // support pids + .number("(d{1,5})?,") // engine rpm + .number("(d{1,3})?,") // speed + .number("(-?d{1,3})?,") // coolant temp + .number("(d+.?d*|Inf|NaN)?,") // fuel consumption + .number("(d{1,5})?,") // dtcs cleared distance + .number("(?:d{1,5})?,") + .expression("([01])?,") // obd connect + .number("(d{1,3})?,") // number of dtcs + .number("(x*),") // dtcs + .number("(d{1,3})?,") // throttle + .number("(?:d{1,3})?,") // engine load + .number("(d{1,3})?,") // fuel level + .expression("(?:[0-9A],)?") // obd protocol + .number("(d+),") // odometer + .expression(PATTERN_LOCATION.pattern()) + .number("(d{1,7}.d)?,") // odometer + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_FRI = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GT...,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:([0-9A-Z]{17}),)?") // vin + .expression("[^,]*,") // device name + .number("(d+)?,") // power + .number("d{1,2},").optional() // report type + .number("d{1,2},").optional() // count + .number(",").optional() // reserved + .number("(d+),").optional() // battery + .expression("((?:") + .expression(PATTERN_LOCATION.pattern()) + .expression(")+)") + .groupBegin() + .number("(d{1,7}.d)?,") // odometer + .number("(d{5}:dd:dd)?,") // hour meter + .number("(x+)?,") // adc 1 + .number("(x+)?,") // adc 2 + .number("(d{1,3})?,") // battery + .number("(?:(xx)(xx)(xx))?,") // device status + .number("(d+)?,") // rpm + .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption + .number("(d+)?,") // fuel level + .or() + .number("(d{1,7}.d)?,").optional() // odometer + .number("(d{1,3})?,") // battery + .groupEnd() + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_ERI = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTERI,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(x{8}),") // mask + .number("(d+)?,") // power + .number("d{1,2},") // report type + .number("d{1,2},") // count + .expression("((?:") + .expression(PATTERN_LOCATION.pattern()) + .expression(")+)") + .number("(d{1,7}.d)?,") // odometer + .number("(d{5}:dd:dd)?,") // hour meter + .number("(x+)?,") // adc 1 + .number("(x+)?,").optional() // adc 2 + .number("(d{1,3})?,") // battery + .number("(?:(xx)(xx)(xx))?,") // device status + .expression("(.*)") // additional data + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_IGN = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GTIG[NF],") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d+,") // ignition off duration + .expression(PATTERN_LOCATION.pattern()) + .number("(d{5}:dd:dd)?,") // hour meter + .number("(d{1,7}.d)?,") // odometer + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_LSW = new PatternBuilder() + .text("+RESP:").expression("GT[LT]SW,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("[01],") // type + .number("([01]),") // state + .expression(PATTERN_LOCATION.pattern()) + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_IDA = new PatternBuilder() + .text("+RESP:GTIDA,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,,") // device name + .number("([^,]+),") // rfid + .expression("[01],") // report type + .number("1,") // count + .expression(PATTERN_LOCATION.pattern()) + .number("(d+.d),") // odometer + .text(",,,,") + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_WIF = new PatternBuilder() + .text("+RESP:GTWIF,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(d+),") // count + .number("((?:x{12},-?d+,,,,)+),,,,") // wifi + .number("(d{1,3}),") // battery + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_GSM = new PatternBuilder() + .text("+RESP:GTGSM,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("(?:STR|CTN|NMR|RTL),") // fix type + .expression("(.*)") // cells + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_PNA = new PatternBuilder() + .text("+RESP:GT").expression("P[NF]A,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF):GT...,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .number("(d{15}|x{14}),") // imei + .expression("[^,]*,") // device name + .number("d*,") + .number("(x{1,2}),") // report type + .number("d{1,2},") // count + .expression(PATTERN_LOCATION.pattern()) + .groupBegin() + .number("(d{1,7}.d)?,").optional() // odometer + .number("(d{1,3})?,") // battery + .or() + .number("(d{1,7}.d)?,") // odometer + .groupEnd() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private static final Pattern PATTERN_BASIC = new PatternBuilder() + .text("+").expression("(?:RESP|BUFF)").text(":") + .expression("GT...,") + .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version + .number("(d{15}|x{14}),") // imei + .any() + .number("(d{1,2})?,") // hdop + .number("(d{1,3}.d)?,") // speed + .number("(d{1,3})?,") // course + .number("(-?d{1,5}.d)?,") // altitude + .number("(-?d{1,3}.d{6})?,") // longitude + .number("(-?d{1,2}.d{6})?,") // latitude + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(x+),") // lac + .number("(x+),").optional(4) // cell + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) + .text(",") + .number("(xxxx)") // count number + .text("$").optional() + .compile(); + + private Object decodeAck(Channel channel, SocketAddress remoteAddress, String sentence, String type) { + Parser parser = new Parser(PATTERN_ACK, sentence); + if (parser.matches()) { + String protocolVersion = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + if (type.equals("HBD")) { + if (channel != null) { + parser.skip(6); + channel.writeAndFlush(new NetworkMessage( + "+SACK:GTHBD," + protocolVersion + "," + parser.next() + "$", remoteAddress)); + } + } else { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, parser.nextDateTime()); + position.setValid(false); + position.set(Position.KEY_RESULT, "Command " + type + " accepted"); + return position; + } + } + return null; + } + + private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { + if (parser.matches()) { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession != null) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + return position; + } + } + return null; + } + + private void decodeDeviceTime(Position position, Parser parser) { + if (parser.hasNext(6)) { + if (ignoreFixTime) { + position.setTime(parser.nextDateTime()); + } else { + position.setDeviceTime(parser.nextDateTime()); + } + } + } + + private Long parseHours(String hoursString) { + if (hoursString != null) { + String[] hours = hoursString.split(":"); + return (long) (Integer.parseInt(hours[0]) * 3600 + + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60 : 0) + + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000; + } + return null; + } + + private Object decodeInf(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_INF, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + switch (parser.nextHexInt()) { + case 0x16: + case 0x1A: + case 0x12: + position.set(Position.KEY_IGNITION, false); + position.set(Position.KEY_MOTION, true); + break; + case 0x11: + position.set(Position.KEY_IGNITION, false); + position.set(Position.KEY_MOTION, false); + break; + case 0x21: + position.set(Position.KEY_IGNITION, true); + position.set(Position.KEY_MOTION, false); + break; + case 0x22: + position.set(Position.KEY_IGNITION, true); + position.set(Position.KEY_MOTION, true); + break; + case 0x41: + position.set(Position.KEY_MOTION, false); + break; + case 0x42: + position.set(Position.KEY_MOTION, true); + break; + default: + break; + } + + position.set(Position.KEY_RSSI, parser.nextInt()); + + parser.next(); // odometer or external power + + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_CHARGE, parser.nextInt() == 1); + + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + + position.set(Position.PREFIX_TEMP + 1, parser.next()); + + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + + getLastLocation(position, parser.nextDateTime()); + + position.set(Position.KEY_INDEX, parser.nextHexInt()); + + return position; + } + + private Object decodeVer(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_VER, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + position.set("deviceType", parser.next()); + position.set(Position.KEY_VERSION_FW, parser.nextHexInt()); + position.set(Position.KEY_VERSION_HW, parser.nextHexInt()); + + getLastLocation(position, parser.nextDateTime()); + + return position; + } + + private void skipLocation(Parser parser) { + parser.skip(19); + } + + private void decodeLocation(Position position, Parser parser) { + Integer hdop = parser.nextInt(); + position.setValid(hdop == null || hdop > 0); + position.set(Position.KEY_HDOP, hdop); + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + if (parser.hasNext(8)) { + position.setValid(true); + position.setLongitude(parser.nextDouble()); + position.setLatitude(parser.nextDouble()); + position.setTime(parser.nextDateTime()); + } else { + getLastLocation(position, null); + } + + if (parser.hasNext(6)) { + int mcc = parser.nextInt(); + int mnc = parser.nextInt(); + if (parser.hasNext(2)) { + position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt()))); + } + if (parser.hasNext(2)) { + position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt()))); + } + } + + if (parser.hasNext()) { + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + } + } + + private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_OBD, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + position.set(Position.KEY_RPM, parser.nextInt()); + position.set(Position.KEY_OBD_SPEED, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); + position.set(Position.KEY_FUEL_CONSUMPTION, parser.next()); + position.set("dtcsClearedDistance", parser.nextInt()); + if (parser.hasNext()) { + position.set("odbConnect", parser.nextInt() == 1); + } + position.set("dtcsNumber", parser.nextInt()); + position.set("dtcsCodes", parser.next()); + position.set(Position.KEY_THROTTLE, parser.nextInt()); + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); + if (parser.hasNext()) { + position.set(Position.KEY_OBD_ODOMETER, parser.nextInt() * 1000); + } + + decodeLocation(position, parser); + + if (parser.hasNext()) { + position.set(Position.KEY_OBD_ODOMETER, (int) (parser.nextDouble() * 1000)); + } + + decodeDeviceTime(position, parser); + + return position; + } + + private Object decodeCan(Channel channel, SocketAddress remoteAddress, String sentence) throws ParseException { + Position position = new Position(getProtocolName()); + + int index = 0; + String[] values = sentence.split(","); + + index += 1; // header + index += 1; // protocol version + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); + position.setDeviceId(deviceSession.getDeviceId()); + + index += 1; // device name + index += 1; // report type + index += 1; // canbus state + long reportMask = Long.parseLong(values[index++], 16); + long reportMaskExt = 0; + + if (BitUtil.check(reportMask, 0)) { + position.set(Position.KEY_VIN, values[index++]); + } + if (BitUtil.check(reportMask, 1)) { + position.set(Position.KEY_IGNITION, Integer.parseInt(values[index++]) > 0); + } + if (BitUtil.check(reportMask, 2)) { + position.set(Position.KEY_OBD_ODOMETER, values[index++]); + } + if (BitUtil.check(reportMask, 3) && !values[index++].isEmpty()) { + position.set(Position.KEY_FUEL_USED, Double.parseDouble(values[index - 1])); + } + if (BitUtil.check(reportMask, 5) && !values[index++].isEmpty()) { + position.set(Position.KEY_RPM, Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMask, 4) && !values[index++].isEmpty()) { + position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1]))); + } + if (BitUtil.check(reportMask, 6) && !values[index++].isEmpty()) { + position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMask, 7) && !values[index++].isEmpty()) { + position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(values[index - 1].substring(1))); + } + if (BitUtil.check(reportMask, 8) && !values[index++].isEmpty()) { + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[index - 1].substring(1))); + } + if (BitUtil.check(reportMask, 9) && !values[index++].isEmpty()) { + position.set("range", Long.parseLong(values[index - 1]) * 100); + } + if (BitUtil.check(reportMask, 10) && !values[index++].isEmpty()) { + position.set(Position.KEY_THROTTLE, Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMask, 11) && !values[index++].isEmpty()) { + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(values[index - 1]))); + } + if (BitUtil.check(reportMask, 12)) { + position.set("drivingHours", Double.parseDouble(values[index++])); + } + if (BitUtil.check(reportMask, 13)) { + position.set("idleHours", Double.parseDouble(values[index++])); + } + if (BitUtil.check(reportMask, 14) && !values[index++].isEmpty()) { + position.set("idleFuelConsumption", Double.parseDouble(values[index - 1])); + } + if (BitUtil.check(reportMask, 15) && !values[index++].isEmpty()) { + position.set(Position.KEY_AXLE_WEIGHT, Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMask, 16) && !values[index++].isEmpty()) { + position.set("tachographInfo", Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMask, 17) && !values[index++].isEmpty()) { + position.set("indicators", Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMask, 18) && !values[index++].isEmpty()) { + position.set("lights", Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMask, 19) && !values[index++].isEmpty()) { + position.set("doors", Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMask, 20) && !values[index++].isEmpty()) { + position.set("vehicleOverspeed", Double.parseDouble(values[index - 1])); + } + if (BitUtil.check(reportMask, 21) && !values[index++].isEmpty()) { + position.set("engineOverspeed", Double.parseDouble(values[index - 1])); + } + if (BitUtil.check(reportMask, 29)) { + reportMaskExt = Long.parseLong(values[index++], 16); + } + if (BitUtil.check(reportMaskExt, 0) && !values[index++].isEmpty()) { + position.set("adBlueLevel", Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMaskExt, 1) && !values[index++].isEmpty()) { + position.set("axleWeight1", Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMaskExt, 2) && !values[index++].isEmpty()) { + position.set("axleWeight3", Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMaskExt, 3) && !values[index++].isEmpty()) { + position.set("axleWeight4", Integer.parseInt(values[index - 1])); + } + if (BitUtil.check(reportMaskExt, 4)) { + index += 1; // tachograph overspeed + } + if (BitUtil.check(reportMaskExt, 5)) { + index += 1; // tachograph motion + } + if (BitUtil.check(reportMaskExt, 6)) { + index += 1; // tachograph direction + } + if (BitUtil.check(reportMaskExt, 7) && !values[index++].isEmpty()) { + position.set(Position.PREFIX_ADC + 1, Integer.parseInt(values[index - 1]) * 0.001); + } + if (BitUtil.check(reportMaskExt, 8)) { + index += 1; // pedal breaking factor + } + if (BitUtil.check(reportMaskExt, 9)) { + index += 1; // engine breaking factor + } + if (BitUtil.check(reportMaskExt, 10)) { + index += 1; // total accelerator kick-downs + } + if (BitUtil.check(reportMaskExt, 11)) { + index += 1; // total effective engine speed + } + if (BitUtil.check(reportMaskExt, 12)) { + index += 1; // total cruise control time + } + if (BitUtil.check(reportMaskExt, 13)) { + index += 1; // total accelerator kick-down time + } + if (BitUtil.check(reportMaskExt, 14)) { + index += 1; // total brake application + } + if (BitUtil.check(reportMaskExt, 15) && !values[index++].isEmpty()) { + position.set("driver1Card", values[index - 1]); + } + if (BitUtil.check(reportMaskExt, 16) && !values[index++].isEmpty()) { + position.set("driver2Card", values[index - 1]); + } + if (BitUtil.check(reportMaskExt, 17) && !values[index++].isEmpty()) { + position.set("driver1Name", values[index - 1]); + } + if (BitUtil.check(reportMaskExt, 18) && !values[index++].isEmpty()) { + position.set("driver2Name", values[index - 1]); + } + if (BitUtil.check(reportMaskExt, 19) && !values[index++].isEmpty()) { + position.set("registration", values[index - 1]); + } + if (BitUtil.check(reportMaskExt, 20)) { + index += 1; // expansion information + } + if (BitUtil.check(reportMaskExt, 21)) { + index += 1; // rapid brakings + } + if (BitUtil.check(reportMaskExt, 22)) { + index += 1; // rapid accelerations + } + if (BitUtil.check(reportMaskExt, 23)) { + index += 1; // engine torque + } + + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + + if (BitUtil.check(reportMask, 30)) { + while (values[index].isEmpty()) { + index += 1; + } + position.setValid(Integer.parseInt(values[index++]) > 0); + if (!values[index].isEmpty()) { + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); + position.setCourse(Integer.parseInt(values[index++])); + position.setAltitude(Double.parseDouble(values[index++])); + position.setLongitude(Double.parseDouble(values[index++])); + position.setLatitude(Double.parseDouble(values[index++])); + position.setTime(dateFormat.parse(values[index++])); + } else { + index += 6; // no location + getLastLocation(position, null); + } + } else { + getLastLocation(position, null); + } + + if (BitUtil.check(reportMask, 31)) { + index += 4; // cell + index += 1; // reserved + } + + if (ignoreFixTime) { + position.setTime(dateFormat.parse(values[index])); + } else { + position.setDeviceTime(dateFormat.parse(values[index])); + } + + return position; + } + + private void decodeStatus(Position position, Parser parser) { + if (parser.hasNext(3)) { + int ignition = parser.nextHexInt(); + if (BitUtil.check(ignition, 4)) { + position.set(Position.KEY_IGNITION, false); + } else if (BitUtil.check(ignition, 5)) { + position.set(Position.KEY_IGNITION, true); + } + position.set(Position.KEY_INPUT, parser.nextHexInt()); + position.set(Position.KEY_OUTPUT, parser.nextHexInt()); + } + } + + private Object decodeFri(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_FRI, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + LinkedList positions = new LinkedList<>(); + + String vin = parser.next(); + Integer power = parser.nextInt(); + Integer battery = parser.nextInt(); + + Parser itemParser = new Parser(PATTERN_LOCATION, parser.next()); + while (itemParser.find()) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_VIN, vin); + + decodeLocation(position, itemParser); + + positions.add(position); + } + + Position position = positions.getLast(); + + skipLocation(parser); + + if (power != null && power > 10) { + position.set(Position.KEY_POWER, power * 0.001); // only on some devices + } + if (battery != null) { + position.set(Position.KEY_BATTERY_LEVEL, battery); + } + + if (parser.hasNext()) { + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + } + position.set(Position.KEY_HOURS, parseHours(parser.next())); + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + + decodeStatus(position, parser); + + position.set(Position.KEY_RPM, parser.nextInt()); + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); + + if (parser.hasNext()) { + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + } + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + + decodeDeviceTime(position, parser); + if (ignoreFixTime) { + positions.clear(); + positions.add(position); + } + + return positions; + } + + private Object decodeEri(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_ERI, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + long mask = parser.nextHexLong(); + + LinkedList positions = new LinkedList<>(); + + Integer power = parser.nextInt(); + + Parser itemParser = new Parser(PATTERN_LOCATION, parser.next()); + while (itemParser.find()) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + decodeLocation(position, itemParser); + + positions.add(position); + } + + Position position = positions.getLast(); + + skipLocation(parser); + + if (power != null) { + position.set(Position.KEY_POWER, power * 0.001); + } + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + position.set(Position.KEY_HOURS, parseHours(parser.next())); + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + + decodeStatus(position, parser); + + int index = 0; + String[] data = parser.next().split(","); + + index += 1; // device type + + if (BitUtil.check(mask, 0)) { + index += 1; // digital fuel sensor data + } + + if (BitUtil.check(mask, 1)) { + int deviceCount = Integer.parseInt(data[index++]); + for (int i = 1; i <= deviceCount; i++) { + index += 1; // id + index += 1; // type + if (!data[index++].isEmpty()) { + position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625); + } + } + } + + if (BitUtil.check(mask, 2)) { + index += 1; // can data + } + + if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) { + int deviceCount = Integer.parseInt(data[index++]); + for (int i = 1; i <= deviceCount; i++) { + index += 1; // type + if (BitUtil.check(mask, 3)) { + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data[index++])); + } + if (BitUtil.check(mask, 4)) { + index += 1; // volume + } + } + } + + decodeDeviceTime(position, parser); + if (ignoreFixTime) { + positions.clear(); + positions.add(position); + } + + return positions; + } + + private Object decodeIgn(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_IGN, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + decodeLocation(position, parser); + + position.set(Position.KEY_IGNITION, sentence.contains("IGN")); + position.set(Position.KEY_HOURS, parseHours(parser.next())); + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + + decodeDeviceTime(position, parser); + + return position; + } + + private Object decodeLsw(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_LSW, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + position.set(Position.PREFIX_IN + (sentence.contains("LSW") ? 1 : 2), parser.nextInt() == 1); + + decodeLocation(position, parser); + + decodeDeviceTime(position, parser); + + return position; + } + + private Object decodeIda(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_IDA, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + decodeLocation(position, parser); + + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + + decodeDeviceTime(position, parser); + + return position; + } + + private Object decodeWif(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_WIF, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + getLastLocation(position, null); + + Network network = new Network(); + + parser.nextInt(); // count + Matcher matcher = Pattern.compile("([0-9a-fA-F]{12}),(-?\\d+),,,,").matcher(parser.next()); + while (matcher.find()) { + String mac = matcher.group(1).replaceAll("(..)", "$1:"); + network.addWifiAccessPoint(WifiAccessPoint.from( + mac.substring(0, mac.length() - 1), Integer.parseInt(matcher.group(2)))); + } + + position.setNetwork(network); + + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + + return position; + } + + private Object decodeGsm(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_GSM, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + getLastLocation(position, null); + + Network network = new Network(); + + String[] data = parser.next().split(","); + for (int i = 0; i < 6; i++) { + if (!data[i * 6].isEmpty()) { + network.addCellTower(CellTower.from( + Integer.parseInt(data[i * 6]), Integer.parseInt(data[i * 6 + 1]), + Integer.parseInt(data[i * 6 + 2], 16), Integer.parseInt(data[i * 6 + 3], 16), + Integer.parseInt(data[i * 6 + 4]))); + } + } + + position.setNetwork(network); + + return position; + } + + private Object decodePna(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_PNA, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + getLastLocation(position, null); + + position.set(Position.KEY_ALARM, sentence.contains("PNA") ? Position.ALARM_POWER_ON : Position.ALARM_POWER_OFF); + + return position; + } + + private Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence, String type) { + Parser parser = new Parser(PATTERN, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + int reportType = parser.nextHexInt(); + if (type.equals("NMR")) { + position.set(Position.KEY_MOTION, reportType == 1); + } else if (type.equals("SOS")) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } else if (type.equals("DIS")) { + position.set(Position.PREFIX_IN + reportType / 0x10, reportType % 0x10 == 1); + } else if (type.equals("IGL")) { + position.set(Position.KEY_IGNITION, reportType % 0x10 == 1); + } + + decodeLocation(position, parser); + + if (parser.hasNext()) { + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + } + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + + if (parser.hasNext()) { + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + } + + decodeDeviceTime(position, parser); + + if (Context.getConfig().getBoolean(getProtocolName() + ".ack") && channel != null) { + channel.writeAndFlush(new NetworkMessage("+SACK:" + parser.next() + "$", remoteAddress)); + } + + return position; + } + + private Object decodeBasic(Channel channel, SocketAddress remoteAddress, String sentence, String type) { + Parser parser = new Parser(PATTERN_BASIC, sentence); + Position position = initPosition(parser, channel, remoteAddress); + if (position == null) { + return null; + } + + if (parser.hasNext()) { + int hdop = parser.nextInt(); + position.setValid(hdop > 0); + position.set(Position.KEY_HDOP, hdop); + } + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + if (parser.hasNext(2)) { + position.setLongitude(parser.nextDouble()); + position.setLatitude(parser.nextDouble()); + } else { + getLastLocation(position, null); + } + + if (parser.hasNext(6)) { + position.setTime(parser.nextDateTime()); + } + + if (parser.hasNext(4)) { + position.setNetwork(new Network(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt()))); + } + + decodeDeviceTime(position, parser); + + switch (type) { + case "TOW": + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + break; + case "IDL": + position.set(Position.KEY_ALARM, Position.ALARM_IDLE); + break; + case "PNA": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_ON); + break; + case "PFA": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); + break; + case "EPN": + case "MPN": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); + break; + case "EPF": + case "MPF": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; + case "BPL": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case "STT": + position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); + break; + case "SWG": + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE); + break; + case "TMP": + case "TEM": + position.set(Position.KEY_ALARM, Position.ALARM_TEMPERATURE); + break; + case "JDR": + case "JDS": + position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); + break; + default: + break; + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = ((ByteBuf) msg).toString(StandardCharsets.US_ASCII); + + int typeIndex = sentence.indexOf(":GT"); + if (typeIndex < 0) { + return null; + } + + Object result; + String type = sentence.substring(typeIndex + 3, typeIndex + 6); + if (sentence.startsWith("+ACK")) { + result = decodeAck(channel, remoteAddress, sentence, type); + } else { + switch (type) { + case "INF": + result = decodeInf(channel, remoteAddress, sentence); + break; + case "OBD": + result = decodeObd(channel, remoteAddress, sentence); + break; + case "CAN": + result = decodeCan(channel, remoteAddress, sentence); + break; + case "FRI": + case "GEO": + case "STR": + result = decodeFri(channel, remoteAddress, sentence); + break; + case "ERI": + result = decodeEri(channel, remoteAddress, sentence); + break; + case "IGN": + case "IGF": + result = decodeIgn(channel, remoteAddress, sentence); + break; + case "LSW": + case "TSW": + result = decodeLsw(channel, remoteAddress, sentence); + break; + case "IDA": + result = decodeIda(channel, remoteAddress, sentence); + break; + case "WIF": + result = decodeWif(channel, remoteAddress, sentence); + break; + case "GSM": + result = decodeGsm(channel, remoteAddress, sentence); + break; + case "VER": + result = decodeVer(channel, remoteAddress, sentence); + break; + case "PNA": + case "PFA": + result = decodePna(channel, remoteAddress, sentence); + break; + default: + result = decodeOther(channel, remoteAddress, sentence, type); + break; + } + + if (result == null) { + result = decodeBasic(channel, remoteAddress, sentence, type); + } + + if (result != null) { + if (result instanceof Position) { + ((Position) result).set(Position.KEY_TYPE, type); + } else { + for (Position p : (List) result) { + p.set(Position.KEY_TYPE, type); + } + } + } + } + + return result; + } + +} diff --git a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java new file mode 100644 index 000000000..5612515c9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GlobalSatProtocol extends BaseProtocol { + + public GlobalSatProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '!')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new GlobalSatProtocolDecoder(GlobalSatProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java new file mode 100644 index 000000000..3d4ab5760 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java @@ -0,0 +1,248 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class GlobalSatProtocolDecoder extends BaseProtocolDecoder { + + private String format0; + private String format1; + + public GlobalSatProtocolDecoder(Protocol protocol) { + super(protocol); + + format0 = Context.getConfig().getString(getProtocolName() + ".format0", "TSPRXAB27GHKLMnaicz*U!"); + format1 = Context.getConfig().getString(getProtocolName() + ".format1", "SARY*U!"); + } + + public void setFormat0(String format) { + format0 = format; + } + + public void setFormat1(String format) { + format1 = format; + } + + private Position decodeOriginal(Channel channel, SocketAddress remoteAddress, String sentence) { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("ACK\r", remoteAddress)); + } + + String format; + if (sentence.startsWith("GSr")) { + format = format0; + } else if (sentence.startsWith("GSh")) { + format = format1; + } else { + return null; + } + + // Check that message contains required parameters + if (!format.contains("B") || !format.contains("S") || !(format.contains("1") + || format.contains("2") || format.contains("3")) || !(format.contains("6") + || format.contains("7") || format.contains("8"))) { + return null; + } + + if (format.contains("*")) { + format = format.substring(0, format.indexOf('*')); + sentence = sentence.substring(0, sentence.indexOf('*')); + } + String[] values = sentence.split(","); + + Position position = new Position(getProtocolName()); + + for (int formatIndex = 0, valueIndex = 1; formatIndex < format.length() + && valueIndex < values.length; formatIndex++) { + String value = values[valueIndex]; + + switch (format.charAt(formatIndex)) { + case 'S': + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + break; + case 'A': + if (value.isEmpty()) { + position.setValid(false); + } else { + position.setValid(Integer.parseInt(value) != 1); + } + break; + case 'B': + DateBuilder dateBuilder = new DateBuilder() + .setDay(Integer.parseInt(value.substring(0, 2))) + .setMonth(Integer.parseInt(value.substring(2, 4))) + .setYear(Integer.parseInt(value.substring(4))); + value = values[++valueIndex]; + dateBuilder + .setHour(Integer.parseInt(value.substring(0, 2))) + .setMinute(Integer.parseInt(value.substring(2, 4))) + .setSecond(Integer.parseInt(value.substring(4))); + position.setTime(dateBuilder.getDate()); + break; + case 'C': + valueIndex += 1; + break; + case '1': + double longitude = Double.parseDouble(value.substring(1)); + if (value.charAt(0) == 'W') { + longitude = -longitude; + } + position.setLongitude(longitude); + break; + case '2': + longitude = Double.parseDouble(value.substring(4)) / 60; + longitude += Integer.parseInt(value.substring(1, 4)); + if (value.charAt(0) == 'W') { + longitude = -longitude; + } + position.setLongitude(longitude); + break; + case '3': + position.setLongitude(Double.parseDouble(value) * 0.000001); + break; + case '6': + double latitude = Double.parseDouble(value.substring(1)); + if (value.charAt(0) == 'S') { + latitude = -latitude; + } + position.setLatitude(latitude); + break; + case '7': + latitude = Double.parseDouble(value.substring(3)) / 60; + latitude += Integer.parseInt(value.substring(1, 3)); + if (value.charAt(0) == 'S') { + latitude = -latitude; + } + position.setLatitude(latitude); + break; + case '8': + position.setLatitude(Double.parseDouble(value) * 0.000001); + break; + case 'G': + position.setAltitude(Double.parseDouble(value)); + break; + case 'H': + position.setSpeed(Double.parseDouble(value)); + break; + case 'I': + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(value))); + break; + case 'J': + position.setSpeed(UnitsConverter.knotsFromMph(Double.parseDouble(value))); + break; + case 'K': + position.setCourse(Double.parseDouble(value)); + break; + case 'N': + if (value.endsWith("mV")) { + position.set(Position.KEY_BATTERY, + Integer.parseInt(value.substring(0, value.length() - 2)) / 1000.0); + } else { + position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(value)); + } + break; + default: + // Unsupported + break; + } + + valueIndex += 1; + } + return position; + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$") + .number("(d+),") // imei + .number("d+,") // mode + .number("(d+),") // fix + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([EW])") + .number("(ddd)(dd.d+),") // longitude (dddmm.mmmm) + .expression("([NS])") + .number("(dd)(dd.d+),") // latitude (ddmm.mmmm) + .number("(d+.?d*),") // altitude + .number("(d+.?d*),") // speed + .number("(d+.?d*)?,") // course + .number("(d+)[,*]") // satellites + .number("(d+.?d*)") // hdop + .compile(); + + private Position decodeAlternative(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(!parser.next().equals("1")); + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setAltitude(parser.nextDouble(0)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_HDOP, parser.nextDouble()); + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("GS")) { + return decodeOriginal(channel, remoteAddress, sentence); + } else if (sentence.startsWith("$")) { + return decodeAlternative(channel, remoteAddress, sentence); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/GnxProtocol.java b/src/main/java/org/traccar/protocol/GnxProtocol.java new file mode 100644 index 000000000..3576bf805 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GnxProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GnxProtocol extends BaseProtocol { + + public GnxProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\n\r")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new GnxProtocolDecoder(GnxProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GnxProtocolDecoder.java b/src/main/java/org/traccar/protocol/GnxProtocolDecoder.java new file mode 100644 index 000000000..c9c221a69 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GnxProtocolDecoder.java @@ -0,0 +1,111 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class GnxProtocolDecoder extends BaseProtocolDecoder { + + public GnxProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_LOCATION = new PatternBuilder() + .number("(d+),") // imei + .number("d+,") // length + .expression("([01]),") // history + .number("(dd)(dd)(dd),") // device time (hhmmss) + .number("(dd)(dd)(dd),") // device date (ddmmyy) + .number("(dd)(dd)(dd),") // fix time (hhmmss) + .number("(dd)(dd)(dd),") // fix date (ddmmyy) + .number("(d),") // valid + .number("(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd.d+),") // longitude + .expression("([EW]),") + .compile(); + + private static final Pattern PATTERN_MIF = new PatternBuilder() + .text("$GNX_MIF,") + .expression(PATTERN_LOCATION.pattern()) + .expression("[01],") // valid card + .expression("([^,]+),") // rfid + .any() + .compile(); + + private static final Pattern PATTERN_OTHER = new PatternBuilder() + .text("$GNX_") + .expression("...,") + .expression(PATTERN_LOCATION.pattern()) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + String type = sentence.substring(5, 8); + + Pattern pattern; + if (type.equals("MIF")) { + pattern = PATTERN_MIF; + } else { + pattern = PATTERN_OTHER; + } + + Parser parser = new Parser(pattern, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.nextInt(0) == 1) { + position.set(Position.KEY_ARCHIVE, true); + } + + position.setDeviceTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY, "GMT+5:30")); + position.setFixTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY, "GMT+5:30")); + + position.setValid(parser.nextInt(0) != 0); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + + if (type.equals("MIF")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocol.java b/src/main/java/org/traccar/protocol/GoSafeProtocol.java new file mode 100644 index 000000000..853b78a16 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GoSafeProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GoSafeProtocol extends BaseProtocol { + + public GoSafeProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new GoSafeProtocolDecoder(GoSafeProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java new file mode 100644 index 000000000..95ef18f20 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java @@ -0,0 +1,269 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class GoSafeProtocolDecoder extends BaseProtocolDecoder { + + public GoSafeProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("*GS") // header + .number("d+,") // protocol version + .number("(d+),") // imei + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("(dd)(dd)(dd),") // date (ddmmyy) + .expression("([^#]*)#?") // data + .compile(); + + private static final Pattern PATTERN_OLD = new PatternBuilder() + .text("*GS") // header + .number("d+,") // protocol version + .number("(d+),") // imei + .text("GPS:") + .number("(dd)(dd)(dd);") // time (hhmmss) + .number("d;").optional() // fix type + .expression("([AV]);") // validity + .number("([NS])(d+.d+);") // latitude + .number("([EW])(d+.d+);") // longitude + .number("(d+)?;") // speed + .number("(d+);") // course + .number("(d+.?d*)").optional() // hdop + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + private void decodeFragment(Position position, String fragment) { + int dataIndex = fragment.indexOf(':'); + int index = 0; + String[] values; + if (fragment.length() == dataIndex + 1) { + values = new String[0]; + } else { + values = fragment.substring(dataIndex + 1).split(";"); + } + switch (fragment.substring(0, dataIndex)) { + case "GPS": + position.setValid(values[index++].equals("A")); + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + position.setLatitude(Double.parseDouble(values[index].substring(1))); + if (values[index++].charAt(0) == 'S') { + position.setLatitude(-position.getLatitude()); + } + position.setLongitude(Double.parseDouble(values[index].substring(1))); + if (values[index++].charAt(0) == 'W') { + position.setLongitude(-position.getLongitude()); + } + if (!values[index++].isEmpty()) { + position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1]))); + } + position.setCourse(Integer.parseInt(values[index++])); + if (index < values.length) { + position.setAltitude(Integer.parseInt(values[index++])); + } + if (index < values.length) { + position.set(Position.KEY_HDOP, Double.parseDouble(values[index++])); + } + if (index < values.length) { + position.set(Position.KEY_VDOP, Double.parseDouble(values[index++])); + } + break; + case "GSM": + index += 1; // registration status + index += 1; // signal strength + position.setNetwork(new Network(CellTower.from( + Integer.parseInt(values[index++]), Integer.parseInt(values[index++]), + Integer.parseInt(values[index++], 16), Integer.parseInt(values[index++], 16), + Integer.parseInt(values[index++])))); + break; + case "COT": + if (index < values.length) { + position.set(Position.KEY_ODOMETER, Long.parseLong(values[index++])); + } + if (index < values.length) { + String[] hours = values[index].split("-"); + position.set(Position.KEY_HOURS, (Integer.parseInt(hours[0]) * 3600 + + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60 : 0) + + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000); + } + break; + case "ADC": + position.set(Position.KEY_POWER, Double.parseDouble(values[index++])); + if (index < values.length) { + position.set(Position.KEY_BATTERY, Double.parseDouble(values[index++])); + } + if (index < values.length) { + position.set(Position.PREFIX_ADC + 1, Double.parseDouble(values[index++])); + } + if (index < values.length) { + position.set(Position.PREFIX_ADC + 2, Double.parseDouble(values[index++])); + } + break; + case "DTT": + position.set(Position.KEY_STATUS, Integer.parseInt(values[index++], 16)); + if (!values[index++].isEmpty()) { + int io = Integer.parseInt(values[index - 1], 16); + position.set(Position.KEY_IGNITION, BitUtil.check(io, 0)); + position.set(Position.PREFIX_IN + 1, BitUtil.check(io, 1)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(io, 2)); + position.set(Position.PREFIX_IN + 3, BitUtil.check(io, 3)); + position.set(Position.PREFIX_IN + 4, BitUtil.check(io, 4)); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(io, 5)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(io, 6)); + position.set(Position.PREFIX_OUT + 3, BitUtil.check(io, 7)); + } + position.set(Position.KEY_GEOFENCE, values[index++] + values[index++]); + position.set("eventStatus", values[index++]); + if (index < values.length) { + position.set("packetType", values[index++]); + } + break; + case "ETD": + position.set("eventData", values[index++]); + break; + case "OBD": + position.set("obd", values[index++]); + break; + case "TAG": + position.set("tagData", values[index++]); + break; + case "IWD": + if (index < values.length && values[index + 1].equals("0")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, values[index + 2]); + } + break; + default: + break; + } + } + + private Object decodeData(DeviceSession deviceSession, Date time, String data) { + + List positions = new LinkedList<>(); + Position position = null; + int index = 0; + String[] fragments = data.split(","); + + while (index < fragments.length) { + + if (fragments[index].isEmpty() || Character.isDigit(fragments[index].charAt(0))) { + + if (position != null) { + positions.add(position); + } + + position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.setTime(time); + + if (!fragments[index++].isEmpty()) { + position.set(Position.KEY_EVENT, Integer.parseInt(fragments[index - 1])); + } + + } else { + + decodeFragment(position, fragments[index++]); + + } + + } + + if (position != null) { + positions.add(position); + } + + return positions; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("1234", remoteAddress)); + } + + String sentence = (String) msg; + Pattern pattern = PATTERN; + if (sentence.startsWith("*GS02")) { + pattern = PATTERN_OLD; + } + + Parser parser = new Parser(pattern, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + if (pattern == PATTERN_OLD) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_HDOP, parser.next()); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + + } else { + + Date time = new Date(); + if (parser.hasNext(6)) { + time = parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY); + } + + return decodeData(deviceSession, time, parser.next()); + + } + } + +} diff --git a/src/main/java/org/traccar/protocol/GotopProtocol.java b/src/main/java/org/traccar/protocol/GotopProtocol.java new file mode 100644 index 000000000..07fe02248 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GotopProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GotopProtocol extends BaseProtocol { + + public GotopProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new GotopProtocolDecoder(GotopProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java b/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java new file mode 100644 index 000000000..2ef975fe5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java @@ -0,0 +1,82 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class GotopProtocolDecoder extends BaseProtocolDecoder { + + public GotopProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(d+),") // imei + .expression("[^,]+,") // type + .expression("([AV]),") // validity + .number("DATE:(dd)(dd)(dd),") // date (yyddmm) + .number("TIME:(dd)(dd)(dd),") // time (hhmmss) + .number("LAT:(d+.d+)([NS]),") // latitude + .number("LOT:(d+.d+)([EW]),") // longitude + .text("Speed:").number("(d+.d+),") // speed + .expression("([^,]+),") // status + .number("(d+)?") // course + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.next().equals("A")); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + + position.set(Position.KEY_STATUS, parser.next()); + + position.setCourse(parser.nextDouble(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gps056FrameDecoder.java b/src/main/java/org/traccar/protocol/Gps056FrameDecoder.java new file mode 100644 index 000000000..0d84bf231 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gps056FrameDecoder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +import java.nio.charset.StandardCharsets; + +public class Gps056FrameDecoder extends BaseFrameDecoder { + + private static final int MESSAGE_HEADER = 4; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() >= MESSAGE_HEADER) { + int length = Integer.parseInt(buf.toString(2, 2, StandardCharsets.US_ASCII)) + 5; + if (buf.readableBytes() >= length) { + ByteBuf frame = buf.readRetainedSlice(length); + while (buf.isReadable() && buf.getUnsignedByte(buf.readerIndex()) != '$') { + buf.readByte(); + } + return frame; + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gps056Protocol.java b/src/main/java/org/traccar/protocol/Gps056Protocol.java new file mode 100644 index 000000000..b6ab10a19 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gps056Protocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Gps056Protocol extends BaseProtocol { + + public Gps056Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Gps056FrameDecoder()); + pipeline.addLast(new Gps056ProtocolDecoder(Gps056Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java new file mode 100644 index 000000000..0ba79bb51 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java @@ -0,0 +1,140 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class Gps056ProtocolDecoder extends BaseProtocolDecoder { + + public Gps056ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static void sendResponse(Channel channel, String type, String imei, ByteBuf content) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + String header = "*" + type + imei; + response.writeBytes(header.getBytes(StandardCharsets.US_ASCII)); + if (content != null) { + response.writeBytes(content); + } + response.writeByte('#'); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + private static double decodeCoordinate(ByteBuf buf) { + double degrees = buf.getUnsignedShort(buf.readerIndex()) / 100; + double minutes = buf.readUnsignedShort() % 100 + buf.readUnsignedShort() * 0.0001; + degrees += minutes / 60; + byte hemisphere = buf.readByte(); + if (hemisphere == 'S' || hemisphere == 'W') { + degrees = -degrees; + } + return degrees; + } + + private static void decodeStatus(ByteBuf buf, Position position) { + + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + + position.set(Position.PREFIX_ADC + 1, buf.readShortLE() * 5.06); // mV + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.skipBytes(2); // length + + String type = buf.readSlice(7).toString(StandardCharsets.US_ASCII); + String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + if (type.startsWith("LOGN")) { + + ByteBuf content = Unpooled.copiedBuffer("1", StandardCharsets.US_ASCII); + try { + sendResponse(channel, "LGSA" + type.substring(4), imei, content); + } finally { + content.release(); + } + + } else if (type.startsWith("GPSL")) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + + position.setValid(true); + position.setTime(dateBuilder.getDate()); + position.setLatitude(decodeCoordinate(buf)); + position.setLongitude(decodeCoordinate(buf)); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedShort()); + + decodeStatus(buf, position); + + sendResponse(channel, "GPSA" + type.substring(4), imei, buf.readSlice(2)); + + return position; + + } else if (type.startsWith("SYNC")) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + decodeStatus(buf, position); + + sendResponse(channel, "SYSA" + type.substring(4), imei, null); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gps103Protocol.java b/src/main/java/org/traccar/protocol/Gps103Protocol.java new file mode 100644 index 000000000..6272a3fd1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gps103Protocol.java @@ -0,0 +1,60 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class Gps103Protocol extends BaseProtocol { + + public Gps103Protocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_POSITION_STOP, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM, + Command.TYPE_REQUEST_PHOTO); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(2048, false, "\r\n", "\n", ";", "*")); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Gps103ProtocolEncoder()); + pipeline.addLast(new Gps103ProtocolDecoder(Gps103Protocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Gps103ProtocolEncoder()); + pipeline.addLast(new Gps103ProtocolDecoder(Gps103Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java new file mode 100644 index 000000000..aa02e8ad4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java @@ -0,0 +1,422 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DataConverter; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Gps103ProtocolDecoder extends BaseProtocolDecoder { + + private int photoPackets = 0; + private ByteBuf photo; + + public Gps103ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("imei:") + .number("(d+),") // imei + .expression("([^,]+),") // alarm + .groupBegin() + .number("(dd)/?(dd)/?(dd) ?") // local date (yymmdd) + .number("(dd):?(dd)(?:dd)?,") // local time (hhmmss) + .or() + .number("d*,") + .groupEnd() + .expression("([^,]+)?,") // rfid + .groupBegin() + .text("L,,,") + .number("(x+),,") // lac + .number("(x+),,,") // cid + .or() + .text("F,") + .groupBegin() + .number("(dd)(dd)(dd).d+") // time utc (hhmmss) + .or() + .number("(?:d{1,5}.d+)?") + .groupEnd() + .text(",") + .expression("([AV]),") // validity + .expression("([NS]),").optional() + .number("(d+)(dd.d+),") // latitude (ddmm.mmmm) + .expression("([NS]),").optional() + .expression("([EW]),").optional() + .number("(d+)(dd.d+),") // longitude (dddmm.mmmm) + .expression("([EW])?,").optional() + .number("(d+.?d*)?").optional() // speed + .number(",(d+.?d*)?").optional() // course + .number(",(d+.?d*)?").optional() // altitude + .number(",([01])?").optional() // ignition + .number(",([01])?").optional() // door + .groupBegin() + .number(",(?:(d+.d+)%)?") // fuel 1 + .number(",(?:(d+.d+)%|d+)?") // fuel 2 + .groupEnd("?") + .number(",([-+]?d+)?").optional() // temperature + .groupEnd() + .any() + .compile(); + + private static final Pattern PATTERN_OBD = new PatternBuilder() + .text("imei:") + .number("(d+),") // imei + .expression("OBD,") // type + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d+)?,") // odometer + .number("(d+.d+)?,") // fuel instant + .number("(d+.d+)?,") // fuel average + .number("(d+)?,") // hours + .number("(d+),") // speed + .number("(d+.?d*%),") // power load + .number("(?:([-+]?d+)|[-+]?),") // temperature + .number("(d+.?d*%),") // throttle + .number("(d+),") // rpm + .number("(d+.d+),") // battery + .number("([^;]*)") // dtcs + .any() + .compile(); + + private static final Pattern PATTERN_ALT = new PatternBuilder() + .text("imei:") + .number("(d+),") // imei + .expression("[^,]+,") + .expression("(?:-+|(.+)),") // event + .expression("(?:-+|(.+)),") // sensor id + .expression("(?:-+|(.+)),") // sensor voltage + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(d+),") // rssi + .number("(d),") // gps status + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(-?d+),") // altitude + .number("(d+.d+),") // hdop + .number("(d+),") // satellites + .number("([01]),") // ignition + .number("([01]),") // charge + .expression("(?:-+|(.+))") // error + .any() + .compile(); + + private String decodeAlarm(String value) { + if (value.startsWith("T:")) { + return Position.ALARM_TEMPERATURE; + } else if (value.startsWith("oil")) { + return Position.ALARM_FUEL_LEAK; + } + switch (value) { + case "tracker": + return null; + case "help me": + return Position.ALARM_SOS; + case "low battery": + return Position.ALARM_LOW_BATTERY; + case "stockade": + return Position.ALARM_GEOFENCE; + case "move": + return Position.ALARM_MOVEMENT; + case "speed": + return Position.ALARM_OVERSPEED; + case "acc on": + return Position.ALARM_POWER_ON; + case "acc off": + return Position.ALARM_POWER_OFF; + case "door alarm": + return Position.ALARM_DOOR; + case "ac alarm": + return Position.ALARM_POWER_CUT; + case "accident alarm": + return Position.ALARM_ACCIDENT; + case "sensor alarm": + return Position.ALARM_SHOCK; + case "bonnet alarm": + return Position.ALARM_BONNET; + case "footbrake alarm": + return Position.ALARM_FOOT_BRAKE; + case "DTC": + return Position.ALARM_FAULT; + default: + return null; + } + } + + private Position decodeRegular(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + String imei = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + String alarm = parser.next(); + position.set(Position.KEY_ALARM, decodeAlarm(alarm)); + if (alarm.equals("help me")) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("**,imei:" + imei + ",E;", remoteAddress)); + } + } else if (alarm.startsWith("vt")) { + photoPackets = Integer.parseInt(alarm.substring(2)); + photo = Unpooled.buffer(); + } else if (alarm.equals("acc on")) { + position.set(Position.KEY_IGNITION, true); + } else if (alarm.equals("acc off")) { + position.set(Position.KEY_IGNITION, false); + } else if (alarm.startsWith("T:")) { + position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(alarm.substring(2))); + } else if (alarm.startsWith("oil ")) { + position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(alarm.substring(4))); + } else if (!position.getAttributes().containsKey(Position.KEY_ALARM) && !alarm.equals("tracker")) { + position.set(Position.KEY_EVENT, alarm); + } + + DateBuilder dateBuilder = new DateBuilder() + .setDate(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + int localHours = parser.nextInt(0); + int localMinutes = parser.nextInt(0); + + String rfid = parser.next(); + if (alarm.equals("rfid")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid); + } + + if (parser.hasNext(2)) { + + getLastLocation(position, null); + + position.setNetwork(new Network(CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0)))); + + } else { + + String utcHours = parser.next(); + String utcMinutes = parser.next(); + + dateBuilder.setTime(localHours, localMinutes, parser.nextInt(0)); + + // Timezone calculation + if (utcHours != null && utcMinutes != null) { + int deltaMinutes = (localHours - Integer.parseInt(utcHours)) * 60; + deltaMinutes += localMinutes - Integer.parseInt(utcMinutes); + if (deltaMinutes <= -12 * 60) { + deltaMinutes += 24 * 60; + } else if (deltaMinutes > 12 * 60) { + deltaMinutes -= 24 * 60; + } + dateBuilder.addMinute(-deltaMinutes); + } + position.setTime(dateBuilder.getDate()); + + position.setValid(parser.next().equals("A")); + position.setFixTime(position.getDeviceTime()); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_HEM)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + if (parser.hasNext()) { + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + } + if (parser.hasNext()) { + position.set(Position.KEY_DOOR, parser.nextInt() == 1); + } + position.set("fuel1", parser.nextDouble()); + position.set("fuel2", parser.nextDouble()); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); + + } + + return position; + } + + private Position decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_OBD, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, parser.nextDateTime()); + + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + parser.nextDouble(0); // instant fuel consumption + position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextDouble(0)); + if (parser.hasNext()) { + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(parser.nextInt())); + } + position.set(Position.KEY_OBD_SPEED, parser.nextInt(0)); + position.set(Position.KEY_ENGINE_LOAD, parser.next()); + position.set(Position.KEY_COOLANT_TEMP, parser.nextInt()); + position.set(Position.KEY_THROTTLE, parser.next()); + position.set(Position.KEY_RPM, parser.nextInt(0)); + position.set(Position.KEY_BATTERY, parser.nextDouble(0)); + position.set(Position.KEY_DTCS, parser.next().replace(',', ' ').trim()); + + return position; + } + + + private Position decodeAlternative(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_ALT, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, parser.next()); + position.set("sensorId", parser.next()); + position.set("sensorVoltage", parser.nextDouble()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + position.set(Position.KEY_RSSI, parser.nextInt()); + + position.setValid(parser.nextInt() > 0); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setCourse(parser.nextInt()); + position.setAltitude(parser.nextInt()); + + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_IGNITION, parser.nextInt() > 0); + position.set(Position.KEY_CHARGE, parser.nextInt() > 0); + position.set("error", parser.next()); + + return position; + } + + private Position decodePhoto(Channel channel, SocketAddress remoteAddress, String sentence) { + + String imei = sentence.substring(5, 5 + 15); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex( + sentence.substring(24, sentence.endsWith(";") ? sentence.length() - 1 : sentence.length()))); + int index = buf.readUnsignedShortLE(); + photo.writeBytes(buf, buf.readerIndex() + 2, buf.readableBytes() - 4); + + if (index + 1 >= photoPackets) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + try { + position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg")); + } finally { + photoPackets = 0; + photo.release(); + photo = null; + } + + return position; + } else { + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.contains("imei:") && sentence.length() <= 30) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("LOAD", remoteAddress)); + Matcher matcher = Pattern.compile("imei:(\\d+),").matcher(sentence); + if (matcher.find()) { + getDeviceSession(channel, remoteAddress, matcher.group(1)); + } + } + return null; + } + + if (!sentence.isEmpty() && Character.isDigit(sentence.charAt(0))) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("ON", remoteAddress)); + } + int start = sentence.indexOf("imei:"); + if (start >= 0) { + sentence = sentence.substring(start); + } else { + return null; + } + } + + if (sentence.substring(21, 21 + 2).equals("vr")) { + return decodePhoto(channel, remoteAddress, sentence); + } else if (sentence.substring(21, 21 + 3).contains("OBD")) { + return decodeObd(channel, remoteAddress, sentence); + } else if (sentence.endsWith("*")) { + return decodeAlternative(channel, remoteAddress, sentence); + } else { + return decodeRegular(channel, remoteAddress, sentence); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java new file mode 100644 index 000000000..47ef2f333 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class Gps103ProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { + + @Override + public String formatValue(String key, Object value) { + + if (key.equals(Command.KEY_FREQUENCY)) { + long frequency = ((Number) value).longValue(); + if (frequency / 60 / 60 > 0) { + return String.format("%02dh", frequency / 60 / 60); + } else if (frequency / 60 > 0) { + return String.format("%02dm", frequency / 60); + } else { + return String.format("%02ds", frequency); + } + } + + return null; + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatCommand(command, "**,imei:{%s},{%s}", Command.KEY_UNIQUE_ID, Command.KEY_DATA); + case Command.TYPE_POSITION_STOP: + return formatCommand(command, "**,imei:{%s},A", Command.KEY_UNIQUE_ID); + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, "**,imei:{%s},B", Command.KEY_UNIQUE_ID); + case Command.TYPE_POSITION_PERIODIC: + return formatCommand( + command, "**,imei:{%s},C,{%s}", this, Command.KEY_UNIQUE_ID, Command.KEY_FREQUENCY); + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, "**,imei:{%s},J", Command.KEY_UNIQUE_ID); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, "**,imei:{%s},K", Command.KEY_UNIQUE_ID); + case Command.TYPE_ALARM_ARM: + return formatCommand(command, "**,imei:{%s},L", Command.KEY_UNIQUE_ID); + case Command.TYPE_ALARM_DISARM: + return formatCommand(command, "**,imei:{%s},M", Command.KEY_UNIQUE_ID); + case Command.TYPE_REQUEST_PHOTO: + return formatCommand(command, "**,imei:{%s},160", Command.KEY_UNIQUE_ID); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/GpsGateProtocol.java b/src/main/java/org/traccar/protocol/GpsGateProtocol.java new file mode 100644 index 000000000..a131b6f48 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GpsGateProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GpsGateProtocol extends BaseProtocol { + + public GpsGateProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\0", "\n", "\r\n")); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new GpsGateProtocolDecoder(GpsGateProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java b/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java new file mode 100644 index 000000000..cc187225b --- /dev/null +++ b/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java @@ -0,0 +1,170 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class GpsGateProtocolDecoder extends BaseProtocolDecoder { + + public GpsGateProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_GPRMC = new PatternBuilder() + .text("$GPRMC,") + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+)?,") // speed + .number("(d+.d+)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + private static final Pattern PATTERN_FRCMD = new PatternBuilder() + .text("$FRCMD,") + .number("(d+),") // imei + .expression("[^,]*,") // command + .expression("[^,]*,") + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*),") // altitude + .number("(d+.?d*),") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([01])") // validity + .any() + .compile(); + + private void send(Channel channel, SocketAddress remoteAddress, String message) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(message + Checksum.nmea(message) + "\r\n", remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("$FRLIN,")) { + + int beginIndex = sentence.indexOf(',', 7); + if (beginIndex != -1) { + beginIndex += 1; + int endIndex = sentence.indexOf(',', beginIndex); + if (endIndex != -1) { + String imei = sentence.substring(beginIndex, endIndex); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession != null) { + if (channel != null) { + send(channel, remoteAddress, "$FRSES," + channel.id().asShortText()); + } + } else { + send(channel, remoteAddress, "$FRERR,AuthError,Unknown device"); + } + } else { + send(channel, remoteAddress, "$FRERR,AuthError,Parse error"); + } + } else { + send(channel, remoteAddress, "$FRERR,AuthError,Parse error"); + } + + } else if (sentence.startsWith("$FRVER,")) { + + send(channel, remoteAddress, "$FRVER,1,0,GpsGate Server 1.0"); + + } else if (sentence.startsWith("$GPRMC,")) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN_GPRMC, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + + } else if (sentence.startsWith("$FRCMD,")) { + + Parser parser = new Parser(PATTERN_FRCMD, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setAltitude(parser.nextDouble(0)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(parser.next().equals("1")); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java b/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java new file mode 100644 index 000000000..ad23ece48 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GpsMarkerProtocol extends BaseProtocol { + + public GpsMarkerProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new GpsMarkerProtocolDecoder(GpsMarkerProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java b/src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java new file mode 100644 index 000000000..bbb2c31e2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java @@ -0,0 +1,90 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class GpsMarkerProtocolDecoder extends BaseProtocolDecoder { + + public GpsMarkerProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$GM") + .number("d") // type + .number("(?:xx)?") // index + .number("(d{15})") // imei + .number("T(dd)(dd)(dd)") // date (ddmmyy) + .number("(dd)(dd)(dd)?") // time (hhmmss) + .expression("([NS])") + .number("(dd)(dd)(dddd)") // latitude + .expression("([EW])") + .number("(ddd)(dd)(dddd)") // longitude + .number("(ddd)") // speed + .number("(ddd)") // course + .number("(x)") // satellites + .number("(dd)") // battery + .number("(d)") // input + .number("(d)") // output + .number("(ddd)") // temperature + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + position.set(Position.PREFIX_TEMP + 1, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/GpsmtaProtocol.java b/src/main/java/org/traccar/protocol/GpsmtaProtocol.java new file mode 100644 index 000000000..ce6cc5929 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GpsmtaProtocol.java @@ -0,0 +1,37 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class GpsmtaProtocol extends BaseProtocol { + + public GpsmtaProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new GpsmtaProtocolDecoder(GpsmtaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java b/src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java new file mode 100644 index 000000000..31f9401b4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java @@ -0,0 +1,92 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.regex.Pattern; + +public class GpsmtaProtocolDecoder extends BaseProtocolDecoder { + + public GpsmtaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("([^ ]+) ") // uid + .number("(d+) ") // time (unix time) + .number("(-?d+.d+) ") // latitude + .number("(-?d+.d+) ") // longitude + .number("(d+) ") // speed + .number("(d+) ") // course + .number("(d+) ") // accuracy + .number("(d+) ") // altitude + .number("(d+) ") // flags + .number("(d+) ") // battery + .number("(d+) ") // temperature + .number("(d)") // charging status + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + String time = parser.next(); + position.setTime(new Date(Long.parseLong(time) * 1000)); + + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(parser.nextInt()); + position.setCourse(parser.nextInt()); + position.setAccuracy(parser.nextInt()); + position.setAltitude(parser.nextInt()); + + position.set(Position.KEY_STATUS, parser.nextInt()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); + position.set(Position.KEY_CHARGE, parser.nextInt() == 1); + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(time, remoteAddress)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/GranitFrameDecoder.java b/src/main/java/org/traccar/protocol/GranitFrameDecoder.java new file mode 100644 index 000000000..bb7f4be44 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GranitFrameDecoder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; +import org.traccar.helper.BufferUtil; + +public class GranitFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int indexEnd = BufferUtil.indexOf("\r\n", buf); + if (indexEnd != -1) { + int indexTilde = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '~'); + if (indexTilde != -1 && indexTilde < indexEnd) { + int length = buf.getUnsignedShortLE(indexTilde + 1); + indexEnd = BufferUtil.indexOf("\r\n", buf, indexTilde + 2 + length, buf.writerIndex()); + if (indexEnd == -1) { + return null; + } + } + ByteBuf frame = buf.readRetainedSlice(indexEnd - buf.readerIndex()); + buf.skipBytes(2); + return frame; + } + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/GranitProtocol.java b/src/main/java/org/traccar/protocol/GranitProtocol.java new file mode 100644 index 000000000..6785f2a2e --- /dev/null +++ b/src/main/java/org/traccar/protocol/GranitProtocol.java @@ -0,0 +1,45 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class GranitProtocol extends BaseProtocol { + + public GranitProtocol() { + setSupportedDataCommands( + Command.TYPE_IDENTIFICATION, + Command.TYPE_REBOOT_DEVICE, + Command.TYPE_POSITION_SINGLE); + setTextCommandEncoder(new GranitProtocolSmsEncoder()); + setSupportedTextCommands( + Command.TYPE_REBOOT_DEVICE, + Command.TYPE_POSITION_PERIODIC); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new GranitFrameDecoder()); + pipeline.addLast(new GranitProtocolEncoder()); + pipeline.addLast(new GranitProtocolDecoder(GranitProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/GranitProtocolDecoder.java b/src/main/java/org/traccar/protocol/GranitProtocolDecoder.java new file mode 100644 index 000000000..8900e5b39 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GranitProtocolDecoder.java @@ -0,0 +1,239 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +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.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class GranitProtocolDecoder extends BaseProtocolDecoder { + + private static final int HEADER_LENGTH = 6; + + private double adc1Ratio; + private double adc2Ratio; + private double adc3Ratio; + private double adc4Ratio; + + public GranitProtocolDecoder(Protocol protocol) { + super(protocol); + adc1Ratio = Context.getConfig().getDouble("granit.adc1Ratio", 1); + adc2Ratio = Context.getConfig().getDouble("granit.adc2Ratio", 1); + adc3Ratio = Context.getConfig().getDouble("granit.adc3Ratio", 1); + adc4Ratio = Context.getConfig().getDouble("granit.adc4Ratio", 1); + } + + public static void appendChecksum(ByteBuf buffer, int length) { + buffer.writeByte('*'); + int checksum = Checksum.xor(buffer.nioBuffer(0, length)) & 0xFF; + String checksumString = String.format("%02X", checksum); + buffer.writeBytes(checksumString.getBytes(StandardCharsets.US_ASCII)); + buffer.writeByte('\r'); buffer.writeByte('\n'); + } + + private static void sendResponseCurrent(Channel channel, int deviceId, long time) { + ByteBuf response = Unpooled.buffer(); + response.writeBytes("BB+UGRC~".getBytes(StandardCharsets.US_ASCII)); + response.writeShortLE(6); // length + response.writeInt((int) time); + response.writeShortLE(deviceId); + appendChecksum(response, 16); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + + private static void sendResponseArchive(Channel channel, int deviceId, int packNum) { + ByteBuf response = Unpooled.buffer(); + response.writeBytes("BB+ARCF~".getBytes(StandardCharsets.US_ASCII)); + response.writeShortLE(4); // length + response.writeShortLE(packNum); + response.writeShortLE(deviceId); + appendChecksum(response, 14); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + + private void decodeStructure(ByteBuf buf, Position position) { + short flags = buf.readUnsignedByte(); + position.setValid(BitUtil.check(flags, 7)); + if (BitUtil.check(flags, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + + short satDel = buf.readUnsignedByte(); + position.set(Position.KEY_SATELLITES, BitUtil.from(satDel, 4)); + + int pdop = BitUtil.to(satDel, 4); + position.set(Position.KEY_PDOP, pdop); + + int lonDegrees = buf.readUnsignedByte(); + int latDegrees = buf.readUnsignedByte(); + int lonMinutes = buf.readUnsignedShortLE(); + int latMinutes = buf.readUnsignedShortLE(); + + double latitude = latDegrees + latMinutes / 60000.0; + double longitude = lonDegrees + lonMinutes / 60000.0; + + if (position.getValid()) { + if (!BitUtil.check(flags, 4)) { + latitude = -latitude; + } + if (!BitUtil.check(flags, 5)) { + longitude = -longitude; + } + } + + position.setLongitude(longitude); + position.setLatitude(latitude); + + position.setSpeed(buf.readUnsignedByte()); + + int course = buf.readUnsignedByte(); + if (BitUtil.check(flags, 6)) { + course = course | 0x100; + } + position.setCourse(course); + + position.set(Position.KEY_DISTANCE, buf.readShortLE()); + + int analogIn1 = buf.readUnsignedByte(); + int analogIn2 = buf.readUnsignedByte(); + int analogIn3 = buf.readUnsignedByte(); + int analogIn4 = buf.readUnsignedByte(); + + int analogInHi = buf.readUnsignedByte(); + + analogIn1 = analogInHi << 8 & 0x300 | analogIn1; + analogIn2 = analogInHi << 6 & 0x300 | analogIn2; + analogIn3 = analogInHi << 4 & 0x300 | analogIn3; + analogIn4 = analogInHi << 2 & 0x300 | analogIn4; + + position.set(Position.PREFIX_ADC + 1, analogIn1 * adc1Ratio); + position.set(Position.PREFIX_ADC + 2, analogIn2 * adc2Ratio); + position.set(Position.PREFIX_ADC + 3, analogIn3 * adc3Ratio); + position.set(Position.PREFIX_ADC + 4, analogIn4 * adc4Ratio); + + position.setAltitude(buf.readUnsignedByte() * 10); + + int output = buf.readUnsignedByte(); + for (int i = 0; i < 8; i++) { + position.set(Position.PREFIX_IO + (i + 1), BitUtil.check(output, i)); + } + buf.readUnsignedByte(); // status message buffer + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int indexTilde = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '~'); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + + if (deviceSession != null && indexTilde == -1) { + String bufString = buf.toString(StandardCharsets.US_ASCII); + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date()); + getLastLocation(position, new Date()); + position.setValid(false); + position.set(Position.KEY_RESULT, bufString); + return position; + } + + if (buf.readableBytes() < HEADER_LENGTH) { + return null; + } + String header = buf.readSlice(HEADER_LENGTH).toString(StandardCharsets.US_ASCII); + + if (header.equals("+RRCB~")) { + + buf.skipBytes(2); // binary length 26 + int deviceId = buf.readUnsignedShortLE(); + deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); + if (deviceSession == null) { + return null; + } + long unixTime = buf.readUnsignedIntLE(); + if (channel != null) { + sendResponseCurrent(channel, deviceId, unixTime); + } + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(unixTime * 1000)); + + decodeStructure(buf, position); + return position; + + } else if (header.equals("+DDAT~")) { + + buf.skipBytes(2); // binary length + int deviceId = buf.readUnsignedShortLE(); + deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); + if (deviceSession == null) { + return null; + } + byte format = buf.readByte(); + if (format != 4) { + return null; + } + byte nblocks = buf.readByte(); + int packNum = buf.readUnsignedShortLE(); + if (channel != null) { + sendResponseArchive(channel, deviceId, packNum); + } + List positions = new ArrayList<>(); + while (nblocks > 0) { + nblocks--; + long unixTime = buf.readUnsignedIntLE(); + int timeIncrement = buf.getUnsignedShortLE(buf.readerIndex() + 120); + for (int i = 0; i < 6; i++) { + if (buf.getUnsignedByte(buf.readerIndex()) != 0xFE) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.setTime(new Date((unixTime + i * timeIncrement) * 1000)); + decodeStructure(buf, position); + position.set(Position.KEY_ARCHIVE, true); + positions.add(position); + } else { + buf.skipBytes(20); // skip filled 0xFE structure + } + } + buf.skipBytes(2); // increment + } + return positions; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/GranitProtocolEncoder.java b/src/main/java/org/traccar/protocol/GranitProtocolEncoder.java new file mode 100644 index 000000000..6345ff971 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GranitProtocolEncoder.java @@ -0,0 +1,48 @@ +/* + * Copyright 2016 - 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. + * 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.nio.charset.StandardCharsets; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.model.Command; + +public class GranitProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeCommand(String commandString) { + ByteBuf buffer = Unpooled.buffer(); + buffer.writeBytes(commandString.getBytes(StandardCharsets.US_ASCII)); + GranitProtocolDecoder.appendChecksum(buffer, commandString.length()); + return buffer; + } + + @Override + protected Object encodeCommand(Command command) { + switch (command.getType()) { + case Command.TYPE_IDENTIFICATION: + return encodeCommand("BB+IDNT"); + case Command.TYPE_REBOOT_DEVICE: + return encodeCommand("BB+RESET"); + case Command.TYPE_POSITION_SINGLE: + return encodeCommand("BB+RRCD"); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java b/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java new file mode 100644 index 000000000..7d5518c17 --- /dev/null +++ b/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class GranitProtocolSmsEncoder extends StringProtocolEncoder { + + @Override + protected String encodeCommand(Command command) { + switch (command.getType()) { + case Command.TYPE_REBOOT_DEVICE: + return "BB+RESET"; + case Command.TYPE_POSITION_PERIODIC: + return formatCommand(command, "BB+BBMD={%s}", Command.KEY_FREQUENCY); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Gt02Protocol.java b/src/main/java/org/traccar/protocol/Gt02Protocol.java new file mode 100644 index 000000000..f412ee720 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gt02Protocol.java @@ -0,0 +1,35 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Gt02Protocol extends BaseProtocol { + + public Gt02Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0)); + pipeline.addLast(new Gt02ProtocolDecoder(Gt02Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java new file mode 100644 index 000000000..78a3fd3ee --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java @@ -0,0 +1,125 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class Gt02ProtocolDecoder extends BaseProtocolDecoder { + + public Gt02ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_DATA = 0x10; + public static final int MSG_HEARTBEAT = 0x1A; + public static final int MSG_RESPONSE = 0x1C; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.readByte(); // size + + Position position = new Position(getProtocolName()); + + // Zero for location messages + int power = buf.readUnsignedByte(); + int gsm = buf.readUnsignedByte(); + + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, buf.readUnsignedShort()); + + int type = buf.readUnsignedByte(); + + if (type == MSG_HEARTBEAT) { + + getLastLocation(position, null); + + position.set(Position.KEY_POWER, power); + position.set(Position.KEY_RSSI, gsm); + + if (channel != null) { + byte[] response = {0x54, 0x68, 0x1A, 0x0D, 0x0A}; + channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(response), remoteAddress)); + } + + } else if (type == MSG_DATA) { + + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + double latitude = buf.readUnsignedInt() / (60.0 * 30000.0); + double longitude = buf.readUnsignedInt() / (60.0 * 30000.0); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedShort()); + + buf.skipBytes(3); // reserved + + long flags = buf.readUnsignedInt(); + position.setValid(BitUtil.check(flags, 0)); + if (!BitUtil.check(flags, 1)) { + latitude = -latitude; + } + if (!BitUtil.check(flags, 2)) { + longitude = -longitude; + } + + position.setLatitude(latitude); + position.setLongitude(longitude); + + } else if (type == MSG_RESPONSE) { + + getLastLocation(position, null); + + position.set(Position.KEY_RESULT, + buf.readSlice(buf.readUnsignedByte()).toString(StandardCharsets.US_ASCII)); + + } else { + + return null; + + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gt06FrameDecoder.java b/src/main/java/org/traccar/protocol/Gt06FrameDecoder.java new file mode 100644 index 000000000..cc934be42 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gt06FrameDecoder.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class Gt06FrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 5) { + return null; + } + + int length = 2 + 2; // head and tail + + if (buf.getByte(buf.readerIndex()) == 0x78) { + length += 1 + buf.getUnsignedByte(buf.readerIndex() + 2); + } else { + length += 2 + buf.getUnsignedShort(buf.readerIndex() + 2); + } + + if (buf.readableBytes() >= length && buf.getUnsignedShort(buf.readerIndex() + length - 2) == 0x0d0a) { + return buf.readRetainedSlice(length); + } + + int endIndex = buf.readerIndex() - 1; + do { + endIndex = buf.indexOf(endIndex + 1, buf.writerIndex(), (byte) 0x0d); + if (endIndex > 0 && buf.writerIndex() > endIndex + 1 && buf.getByte(endIndex + 1) == 0x0a) { + return buf.readRetainedSlice(endIndex + 2 - buf.readerIndex()); + } + } while (endIndex > 0); + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gt06Protocol.java b/src/main/java/org/traccar/protocol/Gt06Protocol.java new file mode 100644 index 000000000..6e5435cd4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gt06Protocol.java @@ -0,0 +1,40 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class Gt06Protocol extends BaseProtocol { + + public Gt06Protocol() { + setSupportedDataCommands( + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_CUSTOM); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Gt06FrameDecoder()); + pipeline.addLast(new Gt06ProtocolEncoder()); + pipeline.addLast(new Gt06ProtocolDecoder(Gt06Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java new file mode 100644 index 000000000..1f8fb66dd --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -0,0 +1,929 @@ +/* + * Copyright 2012 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Device; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; +import java.util.TimeZone; +import java.util.regex.Pattern; + +public class Gt06ProtocolDecoder extends BaseProtocolDecoder { + + private final Map photos = new HashMap<>(); + + public Gt06ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 0x01; + public static final int MSG_GPS = 0x10; + public static final int MSG_LBS = 0x11; + public static final int MSG_GPS_LBS_1 = 0x12; + public static final int MSG_GPS_LBS_2 = 0x22; + public static final int MSG_STATUS = 0x13; + public static final int MSG_SATELLITE = 0x14; + public static final int MSG_STRING = 0x15; + public static final int MSG_GPS_LBS_STATUS_1 = 0x16; + public static final int MSG_WIFI = 0x17; + public static final int MSG_GPS_LBS_STATUS_2 = 0x26; + public static final int MSG_GPS_LBS_STATUS_3 = 0x27; + public static final int MSG_LBS_MULTIPLE = 0x28; + public static final int MSG_LBS_WIFI = 0x2C; + public static final int MSG_LBS_EXTEND = 0x18; + public static final int MSG_LBS_STATUS = 0x19; + public static final int MSG_GPS_PHONE = 0x1A; + public static final int MSG_GPS_LBS_EXTEND = 0x1E; + public static final int MSG_HEARTBEAT = 0x23; + public static final int MSG_ADDRESS_REQUEST = 0x2A; + public static final int MSG_ADDRESS_RESPONSE = 0x97; + public static final int MSG_AZ735_GPS = 0x32; + public static final int MSG_AZ735_ALARM = 0x33; + public static final int MSG_X1_GPS = 0x34; + public static final int MSG_X1_PHOTO_INFO = 0x35; + public static final int MSG_X1_PHOTO_DATA = 0x36; + public static final int MSG_WIFI_2 = 0x69; + public static final int MSG_COMMAND_0 = 0x80; + public static final int MSG_COMMAND_1 = 0x81; + public static final int MSG_COMMAND_2 = 0x82; + public static final int MSG_TIME_REQUEST = 0x8A; + public static final int MSG_INFO = 0x94; + public static final int MSG_STRING_INFO = 0x21; + public static final int MSG_GPS_2 = 0xA0; + public static final int MSG_LBS_2 = 0xA1; + public static final int MSG_WIFI_3 = 0xA2; + public static final int MSG_FENCE_SINGLE = 0xA3; + public static final int MSG_FENCE_MULTI = 0xA4; + public static final int MSG_LBS_ALARM = 0xA5; + public static final int MSG_LBS_ADDRESS = 0xA7; + public static final int MSG_OBD = 0x8C; + public static final int MSG_DTC = 0x65; + public static final int MSG_PID = 0x66; + + private static boolean isSupported(int type) { + return hasGps(type) || hasLbs(type) || hasStatus(type); + } + + private static boolean hasGps(int type) { + switch (type) { + case MSG_GPS: + case MSG_GPS_LBS_1: + case MSG_GPS_LBS_2: + case MSG_GPS_LBS_STATUS_1: + case MSG_GPS_LBS_STATUS_2: + case MSG_GPS_LBS_STATUS_3: + case MSG_GPS_PHONE: + case MSG_GPS_LBS_EXTEND: + case MSG_GPS_2: + case MSG_FENCE_SINGLE: + case MSG_FENCE_MULTI: + return true; + default: + return false; + } + } + + private static boolean hasLbs(int type) { + switch (type) { + case MSG_LBS: + case MSG_LBS_STATUS: + case MSG_GPS_LBS_1: + case MSG_GPS_LBS_2: + case MSG_GPS_LBS_STATUS_1: + case MSG_GPS_LBS_STATUS_2: + case MSG_GPS_LBS_STATUS_3: + case MSG_GPS_2: + case MSG_FENCE_SINGLE: + case MSG_FENCE_MULTI: + case MSG_LBS_ALARM: + case MSG_LBS_ADDRESS: + return true; + default: + return false; + } + } + + private static boolean hasStatus(int type) { + switch (type) { + case MSG_STATUS: + case MSG_LBS_STATUS: + case MSG_GPS_LBS_STATUS_1: + case MSG_GPS_LBS_STATUS_2: + case MSG_GPS_LBS_STATUS_3: + return true; + default: + return false; + } + } + + private static boolean hasLanguage(int type) { + switch (type) { + case MSG_GPS_PHONE: + case MSG_HEARTBEAT: + case MSG_GPS_LBS_STATUS_3: + case MSG_LBS_MULTIPLE: + case MSG_LBS_2: + case MSG_FENCE_MULTI: + return true; + default: + return false; + } + } + + private void sendResponse(Channel channel, boolean extended, int type, int index, ByteBuf content) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + int length = 5 + (content != null ? content.readableBytes() : 0); + if (extended) { + response.writeShort(0x7979); + response.writeShort(length); + } else { + response.writeShort(0x7878); + response.writeByte(length); + } + response.writeByte(type); + if (content != null) { + response.writeBytes(content); + content.release(); + } + response.writeShort(index); + response.writeShort(Checksum.crc16(Checksum.CRC16_X25, + response.nioBuffer(2, response.writerIndex() - 2))); + response.writeByte('\r'); response.writeByte('\n'); // ending + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + private void sendPhotoRequest(Channel channel, int pictureId) { + ByteBuf photo = photos.get(pictureId); + ByteBuf content = Unpooled.buffer(); + content.writeInt(pictureId); + content.writeInt(photo.writerIndex()); + content.writeShort(Math.min(photo.writableBytes(), 1024)); + sendResponse(channel, false, MSG_X1_PHOTO_DATA, 0, content); + } + + private boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) { + + DateBuilder dateBuilder = new DateBuilder(timezone) + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + if (hasLength && buf.readUnsignedByte() == 0) { + return false; + } + + position.set(Position.KEY_SATELLITES, BitUtil.to(buf.readUnsignedByte(), 4)); + + double latitude = buf.readUnsignedInt() / 60.0 / 30000.0; + double longitude = buf.readUnsignedInt() / 60.0 / 30000.0; + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + int flags = buf.readUnsignedShort(); + position.setCourse(BitUtil.to(flags, 10)); + position.setValid(BitUtil.check(flags, 12)); + + if (!BitUtil.check(flags, 10)) { + latitude = -latitude; + } + if (BitUtil.check(flags, 11)) { + longitude = -longitude; + } + + position.setLatitude(latitude); + position.setLongitude(longitude); + + if (BitUtil.check(flags, 14)) { + position.set(Position.KEY_IGNITION, BitUtil.check(flags, 15)); + } + + return true; + } + + private boolean decodeLbs(Position position, ByteBuf buf, boolean hasLength) { + + int length = 0; + if (hasLength) { + length = buf.readUnsignedByte(); + if (length == 0) { + return false; + } + } + + int mcc = buf.readUnsignedShort(); + int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte(); + + position.setNetwork(new Network(CellTower.from( + BitUtil.to(mcc, 15), mnc, buf.readUnsignedShort(), buf.readUnsignedMedium()))); + + if (length > 9) { + buf.skipBytes(length - 9); + } + + return true; + } + + private boolean decodeStatus(Position position, ByteBuf buf) { + + int status = buf.readUnsignedByte(); + + position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 1)); + position.set(Position.KEY_CHARGE, BitUtil.check(status, 2)); + position.set(Position.KEY_BLOCKED, BitUtil.check(status, 7)); + + switch (BitUtil.between(status, 3, 6)) { + case 1: + position.set(Position.KEY_ALARM, Position.ALARM_SHOCK); + break; + case 2: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; + case 3: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case 4: + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + break; + case 7: + position.set(Position.KEY_ALARM, Position.ALARM_REMOVING); + break; + default: + break; + } + + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 100 / 6); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + + return true; + } + + private String decodeAlarm(short value) { + switch (value) { + case 0x01: + return Position.ALARM_SOS; + case 0x02: + return Position.ALARM_POWER_CUT; + case 0x03: + case 0x09: + return Position.ALARM_VIBRATION; + case 0x04: + return Position.ALARM_GEOFENCE_ENTER; + case 0x05: + return Position.ALARM_GEOFENCE_EXIT; + case 0x06: + return Position.ALARM_OVERSPEED; + case 0x0E: + case 0x0F: + return Position.ALARM_LOW_BATTERY; + case 0x11: + return Position.ALARM_POWER_OFF; + case 0x13: + return Position.ALARM_TAMPERING; + case 0x14: + return Position.ALARM_DOOR; + case 0x29: + return Position.ALARM_ACCELERATION; + case 0x30: + return Position.ALARM_BRAKING; + case 0x2A: + case 0x2B: + return Position.ALARM_CORNERING; + case 0x2C: + return Position.ALARM_ACCIDENT; + case 0x23: + return Position.ALARM_FALL_DOWN; + default: + return null; + } + } + + private static final Pattern PATTERN_FUEL = new PatternBuilder() + .text("!AIOIL,") + .number("d+,") // device address + .number("d+.d+,") // output value + .number("(d+.d+),") // temperature + .expression("[^,]+,") // version + .number("dd") // back wave + .number("d") // software status code + .number("d,") // hardware status code + .number("(d+.d+),") // measured value + .expression("[01],") // movement status + .number("d+,") // excited wave times + .number("xx") // checksum + .compile(); + + private Position decodeFuelData(Position position, String sentence) { + Parser parser = new Parser(PATTERN_FUEL, sentence); + if (!parser.matches()) { + return null; + } + + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble(0)); + position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble(0)); + + return position; + } + + private static final Pattern PATTERN_LOCATION = new PatternBuilder() + .text("Current position!") + .number("Lat:([NS])(d+.d+),") // latitude + .number("Lon:([EW])(d+.d+),") // longitude + .text("Course:").number("(d+.d+),") // course + .text("Speed:").number("(d+.d+),") // speed + .text("DateTime:") + .number("(dddd)-(dd)-(dd) +") // date + .number("(dd):(dd):(dd)") // time + .compile(); + + private Position decodeLocationString(Position position, String sentence) { + Parser parser = new Parser(PATTERN_LOCATION, sentence); + if (!parser.matches()) { + return null; + } + + position.setValid(true); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setCourse(parser.nextDouble()); + position.setSpeed(parser.nextDouble()); + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS)); + + return position; + } + + private Object decodeBasic(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + int length = buf.readUnsignedByte(); + int dataLength = length - 5; + int type = buf.readUnsignedByte(); + + DeviceSession deviceSession = null; + if (type != MSG_LOGIN) { + deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + if (deviceSession.getTimeZone() == null) { + deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId())); + } + } + + if (type == MSG_LOGIN) { + + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + buf.readUnsignedShort(); // type + + deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession != null && deviceSession.getTimeZone() == null) { + deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId())); + } + + if (dataLength > 10) { + int extensionBits = buf.readUnsignedShort(); + int hours = (extensionBits >> 4) / 100; + int minutes = (extensionBits >> 4) % 100; + int offset = (hours * 60 + minutes) * 60; + if ((extensionBits & 0x8) != 0) { + offset = -offset; + } + if (deviceSession != null) { + TimeZone timeZone = deviceSession.getTimeZone(); + if (timeZone.getRawOffset() == 0) { + timeZone.setRawOffset(offset * 1000); + deviceSession.setTimeZone(timeZone); + } + } + + } + + if (deviceSession != null) { + sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); + } + + } else if (type == MSG_HEARTBEAT) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + int status = buf.readUnsignedByte(); + position.set(Position.KEY_ARMED, BitUtil.check(status, 0)); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 1)); + position.set(Position.KEY_CHARGE, BitUtil.check(status, 2)); + + if (buf.readableBytes() >= 2 + 6) { + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + } + if (buf.readableBytes() >= 1 + 6) { + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + } + + sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); + + return position; + + } else if (type == MSG_ADDRESS_REQUEST) { + + String response = "NA&&NA&&0##"; + ByteBuf content = Unpooled.buffer(); + content.writeByte(response.length()); + content.writeInt(0); + content.writeBytes(response.getBytes(StandardCharsets.US_ASCII)); + sendResponse(channel, true, MSG_ADDRESS_RESPONSE, 0, content); + + } else if (type == MSG_TIME_REQUEST) { + + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + ByteBuf content = Unpooled.buffer(); + content.writeByte(calendar.get(Calendar.YEAR) - 2000); + content.writeByte(calendar.get(Calendar.MONTH) + 1); + content.writeByte(calendar.get(Calendar.DAY_OF_MONTH)); + content.writeByte(calendar.get(Calendar.HOUR_OF_DAY)); + content.writeByte(calendar.get(Calendar.MINUTE)); + content.writeByte(calendar.get(Calendar.SECOND)); + sendResponse(channel, false, MSG_TIME_REQUEST, 0, content); + + } else if (type == MSG_X1_GPS || type == MSG_X1_PHOTO_INFO) { + + return decodeX1(channel, buf, deviceSession, type); + + } else if (type == MSG_WIFI || type == MSG_WIFI_2) { + + return decodeWifi(channel, buf, deviceSession, type); + + } else if (type == MSG_INFO) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_POWER, buf.readShort() * 0.01); + + return position; + + } else { + + return decodeBasicOther(channel, buf, deviceSession, type, dataLength); + + } + + return null; + } + + private Object decodeX1(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) { + + if (type == MSG_X1_GPS) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedInt(); // data and alarm + + decodeGps(position, buf, false, deviceSession.getTimeZone()); + + buf.readUnsignedShort(); // terminal info + + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedByte(), + buf.readUnsignedShort(), buf.readUnsignedInt()))); + + long driverId = buf.readUnsignedInt(); + if (driverId > 0) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(driverId)); + } + + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + + return position; + + } else if (type == MSG_X1_PHOTO_INFO) { + + buf.skipBytes(6); // time + buf.readUnsignedByte(); // fix status + buf.readUnsignedInt(); // latitude + buf.readUnsignedInt(); // longitude + buf.readUnsignedByte(); // camera id + buf.readUnsignedByte(); // photo source + buf.readUnsignedByte(); // picture format + + ByteBuf photo = Unpooled.buffer(buf.readInt()); + int pictureId = buf.readInt(); + photos.put(pictureId, photo); + sendPhotoRequest(channel, pictureId); + + } + + return null; + } + + private Object decodeWifi(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + ByteBuf time = buf.readSlice(6); + DateBuilder dateBuilder = new DateBuilder() + .setYear(BcdUtil.readInteger(time, 2)) + .setMonth(BcdUtil.readInteger(time, 2)) + .setDay(BcdUtil.readInteger(time, 2)) + .setHour(BcdUtil.readInteger(time, 2)) + .setMinute(BcdUtil.readInteger(time, 2)) + .setSecond(BcdUtil.readInteger(time, 2)); + getLastLocation(position, dateBuilder.getDate()); + + Network network = new Network(); + + int wifiCount = buf.getByte(2); + for (int i = 0; i < wifiCount; i++) { + String mac = String.format("%02x:%02x:%02x:%02x:%02x:%02x", + buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(), + buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + network.addWifiAccessPoint(WifiAccessPoint.from(mac, buf.readUnsignedByte())); + } + + int cellCount = buf.readUnsignedByte(); + int mcc = buf.readUnsignedShort(); + int mnc = buf.readUnsignedByte(); + for (int i = 0; i < cellCount; i++) { + network.addCellTower(CellTower.from( + mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte())); + } + + position.setNetwork(network); + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(0x7878); + response.writeByte(0); + response.writeByte(type); + response.writeBytes(time.resetReaderIndex()); + response.writeByte('\r'); + response.writeByte('\n'); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + + return position; + } + + private Object decodeBasicOther(Channel channel, ByteBuf buf, + DeviceSession deviceSession, int type, int dataLength) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (type == MSG_LBS_MULTIPLE || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI + || type == MSG_LBS_2 || type == MSG_WIFI_3) { + + boolean longFormat = type == MSG_LBS_2 || type == MSG_WIFI_3; + + DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone()) + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + + getLastLocation(position, dateBuilder.getDate()); + + int mcc = buf.readUnsignedShort(); + int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte(); + Network network = new Network(); + for (int i = 0; i < 7; i++) { + int lac = longFormat ? buf.readInt() : buf.readUnsignedShort(); + int cid = longFormat ? (int) buf.readLong() : buf.readUnsignedMedium(); + int rssi = -buf.readUnsignedByte(); + if (lac > 0) { + network.addCellTower(CellTower.from(BitUtil.to(mcc, 15), mnc, lac, cid, rssi)); + } + } + + buf.readUnsignedByte(); // time leads + + if (type != MSG_LBS_MULTIPLE && type != MSG_LBS_2) { + int wifiCount = buf.readUnsignedByte(); + for (int i = 0; i < wifiCount; i++) { + String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); + network.addWifiAccessPoint(WifiAccessPoint.from( + mac.substring(0, mac.length() - 1), buf.readUnsignedByte())); + } + } + + position.setNetwork(network); + + } else if (type == MSG_STRING) { + + getLastLocation(position, null); + + int commandLength = buf.readUnsignedByte(); + + if (commandLength > 0) { + buf.readUnsignedByte(); // server flag (reserved) + position.set(Position.KEY_RESULT, + buf.readSlice(commandLength - 1).toString(StandardCharsets.US_ASCII)); + } + + } else if (isSupported(type)) { + + if (hasGps(type)) { + decodeGps(position, buf, false, deviceSession.getTimeZone()); + } else { + getLastLocation(position, null); + } + + if (hasLbs(type)) { + decodeLbs(position, buf, hasStatus(type)); + } + + if (hasStatus(type)) { + decodeStatus(position, buf); + } + + if (type == MSG_GPS_LBS_1 && buf.readableBytes() == 2 + 6) { + int mask = buf.readUnsignedShort(); + position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(mask, 8 + 6)); + if (BitUtil.check(mask, 8 + 4)) { + int value = BitUtil.to(mask, 8 + 1); + if (BitUtil.check(mask, 8 + 1)) { + value = -value; + } + position.set(Position.PREFIX_TEMP + 1, value); + } else { + int value = BitUtil.to(mask, 8 + 2); + if (BitUtil.check(mask, 8 + 5)) { + position.set(Position.PREFIX_ADC + 1, value); + } else { + position.set(Position.PREFIX_ADC + 1, value * 0.1); + } + } + } + + if (type == MSG_GPS_LBS_1 && buf.readableBytes() == 4 + 6) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + } + + if (type == MSG_GPS_LBS_2 && buf.readableBytes() == 3 + 6) { + position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); // reason + position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0); + } + + } else { + + if (dataLength > 0) { + buf.skipBytes(dataLength); + } + if (type != MSG_COMMAND_0 && type != MSG_COMMAND_1 && type != MSG_COMMAND_2) { + sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); + } + return null; + + } + + if (hasLanguage(type)) { + buf.readUnsignedShort(); + } + + if (type == MSG_GPS_LBS_STATUS_3 || type == MSG_FENCE_MULTI) { + position.set(Position.KEY_GEOFENCE, buf.readUnsignedByte()); + } + + sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); + + return position; + } + + private Object decodeExtended(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + if (deviceSession.getTimeZone() == null) { + deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId())); + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedShort(); // length + int type = buf.readUnsignedByte(); + + if (type == MSG_STRING_INFO) { + + buf.readUnsignedInt(); // server flag + String data; + if (buf.readUnsignedByte() == 1) { + data = buf.readSlice(buf.readableBytes() - 6).toString(StandardCharsets.US_ASCII); + } else { + data = buf.readSlice(buf.readableBytes() - 6).toString(StandardCharsets.UTF_16BE); + } + + if (decodeLocationString(position, data) == null) { + getLastLocation(position, null); + position.set(Position.KEY_RESULT, data); + } + + return position; + + } else if (type == MSG_INFO) { + + int subType = buf.readUnsignedByte(); + + getLastLocation(position, null); + + if (subType == 0x00) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); + return position; + } else if (subType == 0x05) { + int flags = buf.readUnsignedByte(); + position.set(Position.KEY_DOOR, BitUtil.check(flags, 0)); + position.set(Position.PREFIX_IO + 1, BitUtil.check(flags, 2)); + return position; + } else if (subType == 0x0a) { + buf.skipBytes(8); // imei + buf.skipBytes(8); // imsi + position.set("iccid", ByteBufUtil.hexDump(buf.readSlice(8))); + return position; + } else if (subType == 0x0d) { + if (buf.getByte(buf.readerIndex()) != '!') { + buf.skipBytes(6); + } + return decodeFuelData(position, buf.toString( + buf.readerIndex(), buf.readableBytes() - 4 - 2, StandardCharsets.US_ASCII)); + } + + } else if (type == MSG_X1_PHOTO_DATA) { + + int pictureId = buf.readInt(); + + ByteBuf photo = photos.get(pictureId); + + buf.readUnsignedInt(); // offset + buf.readBytes(photo, buf.readUnsignedShort()); + + if (photo.writableBytes() > 0) { + sendPhotoRequest(channel, pictureId); + } else { + Device device = Context.getDeviceManager().getById(deviceSession.getDeviceId()); + position.set( + Position.KEY_IMAGE, Context.getMediaManager().writeFile(device.getUniqueId(), photo, "jpg")); + photos.remove(pictureId).release(); + } + + } else if (type == MSG_AZ735_GPS || type == MSG_AZ735_ALARM) { + + if (!decodeGps(position, buf, true, deviceSession.getTimeZone())) { + getLastLocation(position, position.getDeviceTime()); + } + + if (decodeLbs(position, buf, true)) { + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + } + + buf.skipBytes(buf.readUnsignedByte()); // additional cell towers + buf.skipBytes(buf.readUnsignedByte()); // wifi access point + + int status = buf.readUnsignedByte(); + position.set(Position.KEY_STATUS, status); + + if (type == MSG_AZ735_ALARM) { + switch (status) { + case 0xA0: + position.set(Position.KEY_ARMED, true); + break; + case 0xA1: + position.set(Position.KEY_ARMED, false); + break; + case 0xA2: + case 0xA3: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case 0xA4: + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + break; + case 0xA5: + position.set(Position.KEY_ALARM, Position.ALARM_DOOR); + break; + default: + break; + } + } + + buf.skipBytes(buf.readUnsignedByte()); // reserved extension + + sendResponse(channel, true, type, buf.getShort(buf.writerIndex() - 6), null); + + return position; + + } else if (type == MSG_OBD) { + + DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone()) + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + + getLastLocation(position, dateBuilder.getDate()); + + position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); + + String data = buf.readCharSequence(buf.readableBytes() - 18, StandardCharsets.US_ASCII).toString(); + for (String pair : data.split(",")) { + String[] values = pair.split("="); + switch (Integer.parseInt(values[0].substring(0, 2), 16)) { + case 40: + position.set(Position.KEY_ODOMETER, Integer.parseInt(values[1], 16) * 0.01); + break; + case 43: + position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(values[1], 16) * 0.01); + break; + case 45: + position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[1], 16) * 0.01); + break; + case 53: + position.set(Position.KEY_OBD_SPEED, Integer.parseInt(values[1], 16) * 0.01); + break; + case 54: + position.set(Position.KEY_RPM, Integer.parseInt(values[1], 16) * 0.01); + break; + case 71: + position.set(Position.KEY_FUEL_USED, Integer.parseInt(values[1], 16) * 0.01); + break; + case 73: + position.set(Position.KEY_HOURS, Integer.parseInt(values[1], 16) * 0.01); + break; + case 74: + position.set(Position.KEY_VIN, values[1]); + break; + default: + break; + } + } + + return position; + + } + + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int header = buf.readShort(); + + if (header == 0x7878) { + return decodeBasic(channel, remoteAddress, buf); + } else if (header == 0x7979) { + return decodeExtended(channel, remoteAddress, buf); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java new file mode 100644 index 000000000..05560229f --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java @@ -0,0 +1,78 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Context; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class Gt06ProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeContent(long deviceId, String content) { + + boolean language = Context.getIdentityManager().lookupAttributeBoolean(deviceId, "gt06.language", false, true); + + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte(0x78); + buf.writeByte(0x78); + + buf.writeByte(1 + 1 + 4 + content.length() + 2 + 2 + (language ? 2 : 0)); // message length + + buf.writeByte(0x80); // message type + + buf.writeByte(4 + content.length()); // command length + buf.writeInt(0); + buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); // command + + if (language) { + buf.writeShort(2); // english language + } + + buf.writeShort(0); // message index + + buf.writeShort(Checksum.crc16(Checksum.CRC16_X25, buf.nioBuffer(2, buf.writerIndex() - 2))); + + buf.writeByte('\r'); + buf.writeByte('\n'); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( + command.getDeviceId(), "gt06.alternative", false, true); + + switch (command.getType()) { + case Command.TYPE_ENGINE_STOP: + return encodeContent(command.getDeviceId(), alternative ? "DYD,123456#" : "Relay,1#"); + case Command.TYPE_ENGINE_RESUME: + return encodeContent(command.getDeviceId(), alternative ? "HFYD,123456#" : "Relay,0#"); + case Command.TYPE_CUSTOM: + return encodeContent(command.getDeviceId(), command.getString(Command.KEY_DATA)); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Gt30Protocol.java b/src/main/java/org/traccar/protocol/Gt30Protocol.java new file mode 100644 index 000000000..aa4ad20b1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gt30Protocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Gt30Protocol extends BaseProtocol { + + public Gt30Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Gt30ProtocolDecoder(Gt30Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java new file mode 100644 index 000000000..abf208a46 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java @@ -0,0 +1,114 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Gt30ProtocolDecoder extends BaseProtocolDecoder { + + public Gt30ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$$") + .number("x{4}") // length + .expression("(.{14})") // device id + .number("x{4}") // type + .expression("(.)?") // alarm + .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+)?,") // speed + .number("(d+.d+)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .expression("[^\\|]*") + .number("|(d+.d+)") // hdop + .number("|(-?d+)") // altitude + .number("x{4}") // checksum + .compile(); + + private String decodeAlarm(int value) { + switch (value) { + case 0x01: + case 0x02: + case 0x03: + return Position.ALARM_SOS; + case 0x10: + return Position.ALARM_LOW_BATTERY; + case 0x11: + return Position.ALARM_OVERSPEED; + case 0x12: + return Position.ALARM_GEOFENCE; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next().trim()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.hasNext()) { + position.set(Position.KEY_ALARM, decodeAlarm(parser.next().charAt(0))); + } + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_HDOP, parser.nextDouble()); + + position.setAltitude(parser.nextDouble(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/H02FrameDecoder.java b/src/main/java/org/traccar/protocol/H02FrameDecoder.java new file mode 100644 index 000000000..583ad599f --- /dev/null +++ b/src/main/java/org/traccar/protocol/H02FrameDecoder.java @@ -0,0 +1,95 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class H02FrameDecoder extends BaseFrameDecoder { + + private static final int MESSAGE_SHORT = 32; + private static final int MESSAGE_LONG = 45; + + private int messageLength; + + public H02FrameDecoder(int messageLength) { + this.messageLength = messageLength; + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + char marker = (char) buf.getByte(buf.readerIndex()); + + while (marker != '*' && marker != '$' && marker != 'X' && buf.readableBytes() > 0) { + buf.skipBytes(1); + if (buf.readableBytes() > 0) { + marker = (char) buf.getByte(buf.readerIndex()); + } + } + + switch (marker) { + case '*': + + // Return text message + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '#'); + if (index != -1) { + ByteBuf result = buf.readRetainedSlice(index + 1 - buf.readerIndex()); + while (buf.isReadable() + && (buf.getByte(buf.readerIndex()) == '\r' || buf.getByte(buf.readerIndex()) == '\n')) { + buf.readByte(); // skip new line + } + return result; + } + + break; + + case '$': + + if (messageLength == 0) { + if (buf.readableBytes() == MESSAGE_LONG) { + messageLength = MESSAGE_LONG; + } else { + messageLength = MESSAGE_SHORT; + } + } + + if (buf.readableBytes() >= messageLength) { + return buf.readRetainedSlice(messageLength); + } + + break; + + case 'X': + + if (buf.readableBytes() >= MESSAGE_SHORT) { + return buf.readRetainedSlice(MESSAGE_SHORT); + } + + break; + + default: + + return null; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/H02Protocol.java b/src/main/java/org/traccar/protocol/H02Protocol.java new file mode 100644 index 000000000..251beac5e --- /dev/null +++ b/src/main/java/org/traccar/protocol/H02Protocol.java @@ -0,0 +1,54 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.Context; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class H02Protocol extends BaseProtocol { + + public H02Protocol() { + setSupportedDataCommands( + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_POSITION_PERIODIC + ); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + int messageLength = Context.getConfig().getInteger(getName() + ".messageLength"); + pipeline.addLast(new H02FrameDecoder(messageLength)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new H02ProtocolEncoder()); + pipeline.addLast(new H02ProtocolDecoder(H02Protocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new H02ProtocolEncoder()); + pipeline.addLast(new H02ProtocolDecoder(H02Protocol.this)); + } + }); + } +} diff --git a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java new file mode 100644 index 000000000..c4443a00b --- /dev/null +++ b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java @@ -0,0 +1,583 @@ +/* + * Copyright 2012 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import java.util.regex.Pattern; + +public class H02ProtocolDecoder extends BaseProtocolDecoder { + + public H02ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static double readCoordinate(ByteBuf buf, boolean lon) { + + int degrees = BcdUtil.readInteger(buf, 2); + if (lon) { + degrees = degrees * 10 + (buf.getUnsignedByte(buf.readerIndex()) >> 4); + } + + double result = 0; + if (lon) { + result = buf.readUnsignedByte() & 0x0f; + } + + int length = 6; + if (lon) { + length = 5; + } + + result = result * 10 + BcdUtil.readInteger(buf, length) * 0.0001; + + result /= 60; + result += degrees; + + return result; + } + + private void processStatus(Position position, long status) { + + if (!BitUtil.check(status, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); + } else if (!BitUtil.check(status, 1) || !BitUtil.check(status, 18)) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } else if (!BitUtil.check(status, 2)) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } else if (!BitUtil.check(status, 19)) { + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + } + + position.set(Position.KEY_IGNITION, BitUtil.check(status, 10)); + position.set(Position.KEY_STATUS, status); + + } + + private Integer decodeBattery(int value) { + switch (value) { + case 6: + return 100; + case 5: + return 80; + case 4: + return 60; + case 3: + return 20; + case 2: + return 10; + default: + return null; + } + } + + private Position decodeBinary(ByteBuf buf, Channel channel, SocketAddress remoteAddress) { + + Position position = new Position(getProtocolName()); + + boolean longId = buf.readableBytes() == 42; + + buf.readByte(); // marker + + String id; + if (longId) { + id = ByteBufUtil.hexDump(buf.readSlice(8)).substring(0, 15); + } else { + id = ByteBufUtil.hexDump(buf.readSlice(5)); + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setHour(BcdUtil.readInteger(buf, 2)) + .setMinute(BcdUtil.readInteger(buf, 2)) + .setSecond(BcdUtil.readInteger(buf, 2)) + .setDay(BcdUtil.readInteger(buf, 2)) + .setMonth(BcdUtil.readInteger(buf, 2)) + .setYear(BcdUtil.readInteger(buf, 2)); + position.setTime(dateBuilder.getDate()); + + double latitude = readCoordinate(buf, false); + position.set(Position.KEY_BATTERY_LEVEL, decodeBattery(buf.readUnsignedByte())); + double longitude = readCoordinate(buf, true); + + int flags = buf.readUnsignedByte() & 0x0f; + position.setValid((flags & 0x02) != 0); + if ((flags & 0x04) == 0) { + latitude = -latitude; + } + if ((flags & 0x08) == 0) { + longitude = -longitude; + } + + position.setLatitude(latitude); + position.setLongitude(longitude); + + position.setSpeed(BcdUtil.readInteger(buf, 3)); + position.setCourse((buf.readUnsignedByte() & 0x0f) * 100.0 + BcdUtil.readInteger(buf, 2)); + + processStatus(position, buf.readUnsignedInt()); + + return position; + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("*") + .expression("..,") // manufacturer + .number("(d+)?,") // imei + .groupBegin() + .text("V4,") + .expression("(.*),") // response + .or() + .expression("(V[^,]*),") + .groupEnd() + .number("(?:(dd)(dd)(dd))?,") // time (hhmmss) + .groupBegin() + .expression("([ABV])?,") // validity + .or() + .number("(d+),") // coding scheme + .groupEnd() + .groupBegin() + .number("-(d+)-(d+.d+),") // latitude + .or() + .number("(d+)(dd.d+),") // latitude + .groupEnd() + .expression("([NS]),") + .groupBegin() + .number("-(d+)-(d+.d+),") // longitude + .or() + .number("(d+)(dd.d+),") // longitude + .groupEnd() + .expression("([EW]),") + .number("(d+.?d*),") // speed + .number("(d+.?d*)?,") // course + .number("(?:d+,)?") // battery + .number("(?:(dd)(dd)(dd))?") // date (ddmmyy) + .groupBegin() + .expression(",[^,]*,") + .expression("[^,]*,") + .expression("[^,]*") // sim info + .groupEnd("?") + .groupBegin() + .number(",(x{8})") + .groupBegin() + .number(",(d+),") // odometer + .number("(-?d+),") // temperature + .number("(d+.d+),") // fuel + .number("(-?d+),") // altitude + .number("(x+),") // lac + .number("(x+)") // cid + .or() + .text(",") + .expression("(.*)") // data + .or() + .groupEnd() + .or() + .groupEnd() + .text("#") + .compile(); + + private static final Pattern PATTERN_NBR = new PatternBuilder() + .text("*") + .expression("..,") // manufacturer + .number("(d+),") // imei + .text("NBR,") + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("d+,") // gsm delay time + .number("d+,") // count + .number("((?:d+,d+,d+,)+)") // cells + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(x{8})") // status + .any() + .compile(); + + private static final Pattern PATTERN_LINK = new PatternBuilder() + .text("*") + .expression("..,") // manufacturer + .number("(d+),") // imei + .text("LINK,") + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d+),") // rssi + .number("(d+),") // satellites + .number("(d+),") // battery + .number("(d+),") // steps + .number("(d+),") // turnovers + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(x{8})") // status + .any() + .compile(); + + private static final Pattern PATTERN_V3 = new PatternBuilder() + .text("*") + .expression("..,") // manufacturer + .number("(d+),") // imei + .text("V3,") + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(ddd)") // mcc + .number("(d+),") // mnc + .number("(d+),") // count + .expression("(.*),") // cell info + .number("(x{4}),") // battery + .number("d+,") // reboot info + .text("X,") + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(x{8})") // status + .text("#").optional() + .compile(); + + private static final Pattern PATTERN_VP1 = new PatternBuilder() + .text("*hq,") + .number("(d{15}),") // imei + .text("VP1,") + .groupBegin() + .text("V,") + .number("(d+),") // mcc + .number("(d+),") // mnc + .expression("([^#]+)") // cells + .or() + .expression("[AB],") // validity + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .groupEnd() + .any() + .compile(); + + private void sendResponse(Channel channel, SocketAddress remoteAddress, String id, String type) { + if (channel != null && id != null) { + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + String response = String.format("*HQ,%s,V4,%s,%s#", id, type, dateFormat.format(new Date())); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private Position decodeText(String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + String id = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.hasNext()) { + position.set(Position.KEY_RESULT, parser.next()); + } + + if (parser.hasNext() && parser.next().equals("V1")) { + sendResponse(channel, remoteAddress, id, "V1"); + } + + DateBuilder dateBuilder = new DateBuilder(); + if (parser.hasNext(3)) { + dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + } + + if (parser.hasNext()) { + position.setValid(parser.next().equals("A")); + } + if (parser.hasNext()) { + parser.nextInt(); // coding scheme + position.setValid(true); + } + + if (parser.hasNext(2)) { + position.setLatitude(-parser.nextCoordinate()); + } + if (parser.hasNext(2)) { + position.setLatitude(parser.nextCoordinate()); + } + + if (parser.hasNext(2)) { + position.setLongitude(-parser.nextCoordinate()); + } + if (parser.hasNext(2)) { + position.setLongitude(parser.nextCoordinate()); + } + + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + if (parser.hasNext(3)) { + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + } else { + position.setTime(new Date()); + } + + if (parser.hasNext()) { + processStatus(position, parser.nextLong(16, 0)); + } + + if (parser.hasNext(6)) { + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); + position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble(0)); + + position.setAltitude(parser.nextInt(0)); + + position.setNetwork(new Network(CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0)))); + } + + if (parser.hasNext(4)) { + String[] values = parser.next().split(","); + for (int i = 0; i < values.length; i++) { + position.set(Position.PREFIX_IO + (i + 1), values[i].trim()); + } + } + + return position; + } + + private Position decodeLbs(String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_NBR, sentence); + if (!parser.matches()) { + return null; + } + + String id = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + sendResponse(channel, remoteAddress, id, "NBR"); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + Network network = new Network(); + int mcc = parser.nextInt(0); + int mnc = parser.nextInt(0); + + String[] cells = parser.next().split(","); + for (int i = 0; i < cells.length / 3; i++) { + network.addCellTower(CellTower.from(mcc, mnc, Integer.parseInt(cells[i * 3]), + Integer.parseInt(cells[i * 3 + 1]), Integer.parseInt(cells[i * 3 + 2]))); + } + + position.setNetwork(network); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + getLastLocation(position, dateBuilder.getDate()); + + processStatus(position, parser.nextLong(16, 0)); + + return position; + } + + private Position decodeLink(String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_LINK, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_STEPS, parser.nextInt()); + position.set("turnovers", parser.nextInt()); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + getLastLocation(position, dateBuilder.getDate()); + + processStatus(position, parser.nextLong(16, 0)); + + return position; + } + + private Position decodeV3(String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_V3, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + int mcc = parser.nextInt(); + int mnc = parser.nextInt(); + + int count = parser.nextInt(); + Network network = new Network(); + String[] values = parser.next().split(","); + for (int i = 0; i < count; i++) { + network.addCellTower(CellTower.from( + mcc, mnc, Integer.parseInt(values[i * 4]), Integer.parseInt(values[i * 4 + 1]))); + } + position.setNetwork(network); + + position.set(Position.KEY_BATTERY, parser.nextHexInt()); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + getLastLocation(position, dateBuilder.getDate()); + + processStatus(position, parser.nextLong(16, 0)); + + return position; + } + + private Position decodeVp1(String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_VP1, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.hasNext(3)) { + + getLastLocation(position, null); + + int mcc = parser.nextInt(); + int mnc = parser.nextInt(); + + Network network = new Network(); + for (String cell : parser.next().split("Y")) { + String[] values = cell.split(","); + network.addCellTower(CellTower.from(mcc, mnc, + Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2]))); + } + + position.setNetwork(network); + + } else { + + position.setValid(true); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + position.setTime(new DateBuilder() + .setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)).getDate()); + + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + String marker = buf.toString(0, 1, StandardCharsets.US_ASCII); + + switch (marker) { + case "*": + String sentence = buf.toString(StandardCharsets.US_ASCII).trim(); + int typeStart = sentence.indexOf(',', sentence.indexOf(',') + 1) + 1; + int typeEnd = sentence.indexOf(',', typeStart); + if (typeEnd > 0) { + String type = sentence.substring(typeStart, typeEnd); + switch (type) { + case "NBR": + return decodeLbs(sentence, channel, remoteAddress); + case "LINK": + return decodeLink(sentence, channel, remoteAddress); + case "V3": + return decodeV3(sentence, channel, remoteAddress); + case "VP1": + return decodeVp1(sentence, channel, remoteAddress); + default: + return decodeText(sentence, channel, remoteAddress); + } + } else { + return null; + } + case "$": + return decodeBinary(buf, channel, remoteAddress); + case "X": + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java b/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java new file mode 100644 index 000000000..614a07dd1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com) + * Copyright 2016 - 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. + * 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 org.traccar.Context; +import org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +import java.util.Date; + +public class H02ProtocolEncoder extends StringProtocolEncoder { + + private static final String MARKER = "HQ"; + + private Object formatCommand(Date time, String uniqueId, String type, String... params) { + + StringBuilder result = new StringBuilder( + String.format("*%s,%s,%s,%4$tH%4$tM%4$tS", MARKER, uniqueId, type, time)); + + for (String param : params) { + result.append(",").append(param); + } + + result.append("#"); + + return result.toString(); + } + + protected Object encodeCommand(Command command, Date time) { + String uniqueId = getUniqueId(command.getDeviceId()); + + switch (command.getType()) { + case Command.TYPE_ALARM_ARM: + return formatCommand(time, uniqueId, "SCF", "0", "0"); + case Command.TYPE_ALARM_DISARM: + return formatCommand(time, uniqueId, "SCF", "1", "1"); + case Command.TYPE_ENGINE_STOP: + return formatCommand(time, uniqueId, "S20", "1", "1"); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(time, uniqueId, "S20", "1", "0"); + case Command.TYPE_POSITION_PERIODIC: + String frequency = command.getAttributes().get(Command.KEY_FREQUENCY).toString(); + if (Context.getIdentityManager().lookupAttributeBoolean( + command.getDeviceId(), "h02.alternative", false, true)) { + return formatCommand(time, uniqueId, "D1", frequency); + } else { + return formatCommand(time, uniqueId, "S71", "22", frequency); + } + default: + return null; + } + } + + @Override + protected Object encodeCommand(Command command) { + return encodeCommand(command, new Date()); + } + +} diff --git a/src/main/java/org/traccar/protocol/HaicomProtocol.java b/src/main/java/org/traccar/protocol/HaicomProtocol.java new file mode 100644 index 000000000..6e5760bd4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HaicomProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class HaicomProtocol extends BaseProtocol { + + public HaicomProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '*')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new HaicomProtocolDecoder(HaicomProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java b/src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java new file mode 100644 index 000000000..dd20f2aeb --- /dev/null +++ b/src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java @@ -0,0 +1,109 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class HaicomProtocolDecoder extends BaseProtocolDecoder { + + public HaicomProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$GPRS") + .number("(d+),") // imei + .expression("([^,]+),") // version + .number("(dd)(dd)(dd),") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d)") // flags + .number("(dd)(d{5})") // latitude + .number("(ddd)(d{5}),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+),") // status + .number("(d+)?,") // gprs counting value + .number("(d+)?,") // gps power saving counting value + .number("(d+),") // switch status + .number("(d+)") // relay status + .expression("(?:[LH]{2})?") // power status + .number("#V(d+)") // battery + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_VERSION_FW, parser.next()); + + position.setTime(parser.nextDateTime()); + + int flags = parser.nextInt(0); + + position.setValid(BitUtil.check(flags, 0)); + + double latitude = parser.nextDouble(0) + parser.nextDouble(0) / 60000; + if (BitUtil.check(flags, 2)) { + position.setLatitude(latitude); + } else { + position.setLatitude(-latitude); + } + + double longitude = parser.nextDouble(0) + parser.nextDouble(0) / 60000; + if (BitUtil.check(flags, 1)) { + position.setLongitude(longitude); + } else { + position.setLongitude(-longitude); + } + + position.setSpeed(parser.nextDouble(0) / 10); + position.setCourse(parser.nextDouble(0) / 10); + + position.set(Position.KEY_STATUS, parser.next()); + position.set("gprsCount", parser.next()); + position.set("powersaveCountdown", parser.next()); + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/HomtecsProtocol.java b/src/main/java/org/traccar/protocol/HomtecsProtocol.java new file mode 100644 index 000000000..34dbf0f51 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HomtecsProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class HomtecsProtocol extends BaseProtocol { + + public HomtecsProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new HomtecsProtocolDecoder(HomtecsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java b/src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java new file mode 100644 index 000000000..a93572b5c --- /dev/null +++ b/src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java @@ -0,0 +1,91 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class HomtecsProtocolDecoder extends BaseProtocolDecoder { + + public HomtecsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("([^_]+)") // id + .text("_R") + .number("(x{8}),") // mac ending + .number("(dd)(dd)(dd),") // date (yymmdd) + .number("(dd)(dd)(dd).d+,") // time (hhmmss) + .number("(d+),") // satellites + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(d),") // fix status + .number("(d+.?d*)?,") // hdop + .number("(d+.?d*)?") // altitude + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + String id = parser.next(); + String mac = parser.next(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id, id + "_R" + mac); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.setValid(parser.nextInt(0) > 0); + + position.set(Position.KEY_HDOP, parser.nextDouble(0)); + + position.setAltitude(parser.nextDouble(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/HuaShengFrameDecoder.java b/src/main/java/org/traccar/protocol/HuaShengFrameDecoder.java new file mode 100644 index 000000000..bd52aa9e7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuaShengFrameDecoder.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class HuaShengFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 2) { + return null; + } + + int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0xC0); + if (index != -1) { + ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex()); + + while (buf.readerIndex() <= index) { + int b = buf.readUnsignedByte(); + if (b == 0xDB) { + int ext = buf.readUnsignedByte(); + if (ext == 0xDC) { + result.writeByte(0xC0); + } else if (ext == 0xDD) { + result.writeByte(0xDB); + } + } else { + result.writeByte(b); + } + } + + return result; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocol.java b/src/main/java/org/traccar/protocol/HuaShengProtocol.java new file mode 100644 index 000000000..103f2d501 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuaShengProtocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 2016 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class HuaShengProtocol extends BaseProtocol { + + public HuaShengProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HuaShengFrameDecoder()); + pipeline.addLast(new HuaShengProtocolDecoder(HuaShengProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java new file mode 100644 index 000000000..8a937a194 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java @@ -0,0 +1,155 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class HuaShengProtocolDecoder extends BaseProtocolDecoder { + + public HuaShengProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_POSITION = 0xAA00; + public static final int MSG_POSITION_RSP = 0xFF01; + public static final int MSG_LOGIN = 0xAA02; + public static final int MSG_LOGIN_RSP = 0xFF03; + public static final int MSG_HSO_REQ = 0x0002; + public static final int MSG_HSO_RSP = 0x0003; + + private void sendResponse(Channel channel, int type, int index, ByteBuf content) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0xC0); + response.writeShort(0x0100); + response.writeShort(12 + (content != null ? content.readableBytes() : 0)); + response.writeShort(type); + response.writeShort(0); + response.writeInt(index); + if (content != null) { + response.writeBytes(content); + content.release(); + } + response.writeByte(0xC0); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(1); // start marker + buf.readUnsignedByte(); // flag + buf.readUnsignedByte(); // reserved + buf.readUnsignedShort(); // length + + int type = buf.readUnsignedShort(); + + buf.readUnsignedShort(); // checksum + int index = buf.readInt(); + + if (type == MSG_LOGIN) { + + while (buf.readableBytes() > 4) { + int subtype = buf.readUnsignedShort(); + int length = buf.readUnsignedShort() - 4; + if (subtype == 0x0003) { + String imei = buf.readSlice(length).toString(StandardCharsets.US_ASCII); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession != null && channel != null) { + ByteBuf content = Unpooled.buffer(); + content.writeByte(0); // success + sendResponse(channel, MSG_LOGIN_RSP, index, content); + } + } else { + buf.skipBytes(length); + } + } + + } else if (type == MSG_HSO_REQ) { + + sendResponse(channel, MSG_HSO_RSP, index, null); + + } else if (type == MSG_POSITION) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + int status = buf.readUnsignedShort(); + + position.setValid(BitUtil.check(status, 15)); + + position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 14)); + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + + String time = buf.readSlice(12).toString(StandardCharsets.US_ASCII); + + DateBuilder dateBuilder = new DateBuilder() + .setYear(Integer.parseInt(time.substring(0, 2))) + .setMonth(Integer.parseInt(time.substring(2, 4))) + .setDay(Integer.parseInt(time.substring(4, 6))) + .setHour(Integer.parseInt(time.substring(6, 8))) + .setMinute(Integer.parseInt(time.substring(8, 10))) + .setSecond(Integer.parseInt(time.substring(10, 12))); + position.setTime(dateBuilder.getDate()); + + position.setLongitude(buf.readInt() * 0.00001); + position.setLatitude(buf.readInt() * 0.00001); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.setCourse(buf.readUnsignedShort()); + position.setAltitude(buf.readUnsignedShort()); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000); + + while (buf.readableBytes() > 4) { + buf.readUnsignedShort(); // subtype + int length = buf.readUnsignedShort() - 4; + buf.skipBytes(length); + } + + sendResponse(channel, MSG_POSITION_RSP, index, null); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/HuabaoFrameDecoder.java b/src/main/java/org/traccar/protocol/HuabaoFrameDecoder.java new file mode 100644 index 000000000..b520f6be9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuabaoFrameDecoder.java @@ -0,0 +1,58 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class HuabaoFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 2) { + return null; + } + + int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0x7e); + if (index != -1) { + ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex()); + + while (buf.readerIndex() <= index) { + int b = buf.readUnsignedByte(); + if (b == 0x7d) { + int ext = buf.readUnsignedByte(); + if (ext == 0x01) { + result.writeByte(0x7d); + } else if (ext == 0x02) { + result.writeByte(0x7e); + } + } else { + result.writeByte(b); + } + } + + return result; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocol.java b/src/main/java/org/traccar/protocol/HuabaoProtocol.java new file mode 100644 index 000000000..44c9f7ac7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuabaoProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class HuabaoProtocol extends BaseProtocol { + + public HuabaoProtocol() { + setSupportedDataCommands( + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HuabaoFrameDecoder()); + pipeline.addLast(new HuabaoProtocolEncoder()); + pipeline.addLast(new HuabaoProtocolDecoder(HuabaoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java new file mode 100644 index 000000000..6e2e1377b --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -0,0 +1,235 @@ +/* + * Copyright 2015 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; + +public class HuabaoProtocolDecoder extends BaseProtocolDecoder { + + public HuabaoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_GENERAL_RESPONSE = 0x8001; + public static final int MSG_TERMINAL_REGISTER = 0x0100; + public static final int MSG_TERMINAL_REGISTER_RESPONSE = 0x8100; + public static final int MSG_TERMINAL_CONTROL = 0x8105; + public static final int MSG_TERMINAL_AUTH = 0x0102; + public static final int MSG_LOCATION_REPORT = 0x0200; + public static final int MSG_LOCATION_BATCH = 0x0704; + public static final int MSG_OIL_CONTROL = 0XA006; + + public static final int RESULT_SUCCESS = 0; + + public static ByteBuf formatMessage(int type, ByteBuf id, ByteBuf data) { + ByteBuf buf = Unpooled.buffer(); + buf.writeByte(0x7e); + buf.writeShort(type); + buf.writeShort(data.readableBytes()); + buf.writeBytes(id); + buf.writeShort(1); // index + buf.writeBytes(data); + data.release(); + buf.writeByte(Checksum.xor(buf.nioBuffer(1, buf.readableBytes() - 1))); + buf.writeByte(0x7e); + return buf; + } + + private void sendGeneralResponse( + Channel channel, SocketAddress remoteAddress, ByteBuf id, int type, int index) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(index); + response.writeShort(type); + response.writeByte(RESULT_SUCCESS); + channel.writeAndFlush(new NetworkMessage( + formatMessage(MSG_GENERAL_RESPONSE, id, response), remoteAddress)); + } + } + + private String decodeAlarm(long value) { + if (BitUtil.check(value, 0)) { + return Position.ALARM_SOS; + } + if (BitUtil.check(value, 1)) { + return Position.ALARM_OVERSPEED; + } + if (BitUtil.check(value, 5)) { + return Position.ALARM_GPS_ANTENNA_CUT; + } + if (BitUtil.check(value, 4) || BitUtil.check(value, 9) + || BitUtil.check(value, 10) || BitUtil.check(value, 11)) { + return Position.ALARM_FAULT; + } + if (BitUtil.check(value, 8)) { + return Position.ALARM_POWER_OFF; + } + if (BitUtil.check(value, 20)) { + return Position.ALARM_GEOFENCE; + } + if (BitUtil.check(value, 29)) { + return Position.ALARM_ACCIDENT; + } + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // start marker + int type = buf.readUnsignedShort(); + buf.readUnsignedShort(); // body length + ByteBuf id = buf.readSlice(6); // phone number + int index = buf.readUnsignedShort(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(id)); + if (deviceSession == null) { + return null; + } + + if (deviceSession.getTimeZone() == null) { + deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId(), "GMT+8")); + } + + if (type == MSG_TERMINAL_REGISTER) { + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(index); + response.writeByte(RESULT_SUCCESS); + response.writeBytes("authentication".getBytes(StandardCharsets.US_ASCII)); + channel.writeAndFlush(new NetworkMessage( + formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, response), remoteAddress)); + } + + } else if (type == MSG_TERMINAL_AUTH) { + + sendGeneralResponse(channel, remoteAddress, id, type, index); + + } else if (type == MSG_LOCATION_REPORT) { + + return decodeLocation(deviceSession, buf); + + } else if (type == MSG_LOCATION_BATCH) { + + return decodeLocationBatch(deviceSession, buf); + + } + + return null; + } + + private Position decodeLocation(DeviceSession deviceSession, ByteBuf buf) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedInt())); + + int flags = buf.readInt(); + + position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0)); + + position.setValid(BitUtil.check(flags, 1)); + + double lat = buf.readUnsignedInt() * 0.000001; + double lon = buf.readUnsignedInt() * 0.000001; + + if (BitUtil.check(flags, 2)) { + position.setLatitude(-lat); + } else { + position.setLatitude(lat); + } + + if (BitUtil.check(flags, 3)) { + position.setLongitude(-lon); + } else { + position.setLongitude(lon); + } + + position.setAltitude(buf.readShort()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1)); + position.setCourse(buf.readUnsignedShort()); + + DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone()) + .setYear(BcdUtil.readInteger(buf, 2)) + .setMonth(BcdUtil.readInteger(buf, 2)) + .setDay(BcdUtil.readInteger(buf, 2)) + .setHour(BcdUtil.readInteger(buf, 2)) + .setMinute(BcdUtil.readInteger(buf, 2)) + .setSecond(BcdUtil.readInteger(buf, 2)); + position.setTime(dateBuilder.getDate()); + + while (buf.readableBytes() > 2) { + int subtype = buf.readUnsignedByte(); + int length = buf.readUnsignedByte(); + switch (subtype) { + case 0x01: + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); + break; + case 0x30: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; + case 0x31: + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + default: + buf.skipBytes(length); + break; + } + } + + return position; + } + + private List decodeLocationBatch(DeviceSession deviceSession, ByteBuf buf) { + + List positions = new LinkedList<>(); + + int count = buf.readUnsignedShort(); + buf.readUnsignedByte(); // location type + + for (int i = 0; i < count; i++) { + int endIndex = buf.readUnsignedShort() + buf.readerIndex(); + positions.add(decodeLocation(deviceSession, buf)); + buf.readerIndex(endIndex); + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java new file mode 100644 index 000000000..7759790c4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.Context; +import org.traccar.helper.DataConverter; +import org.traccar.model.Command; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class HuabaoProtocolEncoder extends BaseProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( + command.getDeviceId(), "huabao.alternative", false, true); + + ByteBuf id = Unpooled.wrappedBuffer( + DataConverter.parseHex(getUniqueId(command.getDeviceId()))); + try { + ByteBuf data = Unpooled.buffer(); + byte[] time = DataConverter.parseHex(new SimpleDateFormat("yyMMddHHmmss").format(new Date())); + + switch (command.getType()) { + case Command.TYPE_ENGINE_STOP: + if (alternative) { + data.writeByte(0x01); + data.writeBytes(time); + return HuabaoProtocolDecoder.formatMessage( + HuabaoProtocolDecoder.MSG_OIL_CONTROL, id, data); + } else { + data.writeByte(0xf0); + return HuabaoProtocolDecoder.formatMessage( + HuabaoProtocolDecoder.MSG_TERMINAL_CONTROL, id, data); + } + case Command.TYPE_ENGINE_RESUME: + if (alternative) { + data.writeByte(0x00); + data.writeBytes(time); + return HuabaoProtocolDecoder.formatMessage( + HuabaoProtocolDecoder.MSG_OIL_CONTROL, id, data); + } else { + data.writeByte(0xf1); + return HuabaoProtocolDecoder.formatMessage( + HuabaoProtocolDecoder.MSG_TERMINAL_CONTROL, id, data); + } + default: + return null; + } + } finally { + id.release(); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/HunterProProtocol.java b/src/main/java/org/traccar/protocol/HunterProProtocol.java new file mode 100644 index 000000000..9f6424a57 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HunterProProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class HunterProProtocol extends BaseProtocol { + + public HunterProProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r")); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new HunterProProtocolDecoder(HunterProProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java b/src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java new file mode 100644 index 000000000..06bc12d59 --- /dev/null +++ b/src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java @@ -0,0 +1,83 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class HunterProProtocolDecoder extends BaseProtocolDecoder { + + public HunterProProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number(">(d+)<") // identifier + .text("$GPRMC,") + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder(); + dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/IdplProtocol.java b/src/main/java/org/traccar/protocol/IdplProtocol.java new file mode 100644 index 000000000..418178756 --- /dev/null +++ b/src/main/java/org/traccar/protocol/IdplProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class IdplProtocol extends BaseProtocol { + + public IdplProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new IdplProtocolDecoder(IdplProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/IdplProtocolDecoder.java b/src/main/java/org/traccar/protocol/IdplProtocolDecoder.java new file mode 100644 index 000000000..cf3c03d7f --- /dev/null +++ b/src/main/java/org/traccar/protocol/IdplProtocolDecoder.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016 - 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. + * 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.net.SocketAddress; +import java.util.regex.Pattern; + +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.Parser.CoordinateFormat; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +public class IdplProtocolDecoder extends BaseProtocolDecoder { + + public IdplProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("*ID") // start of frame + .number("(d+),") // command code + .number("(d+),") // imei + .number("(dd)(dd)(dd),") // current date (ddmmyy) + .number("(dd)(dd)(dd),") // current time (hhmmss) + .expression("([A|V]),") // gps fix + .number("(dd)(dd).?(d+),([NS]),") // latitude + .number("(ddd)(dd).?(d+),([EW]),") // longitude + .number("(d{1,3}.dd),") // speed + .number("(d{1,3}.dd),") // course + .number("(d{1,2}),") // sats + .number("(d{1,3}),") // gsm signal strength + .expression("([A|N|S]),") // vehicle status + .expression("([0|1]),") // main power status + .number("(d.dd),") // internal battery voltage + .expression("([0|1]),") // sos alert + .expression("([0|1]),") // body tamper + .expression("([0|1])([0|1]),") // ac status + ign status + .expression("([0|1|2]),") // output1 status + .number("(d{1,3}),") // adc1 + .number("(d{1,3}),") // adc2 + .expression("([0-9A-Z]{3}),") // software version + .expression("([L|R]),") // message type + .number("(x{4})#") // crc + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_TYPE, parser.nextInt(0)); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(CoordinateFormat.DEG_MIN_MIN_HEM)); + position.setLongitude(parser.nextCoordinate(CoordinateFormat.DEG_MIN_MIN_HEM)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_RSSI, parser.nextInt(0)); + position.set("vehicleStatus", parser.next()); + position.set(Position.KEY_POWER, parser.nextInt(0)); + position.set(Position.KEY_BATTERY, parser.nextDouble(0)); + if (parser.nextInt(0) == 1) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + parser.nextInt(0); // body tamper + position.set("acStatus", parser.nextInt(0)); + position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); + position.set(Position.KEY_OUTPUT, parser.nextInt(0)); + position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); + position.set(Position.PREFIX_ADC + 2, parser.nextInt(0)); + position.set(Position.KEY_VERSION_FW, parser.next()); + position.set(Position.KEY_ARCHIVE, parser.next().equals("R")); + + parser.next(); // checksum + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/IntellitracFrameDecoder.java b/src/main/java/org/traccar/protocol/IntellitracFrameDecoder.java new file mode 100644 index 000000000..8322e65ba --- /dev/null +++ b/src/main/java/org/traccar/protocol/IntellitracFrameDecoder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.LineBasedFrameDecoder; +import org.traccar.NetworkMessage; + +public class IntellitracFrameDecoder extends LineBasedFrameDecoder { + + private static final int MESSAGE_MINIMUM_LENGTH = 0; + + public IntellitracFrameDecoder(int maxFrameLength) { + super(maxFrameLength); + } + + // example of sync header: 0xFA 0xF8 0x1B 0x01 0x81 0x60 0x33 0x3C + + @Override + protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) throws Exception { + + // Check minimum length + if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { + return null; + } + + // Check for sync packet + if (buf.getUnsignedShort(buf.readerIndex()) == 0xFAF8) { + ByteBuf syncMessage = buf.readRetainedSlice(8); + if (ctx != null && ctx.channel() != null) { + ctx.channel().writeAndFlush(new NetworkMessage(syncMessage, ctx.channel().remoteAddress())); + } + } + + return super.decode(ctx, buf); + } + +} diff --git a/src/main/java/org/traccar/protocol/IntellitracProtocol.java b/src/main/java/org/traccar/protocol/IntellitracProtocol.java new file mode 100644 index 000000000..3abf40da7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/IntellitracProtocol.java @@ -0,0 +1,38 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class IntellitracProtocol extends BaseProtocol { + + public IntellitracProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new IntellitracFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new IntellitracProtocolDecoder(IntellitracProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java b/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java new file mode 100644 index 000000000..897606270 --- /dev/null +++ b/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java @@ -0,0 +1,117 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class IntellitracProtocolDecoder extends BaseProtocolDecoder { + + public IntellitracProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression(".+,").optional() + .number("(d+),") // identifier + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(-?d+.?d*),") // altitude + .number("(d+),") // satellites + .number("(d+),") // index + .number("(d+),") // input + .number("(d+),?") // output + .number("(d+.d+)?,?") // adc1 + .number("(d+.d+)?,?") // adc2 + .groupBegin() + .number("d{14},d+,") + .number("(d+),") // vss + .number("(d+),") // rpm + .number("(-?d+),") // coolant + .number("(d+),") // fuel + .number("(d+),") // fuel consumption + .number("(-?d+),") // fuel temperature + .number("(d+),") // charger pressure + .number("(d+),") // tpl + .number("(d+),") // axle weight + .number("(d+)") // odometer + .groupEnd("?") + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setValid(true); + position.setLongitude(parser.nextDouble()); + position.setLatitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + position.setAltitude(parser.nextDouble()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_INDEX, parser.nextLong()); + position.set(Position.KEY_INPUT, parser.nextInt()); + position.set(Position.KEY_OUTPUT, parser.nextInt()); + + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); + + // J1939 data + position.set(Position.KEY_OBD_SPEED, parser.nextInt()); + position.set(Position.KEY_RPM, parser.nextInt()); + position.set("coolant", parser.nextInt()); + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); + position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); + position.set("chargerPressure", parser.nextInt()); + position.set("tpl", parser.nextInt()); + position.set(Position.KEY_AXLE_WEIGHT, parser.nextInt()); + position.set(Position.KEY_OBD_ODOMETER, parser.nextInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ItsProtocol.java b/src/main/java/org/traccar/protocol/ItsProtocol.java new file mode 100644 index 000000000..f53600dc9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ItsProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ItsProtocol extends BaseProtocol { + + public ItsProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '*')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new ItsProtocolDecoder(ItsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java new file mode 100644 index 000000000..482f34e65 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java @@ -0,0 +1,170 @@ +/* + * Copyright 2018 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class ItsProtocolDecoder extends BaseProtocolDecoder { + + public ItsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("[^$]*") + .text("$") + .expression(",?[^,]+,") // event + .groupBegin() + .expression("[^,]+,") // vendor + .expression("[^,]+,") // firmware version + .expression("[^,]+,") // type + .number("d+,") + .expression("[LH],") // history + .or() + .expression("[^,]+,") // type + .groupEnd() + .number("(d{15}),") // imei + .groupBegin() + .expression("(..),") // status + .or() + .expression("[^,]*,") // vehicle registration + .number("([01]),") // valid + .groupEnd() + .number("(dd),?(dd),?(dddd),") // date (ddmmyyyy) + .number("(dd),?(dd),?(dd),") // time (hhmmss) + .expression("([AV]),").optional() // valid + .number("(d+.d+),([NS]),") // latitude + .number("(d+.d+),([EW]),") // longitude + .groupBegin() + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(d+),") // satellites + .groupBegin() + .number("(d+.?d*),") // altitude + .number("d+.?d*,") // pdop + .number("d+.?d*,") // hdop + .expression("[^,]*,") + .number("([01]),") // ignition + .number("([01]),") // charging + .number("(d+.?d*),") // power + .number("(d+.?d*),") // battery + .number("[01],") // emergency + .expression("[CO]?,") // tamper + .number("(?:x+,){5}") // main cell + .number("(?:-?x+,){12}") // other cells + .number("([01]{4}),") // inputs + .number("([01]{2}),") // outputs + .groupEnd("?") + .or() + .number("(-?d+.d+),") // altitude + .number("(d+.d+),") // speed + .groupEnd() + .any() + .compile(); + + private String decodeAlarm(String status) { + switch (status) { + case "WD": + case "EA": + return Position.ALARM_SOS; + case "BL": + return Position.ALARM_LOW_BATTERY; + case "HB": + return Position.ALARM_BRAKING; + case "HA": + return Position.ALARM_ACCELERATION; + case "RT": + return Position.ALARM_CORNERING; + case "OS": + return Position.ALARM_OVERSPEED; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (channel != null && sentence.startsWith("$,01,")) { + channel.writeAndFlush(new NetworkMessage("$,1,*", remoteAddress)); + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.hasNext()) { + position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); + } + + if (parser.hasNext()) { + position.setValid(parser.nextInt() == 1); + } + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + if (parser.hasNext()) { + position.setValid(parser.next().equals("A")); + } + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + + if (parser.hasNext(3)) { + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + } + + if (parser.hasNext(7)) { + position.setAltitude(parser.nextDouble()); + position.set(Position.KEY_IGNITION, parser.nextInt() > 0); + position.set(Position.KEY_CHARGE, parser.nextInt() > 0); + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_INPUT, parser.nextBinInt()); + position.set(Position.KEY_OUTPUT, parser.nextBinInt()); + } + + if (parser.hasNext(2)) { + position.setAltitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Ivt401Protocol.java b/src/main/java/org/traccar/protocol/Ivt401Protocol.java new file mode 100644 index 000000000..fb44e4fe9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Ivt401Protocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Ivt401Protocol extends BaseProtocol { + + public Ivt401Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Ivt401ProtocolDecoder(Ivt401Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java new file mode 100644 index 000000000..63556e7a9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java @@ -0,0 +1,183 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Ivt401ProtocolDecoder extends BaseProtocolDecoder { + + public Ivt401ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("(") + .expression("TL[ABLN],") // header + .number("(d+),") // imei + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("([-+]d+.d+),") // latitude + .number("([-+]d+.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(-?d+.?d*),") // altitude + .number("d+,") // satellites or battery status + .number("(d),") // gps status + .number("(d+),") // rssi + .number("(d+),") // input + .number("(d+),") // output + .number("(d+.d+),") // adc + .number("(d+.d+),") // power + .number("(d+.d+),") // battery + .number("(-?d+.?d*),") // pcb temp + .expression("([^,]+),") // temp + .number("(d+),") // movement + .number("(d+.d+),") // acceleration + .number("(-?d+),") // tilt + .number("(d+),") // trip + .number("(d+),") // odometer + .groupBegin() + .number("([01]),") // overspeed + .number("[01],") // input 2 misuse + .number("[01],") // immobilizer + .number("[01],") // temperature alert + .number("[0-2]+,") // geofence + .number("([0-3]),") // harsh driving + .number("[01],") // reconnect + .number("([01]),") // low battery + .number("([01]),") // power disconnected + .number("[01],") // gps failure + .number("([01]),") // towing + .number("[01],") // server unreachable + .number("[128],") // sleep mode + .expression("([^,]+)?,") // driver id + .number("d+,") // sms count + .groupEnd("?") + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setCourse(parser.nextInt()); + position.setAltitude(parser.nextDouble()); + position.setValid(parser.nextInt() > 0); + + position.set(Position.KEY_RSSI, parser.nextInt()); + + String input = parser.next(); + for (int i = 0; i < input.length(); i++) { + int value = Character.getNumericValue(input.charAt(i)); + if (value < 2) { + position.set(Position.PREFIX_IN + (i + 1), value > 0); + } + } + + String output = parser.next(); + for (int i = 0; i < output.length(); i++) { + position.set(Position.PREFIX_OUT + (i + 1), Character.getNumericValue(output.charAt(i)) > 0); + } + + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_DEVICE_TEMP, parser.nextDouble()); + + String temp = parser.next(); + if (temp.startsWith("M")) { + int index = 1; + int startIndex = 1; + int endIndex; + while (startIndex < temp.length()) { + endIndex = temp.indexOf('-', startIndex + 1); + if (endIndex < 0) { + endIndex = temp.indexOf('+', startIndex + 1); + } + if (endIndex < 0) { + endIndex = temp.length(); + } + if (endIndex > 0) { + double value = Double.parseDouble(temp.substring(startIndex, endIndex)); + position.set(Position.PREFIX_TEMP + index++, value); + } + startIndex = endIndex; + } + } else { + position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(temp)); + } + + position.set(Position.KEY_MOTION, parser.nextInt() > 0); + position.set(Position.KEY_ACCELERATION, parser.nextDouble()); + + parser.nextInt(); // tilt + parser.nextInt(); // trip state + + position.set(Position.KEY_ODOMETER, parser.nextLong()); + + if (parser.hasNext(6)) { + position.set(Position.KEY_ALARM, parser.nextInt() == 1 ? Position.ALARM_OVERSPEED : null); + switch (parser.nextInt()) { + case 1: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 2: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 3: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + default: + break; + } + position.set(Position.KEY_ALARM, parser.nextInt() == 1 ? Position.ALARM_LOW_BATTERY : null); + position.set(Position.KEY_ALARM, parser.nextInt() == 1 ? Position.ALARM_POWER_CUT : null); + position.set(Position.KEY_ALARM, parser.nextInt() == 1 ? Position.ALARM_TOW : null); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/JpKorjarFrameDecoder.java b/src/main/java/org/traccar/protocol/JpKorjarFrameDecoder.java new file mode 100644 index 000000000..0eb65c8ef --- /dev/null +++ b/src/main/java/org/traccar/protocol/JpKorjarFrameDecoder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Nyash (nyashh@gmail.com) + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class JpKorjarFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 80) { + return null; + } + + int spaceIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ' '); + if (spaceIndex == -1) { + return null; + } + + int endIndex = buf.indexOf(spaceIndex, buf.writerIndex(), (byte) ','); + if (endIndex == -1) { + return null; + } + + return buf.readRetainedSlice(endIndex + 1); + } + +} diff --git a/src/main/java/org/traccar/protocol/JpKorjarProtocol.java b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java new file mode 100644 index 000000000..fe5b2480d --- /dev/null +++ b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 2016 Nyash (nyashh@gmail.com) + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class JpKorjarProtocol extends BaseProtocol { + + public JpKorjarProtocol() { + addServer(new TrackerServer(false, this.getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new JpKorjarFrameDecoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new JpKorjarProtocolDecoder(JpKorjarProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java b/src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java new file mode 100644 index 000000000..33026918a --- /dev/null +++ b/src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java @@ -0,0 +1,89 @@ +/* + * Copyright 2016 Nyash (nyashh@gmail.com) + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class JpKorjarProtocolDecoder extends BaseProtocolDecoder { + + public JpKorjarProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("KORJAR.PL,") + .number("(d+),") // imei + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d+.d+)([NS]),") // latitude + .number("(d+.d+)([EW]),") // longitude + .number("(d+.d+),") // speed + .number("(d+),") // course + .number("[FL]:(d+.d+)V,") // battery + .number("([01]) ") // valid + .number("(d+) ") // mcc + .number("(d+) ") // mnc + .number("(x+) ") // lac + .number("(x+),") // cid + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_BATTERY, parser.nextDouble(0)); + + position.setValid(parser.nextInt(0) == 1); + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java new file mode 100644 index 000000000..b5d060ecc --- /dev/null +++ b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java @@ -0,0 +1,55 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +import java.text.ParseException; + +public class Jt600FrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + char type = (char) buf.getByte(buf.readerIndex()); + + if (type == '$') { + boolean longFormat = buf.getUnsignedByte(buf.readerIndex() + 1) == 0x75; + int length = buf.getUnsignedShort(buf.readerIndex() + (longFormat ? 8 : 7)) + 10; + if (length <= buf.readableBytes()) { + return buf.readRetainedSlice(length); + } + } else if (type == '(') { + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ')'); + if (endIndex != -1) { + return buf.readRetainedSlice(endIndex + 1); + } + } else { + throw new ParseException(null, 0); // unknown message + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Jt600Protocol.java b/src/main/java/org/traccar/protocol/Jt600Protocol.java new file mode 100644 index 000000000..97c5fa6ce --- /dev/null +++ b/src/main/java/org/traccar/protocol/Jt600Protocol.java @@ -0,0 +1,43 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class Jt600Protocol extends BaseProtocol { + + public Jt600Protocol() { + setSupportedDataCommands( + Command.TYPE_ENGINE_RESUME, + Command.TYPE_ENGINE_STOP, + Command.TYPE_SET_TIMEZONE, + Command.TYPE_REBOOT_DEVICE); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Jt600FrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Jt600ProtocolEncoder()); + pipeline.addLast(new Jt600ProtocolDecoder(Jt600Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java new file mode 100644 index 000000000..1351706e2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java @@ -0,0 +1,375 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.BitBuffer; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class Jt600ProtocolDecoder extends BaseProtocolDecoder { + + public Jt600ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static double convertCoordinate(int raw) { + int degrees = raw / 1000000; + double minutes = (raw % 1000000) / 10000.0; + return degrees + minutes / 60; + } + + private void decodeStatus(Position position, ByteBuf buf) { + + int value = buf.readUnsignedByte(); + + position.set(Position.KEY_IGNITION, BitUtil.check(value, 0)); + position.set(Position.KEY_DOOR, BitUtil.check(value, 6)); + + value = buf.readUnsignedByte(); + + position.set(Position.KEY_CHARGE, BitUtil.check(value, 0)); + position.set(Position.KEY_BLOCKED, BitUtil.check(value, 1)); + + if (BitUtil.check(value, 2)) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + if (BitUtil.check(value, 3) || BitUtil.check(value, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); + } + if (BitUtil.check(value, 4)) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } + + value = buf.readUnsignedByte(); + + if (BitUtil.check(value, 2)) { + position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING); + } + if (BitUtil.check(value, 3)) { + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + } + + buf.readUnsignedByte(); // reserved + + } + + private List decodeBinary(ByteBuf buf, Channel channel, SocketAddress remoteAddress) { + + List positions = new LinkedList<>(); + + buf.readByte(); // header + + boolean longFormat = buf.getUnsignedByte(buf.readerIndex()) == 0x75; + + String id = String.valueOf(Long.parseLong(ByteBufUtil.hexDump(buf.readSlice(5)))); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + int protocolVersion = 0; + if (longFormat) { + protocolVersion = buf.readUnsignedByte(); + } + + int version = BitUtil.from(buf.readUnsignedByte(), 4); + buf.readUnsignedShort(); // length + + while (buf.readableBytes() > 1) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDay(BcdUtil.readInteger(buf, 2)) + .setMonth(BcdUtil.readInteger(buf, 2)) + .setYear(BcdUtil.readInteger(buf, 2)) + .setHour(BcdUtil.readInteger(buf, 2)) + .setMinute(BcdUtil.readInteger(buf, 2)) + .setSecond(BcdUtil.readInteger(buf, 2)); + position.setTime(dateBuilder.getDate()); + + double latitude = convertCoordinate(BcdUtil.readInteger(buf, 8)); + double longitude = convertCoordinate(BcdUtil.readInteger(buf, 9)); + + byte flags = buf.readByte(); + position.setValid((flags & 0x1) == 0x1); + if ((flags & 0x2) == 0) { + latitude = -latitude; + } + position.setLatitude(latitude); + if ((flags & 0x4) == 0) { + longitude = -longitude; + } + position.setLongitude(longitude); + + position.setSpeed(BcdUtil.readInteger(buf, 2)); + position.setCourse(buf.readUnsignedByte() * 2.0); + + if (longFormat) { + + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + buf.readUnsignedInt(); // vehicle id combined + + int status = buf.readUnsignedShort(); + position.set(Position.KEY_ALARM, BitUtil.check(status, 1) ? Position.ALARM_GEOFENCE_ENTER : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 2) ? Position.ALARM_GEOFENCE_EXIT : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 3) ? Position.ALARM_POWER_CUT : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 4) ? Position.ALARM_VIBRATION : null); + position.set(Position.KEY_BLOCKED, BitUtil.check(status, 7)); + position.set(Position.KEY_ALARM, BitUtil.check(status, 8 + 3) ? Position.ALARM_LOW_BATTERY : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 8 + 6) ? Position.ALARM_FAULT : null); + position.set(Position.KEY_STATUS, status); + + int battery = buf.readUnsignedByte(); + if (battery == 0xff) { + position.set(Position.KEY_CHARGE, true); + } else { + position.set(Position.KEY_BATTERY_LEVEL, battery); + } + + CellTower cellTower = CellTower.fromCidLac(buf.readUnsignedShort(), buf.readUnsignedShort()); + cellTower.setSignalStrength((int) buf.readUnsignedByte()); + position.setNetwork(new Network(cellTower)); + + if (protocolVersion == 0x17) { + buf.readUnsignedByte(); // geofence id + buf.skipBytes(3); // reserved + } + + } else if (version == 1) { + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_POWER, buf.readUnsignedByte()); + + buf.readByte(); // other flags and sensors + + position.setAltitude(buf.readUnsignedShort()); + + int cid = buf.readUnsignedShort(); + int lac = buf.readUnsignedShort(); + int rssi = buf.readUnsignedByte(); + + if (cid != 0 && lac != 0) { + CellTower cellTower = CellTower.fromCidLac(cid, lac); + cellTower.setSignalStrength(rssi); + position.setNetwork(new Network(cellTower)); + } else { + position.set(Position.KEY_RSSI, rssi); + } + + } else if (version == 2) { + + int fuel = buf.readUnsignedByte() << 8; + + decodeStatus(position, buf); + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); + + fuel += buf.readUnsignedByte(); + position.set(Position.KEY_FUEL_LEVEL, fuel); + + } else if (version == 3) { + + BitBuffer bitBuffer = new BitBuffer(buf); + + position.set("fuel1", bitBuffer.readUnsigned(12)); + position.set("fuel2", bitBuffer.readUnsigned(12)); + position.set("fuel3", bitBuffer.readUnsigned(12)); + position.set(Position.KEY_ODOMETER, bitBuffer.readUnsigned(20) * 1000); + + int status = bitBuffer.readUnsigned(24); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); + position.set(Position.KEY_STATUS, status); + + } + + positions.add(position); + + } + + buf.readUnsignedByte(); // index + + return positions; + } + + private static final Pattern PATTERN_W01 = new PatternBuilder() + .text("(") + .number("(d+),") // id + .text("W01,") // type + .number("(ddd)(dd.dddd),") // longitude + .expression("([EW]),") + .number("(dd)(dd.dddd),") // latitude + .expression("([NS]),") + .expression("([AV]),") // validity + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+),") // power + .number("(d+),") // gps signal + .number("(d+),") // gsm signal + .number("(d+),") // alert type + .any() + .compile(); + + private Position decodeW01(String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_W01, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setLongitude(parser.nextCoordinate()); + position.setLatitude(parser.nextCoordinate()); + position.setValid(parser.next().equals("A")); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_POWER, parser.nextDouble(0)); + position.set(Position.KEY_GPS, parser.nextInt(0)); + position.set(Position.KEY_RSSI, parser.nextInt(0)); + position.set("alertType", parser.nextInt(0)); + + return position; + } + + private static final Pattern PATTERN_U01 = new PatternBuilder() + .text("(") + .number("(d+),") // id + .number("(Udd),") // type + .number("d+,").optional() // alarm + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([TF]),") // validity + .number("(d+.d+),([NS]),") // latitude + .number("(d+.d+),([EW]),") // longitude + .number("(d+.?d*),") // speed + .number("(d+),") // course + .number("(d+),") // satellites + .number("(d+)%,") // battery + .expression("([01]+),") // status + .number("(d+),") // cid + .number("(d+),") // lac + .number("(d+),") // gsm signal + .number("(d+),") // odometer + .number("(d+)") // serial number + .number(",(xx)").optional() // checksum + .any() + .compile(); + + private Position decodeU01(String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_U01, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + String type = parser.next(); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(parser.next().equals("T")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + + position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); + position.set(Position.KEY_STATUS, parser.nextBinInt(0)); + + CellTower cellTower = CellTower.fromCidLac(parser.nextInt(0), parser.nextInt(0)); + cellTower.setSignalStrength(parser.nextInt(0)); + position.setNetwork(new Network(cellTower)); + + position.set(Position.KEY_ODOMETER, parser.nextLong(0) * 1000); + position.set(Position.KEY_INDEX, parser.nextInt(0)); + + if (channel != null) { + if (type.equals("U01") || type.equals("U02") || type.equals("U03")) { + channel.writeAndFlush(new NetworkMessage("(S39)", remoteAddress)); + } else if (type.equals("U06")) { + channel.writeAndFlush(new NetworkMessage("(S20)", remoteAddress)); + } + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + char first = (char) buf.getByte(0); + + if (first == '$') { + return decodeBinary(buf, channel, remoteAddress); + } else if (first == '(') { + String sentence = buf.toString(StandardCharsets.US_ASCII); + if (sentence.contains("W01")) { + return decodeW01(sentence, channel, remoteAddress); + } else { + return decodeU01(sentence, channel, remoteAddress); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolEncoder.java new file mode 100644 index 000000000..fe5c63c32 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Jt600ProtocolEncoder.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016 - 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. + * 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.TimeZone; + +import org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class Jt600ProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_ENGINE_STOP: + return "(S07,0)"; + case Command.TYPE_ENGINE_RESUME: + return "(S07,1)"; + case Command.TYPE_SET_TIMEZONE: + int offset = TimeZone.getTimeZone(command.getString(Command.KEY_TIMEZONE)).getRawOffset() / 60000; + return "(S09,1," + offset + ")"; + case Command.TYPE_REBOOT_DEVICE: + return "(S17)"; + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/KenjiProtocol.java b/src/main/java/org/traccar/protocol/KenjiProtocol.java new file mode 100644 index 000000000..90c0c511c --- /dev/null +++ b/src/main/java/org/traccar/protocol/KenjiProtocol.java @@ -0,0 +1,40 @@ +/* + * Copyright 2016 Carlos Alvarez (carlos.alvarez.rozas@gmail.com) + * Copyright 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class KenjiProtocol extends BaseProtocol { + + public KenjiProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new KenjiProtocolDecoder(KenjiProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java b/src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java new file mode 100644 index 000000000..63812242a --- /dev/null +++ b/src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java @@ -0,0 +1,110 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class KenjiProtocolDecoder extends BaseProtocolDecoder { + + public KenjiProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text(">") + .number("C(d{6}),") // device id + .number("M(x{6}),") // alarm + .number("O(x{4}),") // output + .number("I(x{4}),") // input + .number("D(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // valid + .number("([NS])(dd)(dd.d+),") // latitude + .number("([EW])(ddd)(dd.d+),") // longitude + .number("T(d+.d+),") // speed + .number("H(d+.d+),") // course + .number("Y(dd)(dd)(dd),") // date (ddmmyy) + .number("G(d+)") // satellites + .any() + .compile(); + + private String decodeAlarm(int value) { + if (BitUtil.check(value, 2)) { + return Position.ALARM_SOS; + } + if (BitUtil.check(value, 4)) { + return Position.ALARM_LOW_BATTERY; + } + if (BitUtil.check(value, 6)) { + return Position.ALARM_MOVEMENT; + } + if (BitUtil.check(value, 1) || BitUtil.check(value, 10) || BitUtil.check(value, 11)) { + return Position.ALARM_VIBRATION; + } + + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_ALARM, decodeAlarm(parser.nextHexInt(0))); + position.set(Position.KEY_OUTPUT, parser.nextHexInt(0)); + position.set(Position.KEY_INPUT, parser.nextHexInt(0)); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/KhdProtocol.java b/src/main/java/org/traccar/protocol/KhdProtocol.java new file mode 100644 index 000000000..cec7158ed --- /dev/null +++ b/src/main/java/org/traccar/protocol/KhdProtocol.java @@ -0,0 +1,40 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class KhdProtocol extends BaseProtocol { + + public KhdProtocol() { + setSupportedDataCommands( + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(512, 3, 2)); + pipeline.addLast(new KhdProtocolEncoder()); + pipeline.addLast(new KhdProtocolDecoder(KhdProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java new file mode 100644 index 000000000..0dd5b085a --- /dev/null +++ b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java @@ -0,0 +1,157 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.Checksum; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class KhdProtocolDecoder extends BaseProtocolDecoder { + + public KhdProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private String readSerialNumber(ByteBuf buf) { + int b1 = buf.readUnsignedByte(); + int b2 = buf.readUnsignedByte() - 0x80; + int b3 = buf.readUnsignedByte() - 0x80; + int b4 = buf.readUnsignedByte(); + return String.format("%02d%02d%02d%02d", b1, b2, b3, b4); + } + + public static final int MSG_LOGIN = 0xB1; + public static final int MSG_CONFIRMATION = 0x21; + public static final int MSG_ON_DEMAND = 0x81; + public static final int MSG_POSITION_UPLOAD = 0x80; + public static final int MSG_POSITION_REUPLOAD = 0x8E; + public static final int MSG_ALARM = 0x82; + public static final int MSG_ADMIN_NUMBER = 0x83; + public static final int MSG_SEND_TEXT = 0x84; + public static final int MSG_REPLY = 0x85; + public static final int MSG_SMS_ALARM_SWITCH = 0x86; + public static final int MSG_PERIPHERAL = 0xA3; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + int type = buf.readUnsignedByte(); + buf.readUnsignedShort(); // size + + if (type == MSG_LOGIN || type == MSG_ADMIN_NUMBER || type == MSG_SEND_TEXT + || type == MSG_SMS_ALARM_SWITCH || type == MSG_POSITION_REUPLOAD) { + + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x29); + response.writeByte(0x29); // header + response.writeByte(MSG_CONFIRMATION); + response.writeShort(5); // size + response.writeByte(buf.getByte(buf.writerIndex() - 2)); + response.writeByte(type); + response.writeByte(buf.writerIndex() > 9 ? buf.getByte(9) : 0); // 10th byte + response.writeByte(Checksum.xor(response.nioBuffer())); + response.writeByte(0x0D); // ending + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + } + + if (type == MSG_ON_DEMAND || type == MSG_POSITION_UPLOAD || type == MSG_POSITION_REUPLOAD + || type == MSG_ALARM || type == MSG_REPLY || type == MSG_PERIPHERAL) { + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, readSerialNumber(buf)); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setYear(BcdUtil.readInteger(buf, 2)) + .setMonth(BcdUtil.readInteger(buf, 2)) + .setDay(BcdUtil.readInteger(buf, 2)) + .setHour(BcdUtil.readInteger(buf, 2)) + .setMinute(BcdUtil.readInteger(buf, 2)) + .setSecond(BcdUtil.readInteger(buf, 2)); + position.setTime(dateBuilder.getDate()); + + position.setLatitude(BcdUtil.readCoordinate(buf)); + position.setLongitude(BcdUtil.readCoordinate(buf)); + position.setSpeed(UnitsConverter.knotsFromKph(BcdUtil.readInteger(buf, 4))); + position.setCourse(BcdUtil.readInteger(buf, 4)); + position.setValid((buf.readUnsignedByte() & 0x80) != 0); + + if (type != MSG_ALARM) { + + position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); + position.set(Position.KEY_STATUS, buf.readUnsignedInt()); + position.set(Position.KEY_HDOP, buf.readUnsignedByte()); + position.set(Position.KEY_VDOP, buf.readUnsignedByte()); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + buf.skipBytes(5); // other location data + + if (type == MSG_PERIPHERAL) { + + buf.readUnsignedShort(); // data length + + int dataType = buf.readUnsignedByte(); + + buf.readUnsignedByte(); // content length + + switch (dataType) { + case 0x01: + position.set(Position.KEY_FUEL_LEVEL, + buf.readUnsignedByte() * 100 + buf.readUnsignedByte()); + break; + case 0x02: + position.set(Position.PREFIX_TEMP + 1, + buf.readUnsignedByte() * 100 + buf.readUnsignedByte()); + break; + default: + break; + } + + } + + } + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java b/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java new file mode 100644 index 000000000..c66129283 --- /dev/null +++ b/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java @@ -0,0 +1,67 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +public class KhdProtocolEncoder extends BaseProtocolEncoder { + + public static final int MSG_CUT_OIL = 0x39; + public static final int MSG_RESUME_OIL = 0x38; + + private ByteBuf encodeCommand(int command, String uniqueId) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte(0x29); + buf.writeByte(0x29); + + buf.writeByte(command); + buf.writeShort(6); // size + + uniqueId = "00000000".concat(uniqueId); + uniqueId = uniqueId.substring(uniqueId.length() - 8); + buf.writeByte(Integer.parseInt(uniqueId.substring(0, 2))); + buf.writeByte(Integer.parseInt(uniqueId.substring(2, 4)) + 0x80); + buf.writeByte(Integer.parseInt(uniqueId.substring(4, 6)) + 0x80); + buf.writeByte(Integer.parseInt(uniqueId.substring(6, 8))); + + buf.writeByte(Checksum.xor(buf.nioBuffer())); + buf.writeByte(0x0D); // ending + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + String uniqueId = getUniqueId(command.getDeviceId()); + + switch (command.getType()) { + case Command.TYPE_ENGINE_STOP: + return encodeCommand(MSG_CUT_OIL, uniqueId); + case Command.TYPE_ENGINE_RESUME: + return encodeCommand(MSG_RESUME_OIL, uniqueId); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/L100FrameDecoder.java b/src/main/java/org/traccar/protocol/L100FrameDecoder.java new file mode 100644 index 000000000..158461895 --- /dev/null +++ b/src/main/java/org/traccar/protocol/L100FrameDecoder.java @@ -0,0 +1,90 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +import java.nio.charset.StandardCharsets; + +public class L100FrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + if (buf.getCharSequence(buf.readerIndex(), 4, StandardCharsets.US_ASCII).toString().equals("ATL,")) { + return decodeNew(buf); + } else { + return decodeOld(buf); + } + } + + private Object decodeOld(ByteBuf buf) { + + int header = buf.getByte(buf.readerIndex()); + boolean obd = header == 'L' || header == 'H'; + + int index; + if (obd) { + index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*'); + } else { + index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02); + if (index < 0) { + index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x04); + if (index < 0) { + return null; + } + } + } + + index += 2; // checksum + + if (buf.writerIndex() >= index) { + if (!obd) { + buf.skipBytes(2); // header + } + ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex() - 2); + buf.skipBytes(2); // footer + return frame; + } + + return null; + } + + private Object decodeNew(ByteBuf buf) { + + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '@'); + if (index < 0) { + return null; + } + + if (buf.writerIndex() >= index + 1) { + ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex()); + buf.skipBytes(1); // delimiter + return frame; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/L100Protocol.java b/src/main/java/org/traccar/protocol/L100Protocol.java new file mode 100644 index 000000000..942029307 --- /dev/null +++ b/src/main/java/org/traccar/protocol/L100Protocol.java @@ -0,0 +1,38 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class L100Protocol extends BaseProtocol { + + public L100Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new L100FrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new L100ProtocolDecoder(L100Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java b/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java new file mode 100644 index 000000000..9868de435 --- /dev/null +++ b/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java @@ -0,0 +1,341 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.ObdDecoder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class L100ProtocolDecoder extends BaseProtocolDecoder { + + public L100ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("ATL") + .expression(",[^,]+,").optional() + .number("(d{15}),") // imei + .text("$GPRMC,") + .number("(dd)(dd)(dd)") // time (hhmmss.sss) + .number(".(ddd)").optional() + .expression(",([AV]),") // validity + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .any() + .text("#") + .number("([01]+),") // io status + .number("(d+.?d*|N.C),") // adc + .expression("[^,]*,") // reserved + .expression("[^,]*,") // reserved + .number("(d+.?d*),") // odometer + .number("(d+.?d*),") // temperature + .number("(d+.?d*),") // battery + .number("(d+),") // rssi + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(x+),") // lac + .number("(x+)") // cid + .any() + .text("ATL") + .compile(); + + private static final Pattern PATTERN_OBD_LOCATION = new PatternBuilder() + .expression("[LH],") // archive + .text("ATL,") + .number("(d{15}),") // imei + .number("(d+),") // type + .number("(d+),") // index + .groupBegin() + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd)(dd),") // date (ddmmyy) + .expression("([AV]),") // validity + .number("(d+.d+);([NS]),") // latitude + .number("(d+.d+);([EW]),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+.d+),") // odometer + .number("(d+.d+),") // battery + .number("(d+),") // rssi + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(d+),") // lac + .number("(x+),") // cid + .number("#(d)(d)(d)(d),") // status + .number("(d),") // overspeed + .text("ATL,") + .groupEnd("?") + .compile(); + + private static final Pattern PATTERN_OBD_DATA = new PatternBuilder() + .expression("[LH],") // archive + .text("ATLOBD,") + .number("(d{15}),") // imei + .number("d+,") // type + .number("d+,") // index + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd)(dd),") // date (ddmmyy) + .expression("[^,]+,") // obd protocol + .expression("(.+)") // data + .compile(); + + private static final Pattern PATTERN_NEW = new PatternBuilder() + .groupBegin() + .text("ATL,") + .expression("[LH],") // archive + .number("(d{15}),") // imei + .groupEnd("?") + .expression("([NPT]),") // alarm + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .number("(d+.d+),([NS]),") // latitude + .number("(d+.d+),([EW]),") // longitude + .number("(d+.?d*),") // speed + .expression("(?:GPS|GSM|INV),") + .number("(d+),") // battery + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(d+),") // lac + .number("(d+)") // cid + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("L") || sentence.startsWith("H")) { + if (sentence.substring(2, 8).equals("ATLOBD")) { + return decodeObdData(channel, remoteAddress, sentence); + } else { + return decodeObdLocation(channel, remoteAddress, sentence); + } + } else if (!sentence.contains("$GPRMC")) { + return decodeNew(channel, remoteAddress, sentence); + } else { + return decodeNormal(channel, remoteAddress, sentence); + } + } + + private Object decodeNormal(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_STATUS, parser.next()); + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.KEY_ODOMETER, parser.nextDouble()); + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + + int rssi = parser.nextInt(); + if (rssi > 0) { + position.setNetwork(new Network(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi))); + } + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(String.valueOf((char) 0x01), remoteAddress)); + } + + return position; + } + + private Object decodeObdLocation(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_OBD_LOCATION, sentence); + if (!parser.matches()) { + return null; + } + + String imei = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + int type = parser.nextInt(); + int index = parser.nextInt(); + + if (type == 1) { + if (channel != null) { + String response = "@" + imei + ",00," + index + ","; + response += "*" + (char) Checksum.xor(response); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setSpeed(parser.nextInt()); + position.setCourse(parser.nextInt()); + + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + + int rssi = parser.nextInt(); + position.setNetwork(new Network(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextHexInt(), rssi))); + + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + parser.next(); // reserved + + switch (parser.nextInt()) { + case 0: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 2: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 1: + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + break; + default: + break; + } + + position.set(Position.KEY_CHARGE, parser.nextInt() == 1); + + if (parser.nextInt() == 1) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } + + return position; + } + + private Object decodeObdData(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_OBD_DATA, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + for (String entry : parser.next().split(",")) { + String[] values = entry.split(":"); + if (values.length == 2 && values[1].charAt(0) != 'X') { + position.add(ObdDecoder.decodeData( + Integer.parseInt(values[0].substring(2), 16), Integer.parseInt(values[1], 16), true)); + } + } + + return position; + } + + private Object decodeNew(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_NEW, sentence); + if (!parser.matches()) { + return null; + } + + String imei = parser.next(); + DeviceSession deviceSession; + if (imei != null) { + deviceSession = getDeviceSession(channel, remoteAddress, imei); + } else { + deviceSession = getDeviceSession(channel, remoteAddress); + } + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + switch (parser.next()) { + case "P": + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + break; + case "T": + position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); + break; + default: + break; + } + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setSpeed(parser.nextDouble()); + + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextHexInt()))); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/LaipacProtocol.java b/src/main/java/org/traccar/protocol/LaipacProtocol.java new file mode 100644 index 000000000..923b08a16 --- /dev/null +++ b/src/main/java/org/traccar/protocol/LaipacProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class LaipacProtocol extends BaseProtocol { + + public LaipacProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new LaipacProtocolDecoder(LaipacProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java new file mode 100644 index 000000000..2f3cbb1b9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -0,0 +1,167 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class LaipacProtocolDecoder extends BaseProtocolDecoder { + + public LaipacProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$AVRMC,") + .expression("([^,]+),") // identifier + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AVRPavrp]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .number("([EW]),") + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .expression("([abZXTSMHFE86430]),") // event code + .expression("([\\d.]+),") // battery voltage + .number("(d+),") // current mileage + .number("(d),") // gps status + .number("(d+),") // adc1 + .number("(d+)") // adc2 + .number(",(xxxx)") // lac + .number("(xxxx),") // cid + .number("(ddd)") // mcc + .number("(ddd)") // mnc + .optional(4) + .text("*") + .number("(xx)") // checksum + .compile(); + + private String decodeAlarm(String event) { + switch (event) { + case "Z": + return Position.ALARM_LOW_BATTERY; + case "X": + return Position.ALARM_GEOFENCE_ENTER; + case "T": + return Position.ALARM_TAMPERING; + case "H": + return Position.ALARM_POWER_OFF; + case "8": + return Position.ALARM_SHOCK; + case "7": + case "4": + return Position.ALARM_GEOFENCE_EXIT; + case "6": + return Position.ALARM_OVERSPEED; + case "3": + return Position.ALARM_SOS; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("$ECHK") && channel != null) { + channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); // heartbeat + return null; + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + String status = parser.next(); + String upperCaseStatus = status.toUpperCase(); + position.setValid(upperCaseStatus.equals("A") || upperCaseStatus.equals("R") || upperCaseStatus.equals("P")); + position.set(Position.KEY_STATUS, status); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + String event = parser.next(); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + position.set(Position.KEY_EVENT, event); + position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); + position.set(Position.KEY_ODOMETER, parser.nextDouble()); + position.set(Position.KEY_GPS, parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); + position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); + + Integer lac = parser.nextHexInt(); + Integer cid = parser.nextHexInt(); + Integer mcc = parser.nextInt(); + Integer mnc = parser.nextInt(); + if (lac != null && cid != null && mcc != null && mnc != null) { + position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid))); + } + + String checksum = parser.next(); + + if (channel != null) { + if (event.equals("3")) { + channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,d*31\r\n", remoteAddress)); + } else if (event.equals("X") || event.equals("4")) { + channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,x*2D\r\n", remoteAddress)); + } else if (event.equals("Z")) { + channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,z*2F\r\n", remoteAddress)); + } else if (Character.isLowerCase(status.charAt(0))) { + String response = "$EAVACK," + event + "," + checksum; + response += Checksum.nmea(response) + "\r\n"; + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/M2cProtocol.java b/src/main/java/org/traccar/protocol/M2cProtocol.java new file mode 100644 index 000000000..9de8526c3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/M2cProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class M2cProtocol extends BaseProtocol { + + public M2cProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(32 * 1024, ']')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new M2cProtocolDecoder(M2cProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/M2cProtocolDecoder.java b/src/main/java/org/traccar/protocol/M2cProtocolDecoder.java new file mode 100644 index 000000000..1460bb176 --- /dev/null +++ b/src/main/java/org/traccar/protocol/M2cProtocolDecoder.java @@ -0,0 +1,131 @@ +/* + * Copyright 2017 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class M2cProtocolDecoder extends BaseProtocolDecoder { + + public M2cProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("#M2C,") + .expression("[^,]+,") // model + .expression("[^,]+,") // firmware + .number("d+,") // protocol + .number("(d+),") // imei + .number("(d+),") // index + .expression("([LH]),") // archive + .number("d+,") // priority + .number("(d+),") // event + .number("(dd)(dd)(dd),") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(-?d+),") // altitude + .number("(d+),") // course + .number("(d+.d+),") // speed + .number("(d+),") // satellites + .number("(d+),") // odometer + .number("(d+),") // input + .number("(d+),") // output + .number("(d+),") // power + .number("(d+),") // battery + .number("(d+),") // adc 1 + .number("(d+),") // adc 2 + .number("(d+.?d*),") // temperature + .any() + .compile(); + + private Position decodePosition(Channel channel, SocketAddress remoteAddress, String line) { + + Parser parser = new Parser(PATTERN, line); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, parser.nextInt()); + + if (parser.next().equals("H")) { + position.set(Position.KEY_ARCHIVE, true); + } + + position.set(Position.KEY_EVENT, parser.nextInt()); + + position.setValid(true); + position.setTime(parser.nextDateTime()); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setAltitude(parser.nextInt()); + position.setCourse(parser.nextInt()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextLong()); + position.set(Position.KEY_INPUT, parser.nextInt()); + position.set(Position.KEY_OUTPUT, parser.nextInt()); + position.set(Position.KEY_POWER, parser.nextInt() * 0.001); + position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); + position.set(Position.PREFIX_ADC + 1, parser.nextInt()); + position.set(Position.PREFIX_ADC + 2, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + sentence = sentence.substring(1); // remove start symbol + + List positions = new LinkedList<>(); + for (String line : sentence.split("\r\n")) { + if (!line.isEmpty()) { + Position position = decodePosition(channel, remoteAddress, line); + if (position != null) { + positions.add(position); + } + } + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/M2mProtocol.java b/src/main/java/org/traccar/protocol/M2mProtocol.java new file mode 100644 index 000000000..dda328a59 --- /dev/null +++ b/src/main/java/org/traccar/protocol/M2mProtocol.java @@ -0,0 +1,35 @@ +/* + * 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. + * 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 io.netty.handler.codec.FixedLengthFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class M2mProtocol extends BaseProtocol { + + public M2mProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new FixedLengthFrameDecoder(23)); + pipeline.addLast(new M2mProtocolDecoder(M2mProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/M2mProtocolDecoder.java b/src/main/java/org/traccar/protocol/M2mProtocolDecoder.java new file mode 100644 index 000000000..21e4a2fd0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/M2mProtocolDecoder.java @@ -0,0 +1,127 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class M2mProtocolDecoder extends BaseProtocolDecoder { + + public M2mProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private boolean firstPacket = true; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + // Remove offset + for (int i = 0; i < buf.readableBytes(); i++) { + int b = buf.getByte(i); + if (b != 0x0b) { + buf.setByte(i, b - 0x20); + } + } + + if (firstPacket) { + + firstPacket = false; + + StringBuilder imei = new StringBuilder(); + for (int i = 0; i < 8; i++) { + int b = buf.readByte(); + if (i != 0) { + imei.append(b / 10); + } + imei.append(b % 10); + } + + getDeviceSession(channel, remoteAddress, imei.toString()); + + } else { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDay(buf.readUnsignedByte() & 0x3f) + .setMonth(buf.readUnsignedByte() & 0x3f) + .setYear(buf.readUnsignedByte()) + .setHour(buf.readUnsignedByte() & 0x3f) + .setMinute(buf.readUnsignedByte() & 0x7f) + .setSecond(buf.readUnsignedByte() & 0x7f); + position.setTime(dateBuilder.getDate()); + + int degrees = buf.readUnsignedByte(); + double latitude = buf.readUnsignedByte(); + latitude += buf.readUnsignedByte() / 100.0; + latitude += buf.readUnsignedByte() / 10000.0; + latitude /= 60; + latitude += degrees; + + int b = buf.readUnsignedByte(); + + degrees = (b & 0x7f) * 100 + buf.readUnsignedByte(); + double longitude = buf.readUnsignedByte(); + longitude += buf.readUnsignedByte() / 100.0; + longitude += buf.readUnsignedByte() / 10000.0; + longitude /= 60; + longitude += degrees; + + if ((b & 0x80) != 0) { + longitude = -longitude; + } + if ((b & 0x40) != 0) { + latitude = -latitude; + } + + position.setValid(true); + position.setLatitude(latitude); + position.setLongitude(longitude); + position.setSpeed(buf.readUnsignedByte()); + + int satellites = buf.readUnsignedByte(); + if (satellites == 0) { + return null; // cell information + } + position.set(Position.KEY_SATELLITES, satellites); + + // decode other data + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/MaestroProtocol.java b/src/main/java/org/traccar/protocol/MaestroProtocol.java new file mode 100644 index 000000000..87453ce7d --- /dev/null +++ b/src/main/java/org/traccar/protocol/MaestroProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.FixedLengthFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class MaestroProtocol extends BaseProtocol { + + public MaestroProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new FixedLengthFrameDecoder(160)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new MaestroProtocolDecoder(MaestroProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java b/src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java new file mode 100644 index 000000000..37b097414 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java @@ -0,0 +1,103 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class MaestroProtocolDecoder extends BaseProtocolDecoder { + + public MaestroProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("@") + .number("(d+),") // imei + .number("d+,") // index + .expression("[^,]+,") // profile + .expression("([01]),") // validity + .number("(d+.d+),") // battery + .number("(d+),") // gsm + .expression("([01]),") // starter + .expression("([01]),") // ignition + .number("(dd)/(dd)/(dd),") // date (yy/mm/dd) + .number("(dd):(dd):(dd),") // time (hh:mm:ss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(d+.?d*),") // altitude + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(d+),") // satellites + .number("(d+.?d*),") // hdop + .number("(d+.?d*)") // odometer + .number(",(d+)").optional() // adc + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.nextInt(0) == 1); + + position.set(Position.KEY_BATTERY, parser.nextDouble(0)); + position.set(Position.KEY_RSSI, parser.nextInt(0)); + position.set(Position.KEY_CHARGE, parser.nextInt(0) == 1); + position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_HDOP, parser.nextDouble(0)); + position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1609.34); + + if (parser.hasNext()) { + position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ManPowerProtocol.java b/src/main/java/org/traccar/protocol/ManPowerProtocol.java new file mode 100644 index 000000000..49d8b1e9f --- /dev/null +++ b/src/main/java/org/traccar/protocol/ManPowerProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ManPowerProtocol extends BaseProtocol { + + public ManPowerProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new ManPowerProtocolDecoder(ManPowerProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java b/src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java new file mode 100644 index 000000000..2c7b7eb40 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class ManPowerProtocolDecoder extends BaseProtocolDecoder { + + public ManPowerProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("simei:") + .number("(d+),") // imei + .expression("[^,]*,[^,]*,") + .expression("([^,]*),") // status + .number("d+,d+,d+.?d*,") + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.dddd),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.dddd),") // longitude + .expression("([EW])?,") + .number("(d+.?d*),") // speed + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_STATUS, parser.next()); + + position.setTime(parser.nextDateTime()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/MegastekFrameDecoder.java b/src/main/java/org/traccar/protocol/MegastekFrameDecoder.java new file mode 100644 index 000000000..347fa24b1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MegastekFrameDecoder.java @@ -0,0 +1,59 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; +import org.traccar.helper.BufferUtil; + +import java.nio.charset.StandardCharsets; + +public class MegastekFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + if (Character.isDigit(buf.getByte(buf.readerIndex()))) { + int length = 4 + Integer.parseInt(buf.toString(buf.readerIndex(), 4, StandardCharsets.US_ASCII)); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } else { + while (buf.getByte(buf.readerIndex()) == '\r' || buf.getByte(buf.readerIndex()) == '\n') { + buf.skipBytes(1); + } + int delimiter = BufferUtil.indexOf("\r\n", buf); + if (delimiter == -1) { + delimiter = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '!'); + } + if (delimiter != -1) { + ByteBuf result = buf.readRetainedSlice(delimiter - buf.readerIndex()); + buf.skipBytes(1); + return result; + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/MegastekProtocol.java b/src/main/java/org/traccar/protocol/MegastekProtocol.java new file mode 100644 index 000000000..e9f5f9fde --- /dev/null +++ b/src/main/java/org/traccar/protocol/MegastekProtocol.java @@ -0,0 +1,38 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class MegastekProtocol extends BaseProtocol { + + public MegastekProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new MegastekFrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new MegastekProtocolDecoder(MegastekProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java b/src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java new file mode 100644 index 000000000..d81cc0eda --- /dev/null +++ b/src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java @@ -0,0 +1,419 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class MegastekProtocolDecoder extends BaseProtocolDecoder { + + public MegastekProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_GPRMC = new PatternBuilder() + .text("$GPRMC,") + .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),([NS]),") // latitude + .number("(d+)(dd.d+),([EW]),") // longitude + .number("(d+.d+)?,") // speed + .number("(d+.d+)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() // checksum + .compile(); + + private static final Pattern PATTERN_SIMPLE = new PatternBuilder() + .expression("[FL],") // flag + .expression("([^,]*),") // alarm + .number("imei:(d+),") // imei + .number("(d+/?d*)?,") // satellites + .number("(d+.d+)?,") // altitude + .number("Battery=(d+)%,,?") // battery + .number("(d)?,") // charger + .number("(d+)?,") // mcc + .number("(d+)?,") // mnc + .number("(xxxx),") // lac + .number("(xxxx);") // cid + .any() // checksum + .compile(); + + private static final Pattern PATTERN_ALTERNATIVE = new PatternBuilder() + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(xxxx),") // lac + .number("(xxxx),") // cid + .number("(d+),") // gsm signal + .number("(d+),") // battery + .number("(d+),") // flags + .number("(d+),") // inputs + .number("(?:(d+),)?") // outputs + .number("(d.?d*),") // adc 1 + .groupBegin() + .number("(d.dd),") // adc 2 + .number("(d.dd),") // adc 3 + .groupEnd("?") + .expression("([^;]+);") // alarm + .any() // checksum + .compile(); + + private boolean parseLocation(String location, Position position) { + + Parser parser = new Parser(PATTERN_GPRMC, location); + if (!parser.matches()) { + return false; + } + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return true; + } + + private Position decodeOld(Channel channel, SocketAddress remoteAddress, String sentence) { + + // Detect type + boolean simple = sentence.charAt(3) == ',' || sentence.charAt(6) == ','; + + // Split message + String id; + String location; + String status; + if (simple) { + + int beginIndex = sentence.indexOf(',') + 1; + int endIndex = sentence.indexOf(',', beginIndex); + id = sentence.substring(beginIndex, endIndex); + + beginIndex = endIndex + 1; + endIndex = sentence.indexOf('*', beginIndex); + if (endIndex != -1) { + endIndex += 3; + } else { + endIndex = sentence.length(); + } + location = sentence.substring(beginIndex, endIndex); + + beginIndex = endIndex + 1; + if (beginIndex > sentence.length()) { + beginIndex = endIndex; + } + status = sentence.substring(beginIndex); + + } else { + + int beginIndex = 3; + int endIndex = beginIndex + 16; + id = sentence.substring(beginIndex, endIndex).trim(); + + beginIndex = endIndex + 2; + endIndex = sentence.indexOf('*', beginIndex) + 3; + location = sentence.substring(beginIndex, endIndex); + + beginIndex = endIndex + 1; + status = sentence.substring(beginIndex); + + } + + Position position = new Position(getProtocolName()); + if (!parseLocation(location, position)) { + return null; + } + + if (simple) { + + Parser parser = new Parser(PATTERN_SIMPLE, status); + if (parser.matches()) { + + position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next(), id); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + String sat = parser.next(); + if (sat.contains("/")) { + position.set(Position.KEY_SATELLITES, Integer.parseInt(sat.split("/")[0])); + position.set(Position.KEY_SATELLITES_VISIBLE, Integer.parseInt(sat.split("/")[1])); + } else { + position.set(Position.KEY_SATELLITES, Integer.parseInt(sat)); + } + + position.setAltitude(parser.nextDouble(0)); + + position.set(Position.KEY_BATTERY_LEVEL, parser.nextDouble(0)); + + String charger = parser.next(); + if (charger != null) { + position.set(Position.KEY_CHARGE, Integer.parseInt(charger) == 1); + } + + if (parser.hasNext(4)) { + position.setNetwork(new Network(CellTower.from( + parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); + } + + } else { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + } + + } else { + + Parser parser = new Parser(PATTERN_ALTERNATIVE, status); + if (parser.matches()) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setNetwork(new Network(CellTower.from(parser.nextInt(0), parser.nextInt(0), + parser.nextHexInt(0), parser.nextHexInt(0), parser.nextInt(0)))); + + position.set(Position.KEY_BATTERY_LEVEL, parser.nextDouble()); + + position.set(Position.KEY_FLAGS, parser.next()); + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + position.set(Position.PREFIX_ADC + 3, parser.next()); + position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); + + } + } + + return position; + } + + private static final Pattern PATTERN_NEW = new PatternBuilder() + .number("dddd").optional() + .text("$MGV") + .number("ddd,") + .number("(d+),") // imei + .expression("[^,]*,") // name + .expression("([RS]),") + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),([NS]),") // latitude + .number("(d+)(dd.d+),([EW]),") // longitude + .number("dd,") + .number("(dd),") // satellites + .number("dd,") + .number("(d+.d+),") // hdop + .number("(d+.d+)?,") // speed + .number("(d+.d+)?,") // course + .number("(-?d+.d+),") // altitude + .number("(d+.d+)?,") // odometer + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(xxxx)?,") // lac + .number("(x+)?,") // cid + .number("(d+)?,") // gsm + .groupBegin() + .number("([01]{4})?,") // input + .number("([01]{4})?,") // output + .number("(d+)?,") // adc1 + .number("(d+)?,") // adc2 + .number("(d+)?,") // adc3 + .or() + .number("(d+),") // input + .number("(d+),") // output + .number("(d+),") // adc1 + .number("(d+),") // adc2 + .number("(d+),") // adc3 + .groupEnd() + .groupBegin() + .number("(-?d+.?d*)") // temperature 1 + .or().text(" ") + .groupEnd("?").text(",") + .groupBegin() + .number("(-?d+.?d*)") // temperature 2 + .or().text(" ") + .groupEnd("?").text(",") + .number("(d+)?,") // rfid + .expression("[^,]*,") + .number("(d+)?,") // battery + .expression("([^,]*)") // alert + .any() + .compile(); + + private Position decodeNew(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_NEW, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.next().equals("S")) { + position.set(Position.KEY_ARCHIVE, true); + } + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_HDOP, parser.nextDouble(0)); + + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + if (parser.hasNext()) { + position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); + } + + int mcc = parser.nextInt(); + int mnc = parser.nextInt(); + Integer lac = parser.nextHexInt(); + Integer cid = parser.nextHexInt(); + Integer rssi = parser.nextInt(); + if (lac != null && cid != null) { + CellTower tower = CellTower.from(mcc, mnc, lac, cid); + if (rssi != null) { + tower.setSignalStrength(rssi); + } + position.setNetwork(new Network(tower)); + } + + if (parser.hasNext(5)) { + position.set(Position.KEY_INPUT, parser.nextBinInt(0)); + position.set(Position.KEY_OUTPUT, parser.nextBinInt(0)); + for (int i = 1; i <= 3; i++) { + position.set(Position.PREFIX_ADC + i, parser.nextInt(0)); + } + } + + if (parser.hasNext(5)) { + position.set(Position.KEY_HEART_RATE, parser.nextInt()); + position.set(Position.KEY_STEPS, parser.nextInt()); + position.set("activityTime", parser.nextInt()); + position.set("lightSleepTime", parser.nextInt()); + position.set("deepSleepTime", parser.nextInt()); + } + + for (int i = 1; i <= 2; i++) { + String adc = parser.next(); + if (adc != null) { + position.set(Position.PREFIX_TEMP + i, Double.parseDouble(adc)); + } + } + + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + String battery = parser.next(); + if (battery != null) { + position.set(Position.KEY_BATTERY, Integer.parseInt(battery)); + } + + position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); + + return position; + } + + private String decodeAlarm(String value) { + value = value.toLowerCase(); + if (value.startsWith("geo")) { + if (value.endsWith("in")) { + return Position.ALARM_GEOFENCE_ENTER; + } else if (value.endsWith("out")) { + return Position.ALARM_GEOFENCE_EXIT; + } + } + switch (value) { + case "poweron": + return Position.ALARM_POWER_ON; + case "poweroff": + return Position.ALARM_POWER_ON; + case "sos": + case "help": + return Position.ALARM_SOS; + case "over speed": + case "overspeed": + return Position.ALARM_OVERSPEED; + case "lowspeed": + return Position.ALARM_LOW_SPEED; + case "low battery": + case "lowbattery": + return Position.ALARM_LOW_BATTERY; + case "vib": + return Position.ALARM_VIBRATION; + case "move in": + return Position.ALARM_GEOFENCE_ENTER; + case "move out": + return Position.ALARM_GEOFENCE_EXIT; + case "error": + return Position.ALARM_FAULT; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.contains("$MG")) { + return decodeNew(channel, remoteAddress, sentence); + } else { + return decodeOld(channel, remoteAddress, sentence); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/MeiligaoFrameDecoder.java b/src/main/java/org/traccar/protocol/MeiligaoFrameDecoder.java new file mode 100644 index 000000000..52f9ae26d --- /dev/null +++ b/src/main/java/org/traccar/protocol/MeiligaoFrameDecoder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class MeiligaoFrameDecoder extends BaseFrameDecoder { + + private static final int MESSAGE_HEADER = 4; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + // Strip not '$' (0x24) bytes from the beginning + while (buf.isReadable() && buf.getUnsignedByte(buf.readerIndex()) != 0x24) { + buf.readByte(); + } + + // Check length and return buffer + if (buf.readableBytes() >= MESSAGE_HEADER) { + int length = buf.getUnsignedShort(buf.readerIndex() + 2); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java new file mode 100644 index 000000000..c307c7318 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java @@ -0,0 +1,52 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class MeiligaoProtocol extends BaseProtocol { + + public MeiligaoProtocol() { + setSupportedDataCommands( + Command.TYPE_POSITION_SINGLE, + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_ALARM_GEOFENCE, + Command.TYPE_SET_TIMEZONE, + Command.TYPE_REQUEST_PHOTO, + Command.TYPE_REBOOT_DEVICE); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new MeiligaoFrameDecoder()); + pipeline.addLast(new MeiligaoProtocolEncoder()); + pipeline.addLast(new MeiligaoProtocolDecoder(MeiligaoProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new MeiligaoProtocolEncoder()); + pipeline.addLast(new MeiligaoProtocolDecoder(MeiligaoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java new file mode 100644 index 000000000..cbfc3660a --- /dev/null +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java @@ -0,0 +1,499 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +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.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +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 photos = new HashMap<>(); + + public MeiligaoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .expression("[^\\|]*") + .groupBegin() + .number("|(d+.d+)?") // hdop + .number("|(-?d+.?d*)?") // altitude + .number("|(xxxx)?") // state + .groupBegin() + .number("|(xxxx),(xxxx)") // adc + .number(",(xxxx)").optional() + .number(",(xxxx)").optional() + .number(",(xxxx)").optional() + .number(",(xxxx)").optional() + .number(",(xxxx)").optional() + .number(",(xxxx)").optional() + .groupBegin() + .number("|x{16,20}") // cell + .number("|(xx)") // rssi + .number("|(x{8})") // odometer + .groupBegin() + .number("|(xx)") // satellites + .text("|") + .expression("(.*)") // driver + .groupEnd("?") + .or() + .number("|(d{1,9})") // odometer + .groupBegin() + .number("|(x{5,})") // rfid + .groupEnd("?") + .groupEnd("?") + .groupEnd("?") + .groupEnd("?") + .any() + .compile(); + + private static final Pattern PATTERN_RFID = new PatternBuilder() + .number("|(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW])") + .compile(); + + private static final Pattern PATTERN_OBD = new PatternBuilder() + .number("(d+.d+),") // battery + .number("(d+),") // rpm + .number("(d+),") // speed + .number("(d+.d+),") // throttle + .number("(d+.d+),") // engine load + .number("(-?d+),") // coolant temp + .number("(d+.d+),") // instantaneous fuel + .number("(d+.d+),") // average fuel + .number("(d+.d+),") // driving range + .number("(d+.?d*),") // odometer + .number("(d+.d+),") // single fuel consumption + .number("(d+.d+),") // total fuel consumption + .number("(d+),") // error code count + .number("(d+),") // hard acceleration count + .number("(d+)") // hard brake count + .compile(); + + private static final Pattern PATTERN_OBDA = new PatternBuilder() + .number("(d+),") // total ignition + .number("(d+.d+),") // total driving time + .number("(d+.d+),") // total idling time + .number("(d+),") // average hot start time + .number("(d+),") // average speed + .number("(d+),") // history highest speed + .number("(d+),") // history highest rpm + .number("(d+),") // total hard acceleration + .number("(d+)") // total hard brake + .compile(); + + public static final int MSG_HEARTBEAT = 0x0001; + public static final int MSG_SERVER = 0x0002; + public static final int MSG_LOGIN = 0x5000; + public static final int MSG_LOGIN_RESPONSE = 0x4000; + public static final int MSG_POSITION = 0x9955; + public static final int MSG_POSITION_LOGGED = 0x9016; + public static final int MSG_ALARM = 0x9999; + public static final int MSG_RFID = 0x9966; + public static final int MSG_RETRANSMISSION = 0x6688; + + 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(ByteBuf buf, Channel channel, SocketAddress remoteAddress) { + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < 7; i++) { + int b = buf.readUnsignedByte(); + + // First digit + int d1 = (b & 0xf0) >> 4; + if (d1 == 0xf) { + break; + } + builder.append(d1); + + // Second digit + int d2 = b & 0x0f; + if (d2 == 0xf) { + break; + } + builder.append(d2); + } + + String id = builder.toString(); + + if (id.length() == 14) { + return getDeviceSession(channel, remoteAddress, id, id + Checksum.luhn(Long.parseLong(id))); + } else { + return getDeviceSession(channel, remoteAddress, id); + } + } + + private static void sendResponse( + Channel channel, SocketAddress remoteAddress, ByteBuf id, int type, ByteBuf msg) { + + if (channel != null) { + ByteBuf buf = Unpooled.buffer( + 2 + 2 + id.readableBytes() + 2 + msg.readableBytes() + 2 + 2); + + buf.writeByte('@'); + buf.writeByte('@'); + buf.writeShort(buf.capacity()); + buf.writeBytes(id); + buf.writeShort(type); + buf.writeBytes(msg); + msg.release(); + buf.writeShort(Checksum.crc16(Checksum.CRC16_CCITT_FALSE, buf.nioBuffer())); + buf.writeByte('\r'); + buf.writeByte('\n'); + + channel.writeAndFlush(new NetworkMessage(buf, remoteAddress)); + } + } + + private String decodeAlarm(short value) { + switch (value) { + case 0x01: + return Position.ALARM_SOS; + case 0x10: + return Position.ALARM_LOW_BATTERY; + case 0x11: + return Position.ALARM_OVERSPEED; + case 0x12: + return Position.ALARM_MOVEMENT; + case 0x13: + return Position.ALARM_GEOFENCE_ENTER; + case 0x14: + return Position.ALARM_ACCIDENT; + case 0x50: + return Position.ALARM_POWER_OFF; + case 0x53: + return Position.ALARM_GPS_ANTENNA_CUT; + case 0x72: + return Position.ALARM_BRAKING; + case 0x73: + return Position.ALARM_ACCELERATION; + default: + return null; + } + } + + private Position decodeRegular(Position position, String sentence) { + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + if (parser.hasNext()) { + position.setSpeed(parser.nextDouble(0)); + } + + if (parser.hasNext()) { + position.setCourse(parser.nextDouble(0)); + } + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_HDOP, parser.nextDouble()); + + if (parser.hasNext()) { + position.setAltitude(parser.nextDouble(0)); + } + + if (parser.hasNext()) { + int status = parser.nextHexInt(); + for (int i = 1; i <= 5; i++) { + position.set(Position.PREFIX_OUT + i, BitUtil.check(status, i - 1)); + } + for (int i = 1; i <= 5; i++) { + position.set(Position.PREFIX_IN + i, BitUtil.check(status, i - 1 + 8)); + } + } + + for (int i = 1; i <= 8; i++) { + position.set(Position.PREFIX_ADC + i, parser.nextHexInt()); + } + + position.set(Position.KEY_RSSI, parser.nextHexInt()); + position.set(Position.KEY_ODOMETER, parser.nextHexLong()); + position.set(Position.KEY_SATELLITES, parser.nextHexInt()); + position.set("driverLicense", parser.next()); + position.set(Position.KEY_ODOMETER, parser.nextLong()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + return position; + } + + private Position decodeRfid(Position position, String sentence) { + Parser parser = new Parser(PATTERN_RFID, sentence); + if (!parser.matches()) { + return null; + } + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + return position; + } + + private Position decodeObd(Position position, String sentence) { + Parser parser = new Parser(PATTERN_OBD, sentence); + if (!parser.matches()) { + return null; + } + + getLastLocation(position, null); + + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_RPM, parser.nextInt()); + position.set(Position.KEY_OBD_SPEED, parser.nextInt()); + position.set(Position.KEY_THROTTLE, parser.nextDouble()); + position.set(Position.KEY_ENGINE_LOAD, parser.nextDouble()); + position.set(Position.KEY_COOLANT_TEMP, parser.nextInt()); + position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextDouble()); + position.set("averageFuelConsumption", parser.nextDouble()); + position.set("drivingRange", parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextDouble()); + position.set("singleFuelConsumption", parser.nextDouble()); + position.set(Position.KEY_FUEL_USED, parser.nextDouble()); + position.set(Position.KEY_DTCS, parser.nextInt()); + position.set("hardAccelerationCount", parser.nextInt()); + position.set("hardBrakingCount", parser.nextInt()); + + return position; + } + + private Position decodeObdA(Position position, String sentence) { + Parser parser = new Parser(PATTERN_OBDA, sentence); + if (!parser.matches()) { + return null; + } + + getLastLocation(position, null); + + position.set("totalIgnitionNo", parser.nextInt(0)); + position.set("totalDrivingTime", parser.nextDouble(0)); + position.set("totalIdlingTime", parser.nextDouble(0)); + position.set("averageHotStartTime", parser.nextInt(0)); + position.set("averageSpeed", parser.nextInt(0)); + position.set("historyHighestSpeed", parser.nextInt(0)); + position.set("historyHighestRpm", parser.nextInt(0)); + position.set("totalHarshAccerleration", parser.nextInt(0)); + position.set("totalHarshBrake", parser.nextInt(0)); + + return position; + } + + private List decodeRetransmission(ByteBuf buf, DeviceSession deviceSession) { + List positions = new LinkedList<>(); + + int count = buf.readUnsignedByte(); + for (int i = 0; i < count; i++) { + + buf.readUnsignedByte(); // alarm + + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\\'); + if (endIndex < 0) { + endIndex = buf.writerIndex() - 4; + } + + String sentence = buf.readSlice(endIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position = decodeRegular(position, sentence); + + if (position != null) { + positions.add(position); + } + + if (buf.readableBytes() > 4) { + buf.readUnsignedByte(); // delimiter + } + + } + + return positions; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + buf.skipBytes(2); // header + buf.readShort(); // length + ByteBuf id = buf.readSlice(7); + int command = buf.readUnsignedShort(); + + if (command == MSG_LOGIN) { + ByteBuf response = Unpooled.wrappedBuffer(new byte[]{0x01}); + sendResponse(channel, remoteAddress, id, MSG_LOGIN_RESPONSE, response); + return null; + } else if (command == MSG_HEARTBEAT) { + ByteBuf response = Unpooled.wrappedBuffer(new byte[]{0x01}); + sendResponse(channel, remoteAddress, id, MSG_HEARTBEAT, response); + return null; + } else if (command == MSG_SERVER) { + ByteBuf response = Unpooled.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, Unpooled.buffer()); + ByteBuf response = Unpooled.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(); + ByteBuf response = Unpooled.copiedBuffer(new byte[]{imageIndex, 0, 0}); + sendResponse(channel, remoteAddress, id, MSG_RETRANSMISSION, response); + return null; + } + + DeviceSession deviceSession = identify(id, channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + 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); + + } else { + + Position position = new Position(getProtocolName()); + + position.setDeviceId(deviceSession.getDeviceId()); + + if (command == MSG_ALARM) { + short alarmCode = buf.readUnsignedByte(); + position.set(Position.KEY_ALARM, decodeAlarm(alarmCode)); + if (alarmCode >= 0x02 && alarmCode <= 0x05) { + position.set(Position.PREFIX_IN + alarmCode, 1); + } else if (alarmCode >= 0x32 && alarmCode <= 0x35) { + position.set(Position.PREFIX_IN + (alarmCode - 0x30), 0); + } + } else if (command == MSG_POSITION_LOGGED) { + buf.skipBytes(6); + } else if (command == MSG_RFID) { + for (int i = 0; i < 15; i++) { + long rfid = buf.readUnsignedInt(); + if (rfid != 0) { + String card = String.format("%010d", rfid); + position.set("card" + (i + 1), card); + 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(); + ByteBuf photo = photos.remove(imageIndex); + try { + position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg")); + } finally { + photo.release(); + } + } + + String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 4, StandardCharsets.US_ASCII); + + 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; + } + + } + } + +} diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java new file mode 100644 index 000000000..57cbbe0fc --- /dev/null +++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java @@ -0,0 +1,86 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.Checksum; +import org.traccar.helper.DataConverter; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; +import java.util.TimeZone; + +public class MeiligaoProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeContent(long deviceId, int type, ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte('@'); + buf.writeByte('@'); + + buf.writeShort(2 + 2 + 7 + 2 + content.readableBytes() + 2 + 2); // message length + + buf.writeBytes(DataConverter.parseHex((getUniqueId(deviceId) + "FFFFFFFFFFFFFF").substring(0, 14))); + + buf.writeShort(type); + + buf.writeBytes(content); + + buf.writeShort(Checksum.crc16(Checksum.CRC16_CCITT_FALSE, buf.nioBuffer())); + + buf.writeByte('\r'); + buf.writeByte('\n'); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + ByteBuf content = Unpooled.buffer(); + + switch (command.getType()) { + case Command.TYPE_POSITION_SINGLE: + 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(), MeiligaoProtocolDecoder.MSG_TRACK_BY_INTERVAL, content); + case Command.TYPE_ENGINE_STOP: + content.writeByte(0x01); + return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL, content); + case Command.TYPE_ENGINE_RESUME: + content.writeByte(0x00); + 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(), 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(), 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(), MeiligaoProtocolDecoder.MSG_REBOOT_GPS, content); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/MeitrackFrameDecoder.java b/src/main/java/org/traccar/protocol/MeitrackFrameDecoder.java new file mode 100644 index 000000000..d122bca0c --- /dev/null +++ b/src/main/java/org/traccar/protocol/MeitrackFrameDecoder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +import java.nio.charset.StandardCharsets; + +public class MeitrackFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); + if (index != -1) { + int length = index - buf.readerIndex() + Integer.parseInt( + buf.toString(buf.readerIndex() + 3, index - buf.readerIndex() - 3, StandardCharsets.US_ASCII)); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocol.java b/src/main/java/org/traccar/protocol/MeitrackProtocol.java new file mode 100644 index 000000000..c887cd3a0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MeitrackProtocol.java @@ -0,0 +1,54 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class MeitrackProtocol extends BaseProtocol { + + public MeitrackProtocol() { + setSupportedDataCommands( + Command.TYPE_POSITION_SINGLE, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM, + Command.TYPE_REQUEST_PHOTO, + Command.TYPE_SEND_SMS); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new MeitrackFrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new MeitrackProtocolEncoder()); + pipeline.addLast(new MeitrackProtocolDecoder(MeitrackProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new MeitrackProtocolEncoder()); + pipeline.addLast(new MeitrackProtocolDecoder(MeitrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java new file mode 100644 index 000000000..55260ef0c --- /dev/null +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java @@ -0,0 +1,534 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class MeitrackProtocolDecoder extends BaseProtocolDecoder { + + private ByteBuf photo; + + public MeitrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$$").expression(".") // flag + .number("d+,") // length + .number("(d+),") // imei + .number("xxx,") // command + .number("d+,").optional() + .number("(d+),") // event + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("([AV]),") // validity + .number("(d+),") // satellites + .number("(d+),") // rssi + .number("(d+.?d*),") // speed + .number("(d+),") // course + .number("(d+.?d*),") // hdop + .number("(-?d+),") // altitude + .number("(d+),") // odometer + .number("(d+),") // runtime + .number("(d+)|") // mcc + .number("(d+)|") // mnc + .number("(x+)|") // lac + .number("(x+),") // cid + .number("(x+),") // state + .number("(x+)?|") // adc1 + .number("(x+)?|") // adc2 + .number("(x+)?|") // adc3 + .number("(x+)|") // battery + .number("(x+)?,") // power + .groupBegin() + .expression("([^,]+)?,").optional() // event specific + .expression("[^,]*,") // reserved + .number("(d+)?,") // protocol + .number("(x{4})?") // fuel + .groupBegin() + .number(",(x{6}(?:|x{6})*)?") // temperature + .groupBegin() + .number(",(d+)") // data count + .expression(",([^*]*)") // data + .groupEnd("?") + .groupEnd("?") + .or() + .any() + .groupEnd() + .text("*") + .number("xx") + .text("\r\n").optional() + .compile(); + + private String decodeAlarm(int event) { + switch (event) { + case 1: + return Position.ALARM_SOS; + case 17: + return Position.ALARM_LOW_BATTERY; + case 18: + return Position.ALARM_LOW_POWER; + case 19: + return Position.ALARM_OVERSPEED; + case 20: + return Position.ALARM_GEOFENCE_ENTER; + case 21: + return Position.ALARM_GEOFENCE_EXIT; + case 22: + return Position.ALARM_POWER_RESTORED; + case 23: + return Position.ALARM_POWER_CUT; + case 36: + return Position.ALARM_TOW; + case 44: + return Position.ALARM_JAMMING; + case 78: + return Position.ALARM_ACCIDENT; + case 90: + case 91: + return Position.ALARM_CORNERING; + case 129: + return Position.ALARM_BRAKING; + case 130: + return Position.ALARM_ACCELERATION; + case 135: + return Position.ALARM_FATIGUE_DRIVING; + default: + return null; + } + } + + private Position decodeRegular(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + Parser parser = new Parser(PATTERN, buf.toString(StandardCharsets.US_ASCII)); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + int event = parser.nextInt(0); + position.set(Position.KEY_EVENT, event); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + + position.setTime(parser.nextDateTime()); + + position.setValid(parser.next().equals("A")); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + int rssi = parser.nextInt(0); + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_HDOP, parser.nextDouble()); + + position.setAltitude(parser.nextDouble(0)); + + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + position.set("runtime", parser.next()); + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0), rssi))); + + position.set(Position.KEY_STATUS, parser.next()); + + for (int i = 1; i <= 3; i++) { + if (parser.hasNext()) { + position.set(Position.PREFIX_ADC + i, parser.nextHexInt(0)); + } + } + + String deviceModel = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getModel(); + if (deviceModel == null) { + deviceModel = ""; + } + switch (deviceModel.toUpperCase()) { + case "MVT340": + case "MVT380": + position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.0 * 2.0 / 1024.0); + position.set(Position.KEY_POWER, parser.nextHexInt(0) * 3.0 * 16.0 / 1024.0); + break; + case "MT90": + position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.3 * 2.0 / 4096.0); + position.set(Position.KEY_POWER, parser.nextHexInt(0)); + break; + case "T1": + case "T3": + case "MVT100": + case "MVT600": + case "MVT800": + case "TC68": + case "TC68S": + position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.3 * 2.0 / 4096.0); + position.set(Position.KEY_POWER, parser.nextHexInt(0) * 3.3 * 16.0 / 4096.0); + break; + case "T311": + case "T322X": + case "T333": + case "T355": + position.set(Position.KEY_BATTERY, parser.nextHexInt(0) / 100.0); + position.set(Position.KEY_POWER, parser.nextHexInt(0) / 100.0); + break; + default: + position.set(Position.KEY_BATTERY, parser.nextHexInt(0)); + position.set(Position.KEY_POWER, parser.nextHexInt(0)); + break; + } + + String eventData = parser.next(); + if (eventData != null && !eventData.isEmpty()) { + switch (event) { + case 37: + position.set(Position.KEY_DRIVER_UNIQUE_ID, eventData); + break; + default: + position.set("eventData", eventData); + break; + } + } + + int protocol = parser.nextInt(0); + + if (parser.hasNext()) { + String fuel = parser.next(); + position.set(Position.KEY_FUEL_LEVEL, + Integer.parseInt(fuel.substring(0, 2), 16) + Integer.parseInt(fuel.substring(2), 16) * 0.01); + } + + if (parser.hasNext()) { + for (String temp : parser.next().split("\\|")) { + int index = Integer.parseInt(temp.substring(0, 2), 16); + if (protocol >= 3) { + double value = (short) Integer.parseInt(temp.substring(2), 16); + position.set(Position.PREFIX_TEMP + index, value * 0.01); + } else { + double value = Byte.parseByte(temp.substring(2, 4), 16); + value += (value < 0 ? -0.01 : 0.01) * Integer.parseInt(temp.substring(4), 16); + position.set(Position.PREFIX_TEMP + index, value); + } + } + } + + if (parser.hasNext(2)) { + parser.nextInt(); // count + decodeDataFields(position, parser.next().split(",")); + } + + return position; + } + + private void decodeDataFields(Position position, String[] values) { + + if (values.length > 1 && !values[1].isEmpty()) { + position.set("tempData", values[1]); + } + + if (values.length > 5 && !values[5].isEmpty()) { + String[] data = values[5].split("\\|"); + boolean started = data[0].charAt(1) == '0'; + position.set("taximeterOn", started); + position.set("taximeterStart", data[1]); + if (data.length > 2) { + position.set("taximeterEnd", data[2]); + position.set("taximeterDistance", Integer.parseInt(data[3])); + position.set("taximeterFare", Integer.parseInt(data[4])); + position.set("taximeterTrip", data[5]); + position.set("taximeterWait", data[6]); + } + } + + } + + private List decodeBinaryC(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + List positions = new LinkedList<>(); + + String flag = buf.toString(2, 1, StandardCharsets.US_ASCII); + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); + + String imei = buf.toString(index + 1, 15, StandardCharsets.US_ASCII); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + buf.skipBytes(index + 1 + 15 + 1 + 3 + 1 + 2 + 2 + 4); + + while (buf.readableBytes() >= 0x34) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + position.setLatitude(buf.readIntLE() * 0.000001); + position.setLongitude(buf.readIntLE() * 0.000001); + + position.setTime(new Date((946684800 + buf.readUnsignedIntLE()) * 1000)); // 946684800 = 2000-01-01 + + position.setValid(buf.readUnsignedByte() == 1); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + int rssi = buf.readUnsignedByte(); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_HDOP, buf.readUnsignedShortLE() * 0.1); + + position.setAltitude(buf.readUnsignedShortLE()); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set("runtime", buf.readUnsignedIntLE()); + + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), + buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), + rssi))); + + position.set(Position.KEY_STATUS, buf.readUnsignedShortLE()); + + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + position.set(Position.KEY_POWER, buf.readUnsignedShortLE()); + + buf.readUnsignedIntLE(); // geo-fence + + positions.add(position); + } + + if (channel != null) { + StringBuilder command = new StringBuilder("@@"); + command.append(flag).append(27 + positions.size() / 10).append(","); + command.append(imei).append(",CCC,").append(positions.size()).append("*"); + int checksum = 0; + for (int i = 0; i < command.length(); i += 1) { + checksum += command.charAt(i); + } + command.append(String.format("%02x", checksum & 0xff).toUpperCase()); + command.append("\r\n"); + channel.writeAndFlush(new NetworkMessage(command.toString(), remoteAddress)); // delete processed data + } + + return positions; + } + + private List decodeBinaryE(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + List positions = new LinkedList<>(); + + buf.readerIndex(buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ',') + 1); + String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); + buf.skipBytes(1 + 3 + 1); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + buf.readUnsignedIntLE(); // remaining cache + int count = buf.readUnsignedShortLE(); + + for (int i = 0; i < count; i++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedShortLE(); // length + buf.readUnsignedShortLE(); // index + + int paramCount = buf.readUnsignedByte(); + for (int j = 0; j < paramCount; j++) { + int id = buf.readUnsignedByte(); + switch (id) { + case 0x01: + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + break; + case 0x05: + position.setValid(buf.readUnsignedByte() > 0); + break; + case 0x06: + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case 0x07: + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; + default: + buf.readUnsignedByte(); + break; + } + } + + paramCount = buf.readUnsignedByte(); + for (int j = 0; j < paramCount; j++) { + int id = buf.readUnsignedByte(); + switch (id) { + case 0x08: + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + break; + case 0x09: + position.setCourse(buf.readUnsignedShortLE()); + break; + case 0x0B: + position.setAltitude(buf.readShortLE()); + break; + case 0x19: + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); + break; + case 0x1A: + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); + break; + default: + buf.readUnsignedShortLE(); + break; + } + } + + paramCount = buf.readUnsignedByte(); + for (int j = 0; j < paramCount; j++) { + int id = buf.readUnsignedByte(); + switch (id) { + case 0x02: + position.setLatitude(buf.readIntLE() * 0.000001); + break; + case 0x03: + position.setLongitude(buf.readIntLE() * 0.000001); + break; + case 0x04: + position.setTime(new Date((946684800 + buf.readUnsignedIntLE()) * 1000)); // 2000-01-01 + break; + case 0x0D: + position.set("runtime", buf.readUnsignedIntLE()); + break; + default: + buf.readUnsignedIntLE(); + break; + } + } + + paramCount = buf.readUnsignedByte(); + for (int j = 0; j < paramCount; j++) { + buf.readUnsignedByte(); // id + buf.skipBytes(buf.readUnsignedByte()); // value + } + + positions.add(position); + } + + return positions; + } + + private void requestPhotoPacket(Channel channel, SocketAddress socketAddress, String imei, String file, int index) { + if (channel != null) { + String content = "D00," + file + "," + index; + int length = 1 + imei.length() + 1 + content.length() + 5; + String response = String.format("@@O%02d,%s,%s*", length, imei, content); + response += Checksum.sum(response) + "\r\n"; + channel.writeAndFlush(new NetworkMessage(response, socketAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); + String imei = buf.toString(index + 1, 15, StandardCharsets.US_ASCII); + index = buf.indexOf(index + 1, buf.writerIndex(), (byte) ','); + String type = buf.toString(index + 1, 3, StandardCharsets.US_ASCII); + + switch (type) { + case "D00": + if (photo == null) { + photo = Unpooled.buffer(); + } + + index = index + 1 + type.length() + 1; + int endIndex = buf.indexOf(index, buf.writerIndex(), (byte) ','); + String file = buf.toString(index, endIndex - index, StandardCharsets.US_ASCII); + index = endIndex + 1; + endIndex = buf.indexOf(index, buf.writerIndex(), (byte) ','); + int total = Integer.parseInt(buf.toString(index, endIndex - index, StandardCharsets.US_ASCII)); + index = endIndex + 1; + endIndex = buf.indexOf(index, buf.writerIndex(), (byte) ','); + int current = Integer.parseInt(buf.toString(index, endIndex - index, StandardCharsets.US_ASCII)); + + buf.readerIndex(endIndex + 1); + photo.writeBytes(buf.readSlice(buf.readableBytes() - 1 - 2 - 2)); + + if (current == total - 1) { + Position position = new Position(getProtocolName()); + position.setDeviceId(getDeviceSession(channel, remoteAddress, imei).getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg")); + photo.release(); + photo = null; + + return position; + } else { + if ((current + 1) % 8 == 0) { + requestPhotoPacket(channel, remoteAddress, imei, file, current + 1); + } + return null; + } + case "D03": + photo = Unpooled.buffer(); + requestPhotoPacket(channel, remoteAddress, imei, "camera_picture.jpg", 0); + return null; + case "CCC": + return decodeBinaryC(channel, remoteAddress, buf); + case "CCE": + return decodeBinaryE(channel, remoteAddress, buf); + default: + return decodeRegular(channel, remoteAddress, buf); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java new file mode 100644 index 000000000..abb6ec9d4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java @@ -0,0 +1,65 @@ +/* + * 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. + * 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 org.traccar.Context; +import org.traccar.StringProtocolEncoder; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +import java.util.Map; + +public class MeitrackProtocolEncoder extends StringProtocolEncoder { + + private Object formatCommand(Command command, char dataId, String content) { + String uniqueId = getUniqueId(command.getDeviceId()); + int length = 1 + uniqueId.length() + 1 + content.length() + 5; + String result = String.format("@@%c%02d,%s,%s*", dataId, length, uniqueId, content); + result += Checksum.sum(result) + "\r\n"; + return result; + } + + @Override + protected Object encodeCommand(Command command) { + + Map attributes = command.getAttributes(); + + boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( + command.getDeviceId(), "meitrack.alternative", false, true); + + switch (command.getType()) { + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, 'Q', "A10"); + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, 'M', "C01,0,12222"); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, 'M', "C01,0,02222"); + case Command.TYPE_ALARM_ARM: + return formatCommand(command, 'M', alternative ? "B21,1" : "C01,0,22122"); + case Command.TYPE_ALARM_DISARM: + return formatCommand(command, 'M', alternative ? "B21,0" : "C01,0,22022"); + case Command.TYPE_REQUEST_PHOTO: + int index = command.getInteger(Command.KEY_INDEX); + return formatCommand(command, 'D', "D03," + (index > 0 ? index : 1) + ",camera_picture.jpg"); + case Command.TYPE_SEND_SMS: + return formatCommand(command, 'f', "C02,0," + + attributes.get(Command.KEY_PHONE) + "," + attributes.get(Command.KEY_MESSAGE)); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/MilesmateProtocol.java b/src/main/java/org/traccar/protocol/MilesmateProtocol.java new file mode 100644 index 000000000..822711603 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MilesmateProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class MilesmateProtocol extends BaseProtocol { + + public MilesmateProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new MilesmateProtocolDecoder(MilesmateProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java b/src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java new file mode 100644 index 000000000..901ceb8f7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java @@ -0,0 +1,108 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class MilesmateProtocolDecoder extends BaseProtocolDecoder { + + public MilesmateProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("ApiString={") + .number("A:(d+),") // imei + .number("B:(d+.d+),") // battery + .number("C:(d+.d+),") // adc + .number("D:(dd)(dd)(dd),") // time (hhmmss) + .number("E:(dd)(dd.d+)([NS]),") // latitude + .number("F:(ddd)(dd.d+)([EW]),") // longitude + .number("G:(d+.d+),") // speed + .number("H:(dd)(dd)(dd),") // date (ddmmyy) + .expression("I:[GL],") // location source + .number("J:(d{8}),") // flags + .number("K:(d{7})") // flags + .expression("([AV]),") // validity + .number("L:d{4},") // pin + .number("M:(d+.d+)") // course + .text("}") + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("+##Received OK\n", remoteAddress)); + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + String flags = parser.next(); + position.set(Position.KEY_IGNITION, flags.charAt(0) == '1'); + position.set(Position.KEY_ALARM, flags.charAt(1) == '1' ? Position.ALARM_SOS : null); + position.set(Position.KEY_CHARGE, flags.charAt(5) == '1'); + position.set(Position.KEY_ALARM, flags.charAt(7) == '1' ? Position.ALARM_OVERSPEED : null); + + flags = parser.next(); + position.set(Position.KEY_BLOCKED, flags.charAt(0) == '1'); + position.set(Position.KEY_ALARM, flags.charAt(1) == '1' ? Position.ALARM_TOW : null); + + position.setValid(parser.next().equals("A")); + + position.setCourse(parser.nextDouble()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java new file mode 100644 index 000000000..d4a154053 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java @@ -0,0 +1,53 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class MiniFinderProtocol extends BaseProtocol { + + public MiniFinderProtocol() { + setSupportedDataCommands( + Command.TYPE_SET_TIMEZONE, + Command.TYPE_VOICE_MONITORING, + Command.TYPE_ALARM_SPEED, + Command.TYPE_ALARM_GEOFENCE, + Command.TYPE_ALARM_VIBRATION, + Command.TYPE_SET_AGPS, + Command.TYPE_ALARM_FALL, + Command.TYPE_MODE_POWER_SAVING, + Command.TYPE_MODE_DEEP_SLEEP, + Command.TYPE_SOS_NUMBER, + Command.TYPE_SET_INDICATOR); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new MiniFinderProtocolEncoder()); + pipeline.addLast(new MiniFinderProtocolDecoder(MiniFinderProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java new file mode 100644 index 000000000..2b7a960c4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java @@ -0,0 +1,208 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class MiniFinderProtocolDecoder extends BaseProtocolDecoder { + + public MiniFinderProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_FIX = new PatternBuilder() + .number("(d+)/(d+)/(d+),") // date (dd/mm/yy) + .number("(d+):(d+):(d+),") // time (hh:mm:ss) + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .compile(); + + private static final Pattern PATTERN_STATE = new PatternBuilder() + .number("(d+.?d*),") // speed (km/h) + .number("(d+.?d*),") // course + .number("(x+),") // flags + .number("(-?d+.d+),") // altitude (meters) + .number("(d+),") // battery (percentage) + .compile(); + + private static final Pattern PATTERN_A = new PatternBuilder() + .text("!A,") + .expression(PATTERN_FIX.pattern()) + .any() // unknown 3 fields + .compile(); + + private static final Pattern PATTERN_C = new PatternBuilder() + .text("!C,") + .expression(PATTERN_FIX.pattern()) + .expression(PATTERN_STATE.pattern()) + .any() // unknown 3 fields + .compile(); + + private static final Pattern PATTERN_BD = new PatternBuilder() + .expression("![BD],") // B - buffered, D - live + .expression(PATTERN_FIX.pattern()) + .expression(PATTERN_STATE.pattern()) + .number("(d+),") // satellites in use + .number("(d+),") // satellites in view + .number("(d+.?d*)") // hdop + .compile(); + + private void decodeFix(Position position, Parser parser) { + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + } + + private void decodeFlags(Position position, int flags) { + + position.setValid(BitUtil.to(flags, 2) > 0); + if (BitUtil.check(flags, 1)) { + position.set(Position.KEY_APPROXIMATE, true); + } + + if (BitUtil.check(flags, 2)) { + position.set(Position.KEY_ALARM, Position.ALARM_FAULT); + } + if (BitUtil.check(flags, 6)) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + if (BitUtil.check(flags, 7)) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } + if (BitUtil.check(flags, 8)) { + position.set(Position.KEY_ALARM, Position.ALARM_FALL_DOWN); + } + if (BitUtil.check(flags, 9) || BitUtil.check(flags, 10) || BitUtil.check(flags, 11)) { + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE); + } + if (BitUtil.check(flags, 12)) { + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + } + if (BitUtil.check(flags, 15) || BitUtil.check(flags, 14)) { + position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); + } + + position.set(Position.KEY_RSSI, BitUtil.between(flags, 16, 21)); + position.set(Position.KEY_CHARGE, BitUtil.check(flags, 22)); + } + + private void decodeState(Position position, Parser parser) { + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + + position.setCourse(parser.nextDouble(0)); + if (position.getCourse() > 360) { + position.setCourse(0); + } + + decodeFlags(position, parser.nextHexInt(0)); + + position.setAltitude(parser.nextDouble(0)); + + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("!1,")) { + int index = sentence.indexOf(',', 3); + if (index < 0) { + index = sentence.length(); + } + getDeviceSession(channel, remoteAddress, sentence.substring(3, index)); + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null || !sentence.matches("![3A-D],.*")) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + String type = sentence.substring(1, 2); + position.set(Position.KEY_TYPE, type); + + if (type.equals("3")) { + + getLastLocation(position, null); + + position.set(Position.KEY_RESULT, sentence.substring(3)); + + return position; + + } else if (type.equals("B") || type.equals("D")) { + + Parser parser = new Parser(PATTERN_BD, sentence); + if (!parser.matches()) { + return null; + } + + decodeFix(position, parser); + decodeState(position, parser); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt(0)); + position.set(Position.KEY_HDOP, parser.nextDouble(0)); + + return position; + + } else if (type.equals("C")) { + + Parser parser = new Parser(PATTERN_C, sentence); + if (!parser.matches()) { + return null; + } + + decodeFix(position, parser); + decodeState(position, parser); + + return position; + + } else if (type.equals("A")) { + + Parser parser = new Parser(PATTERN_A, sentence); + if (!parser.matches()) { + return null; + } + + decodeFix(position, parser); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java new file mode 100644 index 000000000..7a3d5b226 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java @@ -0,0 +1,82 @@ +/* + * Copyright 2016 - 2017 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. + * 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.TimeZone; + +import org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class MiniFinderProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { + + @Override + public String formatValue(String key, Object value) { + switch (key) { + case Command.KEY_ENABLE: + return (Boolean) value ? "1" : "0"; + case Command.KEY_TIMEZONE: + return String.format("%+03d", TimeZone.getTimeZone((String) value).getRawOffset() / 3600000); + case Command.KEY_INDEX: + switch (((Number) value).intValue()) { + case 0: + return "A"; + case 1: + return "B"; + case 2: + return "C"; + default: + return null; + } + default: + return null; + } + } + + @Override + protected Object encodeCommand(Command command) { + + initDevicePassword(command, "123456"); + + switch (command.getType()) { + case Command.TYPE_SET_TIMEZONE: + return formatCommand(command, "{%s}L{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_TIMEZONE); + case Command.TYPE_VOICE_MONITORING: + return formatCommand(command, "{%s}P{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + case Command.TYPE_ALARM_SPEED: + return formatCommand(command, "{%s}J1{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); + case Command.TYPE_ALARM_GEOFENCE: + return formatCommand(command, "{%s}R1{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_RADIUS); + case Command.TYPE_ALARM_VIBRATION: + return formatCommand(command, "{%s}W1,{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); + case Command.TYPE_SET_AGPS: + return formatCommand(command, "{%s}AGPS{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + case Command.TYPE_ALARM_FALL: + return formatCommand(command, "{%s}F{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + case Command.TYPE_MODE_POWER_SAVING: + return formatCommand(command, "{%s}SP{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + case Command.TYPE_MODE_DEEP_SLEEP: + return formatCommand(command, "{%s}DS{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); + case Command.TYPE_SOS_NUMBER: + return formatCommand(command, "{%s}{%s}1,{%s}", this, + Command.KEY_DEVICE_PASSWORD, Command.KEY_INDEX, Command.KEY_PHONE); + case Command.TYPE_SET_INDICATOR: + return formatCommand(command, "{%s}LED{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Mta6Protocol.java b/src/main/java/org/traccar/protocol/Mta6Protocol.java new file mode 100644 index 000000000..632a7df80 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Mta6Protocol.java @@ -0,0 +1,41 @@ +/* + * 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.Context; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Mta6Protocol extends BaseProtocol { + + public Mta6Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new Mta6ProtocolDecoder( + Mta6Protocol.this, !Context.getConfig().getBoolean(getName() + ".can"))); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java new file mode 100644 index 000000000..88419b871 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java @@ -0,0 +1,319 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class Mta6ProtocolDecoder extends BaseProtocolDecoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(Mta6ProtocolDecoder.class); + + private final boolean simple; + + public Mta6ProtocolDecoder(Protocol protocol, boolean simple) { + super(protocol); + this.simple = simple; + } + + private void sendContinue(Channel channel) { + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + + private void sendResponse(Channel channel, short packetId, short packetCount) { + ByteBuf begin = Unpooled.copiedBuffer("#ACK#", StandardCharsets.US_ASCII); + ByteBuf end = Unpooled.buffer(3); + end.writeByte(packetId); + end.writeByte(packetCount); + end.writeByte(0); + + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(begin, end)); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + + private static class FloatReader { + + private int previousFloat; + + public float readFloat(ByteBuf buf) { + switch (buf.getUnsignedByte(buf.readerIndex()) >> 6) { + case 0: + previousFloat = buf.readInt() << 2; + break; + case 1: + previousFloat = (previousFloat & 0xffffff00) + ((buf.readUnsignedByte() & 0x3f) << 2); + break; + case 2: + previousFloat = (previousFloat & 0xffff0000) + ((buf.readUnsignedShort() & 0x3fff) << 2); + break; + case 3: + previousFloat = (previousFloat & 0xff000000) + ((buf.readUnsignedMedium() & 0x3fffff) << 2); + break; + default: + LOGGER.warn("MTA6 float decoding error", new IllegalArgumentException()); + break; + } + return Float.intBitsToFloat(previousFloat); + } + + } + + private static class TimeReader extends FloatReader { + + private long weekNumber; + + public Date readTime(ByteBuf buf) { + long weekTime = (long) (readFloat(buf) * 1000); + if (weekNumber == 0) { + weekNumber = buf.readUnsignedShort(); + } + + DateBuilder dateBuilder = new DateBuilder().setDate(1980, 1, 6); + dateBuilder.addMillis(weekNumber * 7 * 24 * 60 * 60 * 1000 + weekTime); + + return dateBuilder.getDate(); + } + + } + + private List parseFormatA(DeviceSession deviceSession, ByteBuf buf) { + List positions = new LinkedList<>(); + + FloatReader latitudeReader = new FloatReader(); + FloatReader longitudeReader = new FloatReader(); + TimeReader timeReader = new TimeReader(); + + try { + while (buf.isReadable()) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + short flags = buf.readUnsignedByte(); + + short event = buf.readUnsignedByte(); + if (BitUtil.check(event, 7)) { + if (BitUtil.check(event, 6)) { + buf.skipBytes(8); + } else { + while (BitUtil.check(event, 7)) { + event = buf.readUnsignedByte(); + } + } + } + + position.setLatitude(latitudeReader.readFloat(buf) / Math.PI * 180); + position.setLongitude(longitudeReader.readFloat(buf) / Math.PI * 180); + position.setTime(timeReader.readTime(buf)); + + if (BitUtil.check(flags, 0)) { + buf.readUnsignedByte(); // status + } + + if (BitUtil.check(flags, 1)) { + position.setAltitude(buf.readUnsignedShort()); + } + + if (BitUtil.check(flags, 2)) { + position.setSpeed(buf.readUnsignedShort() & 0x03ff); + position.setCourse(buf.readUnsignedByte()); + } + + if (BitUtil.check(flags, 3)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000); + } + + if (BitUtil.check(flags, 4)) { + position.set(Position.KEY_FUEL_CONSUMPTION + "Accumulator1", buf.readUnsignedInt()); + position.set(Position.KEY_FUEL_CONSUMPTION + "Accumulator2", buf.readUnsignedInt()); + position.set("hours1", buf.readUnsignedShort()); + position.set("hours2", buf.readUnsignedShort()); + } + + if (BitUtil.check(flags, 5)) { + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() & 0x03ff); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort() & 0x03ff); + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort() & 0x03ff); + position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShort() & 0x03ff); + } + + if (BitUtil.check(flags, 6)) { + position.set(Position.PREFIX_TEMP + 1, buf.readByte()); + buf.getUnsignedByte(buf.readerIndex()); // control (>> 4) + position.set(Position.KEY_INPUT, buf.readUnsignedShort() & 0x0fff); + buf.readUnsignedShort(); // old sensor state (& 0x0fff) + } + + if (BitUtil.check(flags, 7)) { + position.set(Position.KEY_BATTERY, buf.getUnsignedByte(buf.readerIndex()) >> 2); + position.set(Position.KEY_POWER, buf.readUnsignedShort() & 0x03ff); + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + + position.set(Position.KEY_RSSI, (buf.getUnsignedByte(buf.readerIndex()) >> 4) & 0x07); + + int satellites = buf.readUnsignedByte() & 0x0f; + position.setValid(satellites >= 3); + position.set(Position.KEY_SATELLITES, satellites); + } + positions.add(position); + } + } catch (IndexOutOfBoundsException error) { + LOGGER.warn("MTA6 parsing error", error); + } + + return positions; + } + + private Position parseFormatA1(DeviceSession deviceSession, ByteBuf buf) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + short flags = buf.readUnsignedByte(); + + // Skip events + short event = buf.readUnsignedByte(); + if (BitUtil.check(event, 7)) { + if (BitUtil.check(event, 6)) { + buf.skipBytes(8); + } else { + while (BitUtil.check(event, 7)) { + event = buf.readUnsignedByte(); + } + } + } + + position.setLatitude(new FloatReader().readFloat(buf) / Math.PI * 180); + position.setLongitude(new FloatReader().readFloat(buf) / Math.PI * 180); + position.setTime(new TimeReader().readTime(buf)); + + position.set(Position.KEY_STATUS, buf.readUnsignedByte()); + + if (BitUtil.check(flags, 0)) { + position.setAltitude(buf.readUnsignedShort()); + position.setSpeed(buf.readUnsignedByte()); + position.setCourse(buf.readByte()); + position.set(Position.KEY_ODOMETER, new FloatReader().readFloat(buf)); + } + + if (BitUtil.check(flags, 1)) { + position.set(Position.KEY_FUEL_CONSUMPTION, new FloatReader().readFloat(buf)); + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(new FloatReader().readFloat(buf))); + position.set("tank", buf.readUnsignedByte() * 0.4); + } + + if (BitUtil.check(flags, 2)) { + position.set("engine", buf.readUnsignedShort() * 0.125); + position.set("pedals", buf.readUnsignedByte()); + position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte() - 40); + position.set(Position.KEY_ODOMETER_SERVICE, buf.readUnsignedShort()); + } + + if (BitUtil.check(flags, 3)) { + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShort()); + } + + if (BitUtil.check(flags, 4)) { + position.set(Position.PREFIX_TEMP + 1, buf.readByte()); + buf.getUnsignedByte(buf.readerIndex()); // control (>> 4) + position.set(Position.KEY_INPUT, buf.readUnsignedShort() & 0x0fff); + buf.readUnsignedShort(); // old sensor state (& 0x0fff) + } + + if (BitUtil.check(flags, 5)) { + position.set(Position.KEY_BATTERY, buf.getUnsignedByte(buf.readerIndex()) >> 2); + position.set(Position.KEY_POWER, buf.readUnsignedShort() & 0x03ff); + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + + position.set(Position.KEY_RSSI, buf.getUnsignedByte(buf.readerIndex()) >> 5); + + int satellites = buf.readUnsignedByte() & 0x1f; + position.setValid(satellites >= 3); + position.set(Position.KEY_SATELLITES, satellites); + } + + // other data + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + ByteBuf buf = request.content(); + + buf.skipBytes("id=".length()); + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&'); + String uniqueId = buf.toString(buf.readerIndex(), index - buf.readerIndex(), StandardCharsets.US_ASCII); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); + if (deviceSession == null) { + return null; + } + buf.skipBytes(uniqueId.length()); + buf.skipBytes("&bin=".length()); + + short packetId = buf.readUnsignedByte(); + short offset = buf.readUnsignedByte(); // dataOffset + short packetCount = buf.readUnsignedByte(); + buf.readUnsignedByte(); // reserved + buf.readUnsignedByte(); // timezone + buf.skipBytes(offset - 5); + + if (channel != null) { + sendContinue(channel); + sendResponse(channel, packetId, packetCount); + } + + if (packetId == 0x31 || packetId == 0x32 || packetId == 0x36) { + if (simple) { + return parseFormatA1(deviceSession, buf); + } else { + return parseFormatA(deviceSession, buf); + } + } // else if (0x34 0x38 0x4F 0x59) + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/MtxProtocol.java b/src/main/java/org/traccar/protocol/MtxProtocol.java new file mode 100644 index 000000000..44372ce83 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MtxProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class MtxProtocol extends BaseProtocol { + + public MtxProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new MtxProtocolDecoder(MtxProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MtxProtocolDecoder.java b/src/main/java/org/traccar/protocol/MtxProtocolDecoder.java new file mode 100644 index 000000000..d1207bedf --- /dev/null +++ b/src/main/java/org/traccar/protocol/MtxProtocolDecoder.java @@ -0,0 +1,98 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class MtxProtocolDecoder extends BaseProtocolDecoder { + + public MtxProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("#MTX,") + .number("(d+),") // imei + .number("(dddd)(dd)(dd),") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(d+.?d*),") // speed + .number("(d+),") // course + .number("(d+.?d*),") // odometer + .groupBegin() + .number("d+") + .or() + .text("X") + .groupEnd() + .text(",") + .expression("(?:[01]|X),") + .expression("([01]+),") // input + .expression("([01]+),") // output + .number("(d+),") // adc1 + .number("(d+)") // adc2 + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("#ACK", remoteAddress)); + } + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setValid(true); + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/MxtFrameDecoder.java b/src/main/java/org/traccar/protocol/MxtFrameDecoder.java new file mode 100644 index 000000000..d70e92da1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MxtFrameDecoder.java @@ -0,0 +1,53 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class MxtFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 2) { + return null; + } + + int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0x04); + if (index != -1) { + ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex()); + + while (buf.readerIndex() <= index) { + int b = buf.readUnsignedByte(); + if (b == 0x10) { + result.writeByte(buf.readUnsignedByte() - 0x20); + } else { + result.writeByte(b); + } + } + + return result; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/MxtProtocol.java b/src/main/java/org/traccar/protocol/MxtProtocol.java new file mode 100644 index 000000000..dbe43fe45 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MxtProtocol.java @@ -0,0 +1,34 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class MxtProtocol extends BaseProtocol { + + public MxtProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new MxtFrameDecoder()); + pipeline.addLast(new MxtProtocolDecoder(MxtProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/MxtProtocolDecoder.java b/src/main/java/org/traccar/protocol/MxtProtocolDecoder.java new file mode 100644 index 000000000..7bde85f87 --- /dev/null +++ b/src/main/java/org/traccar/protocol/MxtProtocolDecoder.java @@ -0,0 +1,175 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +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.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class MxtProtocolDecoder extends BaseProtocolDecoder { + + public MxtProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_ACK = 0x02; + public static final int MSG_NACK = 0x03; + public static final int MSG_POSITION = 0x31; + + private static void sendResponse(Channel channel, int device, long id, int crc) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(device); + response.writeByte(MSG_ACK); + response.writeIntLE((int) id); + response.writeShortLE(crc); + response.writeShortLE(Checksum.crc16( + Checksum.CRC16_XMODEM, response.nioBuffer())); + + ByteBuf encoded = Unpooled.buffer(); + encoded.writeByte(0x01); // header + while (response.isReadable()) { + int b = response.readByte(); + if (b == 0x01 || b == 0x04 || b == 0x10 || b == 0x11 || b == 0x13) { + encoded.writeByte(0x10); + b += 0x20; + } + encoded.writeByte(b); + } + response.release(); + encoded.writeByte(0x04); // ending + channel.writeAndFlush(new NetworkMessage(encoded, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // start + int device = buf.readUnsignedByte(); // device descriptor + int type = buf.readUnsignedByte(); + + long id = buf.readUnsignedIntLE(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + + if (type == MSG_POSITION) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedByte(); // protocol + int infoGroups = buf.readUnsignedByte(); + + position.set(Position.KEY_INDEX, buf.readUnsignedShortLE()); + + DateBuilder dateBuilder = new DateBuilder().setDate(2000, 1, 1); + + long date = buf.readUnsignedIntLE(); + + long days = BitUtil.from(date, 6 + 6 + 5); + long hours = BitUtil.between(date, 6 + 6, 6 + 6 + 5); + long minutes = BitUtil.between(date, 6, 6 + 6); + long seconds = BitUtil.to(date, 6); + + dateBuilder.addMillis((((days * 24 + hours) * 60 + minutes) * 60 + seconds) * 1000); + + position.setTime(dateBuilder.getDate()); + + position.setValid(true); + position.setLatitude(buf.readIntLE() / 1000000.0); + position.setLongitude(buf.readIntLE() / 1000000.0); + + long flags = buf.readUnsignedIntLE(); + position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0)); + if (BitUtil.check(flags, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + position.set(Position.KEY_INPUT, BitUtil.between(flags, 2, 7)); + position.set(Position.KEY_OUTPUT, BitUtil.between(flags, 7, 10)); + position.setCourse(BitUtil.between(flags, 10, 13) * 45); + // position.setValid(BitUtil.check(flags, 15)); + position.set(Position.KEY_CHARGE, BitUtil.check(flags, 20)); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + buf.readUnsignedByte(); // input mask + + if (BitUtil.check(infoGroups, 0)) { + buf.skipBytes(8); // waypoints + } + + if (BitUtil.check(infoGroups, 1)) { + buf.skipBytes(8); // wireless accessory + } + + if (BitUtil.check(infoGroups, 2)) { + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_HDOP, buf.readUnsignedByte()); + position.setAccuracy(buf.readUnsignedByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + buf.readUnsignedShortLE(); // time since boot + position.set(Position.KEY_POWER, buf.readUnsignedByte()); + position.set(Position.PREFIX_TEMP + 1, buf.readByte()); + } + + if (BitUtil.check(infoGroups, 3)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + } + + if (BitUtil.check(infoGroups, 4)) { + position.set(Position.KEY_HOURS, UnitsConverter.msFromMinutes(buf.readUnsignedIntLE())); + } + + if (BitUtil.check(infoGroups, 5)) { + buf.readUnsignedIntLE(); // reason + } + + if (BitUtil.check(infoGroups, 6)) { + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE()); + } + + if (BitUtil.check(infoGroups, 7)) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedIntLE())); + } + + buf.readerIndex(buf.writerIndex() - 3); + sendResponse(channel, device, id, buf.readUnsignedShortLE()); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NavigilFrameDecoder.java b/src/main/java/org/traccar/protocol/NavigilFrameDecoder.java new file mode 100644 index 000000000..e8b6bea52 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavigilFrameDecoder.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class NavigilFrameDecoder extends BaseFrameDecoder { + + private static final int MESSAGE_HEADER = 20; + private static final long PREAMBLE = 0x2477F5F6; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + // Check minimum length + if (buf.readableBytes() < MESSAGE_HEADER) { + return null; + } + + // Check for preamble + boolean hasPreamble = false; + if (buf.getUnsignedIntLE(buf.readerIndex()) == PREAMBLE) { + hasPreamble = true; + } + + // Check length and return buffer + int length = buf.getUnsignedShortLE(buf.readerIndex() + 6); + if (buf.readableBytes() >= length) { + if (hasPreamble) { + buf.readUnsignedIntLE(); + length -= 4; + } + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NavigilProtocol.java b/src/main/java/org/traccar/protocol/NavigilProtocol.java new file mode 100644 index 000000000..2c946c39f --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavigilProtocol.java @@ -0,0 +1,34 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class NavigilProtocol extends BaseProtocol { + + public NavigilProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new NavigilFrameDecoder()); + pipeline.addLast(new NavigilProtocolDecoder(NavigilProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java new file mode 100644 index 000000000..db5521201 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java @@ -0,0 +1,308 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Checksum; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; + +public class NavigilProtocolDecoder extends BaseProtocolDecoder { + + public NavigilProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final int LEAP_SECONDS_DELTA = 25; + + public static final int MSG_ERROR = 2; + public static final int MSG_INDICATION = 4; + public static final int MSG_CONN_OPEN = 5; + public static final int MSG_CONN_CLOSE = 6; + public static final int MSG_SYSTEM_REPORT = 7; + public static final int MSG_UNIT_REPORT = 8; + public static final int MSG_GEOFENCE_ALARM = 10; + public static final int MSG_INPUT_ALARM = 11; + public static final int MSG_TG2_REPORT = 12; + public static final int MSG_POSITION_REPORT = 13; + public static final int MSG_POSITION_REPORT_2 = 15; + public static final int MSG_SNAPSHOT4 = 17; + public static final int MSG_TRACKING_DATA = 18; + public static final int MSG_MOTION_ALARM = 19; + public static final int MSG_ACKNOWLEDGEMENT = 255; + + private static Date convertTimestamp(long timestamp) { + return new Date((timestamp - LEAP_SECONDS_DELTA) * 1000); + } + + private int senderSequenceNumber = 1; + + private void sendAcknowledgment(Channel channel, int sequenceNumber) { + ByteBuf data = Unpooled.buffer(4); + data.writeShortLE(sequenceNumber); + data.writeShortLE(0); // OK + + ByteBuf header = Unpooled.buffer(20); + header.writeByte(1); header.writeByte(0); + header.writeShortLE(senderSequenceNumber++); + header.writeShortLE(MSG_ACKNOWLEDGEMENT); + header.writeShortLE(header.capacity() + data.capacity()); + header.writeShortLE(0); + header.writeShortLE(Checksum.crc16(Checksum.CRC16_CCITT_FALSE, data.nioBuffer())); + header.writeIntLE(0); + header.writeIntLE((int) (System.currentTimeMillis() / 1000) + LEAP_SECONDS_DELTA); + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(header, data), channel.remoteAddress())); + } + } + + private Position parseUnitReport( + DeviceSession deviceSession, ByteBuf buf, int sequenceNumber) { + Position position = new Position(getProtocolName()); + + position.setValid(true); + position.set(Position.KEY_INDEX, sequenceNumber); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedShortLE(); // report trigger + position.set(Position.KEY_FLAGS, buf.readUnsignedShortLE()); + + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + position.setAltitude(buf.readUnsignedShortLE()); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedShortLE()); + position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedShortLE()); + position.set("gpsAntennaState", buf.readUnsignedShortLE()); + + position.setSpeed(buf.readUnsignedShortLE() * 0.194384); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set(Position.KEY_DISTANCE, buf.readUnsignedIntLE()); + + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + + position.set(Position.KEY_CHARGE, buf.readUnsignedShortLE()); + + position.setTime(convertTimestamp(buf.readUnsignedIntLE())); + + return position; + } + + private Position parseTg2Report( + DeviceSession deviceSession, ByteBuf buf, int sequenceNumber) { + Position position = new Position(getProtocolName()); + + position.setValid(true); + position.set(Position.KEY_INDEX, sequenceNumber); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedShortLE(); // report trigger + buf.readUnsignedByte(); // reserved + buf.readUnsignedByte(); // assisted GPS age + + position.setTime(convertTimestamp(buf.readUnsignedIntLE())); + + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + position.setAltitude(buf.readUnsignedShortLE()); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); + + position.setSpeed(buf.readUnsignedShortLE() * 0.194384); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + position.set("maximumSpeed", buf.readUnsignedShortLE()); + position.set("minimumSpeed", buf.readUnsignedShortLE()); + + position.set(Position.PREFIX_IO + 1, buf.readUnsignedShortLE()); // VSAUT1 voltage + position.set(Position.PREFIX_IO + 2, buf.readUnsignedShortLE()); // VSAUT2 voltage + position.set(Position.PREFIX_IO + 3, buf.readUnsignedShortLE()); // solar voltage + + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + + return position; + } + + private Position parsePositionReport( + DeviceSession deviceSession, ByteBuf buf, int sequenceNumber, long timestamp) { + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_INDEX, sequenceNumber); + position.setDeviceId(deviceSession.getDeviceId()); + position.setTime(convertTimestamp(timestamp)); + + position.setLatitude(buf.readMediumLE() * 0.00002); + position.setLongitude(buf.readMediumLE() * 0.00002); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedByte() * 2); + + short flags = buf.readUnsignedByte(); + position.setValid((flags & 0x80) == 0x80 && (flags & 0x40) == 0x40); + + buf.readUnsignedByte(); // reserved + + return position; + } + + private Position parsePositionReport2( + DeviceSession deviceSession, ByteBuf buf, int sequenceNumber, long timestamp) { + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_INDEX, sequenceNumber); + position.setDeviceId(deviceSession.getDeviceId()); + position.setTime(convertTimestamp(timestamp)); + + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + + buf.readUnsignedByte(); // report trigger + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + short flags = buf.readUnsignedByte(); + position.setValid((flags & 0x80) == 0x80 && (flags & 0x40) == 0x40); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + + return position; + } + + private Position parseSnapshot4( + DeviceSession deviceSession, ByteBuf buf, int sequenceNumber) { + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_INDEX, sequenceNumber); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedByte(); // report trigger + buf.readUnsignedByte(); // position fix source + buf.readUnsignedByte(); // GNSS fix quality + buf.readUnsignedByte(); // GNSS assistance age + + long flags = buf.readUnsignedIntLE(); + position.setValid((flags & 0x0400) == 0x0400); + + position.setTime(convertTimestamp(buf.readUnsignedIntLE())); + + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + position.setAltitude(buf.readUnsignedShortLE()); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); + + position.setSpeed(buf.readUnsignedShortLE() * 0.194384); + position.setCourse(buf.readUnsignedShortLE() * 0.1); + + position.set("maximumSpeed", buf.readUnsignedByte()); + position.set("minimumSpeed", buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + + position.set(Position.PREFIX_IO + 1, buf.readUnsignedByte()); // supply voltage 1 + position.set(Position.PREFIX_IO + 2, buf.readUnsignedByte()); // supply voltage 2 + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + + return position; + } + + private Position parseTrackingData( + DeviceSession deviceSession, ByteBuf buf, int sequenceNumber, long timestamp) { + Position position = new Position(getProtocolName()); + + position.set(Position.KEY_INDEX, sequenceNumber); + position.setDeviceId(deviceSession.getDeviceId()); + position.setTime(convertTimestamp(timestamp)); + + buf.readUnsignedByte(); // tracking mode + + short flags = buf.readUnsignedByte(); + position.setValid((flags & 0x01) == 0x01); + + buf.readUnsignedShortLE(); // duration + + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedByte() * 2.0); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // protocol version + buf.readUnsignedByte(); // version id + int sequenceNumber = buf.readUnsignedShortLE(); + int messageId = buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); // length + int flags = buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); // checksum + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedIntLE())); + if (deviceSession == null) { + return null; + } + + long timestamp = buf.readUnsignedIntLE(); + + if ((flags & 0x1) == 0x0) { + sendAcknowledgment(channel, sequenceNumber); + } + + switch (messageId) { + case MSG_UNIT_REPORT: + return parseUnitReport(deviceSession, buf, sequenceNumber); + case MSG_TG2_REPORT: + return parseTg2Report(deviceSession, buf, sequenceNumber); + case MSG_POSITION_REPORT: + return parsePositionReport(deviceSession, buf, sequenceNumber, timestamp); + case MSG_POSITION_REPORT_2: + return parsePositionReport2(deviceSession, buf, sequenceNumber, timestamp); + case MSG_SNAPSHOT4: + return parseSnapshot4(deviceSession, buf, sequenceNumber); + case MSG_TRACKING_DATA: + return parseTrackingData(deviceSession, buf, sequenceNumber, timestamp); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/NavisFrameDecoder.java b/src/main/java/org/traccar/protocol/NavisFrameDecoder.java new file mode 100644 index 000000000..8a0bb0b9a --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavisFrameDecoder.java @@ -0,0 +1,109 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import java.nio.charset.StandardCharsets; +import org.traccar.BaseFrameDecoder; +import org.traccar.BasePipelineFactory; + +public class NavisFrameDecoder extends BaseFrameDecoder { + + private static final int NTCB_HEADER_LENGTH = 16; + private static final int NTCB_LENGTH_OFFSET = 12; + private static final int FLEX_HEADER_LENGTH = 2; + + private int flexDataSize; + + public void setFlexDataSize(int flexDataSize) { + this.flexDataSize = flexDataSize; + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.getByte(buf.readerIndex()) == 0x7F) { + return buf.readRetainedSlice(1); // keep alive + } + + if (ctx != null && flexDataSize == 0) { + NavisProtocolDecoder protocolDecoder = + BasePipelineFactory.getHandler(ctx.pipeline(), NavisProtocolDecoder.class); + if (protocolDecoder != null) { + flexDataSize = protocolDecoder.getFlexDataSize(); + } + } + + if (flexDataSize > 0) { + + if (buf.readableBytes() > FLEX_HEADER_LENGTH) { + int length = 0; + String type = buf.toString(buf.readerIndex(), 2, StandardCharsets.US_ASCII); + switch (type) { + // FLEX 1.0 + case "~A": + length = flexDataSize * buf.getByte(buf.readerIndex() + FLEX_HEADER_LENGTH) + 1 + 1; + break; + case "~T": + length = flexDataSize + 4 + 1; + break; + case "~C": + length = flexDataSize + 1; + break; + // FLEX 2.0 (Extra packages) + case "~E": + length++; + for (int i = 0; i < buf.getByte(buf.readerIndex() + FLEX_HEADER_LENGTH); i++) { + if (buf.readableBytes() > FLEX_HEADER_LENGTH + length + 1) { + length += buf.getUnsignedShort(length + FLEX_HEADER_LENGTH) + 2; + } else { + return null; + } + } + length++; + break; + case "~X": + length = buf.getUnsignedShortLE(buf.readerIndex() + FLEX_HEADER_LENGTH) + 4 + 1; + break; + default: + return null; + } + + if (buf.readableBytes() >= FLEX_HEADER_LENGTH + length) { + return buf.readRetainedSlice(buf.readableBytes()); + } + } + + } else { + + if (buf.readableBytes() < NTCB_HEADER_LENGTH) { + return null; + } + + int length = NTCB_HEADER_LENGTH + buf.getUnsignedShortLE(buf.readerIndex() + NTCB_LENGTH_OFFSET); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NavisProtocol.java b/src/main/java/org/traccar/protocol/NavisProtocol.java new file mode 100644 index 000000000..d5af6838d --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavisProtocol.java @@ -0,0 +1,33 @@ +/* + * Copyright 2015 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class NavisProtocol extends BaseProtocol { + + public NavisProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new NavisFrameDecoder()); + pipeline.addLast(new NavisProtocolDecoder(NavisProtocol.this)); + } + }); + } +} diff --git a/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java new file mode 100644 index 000000000..7ba474ae0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java @@ -0,0 +1,683 @@ +/* + * Copyright 2012 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +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.Checksum.Algorithm; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; +import java.util.Date; + +public class NavisProtocolDecoder extends BaseProtocolDecoder { + + private static final int[] FLEX_FIELDS_SIZES = { + 4, 2, 4, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 4, 4, 2, 2, + 4, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 1, 4, 2, 2, 2, 2, 2, 1, 1, 1, 2, 4, 2, 1, + /* FLEX 2.0 */ + 8, 2, 1, 16, 4, 2, 4, 37, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 12, 24, 48, 1, 1, 1, 1, 4, 4, + 1, 4, 2, 6, 2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1 + }; + + private String prefix; + private long deviceUniqueId, serverId; + private int flexDataSize; + private int flexBitFieldSize; + private final byte[] flexBitField = new byte[16]; + + public NavisProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int F10 = 0x01; + public static final int F20 = 0x02; + public static final int F30 = 0x03; + public static final int F40 = 0x04; + public static final int F50 = 0x05; + public static final int F51 = 0x15; + public static final int F52 = 0x25; + public static final int F60 = 0x06; + + public int getFlexDataSize() { + return flexDataSize; + } + + private static boolean isFormat(int type, int... types) { + for (int i : types) { + if (type == i) { + return true; + } + } + return false; + } + + private Position parseNtcbPosition(DeviceSession deviceSession, ByteBuf buf) { + Position position = new Position(getProtocolName()); + + position.setDeviceId(deviceSession.getDeviceId()); + + int format; + if (buf.getUnsignedByte(buf.readerIndex()) == 0) { + format = buf.readUnsignedShortLE(); + } else { + format = buf.readUnsignedByte(); + } + position.set("format", format); + + position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); + position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); + + buf.skipBytes(6); // event time + + short armedStatus = buf.readUnsignedByte(); + if (isFormat(format, F10, F20, F30, F40, F50, F51, F52)) { + position.set(Position.KEY_ARMED, BitUtil.to(armedStatus, 7)); + if (BitUtil.check(armedStatus, 7)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + } else if (isFormat(format, F60)) { + position.set(Position.KEY_ARMED, BitUtil.check(armedStatus, 0)); + if (BitUtil.check(armedStatus, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + } + + position.set(Position.KEY_STATUS, buf.readUnsignedByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + + if (isFormat(format, F10, F20, F30)) { + int output = buf.readUnsignedShortLE(); + position.set(Position.KEY_OUTPUT, output); + for (int i = 0; i < 16; i++) { + position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(output, i)); + } + } else if (isFormat(format, F50, F51, F52)) { + short extField = buf.readUnsignedByte(); + position.set(Position.KEY_OUTPUT, BitUtil.to(extField, 2)); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(extField, 0)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(extField, 1)); + position.set(Position.KEY_SATELLITES, BitUtil.from(extField, 2)); + } else if (isFormat(format, F40, F60)) { + short output = buf.readUnsignedByte(); + position.set(Position.KEY_OUTPUT, BitUtil.to(output, 4)); + for (int i = 0; i < 4; i++) { + position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(output, i)); + } + } + + if (isFormat(format, F10, F20, F30, F40)) { + int input = buf.readUnsignedShortLE(); + position.set(Position.KEY_INPUT, input); + if (!isFormat(format, F40)) { + for (int i = 0; i < 16; i++) { + position.set(Position.PREFIX_IN + (i + 1), BitUtil.check(input, i)); + } + } else { + position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 0)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 1)); + position.set(Position.PREFIX_IN + 3, BitUtil.check(input, 2)); + position.set(Position.PREFIX_IN + 4, BitUtil.check(input, 3)); + position.set(Position.PREFIX_IN + 5, BitUtil.between(input, 4, 7)); + position.set(Position.PREFIX_IN + 6, BitUtil.between(input, 7, 10)); + position.set(Position.PREFIX_IN + 7, BitUtil.between(input, 10, 12)); + position.set(Position.PREFIX_IN + 8, BitUtil.between(input, 12, 14)); + } + } else if (isFormat(format, F50, F51, F52, F60)) { + short input = buf.readUnsignedByte(); + position.set(Position.KEY_INPUT, input); + for (int i = 0; i < 8; i++) { + position.set(Position.PREFIX_IN + (i + 1), BitUtil.check(input, i)); + } + } + + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); + + if (isFormat(format, F10, F20, F30)) { + position.set(Position.PREFIX_TEMP + 1, buf.readShortLE()); + } + + if (isFormat(format, F10, F20, F50, F51, F52, F60)) { + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE()); + } + if (isFormat(format, F60)) { + position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShortLE()); + } + + // Impulse counters + if (isFormat(format, F20, F50, F51, F52, F60)) { + buf.readUnsignedIntLE(); + buf.readUnsignedIntLE(); + } + + if (isFormat(format, F60)) { + // Fuel + buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + + position.set(Position.PREFIX_TEMP + 1, buf.readByte()); + position.set(Position.PREFIX_TEMP + 2, buf.readByte()); + position.set(Position.PREFIX_TEMP + 3, buf.readByte()); + position.set(Position.PREFIX_TEMP + 4, buf.readByte()); + position.set(Position.KEY_AXLE_WEIGHT, buf.readIntLE()); + position.set(Position.KEY_RPM, buf.readUnsignedShortLE()); + } + + if (isFormat(format, F20, F50, F51, F52, F60)) { + int navSensorState = buf.readUnsignedByte(); + position.setValid(BitUtil.check(navSensorState, 1)); + if (isFormat(format, F60)) { + position.set(Position.KEY_SATELLITES, BitUtil.from(navSensorState, 2)); + } + + DateBuilder dateBuilder = new DateBuilder() + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte() + 1, buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + if (isFormat(format, F60)) { + position.setLatitude(buf.readIntLE() / 600000.0); + position.setLongitude(buf.readIntLE() / 600000.0); + position.setAltitude(buf.readIntLE() * 0.1); + } else { + position.setLatitude(buf.readFloatLE() / Math.PI * 180); + position.setLongitude(buf.readFloatLE() / Math.PI * 180); + } + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readFloatLE())); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_ODOMETER, buf.readFloatLE() * 1000); + position.set(Position.KEY_DISTANCE, buf.readFloatLE() * 1000); + + // Segment times + buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); + } + + // Other + if (isFormat(format, F51, F52)) { + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); + buf.readByte(); + buf.readUnsignedShortLE(); + } + + // Four temperature sensors + if (isFormat(format, F40, F52)) { + position.set(Position.PREFIX_TEMP + 1, buf.readByte()); + position.set(Position.PREFIX_TEMP + 2, buf.readByte()); + position.set(Position.PREFIX_TEMP + 3, buf.readByte()); + position.set(Position.PREFIX_TEMP + 4, buf.readByte()); + } + + return position; + } + + private Object processNtcbSingle(DeviceSession deviceSession, Channel channel, ByteBuf buf) { + Position position = parseNtcbPosition(deviceSession, buf); + + ByteBuf response = Unpooled.buffer(7); + response.writeCharSequence("* positions = new LinkedList<>(); + int count = buf.readUnsignedByte(); + + for (int i = 0; i < count; i++) { + Position position = parseNtcbPosition(deviceSession, buf); + if (position.getFixTime() != null) { + positions.add(position); + } + } + + ByteBuf response = Unpooled.buffer(7); + response.writeCharSequence("* positions = new LinkedList<>(); + int count = buf.readUnsignedByte(); + + for (int i = 0; i < count; i++) { + Position position = parser.parsePosition(deviceSession, buf); + if (position.getFixTime() != null) { + positions.add(position); + } + } + + ByteBuf response = Unpooled.buffer(); + response.writeCharSequence(flexHeader, StandardCharsets.US_ASCII); + response.writeByte(count); + sendFlexReply(channel, response); + + return !positions.isEmpty() ? positions : null; + } + + private Object processFlexNegotiation(Channel channel, ByteBuf buf) { + if ((byte) buf.readUnsignedByte() != (byte) 0xB0) { + return null; + } + + short flexProtocolVersion = buf.readUnsignedByte(); + short flexStructVersion = buf.readUnsignedByte(); + if ((flexProtocolVersion == 0x0A || flexProtocolVersion == 0x14) + && (flexStructVersion == 0x0A || flexStructVersion == 0x14)) { + + flexBitFieldSize = buf.readUnsignedByte(); + if (flexBitFieldSize > 122) { + return null; + } + + buf.readBytes(flexBitField, 0, (int) Math.ceil((double) flexBitFieldSize / 8)); + + flexDataSize = 0; + for (int i = 0; i < flexBitFieldSize; i++) { + if (checkFlexBitfield(i)) { + flexDataSize += FLEX_FIELDS_SIZES[i]; + } + } + } else { + flexProtocolVersion = 0x14; + flexStructVersion = 0x14; + } + + ByteBuf response = Unpooled.buffer(9); + response.writeCharSequence("*S")) { + return processHandshake(channel, remoteAddress, buf); + } else { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession != null) { + switch (type) { + case "*>A": + return processNtcbArray(deviceSession, channel, buf); + case "*>T": + return processNtcbSingle(deviceSession, channel, buf); + case "*>F": + buf.skipBytes(3); + return processFlexNegotiation(channel, buf); + default: + break; + } + } + } + + return null; + } + + private Object decodeFlex(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + if (buf.getByte(buf.readerIndex()) == 0x7F) { + return null; // keep alive + } + + String type = buf.toString(buf.readerIndex(), 2, StandardCharsets.US_ASCII); + buf.skipBytes(type.length()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession != null) { + switch (type) { + // FLEX 1.0 + case "~A": + return processFlexArray(this::parseFlexPosition, type, deviceSession, channel, buf); + case "~T": + case "~C": + return processFlexSingle(this::parseFlexPosition, type, deviceSession, channel, buf); + // FLEX 2.0 (extra packages) + case "~E": + return processFlexArray(this::parseFlex20Position, type, deviceSession, channel, buf); + case "~X": + return processFlexSingle(this::parseFlex20Position, type, deviceSession, channel, buf); + default: + break; + } + } + + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (flexDataSize > 0) { + return decodeFlex(channel, remoteAddress, buf); + } else { + return decodeNtcb(channel, remoteAddress, buf); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/NeosProtocol.java b/src/main/java/org/traccar/protocol/NeosProtocol.java new file mode 100644 index 000000000..e545a9969 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NeosProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class NeosProtocol extends BaseProtocol { + + public NeosProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new NeosProtocolDecoder(NeosProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NeosProtocolDecoder.java b/src/main/java/org/traccar/protocol/NeosProtocolDecoder.java new file mode 100644 index 000000000..6b5596dba --- /dev/null +++ b/src/main/java/org/traccar/protocol/NeosProtocolDecoder.java @@ -0,0 +1,98 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class NeosProtocolDecoder extends BaseProtocolDecoder { + + public NeosProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text(">") + .number("(d{8}),") // id + .number("d+,") // status + .number("([01]),") // valid + .number("(dd)(dd)(dd),") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([EW])") + .number("(d+)(dd.d+),") // longitude + .expression("([NS])") + .number("(d+)(dd.d+),") // latitude + .expression("[^,]*,") // response + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+),") // rssi + .expression("[^,]*,") // event data + .number("(d+)-") // adc + .number("(d+),") // battery + .number("0,") + .number("d,") + .number("([01]{8})") // input + .text("*") + .number("xx!") + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("$OK!", remoteAddress)); + } + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.nextInt() > 0); + position.setTime(parser.nextDateTime()); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setSpeed(parser.nextInt()); + position.setCourse(parser.nextInt()); + + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextInt()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_INPUT, parser.nextBinInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/NoranProtocol.java b/src/main/java/org/traccar/protocol/NoranProtocol.java new file mode 100644 index 000000000..9f3078d6d --- /dev/null +++ b/src/main/java/org/traccar/protocol/NoranProtocol.java @@ -0,0 +1,41 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class NoranProtocol extends BaseProtocol { + + public NoranProtocol() { + setSupportedDataCommands( + Command.TYPE_POSITION_SINGLE, + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_POSITION_STOP, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new NoranProtocolEncoder()); + pipeline.addLast(new NoranProtocolDecoder(NoranProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NoranProtocolDecoder.java b/src/main/java/org/traccar/protocol/NoranProtocolDecoder.java new file mode 100644 index 000000000..53dae7fd6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NoranProtocolDecoder.java @@ -0,0 +1,164 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +public class NoranProtocolDecoder extends BaseProtocolDecoder { + + public NoranProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_UPLOAD_POSITION = 0x0008; + public static final int MSG_UPLOAD_POSITION_NEW = 0x0032; + public static final int MSG_CONTROL = 0x0002; + public static final int MSG_CONTROL_RESPONSE = 0x8009; + public static final int MSG_ALARM = 0x0003; + public static final int MSG_SHAKE_HAND = 0x0000; + public static final int MSG_SHAKE_HAND_RESPONSE = 0x8000; + public static final int MSG_IMAGE_SIZE = 0x0200; + public static final int MSG_IMAGE_PACKET = 0x0201; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedShortLE(); // length + int type = buf.readUnsignedShortLE(); + + if (type == MSG_SHAKE_HAND && channel != null) { + + ByteBuf response = Unpooled.buffer(13); + response.writeCharSequence("\r\n*KW", StandardCharsets.US_ASCII); + response.writeByte(0); + response.writeShortLE(response.capacity()); + response.writeShortLE(MSG_SHAKE_HAND_RESPONSE); + response.writeByte(1); // status + response.writeCharSequence("\r\n", StandardCharsets.US_ASCII); + + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + + } else if (type == MSG_UPLOAD_POSITION || type == MSG_UPLOAD_POSITION_NEW + || type == MSG_CONTROL_RESPONSE || type == MSG_ALARM) { + + boolean newFormat = false; + if (type == MSG_UPLOAD_POSITION && buf.readableBytes() == 48 + || type == MSG_ALARM && buf.readableBytes() == 48 + || type == MSG_CONTROL_RESPONSE && buf.readableBytes() == 57) { + newFormat = true; + } + + Position position = new Position(getProtocolName()); + + if (type == MSG_CONTROL_RESPONSE) { + buf.readUnsignedIntLE(); // GIS ip + buf.readUnsignedIntLE(); // GIS port + } + + position.setValid(BitUtil.check(buf.readUnsignedByte(), 0)); + + short alarm = buf.readUnsignedByte(); + switch (alarm) { + case 1: + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + break; + case 2: + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + break; + case 3: + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT); + break; + case 9: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); + break; + default: + break; + } + + if (newFormat) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedIntLE())); + position.setCourse(buf.readFloatLE()); + } else { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedShortLE()); + } + position.setLongitude(buf.readFloatLE()); + position.setLatitude(buf.readFloatLE()); + + if (!newFormat) { + long timeValue = buf.readUnsignedIntLE(); + DateBuilder dateBuilder = new DateBuilder() + .setYear((int) BitUtil.from(timeValue, 26)) + .setMonth((int) BitUtil.between(timeValue, 22, 26)) + .setDay((int) BitUtil.between(timeValue, 17, 22)) + .setHour((int) BitUtil.between(timeValue, 12, 17)) + .setMinute((int) BitUtil.between(timeValue, 6, 12)) + .setSecond((int) BitUtil.to(timeValue, 6)); + position.setTime(dateBuilder.getDate()); + } + + ByteBuf rawId; + if (newFormat) { + rawId = buf.readSlice(12); + } else { + rawId = buf.readSlice(11); + } + String id = rawId.toString(StandardCharsets.US_ASCII).replaceAll("[^\\p{Print}]", ""); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + if (newFormat) { + DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); + position.setTime(dateFormat.parse(buf.readSlice(17).toString(StandardCharsets.US_ASCII))); + buf.readByte(); + } + + if (!newFormat) { + position.set(Position.PREFIX_IO + 1, buf.readUnsignedByte()); + position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); + } else if (type == MSG_UPLOAD_POSITION_NEW) { + position.set(Position.PREFIX_TEMP + 1, buf.readShortLE()); + position.set(Position.KEY_ODOMETER, buf.readFloatLE()); + } + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NoranProtocolEncoder.java b/src/main/java/org/traccar/protocol/NoranProtocolEncoder.java new file mode 100644 index 000000000..92826c8b2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NoranProtocolEncoder.java @@ -0,0 +1,64 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class NoranProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeContent(String content) { + + ByteBuf buf = Unpooled.buffer(12 + 56); + + buf.writeCharSequence("\r\n*KW", StandardCharsets.US_ASCII); + buf.writeByte(0); + buf.writeShortLE(buf.capacity()); + buf.writeShortLE(NoranProtocolDecoder.MSG_CONTROL); + buf.writeInt(0); // gis ip + buf.writeShortLE(0); // gis port + buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); + buf.writerIndex(buf.writerIndex() + 50 - content.length()); + buf.writeCharSequence("\r\n", StandardCharsets.US_ASCII); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_POSITION_SINGLE: + return encodeContent("*KW,000,000,000000#"); + case Command.TYPE_POSITION_PERIODIC: + int interval = command.getInteger(Command.KEY_FREQUENCY); + return encodeContent("*KW,000,002,000000," + interval + "#"); + case Command.TYPE_POSITION_STOP: + return encodeContent("*KW,000,002,000000,0#"); + case Command.TYPE_ENGINE_STOP: + return encodeContent("*KW,000,007,000000,0#"); + case Command.TYPE_ENGINE_RESUME: + return encodeContent("*KW,000,007,000000,1#"); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/NvsFrameDecoder.java b/src/main/java/org/traccar/protocol/NvsFrameDecoder.java new file mode 100644 index 000000000..e93a58cf6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NvsFrameDecoder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class NvsFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 4 + 2) { + return null; + } + + int length; + if (buf.getUnsignedByte(buf.readerIndex()) == 0) { + length = 2 + buf.getUnsignedShort(buf.readerIndex()); + } else { + length = 4 + 2 + buf.getUnsignedShort(buf.readerIndex() + 4) + 2; + } + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NvsProtocol.java b/src/main/java/org/traccar/protocol/NvsProtocol.java new file mode 100644 index 000000000..d319b22f3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NvsProtocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 2016 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class NvsProtocol extends BaseProtocol { + + public NvsProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new NvsFrameDecoder()); + pipeline.addLast(new NvsProtocolDecoder(NvsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NvsProtocolDecoder.java b/src/main/java/org/traccar/protocol/NvsProtocolDecoder.java new file mode 100644 index 000000000..5d1159f7d --- /dev/null +++ b/src/main/java/org/traccar/protocol/NvsProtocolDecoder.java @@ -0,0 +1,137 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class NvsProtocolDecoder extends BaseProtocolDecoder { + + public NvsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private void sendResponse(Channel channel, SocketAddress remoteAddress, String response) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + Unpooled.copiedBuffer(response, StandardCharsets.US_ASCII), remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + + if (buf.getUnsignedByte(buf.readerIndex()) == 0) { + + buf.readUnsignedShort(); // length + + String imei = buf.toString(buf.readerIndex(), 15, StandardCharsets.US_ASCII); + + if (getDeviceSession(channel, remoteAddress, imei) != null) { + sendResponse(channel, remoteAddress, "OK"); + } else { + sendResponse(channel, remoteAddress, "NO01"); + } + + } else { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + buf.skipBytes(4); // marker + buf.readUnsignedShort(); // length + buf.readLong(); // imei + buf.readUnsignedByte(); // codec + int count = buf.readUnsignedByte(); + + for (int i = 0; i < count; i++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + + position.set("reason", buf.readUnsignedByte()); + + position.setLongitude(buf.readInt() / 10000000.0); + position.setLatitude(buf.readInt() / 10000000.0); + position.setAltitude(buf.readShort()); + position.setCourse(buf.readUnsignedShort()); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.setValid(buf.readUnsignedByte() != 0); + + buf.readUnsignedByte(); // used systems + + buf.readUnsignedByte(); // cause element id + + // Read 1 byte data + int cnt = buf.readUnsignedByte(); + for (int j = 0; j < cnt; j++) { + position.set(Position.PREFIX_IO + buf.readUnsignedByte(), buf.readUnsignedByte()); + } + + // Read 2 byte data + cnt = buf.readUnsignedByte(); + for (int j = 0; j < cnt; j++) { + position.set(Position.PREFIX_IO + buf.readUnsignedByte(), buf.readUnsignedShort()); + } + + // Read 4 byte data + cnt = buf.readUnsignedByte(); + for (int j = 0; j < cnt; j++) { + position.set(Position.PREFIX_IO + buf.readUnsignedByte(), buf.readUnsignedInt()); + } + + // Read 8 byte data + cnt = buf.readUnsignedByte(); + for (int j = 0; j < cnt; j++) { + position.set(Position.PREFIX_IO + buf.readUnsignedByte(), buf.readLong()); + } + + positions.add(position); + } + + return positions; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/NyitechProtocol.java b/src/main/java/org/traccar/protocol/NyitechProtocol.java new file mode 100644 index 000000000..58974be5c --- /dev/null +++ b/src/main/java/org/traccar/protocol/NyitechProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; + +public class NyitechProtocol extends BaseProtocol { + + public NyitechProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, -4, 0, true)); + pipeline.addLast(new NyitechProtocolDecoder(NyitechProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java b/src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java new file mode 100644 index 000000000..e145205f7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java @@ -0,0 +1,123 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class NyitechProtocolDecoder extends BaseProtocolDecoder { + + public NyitechProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final short MSG_LOGIN = 0x1001; + public static final short MSG_COMPREHENSIVE_LIVE = 0x2001; + public static final short MSG_COMPREHENSIVE_HISTORY = 0x2002; + public static final short MSG_ALARM = 0x2003; + public static final short MSG_FIXED = 0x2004; + + private void decodeLocation(Position position, ByteBuf buf) { + + DateBuilder dateBuilder = new DateBuilder() + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + int flags = buf.readUnsignedByte(); + position.setValid(BitUtil.to(flags, 2) > 0); + + double lat = buf.readUnsignedIntLE() / 3600000.0; + double lon = buf.readUnsignedIntLE() / 3600000.0; + + position.setLatitude(BitUtil.check(flags, 2) ? lat : -lat); + position.setLongitude(BitUtil.check(flags, 3) ? lon : -lon); + + position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE())); + position.setCourse(buf.readUnsignedShortLE() * 0.1); + position.setAltitude(buf.readShortLE() * 0.1); + } + + private String decodeAlarm(int type) { + switch (type) { + case 0x09: + return Position.ALARM_ACCELERATION; + case 0x0a: + return Position.ALARM_BRAKING; + case 0x0b: + return Position.ALARM_CORNERING; + case 0x0e: + return Position.ALARM_SOS; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.readUnsignedShortLE(); // length + + String id = buf.readCharSequence(12, StandardCharsets.US_ASCII).toString(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + int type = buf.readUnsignedShortLE(); + + if (type != MSG_LOGIN && type != MSG_COMPREHENSIVE_LIVE + && type != MSG_COMPREHENSIVE_HISTORY && type != MSG_ALARM && type != MSG_FIXED) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (type == MSG_COMPREHENSIVE_LIVE || type == MSG_COMPREHENSIVE_HISTORY) { + buf.skipBytes(6); // time + buf.skipBytes(3); // data + } else if (type == MSG_ALARM) { + buf.readUnsignedShortLE(); // random number + buf.readUnsignedByte(); // tag + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + buf.readUnsignedShortLE(); // threshold + buf.readUnsignedShortLE(); // value + buf.skipBytes(6); // time + } else if (type == MSG_FIXED) { + buf.skipBytes(6); // time + } + + decodeLocation(position, buf); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ObdDongleProtocol.java b/src/main/java/org/traccar/protocol/ObdDongleProtocol.java new file mode 100644 index 000000000..10a55759b --- /dev/null +++ b/src/main/java/org/traccar/protocol/ObdDongleProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ObdDongleProtocol extends BaseProtocol { + + public ObdDongleProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1099, 20, 2, 3, 0)); + pipeline.addLast(new ObdDongleProtocolDecoder(ObdDongleProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java b/src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java new file mode 100644 index 000000000..1c9771ce9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java @@ -0,0 +1,130 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class ObdDongleProtocolDecoder extends BaseProtocolDecoder { + + public ObdDongleProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_TYPE_CONNECT = 0x01; + public static final int MSG_TYPE_CONNACK = 0x02; + public static final int MSG_TYPE_PUBLISH = 0x03; + public static final int MSG_TYPE_PUBACK = 0x04; + public static final int MSG_TYPE_PINGREQ = 0x0C; + public static final int MSG_TYPE_PINGRESP = 0x0D; + public static final int MSG_TYPE_DISCONNECT = 0x0E; + + private static void sendResponse(Channel channel, int type, int index, String imei, ByteBuf content) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(0x5555); // header + response.writeShort(index); + response.writeBytes(imei.getBytes(StandardCharsets.US_ASCII)); + response.writeByte(type); + response.writeShort(content.readableBytes()); + response.writeBytes(content); + content.release(); + response.writeByte(0); // checksum + response.writeShort(0xAAAA); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + int index = buf.readUnsignedShort(); + + String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + int type = buf.readUnsignedByte(); + + buf.readUnsignedShort(); // data length + + if (type == MSG_TYPE_CONNECT) { + + ByteBuf response = Unpooled.buffer(); + response.writeByte(1); + response.writeShort(0); + response.writeInt(0); + sendResponse(channel, MSG_TYPE_CONNACK, index, imei, response); + + } else if (type == MSG_TYPE_PUBLISH) { + + int typeMajor = buf.readUnsignedByte(); + int typeMinor = buf.readUnsignedByte(); + + buf.readUnsignedByte(); // event id + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + + int flags = buf.readUnsignedByte(); + + position.setValid(!BitUtil.check(flags, 6)); + + position.set(Position.KEY_SATELLITES, BitUtil.to(flags, 4)); + + double longitude = ((BitUtil.to(buf.readUnsignedShort(), 1) << 24) + buf.readUnsignedMedium()) * 0.00001; + position.setLongitude(BitUtil.check(flags, 5) ? longitude : -longitude); + + double latitude = buf.readUnsignedMedium() * 0.00001; + position.setLatitude(BitUtil.check(flags, 4) ? latitude : -latitude); + + int speedCourse = buf.readUnsignedMedium(); + position.setSpeed(UnitsConverter.knotsFromMph(BitUtil.from(speedCourse, 10) * 0.1)); + position.setCourse(BitUtil.to(speedCourse, 10)); + + ByteBuf response = Unpooled.buffer(); + response.writeByte(typeMajor); + response.writeByte(typeMinor); + sendResponse(channel, MSG_TYPE_PUBACK, index, imei, response); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/OigoProtocol.java b/src/main/java/org/traccar/protocol/OigoProtocol.java new file mode 100644 index 000000000..5056f68aa --- /dev/null +++ b/src/main/java/org/traccar/protocol/OigoProtocol.java @@ -0,0 +1,33 @@ +/* + * Copyright 2016 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class OigoProtocol extends BaseProtocol { + + public OigoProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new OigoProtocolDecoder(OigoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/OigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/OigoProtocolDecoder.java new file mode 100644 index 000000000..b9cc71e8c --- /dev/null +++ b/src/main/java/org/traccar/protocol/OigoProtocolDecoder.java @@ -0,0 +1,240 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class OigoProtocolDecoder extends BaseProtocolDecoder { + + public OigoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_AR_LOCATION = 0x00; + public static final int MSG_AR_REMOTE_START = 0x10; + + public static final int MSG_ACKNOWLEDGEMENT = 0xE0; + + private Position decodeArMessage(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + buf.skipBytes(1); // header + buf.readUnsignedShort(); // length + + int type = buf.readUnsignedByte(); + + int tag = buf.readUnsignedByte(); + + DeviceSession deviceSession; + switch (BitUtil.to(tag, 3)) { + case 0: + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + deviceSession = getDeviceSession(channel, remoteAddress, imei); + break; + case 1: + buf.skipBytes(1); + String meid = buf.readSlice(14).toString(StandardCharsets.US_ASCII); + deviceSession = getDeviceSession(channel, remoteAddress, meid); + break; + default: + deviceSession = getDeviceSession(channel, remoteAddress); + break; + } + + if (deviceSession == null || type != MSG_AR_LOCATION) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + int mask = buf.readInt(); + + if (BitUtil.check(mask, 0)) { + position.set(Position.KEY_INDEX, buf.readUnsignedShort()); + } + + if (BitUtil.check(mask, 1)) { + int date = buf.readUnsignedByte(); + DateBuilder dateBuilder = new DateBuilder() + .setDate(BitUtil.between(date, 4, 8) + 2010, BitUtil.to(date, 4), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + } + + if (BitUtil.check(mask, 2)) { + buf.skipBytes(5); // device time + } + + if (BitUtil.check(mask, 3)) { + position.setLatitude(buf.readUnsignedInt() * 0.000001 - 90); + position.setLongitude(buf.readUnsignedInt() * 0.000001 - 180.0); + } + + if (BitUtil.check(mask, 4)) { + int status = buf.readUnsignedByte(); + position.setValid(BitUtil.between(status, 4, 8) != 0); + position.set(Position.KEY_SATELLITES, BitUtil.to(status, 4)); + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + } + + if (BitUtil.check(mask, 5)) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + } + + if (BitUtil.check(mask, 6)) { + position.setCourse(buf.readUnsignedShort()); + } + + if (BitUtil.check(mask, 7)) { + position.setAltitude(buf.readShort()); + } + + if (BitUtil.check(mask, 8)) { + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + } + + if (BitUtil.check(mask, 9)) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); + } + + if (BitUtil.check(mask, 10)) { + position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); + } + + if (BitUtil.check(mask, 11)) { + buf.skipBytes(2); // gpio + } + + if (BitUtil.check(mask, 12)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); + } + + if (BitUtil.check(mask, 13)) { + buf.skipBytes(6); // software version + } + + if (BitUtil.check(mask, 14)) { + buf.skipBytes(5); // hardware version + } + + if (BitUtil.check(mask, 15)) { + buf.readUnsignedShort(); // device config + } + + return position; + } + + private double convertCoordinate(long value) { + boolean negative = value < 0; + value = Math.abs(value); + double minutes = (value % 100000) * 0.001; + value /= 100000; + double degrees = value + minutes / 60; + return negative ? -degrees : degrees; + } + + private Position decodeMgMessage(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + buf.readUnsignedByte(); // tag + int flags = buf.getUnsignedByte(buf.readerIndex()); + + DeviceSession deviceSession; + if (BitUtil.check(flags, 6)) { + buf.readUnsignedByte(); // flags + deviceSession = getDeviceSession(channel, remoteAddress); + } else { + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + deviceSession = getDeviceSession(channel, remoteAddress, imei); + } + + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.skipBytes(8); // imsi + + int date = buf.readUnsignedShort(); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(2010 + BitUtil.from(date, 12), BitUtil.between(date, 8, 12), BitUtil.to(date, 8)) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), 0); + + position.setValid(true); + position.setLatitude(convertCoordinate(buf.readInt())); + position.setLongitude(convertCoordinate(buf.readInt())); + + position.setAltitude(UnitsConverter.metersFromFeet(buf.readShort())); + position.setCourse(buf.readUnsignedShort()); + position.setSpeed(UnitsConverter.knotsFromMph(buf.readUnsignedByte())); + + position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); + position.set(Position.PREFIX_IO + 1, buf.readUnsignedByte()); + + dateBuilder.setSecond(buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + + int index = buf.readUnsignedByte(); + + position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, (long) (buf.readUnsignedInt() * 1609.34)); + + if (channel != null && BitUtil.check(flags, 7)) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(MSG_ACKNOWLEDGEMENT); + response.writeByte(index); + response.writeByte(0x00); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (buf.getUnsignedByte(buf.readerIndex()) == 0x7e) { + return decodeArMessage(channel, remoteAddress, buf); + } else { + return decodeMgMessage(channel, remoteAddress, buf); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/OkoProtocol.java b/src/main/java/org/traccar/protocol/OkoProtocol.java new file mode 100644 index 000000000..9571ccc48 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OkoProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class OkoProtocol extends BaseProtocol { + + public OkoProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '}')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new OkoProtocolDecoder(OkoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java b/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java new file mode 100644 index 000000000..5adf61494 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java @@ -0,0 +1,100 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class OkoProtocolDecoder extends BaseProtocolDecoder { + + public OkoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("{") + .number("(d{15}),").optional() // imei + .number("(dd)(dd)(dd).d+,") // time + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(d+),") // satellites + .number("(d+.d+),") // adc + .number("(xx),") // event + .number("(d+.d+),") // power + .number("d,") // memory status + .number("(xx)") // io + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession; + if (parser.hasNext()) { + deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + } else { + deviceSession = getDeviceSession(channel, remoteAddress); + } + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.KEY_EVENT, parser.next()); + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_INPUT, parser.nextHexInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/OpenGtsProtocol.java b/src/main/java/org/traccar/protocol/OpenGtsProtocol.java new file mode 100644 index 000000000..5ef3260c6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OpenGtsProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class OpenGtsProtocol extends BaseProtocol { + + public OpenGtsProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new OpenGtsProtocolDecoder(OpenGtsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java b/src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java new file mode 100644 index 000000000..b76cbfa85 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java @@ -0,0 +1,115 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +public class OpenGtsProtocolDecoder extends BaseHttpProtocolDecoder { + + private static final Pattern PATTERN = new PatternBuilder() + .text("$GPRMC,") + .number("(dd)(dd)(dd)(?:.d+)?,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+),") // speed + .number("(d+.d+)?,") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .any() + .compile(); + + public OpenGtsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); + Map> params = decoder.parameters(); + + Position position = new Position(getProtocolName()); + + for (Map.Entry> entry : params.entrySet()) { + String value = entry.getValue().get(0); + switch (entry.getKey()) { + case "id": + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + break; + case "gprmc": + Parser parser = new Parser(PATTERN, value); + if (!parser.matches()) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + break; + case "alt": + position.setAltitude(Double.parseDouble(value)); + break; + case "batt": + position.set(Position.KEY_BATTERY_LEVEL, Double.parseDouble(value)); + break; + default: + break; + } + } + + if (position.getDeviceId() != 0) { + sendResponse(channel, HttpResponseStatus.OK); + return position; + } else { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/OrionFrameDecoder.java b/src/main/java/org/traccar/protocol/OrionFrameDecoder.java new file mode 100644 index 000000000..948806609 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OrionFrameDecoder.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class OrionFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int length = 6; + + if (buf.readableBytes() >= length) { + + int type = buf.getUnsignedByte(buf.readerIndex() + 2) & 0x0f; + + if (type == OrionProtocolDecoder.MSG_USERLOG && buf.readableBytes() >= length + 5) { + + int index = buf.readerIndex() + 3; + int count = buf.getUnsignedByte(index) & 0x0f; + index += 5; + length += 5; + + for (int i = 0; i < count; i++) { + if (buf.readableBytes() < length) { + return null; + } + int logLength = buf.getUnsignedByte(index + 1); + index += logLength; + length += logLength; + } + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + } else if (type == OrionProtocolDecoder.MSG_SYSLOG && buf.readableBytes() >= length + 12) { + + length += buf.getUnsignedShortLE(buf.readerIndex() + 8); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/OrionProtocol.java b/src/main/java/org/traccar/protocol/OrionProtocol.java new file mode 100644 index 000000000..8485ae638 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OrionProtocol.java @@ -0,0 +1,34 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class OrionProtocol extends BaseProtocol { + + public OrionProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new OrionFrameDecoder()); + pipeline.addLast(new OrionProtocolDecoder(OrionProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/OrionProtocolDecoder.java b/src/main/java/org/traccar/protocol/OrionProtocolDecoder.java new file mode 100644 index 000000000..af819989e --- /dev/null +++ b/src/main/java/org/traccar/protocol/OrionProtocolDecoder.java @@ -0,0 +1,115 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.LinkedList; +import java.util.List; + +public class OrionProtocolDecoder extends BaseProtocolDecoder { + + public OrionProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_USERLOG = 0; + public static final int MSG_SYSLOG = 3; + + private static void sendResponse(Channel channel, ByteBuf buf) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(4); + response.writeByte('*'); + response.writeShort(buf.getUnsignedShort(buf.writerIndex() - 2)); + response.writeByte(buf.getUnsignedByte(buf.writerIndex() - 3)); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + private static double convertCoordinate(int raw) { + int degrees = raw / 1000000; + double minutes = (raw % 1000000) / 10000.0; + return degrees + minutes / 60; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + int type = buf.readUnsignedByte() & 0x0f; + + if (type == MSG_USERLOG) { + + int header = buf.readUnsignedByte(); + + if ((header & 0x40) != 0) { + sendResponse(channel, buf); + } + + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, String.valueOf(buf.readUnsignedInt())); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + for (int i = 0; i < (header & 0x0f); i++) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + buf.readUnsignedByte(); // length + position.set(Position.KEY_FLAGS, buf.readUnsignedShortLE()); + + position.setLatitude(convertCoordinate(buf.readIntLE())); + position.setLongitude(convertCoordinate(buf.readIntLE())); + position.setAltitude(buf.readShortLE() / 10.0); + position.setCourse(buf.readUnsignedShortLE()); + position.setSpeed(buf.readUnsignedShortLE() * 0.0539957); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + int satellites = buf.readUnsignedByte(); + position.setValid(satellites >= 3); + position.set(Position.KEY_SATELLITES, satellites); + + positions.add(position); + } + + return positions; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocol.java b/src/main/java/org/traccar/protocol/OsmAndProtocol.java new file mode 100644 index 000000000..d3aa2fd6f --- /dev/null +++ b/src/main/java/org/traccar/protocol/OsmAndProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2015 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class OsmAndProtocol extends BaseProtocol { + + public OsmAndProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new OsmAndProtocolDecoder(OsmAndProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java new file mode 100644 index 000000000..3bc71de81 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java @@ -0,0 +1,184 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateUtil; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder { + + public OsmAndProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); + Map> params = decoder.parameters(); + if (params.isEmpty()) { + decoder = new QueryStringDecoder(request.content().toString(StandardCharsets.US_ASCII), false); + params = decoder.parameters(); + } + + Position position = new Position(getProtocolName()); + position.setValid(true); + + Network network = new Network(); + + for (Map.Entry> entry : params.entrySet()) { + for (String value : entry.getValue()) { + switch (entry.getKey()) { + case "id": + case "deviceid": + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + break; + case "valid": + position.setValid(Boolean.parseBoolean(value) || "1".equals(value)); + break; + case "timestamp": + try { + long timestamp = Long.parseLong(value); + if (timestamp < Integer.MAX_VALUE) { + timestamp *= 1000; + } + position.setTime(new Date(timestamp)); + } catch (NumberFormatException error) { + if (value.contains("T")) { + position.setTime(DateUtil.parseDate(value)); + } else { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + position.setTime(dateFormat.parse(value)); + } + } + break; + case "lat": + position.setLatitude(Double.parseDouble(value)); + break; + case "lon": + position.setLongitude(Double.parseDouble(value)); + break; + case "location": + String[] location = value.split(","); + position.setLatitude(Double.parseDouble(location[0])); + position.setLongitude(Double.parseDouble(location[1])); + break; + case "cell": + String[] cell = value.split(","); + if (cell.length > 4) { + network.addCellTower(CellTower.from( + Integer.parseInt(cell[0]), Integer.parseInt(cell[1]), + Integer.parseInt(cell[2]), Integer.parseInt(cell[3]), Integer.parseInt(cell[4]))); + } else { + network.addCellTower(CellTower.from( + Integer.parseInt(cell[0]), Integer.parseInt(cell[1]), + Integer.parseInt(cell[2]), Integer.parseInt(cell[3]))); + } + break; + case "wifi": + String[] wifi = value.split(","); + network.addWifiAccessPoint(WifiAccessPoint.from( + wifi[0].replace('-', ':'), Integer.parseInt(wifi[1]))); + break; + case "speed": + position.setSpeed(convertSpeed(Double.parseDouble(value), "kn")); + break; + case "bearing": + case "heading": + position.setCourse(Double.parseDouble(value)); + break; + case "altitude": + position.setAltitude(Double.parseDouble(value)); + break; + case "accuracy": + position.setAccuracy(Double.parseDouble(value)); + break; + case "hdop": + position.set(Position.KEY_HDOP, Double.parseDouble(value)); + break; + case "batt": + position.set(Position.KEY_BATTERY_LEVEL, Double.parseDouble(value)); + break; + case "driverUniqueId": + position.set(Position.KEY_DRIVER_UNIQUE_ID, value); + break; + default: + try { + position.set(entry.getKey(), Double.parseDouble(value)); + } catch (NumberFormatException e) { + switch (value) { + case "true": + position.set(entry.getKey(), true); + break; + case "false": + position.set(entry.getKey(), false); + break; + default: + position.set(entry.getKey(), value); + break; + } + } + break; + } + } + } + + if (position.getFixTime() == null) { + position.setTime(new Date()); + } + + if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { + position.setNetwork(network); + } + + if (position.getLatitude() == 0 && position.getLongitude() == 0) { + getLastLocation(position, position.getDeviceTime()); + } + + if (position.getDeviceId() != 0) { + sendResponse(channel, HttpResponseStatus.OK); + return position; + } else { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocol.java b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java new file mode 100644 index 000000000..0086371d8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Jan-Piet Mens (jpmens@gmail.com) + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class OwnTracksProtocol extends BaseProtocol { + + public OwnTracksProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new OwnTracksProtocolDecoder(OwnTracksProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java new file mode 100644 index 000000000..323d97fa3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java @@ -0,0 +1,215 @@ +/* + * Copyright 2017 Jan-Piet Mens (jpmens@gmail.com) + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import javax.json.Json; +import javax.json.JsonObject; +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class OwnTracksProtocolDecoder extends BaseHttpProtocolDecoder { + + public OwnTracksProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + JsonObject root = Json.createReader( + new StringReader(request.content().toString(StandardCharsets.US_ASCII))).readObject(); + + if (!root.containsKey("_type")) { + sendResponse(channel, HttpResponseStatus.OK); + return null; + } + if (!root.getString("_type").equals("location") + && !root.getString("_type").equals("lwt")) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + Position position = new Position(getProtocolName()); + String uniqueId; + + if (root.containsKey("topic")) { + uniqueId = root.getString("topic"); + if (root.containsKey("tid")) { + position.set("tid", root.getString("tid")); + } + } else { + uniqueId = root.getString("tid"); + } + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + if (root.getString("_type").equals("lwt")) { + sendResponse(channel, HttpResponseStatus.OK); + return null; + } + + if (root.containsKey("t") && root.getString("t").equals("p")) { + sendResponse(channel, HttpResponseStatus.OK); + return null; + } + + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(root.getJsonNumber("tst").longValue() * 1000)); + if (root.containsKey("sent")) { + position.setDeviceTime(new Date(root.getJsonNumber("sent").longValue() * 1000)); + } + + position.setValid(true); + + position.setLatitude(root.getJsonNumber("lat").doubleValue()); + position.setLongitude(root.getJsonNumber("lon").doubleValue()); + + if (root.containsKey("vel")) { + position.setSpeed(UnitsConverter.knotsFromKph(root.getInt("vel"))); + } + if (root.containsKey("alt")) { + position.setAltitude(root.getInt("alt")); + } + if (root.containsKey("cog")) { + position.setCourse(root.getInt("cog")); + } + if (root.containsKey("acc")) { + position.setAccuracy(root.getInt("acc")); + } + if (root.containsKey("t")) { + String trigger = root.getString("t"); + position.set("t", trigger); + Integer reportType = -1; + if (root.containsKey("rty")) { + reportType = root.getInt("rty"); + } + setEventOrAlarm(position, trigger, reportType); + } + if (root.containsKey("batt")) { + position.set(Position.KEY_BATTERY_LEVEL, root.getInt("batt")); + } + if (root.containsKey("uext")) { + position.set(Position.KEY_POWER, root.getJsonNumber("uext").doubleValue()); + } + if (root.containsKey("ubatt")) { + position.set(Position.KEY_BATTERY, root.getJsonNumber("ubatt").doubleValue()); + } + if (root.containsKey("vin")) { + position.set(Position.KEY_VIN, root.getString("vin")); + } + if (root.containsKey("name")) { + position.set(Position.KEY_VIN, root.getString("name")); + } + if (root.containsKey("rpm")) { + position.set(Position.KEY_RPM, root.getInt("rpm")); + } + if (root.containsKey("ign")) { + position.set(Position.KEY_IGNITION, root.getBoolean("ign")); + } + if (root.containsKey("motion")) { + position.set(Position.KEY_MOTION, root.getBoolean("motion")); + } + if (root.containsKey("odometer")) { + position.set(Position.KEY_ODOMETER, root.getJsonNumber("odometer").doubleValue() * 1000.0); + } + if (root.containsKey("hmc")) { + position.set(Position.KEY_HOURS, root.getJsonNumber("hmc").doubleValue() / 3600.0); + } + + if (root.containsKey("anum")) { + Integer numberOfAnalogueInputs = root.getInt("anum"); + for (Integer i = 0; i < numberOfAnalogueInputs; i++) { + String indexString = String.format("%02d", i); + if (root.containsKey("adda-" + indexString)) { + position.set(Position.PREFIX_ADC + (i + 1), root.getString("adda-" + indexString)); + } + if (root.containsKey("temp_c-" + indexString)) { + position.set(Position.PREFIX_TEMP + (i + 1), + root.getJsonNumber("temp_c-" + indexString).doubleValue()); + } + } + } + + sendResponse(channel, HttpResponseStatus.OK); + return position; + } + + private void setEventOrAlarm(Position position, String trigger, Integer reportType) { + switch (trigger) { + case "9": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case "1": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_ON); + break; + case "i": + position.set(Position.KEY_IGNITION, true); + break; + case "I": + position.set(Position.KEY_IGNITION, false); + break; + case "E": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); + break; + case "e": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; + case "!": + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + break; + case "s": + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + break; + case "h": + switch (reportType) { + case 0: + case 3: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 1: + case 4: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 2: + case 5: + default: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + } + break; + default: + break; + } + } +} diff --git a/src/main/java/org/traccar/protocol/PathAwayProtocol.java b/src/main/java/org/traccar/protocol/PathAwayProtocol.java new file mode 100644 index 000000000..6b5d75c5e --- /dev/null +++ b/src/main/java/org/traccar/protocol/PathAwayProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class PathAwayProtocol extends BaseProtocol { + + public PathAwayProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new PathAwayProtocolDecoder(PathAwayProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java b/src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java new file mode 100644 index 000000000..02a15e34a --- /dev/null +++ b/src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java @@ -0,0 +1,97 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class PathAwayProtocolDecoder extends BaseProtocolDecoder { + + public PathAwayProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$PWS,") + .number("d+,") // version + .expression("[^,]*,") // name + .expression("[^,]*,") // icon + .expression("[^,]*,") // color + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(-?d+.?d*),") // altitude + .number("(-?d+.?d*),") // speed + .number("(-?d+.?d*),") // course + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); + + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, decoder.parameters().get("UserName").get(0)); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, decoder.parameters().get("LOC").get(0)); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(true); + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + if (channel != null) { + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)).addListener(ChannelFutureListener.CLOSE); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocol.java b/src/main/java/org/traccar/protocol/PiligrimProtocol.java new file mode 100644 index 000000000..d88c1ab72 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PiligrimProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class PiligrimProtocol extends BaseProtocol { + + public PiligrimProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(16384)); + pipeline.addLast(new PiligrimProtocolDecoder(PiligrimProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java new file mode 100644 index 000000000..47aa86da7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -0,0 +1,167 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.QueryStringDecoder; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; + +public class PiligrimProtocolDecoder extends BaseProtocolDecoder { + + public PiligrimProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private void sendResponse(Channel channel, String message) { + if (channel != null) { + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, + Unpooled.copiedBuffer(message, StandardCharsets.US_ASCII)); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + public static final int MSG_GPS = 0xF1; + public static final int MSG_GPS_SENSORS = 0xF2; + public static final int MSG_EVENTS = 0xF3; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + String uri = request.uri(); + + if (uri.startsWith("/config")) { + + sendResponse(channel, "CONFIG: OK"); + + } else if (uri.startsWith("/addlog")) { + + sendResponse(channel, "ADDLOG: OK"); + + } else if (uri.startsWith("/inform")) { + + sendResponse(channel, "INFORM: OK"); + + } else if (uri.startsWith("/bingps")) { + + sendResponse(channel, "BINGPS: OK"); + + QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, decoder.parameters().get("imei").get(0)); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + ByteBuf buf = request.content(); + + while (buf.readableBytes() > 2) { + + buf.readUnsignedByte(); // header + int type = buf.readUnsignedByte(); + buf.readUnsignedByte(); // length + + if (type == MSG_GPS || type == MSG_GPS_SENSORS) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDay(buf.readUnsignedByte()) + .setMonth(buf.getByte(buf.readerIndex()) & 0x0f) + .setYear(2010 + (buf.readUnsignedByte() >> 4)) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + position.setTime(dateBuilder.getDate()); + + double latitude = buf.readUnsignedByte(); + latitude += buf.readUnsignedByte() / 60.0; + latitude += buf.readUnsignedByte() / 6000.0; + latitude += buf.readUnsignedByte() / 600000.0; + + double longitude = buf.readUnsignedByte(); + longitude += buf.readUnsignedByte() / 60.0; + longitude += buf.readUnsignedByte() / 6000.0; + longitude += buf.readUnsignedByte() / 600000.0; + + int flags = buf.readUnsignedByte(); + if (BitUtil.check(flags, 0)) { + latitude = -latitude; + } + if (BitUtil.check(flags, 1)) { + longitude = -longitude; + } + position.setLatitude(latitude); + position.setLongitude(longitude); + + int satellites = buf.readUnsignedByte(); + position.set(Position.KEY_SATELLITES, satellites); + position.setValid(satellites >= 3); + + position.setSpeed(buf.readUnsignedByte()); + + double course = buf.readUnsignedByte() << 1; + course += (flags >> 2) & 1; + course += buf.readUnsignedByte() / 100.0; + position.setCourse(course); + + if (type == MSG_GPS_SENSORS) { + double power = buf.readUnsignedByte(); + power += buf.readUnsignedByte() << 8; + position.set(Position.KEY_POWER, power * 0.01); + + double battery = buf.readUnsignedByte(); + battery += buf.readUnsignedByte() << 8; + position.set(Position.KEY_BATTERY, battery * 0.01); + + buf.skipBytes(6); + } + + positions.add(position); + + } else if (type == MSG_EVENTS) { + + buf.skipBytes(13); + } + } + + return positions; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/PretraceProtocol.java b/src/main/java/org/traccar/protocol/PretraceProtocol.java new file mode 100644 index 000000000..f753cbdb4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PretraceProtocol.java @@ -0,0 +1,44 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class PretraceProtocol extends BaseProtocol { + + public PretraceProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_POSITION_PERIODIC); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new PretraceProtocolEncoder()); + pipeline.addLast(new PretraceProtocolDecoder(PretraceProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java b/src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java new file mode 100644 index 000000000..a19384e62 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java @@ -0,0 +1,132 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class PretraceProtocolDecoder extends BaseProtocolDecoder { + + public PretraceProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("(") + .number("(d{15})") // imei + .number("Uddd") // type + .number("d") // gps type + .expression("([AV])") // validity + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("(dd)(dd.dddd)") // latitude + .expression("([NS])") + .number("(ddd)(dd.dddd)") // longitude + .expression("([EW])") + .number("(ddd)") // speed + .number("(ddd)") // course + .number("(xxx)") // altitude + .number("(x{8})") // odometer + .number("(x)") // satellites + .number("(dd)") // hdop + .number("(dd)") // gsm + .expression("(.{8}),&") // state + .expression("(.+)?") // optional data + .text("^") + .number("xx") // checksum + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.next().equals("A")); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); + position.setCourse(parser.nextInt(0)); + position.setAltitude(parser.nextHexInt(0)); + + position.set(Position.KEY_ODOMETER, parser.nextHexInt(0)); + position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); + position.set(Position.KEY_HDOP, parser.nextInt(0)); + position.set(Position.KEY_RSSI, parser.nextInt(0)); + + parser.next(); // state + + if (parser.hasNext()) { + for (String value : parser.next().split(",")) { + switch (value.charAt(0)) { + case 'P': + if (value.charAt(1) == '1') { + if (value.charAt(4) == '%') { + position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(value.substring(2, 4))); + } else { + position.set(Position.KEY_BATTERY, Integer.parseInt(value.substring(2), 16) * 0.01); + } + } else { + position.set(Position.KEY_POWER, Integer.parseInt(value.substring(2), 16) * 0.01); + } + break; + case 'T': + double temperature = Integer.parseInt(value.substring(2), 16) * 0.25; + if (value.charAt(1) == '1') { + position.set(Position.KEY_DEVICE_TEMP, temperature); + } else { + position.set(Position.PREFIX_TEMP + (value.charAt(1) - '0'), temperature); + } + break; + case 'F': + position.set("fuel" + (value.charAt(1) - '0'), Integer.parseInt(value.substring(2), 16) * 0.01); + break; + case 'R': + position.set(Position.KEY_DRIVER_UNIQUE_ID, value.substring(3)); + break; + default: + break; + } + } + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java b/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java new file mode 100644 index 000000000..9cf951e3b --- /dev/null +++ b/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015 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. + * 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 org.traccar.BaseProtocolEncoder; +import org.traccar.Context; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +public class PretraceProtocolEncoder extends BaseProtocolEncoder { + + private String formatCommand(String uniqueId, String data) { + String content = uniqueId + data; + return String.format("(%s^%02X)", content, Checksum.xor(content)); + } + + @Override + protected Object encodeCommand(Command command) { + + String uniqueId = Context.getIdentityManager().getById(command.getDeviceId()).getUniqueId(); + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatCommand(uniqueId, command.getString(Command.KEY_DATA)); + case Command.TYPE_POSITION_PERIODIC: + return formatCommand( + uniqueId, String.format("D221%1$d,%1$d,,", command.getInteger(Command.KEY_FREQUENCY))); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/PricolProtocol.java b/src/main/java/org/traccar/protocol/PricolProtocol.java new file mode 100644 index 000000000..6821cd949 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PricolProtocol.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.FixedLengthFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class PricolProtocol extends BaseProtocol { + + public PricolProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new FixedLengthFrameDecoder(64)); + pipeline.addLast(new PricolProtocolDecoder(PricolProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new PricolProtocolDecoder(PricolProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/PricolProtocolDecoder.java b/src/main/java/org/traccar/protocol/PricolProtocolDecoder.java new file mode 100644 index 000000000..190c68258 --- /dev/null +++ b/src/main/java/org/traccar/protocol/PricolProtocolDecoder.java @@ -0,0 +1,98 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class PricolProtocolDecoder extends BaseProtocolDecoder { + + public PricolProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // header + + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, buf.readSlice(7).toString(StandardCharsets.US_ASCII)); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set("eventType", buf.readUnsignedByte()); + position.set("packetVersion", buf.readUnsignedByte()); + position.set(Position.KEY_STATUS, buf.readUnsignedByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set(Position.KEY_GPS, buf.readUnsignedByte()); + + position.setTime(new DateBuilder() + .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); + + position.setValid(true); + + double lat = buf.getUnsignedShort(buf.readerIndex()) / 100; + lat += (buf.readUnsignedShort() % 100 * 10000 + buf.readUnsignedShort()) / 600000.0; + position.setLatitude(buf.readUnsignedByte() == 'S' ? -lat : lat); + + double lon = buf.getUnsignedMedium(buf.readerIndex()) / 100; + lon += (buf.readUnsignedMedium() % 100 * 10000 + buf.readUnsignedShort()) / 600000.0; + position.setLongitude(buf.readUnsignedByte() == 'W' ? -lon : lon); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + position.set(Position.KEY_INPUT, buf.readUnsignedShort()); + position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); + + position.set("analogAlerts", buf.readUnsignedByte()); + position.set("customAlertTypes", buf.readUnsignedShort()); + + for (int i = 1; i <= 5; i++) { + position.set(Position.PREFIX_ADC + i, buf.readUnsignedShort()); + } + + position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); + position.set(Position.KEY_RPM, buf.readUnsignedShort()); + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + Unpooled.copiedBuffer("ACK", StandardCharsets.US_ASCII), remoteAddress)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/ProgressProtocol.java b/src/main/java/org/traccar/protocol/ProgressProtocol.java new file mode 100644 index 000000000..aac84205d --- /dev/null +++ b/src/main/java/org/traccar/protocol/ProgressProtocol.java @@ -0,0 +1,36 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; +public class ProgressProtocol extends BaseProtocol { + + public ProgressProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, 4, 0, true)); + pipeline.addLast(new ProgressProtocolDecoder(ProgressProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java b/src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java new file mode 100644 index 000000000..0025cd9e7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java @@ -0,0 +1,172 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class ProgressProtocolDecoder extends BaseProtocolDecoder { + + private long lastIndex; + private long newIndex; + + public ProgressProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_NULL = 0; + public static final int MSG_IDENT = 1; + public static final int MSG_IDENT_FULL = 2; + public static final int MSG_POINT = 10; + public static final int MSG_LOG_SYNC = 100; + public static final int MSG_LOGMSG = 101; + public static final int MSG_TEXT = 102; + public static final int MSG_ALARM = 200; + public static final int MSG_ALARM_RECIEVED = 201; + + private void requestArchive(Channel channel) { + if (lastIndex == 0) { + lastIndex = newIndex; + } else if (newIndex > lastIndex) { + ByteBuf request = Unpooled.buffer(12); + request.writeShortLE(MSG_LOG_SYNC); + request.writeShortLE(4); + request.writeIntLE((int) lastIndex); + request.writeIntLE(0); + channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + int type = buf.readUnsignedShortLE(); + buf.readUnsignedShortLE(); // length + + if (type == MSG_IDENT || type == MSG_IDENT_FULL) { + + buf.readUnsignedIntLE(); // id + int length = buf.readUnsignedShortLE(); + buf.skipBytes(length); + length = buf.readUnsignedShortLE(); + buf.skipBytes(length); + length = buf.readUnsignedShortLE(); + String imei = buf.readSlice(length).toString(StandardCharsets.US_ASCII); + getDeviceSession(channel, remoteAddress, imei); + + } else if (type == MSG_POINT || type == MSG_ALARM || type == MSG_LOGMSG) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + int recordCount = 1; + if (type == MSG_LOGMSG) { + recordCount = buf.readUnsignedShortLE(); + } + + for (int j = 0; j < recordCount; j++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (type == MSG_LOGMSG) { + position.set(Position.KEY_ARCHIVE, true); + int subtype = buf.readUnsignedShortLE(); + if (subtype == MSG_ALARM) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + if (buf.readUnsignedShortLE() > buf.readableBytes()) { + lastIndex += 1; + break; // workaround for device bug + } + lastIndex = buf.readUnsignedIntLE(); + position.set(Position.KEY_INDEX, lastIndex); + } else { + newIndex = buf.readUnsignedIntLE(); + } + + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + position.setLatitude(buf.readIntLE() * 180.0 / 0x7FFFFFFF); + position.setLongitude(buf.readIntLE() * 180.0 / 0x7FFFFFFF); + position.setSpeed(buf.readUnsignedIntLE() * 0.01); + position.setCourse(buf.readUnsignedShortLE() * 0.01); + position.setAltitude(buf.readUnsignedShortLE() * 0.01); + + int satellites = buf.readUnsignedByte(); + position.setValid(satellites >= 3); + position.set(Position.KEY_SATELLITES, satellites); + + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + + long extraFlags = buf.readLongLE(); + + if (BitUtil.check(extraFlags, 0)) { + int count = buf.readUnsignedShortLE(); + for (int i = 1; i <= count; i++) { + position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE()); + } + } + + if (BitUtil.check(extraFlags, 1)) { + int size = buf.readUnsignedShortLE(); + position.set("can", buf.toString(buf.readerIndex(), size, StandardCharsets.US_ASCII)); + buf.skipBytes(size); + } + + if (BitUtil.check(extraFlags, 2)) { + position.set("passenger", ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedShortLE()))); + } + + if (type == MSG_ALARM) { + position.set(Position.KEY_ALARM, true); + byte[] response = {(byte) 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(response), remoteAddress)); + } + + buf.readUnsignedIntLE(); // crc + + positions.add(position); + } + + requestArchive(channel); + + return positions; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt3000Protocol.java b/src/main/java/org/traccar/protocol/Pt3000Protocol.java new file mode 100644 index 000000000..1ad0026a3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt3000Protocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Pt3000Protocol extends BaseProtocol { + + public Pt3000Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, 'd')); // probably wrong + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Pt3000ProtocolDecoder(Pt3000Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java new file mode 100644 index 000000000..e7f9e062a --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java @@ -0,0 +1,83 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Pt3000ProtocolDecoder extends BaseProtocolDecoder { + + public Pt3000ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("%(d+),") // imei + .text("$GPRMC,") + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt502FrameDecoder.java b/src/main/java/org/traccar/protocol/Pt502FrameDecoder.java new file mode 100644 index 000000000..316cd987f --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt502FrameDecoder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +import java.nio.charset.StandardCharsets; + +public class Pt502FrameDecoder extends BaseFrameDecoder { + + private static final int BINARY_HEADER = 5; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + if (buf.getUnsignedByte(buf.readerIndex()) == 0xbf + && buf.toString(buf.readerIndex() + BINARY_HEADER, 4, StandardCharsets.US_ASCII).equals("$PHD")) { + + int length = buf.getUnsignedShortLE(buf.readerIndex() + 3); + if (buf.readableBytes() >= length) { + buf.skipBytes(BINARY_HEADER); + ByteBuf result = buf.readRetainedSlice(length - BINARY_HEADER - 2); + buf.skipBytes(2); // line break + return result; + } + + } else { + + if (buf.getUnsignedByte(buf.readerIndex()) == 0xbf) { + buf.skipBytes(BINARY_HEADER); + } + + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\r'); + if (index < 0) { + index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\n'); + } + + if (index > 0) { + ByteBuf result = buf.readRetainedSlice(index - buf.readerIndex()); + while (buf.isReadable() + && (buf.getByte(buf.readerIndex()) == '\r' || buf.getByte(buf.readerIndex()) == '\n')) { + buf.skipBytes(1); + } + return result; + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt502Protocol.java b/src/main/java/org/traccar/protocol/Pt502Protocol.java new file mode 100644 index 000000000..5afb9451d --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt502Protocol.java @@ -0,0 +1,44 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class Pt502Protocol extends BaseProtocol { + + public Pt502Protocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_SET_TIMEZONE, + Command.TYPE_ALARM_SPEED, + Command.TYPE_OUTPUT_CONTROL, + Command.TYPE_REQUEST_PHOTO); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Pt502FrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Pt502ProtocolEncoder()); + pipeline.addLast(new Pt502ProtocolDecoder(Pt502Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java new file mode 100644 index 000000000..0afec67ad --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java @@ -0,0 +1,212 @@ +/* + * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2012 Luis Parada (luis.parada@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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class Pt502ProtocolDecoder extends BaseProtocolDecoder { + + private static final int MAX_CHUNK_SIZE = 960; + + private ByteBuf photo; + + public Pt502ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .any().text("$") + .expression("([^,]+),") // type + .number("(d+),") // id + .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) + .expression("([AV]),") // validity + .number("(d+)(dd.dddd),") // latitude + .expression("([NS]),") + .number("(d+)(dd.dddd),") // longitude + .expression("([EW]),") + .number("(d+.d+)?,") // speed + .number("(d+.d+)?,") // course + .number("(dd)(dd)(dd),,,") // date (ddmmyy) + .expression("./") + .expression("([01])+,") // input + .expression("([01])+/") // output + .expression("([^/]+)?/") // adc + .number("(d+)") // odometer + .expression("/([^/]+)?/") // rfid + .number("(xxx)").optional(2) // state + .any() + .compile(); + + private String decodeAlarm(String value) { + switch (value) { + case "IN1": + return Position.ALARM_SOS; + case "GOF": + return Position.ALARM_GEOFENCE; + case "TOW": + return Position.ALARM_TOW; + case "HDA": + return Position.ALARM_ACCELERATION; + case "HDB": + return Position.ALARM_BRAKING; + case "FDA": + return Position.ALARM_FATIGUE_DRIVING; + case "SKA": + return Position.ALARM_VIBRATION; + case "PMA": + return Position.ALARM_MOVEMENT; + case "CPA": + return Position.ALARM_POWER_CUT; + default: + return null; + } + } + + private Position decodePosition(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + + if (parser.hasNext()) { + String[] values = parser.next().split(","); + for (int i = 0; i < values.length; i++) { + position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(values[i], 16)); + } + } + + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + if (parser.hasNext()) { + int value = parser.nextHexInt(0); + position.set(Position.KEY_BATTERY, value >> 8); + position.set(Position.KEY_RSSI, (value >> 4) & 0xf); + position.set(Position.KEY_SATELLITES, value & 0xf); + } + + return position; + } + + private void requestPhotoFragment(Channel channel) { + if (channel != null) { + int offset = photo.writerIndex(); + int size = Math.min(photo.writableBytes(), MAX_CHUNK_SIZE); + channel.writeAndFlush(new NetworkMessage("#PHD" + offset + "," + size + "\r\n", channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int typeEndIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); + String type = buf.toString(buf.readerIndex(), typeEndIndex - buf.readerIndex(), StandardCharsets.US_ASCII); + + if (type.startsWith("$PHD")) { + + int dataIndex = buf.indexOf(typeEndIndex + 1, buf.writerIndex(), (byte) ',') + 1; + buf.readerIndex(dataIndex); + + if (photo != null) { + + photo.writeBytes(buf.readSlice(buf.readableBytes())); + + if (photo.writableBytes() > 0) { + + requestPhotoFragment(channel); + + } else { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId(); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg")); + photo.release(); + photo = null; + + return position; + + } + + } + + } else { + + if (type.startsWith("$PHO")) { + int size = Integer.parseInt(type.split("-")[0].substring(4)); + if (size > 0) { + photo = Unpooled.buffer(size); + requestPhotoFragment(channel); + } + } + + return decodePosition(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII)); + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java new file mode 100644 index 000000000..ed18208cc --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 - 2017 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. + * 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.TimeZone; + +import org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class Pt502ProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { + + @Override + public String formatValue(String key, Object value) { + if (key.equals(Command.KEY_TIMEZONE)) { + return String.valueOf(TimeZone.getTimeZone((String) value).getRawOffset() / 3600000); + } + + return null; + } + + @Override + protected String formatCommand(Command command, String format, String... keys) { + return formatCommand(command, format, this, keys); + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatCommand(command, "{%s}\r\n", Command.KEY_DATA); + case Command.TYPE_OUTPUT_CONTROL: + return formatCommand(command, "#OPC{%s},{%s}\r\n", Command.KEY_INDEX, Command.KEY_DATA); + case Command.TYPE_SET_TIMEZONE: + return formatCommand(command, "#TMZ{%s}\r\n", Command.KEY_TIMEZONE); + case Command.TYPE_ALARM_SPEED: + return formatCommand(command, "#SPD{%s}\r\n", Command.KEY_DATA); + case Command.TYPE_REQUEST_PHOTO: + return formatCommand(command, "#PHO\r\n"); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt60Protocol.java b/src/main/java/org/traccar/protocol/Pt60Protocol.java new file mode 100644 index 000000000..c502426c5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt60Protocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Pt60Protocol extends BaseProtocol { + + public Pt60Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "@R#@", "@E#@")); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Pt60ProtocolDecoder(Pt60Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java new file mode 100644 index 000000000..6a3fe2734 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java @@ -0,0 +1,184 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.regex.Pattern; + +public class Pt60ProtocolDecoder extends BaseProtocolDecoder { + + public Pt60ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_G_TRACK = 6; + public static final int MSG_G_STEP_COUNT = 13; + public static final int MSG_G_HEART_RATE = 14; + + public static final int MSG_B_POSITION = 1; + + private static final Pattern PATTERN = new PatternBuilder() + .expression("@(.)#@[,|]") // header + .number("V?dd[,|]") // protocol version + .number("(d+)[,|]") // type + .number("(d+)[,|]") // imei + .number("d+[,|]") // imsi + .groupBegin() + .expression("[^,|]+[,|]").optional() // firmware version + .number("[01][,|]") // state + .number("d+[,|]") // battery + .groupEnd("?") + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd)[,|]") // time (hhmmss) + .expression("(.*)") // data + .expression("[,|]") + .compile(); + + private void sendResponse(Channel channel, SocketAddress remoteAddress, String format, int type, String imei) { + if (channel != null) { + String message; + String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); + if (format.equals("G")) { + message = String.format("@G#@,V01,38,%s,@R#@", time); + } else { + message = String.format("@B#@|01|%03d|%s|0|%s|@E#@", type + 1, imei, time); + } + channel.writeAndFlush(new NetworkMessage(message, remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + String format = parser.next(); + int type = parser.nextInt(); + String imei = parser.next(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + sendResponse(channel, remoteAddress, format, type, imei); + + if (format.equals("G")) { + + if (type != MSG_G_TRACK && type != MSG_G_STEP_COUNT && type != MSG_G_HEART_RATE) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.setDeviceTime(parser.nextDateTime()); + + String[] values = parser.next().split(","); + + if (type == MSG_G_TRACK) { + + position.setValid(true); + position.setFixTime(position.getDeviceTime()); + + String[] coordinates = values[0].split(";"); + position.setLatitude(Double.parseDouble(coordinates[0])); + position.setLongitude(Double.parseDouble(coordinates[1])); + + } else { + + getLastLocation(position, position.getDeviceTime()); + + switch (type) { + case MSG_G_STEP_COUNT: + position.set(Position.KEY_STEPS, Integer.parseInt(values[0])); + break; + case MSG_G_HEART_RATE: + position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[0])); + position.set(Position.KEY_BATTERY, Integer.parseInt(values[1])); + break; + default: + break; + } + + } + + return position; + + } else { + + if (type != MSG_B_POSITION) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.setDeviceTime(parser.nextDateTime()); + + String[] values = parser.next().split("\\|"); + + if (Integer.parseInt(values[values.length - 1]) == 2) { + + getLastLocation(position, position.getDeviceTime()); + + Network network = new Network(); + + for (int i = 0; i < values.length - 1; i++) { + String[] cellValues = values[i].split(","); + CellTower tower = new CellTower(); + tower.setCellId(Long.parseLong(cellValues[0])); + tower.setLocationAreaCode(Integer.parseInt(cellValues[1])); + tower.setMobileNetworkCode(Integer.parseInt(cellValues[2])); + tower.setMobileCountryCode(Integer.parseInt(cellValues[3])); + tower.setSignalStrength(Integer.parseInt(cellValues[4])); + network.addCellTower(tower); + } + + position.setNetwork(network); + + + } else { + + position.setValid(true); + position.setFixTime(position.getDeviceTime()); + + position.setLatitude(Double.parseDouble(values[0])); + position.setLongitude(Double.parseDouble(values[1])); + + } + + return position; + + } + } + +} diff --git a/src/main/java/org/traccar/protocol/RaveonProtocol.java b/src/main/java/org/traccar/protocol/RaveonProtocol.java new file mode 100644 index 000000000..44faadb3b --- /dev/null +++ b/src/main/java/org/traccar/protocol/RaveonProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class RaveonProtocol extends BaseProtocol { + + public RaveonProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new RaveonProtocolDecoder(RaveonProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java b/src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java new file mode 100644 index 000000000..50acd20a1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java @@ -0,0 +1,99 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class RaveonProtocolDecoder extends BaseProtocolDecoder { + + public RaveonProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$PRAVE,") + .number("(d+),") // id + .number("d+,") + .number("(-?)(d+)(dd.d+),") // latitude + .number("(-?)(d+)(dd.d+),") // longitude + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d),") // validity + .number("(d+),") // satellites + .number("(-?d+),") // altitude + .number("(-?d+),") // temperature + .number("(d+.d+),") // power + .number("(d+),") // inputs + .number("(-?d+),") // gsm + .number("(d+),") // speed + .number("(d+),") // course + .expression("([PMACIVSX])?,") // status + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS)); + + position.setValid(parser.nextInt(0) != 0); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + + position.setAltitude(parser.nextInt(0)); + + position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); + position.set(Position.KEY_POWER, parser.nextDouble(0)); + position.set(Position.KEY_INPUT, parser.nextInt(0)); + position.set(Position.KEY_RSSI, parser.nextInt(0)); + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); + position.setCourse(parser.nextInt(0)); + + position.set(Position.KEY_ALARM, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/RecodaProtocol.java b/src/main/java/org/traccar/protocol/RecodaProtocol.java new file mode 100644 index 000000000..0bc9870bc --- /dev/null +++ b/src/main/java/org/traccar/protocol/RecodaProtocol.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; +public class RecodaProtocol extends BaseProtocol { + + public RecodaProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 4, 4, -8, 0, true)); + pipeline.addLast(new RecodaProtocolDecoder(RecodaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java new file mode 100644 index 000000000..04098225f --- /dev/null +++ b/src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java @@ -0,0 +1,110 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class RecodaProtocolDecoder extends BaseProtocolDecoder { + + public RecodaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_HEARTBEAT = 0x00001001; + public static final int MSG_REQUEST_RESPONSE = 0x20000001; + public static final int MSG_SIGNAL_LINK_REGISTRATION = 0x20001001; + public static final int MSG_EVENT_NOTICE = 0x20002001; + public static final int MSG_GPS_DATA = 0x20001011; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int type = buf.readIntLE(); + buf.readUnsignedIntLE(); // length + + if (type != MSG_HEARTBEAT) { + buf.readUnsignedShortLE(); // version + buf.readUnsignedShortLE(); // index + } + + if (type == MSG_SIGNAL_LINK_REGISTRATION) { + + getDeviceSession(channel, remoteAddress, buf.readSlice(12).toString(StandardCharsets.US_ASCII)); + + } else if (type == MSG_GPS_DATA) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(buf.readLongLE())); + + int flags = buf.readUnsignedByte(); + + if (BitUtil.check(flags, 0)) { + + buf.readUnsignedShortLE(); // declination + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); + + position.setLongitude(buf.readUnsignedByte() + buf.readUnsignedByte() / 60.0); + position.setLatitude(buf.readUnsignedByte() + buf.readUnsignedByte() / 60.0); + + position.setLongitude(position.getLongitude() + buf.readUnsignedIntLE() / 3600.0); + position.setLatitude(position.getLatitude() + buf.readUnsignedIntLE() / 3600.0); + + int status = buf.readUnsignedByte(); + + position.setValid(BitUtil.check(status, 0)); + if (BitUtil.check(status, 1)) { + position.setLongitude(-position.getLongitude()); + } + if (!BitUtil.check(status, 2)) { + position.setLatitude(-position.getLatitude()); + } + + } else { + + getLastLocation(position, position.getDeviceTime()); + + } + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/RetranslatorFrameDecoder.java b/src/main/java/org/traccar/protocol/RetranslatorFrameDecoder.java new file mode 100644 index 000000000..4edd09418 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RetranslatorFrameDecoder.java @@ -0,0 +1,37 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class RetranslatorFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int length = 4 + buf.getIntLE(buf.readerIndex()); + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } else { + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/RetranslatorProtocol.java b/src/main/java/org/traccar/protocol/RetranslatorProtocol.java new file mode 100644 index 000000000..fae81f7d2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RetranslatorProtocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class RetranslatorProtocol extends BaseProtocol { + + public RetranslatorProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new RetranslatorFrameDecoder()); + pipeline.addLast(new RetranslatorProtocolDecoder(RetranslatorProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java new file mode 100644 index 000000000..0688c9b0e --- /dev/null +++ b/src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java @@ -0,0 +1,114 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class RetranslatorProtocolDecoder extends BaseProtocolDecoder { + + public RetranslatorProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(new byte[]{0x11}), remoteAddress)); + } + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedInt(); // length + + int idLength = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex(); + String id = buf.readBytes(idLength).toString(StandardCharsets.US_ASCII); + buf.readByte(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + + buf.readUnsignedInt(); // bit flags + + while (buf.isReadable()) { + + buf.readUnsignedShort(); // block type + int blockEnd = buf.readInt() + buf.readerIndex(); + buf.readUnsignedByte(); // security attribute + int dataType = buf.readUnsignedByte(); + + int nameLength = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex(); + String name = buf.readBytes(nameLength).toString(StandardCharsets.US_ASCII); + buf.readByte(); + + if (name.equals("posinfo")) { + position.setValid(true); + position.setLongitude(buf.readDoubleLE()); + position.setLatitude(buf.readDoubleLE()); + position.setAltitude(buf.readDoubleLE()); + position.setSpeed(buf.readShort()); + position.setCourse(buf.readShort()); + position.set(Position.KEY_SATELLITES, buf.readByte()); + } else { + switch (dataType) { + case 1: + int len = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex(); + position.set(name, buf.readBytes(len).toString(StandardCharsets.US_ASCII)); + buf.readByte(); + break; + case 3: + position.set(name, buf.readInt()); + break; + case 4: + position.set(name, buf.readDoubleLE()); + break; + case 5: + position.set(name, buf.readLong()); + break; + default: + break; + } + } + + buf.readerIndex(blockEnd); + + } + + if (position.getLatitude() == 0 && position.getLongitude() == 0) { + getLastLocation(position, position.getDeviceTime()); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/RitiProtocol.java b/src/main/java/org/traccar/protocol/RitiProtocol.java new file mode 100644 index 000000000..de1026672 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RitiProtocol.java @@ -0,0 +1,36 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; +public class RitiProtocol extends BaseProtocol { + + public RitiProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 105, 2, 3, 0, true)); + pipeline.addLast(new RitiProtocolDecoder(RitiProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RitiProtocolDecoder.java b/src/main/java/org/traccar/protocol/RitiProtocolDecoder.java new file mode 100644 index 000000000..46267ca90 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RitiProtocolDecoder.java @@ -0,0 +1,102 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class RitiProtocolDecoder extends BaseProtocolDecoder { + + public RitiProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$GPRMC,") + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedShort())); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set("mode", buf.readUnsignedByte()); + position.set(Position.KEY_COMMAND, buf.readUnsignedByte()); + position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); + + buf.skipBytes(5); // status + buf.readUnsignedShortLE(); // idleCount + buf.readUnsignedShortLE(); // idleTime in seconds + + position.set(Position.KEY_DISTANCE, buf.readUnsignedIntLE()); + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedIntLE()); + + // Parse GPRMC + int end = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*'); + String gprmc = buf.toString(buf.readerIndex(), end - buf.readerIndex(), StandardCharsets.US_ASCII); + Parser parser = new Parser(PATTERN, gprmc); + if (!parser.matches()) { + return null; + } + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/RoboTrackFrameDecoder.java b/src/main/java/org/traccar/protocol/RoboTrackFrameDecoder.java new file mode 100644 index 000000000..85ed6c76f --- /dev/null +++ b/src/main/java/org/traccar/protocol/RoboTrackFrameDecoder.java @@ -0,0 +1,57 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class RoboTrackFrameDecoder extends BaseFrameDecoder { + + private int messageLength(ByteBuf buf) { + switch (buf.getUnsignedByte(buf.readerIndex())) { + case RoboTrackProtocolDecoder.MSG_ID: + return 69; + case RoboTrackProtocolDecoder.MSG_ACK: + return 3; + case RoboTrackProtocolDecoder.MSG_GPS: + case RoboTrackProtocolDecoder.MSG_GSM: + case RoboTrackProtocolDecoder.MSG_IMAGE_START: + return 24; + case RoboTrackProtocolDecoder.MSG_IMAGE_DATA: + return 8 + buf.getUnsignedShortLE(buf.readerIndex() + 1); + case RoboTrackProtocolDecoder.MSG_IMAGE_END: + return 6; + default: + return Integer.MAX_VALUE; + } + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int length = messageLength(buf); + + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/RoboTrackProtocol.java b/src/main/java/org/traccar/protocol/RoboTrackProtocol.java new file mode 100644 index 000000000..c2c531293 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RoboTrackProtocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class RoboTrackProtocol extends BaseProtocol { + + public RoboTrackProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new RoboTrackFrameDecoder()); + pipeline.addLast(new RoboTrackProtocolDecoder(RoboTrackProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java new file mode 100644 index 000000000..b613f31d7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java @@ -0,0 +1,131 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class RoboTrackProtocolDecoder extends BaseProtocolDecoder { + + public RoboTrackProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_ID = 0x00; + public static final int MSG_ACK = 0x80; + public static final int MSG_GPS = 0x03; + public static final int MSG_GSM = 0x04; + public static final int MSG_IMAGE_START = 0x06; + public static final int MSG_IMAGE_DATA = 0x07; + public static final int MSG_IMAGE_END = 0x08; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int type = buf.readUnsignedByte(); + + if (type == MSG_ID) { + + buf.skipBytes(16); // name + + String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); + + if (getDeviceSession(channel, remoteAddress, imei) != null && channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(MSG_ACK); + response.writeByte(0x01); // success + response.writeByte(0x66); // checksum + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + } else if (type == MSG_GPS || type == MSG_GSM) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setDeviceTime(new Date(buf.readUnsignedIntLE() * 1000)); + + if (type == MSG_GPS) { + + position.setValid(true); + position.setFixTime(position.getDeviceTime()); + position.setLatitude(buf.readIntLE() * 0.000001); + position.setLongitude(buf.readIntLE() * 0.000001); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readByte())); + + } else { + + getLastLocation(position, position.getDeviceTime()); + + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), + buf.readUnsignedShortLE(), buf.readUnsignedShortLE()))); + + buf.readUnsignedByte(); // reserved + + } + + int value = buf.readUnsignedByte(); + + position.set(Position.KEY_SATELLITES, BitUtil.to(value, 4)); + position.set(Position.KEY_RSSI, BitUtil.between(value, 4, 7)); + position.set(Position.KEY_MOTION, BitUtil.check(value, 7)); + + value = buf.readUnsignedByte(); + + position.set(Position.KEY_CHARGE, BitUtil.check(value, 0)); + + for (int i = 1; i <= 4; i++) { + position.set(Position.PREFIX_IN + i, BitUtil.check(value, i)); + } + + position.set(Position.KEY_BATTERY_LEVEL, BitUtil.from(value, 5) * 100 / 7); + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + + for (int i = 1; i <= 3; i++) { + position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE()); + } + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocol.java b/src/main/java/org/traccar/protocol/RuptelaProtocol.java new file mode 100644 index 000000000..1ac62570a --- /dev/null +++ b/src/main/java/org/traccar/protocol/RuptelaProtocol.java @@ -0,0 +1,45 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class RuptelaProtocol extends BaseProtocol { + + public RuptelaProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_CONFIGURATION, + Command.TYPE_GET_VERSION, + Command.TYPE_FIRMWARE_UPDATE, + Command.TYPE_OUTPUT_CONTROL, + Command.TYPE_SET_CONNECTION, + Command.TYPE_SET_ODOMETER); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, 2, 0)); + pipeline.addLast(new RuptelaProtocolEncoder()); + pipeline.addLast(new RuptelaProtocolDecoder(RuptelaProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java new file mode 100644 index 000000000..b043b6201 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java @@ -0,0 +1,248 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DataConverter; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class RuptelaProtocolDecoder extends BaseProtocolDecoder { + + public RuptelaProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_RECORDS = 1; + public static final int MSG_DEVICE_CONFIGURATION = 2; + public static final int MSG_DEVICE_VERSION = 3; + public static final int MSG_FIRMWARE_UPDATE = 4; + public static final int MSG_SET_CONNECTION = 5; + public static final int MSG_SET_ODOMETER = 6; + public static final int MSG_SMS_VIA_GPRS_RESPONSE = 7; + public static final int MSG_SMS_VIA_GPRS = 8; + public static final int MSG_DTCS = 9; + public static final int MSG_SET_IO = 17; + public static final int MSG_EXTENDED_RECORDS = 68; + + private Position decodeCommandResponse(DeviceSession deviceSession, int type, ByteBuf buf) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_TYPE, type); + + switch (type) { + case MSG_DEVICE_CONFIGURATION: + case MSG_DEVICE_VERSION: + case MSG_FIRMWARE_UPDATE: + case MSG_SMS_VIA_GPRS_RESPONSE: + position.set(Position.KEY_RESULT, + buf.toString(buf.readerIndex(), buf.readableBytes() - 2, StandardCharsets.US_ASCII).trim()); + return position; + case MSG_SET_IO: + position.set(Position.KEY_RESULT, + String.valueOf(buf.readUnsignedByte())); + return position; + default: + return null; + } + } + + private long readValue(ByteBuf buf, int length, boolean signed) { + switch (length) { + case 1: + return signed ? buf.readByte() : buf.readUnsignedByte(); + case 2: + return signed ? buf.readShort() : buf.readUnsignedShort(); + case 4: + return signed ? buf.readInt() : buf.readUnsignedInt(); + default: + return buf.readLong(); + } + } + + private void decodeParameter(Position position, int id, ByteBuf buf, int length) { + switch (id) { + case 2: + case 3: + case 4: + position.set("di" + (id - 1), readValue(buf, length, false)); + break; + case 5: + position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); + break; + case 74: + position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1); + break; + case 78: + case 79: + case 80: + position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1); + break; + default: + position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); + break; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedShort(); // data length + + String imei = String.format("%015d", buf.readLong()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + int type = buf.readUnsignedByte(); + + if (type == MSG_RECORDS || type == MSG_EXTENDED_RECORDS) { + + List positions = new LinkedList<>(); + + buf.readUnsignedByte(); // records left + int count = buf.readUnsignedByte(); + + for (int i = 0; i < count; i++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + buf.readUnsignedByte(); // timestamp extension + + if (type == MSG_EXTENDED_RECORDS) { + buf.readUnsignedByte(); // record extension + } + + buf.readUnsignedByte(); // priority (reserved) + + position.setValid(true); + position.setLongitude(buf.readInt() / 10000000.0); + position.setLatitude(buf.readInt() / 10000000.0); + position.setAltitude(buf.readUnsignedShort() / 10.0); + position.setCourse(buf.readUnsignedShort() / 100.0); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + + position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); + + if (type == MSG_EXTENDED_RECORDS) { + position.set(Position.KEY_EVENT, buf.readUnsignedShort()); + } else { + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + } + + // Read 1 byte data + int cnt = buf.readUnsignedByte(); + for (int j = 0; j < cnt; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 1); + } + + // Read 2 byte data + cnt = buf.readUnsignedByte(); + for (int j = 0; j < cnt; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 2); + } + + // Read 4 byte data + cnt = buf.readUnsignedByte(); + for (int j = 0; j < cnt; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 4); + } + + // Read 8 byte data + cnt = buf.readUnsignedByte(); + for (int j = 0; j < cnt; j++) { + int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + decodeParameter(position, id, buf, 8); + } + + positions.add(position); + } + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + Unpooled.wrappedBuffer(DataConverter.parseHex("0002640113bc")), remoteAddress)); + } + + return positions; + + } else if (type == MSG_DTCS) { + + List positions = new LinkedList<>(); + + int count = buf.readUnsignedByte(); + + for (int i = 0; i < count; i++) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedByte(); // reserved + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + + position.setValid(true); + position.setLongitude(buf.readInt() / 10000000.0); + position.setLatitude(buf.readInt() / 10000000.0); + + if (buf.readUnsignedByte() == 2) { + position.set(Position.KEY_ARCHIVE, true); + } + + position.set(Position.KEY_DTCS, buf.readSlice(5).toString(StandardCharsets.US_ASCII)); + + positions.add(position); + } + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + Unpooled.wrappedBuffer(DataConverter.parseHex("00026d01c4a4")), remoteAddress)); + } + + return positions; + + } else { + + return decodeCommandResponse(deviceSession, type, buf); + + } + } + +} diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java new file mode 100644 index 000000000..4242584c9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class RuptelaProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeContent(int type, ByteBuf content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeShort(1 + content.readableBytes()); + buf.writeByte(100 + type); + buf.writeBytes(content); + buf.writeShort(Checksum.crc16(Checksum.CRC16_KERMIT, buf.nioBuffer(2, buf.writerIndex() - 2))); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + ByteBuf content = Unpooled.buffer(); + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + content.writeBytes(command.getString(Command.KEY_DATA).getBytes(StandardCharsets.US_ASCII)); + return encodeContent(RuptelaProtocolDecoder.MSG_SMS_VIA_GPRS, content); + case Command.TYPE_CONFIGURATION: + content.writeBytes((command.getString(Command.KEY_DATA) + "\r\n").getBytes(StandardCharsets.US_ASCII)); + return encodeContent(RuptelaProtocolDecoder.MSG_DEVICE_CONFIGURATION, content); + case Command.TYPE_GET_VERSION: + return encodeContent(RuptelaProtocolDecoder.MSG_DEVICE_VERSION, content); + case Command.TYPE_FIRMWARE_UPDATE: + content.writeBytes("|FU_STRT*\r\n".getBytes(StandardCharsets.US_ASCII)); + return encodeContent(RuptelaProtocolDecoder.MSG_FIRMWARE_UPDATE, content); + case Command.TYPE_OUTPUT_CONTROL: + content.writeInt(command.getInteger(Command.KEY_INDEX)); + content.writeInt(Integer.parseInt(command.getString(Command.KEY_DATA))); + return encodeContent(RuptelaProtocolDecoder.MSG_SET_IO, content); + case Command.TYPE_SET_CONNECTION: + String c = command.getString(Command.KEY_SERVER) + "," + command.getInteger(Command.KEY_PORT) + ",TCP"; + content.writeBytes(c.getBytes(StandardCharsets.US_ASCII)); + return encodeContent(RuptelaProtocolDecoder.MSG_SET_CONNECTION, content); + case Command.TYPE_SET_ODOMETER: + content.writeInt(Integer.parseInt(command.getString(Command.KEY_DATA))); + return encodeContent(RuptelaProtocolDecoder.MSG_SET_ODOMETER, content); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/SabertekFrameDecoder.java b/src/main/java/org/traccar/protocol/SabertekFrameDecoder.java new file mode 100644 index 000000000..ad5000bf8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SabertekFrameDecoder.java @@ -0,0 +1,44 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class SabertekFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int beginIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02); + if (beginIndex >= 0) { + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x03); + if (endIndex >= 0) { + buf.readerIndex(beginIndex + 1); + ByteBuf frame = buf.readRetainedSlice(endIndex - beginIndex - 1); + buf.readerIndex(endIndex + 1); + buf.skipBytes(2); // end line + return frame; + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/SabertekProtocol.java b/src/main/java/org/traccar/protocol/SabertekProtocol.java new file mode 100644 index 000000000..0ec847b60 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SabertekProtocol.java @@ -0,0 +1,36 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SabertekProtocol extends BaseProtocol { + + public SabertekProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new SabertekFrameDecoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new SabertekProtocolDecoder(SabertekProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java b/src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java new file mode 100644 index 000000000..3033aa2cc --- /dev/null +++ b/src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java @@ -0,0 +1,135 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.regex.Pattern; + +public class SabertekProtocolDecoder extends BaseProtocolDecoder { + + public SabertekProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text(",") + .number("(d+),") // id + .number("d,") // type + .groupBegin() + .number("d+,") // imei + .number("d+,") // scid + .expression("[^,]*,") // phone + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .groupEnd("?") + .number("(d+),") // battery + .number("(d+),") // rssi + .number("(d+),") // state + .number("(d+),") // events + .number("(d),") // valid + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+),") // altitude + .number("(d+),") // satellites + .number("(d+),") // odometer + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + Unpooled.wrappedBuffer(new byte[]{(byte) (deviceSession != null ? 0x06 : 0x15)}), remoteAddress)); + } + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (parser.hasNext(6)) { + position.setTime(parser.nextDateTime()); + } else { + position.setTime(new Date()); + } + + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextInt()); + + int state = parser.nextInt(); + + position.set(Position.KEY_IGNITION, BitUtil.check(state, 0)); + position.set(Position.KEY_CHARGE, BitUtil.check(state, 1)); + + if (BitUtil.check(state, 2)) { + position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); + } + if (BitUtil.check(state, 3)) { + position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); + } + + int events = parser.nextInt(); + + if (BitUtil.check(events, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + } + if (BitUtil.check(events, 1)) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } + if (BitUtil.check(events, 2)) { + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + } + if (BitUtil.check(events, 3)) { + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + } + + position.setValid(parser.nextInt() == 1); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setCourse(parser.nextInt()); + position.setAltitude(parser.nextInt()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextInt() * 1000L); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SanavProtocol.java b/src/main/java/org/traccar/protocol/SanavProtocol.java new file mode 100644 index 000000000..6799c57e6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SanavProtocol.java @@ -0,0 +1,45 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SanavProtocol extends BaseProtocol { + + public SanavProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new SanavProtocolDecoder(SanavProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new SanavProtocolDecoder(SanavProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SanavProtocolDecoder.java b/src/main/java/org/traccar/protocol/SanavProtocolDecoder.java new file mode 100644 index 000000000..7e1c158e6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SanavProtocolDecoder.java @@ -0,0 +1,107 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class SanavProtocolDecoder extends BaseProtocolDecoder { + + public SanavProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("imei[:=]") + .number("(d+)") // imei + .expression("&?rmc[:=]") + .text("$GPRMC,") + .number("(dd)(dd)(dd).d+,") // time (hhmmss.sss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+),") // speed + .number("(d+.d+)?,") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .groupBegin() + .expression("[^*]*") + .text("*") + .number("xx,") + .expression("[^,]+,") // status + .number("(d+),") // io + .groupEnd("?") + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + if (parser.hasNext()) { + int io = parser.nextHexInt(); + for (int i = 0; i < 5; i++) { + position.set(Position.PREFIX_IN + (i + 1), BitUtil.check(io, i)); + } + position.set(Position.KEY_IGNITION, BitUtil.check(io, 5)); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(io, 6)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(io, 7)); + position.set(Position.KEY_CHARGE, BitUtil.check(io, 8)); + if (!BitUtil.check(io, 9)) { + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + } + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SatsolProtocol.java b/src/main/java/org/traccar/protocol/SatsolProtocol.java new file mode 100644 index 000000000..b69fdd1fe --- /dev/null +++ b/src/main/java/org/traccar/protocol/SatsolProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import java.nio.ByteOrder; + +public class SatsolProtocol extends BaseProtocol { + + public SatsolProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1400, 8, 2, 0, 0, true)); + pipeline.addLast(new SatsolProtocolDecoder(SatsolProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java b/src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java new file mode 100644 index 000000000..c457d5620 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java @@ -0,0 +1,104 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +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.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class SatsolProtocolDecoder extends BaseProtocolDecoder { + + public SatsolProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedShortLE(); // checksum + buf.readUnsignedShortLE(); // preamble + long id = buf.readUnsignedIntLE(); + buf.readUnsignedShortLE(); // length + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + while (buf.isReadable()) { + + buf.readUnsignedShortLE(); // checksum + buf.readUnsignedShortLE(); // checksum + buf.readUnsignedShortLE(); // type + int length = buf.readUnsignedShortLE(); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + position.setLatitude(buf.readUnsignedIntLE() * 0.000001); + position.setLongitude(buf.readUnsignedIntLE() * 0.000001); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE() * 0.01)); + position.setAltitude(buf.readShortLE()); + position.setCourse(buf.readUnsignedShortLE()); + position.setValid(buf.readUnsignedByte() > 0); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + + if (BitUtil.check(buf.readUnsignedByte(), 0)) { + position.set(Position.KEY_ARCHIVE, true); + } + + positions.add(position); + + buf.skipBytes(length); + + } + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeShortLE(0); + response.writeShortLE(0x4CBF); // preamble + response.writeIntLE((int) id); + response.writeShortLE(0); + response.setShortLE(0, Checksum.crc16( + Checksum.CRC16_CCITT_FALSE, response.nioBuffer(2, response.readableBytes() - 2))); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocol.java b/src/main/java/org/traccar/protocol/SigfoxProtocol.java new file mode 100644 index 000000000..e2f2cbe1f --- /dev/null +++ b/src/main/java/org/traccar/protocol/SigfoxProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SigfoxProtocol extends BaseProtocol { + + public SigfoxProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new SigfoxProtocolDecoder(SigfoxProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java new file mode 100644 index 000000000..d7836b35d --- /dev/null +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -0,0 +1,92 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DataConverter; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import javax.json.Json; +import javax.json.JsonObject; +import java.io.StringReader; +import java.net.SocketAddress; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { + + public SigfoxProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + JsonObject json = Json.createReader(new StringReader(URLDecoder.decode( + request.content().toString(StandardCharsets.UTF_8).split("=")[0], "UTF-8"))).readObject(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, json.getString("device")); + if (deviceSession == null) { + sendResponse(channel, HttpResponseStatus.BAD_REQUEST); + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(json.getInt("time") * 1000L)); + + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(json.getString("data"))); + try { + int type = buf.readUnsignedByte() >> 4; + if (type == 0) { + + position.setValid(true); + position.setLatitude(buf.readIntLE() * 0.0000001); + position.setLongitude(buf.readIntLE() * 0.0000001); + position.setCourse(buf.readUnsignedByte() * 2); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.025); + + } else { + + getLastLocation(position, position.getDeviceTime()); + + } + } finally { + buf.release(); + } + + position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").doubleValue()); + position.set(Position.KEY_INDEX, json.getInt("seqNumber")); + + sendResponse(channel, HttpResponseStatus.OK); + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SiwiProtocol.java b/src/main/java/org/traccar/protocol/SiwiProtocol.java new file mode 100644 index 000000000..8963721c8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SiwiProtocol.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SiwiProtocol extends BaseProtocol { + + public SiwiProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new SiwiProtocolDecoder(SiwiProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java b/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java new file mode 100644 index 000000000..6b97f5fe0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java @@ -0,0 +1,96 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class SiwiProtocolDecoder extends BaseProtocolDecoder { + + public SiwiProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$").expression("[A-Z]+,") // header + .number("(d+),") // device id + .number("d+,") // unit no + .expression("([A-Z]),") // reason + .number("d+,") // command code + .number("[^,]*,") // command value + .expression("([01]),") // ignition + .expression("[01],") // power cut + .expression("[01],") // box open + .number("d+,") // message key + .number("(d+),") // odometer + .number("(d+),") // speed + .number("(d+),") // satellites + .expression("([AV]),") // valid + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(-?d+),") // altitude + .number("(d+),") // course + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd)(dd),") // date (ddmmyy) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_EVENT, parser.next()); + position.set(Position.KEY_IGNITION, parser.next().equals("1")); + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + position.setCourse(parser.nextInt(0)); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY, "IST")); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SkypatrolProtocol.java b/src/main/java/org/traccar/protocol/SkypatrolProtocol.java new file mode 100644 index 000000000..7c6203d86 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SkypatrolProtocol.java @@ -0,0 +1,33 @@ +/* + * Copyright 2015 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SkypatrolProtocol extends BaseProtocol { + + public SkypatrolProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new SkypatrolProtocolDecoder(SkypatrolProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java b/src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java new file mode 100644 index 000000000..3c7ca6dc5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java @@ -0,0 +1,193 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; + +public class SkypatrolProtocolDecoder extends BaseProtocolDecoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(SkypatrolProtocolDecoder.class); + + private final long defaultMask; + + public SkypatrolProtocolDecoder(Protocol protocol) { + super(protocol); + defaultMask = Context.getConfig().getInteger(getProtocolName() + ".mask"); + } + + private static double convertCoordinate(long coordinate) { + int sign = 1; + if (coordinate > 0x7fffffffL) { + sign = -1; + coordinate = 0xffffffffL - coordinate; + } + + long degrees = coordinate / 1000000; + double minutes = (coordinate % 1000000) / 10000.0; + + return sign * (degrees + minutes / 60); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int apiNumber = buf.readUnsignedShort(); + int commandType = buf.readUnsignedByte(); + int messageType = BitUtil.from(buf.readUnsignedByte(), 4); + long mask = defaultMask; + if (buf.readUnsignedByte() == 4) { + mask = buf.readUnsignedInt(); + } + + // Binary position report + if (apiNumber == 5 && commandType == 2 && messageType == 1 && BitUtil.check(mask, 0)) { + + Position position = new Position(getProtocolName()); + + if (BitUtil.check(mask, 1)) { + position.set(Position.KEY_STATUS, buf.readUnsignedInt()); + } + + String id; + if (BitUtil.check(mask, 23)) { + id = buf.toString(buf.readerIndex(), 8, StandardCharsets.US_ASCII).trim(); + buf.skipBytes(8); + } else if (BitUtil.check(mask, 2)) { + id = buf.toString(buf.readerIndex(), 22, StandardCharsets.US_ASCII).trim(); + buf.skipBytes(22); + } else { + LOGGER.warn("No device id field"); + return null; + } + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + if (BitUtil.check(mask, 3)) { + position.set(Position.PREFIX_IO + 1, buf.readUnsignedShort()); + } + + if (BitUtil.check(mask, 4)) { + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + } + + if (BitUtil.check(mask, 5)) { + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + } + + if (BitUtil.check(mask, 7)) { + buf.readUnsignedByte(); // function category + } + + DateBuilder dateBuilder = new DateBuilder(); + + if (BitUtil.check(mask, 8)) { + dateBuilder.setDateReverse( + buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + } + + if (BitUtil.check(mask, 9)) { + position.setValid(buf.readUnsignedByte() == 1); // gps status + } + + if (BitUtil.check(mask, 10)) { + position.setLatitude(convertCoordinate(buf.readUnsignedInt())); + } + + if (BitUtil.check(mask, 11)) { + position.setLongitude(convertCoordinate(buf.readUnsignedInt())); + } + + if (BitUtil.check(mask, 12)) { + position.setSpeed(buf.readUnsignedShort() / 10.0); + } + + if (BitUtil.check(mask, 13)) { + position.setCourse(buf.readUnsignedShort() / 10.0); + } + + if (BitUtil.check(mask, 14)) { + dateBuilder.setTime( + buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + } + + position.setTime(dateBuilder.getDate()); + + if (BitUtil.check(mask, 15)) { + position.setAltitude(buf.readMedium()); + } + + if (BitUtil.check(mask, 16)) { + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + } + + if (BitUtil.check(mask, 17)) { + position.set(Position.KEY_BATTERY, buf.readUnsignedShort()); + } + + if (BitUtil.check(mask, 20)) { + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); + } + + if (BitUtil.check(mask, 21)) { + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + } + + if (BitUtil.check(mask, 22)) { + buf.skipBytes(6); // time of message generation + } + + if (BitUtil.check(mask, 24)) { + position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); + } + + if (BitUtil.check(mask, 25)) { + buf.skipBytes(18); // gps overspeed + } + + if (BitUtil.check(mask, 26)) { + buf.skipBytes(54); // cell information + } + + if (BitUtil.check(mask, 28)) { + position.set(Position.KEY_INDEX, buf.readUnsignedShort()); + } + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/SmartSoleProtocol.java b/src/main/java/org/traccar/protocol/SmartSoleProtocol.java new file mode 100644 index 000000000..bcf43f68b --- /dev/null +++ b/src/main/java/org/traccar/protocol/SmartSoleProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SmartSoleProtocol extends BaseProtocol { + + public SmartSoleProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '$')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new SmartSoleProtocolDecoder(SmartSoleProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java b/src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java new file mode 100644 index 000000000..04920c969 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java @@ -0,0 +1,91 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class SmartSoleProtocolDecoder extends BaseProtocolDecoder { + + public SmartSoleProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("#GTXRP=") + .number("(d+),") // imei + .number("d+,") // report type + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(-?d+),") // altitude + .number("(d+),") // speed + .number("([01]),") // valid + .number("(d+),") // satellites + .number("(d+.d+),") // hdop + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d+.d+),") // battery + .number("(d+)") // status + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setFixTime(parser.nextDateTime()); + + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setAltitude(parser.nextInt()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); + position.setValid(parser.nextInt() == 1); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextDouble()); + + position.setDeviceTime(parser.nextDateTime()); + + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_STATUS, parser.nextInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SmokeyProtocol.java b/src/main/java/org/traccar/protocol/SmokeyProtocol.java new file mode 100644 index 000000000..482c8347c --- /dev/null +++ b/src/main/java/org/traccar/protocol/SmokeyProtocol.java @@ -0,0 +1,33 @@ +/* + * Copyright 2016 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SmokeyProtocol extends BaseProtocol { + + public SmokeyProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new SmokeyProtocolDecoder(SmokeyProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java b/src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java new file mode 100644 index 000000000..9da52e97a --- /dev/null +++ b/src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java @@ -0,0 +1,161 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +public class SmokeyProtocolDecoder extends BaseProtocolDecoder { + + public SmokeyProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_DATE_RECORD = 0; + public static final int MSG_DATE_RECORD_ACK = 1; + + private static void sendResponse( + Channel channel, SocketAddress remoteAddress, ByteBuf id, int index, int report) { + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeBytes("SM".getBytes(StandardCharsets.US_ASCII)); + response.writeByte(3); // protocol version + response.writeByte(MSG_DATE_RECORD_ACK); + response.writeBytes(id); + response.writeInt( + (int) ChronoUnit.SECONDS.between(Instant.parse("2000-01-01T00:00:00.00Z"), Instant.now())); + response.writeByte(index); + response.writeByte(report - 0x200); + + short checksum = (short) 0xF5A0; + for (int i = 0; i < response.readableBytes(); i += 2) { + checksum ^= response.getShortLE(i); + } + response.writeShort(checksum); + + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.readUnsignedByte(); // protocol version + + int type = buf.readUnsignedByte(); + + ByteBuf id = buf.readSlice(8); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(id)); + if (deviceSession == null) { + return null; + } + + if (type == MSG_DATE_RECORD) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_VERSION_FW, buf.readUnsignedShort()); + + int status = buf.readUnsignedShort(); + position.set(Position.KEY_STATUS, status); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(2000, 1, 1).addSeconds(buf.readUnsignedInt()); + + getLastLocation(position, dateBuilder.getDate()); + + int index = buf.readUnsignedByte(); + position.set(Position.KEY_INDEX, index); + + int report = buf.readUnsignedShort(); + + buf.readUnsignedShort(); // length + + position.set(Position.KEY_BATTERY, buf.readUnsignedShort()); + + Network network = new Network(); + + if (report != 0x0203) { + + int count = 1; + if (report != 0x0200) { + count = buf.readUnsignedByte(); + } + + for (int i = 0; i < count; i++) { + int mcc = buf.readUnsignedShort(); + int mnc = buf.readUnsignedShort(); + int lac = buf.readUnsignedShort(); + int cid = buf.readUnsignedShort(); + if (i == 0) { + buf.readByte(); // timing advance + } + int rssi = buf.readByte(); + network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi)); + } + + } + + if (report == 0x0202 || report == 0x0203) { + + int count = buf.readUnsignedByte(); + + for (int i = 0; i < count; i++) { + buf.readerIndex(buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0) + 1); // ssid + + String mac = String.format("%02x:%02x:%02x:%02x:%02x:%02x", + buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(), + buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); + + network.addWifiAccessPoint(WifiAccessPoint.from(mac, buf.readByte())); + } + + } + + position.setNetwork(network); + + sendResponse(channel, remoteAddress, id, index, report); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/SpotProtocol.java b/src/main/java/org/traccar/protocol/SpotProtocol.java new file mode 100644 index 000000000..bbf0e8d8a --- /dev/null +++ b/src/main/java/org/traccar/protocol/SpotProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SpotProtocol extends BaseProtocol { + + public SpotProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpResponseEncoder()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new SpotProtocolDecoder(SpotProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java b/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java new file mode 100644 index 000000000..da36c2048 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java @@ -0,0 +1,102 @@ +/* + * Copyright 2017 - 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. + * 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 com.fasterxml.jackson.databind.util.ByteBufferBackedInputStream; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateUtil; +import org.traccar.model.Position; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import java.net.SocketAddress; +import java.util.LinkedList; +import java.util.List; + +public class SpotProtocolDecoder extends BaseHttpProtocolDecoder { + + private DocumentBuilder documentBuilder; + private XPath xPath; + private XPathExpression messageExpression; + + public SpotProtocolDecoder(Protocol protocol) { + super(protocol); + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); + builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + builderFactory.setXIncludeAware(false); + builderFactory.setExpandEntityReferences(false); + documentBuilder = builderFactory.newDocumentBuilder(); + xPath = XPathFactory.newInstance().newXPath(); + messageExpression = xPath.compile("//messageList/message"); + } catch (ParserConfigurationException | XPathExpressionException e) { + throw new RuntimeException(e); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpRequest request = (FullHttpRequest) msg; + + Document document = documentBuilder.parse(new ByteBufferBackedInputStream(request.content().nioBuffer())); + NodeList nodes = (NodeList) messageExpression.evaluate(document, XPathConstants.NODESET); + + List positions = new LinkedList<>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, xPath.evaluate("esnName", node)); + if (deviceSession != null) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(DateUtil.parseDate(xPath.evaluate("timestamp", node))); + position.setLatitude(Double.parseDouble(xPath.evaluate("latitude", node))); + position.setLongitude(Double.parseDouble(xPath.evaluate("longitude", node))); + + position.set(Position.KEY_EVENT, xPath.evaluate("messageType", node)); + + positions.add(position); + + } + } + + sendResponse(channel, HttpResponseStatus.OK); + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocol.java b/src/main/java/org/traccar/protocol/StarLinkProtocol.java new file mode 100644 index 000000000..5630722ee --- /dev/null +++ b/src/main/java/org/traccar/protocol/StarLinkProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class StarLinkProtocol extends BaseProtocol { + + public StarLinkProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StarLinkProtocolDecoder(StarLinkProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java new file mode 100644 index 000000000..ed5f81c1c --- /dev/null +++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -0,0 +1,229 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.TimeZone; +import java.util.regex.Pattern; + +public class StarLinkProtocolDecoder extends BaseProtocolDecoder { + + private String[] dataTags; + private DateFormat dateFormat; + + public StarLinkProtocolDecoder(Protocol protocol) { + super(protocol); + + String format = Context.getConfig().getString( + getProtocolName() + ".format", "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," + + "#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#"); + dataTags = format.split(","); + + dateFormat = new SimpleDateFormat( + Context.getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss")); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression(".") // protocol head + .text("SLU") // message head + .number("(x{6}|d{15}),") // id + .number("(d+),") // type + .number("(d+),") // index + .expression("(.+)") // data + .text("*") + .number("xx") // checksum + .compile(); + + public static final int MSG_EVENT_REPORT = 6; + + private double parseCoordinate(String value) { + int minutesIndex = value.indexOf('.') - 2; + double result = Double.parseDouble(value.substring(1, minutesIndex)); + result += Double.parseDouble(value.substring(minutesIndex)) / 60; + return value.charAt(0) == '+' ? result : -result; + } + + private String decodeAlarm(int event) { + switch (event) { + case 6: + return Position.ALARM_OVERSPEED; + case 7: + return Position.ALARM_GEOFENCE_ENTER; + case 8: + return Position.ALARM_GEOFENCE_EXIT; + case 9: + return Position.ALARM_POWER_CUT; + case 11: + return Position.ALARM_LOW_BATTERY; + case 26: + return Position.ALARM_TOW; + case 36: + return Position.ALARM_SOS; + case 42: + return Position.ALARM_JAMMING; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + int type = parser.nextInt(0); + if (type != MSG_EVENT_REPORT) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.setValid(true); + + position.set(Position.KEY_INDEX, parser.nextInt(0)); + + String[] data = parser.next().split(","); + Integer lac = null, cid = null; + int event = 0; + + for (int i = 0; i < Math.min(data.length, dataTags.length); i++) { + if (data[i].isEmpty()) { + continue; + } + switch (dataTags[i]) { + case "#EDT#": + position.setDeviceTime(dateFormat.parse(data[i])); + break; + case "#EID#": + event = Integer.parseInt(data[i]); + position.set(Position.KEY_ALARM, decodeAlarm(event)); + position.set(Position.KEY_EVENT, event); + break; + case "#PDT#": + position.setFixTime(dateFormat.parse(data[i])); + break; + case "#LAT#": + position.setLatitude(parseCoordinate(data[i])); + break; + case "#LONG#": + position.setLongitude(parseCoordinate(data[i])); + break; + case "#SPD#": + position.setSpeed(Double.parseDouble(data[i])); + break; + case "#HEAD#": + position.setCourse(Integer.parseInt(data[i])); + break; + case "#ODO#": + position.set(Position.KEY_ODOMETER, Long.parseLong(data[i]) * 1000); + break; + case "#IN1#": + position.set(Position.PREFIX_IN + 1, Integer.parseInt(data[i])); + break; + case "#IN2#": + position.set(Position.PREFIX_IN + 2, Integer.parseInt(data[i])); + break; + case "#IN3#": + position.set(Position.PREFIX_IN + 3, Integer.parseInt(data[i])); + break; + case "#IN4#": + position.set(Position.PREFIX_IN + 4, Integer.parseInt(data[i])); + break; + case "#OUT1#": + position.set(Position.PREFIX_OUT + 1, Integer.parseInt(data[i])); + break; + case "#OUT2#": + position.set(Position.PREFIX_OUT + 2, Integer.parseInt(data[i])); + break; + case "#OUT3#": + position.set(Position.PREFIX_OUT + 3, Integer.parseInt(data[i])); + break; + case "#OUT4#": + position.set(Position.PREFIX_OUT + 4, Integer.parseInt(data[i])); + break; + case "#LAC#": + if (!data[i].isEmpty()) { + lac = Integer.parseInt(data[i]); + } + break; + case "#CID#": + if (!data[i].isEmpty()) { + cid = Integer.parseInt(data[i]); + } + break; + case "#VIN#": + position.set(Position.KEY_POWER, Double.parseDouble(data[i])); + break; + case "#VBAT#": + position.set(Position.KEY_BATTERY, Double.parseDouble(data[i])); + break; + case "#DEST#": + position.set("destination", data[i]); + break; + case "#IGN#": + position.set(Position.KEY_IGNITION, data[i].equals("1")); + break; + case "#ENG#": + position.set("engine", data[i].equals("1")); + break; + default: + break; + } + } + + if (position.getFixTime() == null) { + getLastLocation(position, null); + } + + if (lac != null && cid != null) { + position.setNetwork(new Network(CellTower.fromLacCid(lac, cid))); + } + + if (event == 20) { + String rfid = data[data.length - 1]; + if (rfid.matches("0+")) { + rfid = data[data.length - 2]; + } + position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Stl060FrameDecoder.java b/src/main/java/org/traccar/protocol/Stl060FrameDecoder.java new file mode 100644 index 000000000..f72474e2b --- /dev/null +++ b/src/main/java/org/traccar/protocol/Stl060FrameDecoder.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.CharacterDelimiterFrameDecoder; + +public class Stl060FrameDecoder extends CharacterDelimiterFrameDecoder { + + public Stl060FrameDecoder(int maxFrameLength) { + super(maxFrameLength, '#'); + } + + @Override + protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) throws Exception { + + ByteBuf result = (ByteBuf) super.decode(ctx, buf); + + if (result != null) { + + int index = result.indexOf(result.readerIndex(), result.writerIndex(), (byte) '$'); + if (index == -1) { + return result; + } else { + result.skipBytes(index); + return result.readRetainedSlice(result.readableBytes()); + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Stl060Protocol.java b/src/main/java/org/traccar/protocol/Stl060Protocol.java new file mode 100644 index 000000000..2711e936b --- /dev/null +++ b/src/main/java/org/traccar/protocol/Stl060Protocol.java @@ -0,0 +1,38 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Stl060Protocol extends BaseProtocol { + + public Stl060Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Stl060FrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Stl060ProtocolDecoder(Stl060Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java new file mode 100644 index 000000000..7b0055aa1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java @@ -0,0 +1,120 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Stl060ProtocolDecoder extends BaseProtocolDecoder { + + public Stl060ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .any() + .text("$1,") + .number("(d+),") // imei + .text("D001,") // type + .expression("[^,]*,") // vehicle + .number("(dd)/(dd)/(dd),") // date (dd/mm/yy) + .number("(dd):(dd):(dd),") // time (hh:mm:ss) + .number("(dd)(dd).?(d+)([NS]),") // latitude + .number("(ddd)(dd).?(d+)([EW]),") // longitude + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .groupBegin() + .number("(d+),") // odometer + .number("(d+),") // Ignition + .number("(d+),") // di1 + .number("(d+),") // di2 + .number("(d+),") // fuel + .or() + .expression("([01]),") // charging + .expression("([01]),") // ignition + .expression("0,0,") // reserved + .number("(d+),") // di + .expression("([^,]+),") // rfid + .number("(d+),") // odometer + .number("(d+),") // temperature + .number("(d+),") // fuel + .expression("([01]),") // accelerometer + .expression("([01]),") // do1 + .expression("([01]),") // do2 + .groupEnd() + .expression("([AV])") // validity + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + // Old format + if (parser.hasNext(5)) { + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); + position.set(Position.KEY_INPUT, parser.nextInt(0) + parser.nextInt(0) << 1); + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); + } + + // New format + if (parser.hasNext(10)) { + position.set(Position.KEY_CHARGE, parser.nextInt(0) == 1); + position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); + position.set(Position.KEY_INPUT, parser.nextInt(0)); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + position.set(Position.KEY_ODOMETER, parser.nextInt(0)); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); + position.set(Position.KEY_ACCELERATION, parser.nextInt(0) == 1); + position.set(Position.KEY_OUTPUT, parser.nextInt(0) + parser.nextInt(0) << 1); + } + + position.setValid(parser.next().equals("A")); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SuntechProtocol.java b/src/main/java/org/traccar/protocol/SuntechProtocol.java new file mode 100644 index 000000000..29ae114e7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SuntechProtocol.java @@ -0,0 +1,49 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class SuntechProtocol extends BaseProtocol { + + public SuntechProtocol() { + setSupportedDataCommands( + Command.TYPE_OUTPUT_CONTROL, + Command.TYPE_REBOOT_DEVICE, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new SuntechProtocolEncoder()); + pipeline.addLast(new SuntechProtocolDecoder(SuntechProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java new file mode 100644 index 000000000..922431021 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -0,0 +1,467 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +public class SuntechProtocolDecoder extends BaseProtocolDecoder { + + private int protocolType; + private boolean hbm; + private boolean includeAdc; + private boolean includeTemp; + + public SuntechProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public void setProtocolType(int protocolType) { + this.protocolType = protocolType; + } + + public int getProtocolType(long deviceId) { + return Context.getIdentityManager().lookupAttributeInteger( + deviceId, getProtocolName() + ".protocolType", protocolType, true); + } + + public void setHbm(boolean hbm) { + this.hbm = hbm; + } + + public boolean isHbm(long deviceId) { + return Context.getIdentityManager().lookupAttributeBoolean( + deviceId, getProtocolName() + ".hbm", hbm, true); + } + + public void setIncludeAdc(boolean includeAdc) { + this.includeAdc = includeAdc; + } + + public boolean isIncludeAdc(long deviceId) { + return Context.getIdentityManager().lookupAttributeBoolean( + deviceId, getProtocolName() + ".includeAdc", includeAdc, true); + } + + public void setIncludeTemp(boolean includeTemp) { + this.includeTemp = includeTemp; + } + + public boolean isIncludeTemp(long deviceId) { + return Context.getIdentityManager().lookupAttributeBoolean( + deviceId, getProtocolName() + ".includeTemp", includeTemp, true); + } + + private Position decode9( + Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException { + int index = 1; + + String type = values[index++]; + + if (!type.equals("Location") && !type.equals("Emergency") && !type.equals("Alert")) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (type.equals("Emergency") || type.equals("Alert")) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + + if (!type.equals("Alert") || getProtocolType(deviceSession.getDeviceId()) == 0) { + position.set(Position.KEY_VERSION_FW, values[index++]); + } + + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(values[index++] + values[index++])); + + if (getProtocolType(deviceSession.getDeviceId()) == 1) { + index += 1; // cell + } + + position.setLatitude(Double.parseDouble(values[index++])); + position.setLongitude(Double.parseDouble(values[index++])); + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); + position.setCourse(Double.parseDouble(values[index++])); + + position.setValid(values[index++].equals("1")); + + if (getProtocolType(deviceSession.getDeviceId()) == 1) { + position.set(Position.KEY_ODOMETER, Integer.parseInt(values[index++])); + } + + return position; + } + + private String decodeEmergency(int value) { + switch (value) { + case 1: + return Position.ALARM_SOS; + case 2: + return Position.ALARM_PARKING; + case 3: + return Position.ALARM_POWER_CUT; + case 5: + case 6: + return Position.ALARM_DOOR; + case 7: + return Position.ALARM_MOVEMENT; + case 8: + return Position.ALARM_SHOCK; + default: + return null; + } + } + + private String decodeAlert(int value) { + switch (value) { + case 1: + return Position.ALARM_OVERSPEED; + case 5: + return Position.ALARM_GEOFENCE_EXIT; + case 6: + return Position.ALARM_GEOFENCE_ENTER; + case 14: + return Position.ALARM_LOW_BATTERY; + case 15: + return Position.ALARM_SHOCK; + case 16: + return Position.ALARM_ACCIDENT; + case 46: + return Position.ALARM_ACCELERATION; + case 47: + return Position.ALARM_BRAKING; + case 48: + return Position.ALARM_ACCIDENT; + case 50: + return Position.ALARM_JAMMING; + default: + return null; + } + } + private Position decode4( + Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException { + int index = 0; + + String type = values[index++].substring(5); + + if (!type.equals("STT") && !type.equals("ALT")) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_TYPE, type); + + position.set(Position.KEY_VERSION_FW, values[index++]); + index += 1; // model + + Network network = new Network(); + + for (int i = 0; i < 7; i++) { + int cid = Integer.parseInt(values[index++]); + int mcc = Integer.parseInt(values[index++]); + int mnc = Integer.parseInt(values[index++]); + int lac, rssi; + if (i == 0) { + rssi = Integer.parseInt(values[index++]); + lac = Integer.parseInt(values[index++]); + } else { + lac = Integer.parseInt(values[index++]); + rssi = Integer.parseInt(values[index++]); + } + index += 1; // timing advance + if (cid > 0) { + network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi)); + } + } + + position.setNetwork(network); + + position.set(Position.KEY_BATTERY, Double.parseDouble(values[index++])); + position.set(Position.KEY_ARCHIVE, values[index++].equals("0") ? true : null); + position.set(Position.KEY_INDEX, Integer.parseInt(values[index++])); + position.set(Position.KEY_STATUS, Integer.parseInt(values[index++])); + + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(values[index++] + values[index++])); + + position.setLatitude(Double.parseDouble(values[index++])); + position.setLongitude(Double.parseDouble(values[index++])); + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); + position.setCourse(Double.parseDouble(values[index++])); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + + position.setValid(values[index++].equals("1")); + + return position; + } + + private Position decode2356( + Channel channel, SocketAddress remoteAddress, String protocol, String[] values) throws ParseException { + int index = 0; + + String type = values[index++].substring(5); + + if (!type.equals("STT") && !type.equals("EMG") && !type.equals("EVT") && !type.equals("ALT")) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_TYPE, type); + + if (protocol.equals("ST300") || protocol.equals("ST500") || protocol.equals("ST600")) { + index += 1; // model + } + + position.set(Position.KEY_VERSION_FW, values[index++]); + + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(values[index++] + values[index++])); + + if (!protocol.equals("ST500")) { + long cid = Long.parseLong(values[index++], 16); + if (protocol.equals("ST600")) { + position.setNetwork(new Network(CellTower.from( + Integer.parseInt(values[index++]), Integer.parseInt(values[index++]), + Integer.parseInt(values[index++], 16), cid, Integer.parseInt(values[index++])))); + } + } + + position.setLatitude(Double.parseDouble(values[index++])); + position.setLongitude(Double.parseDouble(values[index++])); + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); + position.setCourse(Double.parseDouble(values[index++])); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + + position.setValid(values[index++].equals("1")); + + position.set(Position.KEY_ODOMETER, Integer.parseInt(values[index++])); + position.set(Position.KEY_POWER, Double.parseDouble(values[index++])); + + String io = values[index++]; + if (io.length() == 6) { + position.set(Position.KEY_IGNITION, io.charAt(0) == '1'); + position.set(Position.PREFIX_IN + 1, io.charAt(1) == '1'); + position.set(Position.PREFIX_IN + 2, io.charAt(2) == '1'); + position.set(Position.PREFIX_IN + 3, io.charAt(3) == '1'); + position.set(Position.PREFIX_OUT + 1, io.charAt(4) == '1'); + position.set(Position.PREFIX_OUT + 2, io.charAt(5) == '1'); + } + + switch (type) { + case "STT": + position.set(Position.KEY_STATUS, Integer.parseInt(values[index++])); + position.set(Position.KEY_INDEX, Integer.parseInt(values[index++])); + break; + case "EMG": + position.set(Position.KEY_ALARM, decodeEmergency(Integer.parseInt(values[index++]))); + break; + case "EVT": + position.set(Position.KEY_EVENT, Integer.parseInt(values[index++])); + break; + case "ALT": + position.set(Position.KEY_ALARM, decodeAlert(Integer.parseInt(values[index++]))); + break; + default: + break; + } + + if (isHbm(deviceSession.getDeviceId())) { + + if (index < values.length) { + position.set(Position.KEY_HOURS, UnitsConverter.msFromMinutes(Integer.parseInt(values[index++]))); + } + + if (index < values.length) { + position.set(Position.KEY_BATTERY, Double.parseDouble(values[index++])); + } + + if (index < values.length && values[index++].equals("0")) { + position.set(Position.KEY_ARCHIVE, true); + } + + if (isIncludeAdc(deviceSession.getDeviceId())) { + for (int i = 1; i <= 3; i++) { + if (!values[index++].isEmpty()) { + position.set(Position.PREFIX_ADC + i, Double.parseDouble(values[index - 1])); + } + } + } + + if (values.length - index >= 2) { + String driverUniqueId = values[index++]; + if (values[index++].equals("1") && !driverUniqueId.isEmpty()) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId); + } + } + + if (isIncludeTemp(deviceSession.getDeviceId())) { + for (int i = 1; i <= 3; i++) { + String temperature = values[index++]; + String value = temperature.substring(temperature.indexOf(':') + 1); + if (!value.isEmpty()) { + position.set(Position.PREFIX_TEMP + i, Double.parseDouble(value)); + } + } + + } + + } + + return position; + } + + private Position decodeUniversal( + Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException { + int index = 0; + + String type = values[index++]; + + if (!type.equals("STT")) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_TYPE, type); + + int mask = Integer.parseInt(values[index++], 16); + + if (BitUtil.check(mask, 1)) { + index += 1; // model + } + + if (BitUtil.check(mask, 2)) { + position.set(Position.KEY_VERSION_FW, values[index++]); + } + + if (BitUtil.check(mask, 3) && values[index++].equals("0")) { + position.set(Position.KEY_ARCHIVE, true); + } + + if (BitUtil.check(mask, 4) && BitUtil.check(mask, 5)) { + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(values[index++] + values[index++])); + } + + if (BitUtil.check(mask, 6)) { + index += 1; // cell + } + + if (BitUtil.check(mask, 7)) { + index += 1; // mcc + } + + if (BitUtil.check(mask, 8)) { + index += 1; // mnc + } + + if (BitUtil.check(mask, 9)) { + index += 1; // lac + } + + if (BitUtil.check(mask, 10)) { + position.set(Position.KEY_RSSI, Integer.parseInt(values[index++])); + } + + if (BitUtil.check(mask, 11)) { + position.setLatitude(Double.parseDouble(values[index++])); + } + + if (BitUtil.check(mask, 12)) { + position.setLongitude(Double.parseDouble(values[index++])); + } + + if (BitUtil.check(mask, 13)) { + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); + } + + if (BitUtil.check(mask, 14)) { + position.setCourse(Double.parseDouble(values[index++])); + } + + if (BitUtil.check(mask, 15)) { + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); + } + + if (BitUtil.check(mask, 16)) { + position.setValid(values[index++].equals("1")); + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String[] values = ((String) msg).split(";"); + + if (values[0].length() < 5) { + return decodeUniversal(channel, remoteAddress, values); + } else if (values[0].startsWith("ST9")) { + return decode9(channel, remoteAddress, values); + } else if (values[0].startsWith("ST4")) { + return decode4(channel, remoteAddress, values); + } else { + return decode2356(channel, remoteAddress, values[0].substring(0, 5), values); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java new file mode 100644 index 000000000..90fa4aa39 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 - 2016 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class SuntechProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_REBOOT_DEVICE: + return formatCommand(command, "SA200CMD;{%s};02;Reboot\r", Command.KEY_UNIQUE_ID); + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, "SA200GTR;{%s};02;\r", Command.KEY_UNIQUE_ID); + case Command.TYPE_OUTPUT_CONTROL: + if (command.getAttributes().containsKey(Command.KEY_DATA)) { + if (command.getAttributes().get(Command.KEY_DATA).equals("1")) { + return formatCommand(command, "SA200CMD;{%s};02;Enable{%s}\r", + Command.KEY_UNIQUE_ID, Command.KEY_INDEX); + } else { + return formatCommand(command, "SA200CMD;{%s};02;Disable{%s}\r", + Command.KEY_UNIQUE_ID, Command.KEY_INDEX); + } + } + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, "SA200CMD;{%s};02;Enable1\r", Command.KEY_UNIQUE_ID); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, "SA200CMD;{%s};02;Disable1\r", Command.KEY_UNIQUE_ID); + case Command.TYPE_ALARM_ARM: + return formatCommand(command, "SA200CMD;{%s};02;Enable2\r", Command.KEY_UNIQUE_ID); + case Command.TYPE_ALARM_DISARM: + return formatCommand(command, "SA200CMD;{%s};02;Disable2\r", Command.KEY_UNIQUE_ID); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/SupermateProtocol.java b/src/main/java/org/traccar/protocol/SupermateProtocol.java new file mode 100644 index 000000000..46625ddc7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SupermateProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class SupermateProtocol extends BaseProtocol { + + public SupermateProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "#")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new SupermateProtocolDecoder(SupermateProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java b/src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java new file mode 100644 index 000000000..40a25bb91 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java @@ -0,0 +1,122 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Calendar; +import java.util.regex.Pattern; + +public class SupermateProtocolDecoder extends BaseProtocolDecoder { + + public SupermateProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("d+:") // header + .number("(d+):") // imei + .number("d+:").text("*,") + .number("(d+),") // command id + .expression("([^,]{2}),") // command + .expression("([AV]),") // validity + .number("(xx)(xx)(xx),") // date (yymmdd) + .number("(xx)(xx)(xx),") // time (hhmmss) + .number("(x)(x{7}),") // latitude + .number("(x)(x{7}),") // longitude + .number("(x{4}),") // speed + .number("(x{4}),") // course + .number("(x{12}),") // status + .number("(x+),") // signal + .number("(d+),") // power + .number("(x{4}),") // oil + .number("(x+)?") // odometer + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + String imei = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set("commandId", parser.next()); + position.set(Position.KEY_COMMAND, parser.next()); + + position.setValid(parser.next().equals("A")); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(parser.nextHexInt(0), parser.nextHexInt(0), parser.nextHexInt(0)) + .setTime(parser.nextHexInt(0), parser.nextHexInt(0), parser.nextHexInt(0)); + position.setTime(dateBuilder.getDate()); + + if (parser.nextHexInt(0) == 8) { + position.setLatitude(-parser.nextHexInt(0) / 600000.0); + } else { + position.setLatitude(parser.nextHexInt(0) / 600000.0); + } + + if (parser.nextHexInt(0) == 8) { + position.setLongitude(-parser.nextHexInt(0) / 600000.0); + } else { + position.setLongitude(parser.nextHexInt(0) / 600000.0); + } + + position.setSpeed(parser.nextHexInt(0) / 100.0); + position.setCourse(parser.nextHexInt(0) / 100.0); + + position.set(Position.KEY_STATUS, parser.next()); + position.set("signal", parser.next()); + position.set(Position.KEY_POWER, parser.nextDouble(0)); + position.set("oil", parser.nextHexInt(0)); + position.set(Position.KEY_ODOMETER, parser.nextHexInt(0)); + + if (channel != null) { + Calendar calendar = Calendar.getInstance(); + String content = String.format("#1:%s:1:*,00000000,UP,%02x%02x%02x,%02x%02x%02x#", imei, + calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH), + calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND)); + channel.writeAndFlush(new NetworkMessage( + Unpooled.copiedBuffer(content, StandardCharsets.US_ASCII), remoteAddress)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SviasProtocol.java b/src/main/java/org/traccar/protocol/SviasProtocol.java new file mode 100644 index 000000000..f01f28389 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SviasProtocol.java @@ -0,0 +1,51 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import org.traccar.model.Command; + +public class SviasProtocol extends BaseProtocol { + + public SviasProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_SET_ODOMETER, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM, + Command.TYPE_ALARM_REMOVE); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "]")); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new SviasProtocolEncoder()); + pipeline.addLast(new SviasProtocolDecoder(SviasProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SviasProtocolDecoder.java b/src/main/java/org/traccar/protocol/SviasProtocolDecoder.java new file mode 100644 index 000000000..7e783f6cd --- /dev/null +++ b/src/main/java/org/traccar/protocol/SviasProtocolDecoder.java @@ -0,0 +1,105 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.PatternBuilder; + +import java.net.SocketAddress; +import java.util.regex.Pattern; +import org.traccar.DeviceSession; +import org.traccar.helper.Parser; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +public class SviasProtocolDecoder extends BaseProtocolDecoder { + + public SviasProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("[") // delimiter + .number("d{4},") // hardware version + .number("d{4},") // software version + .number("d+,") // index + .number("(d+),") // imei + .number("d+,") // hour meter + .number("(d+)(dd)(dd),") // date (dmmyy) + .number("(d+)(dd)(dd),") // time (hmmss) + .number("(-?)(d+)(dd)(d{5}),") // latitude + .number("(-?)(d+)(dd)(d{5}),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+),") // odometer + .number("(d+),") // input + .number("(d+),") // output / status + .number("(d),") + .number("(d),") + .number("(d+),") // power + .number("(d+),") // battery level + .number("(d+),") // rssi + .any() + .compile(); + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) + throws Exception { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("@", remoteAddress)); + } + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble() * 0.01)); + position.setCourse(parser.nextDouble() * 0.01); + + position.set(Position.KEY_ODOMETER, parser.nextInt() * 100); + + int input = parser.nextInt(); + int output = parser.nextInt(); + + position.set(Position.KEY_ALARM, BitUtil.check(input, 0) ? Position.ALARM_SOS : null); + position.set(Position.KEY_IGNITION, BitUtil.check(input, 4)); + position.setValid(BitUtil.check(output, 0)); + + position.set(Position.KEY_POWER, parser.nextInt() * 0.001); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java b/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java new file mode 100644 index 000000000..8bfbef119 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class SviasProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatCommand(command, "{%s}", Command.KEY_DATA); + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, "AT+STR=1*"); + case Command.TYPE_SET_ODOMETER: + return formatCommand(command, "AT+ODT={%s}*", Command.KEY_DATA); + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, "AT+OUT=1,1*"); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, "AT+OUT=1,0*"); + case Command.TYPE_ALARM_ARM: + return formatCommand(command, "AT+OUT=2,1*"); + case Command.TYPE_ALARM_DISARM: + return formatCommand(command, "AT+OUT=2,0*"); + case Command.TYPE_ALARM_REMOVE: + return formatCommand(command, "AT+PNC=600*"); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/T55Protocol.java b/src/main/java/org/traccar/protocol/T55Protocol.java new file mode 100644 index 000000000..f5ec19094 --- /dev/null +++ b/src/main/java/org/traccar/protocol/T55Protocol.java @@ -0,0 +1,47 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class T55Protocol extends BaseProtocol { + + public T55Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new T55ProtocolDecoder(T55Protocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new T55ProtocolDecoder(T55Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java new file mode 100644 index 000000000..ba231a635 --- /dev/null +++ b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java @@ -0,0 +1,283 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.channels.DatagramChannel; +import java.util.Date; +import java.util.regex.Pattern; + +public class T55ProtocolDecoder extends BaseProtocolDecoder { + + public T55ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_GPRMC = new PatternBuilder() + .text("$GPRMC,") + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d{2,3})(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .expression("[^*]+") + .text("*") + .expression("[^,]+") + .number(",(d+)") // satellites + .number(",(d+)") // imei + .expression(",([01])") // ignition + .number(",(d+)") // fuel + .number(",(d+)").optional(7) // battery + .number("((?:,d+)+)?") // parameters + .any() + .compile(); + + private static final Pattern PATTERN_GPGGA = new PatternBuilder() + .text("$GPGGA,") + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .expression("([EW]),") + .any() + .compile(); + + private static final Pattern PATTERN_GPRMA = new PatternBuilder() + .text("$GPRMA,") + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),,,") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .any() + .compile(); + + private static final Pattern PATTERN_TRCCR = new PatternBuilder() + .text("$TRCCR,") + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd).?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(-?d+.d+),") // altitude + .number("(d+.?d*),") // battery + .any() + .compile(); + + private Position position = null; + + private Position decodeGprmc( + DeviceSession deviceSession, String sentence, SocketAddress remoteAddress, Channel channel) { + + if (deviceSession != null && channel != null && !(channel instanceof DatagramChannel) + && Context.getIdentityManager().lookupAttributeBoolean( + deviceSession.getDeviceId(), getProtocolName() + ".ack", false, true)) { + channel.writeAndFlush(new NetworkMessage("OK1\r\n", remoteAddress)); + } + + Parser parser = new Parser(PATTERN_GPRMC, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + if (deviceSession != null) { + position.setDeviceId(deviceSession.getDeviceId()); + } + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + if (parser.hasNext(5)) { + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_IGNITION, parser.hasNext() && parser.next().equals("1")); + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); + position.set(Position.KEY_BATTERY, parser.nextInt()); + } + + if (parser.hasNext()) { + String[] parameters = parser.next().split(","); + for (int i = 1; i < parameters.length; i++) { + position.set(Position.PREFIX_IO + i, parameters[i]); + } + } + + if (deviceSession != null) { + return position; + } else { + this.position = position; // save position + return null; + } + } + + private Position decodeGpgga(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN_GPGGA, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setCurrentDate() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + return position; + } + + private Position decodeGprma(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN_GPRMA, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date()); + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + return position; + } + + private Position decodeTrccr(DeviceSession deviceSession, String sentence) { + + Parser parser = new Parser(PATTERN_TRCCR, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + position.set(Position.KEY_BATTERY, parser.nextDouble(0)); + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + DeviceSession deviceSession; + + if (!sentence.startsWith("$") && sentence.contains("$")) { + int index = sentence.indexOf("$"); + String id = sentence.substring(0, index); + if (id.endsWith(",")) { + id = id.substring(0, id.length() - 1); + } else if (id.endsWith("/")) { + id = id.substring(id.indexOf('/') + 1, id.length() - 1); + } + deviceSession = getDeviceSession(channel, remoteAddress, id); + sentence = sentence.substring(index); + } else { + deviceSession = getDeviceSession(channel, remoteAddress); + } + + if (sentence.startsWith("$PGID")) { + getDeviceSession(channel, remoteAddress, sentence.substring(6, sentence.length() - 3)); + } else if (sentence.startsWith("$DEVID")) { + getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.lastIndexOf('*'))); + } else if (sentence.startsWith("$PCPTI")) { + getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.indexOf(",", 7))); + } else if (sentence.startsWith("IMEI")) { + getDeviceSession(channel, remoteAddress, sentence.substring(5)); + } else if (sentence.startsWith("$IMEI")) { + getDeviceSession(channel, remoteAddress, sentence.substring(6)); + } else if (sentence.startsWith("$GPFID")) { + deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(7)); + if (deviceSession != null && position != null) { + Position position = this.position; + position.setDeviceId(deviceSession.getDeviceId()); + this.position = null; + return position; + } + } else if (sentence.matches("^[0-9A-F]+$")) { + getDeviceSession(channel, remoteAddress, sentence); + } else if (sentence.startsWith("$GPRMC")) { + return decodeGprmc(deviceSession, sentence, remoteAddress, channel); + } else if (sentence.startsWith("$GPGGA") && deviceSession != null) { + return decodeGpgga(deviceSession, sentence); + } else if (sentence.startsWith("$GPRMA") && deviceSession != null) { + return decodeGprma(deviceSession, sentence); + } else if (sentence.startsWith("$TRCCR") && deviceSession != null) { + return decodeTrccr(deviceSession, sentence); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/T57FrameDecoder.java b/src/main/java/org/traccar/protocol/T57FrameDecoder.java new file mode 100644 index 000000000..14ba31453 --- /dev/null +++ b/src/main/java/org/traccar/protocol/T57FrameDecoder.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +import java.nio.charset.StandardCharsets; + +public class T57FrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + String type = buf.toString(buf.readerIndex() + 5, 2, StandardCharsets.US_ASCII); + int count = type.equals("F3") ? 12 : 14; + + int index = 0; + while (index >= 0 && count > 0) { + index = buf.indexOf(index + 1, buf.writerIndex(), (byte) '#'); + if (index > 0) { + count -= 1; + } + } + + return index > 0 ? buf.readRetainedSlice(index + 1 - buf.readerIndex()) : null; + } + +} diff --git a/src/main/java/org/traccar/protocol/T57Protocol.java b/src/main/java/org/traccar/protocol/T57Protocol.java new file mode 100644 index 000000000..f67f82318 --- /dev/null +++ b/src/main/java/org/traccar/protocol/T57Protocol.java @@ -0,0 +1,38 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class T57Protocol extends BaseProtocol { + + public T57Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new T57FrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new T57ProtocolDecoder(T57Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/T57ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T57ProtocolDecoder.java new file mode 100644 index 000000000..2a3cca3e4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/T57ProtocolDecoder.java @@ -0,0 +1,84 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class T57ProtocolDecoder extends BaseProtocolDecoder { + + public T57ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("*T57#") + .number("Fd#") // type + .number("([^#]+)#") // device id + .number("(dd)(dd)(dd)#") // date (ddmmyy) + .number("(dd)(dd)(dd)#") // time (hhmmss) + .number("(dd)(dd.d+)#") // latitude + .expression("([NS])#") + .number("(ddd)(dd.d+)#") // longitude + .expression("([EW])#") + .expression("[^#]+#") + .number("(d+.d+)#") // speed + .number("(d+.d+)#") // altitude + .expression("([AV])") // valid + .number("d#") // fix type + .number("(d+.d+)#") // battery + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + position.setAltitude(parser.nextDouble()); + + position.setValid(parser.next().equals("A")); + + position.set(Position.KEY_BATTERY, parser.nextDouble()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/T800xProtocol.java b/src/main/java/org/traccar/protocol/T800xProtocol.java new file mode 100644 index 000000000..85749d0cf --- /dev/null +++ b/src/main/java/org/traccar/protocol/T800xProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class T800xProtocol extends BaseProtocol { + + public T800xProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2, -5, 0)); + pipeline.addLast(new T800xProtocolEncoder()); + pipeline.addLast(new T800xProtocolDecoder(T800xProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java new file mode 100644 index 000000000..dfb286257 --- /dev/null +++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java @@ -0,0 +1,199 @@ +/* + * Copyright 2015 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class T800xProtocolDecoder extends BaseProtocolDecoder { + + public T800xProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 0x01; + public static final int MSG_GPS = 0x02; + public static final int MSG_HEARTBEAT = 0x03; + public static final int MSG_ALARM = 0x04; + public static final int MSG_COMMAND = 0x81; + + private void sendResponse(Channel channel, short header, int type, int index, ByteBuf imei) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(15); + response.writeShort(header); + response.writeByte(type); + response.writeShort(response.capacity()); // length + response.writeShort(index); + response.writeBytes(imei); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + private String decodeAlarm(short value) { + switch (value) { + case 1: + return Position.ALARM_POWER_CUT; + case 2: + return Position.ALARM_LOW_BATTERY; + case 3: + return Position.ALARM_SOS; + case 4: + return Position.ALARM_OVERSPEED; + case 5: + return Position.ALARM_GEOFENCE_ENTER; + case 6: + return Position.ALARM_GEOFENCE_EXIT; + case 7: + return Position.ALARM_TOW; + case 8: + case 10: + return Position.ALARM_VIBRATION; + case 21: + return Position.ALARM_JAMMING; + case 23: + return Position.ALARM_POWER_RESTORED; + case 24: + return Position.ALARM_LOW_POWER; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + short header = buf.readShort(); + int type = buf.readUnsignedByte(); + buf.readUnsignedShort(); // length + int index = buf.readUnsignedShort(); + ByteBuf imei = buf.readSlice(8); + + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, ByteBufUtil.hexDump(imei).substring(1)); + if (deviceSession == null) { + return null; + } + + sendResponse(channel, header, type, index, imei); + + if (type == MSG_GPS || type == MSG_ALARM) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_INDEX, index); + + buf.readUnsignedShort(); // acc on interval + buf.readUnsignedShort(); // acc off interval + buf.readUnsignedByte(); // angle compensation + buf.readUnsignedShort(); // distance compensation + + position.set(Position.KEY_RSSI, BitUtil.to(buf.readUnsignedShort(), 7)); + + int status = buf.readUnsignedByte(); + position.set(Position.KEY_SATELLITES, BitUtil.to(status, 5)); + + buf.readUnsignedByte(); // gsensor manager status + buf.readUnsignedByte(); // other flags + buf.readUnsignedByte(); // heartbeat + buf.readUnsignedByte(); // relay status + buf.readUnsignedShort(); // drag alarm setting + + int io = buf.readUnsignedShort(); + position.set(Position.KEY_IGNITION, BitUtil.check(io, 14)); + position.set("ac", BitUtil.check(io, 13)); + + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + + buf.readUnsignedByte(); // reserved + + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + + int battery = BcdUtil.readInteger(buf, 2); + if (battery == 0) { + battery = 100; + } + position.set(Position.KEY_BATTERY, battery); + + DateBuilder dateBuilder = new DateBuilder() + .setYear(BcdUtil.readInteger(buf, 2)) + .setMonth(BcdUtil.readInteger(buf, 2)) + .setDay(BcdUtil.readInteger(buf, 2)) + .setHour(BcdUtil.readInteger(buf, 2)) + .setMinute(BcdUtil.readInteger(buf, 2)) + .setSecond(BcdUtil.readInteger(buf, 2)); + + if (BitUtil.check(status, 6)) { + + position.setValid(!BitUtil.check(status, 7)); + position.setTime(dateBuilder.getDate()); + position.setAltitude(buf.readFloatLE()); + position.setLongitude(buf.readFloatLE()); + position.setLatitude(buf.readFloatLE()); + position.setSpeed(UnitsConverter.knotsFromKph(BcdUtil.readInteger(buf, 4) * 0.1)); + position.setCourse(buf.readUnsignedShort()); + + } else { + + getLastLocation(position, dateBuilder.getDate()); + + int mcc = buf.readUnsignedShortLE(); + int mnc = buf.readUnsignedShortLE(); + + if (mcc != 0xffff && mnc != 0xffff) { + Network network = new Network(); + for (int i = 0; i < 3; i++) { + network.addCellTower(CellTower.from( + mcc, mnc, buf.readUnsignedShortLE(), buf.readUnsignedShortLE())); + } + position.setNetwork(network); + } + + } + + if (buf.readableBytes() >= 2) { + position.set(Position.KEY_POWER, BcdUtil.readInteger(buf, 4) * 0.01); + } + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/T800xProtocolEncoder.java b/src/main/java/org/traccar/protocol/T800xProtocolEncoder.java new file mode 100644 index 000000000..1d0f3dabe --- /dev/null +++ b/src/main/java/org/traccar/protocol/T800xProtocolEncoder.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.DataConverter; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class T800xProtocolEncoder extends BaseProtocolEncoder { + + public static final int MODE_SETTING = 0x01; + public static final int MODE_BROADCAST = 0x02; + public static final int MODE_FORWARD = 0x03; + + private ByteBuf encodeContent(Command command, String content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeByte('#'); + buf.writeByte('#'); + buf.writeByte(T800xProtocolDecoder.MSG_COMMAND); + buf.writeShort(7 + 8 + 1 + content.length()); + buf.writeShort(1); // serial number + buf.writeBytes(DataConverter.parseHex("0" + getUniqueId(command.getDeviceId()))); + buf.writeByte(MODE_SETTING); + buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return encodeContent(command, command.getString(Command.KEY_DATA)); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/TaipProtocol.java b/src/main/java/org/traccar/protocol/TaipProtocol.java new file mode 100644 index 000000000..b8f40a183 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TaipProtocol.java @@ -0,0 +1,47 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TaipProtocol extends BaseProtocol { + + public TaipProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '<')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java new file mode 100644 index 000000000..8a0cb870b --- /dev/null +++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java @@ -0,0 +1,287 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +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.DateBuilder; +import org.traccar.helper.DateUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.regex.Pattern; + +public class TaipProtocolDecoder extends BaseProtocolDecoder { + + public TaipProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .groupBegin() + .expression("R[EP]V") // type + .groupBegin() + .number("(dd)") // event + .number("(dddd)") // week + .number("(d)") // day + .groupEnd("?") + .number("(d{5})") // seconds + .or() + .expression("(?:RGP|RCQ|RCV|RBR)") // type + .number("(dd)?") // event + .number("(dd)(dd)(dd)") // date (mmddyy) + .number("(dd)(dd)(dd)") // time (hhmmss) + .groupEnd() + .groupBegin() + .number("([-+]dd)(d{5})") // latitude + .number("([-+]ddd)(d{5})") // longitude + .or() + .number("([-+])(dd)(dd.dddd)") // latitude + .number("([-+])(ddd)(dd.dddd)") // longitude + .groupEnd() + .number("(ddd)") // speed + .number("(ddd)") // course + .groupBegin() + .number("([023])") // fix mode + .number("xx") // data age + .number("(xx)") // input + .number("(dd)") // event + .number("(dd)") // hdop + .or() + .groupBegin() + .number("(xx)") // input + .number("(xx)") // satellites + .number("(ddd)") // battery + .number("(x{8})") // odometer + .number("[01]") // gps power + .groupBegin() + .number("([023])") // fix mode + .number("(dd)") // pdop + .number("dd") // satellites + .number("xxxx") // data age + .number("[01]") // modem power + .number("[0-5]") // gsm status + .number("(dd)") // rssi + .number("([-+]dddd)") // temperature 1 + .number("xx") // seconds from last + .number("([-+]dddd)") // temperature 2 + .number("xx") // seconds from last + .groupEnd("?") + .groupEnd("?") + .groupEnd() + .any() + .compile(); + + private Date getTime(long week, long day, long seconds) { + DateBuilder dateBuilder = new DateBuilder() + .setDate(1980, 1, 6) + .addMillis(((week * 7 + day) * 24 * 60 * 60 + seconds) * 1000); + return dateBuilder.getDate(); + } + + private Date getTime(long seconds) { + DateBuilder dateBuilder = new DateBuilder(new Date()) + .setTime(0, 0, 0, 0) + .addMillis(seconds * 1000); + return DateUtil.correctDay(dateBuilder.getDate()); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + int beginIndex = sentence.indexOf('>'); + if (beginIndex != -1) { + sentence = sentence.substring(beginIndex + 1); + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + Boolean valid = null; + Integer event = null; + + if (parser.hasNext(3)) { + event = parser.nextInt(); + position.setTime(getTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0))); + } else if (parser.hasNext()) { + position.setTime(getTime(parser.nextInt(0))); + } + + if (parser.hasNext()) { + event = parser.nextInt(); + } + + if (parser.hasNext(6)) { + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + } + + if (parser.hasNext(4)) { + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG)); + } + if (parser.hasNext(6)) { + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + } + + position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + if (parser.hasNext(4)) { + valid = parser.nextInt() > 0; + int input = parser.nextHexInt(); + position.set(Position.KEY_IGNITION, BitUtil.check(input, 7)); + position.set(Position.KEY_INPUT, input); + event = parser.nextInt(); + position.set(Position.KEY_HDOP, parser.nextInt()); + } + + if (parser.hasNext(4)) { + position.set(Position.KEY_INPUT, parser.nextHexInt(0)); + position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); + position.set(Position.KEY_BATTERY, parser.nextInt(0)); + position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0)); + } + + if (parser.hasNext(4)) { + valid = parser.nextInt() > 0; + position.set(Position.KEY_PDOP, parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.PREFIX_TEMP + 1, parser.nextInt() * 0.01); + position.set(Position.PREFIX_TEMP + 2, parser.nextInt() * 0.01); + } + + position.setValid(valid == null || valid); + + if (event != null) { + position.set(Position.KEY_EVENT, event); + switch (event) { + case 22: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 23: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 24: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + case 26: + case 28: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + default: + break; + } + } + + String[] attributes = null; + beginIndex = sentence.indexOf(';'); + if (beginIndex != -1) { + int endIndex = sentence.indexOf('<', beginIndex); + if (endIndex == -1) { + endIndex = sentence.length(); + } + attributes = sentence.substring(beginIndex, endIndex).split(";"); + } + + return decodeAttributes(channel, remoteAddress, position, attributes); + } + + private Position decodeAttributes( + Channel channel, SocketAddress remoteAddress, Position position, String[] attributes) { + + String uniqueId = null; + DeviceSession deviceSession = null; + String messageIndex = null; + + if (attributes != null) { + for (String attribute : attributes) { + int index = attribute.indexOf('='); + if (index != -1) { + String key = attribute.substring(0, index).toLowerCase(); + String value = attribute.substring(index + 1); + switch (key) { + case "id": + uniqueId = value; + deviceSession = getDeviceSession(channel, remoteAddress, value); + if (deviceSession != null) { + position.setDeviceId(deviceSession.getDeviceId()); + } + break; + case "io": + position.set(Position.KEY_IGNITION, BitUtil.check(value.charAt(0) - '0', 0)); + position.set(Position.KEY_CHARGE, BitUtil.check(value.charAt(0) - '0', 1)); + position.set(Position.KEY_OUTPUT, value.charAt(1) - '0'); + position.set(Position.KEY_INPUT, value.charAt(2) - '0'); + break; + case "ix": + position.set(Position.PREFIX_IO + 1, value); + break; + case "ad": + position.set(Position.PREFIX_ADC + 1, Integer.parseInt(value)); + break; + case "sv": + position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); + break; + case "bl": + position.set(Position.KEY_BATTERY, Integer.parseInt(value) * 0.001); + break; + case "vo": + position.set(Position.KEY_ODOMETER, Long.parseLong(value)); + break; + default: + position.set(key, value); + break; + } + } else if (attribute.startsWith("#")) { + messageIndex = attribute; + } + } + } + + if (deviceSession != null) { + if (channel != null) { + if (messageIndex != null) { + String response = ">ACK;ID=" + uniqueId + ";" + messageIndex + ";*"; + response += String.format("%02X", Checksum.xor(response)) + "<"; + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } else { + channel.writeAndFlush(new NetworkMessage(uniqueId, remoteAddress)); + } + } + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TekFrameDecoder.java b/src/main/java/org/traccar/protocol/TekFrameDecoder.java new file mode 100644 index 000000000..44d2c590e --- /dev/null +++ b/src/main/java/org/traccar/protocol/TekFrameDecoder.java @@ -0,0 +1,42 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; +import org.traccar.helper.BitUtil; + +public class TekFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 17) { + return null; + } + + int length = 17 + buf.getUnsignedByte(16) + (BitUtil.from(buf.getUnsignedByte(15), 6) << 6); + if (buf.readableBytes() >= length) { + return buf.readBytes(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TekProtocol.java b/src/main/java/org/traccar/protocol/TekProtocol.java new file mode 100644 index 000000000..c1d78e6f5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TekProtocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TekProtocol extends BaseProtocol { + + public TekProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TekFrameDecoder()); + pipeline.addLast(new TekProtocolDecoder(TekProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TekProtocolDecoder.java b/src/main/java/org/traccar/protocol/TekProtocolDecoder.java new file mode 100644 index 000000000..a9101e65f --- /dev/null +++ b/src/main/java/org/traccar/protocol/TekProtocolDecoder.java @@ -0,0 +1,139 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class TekProtocolDecoder extends BaseProtocolDecoder { + + public TekProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number(",d+,") + .number("(dd)(dd)(dd).d,") // time (hhmmss) + .number("(dd)(dd.d+)") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+)") // longitude + .expression("([EW]),") + .number("(d+.d+),") // hdop + .number("(d+.d+),") // altitude + .number("(d+),") // fix mode + .number("(d+.d+),") // course + .number("d+.d+,") // speed km + .number("(d+.d+),") // speed kn + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(d+),") // satellites + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // product type + buf.readUnsignedByte(); // hardware version + buf.readUnsignedByte(); // firmware version + buf.readUnsignedByte(); // contact reason + buf.readUnsignedByte(); // alarm / status + buf.readUnsignedByte(); // rssi + buf.readUnsignedByte(); // battery / status + + String imei = ByteBufUtil.hexDump(buf.readBytes(8)).substring(1); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + int type = BitUtil.to(buf.readUnsignedByte(), 6); + buf.readUnsignedByte(); // length + + if (type == 4 || type == 8) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + int count = buf.readUnsignedShort(); + buf.readUnsignedByte(); // hours / tickets + buf.readUnsignedByte(); // error code + buf.readUnsignedByte(); // reserved + buf.readUnsignedByte(); // logger speed + buf.readUnsignedByte(); // login time + buf.readUnsignedByte(); // minutes + + for (int i = 0; i < count; i++) { + position.set("rssi" + (i + 1), buf.readUnsignedByte()); + position.set("temp" + (i + 1), buf.readUnsignedByte() - 30); + int data = buf.readUnsignedShort(); + position.set("src" + (i + 1), BitUtil.from(data, 10)); + position.set("ullage" + (i + 1), BitUtil.to(data, 10)); + } + + return position; + + } else if (type == 17) { + + String sentence = buf.toString(StandardCharsets.US_ASCII); + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + position.set(Position.KEY_HDOP, parser.nextDouble()); + + position.setAltitude(parser.nextDouble()); + position.setValid(parser.nextInt() > 0); + position.setCourse(parser.nextDouble()); + position.setSpeed(parser.nextDouble()); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TelemaxProtocol.java b/src/main/java/org/traccar/protocol/TelemaxProtocol.java new file mode 100644 index 000000000..838da9df1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TelemaxProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TelemaxProtocol extends BaseProtocol { + + public TelemaxProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new TelemaxProtocolDecoder(TelemaxProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java b/src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java new file mode 100644 index 000000000..9369ab101 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java @@ -0,0 +1,112 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class TelemaxProtocolDecoder extends BaseProtocolDecoder { + + public TelemaxProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private String readValue(String sentence, int[] index, int length) { + String value = sentence.substring(index[0], index[0] + length); + index[0] += length; + return value; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("%")) { + int length = Integer.parseInt(sentence.substring(1, 3)); + getDeviceSession(channel, remoteAddress, sentence.substring(3, 3 + length)); + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + int[] index = {0}; + + if (!readValue(sentence, index, 1).equals("Y")) { + return null; + } + + readValue(sentence, index, 8); // command id + readValue(sentence, index, 6); // password + readValue(sentence, index, Integer.parseInt(readValue(sentence, index, 2), 16)); // unit id + readValue(sentence, index, 2); // frame count + + readValue(sentence, index, 2); // data format + + int interval = Integer.parseInt(readValue(sentence, index, 4), 16); + + readValue(sentence, index, 2); // info flags + readValue(sentence, index, 2); // version + + int count = Integer.parseInt(readValue(sentence, index, 2), 16); + + Date time = null; + List positions = new LinkedList<>(); + + for (int i = 0; i < count; i++) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + int speed = Integer.parseInt(readValue(sentence, index, 2), 16); + + position.setValid(BitUtil.check(speed, 7)); + position.setSpeed(BitUtil.to(speed, 7)); + + position.setLongitude((Integer.parseInt(readValue(sentence, index, 6), 16) - 5400000) / 30000.0); + position.setLatitude((Integer.parseInt(readValue(sentence, index, 6), 16) - 5400000) / 30000.0); + + if (i == 0 | i == count - 1) { + time = new SimpleDateFormat("yyMMddHHmmss").parse(readValue(sentence, index, 12)); + position.set(Position.KEY_STATUS, readValue(sentence, index, 8)); + } else { + time = new Date(time.getTime() + interval * 1000); + } + + position.setTime(time); + + positions.add(position); + + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/TelicFrameDecoder.java b/src/main/java/org/traccar/protocol/TelicFrameDecoder.java new file mode 100644 index 000000000..d1fef1b5b --- /dev/null +++ b/src/main/java/org/traccar/protocol/TelicFrameDecoder.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016 - 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. + * 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 org.traccar.BaseFrameDecoder; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +public class TelicFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 4) { + return null; + } + + long length = buf.getUnsignedIntLE(buf.readerIndex()); + + if (length < 1024) { + if (buf.readableBytes() >= length + 4) { + buf.readUnsignedIntLE(); + return buf.readRetainedSlice((int) length); + } + } else { + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0); + if (endIndex >= 0) { + ByteBuf frame = buf.readRetainedSlice(endIndex - buf.readerIndex()); + buf.readByte(); + if (frame.readableBytes() > 0) { + return frame; + } + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TelicProtocol.java b/src/main/java/org/traccar/protocol/TelicProtocol.java new file mode 100644 index 000000000..991befa19 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TelicProtocol.java @@ -0,0 +1,38 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TelicProtocol extends BaseProtocol { + + public TelicProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TelicFrameDecoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new TelicProtocolDecoder(TelicProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java new file mode 100644 index 000000000..6d5e8f21e --- /dev/null +++ b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java @@ -0,0 +1,135 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class TelicProtocolDecoder extends BaseProtocolDecoder { + + public TelicProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("dddd") + .number("(d{6}|d{15})") // device id + .number("(d{1,2}),") // type + .number("d{12},") // event time + .number("d+,") + .number("(dd)(dd)(dd)") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .groupBegin() + .number("(ddd)(dd)(dddd),") // longitude + .number("(dd)(dd)(dddd),") // latitude + .or() + .number("(-?d+),") // longitude + .number("(-?d+),") // latitude + .groupEnd() + .number("(d),") // validity + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+)?,") // satellites + .expression("(?:[^,]*,){7}") + .number("(d+),") // battery + .any() + .compile(); + + private String decodeAlarm(int eventId) { + + switch (eventId) { + case 1: + return Position.ALARM_POWER_ON; + case 2: + return Position.ALARM_SOS; + case 5: + return Position.ALARM_POWER_OFF; + case 7: + return Position.ALARM_GEOFENCE_ENTER; + case 8: + return Position.ALARM_GEOFENCE_EXIT; + case 22: + return Position.ALARM_LOW_BATTERY; + case 25: + return Position.ALARM_MOVEMENT; + default: + return null; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + int event = parser.nextInt(0); + position.set(Position.KEY_EVENT, event); + + position.set(Position.KEY_ALARM, decodeAlarm(event)); + + if (event == 11) { + position.set(Position.KEY_IGNITION, true); + } else if (event == 12) { + position.set(Position.KEY_IGNITION, false); + } + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + if (parser.hasNext(6)) { + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); + } + + if (parser.hasNext(2)) { + position.setLongitude(parser.nextDouble(0) / 10000); + position.setLatitude(parser.nextDouble(0) / 10000); + } + + position.setValid(parser.nextInt(0) != 1); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + if (parser.hasNext()) { + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + } + + position.set(Position.KEY_BATTERY, parser.nextInt(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java new file mode 100644 index 000000000..4d4d79d8d --- /dev/null +++ b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java @@ -0,0 +1,53 @@ +/* + * Copyright 2013 - 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. + * 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 org.traccar.BaseFrameDecoder; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +public class TeltonikaFrameDecoder extends BaseFrameDecoder { + + private static final int MESSAGE_MINIMUM_LENGTH = 12; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + // Check minimum length + if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { + return null; + } + + // Read packet + int length = buf.getUnsignedShort(buf.readerIndex()); + if (length > 0) { + if (buf.readableBytes() >= (length + 2)) { + return buf.readRetainedSlice(length + 2); + } + } else { + int dataLength = buf.getInt(buf.readerIndex() + 4); + if (buf.readableBytes() >= (dataLength + 12)) { + return buf.readRetainedSlice(dataLength + 12); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java new file mode 100644 index 000000000..eef9662d7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java @@ -0,0 +1,45 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class TeltonikaProtocol extends BaseProtocol { + + public TeltonikaProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TeltonikaFrameDecoder()); + pipeline.addLast(new TeltonikaProtocolEncoder()); + pipeline.addLast(new TeltonikaProtocolDecoder(TeltonikaProtocol.this, false)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TeltonikaProtocolEncoder()); + pipeline.addLast(new TeltonikaProtocolDecoder(TeltonikaProtocol.this, true)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java new file mode 100644 index 000000000..974d2c106 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -0,0 +1,597 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +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; +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 photos = new HashMap<>(); + + public void setExtended(boolean extended) { + this.extended = extended; + } + + public TeltonikaProtocolDecoder(Protocol protocol, boolean connectionless) { + super(protocol); + this.connectionless = connectionless; + this.extended = Context.getConfig().getBoolean(getProtocolName() + ".extended"); + } + + private void parseIdentification(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + int length = buf.readUnsignedShort(); + String imei = buf.toString(buf.readerIndex(), length, StandardCharsets.US_ASCII); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + + if (channel != null) { + ByteBuf response = Unpooled.buffer(1); + if (deviceSession != null) { + response.writeByte(1); + } else { + response.writeByte(0); + } + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + public static final int CODEC_GH3000 = 0x07; + public static final int CODEC_8 = 0x08; + public static final int CODEC_8_EXT = 0x8E; + public static final int CODEC_12 = 0x0C; + public static final int CODEC_16 = 0x10; + + 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() - 10))); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private void decodeSerial(Channel channel, SocketAddress remoteAddress, Position position, ByteBuf buf) { + + getLastLocation(position, null); + + 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(); + } + } + + } + + } 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) { + switch (length) { + case 1: + return signed ? buf.readByte() : buf.readUnsignedByte(); + case 2: + return signed ? buf.readShort() : buf.readUnsignedShort(); + case 4: + return signed ? buf.readInt() : buf.readUnsignedInt(); + default: + return buf.readLong(); + } + } + + private void decodeOtherParameter(Position position, int id, ByteBuf buf, int length) { + switch (id) { + case 1: + case 2: + case 3: + case 4: + position.set("di" + id, readValue(buf, length, false)); + break; + case 9: + position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false)); + break; + case 17: + position.set("axisX", readValue(buf, length, true)); + break; + case 18: + position.set("axisY", readValue(buf, length, true)); + break; + case 19: + position.set("axisZ", readValue(buf, length, true)); + break; + case 21: + position.set(Position.KEY_RSSI, readValue(buf, length, false)); + break; + case 25: + case 26: + case 27: + case 28: + position.set(Position.PREFIX_TEMP + (id - 24), readValue(buf, length, true) * 0.1); + break; + case 66: + position.set(Position.KEY_POWER, readValue(buf, length, false) * 0.001); + break; + case 67: + position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); + break; + case 69: + position.set("gpsStatus", readValue(buf, length, false)); + break; + case 72: + case 73: + case 74: + position.set(Position.PREFIX_TEMP + (id - 71), readValue(buf, length, true) * 0.1); + break; + case 78: + long driverUniqueId = readValue(buf, length, false); + if (driverUniqueId != 0) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId)); + } + break; + case 80: + position.set("workMode", readValue(buf, length, false)); + break; + case 129: + case 130: + case 131: + case 132: + case 133: + case 134: + String driver = id == 129 || id == 132 ? "" : position.getString("driver1"); + position.set("driver" + (id >= 132 ? 2 : 1), + driver + buf.readSlice(length).toString(StandardCharsets.US_ASCII).trim()); + break; + case 179: + position.set(Position.PREFIX_OUT + 1, readValue(buf, length, false) == 1); + break; + case 180: + position.set(Position.PREFIX_OUT + 2, readValue(buf, length, false) == 1); + break; + case 181: + position.set(Position.KEY_PDOP, readValue(buf, length, false) * 0.1); + break; + case 182: + position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1); + break; + case 236: + if (readValue(buf, length, false) == 1) { + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + } + break; + case 237: + position.set(Position.KEY_MOTION, readValue(buf, length, false) == 0); + break; + case 238: + switch ((int) readValue(buf, length, false)) { + case 1: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 2: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 3: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + default: + break; + } + break; + case 239: + position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); + break; + case 240: + position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1); + break; + case 241: + position.set(Position.KEY_OPERATOR, readValue(buf, length, false)); + break; + default: + position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); + break; + } + } + + private void decodeGh3000Parameter(Position position, int id, ByteBuf buf, int length) { + switch (id) { + case 1: + position.set(Position.KEY_BATTERY_LEVEL, readValue(buf, length, false)); + break; + case 2: + position.set("usbConnected", readValue(buf, length, false) == 1); + break; + case 5: + position.set("uptime", readValue(buf, length, false)); + break; + case 20: + position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1); + break; + case 21: + position.set(Position.KEY_VDOP, readValue(buf, length, false) * 0.1); + break; + case 22: + position.set(Position.KEY_PDOP, readValue(buf, length, false) * 0.1); + break; + case 67: + position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); + break; + case 221: + position.set("button", readValue(buf, length, false)); + break; + case 222: + if (readValue(buf, length, false) == 1) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + break; + case 240: + position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1); + break; + case 244: + position.set(Position.KEY_ROAMING, readValue(buf, length, false) == 1); + break; + default: + position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); + break; + } + } + + private void decodeParameter(Position position, int id, ByteBuf buf, int length, int codec) { + if (codec == CODEC_GH3000) { + decodeGh3000Parameter(position, id, buf, length); + } else { + decodeOtherParameter(position, id, buf, length); + } + } + + private void decodeNetwork(Position position) { + long cid = position.getLong(Position.PREFIX_IO + 205); + int lac = position.getInteger(Position.PREFIX_IO + 206); + if (cid != 0 && lac != 0) { + CellTower cellTower = CellTower.fromLacCid(lac, cid); + long operator = position.getInteger(Position.KEY_OPERATOR); + if (operator != 0) { + cellTower.setOperator(operator); + } + position.setNetwork(new Network(cellTower)); + } + } + + private int readExtByte(ByteBuf buf, int codec, int... codecs) { + boolean ext = false; + for (int c : codecs) { + if (codec == c) { + ext = true; + break; + } + } + if (ext) { + return buf.readUnsignedShort(); + } else { + return buf.readUnsignedByte(); + } + } + + private void decodeLocation(Position position, ByteBuf buf, int codec) { + + int globalMask = 0x0f; + + if (codec == CODEC_GH3000) { + + long time = buf.readUnsignedInt() & 0x3fffffff; + time += 1167609600; // 2007-01-01 00:00:00 + + globalMask = buf.readUnsignedByte(); + if (BitUtil.check(globalMask, 0)) { + + position.setTime(new Date(time * 1000)); + + int locationMask = buf.readUnsignedByte(); + + if (BitUtil.check(locationMask, 0)) { + position.setLatitude(buf.readFloat()); + position.setLongitude(buf.readFloat()); + } + + if (BitUtil.check(locationMask, 1)) { + position.setAltitude(buf.readUnsignedShort()); + } + + if (BitUtil.check(locationMask, 2)) { + position.setCourse(buf.readUnsignedByte() * 360.0 / 256); + } + + if (BitUtil.check(locationMask, 3)) { + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + } + + if (BitUtil.check(locationMask, 4)) { + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + } + + if (BitUtil.check(locationMask, 5)) { + CellTower cellTower = CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort()); + + if (BitUtil.check(locationMask, 6)) { + cellTower.setSignalStrength((int) buf.readUnsignedByte()); + } + + if (BitUtil.check(locationMask, 7)) { + cellTower.setOperator(buf.readUnsignedInt()); + } + + position.setNetwork(new Network(cellTower)); + + } else { + if (BitUtil.check(locationMask, 6)) { + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + } + if (BitUtil.check(locationMask, 7)) { + position.set(Position.KEY_OPERATOR, buf.readUnsignedInt()); + } + } + + } else { + + getLastLocation(position, new Date(time * 1000)); + + } + + } else { + + position.setTime(new Date(buf.readLong())); + + position.set("priority", buf.readUnsignedByte()); + + position.setLongitude(buf.readInt() / 10000000.0); + position.setLatitude(buf.readInt() / 10000000.0); + position.setAltitude(buf.readShort()); + position.setCourse(buf.readUnsignedShort()); + + int satellites = buf.readUnsignedByte(); + position.set(Position.KEY_SATELLITES, satellites); + + position.setValid(satellites != 0); + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + + position.set(Position.KEY_EVENT, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16)); + if (codec == CODEC_16) { + buf.readUnsignedByte(); // generation type + } + + readExtByte(buf, codec, CODEC_8_EXT); // total IO data records + + } + + // Read 1 byte data + if (BitUtil.check(globalMask, 1)) { + int cnt = readExtByte(buf, codec, CODEC_8_EXT); + for (int j = 0; j < cnt; j++) { + decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 1, codec); + } + } + + // Read 2 byte data + if (BitUtil.check(globalMask, 2)) { + int cnt = readExtByte(buf, codec, CODEC_8_EXT); + for (int j = 0; j < cnt; j++) { + decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 2, codec); + } + } + + // Read 4 byte data + if (BitUtil.check(globalMask, 3)) { + int cnt = readExtByte(buf, codec, CODEC_8_EXT); + for (int j = 0; j < cnt; j++) { + decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 4, codec); + } + } + + // Read 8 byte data + if (codec == CODEC_8 || codec == CODEC_8_EXT || codec == CODEC_16) { + int cnt = readExtByte(buf, codec, CODEC_8_EXT); + for (int j = 0; j < cnt; j++) { + decodeOtherParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 8); + } + } + + // Read 16 byte data + if (extended) { + int cnt = readExtByte(buf, codec, CODEC_8_EXT); + for (int j = 0; j < cnt; j++) { + int id = readExtByte(buf, codec, CODEC_8_EXT, CODEC_16); + position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(16))); + } + } + + // Read X byte data + if (codec == CODEC_8_EXT) { + int cnt = buf.readUnsignedShort(); + for (int j = 0; j < cnt; j++) { + int id = buf.readUnsignedShort(); + int length = buf.readUnsignedShort(); + if (id == 256) { + position.set(Position.KEY_VIN, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); + } else { + position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(length))); + } + } + } + + decodeNetwork(position); + + } + + private List parseData( + Channel channel, SocketAddress remoteAddress, ByteBuf buf, int locationPacketId, String... imei) { + List positions = new LinkedList<>(); + + if (!connectionless) { + buf.readUnsignedInt(); // data length + } + + int codec = buf.readUnsignedByte(); + int count = buf.readUnsignedByte(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + + if (deviceSession == null) { + return null; + } + + for (int i = 0; i < count; i++) { + Position position = new Position(getProtocolName()); + + position.setDeviceId(deviceSession.getDeviceId()); + position.setValid(true); + + if (codec == CODEC_12) { + decodeSerial(channel, remoteAddress, position, buf); + } else { + decodeLocation(position, buf, codec); + } + + if (!position.getOutdated() || !position.getAttributes().isEmpty()) { + positions.add(position); + } + } + + if (channel != null) { + if (connectionless) { + ByteBuf response = Unpooled.buffer(); + response.writeShort(5); + response.writeShort(0); + response.writeByte(0x01); + response.writeByte(locationPacketId); + response.writeByte(count); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } else { + ByteBuf response = Unpooled.buffer(); + response.writeInt(count); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + return positions.isEmpty() ? null : positions; + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (connectionless) { + return decodeUdp(channel, remoteAddress, buf); + } else { + return decodeTcp(channel, remoteAddress, buf); + } + } + + private Object decodeTcp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { + + if (buf.getUnsignedShort(0) > 0) { + parseIdentification(channel, remoteAddress, buf); + } else { + buf.skipBytes(4); + return parseData(channel, remoteAddress, buf, 0); + } + + return null; + } + + private Object decodeUdp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { + + buf.readUnsignedShort(); // length + buf.readUnsignedShort(); // packet id + buf.readUnsignedByte(); // packet type + int locationPacketId = buf.readUnsignedByte(); + String imei = buf.readSlice(buf.readUnsignedShort()).toString(StandardCharsets.US_ASCII); + + return parseData(channel, remoteAddress, buf, locationPacketId, imei); + + } + +} diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolEncoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolEncoder.java new file mode 100644 index 000000000..944cec024 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolEncoder.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 - 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. + * 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 org.traccar.BaseProtocolEncoder; +import org.traccar.helper.Checksum; +import org.traccar.model.Command; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import java.nio.charset.StandardCharsets; + +public class TeltonikaProtocolEncoder extends BaseProtocolEncoder { + + private ByteBuf encodeContent(String content) { + + ByteBuf buf = Unpooled.buffer(); + + buf.writeInt(0); + buf.writeInt(content.length() + 10); + buf.writeByte(TeltonikaProtocolDecoder.CODEC_12); + buf.writeByte(1); // quantity + buf.writeByte(5); // type + buf.writeInt(content.length() + 2); + buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); + buf.writeByte('\r'); + buf.writeByte('\n'); + buf.writeByte(1); // quantity + buf.writeInt(Checksum.crc16(Checksum.CRC16_IBM, buf.nioBuffer(8, buf.writerIndex() - 8))); + + return buf; + } + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return encodeContent(command.getString(Command.KEY_DATA)); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java b/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java new file mode 100644 index 000000000..ca1237cef --- /dev/null +++ b/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java @@ -0,0 +1,35 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class ThinkRaceProtocol extends BaseProtocol { + + public ThinkRaceProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2 + 12 + 1 + 1, 2, 2, 0)); + pipeline.addLast(new ThinkRaceProtocolDecoder(ThinkRaceProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java b/src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java new file mode 100644 index 000000000..0928b25e0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java @@ -0,0 +1,116 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class ThinkRaceProtocolDecoder extends BaseProtocolDecoder { + + public ThinkRaceProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN = 0x80; + public static final int MSG_GPS = 0x90; + + private static double convertCoordinate(long raw, boolean negative) { + long degrees = raw / 1000000; + double minutes = (raw % 1000000) * 0.0001; + double result = degrees + minutes / 60; + if (negative) { + result = -result; + } + return result; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + ByteBuf id = buf.readSlice(12); + buf.readUnsignedByte(); // separator + int type = buf.readUnsignedByte(); + buf.readUnsignedShort(); // length + + if (type == MSG_LOGIN) { + + int command = buf.readUnsignedByte(); // 0x00 - heartbeat + + if (command == 0x01) { + String imei = buf.toString(buf.readerIndex(), 15, StandardCharsets.US_ASCII); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession != null && channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0x48); response.writeByte(0x52); // header + response.writeBytes(id); + response.writeByte(0x2c); // separator + response.writeByte(type); + response.writeShort(0x0002); // length + response.writeShort(0x8000); + response.writeShort(0x0000); // checksum + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + } else if (type == MSG_GPS) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + + int flags = buf.readUnsignedByte(); + + position.setValid(true); + position.setLatitude(convertCoordinate(buf.readUnsignedInt(), !BitUtil.check(flags, 0))); + position.setLongitude(convertCoordinate(buf.readUnsignedInt(), !BitUtil.check(flags, 1))); + + position.setSpeed(buf.readUnsignedByte()); + position.setCourse(buf.readUnsignedByte()); + + position.setNetwork(new Network( + CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort()))); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Tk102Protocol.java b/src/main/java/org/traccar/protocol/Tk102Protocol.java new file mode 100644 index 000000000..9f2463cd6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tk102Protocol.java @@ -0,0 +1,35 @@ +/* + * 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Tk102Protocol extends BaseProtocol { + + public Tk102Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1 + 1 + 10, 1, 1, 0)); + pipeline.addLast(new Tk102ProtocolDecoder(Tk102Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java new file mode 100644 index 000000000..da0c6928b --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java @@ -0,0 +1,144 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class Tk102ProtocolDecoder extends BaseProtocolDecoder { + + public Tk102ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_LOGIN_REQUEST = 0x80; + public static final int MSG_LOGIN_REQUEST_2 = 0x21; + public static final int MSG_LOGIN_RESPONSE = 0x00; + public static final int MSG_HEARTBEAT_REQUEST = 0xF0; + public static final int MSG_HEARTBEAT_RESPONSE = 0xFF; + public static final int MSG_REPORT_ONCE = 0x90; + public static final int MSG_REPORT_INTERVAL = 0x93; + + public static final int MODE_GPRS = 0x30; + public static final int MODE_GPRS_SMS = 0x33; + + private static final Pattern PATTERN = new PatternBuilder() + .text("(") + .expression("[A-Z]+") + .number("(dd)(dd)(dd)") // time (hhmmss) + .expression("([AV])") // validity + .number("(dd)(dd.dddd)([NS])") // latitude + .number("(ddd)(dd.dddd)([EW])") // longitude + .number("(ddd.ddd)") // speed + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .text(")") + .compile(); + + private void sendResponse(Channel channel, int type, ByteBuf dataSequence, ByteBuf content) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte('['); + response.writeByte(type); + response.writeBytes(dataSequence); + response.writeByte(content.readableBytes()); + response.writeBytes(content); + content.release(); + response.writeByte(']'); + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(1); // header + int type = buf.readUnsignedByte(); + ByteBuf dataSequence = buf.readSlice(10); + int length = buf.readUnsignedByte(); + + if (type == MSG_LOGIN_REQUEST || type == MSG_LOGIN_REQUEST_2) { + + ByteBuf data = buf.readSlice(length); + + String id; + if (type == MSG_LOGIN_REQUEST) { + id = data.toString(StandardCharsets.US_ASCII); + } else { + id = data.copy(1, 15).toString(StandardCharsets.US_ASCII); + } + + if (getDeviceSession(channel, remoteAddress, id) != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(MODE_GPRS); + response.writeBytes(data); + sendResponse(channel, MSG_LOGIN_RESPONSE, dataSequence, response); + } + + } else if (type == MSG_HEARTBEAT_REQUEST) { + + sendResponse(channel, MSG_HEARTBEAT_RESPONSE, dataSequence, buf.readRetainedSlice(length)); + + } else { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Tk103FrameDecoder.java b/src/main/java/org/traccar/protocol/Tk103FrameDecoder.java new file mode 100644 index 000000000..b61a42563 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tk103FrameDecoder.java @@ -0,0 +1,75 @@ +/* + * Copyright 2017 Valerii Vyshniak (val@val.one) + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class Tk103FrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 2) { + return null; + } + + int frameStartIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '('); + if (frameStartIndex == -1) { + buf.clear(); + return null; + } + + int frameEndIndex, freeTextSymbolCounter; + for (frameEndIndex = frameStartIndex, freeTextSymbolCounter = 0;; frameEndIndex++) { + int freeTextIndex = frameEndIndex; + frameEndIndex = buf.indexOf(frameEndIndex, buf.writerIndex(), (byte) ')'); + if (frameEndIndex == -1) { + break; + } + for (;; freeTextIndex++, freeTextSymbolCounter++) { + freeTextIndex = buf.indexOf(freeTextIndex, frameEndIndex, (byte) '$'); + if (freeTextIndex == -1 || freeTextIndex >= frameEndIndex) { + break; + } + } + if (freeTextSymbolCounter % 2 == 0) { + break; + } + } + + if (frameEndIndex == -1) { + while (buf.readableBytes() > 1024) { + int discardUntilIndex = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) '('); + if (discardUntilIndex == -1) { + buf.clear(); + } else { + buf.readerIndex(discardUntilIndex); + } + } + return null; + } + + buf.readerIndex(frameStartIndex); + + return buf.readRetainedSlice(frameEndIndex + 1 - frameStartIndex); + } + +} diff --git a/src/main/java/org/traccar/protocol/Tk103Protocol.java b/src/main/java/org/traccar/protocol/Tk103Protocol.java new file mode 100644 index 000000000..fa83133e2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tk103Protocol.java @@ -0,0 +1,69 @@ +/* + * Copyright 2017 Christoph Krey (c@ckrey.de) + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class Tk103Protocol extends BaseProtocol { + + public Tk103Protocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_GET_DEVICE_STATUS, + Command.TYPE_IDENTIFICATION, + Command.TYPE_MODE_DEEP_SLEEP, + Command.TYPE_MODE_POWER_SAVING, + Command.TYPE_ALARM_SOS, + Command.TYPE_SET_CONNECTION, + Command.TYPE_SOS_NUMBER, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_POSITION_STOP, + Command.TYPE_GET_VERSION, + Command.TYPE_POWER_OFF, + Command.TYPE_REBOOT_DEVICE, + Command.TYPE_SET_ODOMETER, + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME, + Command.TYPE_OUTPUT_CONTROL); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Tk103FrameDecoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Tk103ProtocolEncoder()); + pipeline.addLast(new Tk103ProtocolDecoder(Tk103Protocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Tk103ProtocolEncoder()); + pipeline.addLast(new Tk103ProtocolDecoder(Tk103Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java new file mode 100644 index 000000000..9e28b5051 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java @@ -0,0 +1,453 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Tk103ProtocolDecoder extends BaseProtocolDecoder { + + private boolean decodeLow; + + public Tk103ProtocolDecoder(Protocol protocol) { + super(protocol); + decodeLow = Context.getConfig().getBoolean(getProtocolName() + ".decodeLow"); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("(").optional() + .number("(d+)(,)?") // device id + .expression("(.{4}),?") // command + .number("(d*)") + .number("(dd)(dd)(dd),?") // date (mmddyy if comma-delimited, otherwise yyddmm) + .expression("([AV]),?") // validity + .number("(d+)(dd.d+)") // latitude + .expression("([NS]),?") + .number("(d+)(dd.d+)") // longitude + .expression("([EW]),?") + .number("(d+.d)(?:d*,)?") // speed + .number("(dd)(dd)(dd),?") // time (hhmmss) + .groupBegin() + .number("(?:([d.]{6})|(dd)),?") // course + .number("([01])") // charge + .number("([01])") // ignition + .number("(x)") // io + .number("(x)") // io + .number("(x)") // io + .number("(xxx)") // fuel + .number("L(x+)") // odometer + .or() + .number("(d+.d+)") // course + .groupEnd() + .any() + .number("([+-]ddd.d)?") // temperature + .text(")").optional() + .compile(); + + private static final Pattern PATTERN_BATTERY = new PatternBuilder() + .text("(").optional() + .number("(d+),") // device id + .text("ZC20,") + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d+),") // battery level + .number("(d+),") // battery voltage + .number("(d+),") // power voltage + .number("d+") // installed + .any() + .compile(); + + private static final Pattern PATTERN_NETWORK = new PatternBuilder() + .text("(").optional() + .number("(d{12})") // device id + .text("BZ00,") + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(x+),") // lac + .number("(x+),") // cid + .any() + .compile(); + + private static final Pattern PATTERN_LBSWIFI = new PatternBuilder() + .text("(").optional() + .number("(d+),") // device id + .expression("(.{4}),") // command + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(d+),") // lac + .number("(d+),") // cid + .number("(d+),") // number of wifi macs + .number("((?:(?:xx:){5}(?:xx)\\*[-+]?d+\\*d+,)*)") + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd)") // time (hhmmss) + .any() + .compile(); + + private static final Pattern PATTERN_COMMAND_RESULT = new PatternBuilder() + .text("(").optional() + .number("(d+),") // device id + .expression(".{4},") // command + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("\\$([\\s\\S]*?)(?:\\$|$)") // message + .any() + .compile(); + + private String decodeAlarm(int value) { + switch (value) { + case 1: + return Position.ALARM_ACCIDENT; + case 2: + return Position.ALARM_SOS; + case 3: + return Position.ALARM_VIBRATION; + case 4: + return Position.ALARM_LOW_SPEED; + case 5: + return Position.ALARM_OVERSPEED; + case 6: + return Position.ALARM_GEOFENCE_EXIT; + default: + return null; + } + } + + private void decodeType(Position position, String type, String data) { + switch (type) { + case "BO01": + position.set(Position.KEY_ALARM, decodeAlarm(data.charAt(0) - '0')); + break; + case "ZC11": + case "DW31": + case "DW51": + position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); + break; + case "ZC12": + case "DW32": + case "DW52": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case "ZC13": + case "DW33": + case "DW53": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; + case "ZC15": + case "DW35": + case "DW55": + position.set(Position.KEY_IGNITION, true); + break; + case "ZC16": + case "DW36": + case "DW56": + position.set(Position.KEY_IGNITION, false); + break; + case "ZC29": + case "DW42": + case "DW62": + position.set(Position.KEY_IGNITION, true); + break; + case "ZC17": + case "DW37": + case "DW57": + position.set(Position.KEY_ALARM, Position.ALARM_REMOVING); + break; + case "ZC25": + case "DW3E": + case "DW5E": + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + break; + case "ZC26": + case "DW3F": + case "DW5F": + position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); + break; + case "ZC27": + case "DW40": + case "DW60": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + break; + default: + break; + } + } + + private Integer decodeBattery(int value) { + switch (value) { + case 6: + return 100; + case 5: + return 80; + case 4: + return 50; + case 3: + return 20; + case 2: + return 10; + default: + return null; + } + } + + private Position decodeBattery(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_BATTERY, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + int batterylevel = parser.nextInt(0); + if (batterylevel != 255) { + position.set(Position.KEY_BATTERY_LEVEL, decodeBattery(batterylevel)); + } + + int battery = parser.nextInt(0); + if (battery != 65535) { + position.set(Position.KEY_BATTERY, battery * 0.01); + } + + int power = parser.nextInt(0); + if (power != 65535) { + position.set(Position.KEY_POWER, power * 0.1); + } + + return position; + } + + private Position decodeNetwork(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_NETWORK, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); + + return position; + } + + private Position decodeLbsWifi(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_LBSWIFI, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + decodeType(position, parser.next(), "0"); + + getLastLocation(position, null); + + Network network = new Network(); + + network.addCellTower(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt())); + + int wifiCount = parser.nextInt(); + if (parser.hasNext()) { + String[] wifimacs = parser.next().split(","); + if (wifimacs.length == wifiCount) { + for (int i = 0; i < wifiCount; i++) { + String[] wifiinfo = wifimacs[i].split("\\*"); + network.addWifiAccessPoint(WifiAccessPoint.from( + wifiinfo[0], Integer.parseInt(wifiinfo[1]), Integer.parseInt(wifiinfo[2]))); + } + } + } + + if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { + position.setNetwork(network); + } + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + return position; + } + + private Position decodeCommandResult(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_COMMAND_RESULT, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.set(Position.KEY_RESULT, parser.next()); + + return position; + + } + +@Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (channel != null) { + String id = sentence.substring(1, 13); + String type = sentence.substring(13, 17); + if (type.equals("BP00")) { + channel.writeAndFlush(new NetworkMessage("(" + id + "AP01HSO)", remoteAddress)); + return null; + } else if (type.equals("BP05")) { + channel.writeAndFlush(new NetworkMessage("(" + id + "AP05)", remoteAddress)); + } + } + + if (sentence.contains("ZC20")) { + return decodeBattery(channel, remoteAddress, sentence); + } else if (sentence.contains("BZ00")) { + return decodeNetwork(channel, remoteAddress, sentence); + } else if (sentence.contains("ZC03")) { + return decodeCommandResult(channel, remoteAddress, sentence); + } else if (sentence.contains("DW5")) { + return decodeLbsWifi(channel, remoteAddress, sentence); + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + boolean alternative = parser.next() != null; + + decodeType(position, parser.next(), parser.next()); + + DateBuilder dateBuilder = new DateBuilder(); + if (alternative) { + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + } else { + dateBuilder.setDate(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + } + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + position.setSpeed(convertSpeed(parser.nextDouble(0), "kmh")); + + dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + if (parser.hasNext()) { + position.setCourse(parser.nextDouble()); + } + if (parser.hasNext()) { + position.setCourse(parser.nextDouble()); + } + + if (parser.hasNext(7)) { + position.set(Position.KEY_CHARGE, parser.nextInt() == 0); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + + int mask1 = parser.nextHexInt(); + position.set(Position.PREFIX_IN + 2, BitUtil.check(mask1, 0) ? 1 : 0); + position.set("panic", BitUtil.check(mask1, 1) ? 1 : 0); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(mask1, 2) ? 1 : 0); + if (decodeLow || BitUtil.check(mask1, 3)) { + position.set(Position.KEY_BLOCKED, BitUtil.check(mask1, 3) ? 1 : 0); + } + + int mask2 = parser.nextHexInt(); + for (int i = 0; i < 3; i++) { + if (decodeLow || BitUtil.check(mask2, i)) { + position.set("hs" + (3 - i), BitUtil.check(mask2, i) ? 1 : 0); + } + } + if (decodeLow || BitUtil.check(mask2, 3)) { + position.set(Position.KEY_DOOR, BitUtil.check(mask2, 3) ? 1 : 0); + } + + int mask3 = parser.nextHexInt(); + for (int i = 1; i <= 3; i++) { + if (decodeLow || BitUtil.check(mask3, i)) { + position.set("ls" + (3 - i + 1), BitUtil.check(mask3, i) ? 1 : 0); + } + } + + position.set(Position.KEY_FUEL_LEVEL, parser.nextHexInt()); + position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0)); + } + + if (parser.hasNext()) { + position.setCourse(parser.nextDouble()); + } + + if (parser.hasNext()) { + position.set(Position.PREFIX_TEMP + 1, parser.nextDouble(0)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java new file mode 100644 index 000000000..98edc8cb5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java @@ -0,0 +1,110 @@ +/* + * Copyright 2017 Christoph Krey (c@ckrey.de) + * Copyright 2017 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. + * 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 org.traccar.Context; +import org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class Tk103ProtocolEncoder extends StringProtocolEncoder { + + private final boolean forceAlternative; + + public Tk103ProtocolEncoder() { + this.forceAlternative = false; + } + + public Tk103ProtocolEncoder(boolean forceAlternative) { + this.forceAlternative = forceAlternative; + } + + private String formatAlt(Command command, String format, String... keys) { + return formatCommand(command, "[begin]sms2," + format + ",[end]", keys); + } + + @Override + protected Object encodeCommand(Command command) { + + boolean alternative = forceAlternative || Context.getIdentityManager().lookupAttributeBoolean( + command.getDeviceId(), "tk103.alternative", false, true); + + initDevicePassword(command, "123456"); + + if (alternative) { + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatAlt(command, "{%s}", Command.KEY_DATA); + case Command.TYPE_GET_VERSION: + return formatAlt(command, "*about*"); + case Command.TYPE_POWER_OFF: + return formatAlt(command, "*turnoff*"); + case Command.TYPE_REBOOT_DEVICE: + return formatAlt(command, "88888888"); + case Command.TYPE_POSITION_SINGLE: + return formatAlt(command, "*getposl*"); + case Command.TYPE_POSITION_PERIODIC: + return formatAlt(command, "*routetrack*99*"); + case Command.TYPE_POSITION_STOP: + return formatAlt(command, "*routetrackoff*"); + case Command.TYPE_GET_DEVICE_STATUS: + return formatAlt(command, "*status*"); + case Command.TYPE_IDENTIFICATION: + return formatAlt(command, "999999"); + case Command.TYPE_MODE_DEEP_SLEEP: + return formatAlt(command, command.getBoolean(Command.KEY_ENABLE) ? "*sleep*2*" : "*sleepoff*"); + case Command.TYPE_MODE_POWER_SAVING: + return formatAlt(command, command.getBoolean(Command.KEY_ENABLE) ? "*sleepv*" : "*sleepoff*"); + case Command.TYPE_ALARM_SOS: + return formatAlt(command, command.getBoolean(Command.KEY_ENABLE) ? "*soson*" : "*sosoff*"); + case Command.TYPE_SET_CONNECTION: + return formatAlt(command, "*setip*%s*{%s}*", + command.getString(Command.KEY_SERVER).replace(".", "*"), Command.KEY_PORT); + case Command.TYPE_SOS_NUMBER: + return formatAlt(command, "*master*{%s}*{%s}*", Command.KEY_DEVICE_PASSWORD, Command.KEY_PHONE); + default: + return null; + } + } else { + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatCommand(command, "({%s}{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA); + case Command.TYPE_GET_VERSION: + return formatCommand(command, "({%s}AP07)", Command.KEY_UNIQUE_ID); + case Command.TYPE_REBOOT_DEVICE: + return formatCommand(command, "({%s}AT00)", Command.KEY_UNIQUE_ID); + case Command.TYPE_SET_ODOMETER: + return formatCommand(command, "({%s}AX01)", Command.KEY_UNIQUE_ID); + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, "({%s}AP00)", Command.KEY_UNIQUE_ID); + case Command.TYPE_POSITION_PERIODIC: + return formatCommand(command, "({%s}AR00%s0000)", Command.KEY_UNIQUE_ID, + String.format("%04X", command.getInteger(Command.KEY_FREQUENCY))); + case Command.TYPE_POSITION_STOP: + return formatCommand(command, "({%s}AR0000000000)", Command.KEY_UNIQUE_ID); + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, "({%s}AV010)", Command.KEY_UNIQUE_ID); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, "({%s}AV011)", Command.KEY_UNIQUE_ID); + case Command.TYPE_OUTPUT_CONTROL: + return formatCommand(command, "({%s}AV00{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA); + default: + return null; + } + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocol.java b/src/main/java/org/traccar/protocol/Tlt2hProtocol.java new file mode 100644 index 000000000..12fd92afa --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Tlt2hProtocol extends BaseProtocol { + + public Tlt2hProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(32 * 1024, "##\r\n")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Tlt2hProtocolDecoder(Tlt2hProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java new file mode 100644 index 000000000..f67ff88db --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java @@ -0,0 +1,152 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { + + public Tlt2hProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_HEADER = new PatternBuilder() + .number("#(d+)#") // imei + .any() + .expression("([^#]+)#") // status + .number("d+") // number of records + .compile(); + + private static final Pattern PATTERN_POSITION = new PatternBuilder() + .number("#(x+)?") // cell info + .text("$GPRMC,") + .number("(dd)(dd)(dd).d+,") // time (hhmmss.sss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d+)(dd.d+),") // longitude + .number("([EW]),") + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .any() + .compile(); + + private void decodeStatus(Position position, String status) { + switch (status) { + case "AUTOSTART": + case "AUTO": + position.set(Position.KEY_IGNITION, true); + break; + case "AUTOSTOP": + case "AUTOLOW": + position.set(Position.KEY_IGNITION, false); + break; + case "TOWED": + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + break; + case "SOS": + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + break; + case "DEF": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; + case "BLP": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case "CLP": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + break; + case "OS": + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT); + break; + case "RS": + position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER); + break; + case "OVERSPEED": + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + break; + default: + break; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + sentence = sentence.trim(); + + String header = sentence.substring(0, sentence.indexOf('\r')); + Parser parser = new Parser(PATTERN_HEADER, header); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + String status = parser.next(); + + String[] messages = sentence.substring(sentence.indexOf('\n') + 1).split("\r\n"); + List positions = new LinkedList<>(); + + for (String message : messages) { + parser = new Parser(PATTERN_POSITION, message); + if (parser.matches()) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + parser.next(); // base station info + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + decodeStatus(position, status); + + positions.add(position); + } + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/TlvProtocol.java b/src/main/java/org/traccar/protocol/TlvProtocol.java new file mode 100644 index 000000000..94f5da94f --- /dev/null +++ b/src/main/java/org/traccar/protocol/TlvProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TlvProtocol extends BaseProtocol { + + public TlvProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\0')); + pipeline.addLast(new TlvProtocolDecoder(TlvProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TlvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TlvProtocolDecoder.java new file mode 100644 index 000000000..36cf7859f --- /dev/null +++ b/src/main/java/org/traccar/protocol/TlvProtocolDecoder.java @@ -0,0 +1,110 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class TlvProtocolDecoder extends BaseProtocolDecoder { + + public TlvProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private void sendResponse(Channel channel, SocketAddress remoteAddress, String type, String... arguments) { + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeCharSequence(type, StandardCharsets.US_ASCII); + for (String argument : arguments) { + response.writeByte(argument.length()); + response.writeCharSequence(argument, StandardCharsets.US_ASCII); + } + response.writeByte(0); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + private String readArgument(ByteBuf buf) { + return buf.readSlice(buf.readUnsignedByte()).toString(StandardCharsets.US_ASCII); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + String type = buf.readSlice(2).toString(StandardCharsets.US_ASCII); + + if (channel != null) { + switch (type) { + case "0A": + case "0C": + sendResponse(channel, remoteAddress, type); + break; + case "0B": + sendResponse(channel, remoteAddress, type, "1482202689", "10", "20", "15"); + break; + case "0E": + case "0F": + sendResponse(channel, remoteAddress, type, "30", "Unknown"); + break; + default: + break; + } + } + + if (type.equals("0E")) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, readArgument(buf)); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setTime(new Date(Long.parseLong(readArgument(buf)) * 1000)); + + readArgument(buf); // location identifier + + position.setLongitude(Double.parseDouble(readArgument(buf))); + position.setLatitude(Double.parseDouble(readArgument(buf))); + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(readArgument(buf)))); + position.setCourse(Double.parseDouble(readArgument(buf))); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(readArgument(buf))); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TmgFrameDecoder.java b/src/main/java/org/traccar/protocol/TmgFrameDecoder.java new file mode 100644 index 000000000..205adaa51 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TmgFrameDecoder.java @@ -0,0 +1,67 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseFrameDecoder; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +public class TmgFrameDecoder extends BaseFrameDecoder { + + private boolean isLetter(byte c) { + return c >= 'a' && c <= 'z'; + } + + private int findHeader(ByteBuf buffer) { + int guessedIndex = buffer.indexOf(buffer.readerIndex(), buffer.writerIndex(), (byte) '$'); + while (guessedIndex != -1 && buffer.writerIndex() - guessedIndex >= 5) { + if (buffer.getByte(guessedIndex + 4) == ',' + && isLetter(buffer.getByte(guessedIndex + 1)) + && isLetter(buffer.getByte(guessedIndex + 2)) + && isLetter(buffer.getByte(guessedIndex + 3))) { + return guessedIndex; + } + guessedIndex = buffer.indexOf(guessedIndex, buffer.writerIndex(), (byte) '$'); + } + return -1; + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int beginIndex = findHeader(buf); + + if (beginIndex >= 0) { + + buf.readerIndex(beginIndex); + + int endIndex = buf.indexOf(beginIndex, buf.writerIndex(), (byte) '\n'); + + if (endIndex >= 0) { + ByteBuf frame = buf.readRetainedSlice(endIndex - beginIndex); + buf.readByte(); // delimiter + return frame; + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TmgProtocol.java b/src/main/java/org/traccar/protocol/TmgProtocol.java new file mode 100644 index 000000000..020332ce7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TmgProtocol.java @@ -0,0 +1,38 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TmgProtocol extends BaseProtocol { + + public TmgProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TmgFrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new TmgProtocolDecoder(TmgProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TmgProtocolDecoder.java b/src/main/java/org/traccar/protocol/TmgProtocolDecoder.java new file mode 100644 index 000000000..d27849f8c --- /dev/null +++ b/src/main/java/org/traccar/protocol/TmgProtocolDecoder.java @@ -0,0 +1,194 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class TmgProtocolDecoder extends BaseProtocolDecoder { + + public TmgProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$") + .expression("(...),") // type + .expression("[LH],").optional() // history + .number("(d+),") // imei + .number("(dd)(dd)(dddd),") // date (ddmmyyyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(d),") // status + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(ddd)(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .groupBegin() + .number("(-?d+.?d*),") // altitude + .number("(d+.d+),") // hdop + .number("(d+),") // satellites + .number("(d+),") // visible satellites + .number("([^,]*),") // operator + .number("(d+),") // rssi + .number("[^,]*,") // cid + .expression("([01]),") // ignition + .number("(d+.?d*),") // battery + .number("(d+.?d*),") // power + .expression("([01]+),") // input + .expression("([01]+),") // output + .expression("[01]+,") // temper status + .number("(d+.?d*)[^,]*,") // adc1 + .number("(d+.?d*)[^,]*,") // adc2 + .number("d+.?d*,") // trip meter + .expression("([^,]*),") // software version + .expression("([^,]*),").optional() // rfid + .or() + .number("[^,]*,") // cid + .number("(d+),") // rssi + .number("(d+),") // satellites + .number("[^,]*,") // battery level + .expression("([01]),") // ignition + .expression("([LH]{4}),") // input + .expression("[NT]{4},") // tamper status + .expression("([LH]{2}),") // output + .number("(d+.d+),") // adc1 + .number("(d+.d+),") // adc1 + .number("[^,]*,") // device id + .number("(d+),") // odometer + .groupEnd() + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + String type = parser.next(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + switch (type) { + case "rmv": + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; + case "ebl": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + break; + case "ibl": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case "tmp": + case "smt": + case "btt": + position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); + break; + case "ion": + position.set(Position.KEY_IGNITION, true); + break; + case "iof": + position.set(Position.KEY_IGNITION, false); + break; + default: + break; + } + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(parser.nextInt() > 0); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + + if (parser.hasNext(15)) { + + position.setAltitude(parser.nextDouble()); + + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt()); + position.set(Position.KEY_OPERATOR, parser.next()); + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_POWER, parser.nextDouble()); + + int input = parser.nextBinInt(); + int output = parser.nextBinInt(); + + if (!BitUtil.check(input, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + + position.set(Position.KEY_INPUT, input); + position.set(Position.KEY_OUTPUT, output); + + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); + position.set(Position.KEY_VERSION_FW, parser.next()); + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + } + + if (parser.hasNext(6)) { + + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + + char[] input = parser.next().toCharArray(); + for (int i = 0; i < input.length; i++) { + position.set(Position.PREFIX_IN + (i + 1), input[i] == 'H'); + } + + char[] output = parser.next().toCharArray(); + for (int i = 0; i < output.length; i++) { + position.set(Position.PREFIX_OUT + (i + 1), output[i] == 'H'); + } + + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextInt()); + + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/TopflytechProtocol.java b/src/main/java/org/traccar/protocol/TopflytechProtocol.java new file mode 100644 index 000000000..303072bdb --- /dev/null +++ b/src/main/java/org/traccar/protocol/TopflytechProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TopflytechProtocol extends BaseProtocol { + + public TopflytechProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new TopflytechProtocolDecoder(TopflytechProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java new file mode 100644 index 000000000..6de053c32 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java @@ -0,0 +1,76 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class TopflytechProtocolDecoder extends BaseProtocolDecoder { + + public TopflytechProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("(") + .number("(d+)") // imei + .any() + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .expression("([AV])") + .number("(dd)(dd.dddd)([NS])") // latitude + .number("(ddd)(dd.dddd)([EW])") // longitude + .number("(ddd.d)") // speed + .number("(d+.d+)") // course + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/TotemFrameDecoder.java b/src/main/java/org/traccar/protocol/TotemFrameDecoder.java new file mode 100644 index 000000000..3fa5abc7a --- /dev/null +++ b/src/main/java/org/traccar/protocol/TotemFrameDecoder.java @@ -0,0 +1,59 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +import java.nio.charset.StandardCharsets; + +import org.traccar.BaseFrameDecoder; +import org.traccar.helper.BufferUtil; + +public class TotemFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 10) { + return null; + } + + int beginIndex = BufferUtil.indexOf("$$", buf); + if (beginIndex == -1) { + return null; + } else if (beginIndex > buf.readerIndex()) { + buf.readerIndex(beginIndex); + } + + int length; + + if (buf.getByte(buf.readerIndex() + 2) == (byte) '0') { + length = Integer.parseInt(buf.toString(buf.readerIndex() + 2, 4, StandardCharsets.US_ASCII)); + } else { + length = Integer.parseInt(buf.toString(buf.readerIndex() + 2, 2, StandardCharsets.US_ASCII), 16); + } + + if (length <= buf.readableBytes()) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TotemProtocol.java b/src/main/java/org/traccar/protocol/TotemProtocol.java new file mode 100644 index 000000000..66e1ec4f1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TotemProtocol.java @@ -0,0 +1,44 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class TotemProtocol extends BaseProtocol { + + public TotemProtocol() { + setSupportedDataCommands( + Command.TYPE_ENGINE_RESUME, + Command.TYPE_ENGINE_STOP + ); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TotemFrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new TotemProtocolEncoder()); + pipeline.addLast(new TotemProtocolDecoder(TotemProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java new file mode 100644 index 000000000..cd7f684b8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java @@ -0,0 +1,444 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +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.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class TotemProtocolDecoder extends BaseProtocolDecoder { + + public TotemProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN1 = new PatternBuilder() + .text("$$") // header + .number("xx") // length + .number("(d+)|") // imei + .expression("(..)") // alarm + .text("$GPRMC,") + .number("(dd)(dd)(dd).d+,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(d+)(dd.d+),([NS]),") // latitude + .number("(d+)(dd.d+),([EW]),") // longitude + .number("(d+.?d*)?,") // speed + .number("(d+.?d*)?,") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .expression("[^*]*").text("*") + .number("xx|") // checksum + .number("(d+.d+)|") // pdop + .number("(d+.d+)|") // hdop + .number("(d+.d+)|") // vdop + .number("(d+)|") // io status + .number("d+|") // battery time + .number("d") // charged + .number("(ddd)") // battery + .number("(dddd)|") // power + .number("(d+)|").optional() // adc + .number("x*(xxxx)") // lac + .number("(xxxx)|") // cid + .number("(d+)|") // temperature + .number("(d+.d+)|") // odometer + .number("d+|") // serial number + .any() + .number("xxxx") // checksum + .any() + .compile(); + + private static final Pattern PATTERN2 = new PatternBuilder() + .text("$$") // header + .number("xx") // length + .number("(d+)|") // imei + .expression("(..)") // alarm type + .number("(dd)(dd)(dd)") // date (ddmmyy) + .number("(dd)(dd)(dd)|") // time (hhmmss) + .expression("([AV])|") // validity + .number("(d+)(dd.d+)|") // latitude + .expression("([NS])|") + .number("(d+)(dd.d+)|") // longitude + .expression("([EW])|") + .number("(d+.d+)?|") // speed + .number("(d+)?|") // course + .number("(d+.d+)|") // hdop + .number("(d+)|") // io status + .number("d") // charged + .number("(dd)") // battery + .number("(dd)|") // external power + .number("(d+)|") // adc + .number("(xxxx)") // lac + .number("(xxxx)|") // cid + .number("(d+)|") // temperature + .number("(d+.d+)|") // odometer + .number("d+|") // serial number + .number("xxxx") // checksum + .any() + .compile(); + + private static final Pattern PATTERN3 = new PatternBuilder() + .text("$$") // header + .number("xx") // length + .number("(d+)|") // imei + .expression("(..)") // alarm type + .number("(dd)(dd)(dd)") // date (ddmmyy) + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("(xxxx)") // io status + .expression("[01]") // charging + .number("(dd)") // battery + .number("(dd)") // external power + .number("(dddd)") // adc 1 + .number("(dddd)") // adc 2 + .number("(ddd)") // temperature 1 + .number("(ddd)") // temperature 2 + .number("(xxxx)") // lac + .number("(xxxx)") // cid + .expression("([AV])") // validity + .number("(dd)") // satellites + .number("(ddd)") // course + .number("(ddd)") // speed + .number("(dd.d)") // pdop + .number("(d{7})") // odometer + .number("(dd)(dd.dddd)([NS])") // latitude + .number("(ddd)(dd.dddd)([EW])") // longitude + .number("dddd") // serial number + .number("xxxx") // checksum + .any() + .compile(); + + private static final Pattern PATTERN4 = new PatternBuilder() + .text("$$") // header + .number("dddd") // length + .number("(xx)") // type + .number("(d+)|") // imei + .number("(x{8})") // status + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("(dd)") // battery + .number("(dd)") // external power + .number("(dddd)") // adc 1 + .groupBegin() + .groupBegin() + .number("(dddd)") // adc 2 + .number("(dddd)") // adc 3 + .number("(dddd)") // adc 4 + .groupEnd("?") + .number("(dddd)") // temperature 1 + .number("(dddd)?") // temperature 2 + .groupEnd("?") + .number("(xxxx)") // lac + .number("(xxxx)") // cid + .groupBegin() + .number("(dd)") // mcc + .number("(ddd)") // mnc + .groupEnd("?") + .number("(dd)") // satellites + .number("(dd)") // gsm (rssi) + .number("(ddd)") // course + .number("(ddd)") // speed + .number("(dd.d)") // hdop + .number("(d{7})") // odometer + .number("(dd)(dd.dddd)([NS])") // latitude + .number("(ddd)(dd.dddd)([EW])") // longitude + .number("dddd") // serial number + .number("xx") // checksum + .any() + .compile(); + + private String decodeAlarm123(int value) { + switch (value) { + case 0x01: + return Position.ALARM_SOS; + case 0x10: + return Position.ALARM_LOW_BATTERY; + case 0x11: + return Position.ALARM_OVERSPEED; + case 0x30: + return Position.ALARM_PARKING; + case 0x42: + return Position.ALARM_GEOFENCE_EXIT; + case 0x43: + return Position.ALARM_GEOFENCE_ENTER; + default: + return null; + } + } + + private String decodeAlarm4(int value) { + switch (value) { + case 0x01: + return Position.ALARM_SOS; + case 0x02: + return Position.ALARM_OVERSPEED; + case 0x04: + return Position.ALARM_GEOFENCE_EXIT; + case 0x05: + return Position.ALARM_GEOFENCE_ENTER; + case 0x40: + return Position.ALARM_SHOCK; + case 0x42: + return Position.ALARM_ACCELERATION; + case 0x43: + return Position.ALARM_BRAKING; + default: + return null; + } + } + + private boolean decode12(Position position, Parser parser, Pattern pattern) { + + if (parser.hasNext()) { + position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16))); + } + DateBuilder dateBuilder = new DateBuilder(); + int year = 0, month = 0, day = 0; + if (pattern == PATTERN2) { + day = parser.nextInt(0); + month = parser.nextInt(0); + year = parser.nextInt(0); + } + dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + if (pattern == PATTERN1) { + day = parser.nextInt(0); + month = parser.nextInt(0); + year = parser.nextInt(0); + } + if (year == 0) { + return false; // ignore invalid data + } + dateBuilder.setDate(year, month, day); + position.setTime(dateBuilder.getDate()); + + if (pattern == PATTERN1) { + position.set(Position.KEY_PDOP, parser.nextDouble()); + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_VDOP, parser.nextDouble()); + } else { + position.set(Position.KEY_HDOP, parser.nextDouble()); + } + + int io = parser.nextBinInt(); + position.set(Position.KEY_STATUS, io); + if (pattern == PATTERN1) { + position.set(Position.KEY_ALARM, BitUtil.check(io, 0) ? Position.ALARM_SOS : null); + position.set(Position.PREFIX_IN + 3, BitUtil.check(io, 4)); + position.set(Position.PREFIX_IN + 4, BitUtil.check(io, 5)); + position.set(Position.PREFIX_IN + 1, BitUtil.check(io, 6)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(io, 7)); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(io, 8)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(io, 9)); + position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.01); + } else { + position.set(Position.KEY_ANTENNA, BitUtil.check(io, 0)); + position.set(Position.KEY_CHARGE, BitUtil.check(io, 1)); + for (int i = 1; i <= 6; i++) { + position.set(Position.PREFIX_IN + i, BitUtil.check(io, 1 + i)); + } + for (int i = 1; i <= 4; i++) { + position.set(Position.PREFIX_OUT + i, BitUtil.check(io, 7 + i)); + } + position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1); + } + + position.set(Position.KEY_POWER, parser.nextDouble(0)); + position.set(Position.PREFIX_ADC + 1, parser.next()); + + int lac = parser.nextHexInt(0); + int cid = parser.nextHexInt(0); + if (lac != 0 && cid != 0) { + position.setNetwork(new Network(CellTower.fromLacCid(lac, cid))); + } + + position.set(Position.PREFIX_TEMP + 1, parser.next()); + position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); + + return true; + } + + private boolean decode3(Position position, Parser parser) { + + if (parser.hasNext()) { + position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16))); + } + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.set(Position.PREFIX_IO + 1, parser.next()); + position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1); + position.set(Position.KEY_POWER, parser.nextDouble(0)); + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + position.set(Position.PREFIX_TEMP + 1, parser.next()); + position.set(Position.PREFIX_TEMP + 2, parser.next()); + + position.setNetwork(new Network( + CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0)))); + + position.setValid(parser.next().equals("A")); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.setCourse(parser.nextDouble(0)); + position.setSpeed(parser.nextDouble(0)); + position.set(Position.KEY_PDOP, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + return true; + } + + private boolean decode4(Position position, Parser parser) { + + long status = parser.nextHexLong(); + + position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 1) ? Position.ALARM_SOS : null); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 32 - 2)); + position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 3) ? Position.ALARM_OVERSPEED : null); + position.set(Position.KEY_CHARGE, BitUtil.check(status, 32 - 4)); + position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 5) ? Position.ALARM_GEOFENCE_EXIT : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 6) ? Position.ALARM_GEOFENCE_ENTER : null); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(status, 32 - 9)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(status, 32 - 10)); + position.set(Position.PREFIX_OUT + 3, BitUtil.check(status, 32 - 11)); + position.set(Position.PREFIX_OUT + 4, BitUtil.check(status, 32 - 12)); + position.set(Position.PREFIX_IN + 2, BitUtil.check(status, 32 - 13)); + position.set(Position.PREFIX_IN + 3, BitUtil.check(status, 32 - 14)); + position.set(Position.PREFIX_IN + 4, BitUtil.check(status, 32 - 15)); + position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 16) ? Position.ALARM_SHOCK : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 18) ? Position.ALARM_LOW_BATTERY : null); + position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 22) ? Position.ALARM_JAMMING : null); + + + position.setTime(parser.nextDateTime()); + + position.set(Position.KEY_BATTERY, parser.nextDouble() * 0.1); + position.set(Position.KEY_POWER, parser.nextDouble()); + + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + position.set(Position.PREFIX_ADC + 3, parser.next()); + position.set(Position.PREFIX_ADC + 4, parser.next()); + position.set(Position.PREFIX_TEMP + 1, parser.next()); + + if (parser.hasNext()) { + position.set(Position.PREFIX_TEMP + 2, parser.next()); + position.setValid(BitUtil.check(status, 32 - 20)); + } else { + position.setValid(BitUtil.check(status, 32 - 18)); + } + + int lac = parser.nextHexInt(); + int cid = parser.nextHexInt(); + CellTower cellTower; + if (parser.hasNext(2)) { + int mnc = parser.nextInt(); + int mcc = parser.nextInt(); + cellTower = CellTower.from(mcc, mnc, lac, cid); + } else { + cellTower = CellTower.fromLacCid(lac, cid); + } + position.set(Position.KEY_SATELLITES, parser.nextInt()); + cellTower.setSignalStrength(parser.nextInt()); + position.setNetwork(new Network(cellTower)); + + position.setCourse(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextInt() * 1000); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + return true; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + Pattern pattern = PATTERN3; + if (sentence.charAt(2) == '0') { + pattern = PATTERN4; + } else if (sentence.contains("$GPRMC")) { + pattern = PATTERN1; + } else { + int index = sentence.indexOf('|'); + if (index != -1 && sentence.indexOf('|', index + 1) != -1) { + pattern = PATTERN2; + } + } + + Parser parser = new Parser(pattern, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + if (pattern == PATTERN4) { + position.set(Position.KEY_ALARM, decodeAlarm4(parser.nextHexInt())); + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + boolean result; + if (pattern == PATTERN1 || pattern == PATTERN2) { + result = decode12(position, parser, pattern); + } else if (pattern == PATTERN3) { + result = decode3(position, parser); + } else { + result = decode4(position, parser); + } + + if (channel != null) { + if (pattern == PATTERN4) { + String response = "$$0014AA" + sentence.substring(sentence.length() - 6, sentence.length() - 2); + response += String.format("%02X", Checksum.xor(response)).toUpperCase(); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } else { + channel.writeAndFlush(new NetworkMessage("ACK OK\r\n", remoteAddress)); + } + } + + return result ? position : null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java new file mode 100644 index 000000000..b5049859d --- /dev/null +++ b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Irving Gonzalez + * Copyright 2015 - 2016 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class TotemProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + initDevicePassword(command, "000000"); + + switch (command.getType()) { + // Assuming PIN 8 (Output C) is the power wire, like manual says but it can be PIN 5,7,8 + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, "*{%s},025,C,1#", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, "*{%s},025,C,0#", Command.KEY_DEVICE_PASSWORD); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Tr20Protocol.java b/src/main/java/org/traccar/protocol/Tr20Protocol.java new file mode 100644 index 000000000..3eee9d9c3 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tr20Protocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Tr20Protocol extends BaseProtocol { + + public Tr20Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Tr20ProtocolDecoder(Tr20Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java new file mode 100644 index 000000000..c2e6c381f --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java @@ -0,0 +1,103 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Tr20ProtocolDecoder extends BaseProtocolDecoder { + + public Tr20ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_PING = new PatternBuilder() + .text("%%") + .expression("[^,]+,") + .number("(d+)") + .compile(); + + private static final Pattern PATTERN_DATA = new PatternBuilder() + .text("%%") + .expression("([^,]+),") // id + .expression("([AL]),") // validity + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([NS])") + .number("(dd)(dd.d+)") // latitude + .expression("([EW])") + .number("(ddd)(dd.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(?:NA|[FC]?(-?d+)),") // temperature + .number("(x{8}),") // status + .number("(d+)") // event + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN_PING, (String) msg); + if (parser.matches()) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + "&&" + parser.next() + "\r\n", remoteAddress)); // keep-alive response + } + return null; + } + + parser = new Parser(PATTERN_DATA, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.next().equals("A")); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + + position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); + position.set(Position.KEY_STATUS, parser.nextHexLong()); + position.set(Position.KEY_EVENT, parser.nextInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Tr900Protocol.java b/src/main/java/org/traccar/protocol/Tr900Protocol.java new file mode 100644 index 000000000..b70521b35 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tr900Protocol.java @@ -0,0 +1,47 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Tr900Protocol extends BaseProtocol { + + public Tr900Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Tr900ProtocolDecoder(Tr900Protocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Tr900ProtocolDecoder(Tr900Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java new file mode 100644 index 000000000..319194c21 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java @@ -0,0 +1,94 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Tr900ProtocolDecoder extends BaseProtocolDecoder { + + public Tr900ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number(">(d+),") // id + .number("d+,") // period + .number("(d),") // fix + .number("(dd)(dd)(dd),") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([EW])") + .number("(ddd)(dd.d+),") // longitude + .expression("([NS])") + .number("(dd)(dd.d+),") // latitude + .expression("[^,]*,") // command + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(d+),") // gsm + .number("(d+),") // event + .number("(d+)-") // adc + .number("(d+),") // battery + .number("d+,") // impulses + .number("(d+),") // input + .number("(d+)") // status + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.nextInt(0) == 1); + + position.setTime(parser.nextDateTime()); + + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_RSSI, parser.nextDouble()); + position.set(Position.KEY_EVENT, parser.nextInt(0)); + position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); + position.set(Position.KEY_BATTERY, parser.nextInt(0)); + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_STATUS, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/TrackboxProtocol.java b/src/main/java/org/traccar/protocol/TrackboxProtocol.java new file mode 100644 index 000000000..5da5abd64 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TrackboxProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TrackboxProtocol extends BaseProtocol { + + public TrackboxProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new TrackboxProtocolDecoder(TrackboxProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java new file mode 100644 index 000000000..db8022738 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java @@ -0,0 +1,110 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class TrackboxProtocolDecoder extends BaseProtocolDecoder { + + public TrackboxProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) + .number("(dd)(dd.dddd)([NS]),") // latitude + .number("(ddd)(dd.dddd)([EW]),") // longitude + .number("(d+.d),") // hdop + .number("(-?d+.?d*),") // altitude + .number("(d),") // fix type + .number("(d+.d+),") // course + .number("d+.d+,") // speed (kph) + .number("(d+.d+),") // speed (knots) + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(d+)") // satellites + .compile(); + + private void sendResponse(Channel channel, SocketAddress remoteAddress) { + if (channel != null) { + channel.writeAndFlush(new NetworkMessage("=OK=\r\n", remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("a=connect")) { + String id = sentence.substring(sentence.indexOf("i=") + 2); + if (getDeviceSession(channel, remoteAddress, id) != null) { + sendResponse(channel, remoteAddress); + } + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + sendResponse(channel, remoteAddress); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + position.set(Position.KEY_HDOP, parser.nextDouble()); + + position.setAltitude(parser.nextDouble(0)); + + int fix = parser.nextInt(0); + position.set(Position.KEY_GPS, fix); + position.setValid(fix > 0); + + position.setCourse(parser.nextDouble(0)); + position.setSpeed(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/TrakMateProtocol.java b/src/main/java/org/traccar/protocol/TrakMateProtocol.java new file mode 100644 index 000000000..bda5df10f --- /dev/null +++ b/src/main/java/org/traccar/protocol/TrakMateProtocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TrakMateProtocol extends BaseProtocol { + + public TrakMateProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new TrakMateProtocolDecoder(TrakMateProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java new file mode 100644 index 000000000..4d5cb18f5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java @@ -0,0 +1,233 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class TrakMateProtocolDecoder extends BaseProtocolDecoder { + + public TrakMateProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_SRT = new PatternBuilder() + .text("^TMSRT|") + .expression("([^ ]+)|") // uid + .number("(d+.d+)|") // latitude + .number("(d+.d+)|") // longitude + .number("(dd)(dd)(dd)|") // time (hhmmss) + .number("(dd)(dd)(dd)|") // date (ddmmyy) + .number("(d+.d+)|") // software ver + .number("(d+.d+)|") // Hardware ver + .any() + .compile(); + + private static final Pattern PATTERN_PER = new PatternBuilder() + .text("^TM") + .expression("...|") // type + .expression("([^ ]+)|") // uid + .number("(d+)|") // seq + .number("(d+.d+)|") // latitude + .number("(d+.d+)|") // longitude + .number("(dd)(dd)(dd)|") // time (hhmmss) + .number("(dd)(dd)(dd)|") // date (ddmmyy) + .number("(d+.d+)|") // speed + .number("(d+.d+)|") // heading + .number("(d+)|").optional() // satellites + .number("([01])|") // ignition + .groupBegin() + .number("(d+)|") // dop1 + .number("(d+)|") // dop2 + .number("(d+.d+)|") // analog + .number("(d+.d+)|") // internal battery + .or() + .number("-?d+ -?d+ -?d+|") // accelerometer + .number("([01])|") // movement + .groupEnd() + .number("(d+.d+)|") // vehicle battery + .number("(d+.d+)|") // gps odometer + .number("(d+.d+)|").optional() // pulse odometer + .number("([01])|") // main power status + .number("([01])|") // gps data validity + .number("([01])|") // live or cache + .any() + .compile(); + + private static final Pattern PATTERN_ALT = new PatternBuilder() + .text("^TMALT|") + .expression("([^ ]+)|") // uid + .number("(d+)|") // seq + .number("(d+)|") // Alert type + .number("(d+)|") // Alert status + .number("(d+.d+)|") // latitude + .number("(d+.d+)|") // longitude + .number("(dd)(dd)(dd)|") // time (hhmmss) + .number("(dd)(dd)(dd)|") // date (ddmmyy) + .number("(d+.d+)|") // speed + .number("(d+.d+)|") // heading + .any() + .compile(); + + private String decodeAlarm(int value) { + switch (value) { + case 1: + return Position.ALARM_SOS; + case 3: + return Position.ALARM_GEOFENCE; + case 4: + return Position.ALARM_POWER_CUT; + default: + return null; + } + } + + private Object decodeSrt(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_SRT, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + position.set(Position.KEY_VERSION_FW, parser.next()); + position.set(Position.KEY_VERSION_HW, parser.next()); + + return position; + } + + private Object decodeAlt(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN_ALT, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + parser.next(); // seq + position.set(Position.KEY_ALARM, decodeAlarm(parser.nextInt())); + parser.next(); // alert status or data + + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + return position; + } + + private Object decodePer(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN_PER, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + parser.next(); // seq + + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_IGNITION, parser.nextInt() > 0); + + if (parser.hasNext(4)) { + position.set("dop1", parser.nextInt()); + position.set("dop2", parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + } + + if (parser.hasNext()) { + position.set(Position.KEY_MOTION, parser.nextInt(0) > 0); + } + + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextDouble()); + position.set("pulseOdometer", parser.nextDouble()); + position.set(Position.KEY_STATUS, parser.nextInt()); + + position.setValid(parser.nextInt() > 0); + + position.set(Position.KEY_ARCHIVE, parser.nextInt() > 0); + + return position; + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + int typeIndex = sentence.indexOf("^TM"); + if (typeIndex < 0) { + return null; + } + + String type = sentence.substring(typeIndex + 3, typeIndex + 6); + switch (type) { + case "ALT": + return decodeAlt(channel, remoteAddress, sentence); + case "SRT": + return decodeSrt(channel, remoteAddress, sentence); + default: + return decodePer(channel, remoteAddress, sentence); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java new file mode 100644 index 000000000..aaaaccb60 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java @@ -0,0 +1,46 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class TramigoFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode(ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 20) { + return null; + } + + int length; + if (buf.getUnsignedByte(buf.readerIndex()) == 0x80) { + length = buf.getUnsignedShortLE(buf.readerIndex() + 6); + } else { + length = buf.getUnsignedShort(buf.readerIndex() + 6); + } + + if (length >= buf.readableBytes()) { + return buf.readRetainedSlice(length); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TramigoProtocol.java b/src/main/java/org/traccar/protocol/TramigoProtocol.java new file mode 100644 index 000000000..f683ccc5d --- /dev/null +++ b/src/main/java/org/traccar/protocol/TramigoProtocol.java @@ -0,0 +1,34 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TramigoProtocol extends BaseProtocol { + + public TramigoProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TramigoFrameDecoder()); + pipeline.addLast(new TramigoProtocolDecoder(TramigoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java new file mode 100644 index 000000000..e42e2f670 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java @@ -0,0 +1,160 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TramigoProtocolDecoder extends BaseProtocolDecoder { + + public TramigoProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_COMPACT = 0x0100; + public static final int MSG_FULL = 0x00FE; + + private static final String[] DIRECTIONS = new String[] {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}; + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + int protocol = buf.readUnsignedByte(); + boolean legacy = protocol == 0x80; + + buf.readUnsignedByte(); // version id + int index = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE(); + int type = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE(); + buf.readUnsignedShort(); // length + buf.readUnsignedShort(); // mask + buf.readUnsignedShort(); // checksum + long id = legacy ? buf.readUnsignedInt() : buf.readUnsignedIntLE(); + buf.readUnsignedInt(); // time + + Position position = new Position(getProtocolName()); + position.set(Position.KEY_INDEX, index); + position.setValid(true); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + if (protocol == 0x01 && (type == MSG_COMPACT || type == MSG_FULL)) { + + // need to send ack? + + buf.readUnsignedShortLE(); // report trigger + buf.readUnsignedShortLE(); // state flag + + position.setLatitude(buf.readUnsignedIntLE() * 0.0000001); + position.setLongitude(buf.readUnsignedIntLE() * 0.0000001); + + position.set(Position.KEY_RSSI, buf.readUnsignedShortLE()); + position.set(Position.KEY_SATELLITES, buf.readUnsignedShortLE()); + position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedShortLE()); + position.set("gpsAntennaStatus", buf.readUnsignedShortLE()); + + position.setSpeed(buf.readUnsignedShortLE() * 0.194384); + position.setCourse(buf.readUnsignedShortLE()); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); + + position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE()); + + position.set(Position.KEY_CHARGE, buf.readUnsignedShortLE()); + + position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); + + // parse other data + + return position; + + } else if (legacy) { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage( + Unpooled.copiedBuffer("gprs,ack," + index, StandardCharsets.US_ASCII), remoteAddress)); + } + + String sentence = buf.toString(StandardCharsets.US_ASCII); + + Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)"); + Matcher matcher = pattern.matcher(sentence); + if (!matcher.find()) { + return null; + } + position.setLatitude(Double.parseDouble(matcher.group(1))); + position.setLongitude(Double.parseDouble(matcher.group(2))); + + pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h"); + matcher = pattern.matcher(sentence); + if (matcher.find()) { + for (int i = 0; i < DIRECTIONS.length; i++) { + if (matcher.group(1).equals(DIRECTIONS[i])) { + position.setCourse(i * 45.0); + break; + } + } + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(matcher.group(2)))); + } + + pattern = Pattern.compile("(\\d{1,2}:\\d{2}(:\\d{2})? \\w{3} \\d{1,2})"); + matcher = pattern.matcher(sentence); + if (!matcher.find()) { + return null; + } + DateFormat dateFormat = new SimpleDateFormat( + matcher.group(2) != null ? "HH:mm:ss MMM d yyyy" : "HH:mm MMM d yyyy", Locale.ENGLISH); + position.setTime(DateUtil.correctYear( + dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR)))); + + if (sentence.contains("Ignition on detected")) { + position.set(Position.KEY_IGNITION, true); + } else if (sentence.contains("Ignition off detected")) { + position.set(Position.KEY_IGNITION, false); + } + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/TrvProtocol.java b/src/main/java/org/traccar/protocol/TrvProtocol.java new file mode 100644 index 000000000..99a164cf1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TrvProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TrvProtocol extends BaseProtocol { + + public TrvProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new TrvProtocolDecoder(TrvProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java new file mode 100644 index 000000000..b63385187 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java @@ -0,0 +1,258 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.regex.Pattern; + +public class TrvProtocolDecoder extends BaseProtocolDecoder { + + public TrvProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("[A-Z]{2,3}") + .number("APdd") + .number("(dd)(dd)(dd)") // date (yymmdd) + .expression("([AV])") // validity + .number("(dd)(dd.d+)") // latitude + .expression("([NS])") + .number("(ddd)(dd.d+)") // longitude + .expression("([EW])") + .number("(ddd.d)") // speed + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("([d.]{6})") // course + .number("(ddd)") // gsm + .number("(ddd)") // satellites + .number("(ddd)") // battery + .number("(d)") // acc + .number("(dd)") // arm status + .number("(dd),") // working mode + .number("(d+),") // mcc + .number("(d+),") // mnc + .number("(d+),") // lac + .number("(d+)") // cell + .any() + .compile(); + + private static final Pattern PATTERN_HEATRBEAT = new PatternBuilder() + .expression("[A-Z]{2,3}") + .text("CP01,") + .number("(ddd)") // gsm + .number("(ddd)") // gps + .number("(ddd)") // battery + .number("(d)") // acc + .number("(dd)") // arm status + .number("(dd)") // working mode + .groupBegin() + .number("(ddd)") // interval + .number("d") // vibration alarm + .number("ddd") // vibration sensitivity + .number("d") // automatic arm + .number("dddd") // automatic arm time + .number("(d)") // blocked + .number("(d)") // power status + .number("(d)") // movement status + .groupEnd("?") + .any() + .compile(); + + private static final Pattern PATTERN_LBS = new PatternBuilder() + .expression("[A-Z]{2,3}") + .text("AP02,") + .expression("[^,]+,") // language + .number("[01],") // reply + .number("d+,") // cell count + .number("(d+),") // mcc + .number("(d+),") // mnc + .expression("(") + .groupBegin() + .number("d+|") // lac + .number("d+|") // cid + .number("d+,") // rssi + .groupEnd("+") + .expression(")") + .number("d+,") // wifi count + .expression("(.*)") // wifi + .compile(); + + private Boolean decodeOptionalValue(Parser parser, int activeValue) { + int value = parser.nextInt(); + if (value != 0) { + return value == activeValue; + } + return null; + } + + private void decodeCommon(Position position, Parser parser) { + + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_BATTERY, parser.nextInt()); + position.set(Position.KEY_IGNITION, decodeOptionalValue(parser, 1)); + position.set(Position.KEY_ARMED, decodeOptionalValue(parser, 1)); + + int mode = parser.nextInt(); + if (mode != 0) { + position.set("mode", mode); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + String id = sentence.startsWith("TRV") ? sentence.substring(0, 3) : sentence.substring(0, 2); + String type = sentence.substring(id.length(), id.length() + 4); + + if (channel != null) { + String responseHeader = id + (char) (type.charAt(0) + 1) + type.substring(1); + if (type.equals("AP00") && id.equals("IW")) { + String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); + channel.writeAndFlush(new NetworkMessage(responseHeader + "," + time + ",0#", remoteAddress)); + } else if (type.equals("AP14")) { + channel.writeAndFlush(new NetworkMessage(responseHeader + ",0.000,0.000#", remoteAddress)); + } else { + channel.writeAndFlush(new NetworkMessage(responseHeader + "#", remoteAddress)); + } + } + + if (type.equals("AP00")) { + getDeviceSession(channel, remoteAddress, sentence.substring(id.length() + type.length())); + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + if (type.equals("CP01")) { + + Parser parser = new Parser(PATTERN_HEATRBEAT, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + decodeCommon(position, parser); + + if (parser.hasNext(3)) { + position.set(Position.KEY_BLOCKED, decodeOptionalValue(parser, 2)); + position.set(Position.KEY_CHARGE, decodeOptionalValue(parser, 1)); + position.set(Position.KEY_MOTION, decodeOptionalValue(parser, 1)); + } + + return position; + + } else if (type.equals("AP01") || type.equals("AP10")) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + + dateBuilder.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.setCourse(parser.nextDouble()); + + decodeCommon(position, parser); + + position.setNetwork(new Network(CellTower.from( + parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt()))); + + return position; + + } else if (type.equals("AP02")) { + + Parser parser = new Parser(PATTERN_LBS, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + int mcc = parser.nextInt(); + int mnc = parser.nextInt(); + + Network network = new Network(); + + for (String cell : parser.next().split(",")) { + if (!cell.isEmpty()) { + String[] values = cell.split("\\|"); + network.addCellTower(CellTower.from( + mcc, mnc, + Integer.parseInt(values[0]), + Integer.parseInt(values[1]), + Integer.parseInt(values[2]))); + } + } + + for (String wifi : parser.next().split("&")) { + if (!wifi.isEmpty()) { + String[] values = wifi.split("\\|"); + network.addWifiAccessPoint(WifiAccessPoint.from(values[1], Integer.parseInt(values[2]))); + } + } + + position.setNetwork(network); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Tt8850Protocol.java b/src/main/java/org/traccar/protocol/Tt8850Protocol.java new file mode 100644 index 000000000..66a13da9e --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tt8850Protocol.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Tt8850Protocol extends BaseProtocol { + + public Tt8850Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "$")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Tt8850ProtocolDecoder(Tt8850Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java new file mode 100644 index 000000000..1010528c4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java @@ -0,0 +1,99 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Tt8850ProtocolDecoder extends BaseProtocolDecoder { + + public Tt8850ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .binary("0004,") + .number("xxxx,") + .expression("[01],") + .expression("GT...,") + .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version + .expression("([^,]+),") // imei + .any() + .number("(d{1,2})?,") // gps accuracy + .number("(d{1,3}.d)?,") // speed + .number("(d{1,3})?,") // course + .number("(-?d{1,5}.d)?,") // altitude + .number("(-?d{1,3}.d{6}),") // longitude + .number("(-?d{1,2}.d{6}),") // latitude + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(0ddd)?,") // mcc + .number("(0ddd)?,") // mnc + .number("(xxxx)?,") // lac + .number("(xxxx)?,") // cell + .any() + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(xxxx)") + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(true); + position.setAccuracy(parser.nextInt(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setLatitude(parser.nextDouble(0)); + + position.setTime(parser.nextDateTime()); + + if (parser.hasNext(4)) { + position.setNetwork(new Network( + CellTower.from(parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/TytanProtocol.java b/src/main/java/org/traccar/protocol/TytanProtocol.java new file mode 100644 index 000000000..32e9acae1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TytanProtocol.java @@ -0,0 +1,33 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class TytanProtocol extends BaseProtocol { + + public TytanProtocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new TytanProtocolDecoder(TytanProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TytanProtocolDecoder.java b/src/main/java/org/traccar/protocol/TytanProtocolDecoder.java new file mode 100644 index 000000000..93d3a63d2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TytanProtocolDecoder.java @@ -0,0 +1,192 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +public class TytanProtocolDecoder extends BaseProtocolDecoder { + + public TytanProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private void decodeExtraData(Position position, ByteBuf buf, int end) { + while (buf.readerIndex() < end) { + + int type = buf.readUnsignedByte(); + int length = buf.readUnsignedByte(); + if (length == 255) { + length += buf.readUnsignedByte(); + } + + int n; + + switch (type) { + case 2: + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedMedium()); + break; + case 5: + position.set(Position.KEY_INPUT, buf.readUnsignedByte()); + break; + case 6: + n = buf.readUnsignedByte() >> 4; + if (n < 2) { + position.set(Position.PREFIX_ADC + n, buf.readFloat()); + } else { + position.set("di" + (n - 2), buf.readFloat()); + } + break; + case 7: + int alarm = buf.readUnsignedByte(); + buf.readUnsignedByte(); + if (BitUtil.check(alarm, 5)) { + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + } + break; + case 8: + position.set("antihijack", buf.readUnsignedByte()); + break; + case 9: + position.set("unauthorized", ByteBufUtil.hexDump(buf.readSlice(8))); + break; + case 10: + position.set("authorized", ByteBufUtil.hexDump(buf.readSlice(8))); + break; + case 24: + for (int i = 0; i < length / 2; i++) { + position.set(Position.PREFIX_TEMP + buf.readUnsignedByte(), buf.readByte()); + } + break; + case 28: + position.set(Position.KEY_AXLE_WEIGHT, buf.readUnsignedShort()); + buf.readUnsignedByte(); + break; + case 90: + position.set(Position.KEY_POWER, buf.readFloat()); + break; + case 101: + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); + break; + case 102: + position.set(Position.KEY_RPM, buf.readUnsignedByte() * 50); + break; + case 107: + int fuel = buf.readUnsignedShort(); + int fuelFormat = fuel >> 14; + if (fuelFormat == 1) { + position.set("fuelValue", (fuel & 0x3fff) * 0.4 + "%"); + } else if (fuelFormat == 2) { + position.set("fuelValue", (fuel & 0x3fff) * 0.5 + " l"); + } else if (fuelFormat == 3) { + position.set("fuelValue", (fuel & 0x3fff) * -0.5 + " l"); + } + break; + case 108: + position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 5); + break; + case 150: + position.set(Position.KEY_DOOR, buf.readUnsignedByte()); + break; + default: + buf.skipBytes(length); + break; + } + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // protocol + buf.readUnsignedShort(); // length + int index = buf.readUnsignedByte() >> 3; + + if (channel != null) { + ByteBuf response = Unpooled.copiedBuffer("^" + index, StandardCharsets.US_ASCII); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + String id = String.valueOf(buf.readUnsignedInt()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + List positions = new LinkedList<>(); + + while (buf.readableBytes() > 2) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + int end = buf.readerIndex() + buf.readUnsignedByte(); + + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + + int flags = buf.readUnsignedByte(); + position.set(Position.KEY_SATELLITES, BitUtil.from(flags, 2)); + position.setValid(BitUtil.to(flags, 2) > 0); + + // Latitude + double lat = buf.readUnsignedMedium(); + lat = lat * -180 / 16777216 + 90; + position.setLatitude(lat); + + // Longitude + double lon = buf.readUnsignedMedium(); + lon = lon * 360 / 16777216 - 180; + position.setLongitude(lon); + + // Status + flags = buf.readUnsignedByte(); + position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0)); + position.set(Position.KEY_RSSI, BitUtil.between(flags, 2, 5)); + position.setCourse((BitUtil.from(flags, 5) * 45 + 180) % 360); + + // Speed + int speed = buf.readUnsignedByte(); + if (speed < 250) { + position.setSpeed(UnitsConverter.knotsFromKph(speed)); + } + + decodeExtraData(position, buf, end); + + positions.add(position); + } + + return positions; + } + +} diff --git a/src/main/java/org/traccar/protocol/TzoneProtocol.java b/src/main/java/org/traccar/protocol/TzoneProtocol.java new file mode 100644 index 000000000..6e855d138 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TzoneProtocol.java @@ -0,0 +1,36 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; + +public class TzoneProtocol extends BaseProtocol { + + public TzoneProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 2, 2, 0)); + pipeline.addLast(new TzoneProtocolDecoder(TzoneProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java new file mode 100644 index 000000000..87b44a4b2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java @@ -0,0 +1,293 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; + +public class TzoneProtocolDecoder extends BaseProtocolDecoder { + + public TzoneProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private String decodeAlarm(Short value) { + switch (value) { + case 0x01: + return Position.ALARM_SOS; + case 0x10: + return Position.ALARM_LOW_BATTERY; + case 0x11: + return Position.ALARM_OVERSPEED; + case 0x14: + return Position.ALARM_BRAKING; + case 0x15: + return Position.ALARM_ACCELERATION; + case 0x30: + return Position.ALARM_PARKING; + case 0x42: + return Position.ALARM_GEOFENCE_EXIT; + case 0x43: + return Position.ALARM_GEOFENCE_ENTER; + default: + return null; + } + } + + private boolean decodeGps(Position position, ByteBuf buf, int hardware) { + + int blockLength = buf.readUnsignedShort(); + int blockEnd = buf.readerIndex() + blockLength; + + if (blockLength < 22) { + return false; + } + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + + double lat; + double lon; + + if (hardware == 0x10A || hardware == 0x10B) { + lat = buf.readUnsignedInt() / 600000.0; + lon = buf.readUnsignedInt() / 600000.0; + } else { + lat = buf.readUnsignedInt() / 100000.0 / 60.0; + lon = buf.readUnsignedInt() / 100000.0 / 60.0; + } + + position.setFixTime(new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); + + position.setSpeed(buf.readUnsignedShort() * 0.01); + + position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); + + int flags = buf.readUnsignedShort(); + position.setCourse(BitUtil.to(flags, 9)); + if (!BitUtil.check(flags, 10)) { + lat = -lat; + } + position.setLatitude(lat); + if (BitUtil.check(flags, 9)) { + lon = -lon; + } + position.setLongitude(lon); + position.setValid(BitUtil.check(flags, 11)); + + buf.readerIndex(blockEnd); + + return true; + } + + private void decodeCards(Position position, ByteBuf buf) { + + int index = 1; + for (int i = 0; i < 4; i++) { + + int blockLength = buf.readUnsignedShort(); + int blockEnd = buf.readerIndex() + blockLength; + + if (blockLength > 0) { + + int count = buf.readUnsignedByte(); + for (int j = 0; j < count; j++) { + + int length = buf.readUnsignedByte(); + + boolean odd = length % 2 != 0; + if (odd) { + length += 1; + } + + String num = ByteBufUtil.hexDump(buf.readSlice(length / 2)); + + if (odd) { + num = num.substring(1); + } + + position.set("card" + index, num); + } + } + + buf.readerIndex(blockEnd); + } + + } + + private void decodePassengers(Position position, ByteBuf buf) { + + int blockLength = buf.readUnsignedShort(); + int blockEnd = buf.readerIndex() + blockLength; + + if (blockLength > 0) { + + position.set("passengersOn", buf.readUnsignedMedium()); + position.set("passengersOff", buf.readUnsignedMedium()); + + } + + buf.readerIndex(blockEnd); + + } + + private void decodeTags(Position position, ByteBuf buf) { + + int blockLength = buf.readUnsignedShort(); + int blockEnd = buf.readerIndex() + blockLength; + + if (blockLength > 0) { + + buf.readUnsignedByte(); // tag type + + int count = buf.readUnsignedByte(); + int tagLength = buf.readUnsignedByte(); + + for (int i = 1; i <= count; i++) { + int tagEnd = buf.readerIndex() + tagLength; + + buf.readUnsignedByte(); // status + buf.readUnsignedShortLE(); // battery voltage + + position.set(Position.PREFIX_TEMP + i, (buf.readShortLE() & 0x3fff) * 0.1); + + buf.readUnsignedByte(); // humidity + buf.readUnsignedByte(); // rssi + + buf.readerIndex(tagEnd); + } + + } + + buf.readerIndex(blockEnd); + + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(2); // header + buf.readUnsignedShort(); // length + if (buf.readUnsignedShort() != 0x2424) { + return null; + } + int hardware = buf.readUnsignedShort(); + long firmware = buf.readUnsignedInt(); + + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_VERSION_HW, hardware); + position.set(Position.KEY_VERSION_FW, firmware); + + position.setDeviceTime(new DateBuilder() + .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) + .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); + + // GPS info + + if (hardware == 0x406 || !decodeGps(position, buf, hardware)) { + + getLastLocation(position, position.getDeviceTime()); + + } + + // LBS info + + int blockLength = buf.readUnsignedShort(); + int blockEnd = buf.readerIndex() + blockLength; + + if (blockLength > 0 && (hardware == 0x10A || hardware == 0x10B || hardware == 0x406)) { + position.setNetwork(new Network( + CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort()))); + } + + buf.readerIndex(blockEnd); + + // Status info + + blockLength = buf.readUnsignedShort(); + blockEnd = buf.readerIndex() + blockLength; + + if (blockLength >= 13) { + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + position.set("terminalInfo", buf.readUnsignedByte()); + + int status = buf.readUnsignedByte(); + position.set(Position.PREFIX_OUT + 1, BitUtil.check(status, 0)); + position.set(Position.PREFIX_OUT + 2, BitUtil.check(status, 1)); + status = buf.readUnsignedByte(); + position.set(Position.PREFIX_IN + 1, BitUtil.check(status, 4)); + if (BitUtil.check(status, 0)) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set("gsmStatus", buf.readUnsignedByte()); + position.set(Position.KEY_BATTERY, buf.readUnsignedShort()); + position.set(Position.KEY_POWER, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); + position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); + } + + if (blockLength >= 15) { + position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort()); + } + + buf.readerIndex(blockEnd); + + if (hardware == 0x10B) { + + decodeCards(position, buf); + + buf.skipBytes(buf.readUnsignedShort()); // temperature + buf.skipBytes(buf.readUnsignedShort()); // lock + + decodePassengers(position, buf); + + } + + if (hardware == 0x406) { + + decodeTags(position, buf); + + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/UlbotechFrameDecoder.java b/src/main/java/org/traccar/protocol/UlbotechFrameDecoder.java new file mode 100644 index 000000000..f141dc9b7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/UlbotechFrameDecoder.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 - 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. + * 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 org.traccar.BaseFrameDecoder; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +public class UlbotechFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 2) { + return null; + } + + if (buf.getUnsignedByte(buf.readerIndex()) == 0xF8) { + + int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0xF8); + if (index != -1) { + ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex()); + + while (buf.readerIndex() <= index) { + int b = buf.readUnsignedByte(); + if (b == 0xF7) { + int ext = buf.readUnsignedByte(); + if (ext == 0x00) { + result.writeByte(0xF7); + } else if (ext == 0x0F) { + result.writeByte(0xF8); + } + } else { + result.writeByte(b); + } + } + + return result; + } + + } else { + + int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '#'); + if (index != -1) { + return buf.readRetainedSlice(index + 1 - buf.readerIndex()); + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/UlbotechProtocol.java b/src/main/java/org/traccar/protocol/UlbotechProtocol.java new file mode 100644 index 000000000..b99ec1cc6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/UlbotechProtocol.java @@ -0,0 +1,34 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class UlbotechProtocol extends BaseProtocol { + + public UlbotechProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new UlbotechFrameDecoder()); + pipeline.addLast(new UlbotechProtocolDecoder(UlbotechProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java new file mode 100644 index 000000000..0a2a59e23 --- /dev/null +++ b/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java @@ -0,0 +1,371 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +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.DateBuilder; +import org.traccar.helper.ObdDecoder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.regex.Pattern; + +public class UlbotechProtocolDecoder extends BaseProtocolDecoder { + + public UlbotechProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final short DATA_GPS = 0x01; + private static final short DATA_LBS = 0x02; + private static final short DATA_STATUS = 0x03; + private static final short DATA_ODOMETER = 0x04; + private static final short DATA_ADC = 0x05; + private static final short DATA_GEOFENCE = 0x06; + private static final short DATA_OBD2 = 0x07; + private static final short DATA_FUEL = 0x08; + private static final short DATA_OBD2_ALARM = 0x09; + private static final short DATA_HARSH_DRIVER = 0x0A; + private static final short DATA_CANBUS = 0x0B; + private static final short DATA_J1708 = 0x0C; + private static final short DATA_VIN = 0x0D; + private static final short DATA_RFID = 0x0E; + private static final short DATA_EVENT = 0x10; + + private void decodeObd(Position position, ByteBuf buf, int length) { + + int end = buf.readerIndex() + length; + + while (buf.readerIndex() < end) { + int parameterLength = buf.getUnsignedByte(buf.readerIndex()) >> 4; + int mode = buf.readUnsignedByte() & 0x0F; + position.add(ObdDecoder.decode(mode, ByteBufUtil.hexDump(buf.readSlice(parameterLength - 1)))); + } + } + + private void decodeJ1708(Position position, ByteBuf buf, int length) { + + int end = buf.readerIndex() + length; + + while (buf.readerIndex() < end) { + int mark = buf.readUnsignedByte(); + int len = BitUtil.between(mark, 0, 6); + int type = BitUtil.between(mark, 6, 8); + int id = buf.readUnsignedByte(); + if (type == 3) { + id += 256; + } + String value = ByteBufUtil.hexDump(buf.readSlice(len - 1)); + if (type == 2 || type == 3) { + position.set("pid" + id, value); + } + } + } + + private void decodeDriverBehavior(Position position, ByteBuf buf) { + + int value = buf.readUnsignedByte(); + + if (BitUtil.check(value, 0)) { + position.set("rapidAcceleration", true); + } + if (BitUtil.check(value, 1)) { + position.set("roughBraking", true); + } + if (BitUtil.check(value, 2)) { + position.set("harshCourse", true); + } + if (BitUtil.check(value, 3)) { + position.set("noWarmUp", true); + } + if (BitUtil.check(value, 4)) { + position.set("longIdle", true); + } + if (BitUtil.check(value, 5)) { + position.set("fatigueDriving", true); + } + if (BitUtil.check(value, 6)) { + position.set("roughTerrain", true); + } + if (BitUtil.check(value, 7)) { + position.set("highRpm", true); + } + } + + private String decodeAlarm(int alarm) { + if (BitUtil.check(alarm, 0)) { + return Position.ALARM_POWER_OFF; + } + if (BitUtil.check(alarm, 1)) { + return Position.ALARM_MOVEMENT; + } + if (BitUtil.check(alarm, 2)) { + return Position.ALARM_OVERSPEED; + } + if (BitUtil.check(alarm, 4)) { + return Position.ALARM_GEOFENCE; + } + if (BitUtil.check(alarm, 10)) { + return Position.ALARM_SOS; + } + return null; + } + + private void decodeAdc(Position position, ByteBuf buf, int length) { + for (int i = 0; i < length / 2; i++) { + int value = buf.readUnsignedShort(); + int id = BitUtil.from(value, 12); + value = BitUtil.to(value, 12); + switch (id) { + case 0: + position.set(Position.KEY_POWER, value * (100 + 10) / 4096.0 - 10); + break; + case 1: + position.set(Position.PREFIX_TEMP + 1, value * (125 + 55) / 4096.0 - 55); + break; + case 2: + position.set(Position.KEY_BATTERY, value * (100 + 10) / 4096.0 - 10); + break; + case 3: + position.set(Position.PREFIX_ADC + 1, value * (100 + 10) / 4096.0 - 10); + break; + default: + position.set(Position.PREFIX_IO + id, value); + break; + } + } + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("*TS") + .number("dd,") // protocol version + .number("(d{15}),") // device id + .number("(dd)(dd)(dd)") // time + .number("(dd)(dd)(dd),") // date + .expression("([^#]+)") // command + .text("#") + .compile(); + + private Object decodeText(Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)) + .setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + getLastLocation(position, dateBuilder.getDate()); + + position.set(Position.KEY_RESULT, parser.next()); + + return position; + } + + private Object decodeBinary(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { + + buf.readUnsignedByte(); // header + buf.readUnsignedByte(); // version + buf.readUnsignedByte(); // type + + String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + if (deviceSession.getTimeZone() == null) { + deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId())); + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + long seconds = buf.readUnsignedInt() & 0x7fffffffL; + seconds += 946684800L; // 2000-01-01 00:00 + seconds -= deviceSession.getTimeZone().getRawOffset() / 1000; + Date time = new Date(seconds * 1000); + + boolean hasLocation = false; + + while (buf.readableBytes() > 3) { + + int type = buf.readUnsignedByte(); + int length = type == DATA_CANBUS ? buf.readUnsignedShort() : buf.readUnsignedByte(); + + switch (type) { + + case DATA_GPS: + hasLocation = true; + position.setValid(true); + position.setLatitude(buf.readInt() / 1000000.0); + position.setLongitude(buf.readInt() / 1000000.0); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + position.setCourse(buf.readUnsignedShort()); + position.set(Position.KEY_HDOP, buf.readUnsignedShort()); + break; + + case DATA_LBS: + if (length == 11) { + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedShort(), + buf.readUnsignedShort(), buf.readUnsignedInt(), -buf.readUnsignedByte()))); + } else { + position.setNetwork(new Network(CellTower.from( + buf.readUnsignedShort(), buf.readUnsignedShort(), + buf.readUnsignedShort(), buf.readUnsignedShort(), -buf.readUnsignedByte()))); + } + if (length > 9 && length != 11) { + buf.skipBytes(length - 9); + } + break; + + case DATA_STATUS: + int status = buf.readUnsignedShort(); + position.set(Position.KEY_IGNITION, BitUtil.check(status, 9)); + position.set(Position.KEY_STATUS, status); + position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedShort())); + break; + + case DATA_ODOMETER: + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); + break; + + case DATA_ADC: + decodeAdc(position, buf, length); + break; + + case DATA_GEOFENCE: + position.set("geofenceIn", buf.readUnsignedInt()); + position.set("geofenceAlarm", buf.readUnsignedInt()); + break; + + case DATA_OBD2: + decodeObd(position, buf, length); + break; + + case DATA_FUEL: + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt() / 10000.0); + break; + + case DATA_OBD2_ALARM: + decodeObd(position, buf, length); + break; + + case DATA_HARSH_DRIVER: + decodeDriverBehavior(position, buf); + break; + + case DATA_CANBUS: + position.set("can", ByteBufUtil.hexDump(buf.readSlice(length))); + break; + + case DATA_J1708: + decodeJ1708(position, buf, length); + break; + + case DATA_VIN: + position.set(Position.KEY_VIN, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); + break; + + case DATA_RFID: + position.set(Position.KEY_DRIVER_UNIQUE_ID, + buf.readSlice(length - 1).toString(StandardCharsets.US_ASCII)); + position.set("authorized", buf.readUnsignedByte() != 0); + break; + + case DATA_EVENT: + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + if (length > 1) { + position.set("eventMask", buf.readUnsignedInt()); + } + break; + + default: + buf.skipBytes(length); + break; + } + } + + if (!hasLocation) { + getLastLocation(position, time); + } else { + position.setTime(time); + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (buf.getUnsignedByte(buf.readerIndex()) == 0xF8) { + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte(0xF8); + response.writeByte(DATA_GPS); + response.writeByte(0xFE); + response.writeShort(buf.getShort(response.writerIndex() - 1 - 2)); + response.writeShort(Checksum.crc16(Checksum.CRC16_XMODEM, response.nioBuffer(1, 4))); + response.writeByte(0xF8); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + + return decodeBinary(channel, remoteAddress, buf); + } else { + + if (channel != null) { + channel.writeAndFlush(new NetworkMessage(Unpooled.copiedBuffer(String.format("*TS01,ACK:%04X#", + Checksum.crc16(Checksum.CRC16_XMODEM, buf.nioBuffer(1, buf.writerIndex() - 2))), + StandardCharsets.US_ASCII), remoteAddress)); + } + + return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII)); + } + } + +} diff --git a/src/main/java/org/traccar/protocol/UproProtocol.java b/src/main/java/org/traccar/protocol/UproProtocol.java new file mode 100644 index 000000000..4e60ffeb6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/UproProtocol.java @@ -0,0 +1,37 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class UproProtocol extends BaseProtocol { + + public UproProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new UproProtocolDecoder(UproProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java new file mode 100644 index 000000000..dc7a9200d --- /dev/null +++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java @@ -0,0 +1,212 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class UproProtocolDecoder extends BaseProtocolDecoder { + + public UproProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_HEADER = new PatternBuilder() + .text("*") + .expression("(..20)") // head + .expression("([01])") // ack + .number("(d+),") // device id + .expression("(.)") // type + .expression("(.)") // subtype + .any() + .compile(); + + private static final Pattern PATTERN_LOCATION = new PatternBuilder() + .number("(dd)(dd)(dd)") // time (hhmmss) + .number("(dd)(dd)(dddd)") // latitude + .number("(ddd)(dd)(dddd)") // longitude + .number("(d)") // flags + .number("(dd)") // speed + .number("(dd)") // course + .number("(dd)(dd)(dd)") // date (ddmmyy) + .compile(); + + private void decodeLocation(Position position, String data) { + Parser parser = new Parser(PATTERN_LOCATION, data); + if (parser.matches()) { + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(true); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); + + int flags = parser.nextInt(0); + position.setValid(BitUtil.check(flags, 0)); + if (!BitUtil.check(flags, 1)) { + position.setLatitude(-position.getLatitude()); + } + if (!BitUtil.check(flags, 2)) { + position.setLongitude(-position.getLongitude()); + } + + position.setSpeed(parser.nextInt(0) * 2); + position.setCourse(parser.nextInt(0) * 10); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (buf.getByte(buf.readerIndex()) != '*') { + return null; + } + + int headerIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&'); + if (headerIndex < 0) { + headerIndex = buf.writerIndex(); + } + String header = buf.readSlice(headerIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII); + + Parser parser = new Parser(PATTERN_HEADER, header); + if (!parser.matches()) { + return null; + } + + String head = parser.next(); + boolean reply = parser.next().equals("1"); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + String type = parser.next(); + String subtype = parser.next(); + + if (reply && channel != null) { + channel.writeAndFlush(new NetworkMessage("*" + head + "Y" + type + subtype + "#", remoteAddress)); + } + + while (buf.isReadable()) { + + buf.readByte(); // skip delimiter + + byte dataType = buf.readByte(); + + int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&'); + if (delimiterIndex < 0) { + delimiterIndex = buf.writerIndex(); + } + + ByteBuf data = buf.readSlice(delimiterIndex - buf.readerIndex()); + + switch (dataType) { + case 'A': + decodeLocation(position, data.toString(StandardCharsets.US_ASCII)); + break; + case 'B': + position.set(Position.KEY_STATUS, data.toString(StandardCharsets.US_ASCII)); + break; + case 'C': + long odometer = 0; + while (data.isReadable()) { + odometer <<= 4; + odometer += data.readByte() - (byte) '0'; + } + position.set(Position.KEY_ODOMETER, odometer * 2 * 1852 / 3600); + break; + case 'F': + position.setSpeed( + Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1); + break; + case 'K': + position.set("statusExtended", data.toString(StandardCharsets.US_ASCII)); + break; + case 'P': + if (data.readableBytes() >= 16) { + position.setNetwork(new Network(CellTower.from( + Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)), + Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)), + Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16), + Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16)))); + } + break; + case 'Q': + position.set("obdPid", ByteBufUtil.hexDump(data)); + break; + case 'R': + if (head.startsWith("HQ")) { + position.set(Position.KEY_RSSI, + Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); + position.set(Position.KEY_SATELLITES, + Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); + } else { + position.set("odbTravel", ByteBufUtil.hexDump(data)); + } + break; + case 'S': + position.set("obdTraffic", ByteBufUtil.hexDump(data)); + break; + case 'T': + position.set(Position.KEY_BATTERY_LEVEL, + Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); + break; + case 'V': + position.set(Position.KEY_POWER, + Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1); + break; + default: + break; + } + + } + + if (position.getLatitude() != 0 && position.getLongitude() != 0) { + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/V680Protocol.java b/src/main/java/org/traccar/protocol/V680Protocol.java new file mode 100644 index 000000000..dc0922cd4 --- /dev/null +++ b/src/main/java/org/traccar/protocol/V680Protocol.java @@ -0,0 +1,47 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class V680Protocol extends BaseProtocol { + + public V680Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##")); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new V680ProtocolDecoder(V680Protocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new V680ProtocolDecoder(V680Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java b/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java new file mode 100644 index 000000000..0342404a6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java @@ -0,0 +1,132 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class V680ProtocolDecoder extends BaseProtocolDecoder { + + public V680ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .groupBegin() + .number("#(d+)#") // imei + .expression("([^#]*)#") // user + .groupEnd("?") + .number("(d+)#") // fix + .expression("([^#]+)#") // password + .expression("([^#]+)#") // event + .number("(d+)#") // packet number + .expression("([^#]+)?#?") // gsm base station + .expression("(?:[^#]+#)?") + .number("(d+.d+),([EW]),") // longitude + .number("(d+.d+),([NS]),") // latitude + .number("(d+.d+),") // speed + .number("(d+.?d*)?#") // course + .number("(dd)(dd)(dd)#") // date (ddmmyy) + .number("(dd)(dd)(dd)") // time (hhmmss) + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + sentence = sentence.trim(); + + if (sentence.length() == 16) { + + getDeviceSession(channel, remoteAddress, sentence.substring(1, sentence.length())); + + } else { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession; + if (parser.hasNext()) { + deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + } else { + deviceSession = getDeviceSession(channel, remoteAddress); + } + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.set("user", parser.next()); + position.setValid(parser.nextInt(0) > 0); + position.set("password", parser.next()); + position.set(Position.KEY_EVENT, parser.next()); + position.set("packet", parser.next()); + position.set("lbsData", parser.next()); + + double lon = parser.nextDouble(0); + boolean west = parser.next().equals("W"); + double lat = parser.nextDouble(0); + boolean south = parser.next().equals("S"); + + if (lat > 90 || lon > 180) { + int lonDegrees = (int) (lon * 0.01); + lon = (lon - lonDegrees * 100) / 60.0; + lon += lonDegrees; + + int latDegrees = (int) (lat * 0.01); + lat = (lat - latDegrees * 100) / 60.0; + lat += latDegrees; + } + + position.setLongitude(west ? -lon : lon); + position.setLatitude(south ? -lat : lat); + + position.setSpeed(parser.nextDouble(0)); + position.setCourse(parser.nextDouble(0)); + + int day = parser.nextInt(0); + int month = parser.nextInt(0); + if (day == 0 && month == 0) { + return null; // invalid date + } + + DateBuilder dateBuilder = new DateBuilder() + .setDate(parser.nextInt(0), month, day) + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + return position; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/VisiontekProtocol.java b/src/main/java/org/traccar/protocol/VisiontekProtocol.java new file mode 100644 index 000000000..2c6af45a8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/VisiontekProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class VisiontekProtocol extends BaseProtocol { + + public VisiontekProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new VisiontekProtocolDecoder(VisiontekProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java b/src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java new file mode 100644 index 000000000..c4787bda2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java @@ -0,0 +1,138 @@ +/* + * Copyright 2014 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class VisiontekProtocolDecoder extends BaseProtocolDecoder { + + public VisiontekProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("$1,") + .expression("([^,]+),") // identifier + .number("(d+),").optional() // imei + .number("(dd),(dd),(dd),") // date (dd,mm,yy) + .number("(dd),(dd),(dd),") // time (hh,mm,ss) + .groupBegin() + .number("(dd)(dd).?(d+)([NS]),") // latitude + .number("(ddd)(dd).?(d+)([EW]),") // longitude + .or() + .number("(dd.d+)([NS]),") // latitude + .number("(ddd.d+)([EW]),") // longitude + .groupEnd() + .number("(d+.?d+),") // speed + .number("(d+),") // course + .groupBegin() + .number("(d+),") // altitude + .number("(d+),") // satellites + .number("(d+),") // odometer + .number("([01]),") // ignition + .number("([01]),") // input 1 + .number("([01]),") // input 2 + .number("([01]),") // immobilizer + .number("([01]),") // external battery status + .number("(d+),") // gsm + .or() + .number("(d+.d),") // hdop + .number("(d+),") // altitude + .number("(d+),") // odometer + .number("([01],[01],[01],[01]),") // input + .number("([01],[01],[01],[01]),") // output + .number("(d+.?d*),") // adc 1 + .number("(d+.?d*),") // adc 2 + .groupEnd("?") + .any() + .expression("([AV])") // validity + .number(",(d{10})").optional() // rfid + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next(), parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + if (parser.hasNext(8)) { + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); + } + if (parser.hasNext(4)) { + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + } + + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble( + parser.next().replace(".", "")) / 10)); + + position.setCourse(parser.nextDouble(0)); + + if (parser.hasNext(9)) { + position.setAltitude(parser.nextDouble(0)); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000); + position.set(Position.KEY_IGNITION, parser.next().equals("1")); + position.set(Position.PREFIX_IO + 1, parser.next()); + position.set(Position.PREFIX_IO + 2, parser.next()); + position.set("immobilizer", parser.next()); + position.set(Position.KEY_CHARGE, parser.next().equals("1")); + position.set(Position.KEY_RSSI, parser.nextDouble()); + } + + if (parser.hasNext(7)) { + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.setAltitude(parser.nextDouble(0)); + position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000); + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + } + + position.setValid(parser.next().equals("A")); + + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Vt200FrameDecoder.java b/src/main/java/org/traccar/protocol/Vt200FrameDecoder.java new file mode 100644 index 000000000..0fd83e715 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Vt200FrameDecoder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseFrameDecoder; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +public class Vt200FrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ')') + 1; + if (endIndex > 0) { + + ByteBuf frame = Unpooled.buffer(); + + while (buf.readerIndex() < endIndex) { + int b = buf.readByte(); + if (b == '=') { + frame.writeByte(buf.readByte() ^ '='); + } else { + frame.writeByte(b); + } + } + + return frame; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/Vt200Protocol.java b/src/main/java/org/traccar/protocol/Vt200Protocol.java new file mode 100644 index 000000000..2a9ef6ab5 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Vt200Protocol.java @@ -0,0 +1,34 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Vt200Protocol extends BaseProtocol { + + public Vt200Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Vt200FrameDecoder()); + pipeline.addLast(new Vt200ProtocolDecoder(Vt200Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java new file mode 100644 index 000000000..b1564abd9 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java @@ -0,0 +1,150 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.BcdUtil; +import org.traccar.helper.BitUtil; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Arrays; +import java.util.Date; + +public class Vt200ProtocolDecoder extends BaseProtocolDecoder { + + public Vt200ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static double decodeCoordinate(int value) { + int degrees = value / 1000000; + int minutes = value % 1000000; + return degrees + minutes * 0.0001 / 60; + } + + protected Date decodeDate(ByteBuf buf) { + DateBuilder dateBuilder = new DateBuilder() + .setDateReverse(BcdUtil.readInteger(buf, 2), BcdUtil.readInteger(buf, 2), BcdUtil.readInteger(buf, 2)) + .setTime(BcdUtil.readInteger(buf, 2), BcdUtil.readInteger(buf, 2), BcdUtil.readInteger(buf, 2)); + return dateBuilder.getDate(); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(1); // header + + String id = ByteBufUtil.hexDump(buf.readSlice(6)); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + int type = buf.readUnsignedShort(); + buf.readUnsignedShort(); // length + + if (type == 0x2086 || type == 0x2084 || type == 0x2082) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + buf.readUnsignedByte(); // data type + buf.readUnsignedShort(); // trip id + + position.setTime(decodeDate(buf)); + + position.setLatitude(decodeCoordinate(BcdUtil.readInteger(buf, 8))); + position.setLongitude(decodeCoordinate(BcdUtil.readInteger(buf, 9))); + + int flags = buf.readUnsignedByte(); + position.setValid(BitUtil.check(flags, 0)); + if (!BitUtil.check(flags, 1)) { + position.setLatitude(-position.getLatitude()); + } + if (!BitUtil.check(flags, 2)) { + position.setLongitude(-position.getLongitude()); + } + + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.setCourse(buf.readUnsignedByte() * 2); + + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); + position.set(Position.KEY_STATUS, buf.readUnsignedInt()); + + // additional data + + return position; + + } else if (type == 0x3088) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + buf.readUnsignedShort(); // trip id + buf.skipBytes(8); // imei + buf.skipBytes(8); // imsi + + position.set("tripStart", decodeDate(buf).getTime()); + position.set("tripEnd", decodeDate(buf).getTime()); + position.set("drivingTime", buf.readUnsignedShort()); + + position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt()); + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); + + position.set("maxSpeed", UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + position.set("maxRpm", buf.readUnsignedShort()); + position.set("maxTemp", buf.readUnsignedByte() - 40); + position.set("hardAccelerationCount", buf.readUnsignedByte()); + position.set("hardBrakingCount", buf.readUnsignedByte()); + + for (String speedType : Arrays.asList("over", "high", "normal", "low")) { + position.set(speedType + "SpeedTime", buf.readUnsignedShort()); + position.set(speedType + "SpeedDistance", buf.readUnsignedInt()); + position.set(speedType + "SpeedFuel", buf.readUnsignedInt()); + } + + position.set("idleTime", buf.readUnsignedShort()); + position.set("idleFuel", buf.readUnsignedInt()); + + position.set("hardCorneringCount", buf.readUnsignedByte()); + position.set("overspeedCount", buf.readUnsignedByte()); + position.set("overheatCount", buf.readUnsignedShort()); + position.set("laneChangeCount", buf.readUnsignedByte()); + position.set("emergencyRefueling", buf.readUnsignedByte()); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/VtfmsFrameDecoder.java b/src/main/java/org/traccar/protocol/VtfmsFrameDecoder.java new file mode 100644 index 000000000..62a189960 --- /dev/null +++ b/src/main/java/org/traccar/protocol/VtfmsFrameDecoder.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseFrameDecoder; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +public class VtfmsFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ')'); + if (endIndex > 0) { + endIndex += 1 + 3; + if (buf.writerIndex() >= endIndex) { + return buf.readRetainedSlice(endIndex - buf.readerIndex()); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/VtfmsProtocol.java b/src/main/java/org/traccar/protocol/VtfmsProtocol.java new file mode 100644 index 000000000..2826a86e6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/VtfmsProtocol.java @@ -0,0 +1,44 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import io.netty.handler.codec.string.StringDecoder; + +public class VtfmsProtocol extends BaseProtocol { + + public VtfmsProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new VtfmsFrameDecoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new VtfmsProtocolDecoder(VtfmsProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new VtfmsProtocolDecoder(VtfmsProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java b/src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java new file mode 100644 index 000000000..17fac4311 --- /dev/null +++ b/src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java @@ -0,0 +1,167 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class VtfmsProtocolDecoder extends BaseProtocolDecoder { + + private static final String[] DIRECTIONS = new String[] {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}; + + public VtfmsProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("(") + .number("(d{15}),") // imei + .number("[0-9A-Z]{3}dd,") // packet count + .number("(dd),") // packet id + .number("[^,]*,") // reserved + .number("(d+)?,") // rssi + .number("(?:d+)?,") // fix status + .number("(d+)?,") // satellites + .number("[^,]*,") // reserved + .expression("([AV]),") // validity + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(dd)(dd)(dd),") // time (ddmmyy) + .number("(-?d+.d+),") // latitude + .number("(-?d+.d+),") // longitude + .number("(?:(d+)|([NESW]{1,2})),") // course + .number("(d+),") // speed + .number("(d+),") // hours + .number("(d+),") // idle hours + .expression("[KNT],") // antenna status + .number("(d+),") // odometer + .expression("([01]),") // power status + .number("(d+.d+),") // power voltage + .number("[^,]*,") // reserved + .number("(d+)?,") // fuel level + .number("(d+.d+)?,") // adc 1 + .number("[^,]*,") // reserved + .number("(d+.d+)?,") // adc 2 + .expression("([01]),") // di 1 + .expression("([01]),") // di 2 + .expression("([01]),") // di 3 + .expression("([01]),") // di 4 + .expression("([01]),") // do 1 + .expression("([01]),") // do 2 + .expression("([01]),") // do 3 + .number("[^,]*,") // reserved + .number("[^,]*") // reserved + .text(")") + .number("ddd") // checksum + .compile(); + + private String decodeAlarm(int value) { + switch (value) { + case 10: + return Position.ALARM_OVERSPEED; + case 14: + return Position.ALARM_POWER_CUT; + case 15: + return Position.ALARM_POWER_RESTORED; + case 32: + return Position.ALARM_BRAKING; + case 33: + return Position.ALARM_ACCELERATION; + default: + return null; + } + } + + private double convertToDegrees(double value) { + double degrees = Math.floor(value / 100); + return degrees + (value - degrees * 100) / 60; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.set(Position.KEY_ALARM, decodeAlarm(parser.nextInt())); + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); + + double latitude = parser.nextDouble(); + double longitude = parser.nextDouble(); + if (Math.abs(latitude) > 90 || Math.abs(longitude) > 180) { + position.setLatitude(convertToDegrees(latitude)); + position.setLongitude(convertToDegrees(longitude)); + } else { + position.setLatitude(latitude); + position.setLongitude(longitude); + } + + position.setCourse(parser.nextDouble(0)); + if (parser.hasNext()) { + String direction = parser.next(); + for (int i = 0; i < DIRECTIONS.length; i++) { + if (direction.equals(DIRECTIONS[i])) { + position.setCourse(i * 45.0); + break; + } + } + } + + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(parser.nextInt())); + position.set("idleHours", parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextInt() * 100); + position.set(Position.KEY_CHARGE, parser.next().equals("1")); + position.set(Position.KEY_POWER, parser.nextDouble()); + position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); + position.set(Position.PREFIX_IN + 1, parser.nextInt()); + position.set(Position.PREFIX_IN + 2, parser.nextInt()); + position.set(Position.PREFIX_IN + 3, parser.nextInt()); + position.set(Position.PREFIX_IN + 4, parser.nextInt()); + position.set(Position.PREFIX_OUT + 1, parser.nextInt()); + position.set(Position.PREFIX_OUT + 2, parser.nextInt()); + position.set(Position.PREFIX_OUT + 3, parser.nextInt()); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java new file mode 100644 index 000000000..f99bd52e2 --- /dev/null +++ b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java @@ -0,0 +1,67 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class WatchFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ']') + 1; + if (endIndex > 0) { + ByteBuf frame = Unpooled.buffer(); + while (buf.readerIndex() < endIndex) { + byte b1 = buf.readByte(); + if (b1 == '}') { + byte b2 = buf.readByte(); + switch (b2) { + case 0x01: + frame.writeByte('}'); + break; + case 0x02: + frame.writeByte('['); + break; + case 0x03: + frame.writeByte(']'); + break; + case 0x04: + frame.writeByte(','); + break; + case 0x05: + frame.writeByte('*'); + break; + default: + throw new IllegalArgumentException(String.format( + "unexpected byte at %d: 0x%02x", buf.readerIndex() - 1, b2)); + } + } else { + frame.writeByte(b1); + } + } + return frame; + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/WatchProtocol.java b/src/main/java/org/traccar/protocol/WatchProtocol.java new file mode 100644 index 000000000..fe285e70d --- /dev/null +++ b/src/main/java/org/traccar/protocol/WatchProtocol.java @@ -0,0 +1,53 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +public class WatchProtocol extends BaseProtocol { + + public WatchProtocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_SOS_NUMBER, + Command.TYPE_ALARM_SOS, + Command.TYPE_ALARM_BATTERY, + Command.TYPE_REBOOT_DEVICE, + Command.TYPE_POWER_OFF, + Command.TYPE_ALARM_REMOVE, + Command.TYPE_SILENCE_TIME, + Command.TYPE_ALARM_CLOCK, + Command.TYPE_SET_PHONEBOOK, + Command.TYPE_MESSAGE, + Command.TYPE_VOICE_MESSAGE, + Command.TYPE_SET_TIMEZONE, + Command.TYPE_SET_INDICATOR); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new WatchFrameDecoder()); + pipeline.addLast(new WatchProtocolEncoder()); + pipeline.addLast(new WatchProtocolDecoder(WatchProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java new file mode 100644 index 000000000..70b207e9b --- /dev/null +++ b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java @@ -0,0 +1,329 @@ +/* + * 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.regex.Pattern; + +public class WatchProtocolDecoder extends BaseProtocolDecoder { + + private static final Logger LOGGER = LoggerFactory.getLogger(WatchProtocolDecoder.class); + + public WatchProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN_POSITION = new PatternBuilder() + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([AV]),") // validity + .number(" *(-?d+.d+),") // latitude + .expression("([NS]),") + .number(" *(-?d+.d+),") // longitude + .expression("([EW])?,") + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(d+.?d*),") // altitude + .number("(d+),") // satellites + .number("(d+),") // rssi + .number("(d+),") // battery + .number("(d+),") // steps + .number("d+,") // tumbles + .number("(x+),") // status + .expression("(.*)") // cell and wifi + .compile(); + + private void sendResponse(Channel channel, String id, String index, String content) { + if (channel != null) { + String response; + if (index != null) { + response = String.format("[%s*%s*%s*%04x*%s]", + manufacturer, id, index, content.length(), content); + } else { + response = String.format("[%s*%s*%04x*%s]", + manufacturer, id, content.length(), content); + } + ByteBuf buf = Unpooled.copiedBuffer(response, StandardCharsets.US_ASCII); + channel.writeAndFlush(new NetworkMessage(buf, channel.remoteAddress())); + } + } + + private String decodeAlarm(int status) { + if (BitUtil.check(status, 0)) { + return Position.ALARM_LOW_BATTERY; + } else if (BitUtil.check(status, 1)) { + return Position.ALARM_GEOFENCE_EXIT; + } else if (BitUtil.check(status, 2)) { + return Position.ALARM_GEOFENCE_ENTER; + } else if (BitUtil.check(status, 3)) { + return Position.ALARM_OVERSPEED; + } else if (BitUtil.check(status, 16)) { + return Position.ALARM_SOS; + } else if (BitUtil.check(status, 17)) { + return Position.ALARM_LOW_BATTERY; + } else if (BitUtil.check(status, 18)) { + return Position.ALARM_GEOFENCE_EXIT; + } else if (BitUtil.check(status, 19)) { + return Position.ALARM_GEOFENCE_ENTER; + } else if (BitUtil.check(status, 20)) { + return Position.ALARM_REMOVING; + } else if (BitUtil.check(status, 21)) { + return Position.ALARM_FALL_DOWN; + } + return null; + } + + private Position decodePosition(DeviceSession deviceSession, String data) { + + Parser parser = new Parser(PATTERN_POSITION, data); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt(0)); + position.set(Position.KEY_RSSI, parser.nextInt(0)); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); + + position.set(Position.KEY_STEPS, parser.nextInt(0)); + + int status = parser.nextHexInt(0); + position.set(Position.KEY_ALARM, decodeAlarm(status)); + if (BitUtil.check(status, 4)) { + position.set(Position.KEY_MOTION, true); + } + + String[] values = parser.next().split(","); + int index = 0; + + Network network = new Network(); + + int cellCount = Integer.parseInt(values[index++]); + index += 1; // timing advance + int mcc = Integer.parseInt(values[index++]); + int mnc = Integer.parseInt(values[index++]); + + for (int i = 0; i < cellCount; i++) { + network.addCellTower(CellTower.from(mcc, mnc, + Integer.parseInt(values[index++]), Integer.parseInt(values[index++]), + Integer.parseInt(values[index++]))); + } + + if (index < values.length && !values[index].isEmpty()) { + int wifiCount = Integer.parseInt(values[index++]); + + for (int i = 0; i < wifiCount; i++) { + index += 1; // wifi name + network.addWifiAccessPoint(WifiAccessPoint.from( + values[index++], Integer.parseInt(values[index++]))); + } + } + + if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { + position.setNetwork(network); + } + + return position; + } + + private boolean hasIndex; + private String manufacturer; + + public boolean getHasIndex() { + return hasIndex; + } + + public String getManufacturer() { + return manufacturer; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.skipBytes(1); // '[' header + manufacturer = buf.readSlice(2).toString(StandardCharsets.US_ASCII); + buf.skipBytes(1); // '*' delimiter + + int idIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*'); + String id = buf.readSlice(idIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); + if (deviceSession == null) { + return null; + } + + buf.skipBytes(1); // '*' delimiter + + String index = null; + int contentIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*'); + if (contentIndex + 5 < buf.writerIndex() && buf.getByte(contentIndex + 5) == '*' + && buf.toString(contentIndex + 1, 4, StandardCharsets.US_ASCII).matches("\\p{XDigit}+")) { + int indexLength = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*') - buf.readerIndex(); + hasIndex = true; + index = buf.readSlice(indexLength).toString(StandardCharsets.US_ASCII); + buf.skipBytes(1); // '*' delimiter + } + + buf.skipBytes(4); // length + buf.skipBytes(1); // '*' delimiter + + buf.writerIndex(buf.writerIndex() - 1); // ']' ignore ending + + contentIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); + if (contentIndex < 0) { + contentIndex = buf.writerIndex(); + } + + String type = buf.readSlice(contentIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII); + + if (contentIndex < buf.writerIndex()) { + buf.readerIndex(contentIndex + 1); + } + + if (type.equals("INIT")) { + + sendResponse(channel, id, index, "INIT,1"); + + } else if (type.equals("LK")) { + + sendResponse(channel, id, index, "LK"); + + if (buf.isReadable()) { + String[] values = buf.toString(StandardCharsets.US_ASCII).split(","); + if (values.length >= 3) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[2])); + + return position; + } + } + + } else if (type.equals("UD") || type.equals("UD2") || type.equals("UD3") + || type.equals("AL") || type.equals("WT")) { + + Position position = decodePosition(deviceSession, buf.toString(StandardCharsets.US_ASCII)); + + if (type.equals("AL")) { + if (position != null) { + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + } + sendResponse(channel, id, index, "AL"); + } + + return position; + + } else if (type.equals("TKQ")) { + + sendResponse(channel, id, index, "TKQ"); + + } else if (type.equals("PULSE") || type.equals("heart") || type.equals("bphrt")) { + + if (buf.isReadable()) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, new Date()); + + String[] values = buf.toString(StandardCharsets.US_ASCII).split(","); + int valueIndex = 0; + + if (type.equals("bphrt")) { + position.set("pressureHigh", values[valueIndex++]); + position.set("pressureLow", values[valueIndex++]); + } + position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[valueIndex])); + + return position; + + } + + } else if (type.equals("img")) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + int timeIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); + buf.readerIndex(timeIndex + 12 + 2); + position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(id, buf, "jpg")); + + return position; + + } else if (type.equals("TK")) { + + if (buf.readableBytes() == 1) { + byte result = buf.readByte(); + if (result != '1') { + LOGGER.warn(type + "," + result); + } + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_AUDIO, Context.getMediaManager().writeFile(id, buf, "amr")); + + return position; + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java new file mode 100644 index 000000000..264aec81f --- /dev/null +++ b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java @@ -0,0 +1,167 @@ +/* + * Copyright 2016 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.StringProtocolEncoder; +import org.traccar.helper.DataConverter; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + +public class WatchProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { + + @Override + public String formatValue(String key, Object value) { + if (key.equals(Command.KEY_TIMEZONE)) { + double offset = TimeZone.getTimeZone((String) value).getRawOffset() / 3600000.0; + DecimalFormat fmt = new DecimalFormat("+#.##;-#.##", DecimalFormatSymbols.getInstance(Locale.US)); + return fmt.format(offset); + } else if (key.equals(Command.KEY_MESSAGE)) { + return DataConverter.printHex(value.toString().getBytes(StandardCharsets.UTF_16BE)); + } else if (key.equals(Command.KEY_ENABLE)) { + return (boolean) value ? "1" : "0"; + } + + return null; + } + + protected ByteBuf formatTextCommand(Channel channel, Command command, String format, String... keys) { + String content = formatCommand(command, format, this, keys); + ByteBuf buf = Unpooled.copiedBuffer(content, StandardCharsets.US_ASCII); + + return formatBinaryCommand(channel, command, "", buf); + } + + protected ByteBuf formatBinaryCommand(Channel channel, Command command, String textPrefix, ByteBuf data) { + boolean hasIndex = false; + String manufacturer = "CS"; + if (channel != null) { + WatchProtocolDecoder decoder = channel.pipeline().get(WatchProtocolDecoder.class); + if (decoder != null) { + hasIndex = decoder.getHasIndex(); + manufacturer = decoder.getManufacturer(); + } + } + + ByteBuf buf = Unpooled.buffer(); + buf.writeByte('['); + buf.writeCharSequence(manufacturer, StandardCharsets.US_ASCII); + buf.writeByte('*'); + buf.writeCharSequence(getUniqueId(command.getDeviceId()), StandardCharsets.US_ASCII); + buf.writeByte('*'); + if (hasIndex) { + buf.writeCharSequence("0001", StandardCharsets.US_ASCII); + buf.writeByte('*'); + } + buf.writeCharSequence(String.format("%04x", data.readableBytes() + textPrefix.length()), + StandardCharsets.US_ASCII); + buf.writeByte('*'); + buf.writeCharSequence(textPrefix, StandardCharsets.US_ASCII); + buf.writeBytes(data); + buf.writeByte(']'); + + return buf; + } + + private static Map mapping = new HashMap<>(); + + static { + mapping.put((byte) 0x7d, (byte) 0x01); + mapping.put((byte) 0x5B, (byte) 0x02); + mapping.put((byte) 0x5D, (byte) 0x03); + mapping.put((byte) 0x2C, (byte) 0x04); + mapping.put((byte) 0x2A, (byte) 0x05); + } + + private ByteBuf getBinaryData(Command command) { + byte[] data = DataConverter.parseHex(command.getString(Command.KEY_DATA)); + + int encodedLength = data.length; + for (byte b : data) { + if (mapping.containsKey(b)) { + encodedLength += 1; + } + } + + int index = 0; + byte[] encodedData = new byte[encodedLength]; + + for (byte b : data) { + Byte replacement = mapping.get(b); + if (replacement != null) { + encodedData[index] = 0x7D; + index += 1; + encodedData[index] = replacement; + } else { + encodedData[index] = b; + } + index += 1; + } + + return Unpooled.copiedBuffer(encodedData); + } + + @Override + protected Object encodeCommand(Channel channel, Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatTextCommand(channel, command, command.getString(Command.KEY_DATA)); + case Command.TYPE_POSITION_SINGLE: + return formatTextCommand(channel, command, "RG"); + case Command.TYPE_SOS_NUMBER: + return formatTextCommand(channel, command, "SOS{%s},{%s}", Command.KEY_INDEX, Command.KEY_PHONE); + case Command.TYPE_ALARM_SOS: + return formatTextCommand(channel, command, "SOSSMS,{%s}", Command.KEY_ENABLE); + case Command.TYPE_ALARM_BATTERY: + return formatTextCommand(channel, command, "LOWBAT,{%s}", Command.KEY_ENABLE); + case Command.TYPE_REBOOT_DEVICE: + return formatTextCommand(channel, command, "RESET"); + case Command.TYPE_POWER_OFF: + return formatTextCommand(channel, command, "POWEROFF"); + case Command.TYPE_ALARM_REMOVE: + return formatTextCommand(channel, command, "REMOVE,{%s}", Command.KEY_ENABLE); + case Command.TYPE_SILENCE_TIME: + return formatTextCommand(channel, command, "SILENCETIME,{%s}", Command.KEY_DATA); + case Command.TYPE_ALARM_CLOCK: + return formatTextCommand(channel, command, "REMIND,{%s}", Command.KEY_DATA); + case Command.TYPE_SET_PHONEBOOK: + return formatTextCommand(channel, command, "PHB,{%s}", Command.KEY_DATA); + case Command.TYPE_MESSAGE: + return formatTextCommand(channel, command, "MESSAGE,{%s}", Command.KEY_MESSAGE); + case Command.TYPE_VOICE_MESSAGE: + return formatBinaryCommand(channel, command, "TK,", getBinaryData(command)); + case Command.TYPE_POSITION_PERIODIC: + return formatTextCommand(channel, command, "UPLOAD,{%s}", Command.KEY_FREQUENCY); + case Command.TYPE_SET_TIMEZONE: + return formatTextCommand(channel, command, "LZ,,{%s}", Command.KEY_TIMEZONE); + case Command.TYPE_SET_INDICATOR: + return formatTextCommand(channel, command, "FLOWER,{%s}", Command.KEY_DATA); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/WialonProtocol.java b/src/main/java/org/traccar/protocol/WialonProtocol.java new file mode 100644 index 000000000..06b54dceb --- /dev/null +++ b/src/main/java/org/traccar/protocol/WialonProtocol.java @@ -0,0 +1,54 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.Context; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +import io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; + +import java.nio.charset.StandardCharsets; +public class WialonProtocol extends BaseProtocol { + + public WialonProtocol() { + setSupportedDataCommands( + Command.TYPE_REBOOT_DEVICE, + Command.TYPE_SEND_USSD, + Command.TYPE_IDENTIFICATION, + Command.TYPE_OUTPUT_CONTROL); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(4 * 1024)); + pipeline.addLast(new StringEncoder()); + boolean utf8 = Context.getConfig().getBoolean(getName() + ".utf8"); + if (utf8) { + pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8)); + } else { + pipeline.addLast(new StringDecoder()); + } + pipeline.addLast(new WialonProtocolEncoder()); + pipeline.addLast(new WialonProtocolDecoder(WialonProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java new file mode 100644 index 000000000..de7073b67 --- /dev/null +++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java @@ -0,0 +1,196 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class WialonProtocolDecoder extends BaseProtocolDecoder { + + public WialonProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("(dd)(dd)(dd);") // date (ddmmyy) + .number("(dd)(dd)(dd);") // time (hhmmss) + .number("(dd)(dd.d+);") // latitude + .expression("([NS]);") + .number("(ddd)(dd.d+);") // longitude + .expression("([EW]);") + .number("(d+.?d*)?;") // speed + .number("(d+.?d*)?;") // course + .number("(?:NA|(-?d+.?d*));") // altitude + .number("(?:NA|(d+))") // satellites + .groupBegin().text(";") + .number("(?:NA|(d+.?d*));") // hdop + .number("(?:NA|(d+));") // inputs + .number("(?:NA|(d+));") // outputs + .expression("(?:NA|([^;]*));") // adc + .expression("(?:NA|([^;]*));") // ibutton + .expression("(?:NA|(.*))") // params + .groupEnd("?") + .compile(); + + private void sendResponse(Channel channel, SocketAddress remoteAddress, String prefix, Integer number) { + if (channel != null) { + StringBuilder response = new StringBuilder(prefix); + if (number != null) { + response.append(number); + } + response.append("\r\n"); + channel.writeAndFlush(new NetworkMessage(response.toString(), remoteAddress)); + } + } + + private Position decodePosition(Channel channel, SocketAddress remoteAddress, String substring) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, substring); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); + + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + if (parser.hasNext()) { + int satellites = parser.nextInt(0); + position.setValid(satellites >= 3); + position.set(Position.KEY_SATELLITES, satellites); + } + + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + + if (parser.hasNext()) { + String[] values = parser.next().split(","); + for (int i = 0; i < values.length; i++) { + position.set(Position.PREFIX_ADC + (i + 1), values[i]); + } + } + + position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); + + if (parser.hasNext()) { + String[] values = parser.next().split(","); + for (String param : values) { + Matcher paramParser = Pattern.compile("(.*):[1-3]:(.*)").matcher(param); + if (paramParser.matches()) { + try { + position.set(paramParser.group(1).toLowerCase(), Double.parseDouble(paramParser.group(2))); + } catch (NumberFormatException e) { + position.set(paramParser.group(1).toLowerCase(), paramParser.group(2)); + } + } + } + } + + return position; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("#L#")) { + + String[] values = sentence.substring(3).split(";"); + + String imei = values[0].indexOf('.') >= 0 ? values[1] : values[0]; + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession != null) { + sendResponse(channel, remoteAddress, "#AL#", 1); + } + + } else if (sentence.startsWith("#P#")) { + + sendResponse(channel, remoteAddress, "#AP#", null); // heartbeat + + } else if (sentence.startsWith("#SD#") || sentence.startsWith("#D#")) { + + Position position = decodePosition( + channel, remoteAddress, sentence.substring(sentence.indexOf('#', 1) + 1)); + + if (position != null) { + sendResponse(channel, remoteAddress, "#AD#", 1); + return position; + } + + } else if (sentence.startsWith("#B#")) { + + String[] messages = sentence.substring(sentence.indexOf('#', 1) + 1).split("\\|"); + List positions = new LinkedList<>(); + + for (String message : messages) { + Position position = decodePosition(channel, remoteAddress, message); + if (position != null) { + position.set(Position.KEY_ARCHIVE, true); + positions.add(position); + } + } + + sendResponse(channel, remoteAddress, "#AB#", messages.length); + if (!positions.isEmpty()) { + return positions; + } + + } else if (sentence.startsWith("#M#")) { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession != null) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, new Date()); + position.setValid(false); + position.set(Position.KEY_RESULT, sentence.substring(sentence.indexOf('#', 1) + 1)); + sendResponse(channel, remoteAddress, "#AM#", 1); + return position; + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java b/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java new file mode 100644 index 000000000..9ff1631eb --- /dev/null +++ b/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java @@ -0,0 +1,40 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class WialonProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + switch (command.getType()) { + case Command.TYPE_REBOOT_DEVICE: + return formatCommand(command, "reboot\r\n"); + case Command.TYPE_SEND_USSD: + return formatCommand(command, "USSD:{%s}\r\n", Command.KEY_PHONE); + case Command.TYPE_IDENTIFICATION: + return formatCommand(command, "VER?\r\n"); + case Command.TYPE_OUTPUT_CONTROL: + return formatCommand(command, "L{%s}={%s}\r\n", Command.KEY_INDEX, Command.KEY_DATA); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/WondexFrameDecoder.java b/src/main/java/org/traccar/protocol/WondexFrameDecoder.java new file mode 100644 index 000000000..39d83d761 --- /dev/null +++ b/src/main/java/org/traccar/protocol/WondexFrameDecoder.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013 - 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. + * 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 org.traccar.BaseFrameDecoder; +import org.traccar.NetworkMessage; +import org.traccar.helper.BufferUtil; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +public class WondexFrameDecoder extends BaseFrameDecoder { + + private static final int KEEP_ALIVE_LENGTH = 8; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < KEEP_ALIVE_LENGTH) { + return null; + } + + if (buf.getUnsignedByte(buf.readerIndex()) == 0xD0) { + + // Send response + ByteBuf frame = buf.readRetainedSlice(KEEP_ALIVE_LENGTH); + if (channel != null) { + frame.retain(); + channel.writeAndFlush(new NetworkMessage(frame, channel.remoteAddress())); + } + return frame; + + } else { + + int index = BufferUtil.indexOf("\r\n", buf); + if (index != -1) { + ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex()); + buf.skipBytes(2); + return frame; + } + + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/WondexProtocol.java b/src/main/java/org/traccar/protocol/WondexProtocol.java new file mode 100644 index 000000000..8c6283d66 --- /dev/null +++ b/src/main/java/org/traccar/protocol/WondexProtocol.java @@ -0,0 +1,55 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +import io.netty.handler.codec.string.StringEncoder; + +public class WondexProtocol extends BaseProtocol { + + public WondexProtocol() { + setTextCommandEncoder(new WondexProtocolEncoder()); + setSupportedCommands( + Command.TYPE_GET_DEVICE_STATUS, + Command.TYPE_GET_MODEM_STATUS, + Command.TYPE_REBOOT_DEVICE, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_GET_VERSION, + Command.TYPE_IDENTIFICATION); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new WondexFrameDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new WondexProtocolEncoder()); + pipeline.addLast(new WondexProtocolDecoder(WondexProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new WondexProtocolEncoder()); + pipeline.addLast(new WondexProtocolDecoder(WondexProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/WondexProtocolDecoder.java b/src/main/java/org/traccar/protocol/WondexProtocolDecoder.java new file mode 100644 index 000000000..b85ae2656 --- /dev/null +++ b/src/main/java/org/traccar/protocol/WondexProtocolDecoder.java @@ -0,0 +1,128 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.regex.Pattern; + +public class WondexProtocolDecoder extends BaseProtocolDecoder { + + public WondexProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("[^d]*") // header + .number("(d+),") // device identifier + .number("(dddd)(dd)(dd)") // date (yyyymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(-?d+.?d*),") // altitude + .number("(d+),") // satellites + .number("(d+),?") // event + .number("(d+.d+)V,").optional() // battery + .number("(d+.d+)?,?") // odometer + .number("(d+)?,?") // input + .number("(d+.d+)?,?") // adc1 + .number("(d+.d+)?,?") // adc2 + .number("(d+)?") // output + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + if (buf.getUnsignedByte(0) == 0xD0) { + + long deviceId = ((Long.reverseBytes(buf.getLong(0))) >> 32) & 0xFFFFFFFFL; + getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); + + return null; + } else if (buf.toString(StandardCharsets.US_ASCII).startsWith("$OK:") + || buf.toString(StandardCharsets.US_ASCII).startsWith("$ERR:") + || buf.toString(StandardCharsets.US_ASCII).startsWith("$MSG:")) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, new Date()); + position.set(Position.KEY_RESULT, buf.toString(StandardCharsets.US_ASCII)); + + return position; + + } else { + + Parser parser = new Parser(PATTERN, buf.toString(StandardCharsets.US_ASCII)); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setLongitude(parser.nextDouble(0)); + position.setLatitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + + int satellites = parser.nextInt(0); + position.setValid(satellites != 0); + position.set(Position.KEY_SATELLITES, satellites); + + position.set(Position.KEY_EVENT, parser.next()); + position.set(Position.KEY_BATTERY, parser.nextDouble()); + if (parser.hasNext()) { + position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); + } + position.set(Position.KEY_INPUT, parser.next()); + position.set(Position.PREFIX_ADC + 1, parser.next()); + position.set(Position.PREFIX_ADC + 2, parser.next()); + position.set(Position.KEY_OUTPUT, parser.next()); + + return position; + + } + + } + +} diff --git a/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java new file mode 100644 index 000000000..f9e8eeb9b --- /dev/null +++ b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2016 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class WondexProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + initDevicePassword(command, "0000"); + + switch (command.getType()) { + case Command.TYPE_REBOOT_DEVICE: + return formatCommand(command, "$WP+REBOOT={%s}", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_GET_DEVICE_STATUS: + return formatCommand(command, "$WP+TEST={%s}", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_GET_MODEM_STATUS: + return formatCommand(command, "$WP+GSMINFO={%s}", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_IDENTIFICATION: + return formatCommand(command, "$WP+IMEI={%s}", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, "$WP+GETLOCATION={%s}", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_GET_VERSION: + return formatCommand(command, "$WP+VER={%s}", Command.KEY_DEVICE_PASSWORD); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/WristbandProtocol.java b/src/main/java/org/traccar/protocol/WristbandProtocol.java new file mode 100644 index 000000000..1e5ef2c01 --- /dev/null +++ b/src/main/java/org/traccar/protocol/WristbandProtocol.java @@ -0,0 +1,35 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class WristbandProtocol extends BaseProtocol { + + public WristbandProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2, 3, 0)); + pipeline.addLast(new WristbandProtocolDecoder(WristbandProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java b/src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java new file mode 100644 index 000000000..7f2b0af85 --- /dev/null +++ b/src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java @@ -0,0 +1,207 @@ +/* + * Copyright 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Network; +import org.traccar.model.Position; +import org.traccar.model.WifiAccessPoint; + +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +public class WristbandProtocolDecoder extends BaseProtocolDecoder { + + public WristbandProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private void sendResponse( + Channel channel, String imei, String version, int type, String data) { + + if (channel != null) { + String sentence = String.format("YX%s|%s|0|{F%02d#%s}\r\n", imei, version, type, data); + ByteBuf response = Unpooled.buffer(); + if (type != 91) { + response.writeBytes(new byte[]{0x00, 0x01, 0x02}); + response.writeShort(sentence.length()); + } + response.writeCharSequence(sentence, StandardCharsets.US_ASCII); + if (type != 91) { + response.writeBytes(new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0xFC}); + } + channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); + } + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("..") // header + .number("(d+)|") // imei + .number("([vV]d+.d+)|") // version + .number("d+|") // model + .text("{") + .number("F(d+)") // function + .groupBegin() + .text("#") + .expression("(.*)") // data + .groupEnd("?") + .text("}") + .text("\r\n") + .compile(); + + private Position decodePosition(DeviceSession deviceSession, String sentence) throws ParseException { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + String[] values = sentence.split(","); + + position.setValid(true); + position.setLongitude(Double.parseDouble(values[0])); + position.setLatitude(Double.parseDouble(values[1])); + position.setTime(new SimpleDateFormat("yyyyMMddHHmm").parse(values[2])); + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[3]))); + + return position; + } + + private Position decodeStatus(DeviceSession deviceSession, String sentence) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(sentence.split(",")[0])); + + return position; + } + + private Position decodeNetwork(DeviceSession deviceSession, String sentence, boolean wifi) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + Network network = new Network(); + String[] fragments = sentence.split("\\|"); + + if (wifi) { + for (String item : fragments[0].split("_")) { + String[] values = item.split(","); + network.addWifiAccessPoint(WifiAccessPoint.from(values[0], Integer.parseInt(values[1]))); + } + } + + for (String item : fragments[wifi ? 1 : 0].split(":")) { + String[] values = item.split(","); + int lac = Integer.parseInt(values[0]); + int mnc = Integer.parseInt(values[1]); + int mcc = Integer.parseInt(values[2]); + int cid = Integer.parseInt(values[3]); + int rssi = Integer.parseInt(values[4]); + network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi)); + } + + position.setNetwork(network); + + return position; + } + + private List decodeMessage( + Channel channel, SocketAddress remoteAddress, String sentence) throws ParseException { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + String imei = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + + String version = parser.next(); + int type = parser.nextInt(); + + List positions = new LinkedList<>(); + String data = parser.next(); + + switch (type) { + case 90: + sendResponse(channel, imei, version, type, getServer(channel, ',')); + break; + case 91: + String time = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); + sendResponse(channel, imei, version, type, time + "|" + getServer(channel, ',')); + break; + case 1: + positions.add(decodeStatus(deviceSession, data)); + sendResponse(channel, imei, version, type, data.split(",")[1]); + break; + case 2: + for (String fragment : data.split("\\|")) { + positions.add(decodePosition(deviceSession, fragment)); + } + break; + case 3: + case 4: + positions.add(decodeNetwork(deviceSession, data, type == 3)); + break; + case 64: + sendResponse(channel, imei, version, type, data); + break; + default: + break; + } + + return positions.isEmpty() ? null : positions; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + buf.skipBytes(3); // header + buf.readUnsignedShort(); // length + + String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 3, StandardCharsets.US_ASCII); + + buf.skipBytes(3); // footer + + return decodeMessage(channel, remoteAddress, sentence); + } + +} diff --git a/src/main/java/org/traccar/protocol/XexunFrameDecoder.java b/src/main/java/org/traccar/protocol/XexunFrameDecoder.java new file mode 100644 index 000000000..114e94061 --- /dev/null +++ b/src/main/java/org/traccar/protocol/XexunFrameDecoder.java @@ -0,0 +1,58 @@ +/* + * 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. + * 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 org.traccar.BaseFrameDecoder; +import org.traccar.helper.BufferUtil; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +public class XexunFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + if (buf.readableBytes() < 80) { + return null; + } + + int beginIndex = BufferUtil.indexOf("GPRMC", buf); + if (beginIndex == -1) { + beginIndex = BufferUtil.indexOf("GNRMC", buf); + if (beginIndex == -1) { + return null; + } + } + + int identifierIndex = BufferUtil.indexOf("imei:", buf, beginIndex, buf.writerIndex()); + if (identifierIndex == -1) { + return null; + } + + int endIndex = buf.indexOf(identifierIndex, buf.writerIndex(), (byte) ','); + if (endIndex == -1) { + return null; + } + + buf.skipBytes(beginIndex - buf.readerIndex()); + + return buf.readRetainedSlice(endIndex - beginIndex + 1); + } + +} diff --git a/src/main/java/org/traccar/protocol/XexunProtocol.java b/src/main/java/org/traccar/protocol/XexunProtocol.java new file mode 100644 index 000000000..0005270fb --- /dev/null +++ b/src/main/java/org/traccar/protocol/XexunProtocol.java @@ -0,0 +1,51 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.Context; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +import io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; + +public class XexunProtocol extends BaseProtocol { + + public XexunProtocol() { + setSupportedDataCommands( + Command.TYPE_ENGINE_STOP, + Command.TYPE_ENGINE_RESUME); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + boolean full = Context.getConfig().getBoolean(getName() + ".extended"); + if (full) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); // tracker bug \n\r + } else { + pipeline.addLast(new XexunFrameDecoder()); + } + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new XexunProtocolEncoder()); + pipeline.addLast(new XexunProtocolDecoder(XexunProtocol.this, full)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/XexunProtocolDecoder.java b/src/main/java/org/traccar/protocol/XexunProtocolDecoder.java new file mode 100644 index 000000000..5e2d0c05e --- /dev/null +++ b/src/main/java/org/traccar/protocol/XexunProtocolDecoder.java @@ -0,0 +1,152 @@ +/* + * 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class XexunProtocolDecoder extends BaseProtocolDecoder { + + private final boolean full; + + public XexunProtocolDecoder(Protocol protocol, boolean full) { + super(protocol); + this.full = full; + } + + private static final Pattern PATTERN_BASIC = new PatternBuilder() + .expression("G[PN]RMC,") + .number("(?:(dd)(dd)(dd))?.?d*,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(d*?)(d?d.d+),([NS]),") // latitude + .number("(d*?)(d?d.d+),([EW])?,") // longitude + .number("(d+.?d*),") // speed + .number("(d+.?d*)?,") // course + .number("(?:(dd)(dd)(dd))?,") // date (ddmmyy) + .expression("[^*]*").text("*") + .number("xx") // checksum + .expression("\\r\\n").optional() + .expression(",([FL]),") // signal + .expression("([^,]*),").optional() // alarm + .any() + .number("imei:(d+),") // imei + .compile(); + + private static final Pattern PATTERN_FULL = new PatternBuilder() + .any() + .number("(d+),") // serial + .expression("([^,]+)?,") // phone number + .expression(PATTERN_BASIC.pattern()) + .number("(d+),") // satellites + .number("(-?d+.d+)?,") // altitude + .number("[FL]:(d+.d+)V") // power + .any() + .compile(); + + private String decodeStatus(Position position, String value) { + if (value != null) { + switch (value.toLowerCase()) { + case "acc on": + case "accstart": + position.set(Position.KEY_IGNITION, true); + break; + case "acc off": + case "accstop": + position.set(Position.KEY_IGNITION, false); + break; + case "help me!": + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + break; + case "low battery": + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + case "move!": + case "moved!": + position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); + break; + default: + break; + } + } + return null; + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Pattern pattern = PATTERN_BASIC; + if (full) { + pattern = PATTERN_FULL; + } + + Parser parser = new Parser(pattern, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + if (full) { + position.set("serial", parser.next()); + position.set("number", parser.next()); + } + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + position.setSpeed(convertSpeed(parser.nextDouble(0), "kn")); + + position.setCourse(parser.nextDouble(0)); + + dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); + position.setTime(dateBuilder.getDate()); + + position.set("signal", parser.next()); + + decodeStatus(position, parser.next()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + if (full) { + position.set(Position.KEY_SATELLITES, parser.nextInt()); + + position.setAltitude(parser.nextDouble(0)); + + position.set(Position.KEY_POWER, parser.nextDouble(0)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java b/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java new file mode 100644 index 000000000..515cfbbd0 --- /dev/null +++ b/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java @@ -0,0 +1,38 @@ +/* + * Copyright 2016 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class XexunProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + initDevicePassword(command, "123456"); + + switch (command.getType()) { + case Command.TYPE_ENGINE_STOP: + return formatCommand(command, "powercar{%s} 11", Command.KEY_DEVICE_PASSWORD); + case Command.TYPE_ENGINE_RESUME: + return formatCommand(command, "powercar{%s} 00", Command.KEY_DEVICE_PASSWORD); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/XirgoProtocol.java b/src/main/java/org/traccar/protocol/XirgoProtocol.java new file mode 100644 index 000000000..4979fda5d --- /dev/null +++ b/src/main/java/org/traccar/protocol/XirgoProtocol.java @@ -0,0 +1,53 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.CharacterDelimiterFrameDecoder; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; + +public class XirgoProtocol extends BaseProtocol { + + public XirgoProtocol() { + setSupportedDataCommands( + Command.TYPE_OUTPUT_CONTROL); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##")); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new XirgoProtocolEncoder()); + pipeline.addLast(new XirgoProtocolDecoder(XirgoProtocol.this)); + } + }); + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new XirgoProtocolEncoder()); + pipeline.addLast(new XirgoProtocolDecoder(XirgoProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java b/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java new file mode 100644 index 000000000..6d215e672 --- /dev/null +++ b/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java @@ -0,0 +1,355 @@ +/* + * Copyright 2015 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class XirgoProtocolDecoder extends BaseProtocolDecoder { + + private Boolean newFormat; + private String form; + + public XirgoProtocolDecoder(Protocol protocol) { + super(protocol); + form = Context.getConfig().getString(getProtocolName() + ".form"); + } + + public void setForm(String form) { + this.form = form; + } + + private static final Pattern PATTERN_OLD = new PatternBuilder() + .text("$$") + .number("(d+),") // imei + .number("(d+),") // event + .number("(dddd)/(dd)/(dd),") // date (yyyy/mm/dd) + .number("(dd):(dd):(dd),") // time (hh:mm:ss) + .number("(-?d+.?d*),") // latitude + .number("(-?d+.?d*),") // longitude + .number("(-?d+.?d*),") // altitude + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(d+),") // satellites + .number("(d+.?d*),") // hdop + .number("(d+.d+),") // battery + .number("(d+),") // gsm + .number("(d+.?d*),") // odometer + .number("(d+),") // gps + .any() + .compile(); + + private static final Pattern PATTERN_NEW = new PatternBuilder() + .text("$$") + .number("(d+),") // imei + .number("(d+),") // event + .number("(dddd)/(dd)/(dd),") // date (yyyy/mm/dd) + .number("(dd):(dd):(dd),") // time (hh:mm:ss) + .number("(-?d+.?d*),") // latitude + .number("(-?d+.?d*),") // longitude + .number("(-?d+.?d*),") // altitude + .number("(d+.?d*),") // speed + .number("d+.?d*,") // acceleration + .number("d+.?d*,") // deceleration + .number("d+,") + .number("(d+.?d*),") // course + .number("(d+),") // satellites + .number("(d+.?d*),") // hdop + .number("(d+.?d*),") // odometer + .number("(d+.?d*),") // fuel consumption + .number("(d+.d+),") // battery + .number("(d+),") // gsm + .number("(d+),") // gps + .groupBegin() + .number("d,") // reset mode + .expression("([01])") // input 1 + .expression("([01])") // input 1 + .expression("([01])") // input 1 + .expression("([01]),") // output 1 + .number("(d+.?d*),") // adc 1 + .number("(d+.?d*),") // fuel level + .number("d+,") // engine load + .number("(d+),") // engine hours + .number("(d+),") // oil pressure + .number("(d+),") // oil level + .number("(-?d+),") // oil temperature + .number("(d+),") // coolant pressure + .number("(d+),") // coolant level + .number("(-?d+)") // coolant temperature + .groupEnd("?") + .any() + .compile(); + + private void decodeEvent(Position position, int event) { + + position.set(Position.KEY_EVENT, event); + + switch (event) { + case 4001: + case 4003: + case 6011: + case 6013: + position.set(Position.KEY_IGNITION, true); + break; + case 4002: + case 4004: + case 6012: + case 6014: + position.set(Position.KEY_IGNITION, false); + break; + case 4005: + position.set(Position.KEY_CHARGE, false); + break; + case 6002: + position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); + break; + case 6006: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 6007: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 6008: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); + break; + case 6009: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); + break; + case 6010: + position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); + break; + case 6016: + position.set(Position.KEY_ALARM, Position.ALARM_IDLE); + break; + case 6017: + position.set(Position.KEY_ALARM, Position.ALARM_TOW); + break; + case 6030: + case 6071: + position.set(Position.KEY_MOTION, true); + break; + case 6031: + position.set(Position.KEY_MOTION, false); + break; + case 6032: + position.set(Position.KEY_ALARM, Position.ALARM_PARKING); + break; + case 6090: + position.set(Position.KEY_ALARM, Position.ALARM_REMOVING); + break; + case 6091: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + default: + break; + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + if (form != null) { + return decodeCustom(channel, remoteAddress, sentence); + } else { + return decodeFixed(channel, remoteAddress, sentence); + } + } + + + private Object decodeCustom( + Channel channel, SocketAddress remoteAddress, String sentence) { + + String[] keys = form.split(","); + String[] values = sentence.replace("$$", "").replace("##", "").split(","); + + Position position = new Position(getProtocolName()); + DateBuilder dateBuilder = new DateBuilder(); + + for (int i = 0; i < Math.min(keys.length, values.length); i++) { + switch (keys[i]) { + case "UID": + case "IM": + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[i]); + if (deviceSession != null) { + position.setDeviceId(deviceSession.getDeviceId()); + } + break; + case "EV": + decodeEvent(position, Integer.parseInt(values[i])); + break; + case "D": + String[] date = values[i].split("/"); + dateBuilder.setMonth(Integer.parseInt(date[0])); + dateBuilder.setDay(Integer.parseInt(date[1])); + dateBuilder.setYear(Integer.parseInt(date[2])); + break; + case "T": + String[] time = values[i].split(":"); + dateBuilder.setHour(Integer.parseInt(time[0])); + dateBuilder.setMinute(Integer.parseInt(time[1])); + dateBuilder.setSecond(Integer.parseInt(time[2])); + break; + case "LT": + position.setLatitude(Double.parseDouble(values[i])); + break; + case "LN": + position.setLongitude(Double.parseDouble(values[i])); + break; + case "AL": + position.setAltitude(Integer.parseInt(values[i])); + break; + case "GSPT": + position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[i]))); + break; + case "HD": + if (values[i].contains(".")) { + position.setCourse(Double.parseDouble(values[i])); + } else { + position.setCourse(Integer.parseInt(values[i]) * 0.1); + } + break; + case "SV": + position.set(Position.KEY_SATELLITES, Integer.parseInt(values[i])); + break; + case "BV": + position.set(Position.KEY_BATTERY, Double.parseDouble(values[i])); + break; + case "CQ": + position.set(Position.KEY_RSSI, Integer.parseInt(values[i])); + break; + case "MI": + position.set(Position.KEY_ODOMETER, Integer.parseInt(values[i])); + break; + case "GS": + position.setValid(Integer.parseInt(values[i]) == 3); + break; + case "SI": + position.set("iccid", values[i]); + break; + case "IG": + int ignition = Integer.parseInt(values[i]); + if (ignition > 0) { + position.set(Position.KEY_IGNITION, ignition == 1); + } + break; + case "OT": + position.set(Position.KEY_OUTPUT, Integer.parseInt(values[i])); + break; + default: + break; + } + } + + position.setTime(dateBuilder.getDate()); + + return position.getDeviceId() > 0 ? position : null; + } + + private Object decodeFixed( + Channel channel, SocketAddress remoteAddress, String sentence) { + + Parser parser; + if (newFormat == null) { + parser = new Parser(PATTERN_NEW, sentence); + if (parser.matches()) { + newFormat = true; + } else { + parser = new Parser(PATTERN_OLD, sentence); + if (parser.matches()) { + newFormat = false; + } else { + return null; + } + } + } else { + if (newFormat) { + parser = new Parser(PATTERN_NEW, sentence); + } else { + parser = new Parser(PATTERN_OLD, sentence); + } + if (!parser.matches()) { + return null; + } + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + decodeEvent(position, parser.nextInt()); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextDouble()); + + if (newFormat) { + position.set(Position.KEY_ODOMETER, UnitsConverter.metersFromMiles(parser.nextDouble(0))); + position.set(Position.KEY_FUEL_CONSUMPTION, parser.next()); + } + + position.set(Position.KEY_BATTERY, parser.nextDouble(0)); + position.set(Position.KEY_RSSI, parser.nextDouble()); + + if (!newFormat) { + position.set(Position.KEY_ODOMETER, UnitsConverter.metersFromMiles(parser.nextDouble(0))); + } + + position.setValid(parser.nextInt(0) == 1); + + if (newFormat && parser.hasNext(13)) { + position.set(Position.PREFIX_IN + 1, parser.nextInt()); + position.set(Position.PREFIX_IN + 2, parser.nextInt()); + position.set(Position.PREFIX_IN + 3, parser.nextInt()); + position.set(Position.PREFIX_OUT + 1, parser.nextInt()); + position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); + position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble()); + position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(parser.nextInt())); + position.set("oilPressure", parser.nextInt()); + position.set("oilLevel", parser.nextInt()); + position.set("oilTemp", parser.nextInt()); + position.set("coolantPressure", parser.nextInt()); + position.set("coolantLevel", parser.nextInt()); + position.set("coolantTemp", parser.nextInt()); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/XirgoProtocolEncoder.java b/src/main/java/org/traccar/protocol/XirgoProtocolEncoder.java new file mode 100644 index 000000000..dd5e30cca --- /dev/null +++ b/src/main/java/org/traccar/protocol/XirgoProtocolEncoder.java @@ -0,0 +1,34 @@ +/* + * Copyright 2017 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. + * 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 org.traccar.StringProtocolEncoder; +import org.traccar.model.Command; + +public class XirgoProtocolEncoder extends StringProtocolEncoder { + + @Override + protected Object encodeCommand(Command command) { + + switch (command.getType()) { + case Command.TYPE_OUTPUT_CONTROL: + return String.format("+XT:7005,%d,1", command.getInteger(Command.KEY_DATA) + 1); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Xrb28Protocol.java b/src/main/java/org/traccar/protocol/Xrb28Protocol.java new file mode 100644 index 000000000..b1f1c34fb --- /dev/null +++ b/src/main/java/org/traccar/protocol/Xrb28Protocol.java @@ -0,0 +1,49 @@ +/* + * Copyright 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.model.Command; + +import java.nio.charset.StandardCharsets; + +public class Xrb28Protocol extends BaseProtocol { + + public Xrb28Protocol() { + setSupportedDataCommands( + Command.TYPE_CUSTOM, + Command.TYPE_POSITION_SINGLE, + Command.TYPE_POSITION_PERIODIC, + Command.TYPE_ALARM_ARM, + Command.TYPE_ALARM_DISARM); + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder(StandardCharsets.ISO_8859_1)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new Xrb28ProtocolEncoder()); + pipeline.addLast(new Xrb28ProtocolDecoder(Xrb28Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java new file mode 100644 index 000000000..938394d6b --- /dev/null +++ b/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java @@ -0,0 +1,187 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.model.Command; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { + + private String pendingCommand; + + public void setPendingCommand(String pendingCommand) { + this.pendingCommand = pendingCommand; + } + + public Xrb28ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("*") + .expression("....,") + .expression("..,") // vendor + .number("d{15},") // imei + .expression("..,") // type + .number("0,") // reserved + .number("(dd)(dd)(dd).d+,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d{2,3})(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+),") // satellites + .number("(d+.d+),") // hdop + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(-?d+.?d*),") // altitude + .expression(".,") // height unit + .expression(".#") // mode + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(9, 24)); + if (deviceSession == null) { + return null; + } + + String type = sentence.substring(25, 27); + if (channel != null) { + if (type.matches("L0|L1|W0|E1")) { + channel.write(new NetworkMessage( + "\u00ff\u00ff*SCOS" + sentence.substring(5, 27) + "#\n", + remoteAddress)); + } else if (type.equals("R0") && pendingCommand != null) { + String command = pendingCommand.equals(Command.TYPE_ALARM_ARM) ? "L1," : "L0,"; + channel.write(new NetworkMessage( + "\u00ff\u00ff*SCOS" + sentence.substring(5, 25) + command + sentence.substring(30) + "\n", + remoteAddress)); + pendingCommand = null; + } + } + + if (!type.startsWith("D")) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + String payload = sentence.substring(25, sentence.length() - 1); + + int index = 0; + String[] values = payload.substring(3).split(","); + + switch (type) { + case "Q0": + position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.01); + position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[index++])); + position.set(Position.KEY_RSSI, Integer.parseInt(values[index++])); + break; + case "H0": + position.set(Position.KEY_BLOCKED, Integer.parseInt(values[index++]) > 0); + position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.01); + position.set(Position.KEY_RSSI, Integer.parseInt(values[index++])); + position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[index++])); + break; + case "W0": + switch (Integer.parseInt(values[index++])) { + case 1: + position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); + break; + case 2: + position.set(Position.KEY_ALARM, Position.ALARM_FALL_DOWN); + break; + case 3: + position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); + break; + default: + break; + } + break; + case "E0": + position.set(Position.KEY_ALARM, Position.ALARM_FAULT); + position.set("error", Integer.parseInt(values[index++])); + break; + case "S1": + position.set(Position.KEY_EVENT, Integer.parseInt(values[index++])); + break; + case "R0": + case "L0": + case "L1": + case "S4": + case "S5": + case "S6": + case "S7": + case "V0": + case "G0": + case "K0": + case "I0": + case "M0": + position.set(Position.KEY_RESULT, payload); + break; + default: + break; + } + + return !position.getAttributes().isEmpty() ? position : null; + + } else { + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextDouble()); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.setAltitude(parser.nextDouble()); + + return position; + + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Xrb28ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Xrb28ProtocolEncoder.java new file mode 100644 index 000000000..617639312 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Xrb28ProtocolEncoder.java @@ -0,0 +1,52 @@ +/* + * Copyright 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolEncoder; +import org.traccar.model.Command; + +public class Xrb28ProtocolEncoder extends BaseProtocolEncoder { + + private String formatCommand(Command command, String content) { + return String.format("\u00ff\u00ff*SCOS,OM,%s,%s#\n", getUniqueId(command.getDeviceId()), content); + } + + @Override + protected Object encodeCommand(Channel channel, Command command) { + + switch (command.getType()) { + case Command.TYPE_CUSTOM: + return formatCommand(command, command.getString(Command.KEY_DATA)); + case Command.TYPE_POSITION_SINGLE: + return formatCommand(command, "D0"); + case Command.TYPE_POSITION_PERIODIC: + return formatCommand(command, "D1," + command.getInteger(Command.KEY_FREQUENCY)); + case Command.TYPE_ENGINE_STOP: + case Command.TYPE_ALARM_DISARM: + if (channel != null) { + Xrb28ProtocolDecoder decoder = channel.pipeline().get(Xrb28ProtocolDecoder.class); + if (decoder != null) { + decoder.setPendingCommand(command.getType()); + } + } + return formatCommand(command, "R0,0,20,1234," + System.currentTimeMillis() / 1000); + default: + return null; + } + } + +} diff --git a/src/main/java/org/traccar/protocol/Xt013Protocol.java b/src/main/java/org/traccar/protocol/Xt013Protocol.java new file mode 100644 index 000000000..ebb3c123f --- /dev/null +++ b/src/main/java/org/traccar/protocol/Xt013Protocol.java @@ -0,0 +1,40 @@ +/* + * 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +import io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; + +public class Xt013Protocol extends BaseProtocol { + + public Xt013Protocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new Xt013ProtocolDecoder(Xt013Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java new file mode 100644 index 000000000..f49fb9563 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java @@ -0,0 +1,94 @@ +/* + * Copyright 2015 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class Xt013ProtocolDecoder extends BaseProtocolDecoder { + + public Xt013ProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .number("HI,d+").optional() + .text("TK,") + .number("(d+),") // imei + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .number("([+-]d+.d+),") // latitude + .number("([+-]d+.d+),") // longitude + .number("(d+),") // speed + .number("(d+),") // course + .number("d+,") + .number("(d+),") // altitude + .expression("([FL]),") // gps fix + .number("d+,") + .number("(d+),") // gps level + .number("x+,") + .number("x+,") + .number("(d+),") // gsm level + .expression("[^,]*,") + .number("(d+.d+),") // battery + .number("(d),") // charging + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setLatitude(parser.nextDouble(0)); + position.setLongitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); + position.setCourse(parser.nextDouble(0)); + position.setAltitude(parser.nextDouble(0)); + position.setValid(parser.next().equals("F")); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_RSSI, parser.nextDouble()); + position.set(Position.KEY_BATTERY, parser.nextDouble(0)); + position.set(Position.KEY_CHARGE, parser.next().equals("1")); + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/Xt2400Protocol.java b/src/main/java/org/traccar/protocol/Xt2400Protocol.java new file mode 100644 index 000000000..9427876c8 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Xt2400Protocol.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017 - 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. + * 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 org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class Xt2400Protocol extends BaseProtocol { + + public Xt2400Protocol() { + addServer(new TrackerServer(true, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new Xt2400ProtocolDecoder(Xt2400Protocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java new file mode 100644 index 000000000..819011a50 --- /dev/null +++ b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java @@ -0,0 +1,198 @@ +/* + * Copyright 2017 - 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. + * 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 io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Context; +import org.traccar.DeviceSession; +import org.traccar.Protocol; +import org.traccar.helper.DataConverter; +import org.traccar.helper.UnitsConverter; +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.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { + + public Xt2400ProtocolDecoder(Protocol protocol) { + super(protocol); + + String config = Context.getConfig().getString(getProtocolName() + ".config"); + if (config != null) { + setConfig(config); + } + } + + private static final Map TAG_LENGTH_MAP = new HashMap<>(); + + static { + int[] l1 = { + 0x01, 0x02, 0x04, 0x0b, 0x0c, 0x0d, 0x12, 0x13, + 0x16, 0x17, 0x1c, 0x1f, 0x23, 0x2c, 0x2d, 0x30, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x40, 0x41, + 0x53, 0x66, 0x69, 0x6a, 0x93, 0x94, 0x96 + }; + int[] l2 = { + 0x05, 0x09, 0x0a, 0x14, 0x15, 0x1d, 0x1e, 0x24, + 0x26, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x57, 0x58, 0x59, 0x5a, 0x6b, 0x6f, 0x7A, + 0x7B, 0x7C, 0x7d, 0x7E, 0x7F, 0x80, 0x81, 0x82, + 0x83, 0x84, 0x85, 0x86 + }; + int[] l4 = { + 0x03, 0x06, 0x07, 0x08, 0x0e, 0x0f, 0x10, 0x11, + 0x18, 0x19, 0x1a, 0x1b, 0x20, 0x21, 0x22, 0x2e, + 0x2f, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x54, 0x55, 0x56, 0x5b, 0x5c, 0x5d, + 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x68, 0x6e, 0x71, + 0x72, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d + }; + for (int i : l1) { + TAG_LENGTH_MAP.put(i, 1); + } + for (int i : l2) { + TAG_LENGTH_MAP.put(i, 2); + } + for (int i : l4) { + TAG_LENGTH_MAP.put(i, 4); + } + TAG_LENGTH_MAP.put(0x95, 24); + } + + private static int getTagLength(int tag) { + Integer length = TAG_LENGTH_MAP.get(tag); + if (length == null) { + throw new IllegalArgumentException("Unknown tag: " + tag); + } + return length; + } + + private Map formats = new HashMap<>(); + + public void setConfig(String configString) { + Pattern pattern = Pattern.compile(":wycfg pcr\\[\\d+\\] ([0-9a-fA-F]{2})[0-9a-fA-F]{2}([0-9a-fA-F]+)"); + Matcher matcher = pattern.matcher(configString); + while (matcher.find()) { + formats.put(Short.parseShort(matcher.group(1), 16), DataConverter.parseHex(matcher.group(2))); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + byte[] format = null; + if (formats.size() > 1) { + format = formats.get(buf.getUnsignedByte(buf.readerIndex())); + } else if (!formats.isEmpty()) { + format = formats.values().iterator().next(); + } + + if (format == null) { + return null; + } + + Position position = new Position(getProtocolName()); + + for (byte tag : format) { + switch (tag) { + case 0x03: + DeviceSession deviceSession = getDeviceSession( + channel, remoteAddress, String.valueOf(buf.readUnsignedInt())); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + break; + case 0x04: + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + break; + case 0x05: + position.set(Position.KEY_INDEX, buf.readUnsignedShort()); + break; + case 0x06: + position.setTime(new Date(buf.readUnsignedInt() * 1000)); + break; + case 0x07: + position.setLatitude(buf.readInt() * 0.000001); + break; + case 0x08: + position.setLongitude(buf.readInt() * 0.000001); + break; + case 0x09: + position.setAltitude(buf.readShort() * 0.1); + break; + case 0x0a: + position.setCourse(buf.readShort() * 0.1); + break; + case 0x0b: + position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); + break; + case 0x10: + position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); + break; + case 0x12: + position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); + break; + case 0x13: + position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); + break; + case 0x14: + position.set(Position.KEY_RSSI, buf.readShort()); + break; + case 0x16: + position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.1); + break; + case 0x17: + position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); + break; + case 0x57: + position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(buf.readUnsignedShort())); + break; + case 0x65: + position.set(Position.KEY_VIN, buf.readSlice(17).toString(StandardCharsets.US_ASCII)); + break; + case 0x73: + position.set(Position.KEY_VERSION_FW, buf.readSlice(16).toString(StandardCharsets.US_ASCII).trim()); + break; + default: + buf.skipBytes(getTagLength(tag)); + break; + } + } + + if (position.getLatitude() != 0 && position.getLongitude() != 0) { + position.setValid(true); + } else { + getLastLocation(position, position.getDeviceTime()); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/protocol/YwtProtocol.java b/src/main/java/org/traccar/protocol/YwtProtocol.java new file mode 100644 index 000000000..c525b75cf --- /dev/null +++ b/src/main/java/org/traccar/protocol/YwtProtocol.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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 io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; + +public class YwtProtocol extends BaseProtocol { + + public YwtProtocol() { + addServer(new TrackerServer(false, getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new LineBasedFrameDecoder(1024)); + pipeline.addLast(new StringEncoder()); + pipeline.addLast(new StringDecoder()); + pipeline.addLast(new YwtProtocolDecoder(YwtProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/YwtProtocolDecoder.java b/src/main/java/org/traccar/protocol/YwtProtocolDecoder.java new file mode 100644 index 000000000..bf5a23fa7 --- /dev/null +++ b/src/main/java/org/traccar/protocol/YwtProtocolDecoder.java @@ -0,0 +1,116 @@ +/* + * Copyright 2013 - 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. + * 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 io.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class YwtProtocolDecoder extends BaseProtocolDecoder { + + public YwtProtocolDecoder(Protocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .expression("%(..),") // type + .number("(d+):") // unit identifier + .number("d+,") // subtype + .number("(dd)(dd)(dd)") // date (yymmdd) + .number("(dd)(dd)(dd),") // time (hhmmss) + .expression("([EW])") + .number("(ddd.d{6}),") // longitude + .expression("([NS])") + .number("(dd.d{6}),") // latitude + .number("(d+)?,") // altitude + .number("(d+),") // speed + .number("(d+),") // course + .number("(d+),") // satellite + .expression("([^,]+),") // report identifier + .expression("([-0-9a-fA-F]+)") // status + .any() + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + // Synchronization + if (sentence.startsWith("%SN") && channel != null) { + int start = sentence.indexOf(':'); + int end = start; + for (int i = 0; i < 4; i++) { + end = sentence.indexOf(',', end + 1); + } + if (end == -1) { + end = sentence.length(); + } + + channel.writeAndFlush(new NetworkMessage("%AT+SN=" + sentence.substring(start, end), remoteAddress)); + return null; + } + + Parser parser = new Parser(PATTERN, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + + String type = parser.next(); + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + position.setTime(parser.nextDateTime()); + + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); + position.setAltitude(parser.nextDouble(0)); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + + int satellites = parser.nextInt(); + position.setValid(satellites != 0); + position.set(Position.KEY_SATELLITES, satellites); + + String reportId = parser.next(); + + position.set(Position.KEY_STATUS, parser.next()); + + // Send response + if ((type.equals("KP") || type.equals("EP")) && channel != null) { + channel.writeAndFlush(new NetworkMessage("%AT+" + type + "=" + reportId + "\r\n", remoteAddress)); + } + + return position; + } + +} diff --git a/src/main/java/org/traccar/reports/Events.java b/src/main/java/org/traccar/reports/Events.java new file mode 100644 index 000000000..66d9e708d --- /dev/null +++ b/src/main/java/org/traccar/reports/Events.java @@ -0,0 +1,133 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; + +import org.apache.poi.ss.util.WorkbookUtil; +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Geofence; +import org.traccar.model.Group; +import org.traccar.model.Maintenance; +import org.traccar.reports.model.DeviceReport; + +public final class Events { + + private Events() { + } + + public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, + Collection types, Date from, Date to) throws SQLException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList result = new ArrayList<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + Collection events = Context.getDataManager().getEvents(deviceId, from, to); + boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS); + for (Event event : events) { + if (all || types.contains(event.getType())) { + long geofenceId = event.getGeofenceId(); + long maintenanceId = event.getMaintenanceId(); + if ((geofenceId == 0 || Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) + && (maintenanceId == 0 + || Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId))) { + result.add(event); + } + } + } + } + return result; + } + + public static void getExcel(OutputStream outputStream, + long userId, Collection deviceIds, Collection groupIds, + Collection types, Date from, Date to) throws SQLException, IOException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList devicesEvents = new ArrayList<>(); + ArrayList sheetNames = new ArrayList<>(); + HashMap geofenceNames = new HashMap<>(); + HashMap maintenanceNames = new HashMap<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + Collection events = Context.getDataManager().getEvents(deviceId, from, to); + boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS); + for (Iterator iterator = events.iterator(); iterator.hasNext();) { + Event event = iterator.next(); + if (all || types.contains(event.getType())) { + long geofenceId = event.getGeofenceId(); + long maintenanceId = event.getMaintenanceId(); + if (geofenceId != 0) { + if (Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) { + Geofence geofence = Context.getGeofenceManager().getById(geofenceId); + if (geofence != null) { + geofenceNames.put(geofenceId, geofence.getName()); + } + } else { + iterator.remove(); + } + } else if (maintenanceId != 0) { + if (Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId)) { + Maintenance maintenance = Context.getMaintenancesManager().getById(maintenanceId); + if (maintenance != null) { + maintenanceNames.put(maintenanceId, maintenance.getName()); + } + } else { + iterator.remove(); + } + } + } else { + iterator.remove(); + } + } + DeviceReport deviceEvents = new DeviceReport(); + Device device = Context.getIdentityManager().getById(deviceId); + deviceEvents.setDeviceName(device.getName()); + sheetNames.add(WorkbookUtil.createSafeSheetName(deviceEvents.getDeviceName())); + if (device.getGroupId() != 0) { + Group group = Context.getGroupsManager().getById(device.getGroupId()); + if (group != null) { + deviceEvents.setGroupName(group.getName()); + } + } + deviceEvents.setObjects(events); + devicesEvents.add(deviceEvents); + } + String templatePath = Context.getConfig().getString("report.templatesPath", + "templates/export/"); + try (InputStream inputStream = new FileInputStream(templatePath + "/events.xlsx")) { + org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + jxlsContext.putVar("devices", devicesEvents); + jxlsContext.putVar("sheetNames", sheetNames); + jxlsContext.putVar("geofenceNames", geofenceNames); + jxlsContext.putVar("maintenanceNames", maintenanceNames); + jxlsContext.putVar("from", from); + jxlsContext.putVar("to", to); + ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); + } + } +} diff --git a/src/main/java/org/traccar/reports/ReportUtils.java b/src/main/java/org/traccar/reports/ReportUtils.java new file mode 100644 index 000000000..3a631e0d9 --- /dev/null +++ b/src/main/java/org/traccar/reports/ReportUtils.java @@ -0,0 +1,378 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports; + +import org.apache.velocity.tools.generic.DateTool; +import org.apache.velocity.tools.generic.NumberTool; +import org.jxls.area.Area; +import org.jxls.builder.xls.XlsCommentAreaBuilder; +import org.jxls.common.CellRef; +import org.jxls.formula.StandardFormulaProcessor; +import org.jxls.transform.Transformer; +import org.jxls.transform.poi.PoiTransformer; +import org.jxls.util.TransformerFactory; +import org.traccar.Context; +import org.traccar.database.DeviceManager; +import org.traccar.database.IdentityManager; +import org.traccar.handler.events.MotionEventHandler; +import org.traccar.model.DeviceState; +import org.traccar.model.Driver; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.reports.model.BaseReport; +import org.traccar.reports.model.StopReport; +import org.traccar.reports.model.TripReport; +import org.traccar.reports.model.TripsConfig; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + +public final class ReportUtils { + + private ReportUtils() { + } + + public static void checkPeriodLimit(Date from, Date to) { + long limit = Context.getConfig().getLong("report.periodLimit") * 1000; + if (limit > 0 && to.getTime() - from.getTime() > limit) { + throw new IllegalArgumentException("Time period exceeds the limit"); + } + } + + public static String getDistanceUnit(long userId) { + return (String) Context.getPermissionsManager().lookupAttribute(userId, "distanceUnit", "km"); + } + + public static String getSpeedUnit(long userId) { + return (String) Context.getPermissionsManager().lookupAttribute(userId, "speedUnit", "kn"); + } + + public static String getVolumeUnit(long userId) { + return (String) Context.getPermissionsManager().lookupAttribute(userId, "volumeUnit", "ltr"); + } + + public static TimeZone getTimezone(long userId) { + String timezone = (String) Context.getPermissionsManager().lookupAttribute(userId, "timezone", null); + return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); + } + + public static Collection getDeviceList(Collection deviceIds, Collection groupIds) { + Collection result = new ArrayList<>(); + result.addAll(deviceIds); + for (long groupId : groupIds) { + result.addAll(Context.getPermissionsManager().getGroupDevices(groupId)); + } + return result; + } + + public static double calculateDistance(Position firstPosition, Position lastPosition) { + return calculateDistance(firstPosition, lastPosition, true); + } + + public static double calculateDistance(Position firstPosition, Position lastPosition, boolean useOdometer) { + double distance = 0.0; + double firstOdometer = firstPosition.getDouble(Position.KEY_ODOMETER); + double lastOdometer = lastPosition.getDouble(Position.KEY_ODOMETER); + + if (useOdometer && (firstOdometer != 0.0 || lastOdometer != 0.0)) { + distance = lastOdometer - firstOdometer; + } else if (firstPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE) + && lastPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) { + distance = lastPosition.getDouble(Position.KEY_TOTAL_DISTANCE) + - firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE); + } + return distance; + } + + public static double calculateFuel(Position firstPosition, Position lastPosition) { + + if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null + && lastPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null) { + + BigDecimal value = new BigDecimal(firstPosition.getDouble(Position.KEY_FUEL_LEVEL) + - lastPosition.getDouble(Position.KEY_FUEL_LEVEL)); + return value.setScale(1, RoundingMode.HALF_EVEN).doubleValue(); + } + return 0; + } + + public static String findDriver(Position firstPosition, Position lastPosition) { + if (firstPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { + return firstPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); + } else if (lastPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { + return lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); + } + return null; + } + + public static String findDriverName(String driverUniqueId) { + if (driverUniqueId != null && Context.getDriversManager() != null) { + Driver driver = Context.getDriversManager().getDriverByUniqueId(driverUniqueId); + if (driver != null) { + return driver.getName(); + } + } + return null; + } + + public static org.jxls.common.Context initializeContext(long userId) { + org.jxls.common.Context jxlsContext = PoiTransformer.createInitialContext(); + jxlsContext.putVar("distanceUnit", getDistanceUnit(userId)); + jxlsContext.putVar("speedUnit", getSpeedUnit(userId)); + jxlsContext.putVar("volumeUnit", getVolumeUnit(userId)); + jxlsContext.putVar("webUrl", Context.getVelocityEngine().getProperty("web.url")); + jxlsContext.putVar("dateTool", new DateTool()); + jxlsContext.putVar("numberTool", new NumberTool()); + jxlsContext.putVar("timezone", getTimezone(userId)); + jxlsContext.putVar("locale", Locale.getDefault()); + jxlsContext.putVar("bracketsRegex", "[\\{\\}\"]"); + return jxlsContext; + } + + public static void processTemplateWithSheets( + InputStream templateStream, OutputStream targetStream, + org.jxls.common.Context jxlsContext) throws IOException { + + Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream); + List xlsAreas = new XlsCommentAreaBuilder(transformer).build(); + for (Area xlsArea : xlsAreas) { + xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), jxlsContext); + xlsArea.setFormulaProcessor(new StandardFormulaProcessor()); + xlsArea.processFormulas(); + } + transformer.deleteSheet(xlsAreas.get(0).getStartCellRef().getSheetName()); + transformer.write(); + } + + private static TripReport calculateTrip( + ArrayList positions, int startIndex, int endIndex, boolean ignoreOdometer) { + + Position startTrip = positions.get(startIndex); + Position endTrip = positions.get(endIndex); + + double speedMax = 0.0; + double speedSum = 0.0; + for (int i = startIndex; i <= endIndex; i++) { + double speed = positions.get(i).getSpeed(); + speedSum += speed; + if (speed > speedMax) { + speedMax = speed; + } + } + + TripReport trip = new TripReport(); + + long tripDuration = endTrip.getFixTime().getTime() - startTrip.getFixTime().getTime(); + long deviceId = startTrip.getDeviceId(); + trip.setDeviceId(deviceId); + trip.setDeviceName(Context.getIdentityManager().getById(deviceId).getName()); + + trip.setStartPositionId(startTrip.getId()); + trip.setStartLat(startTrip.getLatitude()); + trip.setStartLon(startTrip.getLongitude()); + trip.setStartTime(startTrip.getFixTime()); + String startAddress = startTrip.getAddress(); + if (startAddress == null && Context.getGeocoder() != null + && Context.getConfig().getBoolean("geocoder.onRequest")) { + startAddress = Context.getGeocoder().getAddress(startTrip.getLatitude(), startTrip.getLongitude(), null); + } + trip.setStartAddress(startAddress); + + trip.setEndPositionId(endTrip.getId()); + trip.setEndLat(endTrip.getLatitude()); + trip.setEndLon(endTrip.getLongitude()); + trip.setEndTime(endTrip.getFixTime()); + String endAddress = endTrip.getAddress(); + if (endAddress == null && Context.getGeocoder() != null + && Context.getConfig().getBoolean("geocoder.onRequest")) { + endAddress = Context.getGeocoder().getAddress(endTrip.getLatitude(), endTrip.getLongitude(), null); + } + trip.setEndAddress(endAddress); + + trip.setDistance(calculateDistance(startTrip, endTrip, !ignoreOdometer)); + trip.setDuration(tripDuration); + trip.setAverageSpeed(speedSum / (endIndex - startIndex)); + trip.setMaxSpeed(speedMax); + trip.setSpentFuel(calculateFuel(startTrip, endTrip)); + + trip.setDriverUniqueId(findDriver(startTrip, endTrip)); + trip.setDriverName(findDriverName(trip.getDriverUniqueId())); + + if (!ignoreOdometer + && startTrip.getDouble(Position.KEY_ODOMETER) != 0 + && endTrip.getDouble(Position.KEY_ODOMETER) != 0) { + trip.setStartOdometer(startTrip.getDouble(Position.KEY_ODOMETER)); + trip.setEndOdometer(endTrip.getDouble(Position.KEY_ODOMETER)); + } else { + trip.setStartOdometer(startTrip.getDouble(Position.KEY_TOTAL_DISTANCE)); + trip.setEndOdometer(endTrip.getDouble(Position.KEY_TOTAL_DISTANCE)); + } + + return trip; + } + + private static StopReport calculateStop( + ArrayList positions, int startIndex, int endIndex, boolean ignoreOdometer) { + + Position startStop = positions.get(startIndex); + Position endStop = positions.get(endIndex); + + StopReport stop = new StopReport(); + + long deviceId = startStop.getDeviceId(); + stop.setDeviceId(deviceId); + stop.setDeviceName(Context.getIdentityManager().getById(deviceId).getName()); + + stop.setPositionId(startStop.getId()); + stop.setLatitude(startStop.getLatitude()); + stop.setLongitude(startStop.getLongitude()); + stop.setStartTime(startStop.getFixTime()); + String address = startStop.getAddress(); + if (address == null && Context.getGeocoder() != null + && Context.getConfig().getBoolean("geocoder.onRequest")) { + address = Context.getGeocoder().getAddress(stop.getLatitude(), stop.getLongitude(), null); + } + stop.setAddress(address); + + stop.setEndTime(endStop.getFixTime()); + + long stopDuration = endStop.getFixTime().getTime() - startStop.getFixTime().getTime(); + stop.setDuration(stopDuration); + stop.setSpentFuel(calculateFuel(startStop, endStop)); + + long engineHours = 0; + if (startStop.getAttributes().containsKey(Position.KEY_HOURS) + && endStop.getAttributes().containsKey(Position.KEY_HOURS)) { + engineHours = endStop.getLong(Position.KEY_HOURS) - startStop.getLong(Position.KEY_HOURS); + } else if (Context.getConfig().getBoolean("processing.engineHours.enable")) { + // Temporary fallback for old data, to be removed in May 2019 + for (int i = startIndex + 1; i <= endIndex; i++) { + if (positions.get(i).getBoolean(Position.KEY_IGNITION) + && positions.get(i - 1).getBoolean(Position.KEY_IGNITION)) { + engineHours += positions.get(i).getFixTime().getTime() + - positions.get(i - 1).getFixTime().getTime(); + } + } + } + stop.setEngineHours(engineHours); + + if (!ignoreOdometer + && startStop.getDouble(Position.KEY_ODOMETER) != 0 + && endStop.getDouble(Position.KEY_ODOMETER) != 0) { + stop.setStartOdometer(startStop.getDouble(Position.KEY_ODOMETER)); + stop.setEndOdometer(endStop.getDouble(Position.KEY_ODOMETER)); + } else { + stop.setStartOdometer(startStop.getDouble(Position.KEY_TOTAL_DISTANCE)); + stop.setEndOdometer(endStop.getDouble(Position.KEY_TOTAL_DISTANCE)); + } + + return stop; + + } + + private static T calculateTripOrStop( + ArrayList positions, int startIndex, int endIndex, boolean ignoreOdometer, Class reportClass) { + + if (reportClass.equals(TripReport.class)) { + return (T) calculateTrip(positions, startIndex, endIndex, ignoreOdometer); + } else { + return (T) calculateStop(positions, startIndex, endIndex, ignoreOdometer); + } + } + + private static boolean isMoving(ArrayList positions, int index, TripsConfig tripsConfig) { + if (tripsConfig.getMinimalNoDataDuration() > 0) { + boolean beforeGap = index < positions.size() - 1 + && positions.get(index + 1).getFixTime().getTime() - positions.get(index).getFixTime().getTime() + >= tripsConfig.getMinimalNoDataDuration(); + boolean afterGap = index > 0 + && positions.get(index).getFixTime().getTime() - positions.get(index - 1).getFixTime().getTime() + >= tripsConfig.getMinimalNoDataDuration(); + if (beforeGap || afterGap) { + return false; + } + } + if (positions.get(index).getAttributes().containsKey(Position.KEY_MOTION) + && positions.get(index).getAttributes().get(Position.KEY_MOTION) instanceof Boolean) { + return positions.get(index).getBoolean(Position.KEY_MOTION); + } else { + return positions.get(index).getSpeed() > tripsConfig.getSpeedThreshold(); + } + } + + public static Collection detectTripsAndStops( + IdentityManager identityManager, DeviceManager deviceManager, + Collection positionCollection, + TripsConfig tripsConfig, boolean ignoreOdometer, Class reportClass) { + + Collection result = new ArrayList<>(); + + ArrayList positions = new ArrayList<>(positionCollection); + if (!positions.isEmpty()) { + boolean trips = reportClass.equals(TripReport.class); + MotionEventHandler motionHandler = new MotionEventHandler(identityManager, deviceManager, tripsConfig); + DeviceState deviceState = new DeviceState(); + deviceState.setMotionState(isMoving(positions, 0, tripsConfig)); + int startEventIndex = trips == deviceState.getMotionState() ? 0 : -1; + int startNoEventIndex = -1; + for (int i = 0; i < positions.size(); i++) { + Map event = motionHandler.updateMotionState(deviceState, positions.get(i), + isMoving(positions, i, tripsConfig)); + if (startEventIndex == -1 + && (trips != deviceState.getMotionState() && deviceState.getMotionPosition() != null + || trips == deviceState.getMotionState() && event != null)) { + startEventIndex = i; + startNoEventIndex = -1; + } else if (trips != deviceState.getMotionState() && startEventIndex != -1 + && deviceState.getMotionPosition() == null && event == null) { + startEventIndex = -1; + } + if (startNoEventIndex == -1 + && (trips == deviceState.getMotionState() && deviceState.getMotionPosition() != null + || trips != deviceState.getMotionState() && event != null)) { + startNoEventIndex = i; + } else if (startNoEventIndex != -1 && deviceState.getMotionPosition() == null && event == null) { + startNoEventIndex = -1; + } + if (startEventIndex != -1 && startNoEventIndex != -1 && event != null + && trips != deviceState.getMotionState()) { + result.add(calculateTripOrStop(positions, startEventIndex, startNoEventIndex, + ignoreOdometer, reportClass)); + startEventIndex = -1; + } + } + if (startEventIndex != -1 && (startNoEventIndex != -1 || !trips)) { + result.add(calculateTripOrStop(positions, startEventIndex, + startNoEventIndex != -1 ? startNoEventIndex : positions.size() - 1, + ignoreOdometer, reportClass)); + } + } + + return result; + } + +} diff --git a/src/main/java/org/traccar/reports/Route.java b/src/main/java/org/traccar/reports/Route.java new file mode 100644 index 000000000..6adb00aae --- /dev/null +++ b/src/main/java/org/traccar/reports/Route.java @@ -0,0 +1,85 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import org.apache.poi.ss.util.WorkbookUtil; +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Group; +import org.traccar.model.Position; +import org.traccar.reports.model.DeviceReport; + +public final class Route { + + private Route() { + } + + public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList result = new ArrayList<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + result.addAll(Context.getDataManager().getPositions(deviceId, from, to)); + } + return result; + } + + public static void getExcel(OutputStream outputStream, + long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException, IOException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList devicesRoutes = new ArrayList<>(); + ArrayList sheetNames = new ArrayList<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + Collection positions = Context.getDataManager() + .getPositions(deviceId, from, to); + DeviceReport deviceRoutes = new DeviceReport(); + Device device = Context.getIdentityManager().getById(deviceId); + deviceRoutes.setDeviceName(device.getName()); + sheetNames.add(WorkbookUtil.createSafeSheetName(deviceRoutes.getDeviceName())); + if (device.getGroupId() != 0) { + Group group = Context.getGroupsManager().getById(device.getGroupId()); + if (group != null) { + deviceRoutes.setGroupName(group.getName()); + } + } + deviceRoutes.setObjects(positions); + devicesRoutes.add(deviceRoutes); + } + String templatePath = Context.getConfig().getString("report.templatesPath", + "templates/export/"); + try (InputStream inputStream = new FileInputStream(templatePath + "/route.xlsx")) { + org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + jxlsContext.putVar("devices", devicesRoutes); + jxlsContext.putVar("sheetNames", sheetNames); + jxlsContext.putVar("from", from); + jxlsContext.putVar("to", to); + ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); + } + } +} diff --git a/src/main/java/org/traccar/reports/Stops.java b/src/main/java/org/traccar/reports/Stops.java new file mode 100644 index 000000000..98c9cef00 --- /dev/null +++ b/src/main/java/org/traccar/reports/Stops.java @@ -0,0 +1,102 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import org.apache.poi.ss.util.WorkbookUtil; +import org.traccar.Context; +import org.traccar.Main; +import org.traccar.database.DeviceManager; +import org.traccar.database.IdentityManager; +import org.traccar.model.Device; +import org.traccar.model.Group; +import org.traccar.reports.model.DeviceReport; +import org.traccar.reports.model.StopReport; + +public final class Stops { + + private Stops() { + } + + private static Collection detectStops(long deviceId, Date from, Date to) throws SQLException { + boolean ignoreOdometer = Context.getDeviceManager() + .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); + + IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); + DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); + + return ReportUtils.detectTripsAndStops( + identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to), + Context.getTripsConfig(), ignoreOdometer, StopReport.class); + } + + public static Collection getObjects( + long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList result = new ArrayList<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + result.addAll(detectStops(deviceId, from, to)); + } + return result; + } + + public static void getExcel( + OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException, IOException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList devicesStops = new ArrayList<>(); + ArrayList sheetNames = new ArrayList<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + Collection stops = detectStops(deviceId, from, to); + DeviceReport deviceStops = new DeviceReport(); + Device device = Context.getIdentityManager().getById(deviceId); + deviceStops.setDeviceName(device.getName()); + sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName())); + if (device.getGroupId() != 0) { + Group group = Context.getGroupsManager().getById(device.getGroupId()); + if (group != null) { + deviceStops.setGroupName(group.getName()); + } + } + deviceStops.setObjects(stops); + devicesStops.add(deviceStops); + } + String templatePath = Context.getConfig().getString("report.templatesPath", + "templates/export/"); + try (InputStream inputStream = new FileInputStream(templatePath + "/stops.xlsx")) { + org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + jxlsContext.putVar("devices", devicesStops); + jxlsContext.putVar("sheetNames", sheetNames); + jxlsContext.putVar("from", from); + jxlsContext.putVar("to", to); + ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); + } + } + +} diff --git a/src/main/java/org/traccar/reports/Summary.java b/src/main/java/org/traccar/reports/Summary.java new file mode 100644 index 000000000..9810424d8 --- /dev/null +++ b/src/main/java/org/traccar/reports/Summary.java @@ -0,0 +1,117 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import org.jxls.util.JxlsHelper; +import org.traccar.Context; +import org.traccar.model.Position; +import org.traccar.reports.model.SummaryReport; + +public final class Summary { + + private Summary() { + } + + private static SummaryReport calculateSummaryResult(long deviceId, Date from, Date to) throws SQLException { + SummaryReport result = new SummaryReport(); + result.setDeviceId(deviceId); + result.setDeviceName(Context.getIdentityManager().getById(deviceId).getName()); + Collection positions = Context.getDataManager().getPositions(deviceId, from, to); + if (positions != null && !positions.isEmpty()) { + Position firstPosition = null; + Position previousPosition = null; + double speedSum = 0; + boolean engineHoursEnabled = Context.getConfig().getBoolean("processing.engineHours.enable"); + for (Position position : positions) { + if (firstPosition == null) { + firstPosition = position; + } + if (engineHoursEnabled && previousPosition != null + && position.getBoolean(Position.KEY_IGNITION) + && previousPosition.getBoolean(Position.KEY_IGNITION)) { + // Temporary fallback for old data, to be removed in May 2019 + result.addEngineHours(position.getFixTime().getTime() + - previousPosition.getFixTime().getTime()); + } + previousPosition = position; + speedSum += position.getSpeed(); + result.setMaxSpeed(position.getSpeed()); + } + boolean ignoreOdometer = Context.getDeviceManager() + .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); + result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer)); + result.setAverageSpeed(speedSum / positions.size()); + result.setSpentFuel(ReportUtils.calculateFuel(firstPosition, previousPosition)); + + if (engineHoursEnabled + && firstPosition.getAttributes().containsKey(Position.KEY_HOURS) + && previousPosition.getAttributes().containsKey(Position.KEY_HOURS)) { + result.setEngineHours( + previousPosition.getLong(Position.KEY_HOURS) - firstPosition.getLong(Position.KEY_HOURS)); + } + + if (!ignoreOdometer + && firstPosition.getDouble(Position.KEY_ODOMETER) != 0 + && previousPosition.getDouble(Position.KEY_ODOMETER) != 0) { + result.setStartOdometer(firstPosition.getDouble(Position.KEY_ODOMETER)); + result.setEndOdometer(previousPosition.getDouble(Position.KEY_ODOMETER)); + } else { + result.setStartOdometer(firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE)); + result.setEndOdometer(previousPosition.getDouble(Position.KEY_TOTAL_DISTANCE)); + } + + } + return result; + } + + public static Collection getObjects(long userId, Collection deviceIds, + Collection groupIds, Date from, Date to) throws SQLException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList result = new ArrayList<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + result.add(calculateSummaryResult(deviceId, from, to)); + } + return result; + } + + public static void getExcel(OutputStream outputStream, + long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException, IOException { + ReportUtils.checkPeriodLimit(from, to); + Collection summaries = getObjects(userId, deviceIds, groupIds, from, to); + String templatePath = Context.getConfig().getString("report.templatesPath", + "templates/export/"); + try (InputStream inputStream = new FileInputStream(templatePath + "/summary.xlsx")) { + org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + jxlsContext.putVar("summaries", summaries); + jxlsContext.putVar("from", from); + jxlsContext.putVar("to", to); + JxlsHelper.getInstance().setUseFastFormulaProcessor(false) + .processTemplate(inputStream, outputStream, jxlsContext); + } + } +} diff --git a/src/main/java/org/traccar/reports/Trips.java b/src/main/java/org/traccar/reports/Trips.java new file mode 100644 index 000000000..3cda65553 --- /dev/null +++ b/src/main/java/org/traccar/reports/Trips.java @@ -0,0 +1,100 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import org.apache.poi.ss.util.WorkbookUtil; +import org.traccar.Context; +import org.traccar.Main; +import org.traccar.database.DeviceManager; +import org.traccar.database.IdentityManager; +import org.traccar.model.Device; +import org.traccar.model.Group; +import org.traccar.reports.model.DeviceReport; +import org.traccar.reports.model.TripReport; + +public final class Trips { + + private Trips() { + } + + private static Collection detectTrips(long deviceId, Date from, Date to) throws SQLException { + boolean ignoreOdometer = Context.getDeviceManager() + .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); + + IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); + DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); + + return ReportUtils.detectTripsAndStops( + identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to), + Context.getTripsConfig(), ignoreOdometer, TripReport.class); + } + + public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList result = new ArrayList<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + result.addAll(detectTrips(deviceId, from, to)); + } + return result; + } + + public static void getExcel(OutputStream outputStream, + long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException, IOException { + ReportUtils.checkPeriodLimit(from, to); + ArrayList devicesTrips = new ArrayList<>(); + ArrayList sheetNames = new ArrayList<>(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + Collection trips = detectTrips(deviceId, from, to); + DeviceReport deviceTrips = new DeviceReport(); + Device device = Context.getIdentityManager().getById(deviceId); + deviceTrips.setDeviceName(device.getName()); + sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName())); + if (device.getGroupId() != 0) { + Group group = Context.getGroupsManager().getById(device.getGroupId()); + if (group != null) { + deviceTrips.setGroupName(group.getName()); + } + } + deviceTrips.setObjects(trips); + devicesTrips.add(deviceTrips); + } + String templatePath = Context.getConfig().getString("report.templatesPath", + "templates/export/"); + try (InputStream inputStream = new FileInputStream(templatePath + "/trips.xlsx")) { + org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + jxlsContext.putVar("devices", devicesTrips); + jxlsContext.putVar("sheetNames", sheetNames); + jxlsContext.putVar("from", from); + jxlsContext.putVar("to", to); + ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); + } + } + +} diff --git a/src/main/java/org/traccar/reports/model/BaseReport.java b/src/main/java/org/traccar/reports/model/BaseReport.java new file mode 100644 index 000000000..9f2d1188c --- /dev/null +++ b/src/main/java/org/traccar/reports/model/BaseReport.java @@ -0,0 +1,106 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports.model; + +public class BaseReport { + + private long deviceId; + + public long getDeviceId() { + return deviceId; + } + + public void setDeviceId(long deviceId) { + this.deviceId = deviceId; + } + + private String deviceName; + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + private double distance; + + public double getDistance() { + return distance; + } + + public void setDistance(double distance) { + this.distance = distance; + } + + public void addDistance(double distance) { + this.distance += distance; + } + + private double averageSpeed; + + public double getAverageSpeed() { + return averageSpeed; + } + + public void setAverageSpeed(Double averageSpeed) { + this.averageSpeed = averageSpeed; + } + + private double maxSpeed; + + public double getMaxSpeed() { + return maxSpeed; + } + + public void setMaxSpeed(double maxSpeed) { + if (maxSpeed > this.maxSpeed) { + this.maxSpeed = maxSpeed; + } + } + + private double spentFuel; + + public double getSpentFuel() { + return spentFuel; + } + + public void setSpentFuel(double spentFuel) { + this.spentFuel = spentFuel; + } + + private double startOdometer; + + public double getStartOdometer() { + return startOdometer; + } + + public void setStartOdometer(double startOdometer) { + this.startOdometer = startOdometer; + } + private double endOdometer; + + public double getEndOdometer() { + return endOdometer; + } + + public void setEndOdometer(double endOdometer) { + this.endOdometer = endOdometer; + } + +} diff --git a/src/main/java/org/traccar/reports/model/DeviceReport.java b/src/main/java/org/traccar/reports/model/DeviceReport.java new file mode 100644 index 000000000..932753d15 --- /dev/null +++ b/src/main/java/org/traccar/reports/model/DeviceReport.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class DeviceReport { + + private String deviceName; + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + private String groupName = ""; + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + private List objects; + + public Collection getObjects() { + return objects; + } + + public void setObjects(Collection objects) { + this.objects = new ArrayList<>(objects); + } + +} diff --git a/src/main/java/org/traccar/reports/model/StopReport.java b/src/main/java/org/traccar/reports/model/StopReport.java new file mode 100644 index 000000000..245292b63 --- /dev/null +++ b/src/main/java/org/traccar/reports/model/StopReport.java @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports.model; + +import java.util.Date; + +public class StopReport extends BaseReport { + + private long positionId; + + public long getPositionId() { + return positionId; + } + + public void setPositionId(long positionId) { + this.positionId = positionId; + } + + private double latitude; + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + private double longitude; + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + private Date startTime; + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + private Date endTime; + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + private String address; + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + private long duration; + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + private long engineHours; // milliseconds + + public long getEngineHours() { + return engineHours; + } + + public void setEngineHours(long engineHours) { + this.engineHours = engineHours; + } + + public void addEngineHours(long engineHours) { + this.engineHours += engineHours; + } +} diff --git a/src/main/java/org/traccar/reports/model/SummaryReport.java b/src/main/java/org/traccar/reports/model/SummaryReport.java new file mode 100644 index 000000000..6f9e9459f --- /dev/null +++ b/src/main/java/org/traccar/reports/model/SummaryReport.java @@ -0,0 +1,34 @@ +/* + * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports.model; + +public class SummaryReport extends BaseReport { + + private long engineHours; // milliseconds + + public long getEngineHours() { + return engineHours; + } + + public void setEngineHours(long engineHours) { + this.engineHours = engineHours; + } + + public void addEngineHours(long engineHours) { + this.engineHours += engineHours; + } +} diff --git a/src/main/java/org/traccar/reports/model/TripReport.java b/src/main/java/org/traccar/reports/model/TripReport.java new file mode 100644 index 000000000..3140f3019 --- /dev/null +++ b/src/main/java/org/traccar/reports/model/TripReport.java @@ -0,0 +1,152 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports.model; + +import java.util.Date; + +public class TripReport extends BaseReport { + + private long startPositionId; + + public long getStartPositionId() { + return startPositionId; + } + + public void setStartPositionId(long startPositionId) { + this.startPositionId = startPositionId; + } + + private long endPositionId; + + public long getEndPositionId() { + return endPositionId; + } + + public void setEndPositionId(long endPositionId) { + this.endPositionId = endPositionId; + } + + private double startLat; + + public double getStartLat() { + return startLat; + } + + public void setStartLat(double startLat) { + this.startLat = startLat; + } + + private double startLon; + + public double getStartLon() { + return startLon; + } + + public void setStartLon(double startLon) { + this.startLon = startLon; + } + + private double endLat; + + public double getEndLat() { + return endLat; + } + + public void setEndLat(double endLat) { + this.endLat = endLat; + } + + private double endLon; + + public double getEndLon() { + return endLon; + } + + public void setEndLon(double endLon) { + this.endLon = endLon; + } + + private Date startTime; + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + private String startAddress; + + public String getStartAddress() { + return startAddress; + } + + public void setStartAddress(String address) { + this.startAddress = address; + } + + private Date endTime; + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + private String endAddress; + + public String getEndAddress() { + return endAddress; + } + + public void setEndAddress(String address) { + this.endAddress = address; + } + + private long duration; + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + private String driverUniqueId; + + public String getDriverUniqueId() { + return driverUniqueId; + } + + public void setDriverUniqueId(String driverUniqueId) { + this.driverUniqueId = driverUniqueId; + } + + private String driverName; + + public String getDriverName() { + return driverName; + } + + public void setDriverName(String driverName) { + this.driverName = driverName; + } +} diff --git a/src/main/java/org/traccar/reports/model/TripsConfig.java b/src/main/java/org/traccar/reports/model/TripsConfig.java new file mode 100644 index 000000000..0f0c615d3 --- /dev/null +++ b/src/main/java/org/traccar/reports/model/TripsConfig.java @@ -0,0 +1,105 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.reports.model; + +public class TripsConfig { + + public TripsConfig() { + } + + public TripsConfig(double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration, + long minimalNoDataDuration, boolean useIgnition, boolean processInvalidPositions, double speedThreshold) { + this.minimalTripDistance = minimalTripDistance; + this.minimalTripDuration = minimalTripDuration; + this.minimalParkingDuration = minimalParkingDuration; + this.minimalNoDataDuration = minimalNoDataDuration; + this.useIgnition = useIgnition; + this.processInvalidPositions = processInvalidPositions; + this.speedThreshold = speedThreshold; + } + + private double minimalTripDistance; + + public double getMinimalTripDistance() { + return minimalTripDistance; + } + + public void setMinimalTripDistance(double minimalTripDistance) { + this.minimalTripDistance = minimalTripDistance; + } + + private long minimalTripDuration; + + public long getMinimalTripDuration() { + return minimalTripDuration; + } + + public void setMinimalTripDuration(long minimalTripDuration) { + this.minimalTripDuration = minimalTripDuration; + } + + private long minimalParkingDuration; + + public long getMinimalParkingDuration() { + return minimalParkingDuration; + } + + public void setMinimalParkingDuration(long minimalParkingDuration) { + this.minimalParkingDuration = minimalParkingDuration; + } + + private long minimalNoDataDuration; + + public long getMinimalNoDataDuration() { + return minimalNoDataDuration; + } + + public void setMinimalNoDataDuration(long minimalNoDataDuration) { + this.minimalNoDataDuration = minimalNoDataDuration; + } + + private boolean useIgnition; + + public boolean getUseIgnition() { + return useIgnition; + } + + public void setUseIgnition(boolean useIgnition) { + this.useIgnition = useIgnition; + } + + private boolean processInvalidPositions; + + public boolean getProcessInvalidPositions() { + return processInvalidPositions; + } + + public void setProcessInvalidPositions(boolean processInvalidPositions) { + this.processInvalidPositions = processInvalidPositions; + } + + private double speedThreshold; + + public double getSpeedThreshold() { + return speedThreshold; + } + + public void setSpeedThreshold(double speedThreshold) { + this.speedThreshold = speedThreshold; + } + +} diff --git a/src/main/java/org/traccar/sms/HttpSmsClient.java b/src/main/java/org/traccar/sms/HttpSmsClient.java new file mode 100644 index 000000000..8e2b67bf7 --- /dev/null +++ b/src/main/java/org/traccar/sms/HttpSmsClient.java @@ -0,0 +1,110 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.sms; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.InvocationCallback; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.api.SecurityRequestFilter; +import org.traccar.helper.DataConverter; +import org.traccar.notification.MessageException; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +public class HttpSmsClient implements SmsManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(HttpSmsClient.class); + + private String url; + private String authorizationHeader; + private String authorization; + private String template; + private boolean encode; + private MediaType mediaType; + + public HttpSmsClient() { + url = Context.getConfig().getString("sms.http.url"); + authorizationHeader = Context.getConfig().getString("sms.http.authorizationHeader", + SecurityRequestFilter.AUTHORIZATION_HEADER); + authorization = Context.getConfig().getString("sms.http.authorization"); + if (authorization == null) { + String user = Context.getConfig().getString("sms.http.user"); + String password = Context.getConfig().getString("sms.http.password"); + authorization = "Basic " + + DataConverter.printBase64((user + ":" + password).getBytes(StandardCharsets.UTF_8)); + } + template = Context.getConfig().getString("sms.http.template").trim(); + if (template.charAt(0) == '{' || template.charAt(0) == '[') { + encode = false; + mediaType = MediaType.APPLICATION_JSON_TYPE; + } else { + encode = true; + mediaType = MediaType.APPLICATION_FORM_URLENCODED_TYPE; + } + } + + private String prepareValue(String value) throws UnsupportedEncodingException { + return encode ? URLEncoder.encode(value, StandardCharsets.UTF_8.name()) : value; + } + + private String preparePayload(String destAddress, String message) { + try { + return template + .replace("{phone}", prepareValue(destAddress)) + .replace("{message}", prepareValue(message.trim())); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + private Invocation.Builder getRequestBuilder() { + return Context.getClient().target(url).request() + .header(authorizationHeader, authorization); + } + + @Override + public void sendMessageSync(String destAddress, String message, boolean command) throws MessageException { + Response response = getRequestBuilder().post(Entity.entity(preparePayload(destAddress, message), mediaType)); + if (response.getStatus() / 100 != 2) { + throw new MessageException(response.readEntity(String.class)); + } + } + + @Override + public void sendMessageAsync(final String destAddress, final String message, final boolean command) { + getRequestBuilder().async().post( + Entity.entity(preparePayload(destAddress, message), mediaType), new InvocationCallback() { + @Override + public void completed(String s) { + } + + @Override + public void failed(Throwable throwable) { + LOGGER.warn("SMS send failed", throwable); + } + }); + } + +} diff --git a/src/main/java/org/traccar/sms/SmsManager.java b/src/main/java/org/traccar/sms/SmsManager.java new file mode 100644 index 000000000..3b0cbda7f --- /dev/null +++ b/src/main/java/org/traccar/sms/SmsManager.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.sms; + +import org.traccar.notification.MessageException; + +public interface SmsManager { + + void sendMessageSync( + String destAddress, String message, boolean command) throws InterruptedException, MessageException; + + void sendMessageAsync( + String destAddress, String message, boolean command); + +} diff --git a/src/main/java/org/traccar/sms/smpp/ClientSmppSessionHandler.java b/src/main/java/org/traccar/sms/smpp/ClientSmppSessionHandler.java new file mode 100644 index 000000000..6b9de3107 --- /dev/null +++ b/src/main/java/org/traccar/sms/smpp/ClientSmppSessionHandler.java @@ -0,0 +1,82 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.sms.smpp; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.cloudhopper.commons.charset.CharsetUtil; +import com.cloudhopper.smpp.SmppConstants; +import com.cloudhopper.smpp.impl.DefaultSmppSessionHandler; +import com.cloudhopper.smpp.pdu.DeliverSm; +import com.cloudhopper.smpp.pdu.PduRequest; +import com.cloudhopper.smpp.pdu.PduResponse; +import com.cloudhopper.smpp.util.SmppUtil; + +public class ClientSmppSessionHandler extends DefaultSmppSessionHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(ClientSmppSessionHandler.class); + + private SmppClient smppClient; + + public ClientSmppSessionHandler(SmppClient smppClient) { + this.smppClient = smppClient; + } + + @Override + public void firePduRequestExpired(PduRequest pduRequest) { + LOGGER.warn("PDU request expired: " + pduRequest); + } + + @Override + public PduResponse firePduRequestReceived(PduRequest request) { + PduResponse response; + try { + if (request instanceof DeliverSm) { + String sourceAddress = ((DeliverSm) request).getSourceAddress().getAddress(); + String message = CharsetUtil.decode(((DeliverSm) request).getShortMessage(), + smppClient.mapDataCodingToCharset(((DeliverSm) request).getDataCoding())); + LOGGER.info("SMS Message Received: " + message.trim() + ", Source Address: " + sourceAddress); + + boolean isDeliveryReceipt; + if (smppClient.getDetectDlrByOpts()) { + isDeliveryReceipt = request.getOptionalParameters() != null; + } else { + isDeliveryReceipt = SmppUtil.isMessageTypeAnyDeliveryReceipt(((DeliverSm) request).getEsmClass()); + } + + if (!isDeliveryReceipt) { + TextMessageEventHandler.handleTextMessage(sourceAddress, message); + } + } + response = request.createResponse(); + } catch (Exception error) { + LOGGER.warn("SMS receiving error", error); + response = request.createResponse(); + response.setResultMessage(error.getMessage()); + response.setCommandStatus(SmppConstants.STATUS_UNKNOWNERR); + } + return response; + } + + @Override + public void fireChannelUnexpectedlyClosed() { + LOGGER.warn("SMPP session channel unexpectedly closed"); + smppClient.scheduleReconnect(); + } + +} diff --git a/src/main/java/org/traccar/sms/smpp/EnquireLinkTask.java b/src/main/java/org/traccar/sms/smpp/EnquireLinkTask.java new file mode 100644 index 000000000..7086709d7 --- /dev/null +++ b/src/main/java/org/traccar/sms/smpp/EnquireLinkTask.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.sms.smpp; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.cloudhopper.smpp.SmppSession; +import com.cloudhopper.smpp.pdu.EnquireLink; +import com.cloudhopper.smpp.type.RecoverablePduException; +import com.cloudhopper.smpp.type.SmppChannelException; +import com.cloudhopper.smpp.type.SmppTimeoutException; +import com.cloudhopper.smpp.type.UnrecoverablePduException; + +public class EnquireLinkTask implements Runnable { + + private static final Logger LOGGER = LoggerFactory.getLogger(EnquireLinkTask.class); + + private SmppClient smppClient; + private Integer enquireLinkTimeout; + + public EnquireLinkTask(SmppClient smppClient, Integer enquireLinkTimeout) { + this.smppClient = smppClient; + this.enquireLinkTimeout = enquireLinkTimeout; + } + + @Override + public void run() { + SmppSession smppSession = smppClient.getSession(); + if (smppSession != null && smppSession.isBound()) { + try { + smppSession.enquireLink(new EnquireLink(), enquireLinkTimeout); + } catch (SmppTimeoutException | SmppChannelException + | RecoverablePduException | UnrecoverablePduException error) { + LOGGER.warn("Enquire link failed, executing reconnect: ", error); + smppClient.scheduleReconnect(); + } catch (InterruptedException error) { + LOGGER.info("Enquire link interrupted, probably killed by reconnecting"); + } + } else { + LOGGER.warn("Enquire link running while session is not connected"); + } + } + +} diff --git a/src/main/java/org/traccar/sms/smpp/ReconnectionTask.java b/src/main/java/org/traccar/sms/smpp/ReconnectionTask.java new file mode 100644 index 000000000..c009de8e7 --- /dev/null +++ b/src/main/java/org/traccar/sms/smpp/ReconnectionTask.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.sms.smpp; + +public class ReconnectionTask implements Runnable { + + private final SmppClient smppClient; + + protected ReconnectionTask(SmppClient smppClient) { + this.smppClient = smppClient; + } + + @Override + public void run() { + smppClient.reconnect(); + } + +} diff --git a/src/main/java/org/traccar/sms/smpp/SmppClient.java b/src/main/java/org/traccar/sms/smpp/SmppClient.java new file mode 100644 index 000000000..874253d36 --- /dev/null +++ b/src/main/java/org/traccar/sms/smpp/SmppClient.java @@ -0,0 +1,272 @@ +/* + * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.sms.smpp; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.notification.MessageException; +import org.traccar.sms.SmsManager; + +import com.cloudhopper.commons.charset.CharsetUtil; +import com.cloudhopper.smpp.SmppBindType; +import com.cloudhopper.smpp.SmppConstants; +import com.cloudhopper.smpp.SmppSession; +import com.cloudhopper.smpp.SmppSessionConfiguration; +import com.cloudhopper.smpp.impl.DefaultSmppClient; +import com.cloudhopper.smpp.impl.DefaultSmppSessionHandler; +import com.cloudhopper.smpp.pdu.SubmitSm; +import com.cloudhopper.smpp.pdu.SubmitSmResp; +import com.cloudhopper.smpp.tlv.Tlv; +import com.cloudhopper.smpp.type.Address; +import com.cloudhopper.smpp.type.RecoverablePduException; +import com.cloudhopper.smpp.type.SmppChannelException; +import com.cloudhopper.smpp.type.SmppTimeoutException; +import com.cloudhopper.smpp.type.UnrecoverablePduException; + +public class SmppClient implements SmsManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(SmppClient.class); + + private SmppSessionConfiguration sessionConfig = new SmppSessionConfiguration(); + private SmppSession smppSession; + private DefaultSmppSessionHandler sessionHandler = new ClientSmppSessionHandler(this); + private ExecutorService executorService = Executors.newCachedThreadPool(); + private DefaultSmppClient clientBootstrap = new DefaultSmppClient(); + + private ScheduledExecutorService enquireLinkExecutor; + private ScheduledFuture enquireLinkTask; + private Integer enquireLinkPeriod; + private Integer enquireLinkTimeout; + + private ScheduledExecutorService reconnectionExecutor; + private ScheduledFuture reconnectionTask; + private Integer reconnectionDelay; + + private String sourceAddress; + private String commandSourceAddress; + private int submitTimeout; + private boolean requestDlr; + private boolean detectDlrByOpts; + private String notificationsCharsetName; + private byte notificationsDataCoding; + private String commandsCharsetName; + private byte commandsDataCoding; + + private byte sourceTon; + private byte sourceNpi; + private byte commandSourceTon; + private byte commandSourceNpi; + + private byte destTon; + private byte destNpi; + + public SmppClient() { + sessionConfig.setName("Traccar.smppSession"); + sessionConfig.setInterfaceVersion( + (byte) Context.getConfig().getInteger("sms.smpp.version", SmppConstants.VERSION_3_4)); + sessionConfig.setType(SmppBindType.TRANSCEIVER); + sessionConfig.setHost(Context.getConfig().getString("sms.smpp.host", "localhost")); + sessionConfig.setPort(Context.getConfig().getInteger("sms.smpp.port", 2775)); + sessionConfig.setSystemId(Context.getConfig().getString("sms.smpp.username", "user")); + sessionConfig.setSystemType(Context.getConfig().getString("sms.smpp.systemType", null)); + sessionConfig.setPassword(Context.getConfig().getString("sms.smpp.password", "password")); + sessionConfig.getLoggingOptions().setLogBytes(false); + sessionConfig.getLoggingOptions().setLogPdu(Context.getConfig().getBoolean("sms.smpp.logPdu")); + + sourceAddress = Context.getConfig().getString("sms.smpp.sourceAddress", ""); + commandSourceAddress = Context.getConfig().getString("sms.smpp.commandSourceAddress", sourceAddress); + submitTimeout = Context.getConfig().getInteger("sms.smpp.submitTimeout", 10000); + + requestDlr = Context.getConfig().getBoolean("sms.smpp.requestDlr"); + detectDlrByOpts = Context.getConfig().getBoolean("sms.smpp.detectDlrByOpts"); + + notificationsCharsetName = Context.getConfig().getString("sms.smpp.notificationsCharset", + CharsetUtil.NAME_UCS_2); + notificationsDataCoding = (byte) Context.getConfig().getInteger("sms.smpp.notificationsDataCoding", + SmppConstants.DATA_CODING_UCS2); + commandsCharsetName = Context.getConfig().getString("sms.smpp.commandsCharset", + CharsetUtil.NAME_GSM); + commandsDataCoding = (byte) Context.getConfig().getInteger("sms.smpp.commandsDataCoding", + SmppConstants.DATA_CODING_DEFAULT); + + + sourceTon = (byte) Context.getConfig().getInteger("sms.smpp.sourceTon", SmppConstants.TON_ALPHANUMERIC); + commandSourceTon = (byte) Context.getConfig().getInteger("sms.smpp.commandSourceTon", sourceTon); + sourceNpi = (byte) Context.getConfig().getInteger("sms.smpp.sourceNpi", SmppConstants.NPI_UNKNOWN); + commandSourceNpi = (byte) Context.getConfig().getInteger("sms.smpp.commandSourceNpi", sourceNpi); + + destTon = (byte) Context.getConfig().getInteger("sms.smpp.destTon", SmppConstants.TON_INTERNATIONAL); + destNpi = (byte) Context.getConfig().getInteger("sms.smpp.destNpi", SmppConstants.NPI_E164); + + enquireLinkPeriod = Context.getConfig().getInteger("sms.smpp.enquireLinkPeriod", 60000); + enquireLinkTimeout = Context.getConfig().getInteger("sms.smpp.enquireLinkTimeout", 10000); + enquireLinkExecutor = Executors.newScheduledThreadPool(1, new ThreadFactory() { + @Override + public Thread newThread(Runnable runnable) { + Thread thread = new Thread(runnable); + String name = sessionConfig.getName(); + thread.setName("EnquireLink-" + name); + return thread; + } + }); + + reconnectionDelay = Context.getConfig().getInteger("sms.smpp.reconnectionDelay", 10000); + reconnectionExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable runnable) { + Thread thread = new Thread(runnable); + String name = sessionConfig.getName(); + thread.setName("Reconnection-" + name); + return thread; + } + }); + + scheduleReconnect(); + } + + public synchronized SmppSession getSession() { + return smppSession; + } + + public String mapDataCodingToCharset(byte dataCoding) { + switch (dataCoding) { + case SmppConstants.DATA_CODING_LATIN1: + return CharsetUtil.NAME_ISO_8859_1; + case SmppConstants.DATA_CODING_UCS2: + return CharsetUtil.NAME_UCS_2; + default: + return CharsetUtil.NAME_GSM; + } + } + + public boolean getDetectDlrByOpts() { + return detectDlrByOpts; + } + + protected synchronized void reconnect() { + try { + disconnect(); + smppSession = clientBootstrap.bind(sessionConfig, sessionHandler); + stopReconnectionkTask(); + runEnquireLinkTask(); + LOGGER.info("SMPP session connected"); + } catch (SmppTimeoutException | SmppChannelException + | UnrecoverablePduException | InterruptedException error) { + LOGGER.warn("Unable to connect to SMPP server: ", error); + } + } + + public void scheduleReconnect() { + if (reconnectionTask == null || reconnectionTask.isDone()) { + reconnectionTask = reconnectionExecutor.scheduleWithFixedDelay( + new ReconnectionTask(this), + reconnectionDelay, reconnectionDelay, TimeUnit.MILLISECONDS); + } + } + + private void stopReconnectionkTask() { + if (reconnectionTask != null) { + reconnectionTask.cancel(false); + } + } + + private void disconnect() { + stopEnquireLinkTask(); + destroySession(); + } + + private void runEnquireLinkTask() { + enquireLinkTask = enquireLinkExecutor.scheduleWithFixedDelay( + new EnquireLinkTask(this, enquireLinkTimeout), + enquireLinkPeriod, enquireLinkPeriod, TimeUnit.MILLISECONDS); + } + + private void stopEnquireLinkTask() { + if (enquireLinkTask != null) { + enquireLinkTask.cancel(true); + } + } + + private void destroySession() { + if (smppSession != null) { + LOGGER.info("Cleaning up SMPP session... "); + smppSession.destroy(); + smppSession = null; + } + } + + @Override + public synchronized void sendMessageSync(String destAddress, String message, boolean command) + throws MessageException, InterruptedException, IllegalStateException { + if (getSession() != null && getSession().isBound()) { + try { + SubmitSm submit = new SubmitSm(); + byte[] textBytes; + textBytes = CharsetUtil.encode(message, command ? commandsCharsetName : notificationsCharsetName); + submit.setDataCoding(command ? commandsDataCoding : notificationsDataCoding); + if (requestDlr) { + submit.setRegisteredDelivery(SmppConstants.REGISTERED_DELIVERY_SMSC_RECEIPT_REQUESTED); + } + + if (textBytes != null && textBytes.length > 255) { + submit.addOptionalParameter(new Tlv(SmppConstants.TAG_MESSAGE_PAYLOAD, textBytes, + "message_payload")); + } else { + submit.setShortMessage(textBytes); + } + + submit.setSourceAddress(command ? new Address(commandSourceTon, commandSourceNpi, commandSourceAddress) + : new Address(sourceTon, sourceNpi, sourceAddress)); + submit.setDestAddress(new Address(destTon, destNpi, destAddress)); + SubmitSmResp submitResponce = getSession().submit(submit, submitTimeout); + if (submitResponce.getCommandStatus() == SmppConstants.STATUS_OK) { + LOGGER.info("SMS submitted, message id: " + submitResponce.getMessageId()); + } else { + throw new IllegalStateException(submitResponce.getResultMessage()); + } + } catch (SmppChannelException | RecoverablePduException + | SmppTimeoutException | UnrecoverablePduException error) { + throw new MessageException(error); + } + } else { + throw new MessageException(new SmppChannelException("SMPP session is not connected")); + } + } + + @Override + public void sendMessageAsync(final String destAddress, final String message, final boolean command) { + executorService.execute(new Runnable() { + @Override + public void run() { + try { + sendMessageSync(destAddress, message, command); + } catch (MessageException | InterruptedException | IllegalStateException error) { + LOGGER.warn("SMS sending error", error); + } + } + }); + } + +} diff --git a/src/main/java/org/traccar/sms/smpp/TextMessageEventHandler.java b/src/main/java/org/traccar/sms/smpp/TextMessageEventHandler.java new file mode 100644 index 000000000..37c29972d --- /dev/null +++ b/src/main/java/org/traccar/sms/smpp/TextMessageEventHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.sms.smpp; + +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Event; + +public final class TextMessageEventHandler { + + private TextMessageEventHandler() { + } + + public static void handleTextMessage(String phone, String message) { + Device device = Context.getDeviceManager().getDeviceByPhone(phone); + if (device != null && Context.getNotificationManager() != null) { + Event event = new Event(Event.TYPE_TEXT_MESSAGE, device.getId()); + event.set("message", message); + Context.getNotificationManager().updateEvent(event, null); + } + } + +} diff --git a/src/main/java/org/traccar/web/ConsoleServlet.java b/src/main/java/org/traccar/web/ConsoleServlet.java new file mode 100644 index 000000000..2b38a935a --- /dev/null +++ b/src/main/java/org/traccar/web/ConsoleServlet.java @@ -0,0 +1,61 @@ +/* + * Copyright 2015 - 2016 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. + * 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.web; + +import org.h2.server.web.ConnectionInfo; +import org.h2.server.web.WebServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class ConsoleServlet extends WebServlet { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleServlet.class); + + @Override + public void init() { + super.init(); + + try { + Field field = WebServlet.class.getDeclaredField("server"); + field.setAccessible(true); + org.h2.server.web.WebServer server = (org.h2.server.web.WebServer) field.get(this); + + ConnectionInfo connectionInfo = new ConnectionInfo("Traccar|" + + Context.getConfig().getString("database.driver") + "|" + + Context.getConfig().getString("database.url") + "|" + + Context.getConfig().getString("database.user")); + + Method method; + + method = org.h2.server.web.WebServer.class.getDeclaredMethod("updateSetting", ConnectionInfo.class); + method.setAccessible(true); + method.invoke(server, connectionInfo); + + method = org.h2.server.web.WebServer.class.getDeclaredMethod("setAllowOthers", boolean.class); + method.setAccessible(true); + method.invoke(server, true); + + } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + LOGGER.warn("Console reflection error", e); + } + } + +} diff --git a/src/main/java/org/traccar/web/CsvBuilder.java b/src/main/java/org/traccar/web/CsvBuilder.java new file mode 100644 index 000000000..3fe7e408f --- /dev/null +++ b/src/main/java/org/traccar/web/CsvBuilder.java @@ -0,0 +1,164 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.web; + +import java.beans.Introspector; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.helper.DateUtil; + +public class CsvBuilder { + + private static final Logger LOGGER = LoggerFactory.getLogger(CsvBuilder.class); + + private static final String LINE_ENDING = "\r\n"; + private static final String SEPARATOR = ";"; + + private StringBuilder builder = new StringBuilder(); + + private void addLineEnding() { + builder.append(LINE_ENDING); + } + private void addSeparator() { + builder.append(SEPARATOR); + } + + private SortedSet getSortedMethods(Object object) { + Method[] methodArray = object.getClass().getMethods(); + SortedSet methods = new TreeSet<>(new Comparator() { + @Override + public int compare(Method m1, Method m2) { + if (m1.getName().equals("getAttributes") && !m1.getName().equals(m2.getName())) { + return 1; + } + if (m2.getName().equals("getAttributes") && !m1.getName().equals(m2.getName())) { + return -1; + } + return m1.getName().compareTo(m2.getName()); + } + }); + methods.addAll(Arrays.asList(methodArray)); + return methods; + } + + public void addLine(Object object) { + + SortedSet methods = getSortedMethods(object); + + for (Method method : methods) { + if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { + try { + if (method.getReturnType().equals(boolean.class)) { + builder.append(method.invoke(object)); + addSeparator(); + } else if (method.getReturnType().equals(int.class)) { + builder.append(method.invoke(object)); + addSeparator(); + } else if (method.getReturnType().equals(long.class)) { + builder.append(method.invoke(object)); + addSeparator(); + } else if (method.getReturnType().equals(double.class)) { + builder.append(method.invoke(object)); + addSeparator(); + } else if (method.getReturnType().equals(String.class)) { + builder.append((String) method.invoke(object)); + addSeparator(); + } else if (method.getReturnType().equals(Date.class)) { + Date value = (Date) method.invoke(object); + builder.append(DateUtil.formatDate(value)); + addSeparator(); + } else if (method.getReturnType().equals(Map.class)) { + Map value = (Map) method.invoke(object); + if (value != null) { + try { + String map = Context.getObjectMapper().writeValueAsString(value); + map = map.replaceAll("[\\{\\}\"]", ""); + map = map.replaceAll(",", " "); + builder.append(map); + addSeparator(); + } catch (JsonProcessingException e) { + LOGGER.warn("Map JSON formatting error", e); + } + } + } + } catch (IllegalAccessException | InvocationTargetException error) { + LOGGER.warn("Reflection invocation error", error); + } + } + } + addLineEnding(); + } + + public void addHeaderLine(Object object) { + + SortedSet methods = getSortedMethods(object); + + for (Method method : methods) { + if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { + String name = Introspector.decapitalize(method.getName().substring(3)); + if (!name.equals("class")) { + builder.append(name); + addSeparator(); + } + } + } + addLineEnding(); + } + + public void addArray(Collection array) { + for (Object object : array) { + switch (object.getClass().getSimpleName().toLowerCase()) { + case "string": + builder.append(object.toString()); + addLineEnding(); + break; + case "long": + builder.append((long) object); + addLineEnding(); + break; + case "double": + builder.append((double) object); + addLineEnding(); + break; + case "boolean": + builder.append((boolean) object); + addLineEnding(); + break; + default: + addLine(object); + break; + } + } + } + + public String build() { + return builder.toString(); + } + +} diff --git a/src/main/java/org/traccar/web/GpxBuilder.java b/src/main/java/org/traccar/web/GpxBuilder.java new file mode 100644 index 000000000..638d100e5 --- /dev/null +++ b/src/main/java/org/traccar/web/GpxBuilder.java @@ -0,0 +1,69 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * 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.web; + +import java.util.Collection; + +import org.traccar.helper.DateUtil; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +public class GpxBuilder { + + private StringBuilder builder = new StringBuilder(); + private static final String HEADER = "" + + "\n"; + private static final String NAME = "%1$s%n"; + private static final String POINT = "" + + "" + + "%4$f" + + "%5$f" + + "%6$f" + + "%n"; + private static final String FOOTER = ""; + + public GpxBuilder() { + builder.append(HEADER); + builder.append("\n"); + } + + public GpxBuilder(String name) { + builder.append(HEADER); + builder.append(String.format(NAME, name)); + } + + public void addPosition(Position position) { + builder.append(String.format(POINT, position.getLatitude(), position.getLongitude(), + DateUtil.formatDate(position.getFixTime()), position.getAltitude(), + position.getCourse(), UnitsConverter.mpsFromKnots(position.getSpeed()))); + } + + public void addPositions(Collection positions) { + for (Position position : positions) { + addPosition(position); + } + } + + public String build() { + builder.append(FOOTER); + return builder.toString(); + } + +} diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java new file mode 100644 index 000000000..70fef4ed3 --- /dev/null +++ b/src/main/java/org/traccar/web/WebServer.java @@ -0,0 +1,173 @@ +/* + * Copyright 2012 - 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. + * 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.web; + +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.proxy.AsyncProxyServlet; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ErrorHandler; +import org.eclipse.jetty.server.handler.HandlerList; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.servlet.ServletContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.api.AsyncSocketServlet; +import org.traccar.api.CorsResponseFilter; +import org.traccar.api.MediaFilter; +import org.traccar.api.ObjectMapperProvider; +import org.traccar.api.ResourceErrorHandler; +import org.traccar.api.SecurityRequestFilter; +import org.traccar.api.resource.ServerResource; + +import javax.servlet.DispatcherType; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.net.InetSocketAddress; +import java.util.EnumSet; + +public class WebServer { + + private static final Logger LOGGER = LoggerFactory.getLogger(WebServer.class); + + private Server server; + + private void initServer(Config config) { + + String address = config.getString("web.address"); + int port = config.getInteger("web.port", 8082); + if (address == null) { + server = new Server(port); + } else { + server = new Server(new InetSocketAddress(address, port)); + } + } + + public WebServer(Config config) { + + initServer(config); + + ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); + + int sessionTimeout = config.getInteger("web.sessionTimeout"); + if (sessionTimeout > 0) { + servletHandler.getSessionHandler().setMaxInactiveInterval(sessionTimeout); + } + + initApi(config, servletHandler); + + if (config.getBoolean("web.console")) { + servletHandler.addServlet(new ServletHolder(new ConsoleServlet()), "/console/*"); + } + + initWebApp(config, servletHandler); + + servletHandler.setErrorHandler(new ErrorHandler() { + @Override + protected void handleErrorPage( + HttpServletRequest request, Writer writer, int code, String message) throws IOException { + writer.write("Error" + + code + " - " + HttpStatus.getMessage(code) + ""); + } + }); + + HandlerList handlers = new HandlerList(); + initClientProxy(config, handlers); + handlers.addHandler(servletHandler); + server.setHandler(handlers); + } + + private void initClientProxy(Config config, HandlerList handlers) { + int port = config.getInteger("osmand.port"); + if (port != 0) { + ServletContextHandler servletHandler = new ServletContextHandler() { + @Override + public void doScope( + String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException { + if (target.equals("/") && request.getMethod().equals(HttpMethod.POST.asString())) { + super.doScope(target, baseRequest, request, response); + } + } + }; + ServletHolder servletHolder = new ServletHolder(new AsyncProxyServlet.Transparent()); + servletHolder.setInitParameter("proxyTo", "http://localhost:" + port); + servletHandler.addServlet(servletHolder, "/"); + handlers.addHandler(servletHandler); + } + } + + private void initWebApp(Config config, ServletContextHandler servletHandler) { + ServletHolder servletHolder = new ServletHolder(DefaultServlet.class); + servletHolder.setInitParameter("resourceBase", new File(config.getString("web.path")).getAbsolutePath()); + if (config.getBoolean("web.debug")) { + servletHandler.setWelcomeFiles(new String[] {"debug.html", "index.html"}); + } else { + String cache = config.getString("web.cacheControl"); + if (cache != null && !cache.isEmpty()) { + servletHolder.setInitParameter("cacheControl", cache); + } + servletHandler.setWelcomeFiles(new String[] {"release.html", "index.html"}); + } + servletHandler.addServlet(servletHolder, "/*"); + } + + private void initApi(Config config, ServletContextHandler servletHandler) { + servletHandler.addServlet(new ServletHolder(new AsyncSocketServlet()), "/api/socket"); + + if (config.hasKey("media.path")) { + ServletHolder servletHolder = new ServletHolder(DefaultServlet.class); + servletHolder.setInitParameter("resourceBase", new File(config.getString("media.path")).getAbsolutePath()); + servletHolder.setInitParameter("dirAllowed", config.getString("media.dirAllowed", "false")); + servletHolder.setInitParameter("pathInfoOnly", "true"); + servletHandler.addServlet(servletHolder, "/api/media/*"); + servletHandler.addFilter(MediaFilter.class, "/api/media/*", EnumSet.allOf(DispatcherType.class)); + } + + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig.registerClasses(JacksonFeature.class, ObjectMapperProvider.class, ResourceErrorHandler.class); + resourceConfig.registerClasses(SecurityRequestFilter.class, CorsResponseFilter.class); + resourceConfig.packages(ServerResource.class.getPackage().getName()); + servletHandler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/api/*"); + } + + public void start() { + try { + server.start(); + } catch (Exception error) { + LOGGER.warn("Web server start failed", error); + } + } + + public void stop() { + try { + server.stop(); + } catch (Exception error) { + LOGGER.warn("Web server stop failed", error); + } + } + +} diff --git a/src/org/traccar/BaseDataHandler.java b/src/org/traccar/BaseDataHandler.java deleted file mode 100644 index 48794b0d7..000000000 --- a/src/org/traccar/BaseDataHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.traccar.model.Position; - -public abstract class BaseDataHandler extends ChannelInboundHandlerAdapter { - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof Position) { - Position position = handlePosition((Position) msg); - if (position != null) { - ctx.fireChannelRead(position); - } - } else { - super.channelRead(ctx, msg); - } - } - - protected abstract Position handlePosition(Position position); - -} diff --git a/src/org/traccar/BaseFrameDecoder.java b/src/org/traccar/BaseFrameDecoder.java deleted file mode 100644 index f90f90e4b..000000000 --- a/src/org/traccar/BaseFrameDecoder.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; - -import java.util.List; - -public abstract class BaseFrameDecoder extends ByteToMessageDecoder { - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - Object decoded = decode(ctx, ctx != null ? ctx.channel() : null, in); - if (decoded != null) { - out.add(decoded); - } - } - - protected abstract Object decode(ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception; - -} diff --git a/src/org/traccar/BaseHttpProtocolDecoder.java b/src/org/traccar/BaseHttpProtocolDecoder.java deleted file mode 100644 index 57a68acac..000000000 --- a/src/org/traccar/BaseHttpProtocolDecoder.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; - -public abstract class BaseHttpProtocolDecoder extends BaseProtocolDecoder { - - public BaseHttpProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public void sendResponse(Channel channel, HttpResponseStatus status) { - if (channel != null) { - HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status); - response.headers().add(HttpHeaderNames.CONTENT_LENGTH, 0); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - -} diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java deleted file mode 100644 index b3d37f689..000000000 --- a/src/org/traccar/BasePipelineFactory.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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 io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelInboundHandler; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOutboundHandler; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.timeout.IdleStateHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Keys; -import org.traccar.handler.DefaultDataHandler; -import org.traccar.handler.events.AlertEventHandler; -import org.traccar.handler.events.CommandResultEventHandler; -import org.traccar.handler.events.DriverEventHandler; -import org.traccar.handler.events.FuelDropEventHandler; -import org.traccar.handler.events.GeofenceEventHandler; -import org.traccar.handler.events.IgnitionEventHandler; -import org.traccar.handler.events.MaintenanceEventHandler; -import org.traccar.handler.events.MotionEventHandler; -import org.traccar.handler.events.OverspeedEventHandler; -import org.traccar.handler.ComputedAttributesHandler; -import org.traccar.handler.CopyAttributesHandler; -import org.traccar.handler.DistanceHandler; -import org.traccar.handler.EngineHoursHandler; -import org.traccar.handler.FilterHandler; -import org.traccar.handler.GeocoderHandler; -import org.traccar.handler.GeolocationHandler; -import org.traccar.handler.HemisphereHandler; -import org.traccar.handler.MotionHandler; -import org.traccar.handler.NetworkMessageHandler; -import org.traccar.handler.OpenChannelHandler; -import org.traccar.handler.RemoteAddressHandler; -import org.traccar.handler.StandardLoggingHandler; - -import java.util.Map; - -public abstract class BasePipelineFactory extends ChannelInitializer { - - private static final Logger LOGGER = LoggerFactory.getLogger(BasePipelineFactory.class); - - private final TrackerServer server; - private boolean eventsEnabled; - private int timeout; - - public BasePipelineFactory(TrackerServer server, String protocol) { - this.server = server; - eventsEnabled = Context.getConfig().getBoolean(Keys.EVENT_ENABLE); - timeout = Context.getConfig().getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol)); - if (timeout == 0) { - timeout = Context.getConfig().getInteger(Keys.SERVER_TIMEOUT); - } - } - - protected abstract void addProtocolHandlers(PipelineBuilder pipeline); - - @SafeVarargs - private final void addHandlers(ChannelPipeline pipeline, Class... handlerClasses) { - for (Class handlerClass : handlerClasses) { - if (handlerClass != null) { - pipeline.addLast(Main.getInjector().getInstance(handlerClass)); - } - } - } - - public static T getHandler(ChannelPipeline pipeline, Class clazz) { - for (Map.Entry handlerEntry : pipeline) { - ChannelHandler handler = handlerEntry.getValue(); - if (handler instanceof WrapperInboundHandler) { - handler = ((WrapperInboundHandler) handler).getWrappedHandler(); - } else if (handler instanceof WrapperOutboundHandler) { - handler = ((WrapperOutboundHandler) handler).getWrappedHandler(); - } - if (clazz.isAssignableFrom(handler.getClass())) { - return (T) handler; - } - } - return null; - } - - @Override - protected void initChannel(Channel channel) { - final ChannelPipeline pipeline = channel.pipeline(); - - if (timeout > 0 && !server.isDatagram()) { - pipeline.addLast(new IdleStateHandler(timeout, 0, 0)); - } - pipeline.addLast(new OpenChannelHandler(server)); - pipeline.addLast(new NetworkMessageHandler()); - pipeline.addLast(new StandardLoggingHandler()); - - addProtocolHandlers(handler -> { - if (!(handler instanceof BaseProtocolDecoder || handler instanceof BaseProtocolEncoder)) { - if (handler instanceof ChannelInboundHandler) { - handler = new WrapperInboundHandler((ChannelInboundHandler) handler); - } else { - handler = new WrapperOutboundHandler((ChannelOutboundHandler) handler); - } - } - pipeline.addLast(handler); - }); - - addHandlers( - pipeline, - GeolocationHandler.class, - HemisphereHandler.class, - DistanceHandler.class, - RemoteAddressHandler.class); - - addDynamicHandlers(pipeline); - - addHandlers( - pipeline, - FilterHandler.class, - GeocoderHandler.class, - MotionHandler.class, - EngineHoursHandler.class, - CopyAttributesHandler.class, - ComputedAttributesHandler.class, - WebDataHandler.class, - DefaultDataHandler.class); - - if (eventsEnabled) { - addHandlers( - pipeline, - CommandResultEventHandler.class, - OverspeedEventHandler.class, - FuelDropEventHandler.class, - MotionEventHandler.class, - GeofenceEventHandler.class, - AlertEventHandler.class, - IgnitionEventHandler.class, - MaintenanceEventHandler.class, - DriverEventHandler.class); - } - - pipeline.addLast(new MainEventHandler()); - } - - private void addDynamicHandlers(ChannelPipeline pipeline) { - String handlers = Context.getConfig().getString(Keys.EXTRA_HANDLERS); - if (handlers != null) { - for (String handler : handlers.split(",")) { - try { - pipeline.addLast((ChannelHandler) Class.forName(handler).getDeclaredConstructor().newInstance()); - } catch (ReflectiveOperationException error) { - LOGGER.warn("Dynamic handler error", error); - } - } - } - } - -} diff --git a/src/org/traccar/BaseProtocol.java b/src/org/traccar/BaseProtocol.java deleted file mode 100644 index c0fd1e27f..000000000 --- a/src/org/traccar/BaseProtocol.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.Unpooled; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.database.ActiveDevice; -import org.traccar.helper.DataConverter; -import org.traccar.model.Command; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -public abstract class BaseProtocol implements Protocol { - - private final String name; - private final Set supportedDataCommands = new HashSet<>(); - private final Set supportedTextCommands = new HashSet<>(); - private final List serverList = new LinkedList<>(); - - private StringProtocolEncoder textCommandEncoder = null; - - public static String nameFromClass(Class clazz) { - String className = clazz.getSimpleName(); - return className.substring(0, className.length() - 8).toLowerCase(); - } - - public BaseProtocol() { - name = nameFromClass(getClass()); - } - - @Override - public String getName() { - return name; - } - - protected void addServer(TrackerServer server) { - serverList.add(server); - } - - @Override - public Collection getServerList() { - return serverList; - } - - public void setSupportedDataCommands(String... commands) { - supportedDataCommands.addAll(Arrays.asList(commands)); - } - - public void setSupportedTextCommands(String... commands) { - supportedTextCommands.addAll(Arrays.asList(commands)); - } - - public void setSupportedCommands(String... commands) { - supportedDataCommands.addAll(Arrays.asList(commands)); - supportedTextCommands.addAll(Arrays.asList(commands)); - } - - @Override - public Collection getSupportedDataCommands() { - Set commands = new HashSet<>(supportedDataCommands); - commands.add(Command.TYPE_CUSTOM); - return commands; - } - - @Override - public Collection getSupportedTextCommands() { - Set commands = new HashSet<>(supportedTextCommands); - commands.add(Command.TYPE_CUSTOM); - return commands; - } - - @Override - public void sendDataCommand(ActiveDevice activeDevice, Command command) { - if (supportedDataCommands.contains(command.getType())) { - activeDevice.write(command); - } else if (command.getType().equals(Command.TYPE_CUSTOM)) { - String data = command.getString(Command.KEY_DATA); - if (BasePipelineFactory.getHandler(activeDevice.getChannel().pipeline(), StringEncoder.class) != null) { - activeDevice.write(data); - } else { - activeDevice.write(Unpooled.wrappedBuffer(DataConverter.parseHex(data))); - } - } else { - throw new RuntimeException("Command " + command.getType() + " is not supported in protocol " + getName()); - } - } - - public void setTextCommandEncoder(StringProtocolEncoder textCommandEncoder) { - this.textCommandEncoder = textCommandEncoder; - } - - @Override - public void sendTextCommand(String destAddress, Command command) throws Exception { - if (Context.getSmsManager() != null) { - if (command.getType().equals(Command.TYPE_CUSTOM)) { - Context.getSmsManager().sendMessageSync(destAddress, command.getString(Command.KEY_DATA), true); - } else if (supportedTextCommands.contains(command.getType()) && textCommandEncoder != null) { - String encodedCommand = (String) textCommandEncoder.encodeCommand(command); - if (encodedCommand != null) { - Context.getSmsManager().sendMessageSync(destAddress, encodedCommand, true); - } else { - throw new RuntimeException("Failed to encode command"); - } - } else { - throw new RuntimeException( - "Command " + command.getType() + " is not supported in protocol " + getName()); - } - } else { - throw new RuntimeException("SMS is not enabled"); - } - } - -} diff --git a/src/org/traccar/BaseProtocolDecoder.java b/src/org/traccar/BaseProtocolDecoder.java deleted file mode 100644 index aa5be612e..000000000 --- a/src/org/traccar/BaseProtocolDecoder.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import io.netty.channel.socket.DatagramChannel; -import io.netty.handler.codec.http.HttpRequestDecoder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.database.ConnectionManager; -import org.traccar.database.IdentityManager; -import org.traccar.database.StatisticsManager; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Device; -import org.traccar.model.Position; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.TimeZone; - -public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { - - private static final Logger LOGGER = LoggerFactory.getLogger(BaseProtocolDecoder.class); - - private static final String PROTOCOL_UNKNOWN = "unknown"; - - private final Config config = Context.getConfig(); - private final IdentityManager identityManager = Context.getIdentityManager(); - private final ConnectionManager connectionManager = Context.getConnectionManager(); - private final StatisticsManager statisticsManager; - private final Protocol protocol; - - public BaseProtocolDecoder(Protocol protocol) { - this.protocol = protocol; - statisticsManager = Main.getInjector() != null ? Main.getInjector().getInstance(StatisticsManager.class) : null; - } - - public String getProtocolName() { - return protocol != null ? protocol.getName() : PROTOCOL_UNKNOWN; - } - - public String getServer(Channel channel, char delimiter) { - String server = config.getString(getProtocolName() + ".server"); - if (server == null && channel != null) { - InetSocketAddress address = (InetSocketAddress) channel.localAddress(); - server = address.getAddress().getHostAddress() + ":" + address.getPort(); - } - return server != null ? server.replace(':', delimiter) : null; - } - - protected double convertSpeed(double value, String defaultUnits) { - switch (config.getString(getProtocolName() + ".speed", defaultUnits)) { - case "kmh": - return UnitsConverter.knotsFromKph(value); - case "mps": - return UnitsConverter.knotsFromMps(value); - case "mph": - return UnitsConverter.knotsFromMph(value); - case "kn": - default: - return value; - } - } - - protected TimeZone getTimeZone(long deviceId) { - return getTimeZone(deviceId, "UTC"); - } - - protected TimeZone getTimeZone(long deviceId, String defaultTimeZone) { - TimeZone result = TimeZone.getTimeZone(defaultTimeZone); - String timeZoneName = identityManager.lookupAttributeString(deviceId, "decoder.timezone", null, true); - if (timeZoneName != null) { - result = TimeZone.getTimeZone(timeZoneName); - } else { - int timeZoneOffset = config.getInteger(getProtocolName() + ".timezone", 0); - if (timeZoneOffset != 0) { - result.setRawOffset(timeZoneOffset * 1000); - LOGGER.warn("Config parameter " + getProtocolName() + ".timezone is deprecated"); - } - } - return result; - } - - private DeviceSession channelDeviceSession; // connection-based protocols - private Map addressDeviceSessions = new HashMap<>(); // connectionless protocols - - private long findDeviceId(SocketAddress remoteAddress, String... uniqueIds) { - if (uniqueIds.length > 0) { - long deviceId = 0; - Device device = null; - try { - for (String uniqueId : uniqueIds) { - if (uniqueId != null) { - device = identityManager.getByUniqueId(uniqueId); - if (device != null) { - deviceId = device.getId(); - break; - } - } - } - } catch (Exception e) { - LOGGER.warn("Find device error", e); - } - if (deviceId == 0 && config.getBoolean("database.registerUnknown")) { - return identityManager.addUnknownDevice(uniqueIds[0]); - } - if (device != null && !device.getDisabled() || config.getBoolean("database.storeDisabled")) { - return deviceId; - } - StringBuilder message = new StringBuilder(); - if (deviceId == 0) { - message.append("Unknown device -"); - } else { - message.append("Disabled device -"); - } - for (String uniqueId : uniqueIds) { - message.append(" ").append(uniqueId); - } - if (remoteAddress != null) { - message.append(" (").append(((InetSocketAddress) remoteAddress).getHostString()).append(")"); - } - LOGGER.warn(message.toString()); - } - return 0; - } - - public DeviceSession getDeviceSession(Channel channel, SocketAddress remoteAddress, String... uniqueIds) { - if (channel != null && BasePipelineFactory.getHandler(channel.pipeline(), HttpRequestDecoder.class) != null - || config.getBoolean("decoder.ignoreSessionCache")) { - long deviceId = findDeviceId(remoteAddress, uniqueIds); - if (deviceId != 0) { - if (connectionManager != null) { - connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress); - } - return new DeviceSession(deviceId); - } else { - return null; - } - } - if (channel instanceof DatagramChannel) { - long deviceId = findDeviceId(remoteAddress, uniqueIds); - DeviceSession deviceSession = addressDeviceSessions.get(remoteAddress); - if (deviceSession != null && (deviceSession.getDeviceId() == deviceId || uniqueIds.length == 0)) { - return deviceSession; - } else if (deviceId != 0) { - deviceSession = new DeviceSession(deviceId); - addressDeviceSessions.put(remoteAddress, deviceSession); - if (connectionManager != null) { - connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress); - } - return deviceSession; - } else { - return null; - } - } else { - if (channelDeviceSession == null) { - long deviceId = findDeviceId(remoteAddress, uniqueIds); - if (deviceId != 0) { - channelDeviceSession = new DeviceSession(deviceId); - if (connectionManager != null) { - connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress); - } - } - } - return channelDeviceSession; - } - } - - public void getLastLocation(Position position, Date deviceTime) { - if (position.getDeviceId() != 0) { - position.setOutdated(true); - - Position last = identityManager.getLastPosition(position.getDeviceId()); - if (last != null) { - position.setFixTime(last.getFixTime()); - position.setValid(last.getValid()); - position.setLatitude(last.getLatitude()); - position.setLongitude(last.getLongitude()); - position.setAltitude(last.getAltitude()); - position.setSpeed(last.getSpeed()); - position.setCourse(last.getCourse()); - position.setAccuracy(last.getAccuracy()); - } else { - position.setFixTime(new Date(0)); - } - - if (deviceTime != null) { - position.setDeviceTime(deviceTime); - } else { - position.setDeviceTime(new Date()); - } - } - } - - @Override - protected void onMessageEvent( - Channel channel, SocketAddress remoteAddress, Object originalMessage, Object decodedMessage) { - if (statisticsManager != null) { - statisticsManager.registerMessageReceived(); - } - Position position = null; - if (decodedMessage != null) { - if (decodedMessage instanceof Position) { - position = (Position) decodedMessage; - } else if (decodedMessage instanceof Collection) { - Collection positions = (Collection) decodedMessage; - if (!positions.isEmpty()) { - position = (Position) positions.iterator().next(); - } - } - } - if (position != null) { - connectionManager.updateDevice( - position.getDeviceId(), Device.STATUS_ONLINE, new Date()); - } else { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession != null) { - connectionManager.updateDevice( - deviceSession.getDeviceId(), Device.STATUS_ONLINE, new Date()); - } - } - } - - @Override - protected Object handleEmptyMessage(Channel channel, SocketAddress remoteAddress, Object msg) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (config.getBoolean("database.saveEmpty") && deviceSession != null) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, null); - return position; - } else { - return null; - } - } - -} diff --git a/src/org/traccar/BaseProtocolEncoder.java b/src/org/traccar/BaseProtocolEncoder.java deleted file mode 100644 index d7625e4b8..000000000 --- a/src/org/traccar/BaseProtocolEncoder.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundHandlerAdapter; -import io.netty.channel.ChannelPromise; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.model.Command; -import org.traccar.model.Device; - -public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(BaseProtocolEncoder.class); - - protected String getUniqueId(long deviceId) { - return Context.getIdentityManager().getById(deviceId).getUniqueId(); - } - - protected void initDevicePassword(Command command, String defaultPassword) { - if (!command.getAttributes().containsKey(Command.KEY_DEVICE_PASSWORD)) { - Device device = Context.getIdentityManager().getById(command.getDeviceId()); - String password = device.getString(Command.KEY_DEVICE_PASSWORD); - if (password != null) { - command.set(Command.KEY_DEVICE_PASSWORD, password); - } else { - command.set(Command.KEY_DEVICE_PASSWORD, defaultPassword); - } - } - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - - NetworkMessage networkMessage = (NetworkMessage) msg; - - if (networkMessage.getMessage() instanceof Command) { - - Command command = (Command) networkMessage.getMessage(); - Object encodedCommand = encodeCommand(ctx.channel(), command); - - StringBuilder s = new StringBuilder(); - s.append("[").append(ctx.channel().id().asShortText()).append("] "); - s.append("id: ").append(getUniqueId(command.getDeviceId())).append(", "); - s.append("command type: ").append(command.getType()).append(" "); - if (encodedCommand != null) { - s.append("sent"); - } else { - s.append("not sent"); - } - LOGGER.info(s.toString()); - - ctx.write(new NetworkMessage(encodedCommand, networkMessage.getRemoteAddress()), promise); - - } else { - - super.write(ctx, msg, promise); - - } - } - - protected Object encodeCommand(Channel channel, Command command) { - return encodeCommand(command); - } - - protected Object encodeCommand(Command command) { - return null; - } - -} diff --git a/src/org/traccar/CharacterDelimiterFrameDecoder.java b/src/org/traccar/CharacterDelimiterFrameDecoder.java deleted file mode 100644 index eeb8834dc..000000000 --- a/src/org/traccar/CharacterDelimiterFrameDecoder.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.handler.codec.DelimiterBasedFrameDecoder; - -public class CharacterDelimiterFrameDecoder extends DelimiterBasedFrameDecoder { - - private static ByteBuf createDelimiter(char delimiter) { - byte[] buf = {(byte) delimiter}; - return Unpooled.wrappedBuffer(buf); - } - - private static ByteBuf createDelimiter(String delimiter) { - byte[] buf = new byte[delimiter.length()]; - for (int i = 0; i < delimiter.length(); i++) { - buf[i] = (byte) delimiter.charAt(i); - } - return Unpooled.wrappedBuffer(buf); - } - - private static ByteBuf[] convertDelimiters(String[] delimiters) { - ByteBuf[] result = new ByteBuf[delimiters.length]; - for (int i = 0; i < delimiters.length; i++) { - result[i] = createDelimiter(delimiters[i]); - } - return result; - } - - public CharacterDelimiterFrameDecoder(int maxFrameLength, char delimiter) { - super(maxFrameLength, createDelimiter(delimiter)); - } - - public CharacterDelimiterFrameDecoder(int maxFrameLength, String delimiter) { - super(maxFrameLength, createDelimiter(delimiter)); - } - - public CharacterDelimiterFrameDecoder(int maxFrameLength, boolean stripDelimiter, String delimiter) { - super(maxFrameLength, stripDelimiter, createDelimiter(delimiter)); - } - - public CharacterDelimiterFrameDecoder(int maxFrameLength, String... delimiters) { - super(maxFrameLength, convertDelimiters(delimiters)); - } - - public CharacterDelimiterFrameDecoder(int maxFrameLength, boolean stripDelimiter, String... delimiters) { - super(maxFrameLength, stripDelimiter, convertDelimiters(delimiters)); - } - -} diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java deleted file mode 100644 index 9c20db9e4..000000000 --- a/src/org/traccar/Context.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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 com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.jsr353.JSR353Module; -import org.apache.velocity.app.VelocityEngine; -import org.eclipse.jetty.util.URIUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.database.AttributesManager; -import org.traccar.database.BaseObjectManager; -import org.traccar.database.CalendarManager; -import org.traccar.database.CommandsManager; -import org.traccar.database.ConnectionManager; -import org.traccar.database.DataManager; -import org.traccar.database.DeviceManager; -import org.traccar.database.DriversManager; -import org.traccar.database.GeofenceManager; -import org.traccar.database.GroupsManager; -import org.traccar.database.IdentityManager; -import org.traccar.database.LdapProvider; -import org.traccar.database.MailManager; -import org.traccar.database.MaintenancesManager; -import org.traccar.database.MediaManager; -import org.traccar.database.NotificationManager; -import org.traccar.database.PermissionsManager; -import org.traccar.database.UsersManager; -import org.traccar.geocoder.Geocoder; -import org.traccar.helper.Log; -import org.traccar.helper.SanitizerModule; -import org.traccar.model.Attribute; -import org.traccar.model.BaseModel; -import org.traccar.model.Calendar; -import org.traccar.model.Command; -import org.traccar.model.Device; -import org.traccar.model.Driver; -import org.traccar.model.Geofence; -import org.traccar.model.Group; -import org.traccar.model.Maintenance; -import org.traccar.model.Notification; -import org.traccar.model.User; -import org.traccar.notification.EventForwarder; -import org.traccar.notification.JsonTypeEventForwarder; -import org.traccar.notification.NotificatorManager; -import org.traccar.reports.model.TripsConfig; -import org.traccar.sms.SmsManager; -import org.traccar.sms.smpp.SmppClient; -import org.traccar.web.WebServer; - -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.ext.ContextResolver; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Properties; - -public final class Context { - - private static final Logger LOGGER = LoggerFactory.getLogger(Context.class); - - private Context() { - } - - private static Config config; - - public static Config getConfig() { - return config; - } - - private static ObjectMapper objectMapper; - - public static ObjectMapper getObjectMapper() { - return objectMapper; - } - - private static IdentityManager identityManager; - - public static IdentityManager getIdentityManager() { - return identityManager; - } - - private static DataManager dataManager; - - public static DataManager getDataManager() { - return dataManager; - } - - private static LdapProvider ldapProvider; - - public static LdapProvider getLdapProvider() { - return ldapProvider; - } - - private static MailManager mailManager; - - public static MailManager getMailManager() { - return mailManager; - } - - private static MediaManager mediaManager; - - public static MediaManager getMediaManager() { - return mediaManager; - } - - private static UsersManager usersManager; - - public static UsersManager getUsersManager() { - return usersManager; - } - - private static GroupsManager groupsManager; - - public static GroupsManager getGroupsManager() { - return groupsManager; - } - - private static DeviceManager deviceManager; - - public static DeviceManager getDeviceManager() { - return deviceManager; - } - - private static ConnectionManager connectionManager; - - public static ConnectionManager getConnectionManager() { - return connectionManager; - } - - private static PermissionsManager permissionsManager; - - public static PermissionsManager getPermissionsManager() { - return permissionsManager; - } - - public static Geocoder getGeocoder() { - return Main.getInjector() != null ? Main.getInjector().getInstance(Geocoder.class) : null; - } - - private static WebServer webServer; - - public static WebServer getWebServer() { - return webServer; - } - - private static ServerManager serverManager; - - public static ServerManager getServerManager() { - return serverManager; - } - - private static GeofenceManager geofenceManager; - - public static GeofenceManager getGeofenceManager() { - return geofenceManager; - } - - private static CalendarManager calendarManager; - - public static CalendarManager getCalendarManager() { - return calendarManager; - } - - private static NotificationManager notificationManager; - - public static NotificationManager getNotificationManager() { - return notificationManager; - } - - private static NotificatorManager notificatorManager; - - public static NotificatorManager getNotificatorManager() { - return notificatorManager; - } - - private static VelocityEngine velocityEngine; - - public static VelocityEngine getVelocityEngine() { - return velocityEngine; - } - - private static Client client = ClientBuilder.newClient(); - - public static Client getClient() { - return client; - } - - private static EventForwarder eventForwarder; - - public static EventForwarder getEventForwarder() { - return eventForwarder; - } - - private static AttributesManager attributesManager; - - public static AttributesManager getAttributesManager() { - return attributesManager; - } - - private static DriversManager driversManager; - - public static DriversManager getDriversManager() { - return driversManager; - } - - private static CommandsManager commandsManager; - - public static CommandsManager getCommandsManager() { - return commandsManager; - } - - private static MaintenancesManager maintenancesManager; - - public static MaintenancesManager getMaintenancesManager() { - return maintenancesManager; - } - - private static SmsManager smsManager; - - public static SmsManager getSmsManager() { - return smsManager; - } - - private static TripsConfig tripsConfig; - - public static TripsConfig getTripsConfig() { - return tripsConfig; - } - - public static TripsConfig initTripsConfig() { - return new TripsConfig( - config.getLong("report.trip.minimalTripDistance", 500), - config.getLong("report.trip.minimalTripDuration", 300) * 1000, - config.getLong("report.trip.minimalParkingDuration", 300) * 1000, - config.getLong("report.trip.minimalNoDataDuration", 3600) * 1000, - config.getBoolean("report.trip.useIgnition"), - config.getBoolean("event.motion.processInvalidPositions"), - config.getDouble("event.motion.speedThreshold", 0.01)); - } - - private static class ObjectMapperContextResolver implements ContextResolver { - - @Override - public ObjectMapper getContext(Class clazz) { - return objectMapper; - } - - } - - public static void init(String configFile) throws Exception { - - try { - config = new Config(configFile); - } catch (Exception e) { - config = new Config(); - Log.setupDefaultLogger(); - throw e; - } - - if (config.getBoolean("logger.enable")) { - Log.setupLogger(config); - } - - objectMapper = new ObjectMapper(); - objectMapper.registerModule(new SanitizerModule()); - objectMapper.registerModule(new JSR353Module()); - objectMapper.setConfig( - objectMapper.getSerializationConfig().without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)); - if (Context.getConfig().getBoolean("mapper.prettyPrintedJson")) { - objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - } - - client = ClientBuilder.newClient().register(new ObjectMapperContextResolver()); - - if (config.hasKey("database.url")) { - dataManager = new DataManager(config); - } - - if (config.getBoolean("ldap.enable")) { - ldapProvider = new LdapProvider(config); - } - - mailManager = new MailManager(); - - mediaManager = new MediaManager(config.getString("media.path")); - - if (dataManager != null) { - usersManager = new UsersManager(dataManager); - groupsManager = new GroupsManager(dataManager); - deviceManager = new DeviceManager(dataManager); - } - - identityManager = deviceManager; - - if (config.getBoolean("web.enable")) { - webServer = new WebServer(config); - } - - permissionsManager = new PermissionsManager(dataManager, usersManager); - - connectionManager = new ConnectionManager(); - - tripsConfig = initTripsConfig(); - - if (config.getBoolean("sms.enable")) { - final String smsManagerClass = config.getString("sms.manager.class", SmppClient.class.getCanonicalName()); - try { - smsManager = (SmsManager) Class.forName(smsManagerClass).newInstance(); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { - LOGGER.warn("Error loading SMS Manager class : " + smsManagerClass, e); - } - } - - if (config.getBoolean("event.enable")) { - initEventsModule(); - } - - serverManager = new ServerManager(); - - if (config.getBoolean("event.forward.enable")) { - eventForwarder = new JsonTypeEventForwarder(); - } - - attributesManager = new AttributesManager(dataManager); - - driversManager = new DriversManager(dataManager); - - commandsManager = new CommandsManager(dataManager, config.getBoolean("commands.queueing")); - - } - - private static void initEventsModule() { - - geofenceManager = new GeofenceManager(dataManager); - calendarManager = new CalendarManager(dataManager); - maintenancesManager = new MaintenancesManager(dataManager); - notificationManager = new NotificationManager(dataManager); - notificatorManager = new NotificatorManager(); - Properties velocityProperties = new Properties(); - velocityProperties.setProperty("file.resource.loader.path", - Context.getConfig().getString("templates.rootPath", "templates") + "/"); - velocityProperties.setProperty("runtime.log.logsystem.class", - "org.apache.velocity.runtime.log.NullLogChute"); - - String address; - try { - address = config.getString("web.address", InetAddress.getLocalHost().getHostAddress()); - } catch (UnknownHostException e) { - address = "localhost"; - } - - String webUrl = URIUtil.newURI("http", address, config.getInteger("web.port", 8082), "", ""); - webUrl = Context.getConfig().getString("web.url", webUrl); - velocityProperties.setProperty("web.url", webUrl); - - velocityEngine = new VelocityEngine(); - velocityEngine.init(velocityProperties); - } - - public static void init(IdentityManager testIdentityManager, MediaManager testMediaManager) { - config = new Config(); - objectMapper = new ObjectMapper(); - objectMapper.registerModule(new JSR353Module()); - client = ClientBuilder.newClient().register(new ObjectMapperContextResolver()); - identityManager = testIdentityManager; - mediaManager = testMediaManager; - } - - public static BaseObjectManager getManager(Class clazz) { - if (clazz.equals(Device.class)) { - return (BaseObjectManager) deviceManager; - } else if (clazz.equals(Group.class)) { - return (BaseObjectManager) groupsManager; - } else if (clazz.equals(User.class)) { - return (BaseObjectManager) usersManager; - } else if (clazz.equals(Calendar.class)) { - return (BaseObjectManager) calendarManager; - } else if (clazz.equals(Attribute.class)) { - return (BaseObjectManager) attributesManager; - } else if (clazz.equals(Geofence.class)) { - return (BaseObjectManager) geofenceManager; - } else if (clazz.equals(Driver.class)) { - return (BaseObjectManager) driversManager; - } else if (clazz.equals(Command.class)) { - return (BaseObjectManager) commandsManager; - } else if (clazz.equals(Maintenance.class)) { - return (BaseObjectManager) maintenancesManager; - } else if (clazz.equals(Notification.class)) { - return (BaseObjectManager) notificationManager; - } - return null; - } - -} diff --git a/src/org/traccar/DeviceSession.java b/src/org/traccar/DeviceSession.java deleted file mode 100644 index 322381807..000000000 --- a/src/org/traccar/DeviceSession.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 java.util.TimeZone; - -public class DeviceSession { - - private final long deviceId; - - public DeviceSession(long deviceId) { - this.deviceId = deviceId; - } - - public long getDeviceId() { - return deviceId; - } - - private TimeZone timeZone; - - public void setTimeZone(TimeZone timeZone) { - this.timeZone = timeZone; - } - - public TimeZone getTimeZone() { - return timeZone; - } - -} diff --git a/src/org/traccar/EventLoopGroupFactory.java b/src/org/traccar/EventLoopGroupFactory.java deleted file mode 100644 index 482559253..000000000 --- a/src/org/traccar/EventLoopGroupFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; - -public final class EventLoopGroupFactory { - - private static EventLoopGroup bossGroup = new NioEventLoopGroup(); - private static EventLoopGroup workerGroup = new NioEventLoopGroup(); - - private EventLoopGroupFactory() { - } - - public static EventLoopGroup getBossGroup() { - return bossGroup; - } - - public static EventLoopGroup getWorkerGroup() { - return workerGroup; - } - -} diff --git a/src/org/traccar/ExtendedObjectDecoder.java b/src/org/traccar/ExtendedObjectDecoder.java deleted file mode 100644 index 681924e87..000000000 --- a/src/org/traccar/ExtendedObjectDecoder.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.util.ReferenceCountUtil; -import org.traccar.helper.DataConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Collection; - -public abstract class ExtendedObjectDecoder extends ChannelInboundHandlerAdapter { - - private void saveOriginal(Object decodedMessage, Object originalMessage) { - if (Context.getConfig().getBoolean("database.saveOriginal") && decodedMessage instanceof Position) { - Position position = (Position) decodedMessage; - if (originalMessage instanceof ByteBuf) { - ByteBuf buf = (ByteBuf) originalMessage; - position.set(Position.KEY_ORIGINAL, ByteBufUtil.hexDump(buf)); - } else if (originalMessage instanceof String) { - position.set(Position.KEY_ORIGINAL, DataConverter.printHex( - ((String) originalMessage).getBytes(StandardCharsets.US_ASCII))); - } - } - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - NetworkMessage networkMessage = (NetworkMessage) msg; - Object originalMessage = networkMessage.getMessage(); - try { - Object decodedMessage = decode(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage); - onMessageEvent(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage, decodedMessage); - if (decodedMessage == null) { - decodedMessage = handleEmptyMessage(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage); - } - if (decodedMessage != null) { - if (decodedMessage instanceof Collection) { - for (Object o : (Collection) decodedMessage) { - saveOriginal(o, originalMessage); - ctx.fireChannelRead(o); - } - } else { - saveOriginal(decodedMessage, originalMessage); - ctx.fireChannelRead(decodedMessage); - } - } - } finally { - ReferenceCountUtil.release(originalMessage); - } - } - - protected void onMessageEvent( - Channel channel, SocketAddress remoteAddress, Object originalMessage, Object decodedMessage) { - } - - protected Object handleEmptyMessage(Channel channel, SocketAddress remoteAddress, Object msg) { - return null; - } - - protected abstract Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception; - -} diff --git a/src/org/traccar/GlobalTimer.java b/src/org/traccar/GlobalTimer.java deleted file mode 100644 index a97321ba2..000000000 --- a/src/org/traccar/GlobalTimer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012 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. - * 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 io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; - -public final class GlobalTimer { - - private static Timer instance = null; - - private GlobalTimer() { - } - - public static void release() { - if (instance != null) { - instance.stop(); - } - instance = null; - } - - public static Timer getTimer() { - if (instance == null) { - instance = new HashedWheelTimer(); - } - return instance; - } - -} diff --git a/src/org/traccar/Main.java b/src/org/traccar/Main.java deleted file mode 100644 index 6ebd1d399..000000000 --- a/src/org/traccar/Main.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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 com.google.inject.Guice; -import com.google.inject.Injector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryMXBean; -import java.lang.management.OperatingSystemMXBean; -import java.lang.management.RuntimeMXBean; -import java.nio.charset.Charset; -import java.sql.SQLException; -import java.util.Timer; -import java.util.TimerTask; -import java.util.Locale; - -public final class Main { - - private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); - - private static final long CLEAN_PERIOD = 24 * 60 * 60 * 1000; - - private static Injector injector; - - public static Injector getInjector() { - return injector; - } - - private Main() { - } - - public static void logSystemInfo() { - try { - OperatingSystemMXBean operatingSystemBean = ManagementFactory.getOperatingSystemMXBean(); - LOGGER.info("Operating system" - + " name: " + operatingSystemBean.getName() - + " version: " + operatingSystemBean.getVersion() - + " architecture: " + operatingSystemBean.getArch()); - - RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); - LOGGER.info("Java runtime" - + " name: " + runtimeBean.getVmName() - + " vendor: " + runtimeBean.getVmVendor() - + " version: " + runtimeBean.getVmVersion()); - - MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); - LOGGER.info("Memory limit" - + " heap: " + memoryBean.getHeapMemoryUsage().getMax() / (1024 * 1024) + "mb" - + " non-heap: " + memoryBean.getNonHeapMemoryUsage().getMax() / (1024 * 1024) + "mb"); - - LOGGER.info("Character encoding: " - + System.getProperty("file.encoding") + " charset: " + Charset.defaultCharset()); - - } catch (Exception error) { - LOGGER.warn("Failed to get system info"); - } - } - - public static void main(String[] args) throws Exception { - Locale.setDefault(Locale.ENGLISH); - - if (args.length <= 0) { - throw new RuntimeException("Configuration file is not provided"); - } - - final String configFile = args[args.length - 1]; - - if (args[0].startsWith("--")) { - WindowsService windowsService = new WindowsService("traccar") { - @Override - public void run() { - Main.run(configFile); - } - }; - switch (args[0]) { - case "--install": - windowsService.install("traccar", null, null, null, null, configFile); - return; - case "--uninstall": - windowsService.uninstall(); - return; - case "--service": - default: - windowsService.init(); - break; - } - } else { - run(configFile); - } - } - - public static void run(String configFile) { - try { - Context.init(configFile); - injector = Guice.createInjector(new MainModule()); - logSystemInfo(); - LOGGER.info("Version: " + Main.class.getPackage().getImplementationVersion()); - LOGGER.info("Starting server..."); - - Context.getServerManager().start(); - if (Context.getWebServer() != null) { - Context.getWebServer().start(); - } - - new Timer().scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - try { - Context.getDataManager().clearHistory(); - } catch (SQLException error) { - LOGGER.warn("Clear history error", error); - } - } - }, 0, CLEAN_PERIOD); - - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - LOGGER.error("Thread exception", e); - } - }); - - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - LOGGER.info("Shutting down server..."); - - if (Context.getWebServer() != null) { - Context.getWebServer().stop(); - } - Context.getServerManager().stop(); - } - }); - } catch (Exception e) { - LOGGER.error("Main method error", e); - throw new RuntimeException(e); - } - } - -} diff --git a/src/org/traccar/MainEventHandler.java b/src/org/traccar/MainEventHandler.java deleted file mode 100644 index a8b53ff60..000000000 --- a/src/org/traccar/MainEventHandler.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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 io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.socket.DatagramChannel; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.timeout.IdleStateEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.database.StatisticsManager; -import org.traccar.helper.DateUtil; -import org.traccar.model.Position; - -import java.sql.SQLException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; - -public class MainEventHandler extends ChannelInboundHandlerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(MainEventHandler.class); - - private static final String DEFAULT_LOGGER_ATTRIBUTES = "time,position,speed,course,accuracy,result"; - - private final Set connectionlessProtocols = new HashSet<>(); - private final Set logAttributes = new LinkedHashSet<>(); - - public MainEventHandler() { - String connectionlessProtocolList = Context.getConfig().getString("status.ignoreOffline"); - if (connectionlessProtocolList != null) { - connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split(","))); - } - logAttributes.addAll(Arrays.asList( - Context.getConfig().getString("logger.attributes", DEFAULT_LOGGER_ATTRIBUTES).split(","))); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - if (msg instanceof Position) { - - Position position = (Position) msg; - try { - Context.getDeviceManager().updateLatestPosition(position); - } catch (SQLException error) { - LOGGER.warn("Failed to update device", error); - } - - String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId(); - - StringBuilder builder = new StringBuilder(); - builder.append(formatChannel(ctx.channel())).append(" "); - builder.append("id: ").append(uniqueId); - for (String attribute : logAttributes) { - switch (attribute) { - case "time": - builder.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false)); - break; - case "position": - builder.append(", lat: ").append(String.format("%.5f", position.getLatitude())); - builder.append(", lon: ").append(String.format("%.5f", position.getLongitude())); - break; - case "speed": - if (position.getSpeed() > 0) { - builder.append(", speed: ").append(String.format("%.1f", position.getSpeed())); - } - break; - case "course": - builder.append(", course: ").append(String.format("%.1f", position.getCourse())); - break; - case "accuracy": - if (position.getAccuracy() > 0) { - builder.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy())); - } - break; - case "outdated": - if (position.getOutdated()) { - builder.append(", outdated"); - } - break; - case "invalid": - if (!position.getValid()) { - builder.append(", invalid"); - } - break; - default: - Object value = position.getAttributes().get(attribute); - if (value != null) { - builder.append(", ").append(attribute).append(": ").append(value); - } - break; - } - } - LOGGER.info(builder.toString()); - - Main.getInjector().getInstance(StatisticsManager.class).registerMessageStored(position.getDeviceId()); - } - } - - private static String formatChannel(Channel channel) { - return String.format("[%s]", channel.id().asShortText()); - } - - @Override - public void channelActive(ChannelHandlerContext ctx) { - if (!(ctx.channel() instanceof DatagramChannel)) { - LOGGER.info(formatChannel(ctx.channel()) + " connected"); - } - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) { - LOGGER.info(formatChannel(ctx.channel()) + " disconnected"); - closeChannel(ctx.channel()); - - if (BasePipelineFactory.getHandler(ctx.pipeline(), HttpRequestDecoder.class) == null - && !connectionlessProtocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName())) { - Context.getConnectionManager().removeActiveDevice(ctx.channel()); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - while (cause.getCause() != null && cause.getCause() != cause) { - cause = cause.getCause(); - } - LOGGER.warn(formatChannel(ctx.channel()) + " error", cause); - closeChannel(ctx.channel()); - } - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { - if (evt instanceof IdleStateEvent) { - LOGGER.info(formatChannel(ctx.channel()) + " timed out"); - closeChannel(ctx.channel()); - } - } - - private void closeChannel(Channel channel) { - if (!(channel instanceof DatagramChannel)) { - channel.close(); - } - } - -} diff --git a/src/org/traccar/MainModule.java b/src/org/traccar/MainModule.java deleted file mode 100644 index 6fe8bad1c..000000000 --- a/src/org/traccar/MainModule.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright 2018 - 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. - * 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 com.fasterxml.jackson.databind.ObjectMapper; -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.Singleton; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.AttributesManager; -import org.traccar.database.CalendarManager; -import org.traccar.database.DataManager; -import org.traccar.database.DeviceManager; -import org.traccar.database.GeofenceManager; -import org.traccar.database.IdentityManager; -import org.traccar.database.MaintenancesManager; -import org.traccar.database.StatisticsManager; -import org.traccar.geocoder.AddressFormat; -import org.traccar.geocoder.BanGeocoder; -import org.traccar.geocoder.BingMapsGeocoder; -import org.traccar.geocoder.FactualGeocoder; -import org.traccar.geocoder.GeocodeFarmGeocoder; -import org.traccar.geocoder.GeocodeXyzGeocoder; -import org.traccar.geocoder.Geocoder; -import org.traccar.geocoder.GisgraphyGeocoder; -import org.traccar.geocoder.GoogleGeocoder; -import org.traccar.geocoder.HereGeocoder; -import org.traccar.geocoder.MapQuestGeocoder; -import org.traccar.geocoder.MapmyIndiaGeocoder; -import org.traccar.geocoder.NominatimGeocoder; -import org.traccar.geocoder.OpenCageGeocoder; -import org.traccar.geolocation.GeolocationProvider; -import org.traccar.geolocation.GoogleGeolocationProvider; -import org.traccar.geolocation.MozillaGeolocationProvider; -import org.traccar.geolocation.OpenCellIdGeolocationProvider; -import org.traccar.geolocation.UnwiredGeolocationProvider; -import org.traccar.handler.ComputedAttributesHandler; -import org.traccar.handler.CopyAttributesHandler; -import org.traccar.handler.DefaultDataHandler; -import org.traccar.handler.DistanceHandler; -import org.traccar.handler.EngineHoursHandler; -import org.traccar.handler.FilterHandler; -import org.traccar.handler.GeocoderHandler; -import org.traccar.handler.GeolocationHandler; -import org.traccar.handler.HemisphereHandler; -import org.traccar.handler.MotionHandler; -import org.traccar.handler.RemoteAddressHandler; -import org.traccar.handler.events.AlertEventHandler; -import org.traccar.handler.events.CommandResultEventHandler; -import org.traccar.handler.events.DriverEventHandler; -import org.traccar.handler.events.FuelDropEventHandler; -import org.traccar.handler.events.GeofenceEventHandler; -import org.traccar.handler.events.IgnitionEventHandler; -import org.traccar.handler.events.MaintenanceEventHandler; -import org.traccar.handler.events.MotionEventHandler; -import org.traccar.handler.events.OverspeedEventHandler; -import org.traccar.reports.model.TripsConfig; - -import javax.annotation.Nullable; -import javax.ws.rs.client.Client; - -public class MainModule extends AbstractModule { - - @Provides - public static ObjectMapper provideObjectMapper() { - return Context.getObjectMapper(); - } - - @Provides - public static Config provideConfig() { - return Context.getConfig(); - } - - @Provides - public static DataManager provideDataManager() { - return Context.getDataManager(); - } - - @Provides - public static IdentityManager provideIdentityManager() { - return Context.getIdentityManager(); - } - - @Provides - public static Client provideClient() { - return Context.getClient(); - } - - @Provides - public static TripsConfig provideTripsConfig() { - return Context.getTripsConfig(); - } - - @Provides - public static DeviceManager provideDeviceManager() { - return Context.getDeviceManager(); - } - - @Provides - public static GeofenceManager provideGeofenceManager() { - return Context.getGeofenceManager(); - } - - @Provides - public static CalendarManager provideCalendarManager() { - return Context.getCalendarManager(); - } - - @Provides - public static AttributesManager provideAttributesManager() { - return Context.getAttributesManager(); - } - - @Provides - public static MaintenancesManager provideMaintenancesManager() { - return Context.getMaintenancesManager(); - } - - @Singleton - @Provides - public static StatisticsManager provideStatisticsManager(Config config, DataManager dataManager, Client client) { - return new StatisticsManager(config, dataManager, client); - } - - @Singleton - @Provides - public static Geocoder provideGeocoder(Config config) { - if (config.getBoolean(Keys.GEOCODER_ENABLE)) { - String type = config.getString(Keys.GEOCODER_TYPE, "google"); - String url = config.getString(Keys.GEOCODER_URL); - String id = config.getString(Keys.GEOCODER_ID); - String key = config.getString(Keys.GEOCODER_KEY); - String language = config.getString(Keys.GEOCODER_LANGUAGE); - String formatString = config.getString(Keys.GEOCODER_FORMAT); - AddressFormat addressFormat = formatString != null ? new AddressFormat(formatString) : new AddressFormat(); - - int cacheSize = config.getInteger(Keys.GEOCODER_CACHE_SIZE); - switch (type) { - case "nominatim": - return new NominatimGeocoder(url, key, language, cacheSize, addressFormat); - case "gisgraphy": - return new GisgraphyGeocoder(url, cacheSize, addressFormat); - case "mapquest": - return new MapQuestGeocoder(url, key, cacheSize, addressFormat); - case "opencage": - return new OpenCageGeocoder(url, key, cacheSize, addressFormat); - case "bingmaps": - return new BingMapsGeocoder(url, key, cacheSize, addressFormat); - case "factual": - return new FactualGeocoder(url, key, cacheSize, addressFormat); - case "geocodefarm": - return new GeocodeFarmGeocoder(key, language, cacheSize, addressFormat); - case "geocodexyz": - return new GeocodeXyzGeocoder(key, cacheSize, addressFormat); - case "ban": - return new BanGeocoder(cacheSize, addressFormat); - case "here": - return new HereGeocoder(id, key, language, cacheSize, addressFormat); - case "mapmyindia": - return new MapmyIndiaGeocoder(url, key, cacheSize, addressFormat); - default: - return new GoogleGeocoder(key, language, cacheSize, addressFormat); - } - } - return null; - } - - @Singleton - @Provides - public static GeolocationProvider provideGeolocationProvider(Config config) { - if (config.getBoolean(Keys.GEOLOCATION_ENABLE)) { - String type = config.getString(Keys.GEOLOCATION_TYPE, "mozilla"); - String url = config.getString(Keys.GEOLOCATION_URL); - String key = config.getString(Keys.GEOLOCATION_KEY); - switch (type) { - case "google": - return new GoogleGeolocationProvider(key); - case "opencellid": - return new OpenCellIdGeolocationProvider(key); - case "unwired": - return new UnwiredGeolocationProvider(url, key); - default: - return new MozillaGeolocationProvider(key); - } - } - return null; - } - - @Singleton - @Provides - public static DistanceHandler provideDistanceHandler(Config config, IdentityManager identityManager) { - return new DistanceHandler(config, identityManager); - } - - @Singleton - @Provides - public static FilterHandler provideFilterHandler(Config config) { - if (config.getBoolean(Keys.FILTER_ENABLE)) { - return new FilterHandler(config); - } - return null; - } - - @Singleton - @Provides - public static HemisphereHandler provideHemisphereHandler(Config config) { - if (config.hasKey(Keys.LOCATION_LATITUDE_HEMISPHERE) || config.hasKey(Keys.LOCATION_LONGITUDE_HEMISPHERE)) { - return new HemisphereHandler(config); - } - return null; - } - - @Singleton - @Provides - public static RemoteAddressHandler provideRemoteAddressHandler(Config config) { - if (config.getBoolean(Keys.PROCESSING_REMOTE_ADDRESS_ENABLE)) { - return new RemoteAddressHandler(); - } - return null; - } - - @Singleton - @Provides - public static WebDataHandler provideWebDataHandler( - Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) { - if (config.getBoolean(Keys.FORWARD_ENABLE)) { - return new WebDataHandler(config, identityManager, objectMapper, client); - } - return null; - } - - @Singleton - @Provides - public static GeolocationHandler provideGeolocationHandler( - Config config, @Nullable GeolocationProvider geolocationProvider, StatisticsManager statisticsManager) { - if (geolocationProvider != null) { - return new GeolocationHandler(config, geolocationProvider, statisticsManager); - } - return null; - } - - @Singleton - @Provides - public static GeocoderHandler provideGeocoderHandler( - Config config, @Nullable Geocoder geocoder, IdentityManager identityManager, - StatisticsManager statisticsManager) { - if (geocoder != null) { - return new GeocoderHandler(config, geocoder, identityManager, statisticsManager); - } - return null; - } - - @Singleton - @Provides - public static MotionHandler provideMotionHandler(TripsConfig tripsConfig) { - return new MotionHandler(tripsConfig.getSpeedThreshold()); - } - - @Singleton - @Provides - public static EngineHoursHandler provideEngineHoursHandler(Config config, IdentityManager identityManager) { - if (config.getBoolean(Keys.PROCESSING_ENGINE_HOURS_ENABLE)) { - return new EngineHoursHandler(identityManager); - } - return null; - } - - @Singleton - @Provides - public static CopyAttributesHandler provideCopyAttributesHandler(Config config, IdentityManager identityManager) { - if (config.getBoolean(Keys.PROCESSING_COPY_ATTRIBUTES_ENABLE)) { - return new CopyAttributesHandler(identityManager); - } - return null; - } - - @Singleton - @Provides - public static ComputedAttributesHandler provideComputedAttributesHandler( - Config config, IdentityManager identityManager, AttributesManager attributesManager) { - if (config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_ENABLE)) { - return new ComputedAttributesHandler(config, identityManager, attributesManager); - } - return null; - } - - @Singleton - @Provides - public static DefaultDataHandler provideDefaultDataHandler(@Nullable DataManager dataManager) { - if (dataManager != null) { - return new DefaultDataHandler(dataManager); - } - return null; - } - - @Singleton - @Provides - public static CommandResultEventHandler provideCommandResultEventHandler() { - return new CommandResultEventHandler(); - } - - @Singleton - @Provides - public static OverspeedEventHandler provideOverspeedEventHandler( - Config config, DeviceManager deviceManager, GeofenceManager geofenceManager) { - return new OverspeedEventHandler(config, deviceManager, geofenceManager); - } - - @Singleton - @Provides - public static FuelDropEventHandler provideFuelDropEventHandler(IdentityManager identityManager) { - return new FuelDropEventHandler(identityManager); - } - - @Singleton - @Provides - public static MotionEventHandler provideMotionEventHandler( - IdentityManager identityManager, DeviceManager deviceManager, TripsConfig tripsConfig) { - return new MotionEventHandler(identityManager, deviceManager, tripsConfig); - } - - @Singleton - @Provides - public static GeofenceEventHandler provideGeofenceEventHandler( - IdentityManager identityManager, GeofenceManager geofenceManager, CalendarManager calendarManager) { - return new GeofenceEventHandler(identityManager, geofenceManager, calendarManager); - } - - @Singleton - @Provides - public static AlertEventHandler provideAlertEventHandler(Config config, IdentityManager identityManager) { - return new AlertEventHandler(config, identityManager); - } - - @Singleton - @Provides - public static IgnitionEventHandler provideIgnitionEventHandler(IdentityManager identityManager) { - return new IgnitionEventHandler(identityManager); - } - - @Singleton - @Provides - public static MaintenanceEventHandler provideMaintenanceEventHandler( - IdentityManager identityManager, MaintenancesManager maintenancesManager) { - return new MaintenanceEventHandler(identityManager, maintenancesManager); - } - - @Singleton - @Provides - public static DriverEventHandler provideDriverEventHandler(IdentityManager identityManager) { - return new DriverEventHandler(identityManager); - } - - @Override - protected void configure() { - binder().requireExplicitBindings(); - } - -} diff --git a/src/org/traccar/NetworkMessage.java b/src/org/traccar/NetworkMessage.java deleted file mode 100644 index 14a397e69..000000000 --- a/src/org/traccar/NetworkMessage.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 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. - * 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 java.net.SocketAddress; - -public class NetworkMessage { - - private final SocketAddress remoteAddress; - private final Object message; - - public NetworkMessage(Object message, SocketAddress remoteAddress) { - this.message = message; - this.remoteAddress = remoteAddress; - } - - public SocketAddress getRemoteAddress() { - return remoteAddress; - } - - public Object getMessage() { - return message; - } - -} diff --git a/src/org/traccar/PipelineBuilder.java b/src/org/traccar/PipelineBuilder.java deleted file mode 100644 index 3334040b1..000000000 --- a/src/org/traccar/PipelineBuilder.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.ChannelHandler; - -public interface PipelineBuilder { - - void addLast(ChannelHandler handler); - -} diff --git a/src/org/traccar/Protocol.java b/src/org/traccar/Protocol.java deleted file mode 100644 index 3b66f2598..000000000 --- a/src/org/traccar/Protocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 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. - * 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.database.ActiveDevice; -import org.traccar.model.Command; - -import java.util.Collection; - -public interface Protocol { - - String getName(); - - Collection getServerList(); - - Collection getSupportedDataCommands(); - - void sendDataCommand(ActiveDevice activeDevice, Command command); - - Collection getSupportedTextCommands(); - - void sendTextCommand(String destAddress, Command command) throws Exception; - -} diff --git a/src/org/traccar/ServerManager.java b/src/org/traccar/ServerManager.java deleted file mode 100644 index 6a3273402..000000000 --- a/src/org/traccar/ServerManager.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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. - * 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.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.net.BindException; -import java.net.URI; -import java.net.URL; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.Enumeration; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -public class ServerManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(ServerManager.class); - - private final List serverList = new LinkedList<>(); - private final Map protocolList = new ConcurrentHashMap<>(); - - public ServerManager() throws Exception { - - List names = new LinkedList<>(); - String packageName = "org.traccar.protocol"; - String packagePath = packageName.replace('.', '/'); - URL packageUrl = getClass().getClassLoader().getResource(packagePath); - - if (packageUrl.getProtocol().equals("jar")) { - String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8.name()); - try (JarFile jf = new JarFile(jarFileName.substring(5, jarFileName.indexOf("!")))) { - Enumeration jarEntries = jf.entries(); - while (jarEntries.hasMoreElements()) { - String entryName = jarEntries.nextElement().getName(); - if (entryName.startsWith(packagePath) && entryName.length() > packagePath.length() + 5) { - names.add(entryName.substring(packagePath.length() + 1, entryName.lastIndexOf('.'))); - } - } - } - } else { - File folder = new File(new URI(packageUrl.toString())); - File[] files = folder.listFiles(); - if (files != null) { - for (File actual: files) { - String entryName = actual.getName(); - names.add(entryName.substring(0, entryName.lastIndexOf('.'))); - } - } - } - - for (String name : names) { - Class protocolClass = Class.forName(packageName + '.' + name); - if (BaseProtocol.class.isAssignableFrom(protocolClass) - && Context.getConfig().hasKey(BaseProtocol.nameFromClass(protocolClass) + ".port")) { - BaseProtocol protocol = (BaseProtocol) protocolClass.newInstance(); - serverList.addAll(protocol.getServerList()); - protocolList.put(protocol.getName(), protocol); - } - } - } - - public BaseProtocol getProtocol(String name) { - return protocolList.get(name); - } - - public void start() throws Exception { - for (TrackerServer server: serverList) { - try { - server.start(); - } catch (BindException e) { - LOGGER.warn("Port {} is disabled due to conflict", server.getPort()); - } - } - } - - public void stop() { - for (TrackerServer server: serverList) { - server.stop(); - } - GlobalTimer.release(); - } - -} diff --git a/src/org/traccar/StringProtocolEncoder.java b/src/org/traccar/StringProtocolEncoder.java deleted file mode 100644 index 1945ae174..000000000 --- a/src/org/traccar/StringProtocolEncoder.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 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. - * 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.model.Command; - -import java.util.Map; - -public abstract class StringProtocolEncoder extends BaseProtocolEncoder { - - public interface ValueFormatter { - String formatValue(String key, Object value); - } - - protected String formatCommand(Command command, String format, ValueFormatter valueFormatter, String... keys) { - - String result = String.format(format, (Object[]) keys); - - result = result.replaceAll("\\{" + Command.KEY_UNIQUE_ID + "}", getUniqueId(command.getDeviceId())); - for (Map.Entry entry : command.getAttributes().entrySet()) { - String value = null; - if (valueFormatter != null) { - value = valueFormatter.formatValue(entry.getKey(), entry.getValue()); - } - if (value == null) { - value = entry.getValue().toString(); - } - result = result.replaceAll("\\{" + entry.getKey() + "}", value); - } - - return result; - } - - protected String formatCommand(Command command, String format, String... keys) { - return formatCommand(command, format, null, keys); - } - -} diff --git a/src/org/traccar/TrackerServer.java b/src/org/traccar/TrackerServer.java deleted file mode 100644 index 3a1e1c4e8..000000000 --- a/src/org/traccar/TrackerServer.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - * 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 io.netty.bootstrap.AbstractBootstrap; -import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.Channel; -import io.netty.channel.group.ChannelGroup; -import io.netty.channel.group.DefaultChannelGroup; -import io.netty.channel.socket.nio.NioDatagramChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.util.concurrent.GlobalEventExecutor; - -import java.net.InetSocketAddress; - -public abstract class TrackerServer { - - private final boolean datagram; - private final AbstractBootstrap bootstrap; - - public boolean isDatagram() { - return datagram; - } - - public TrackerServer(boolean datagram, String protocol) { - this.datagram = datagram; - - address = Context.getConfig().getString(protocol + ".address"); - port = Context.getConfig().getInteger(protocol + ".port"); - - BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, protocol) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - TrackerServer.this.addProtocolHandlers(pipeline); - } - }; - - if (datagram) { - - this.bootstrap = new Bootstrap() - .group(EventLoopGroupFactory.getWorkerGroup()) - .channel(NioDatagramChannel.class) - .handler(pipelineFactory); - - } else { - - this.bootstrap = new ServerBootstrap() - .group(EventLoopGroupFactory.getBossGroup(), EventLoopGroupFactory.getWorkerGroup()) - .channel(NioServerSocketChannel.class) - .childHandler(pipelineFactory); - - } - } - - protected abstract void addProtocolHandlers(PipelineBuilder pipeline); - - private int port; - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - private String address; - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - private final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); - - public ChannelGroup getChannelGroup() { - return channelGroup; - } - - public void start() throws Exception { - InetSocketAddress endpoint; - if (address == null) { - endpoint = new InetSocketAddress(port); - } else { - endpoint = new InetSocketAddress(address, port); - } - - Channel channel = bootstrap.bind(endpoint).sync().channel(); - if (channel != null) { - getChannelGroup().add(channel); - } - } - - public void stop() { - channelGroup.close().awaitUninterruptibly(); - } - -} diff --git a/src/org/traccar/WebDataHandler.java b/src/org/traccar/WebDataHandler.java deleted file mode 100644 index 64396de03..000000000 --- a/src/org/traccar/WebDataHandler.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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 com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.netty.channel.ChannelHandler; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.IdentityManager; -import org.traccar.helper.Checksum; -import org.traccar.model.Device; -import org.traccar.model.Position; -import org.traccar.model.Group; - -import javax.inject.Inject; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.Invocation; -import java.util.HashMap; -import java.util.Map; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Calendar; -import java.util.Formatter; -import java.util.Locale; -import java.util.TimeZone; - -@ChannelHandler.Sharable -public class WebDataHandler extends BaseDataHandler { - - private static final String KEY_POSITION = "position"; - private static final String KEY_DEVICE = "device"; - - private final IdentityManager identityManager; - private final ObjectMapper objectMapper; - private final Client client; - - private final String url; - private final String header; - private final boolean json; - - @Inject - public WebDataHandler( - Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) { - this.identityManager = identityManager; - this.objectMapper = objectMapper; - this.client = client; - this.url = config.getString(Keys.FORWARD_URL); - this.header = config.getString(Keys.FORWARD_HEADER); - this.json = config.getBoolean(Keys.FORWARD_JSON); - } - - private static String formatSentence(Position position) { - - StringBuilder s = new StringBuilder("$GPRMC,"); - - try (Formatter f = new Formatter(s, Locale.ENGLISH)) { - - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ENGLISH); - calendar.setTimeInMillis(position.getFixTime().getTime()); - - f.format("%1$tH%1$tM%1$tS.%1$tL,A,", calendar); - - double lat = position.getLatitude(); - double lon = position.getLongitude(); - - f.format("%02d%07.4f,%c,", (int) Math.abs(lat), Math.abs(lat) % 1 * 60, lat < 0 ? 'S' : 'N'); - f.format("%03d%07.4f,%c,", (int) Math.abs(lon), Math.abs(lon) % 1 * 60, lon < 0 ? 'W' : 'E'); - - f.format("%.2f,%.2f,", position.getSpeed(), position.getCourse()); - f.format("%1$td%1$tm%1$ty,,", calendar); - } - - s.append(Checksum.nmea(s.toString())); - - return s.toString(); - } - - private String calculateStatus(Position position) { - if (position.getAttributes().containsKey(Position.KEY_ALARM)) { - return "0xF841"; // STATUS_PANIC_ON - } else if (position.getSpeed() < 1.0) { - return "0xF020"; // STATUS_LOCATION - } else { - return "0xF11C"; // STATUS_MOTION_MOVING - } - } - - public String formatRequest(Position position) throws UnsupportedEncodingException, JsonProcessingException { - - Device device = identityManager.getById(position.getDeviceId()); - - String request = url - .replace("{name}", URLEncoder.encode(device.getName(), StandardCharsets.UTF_8.name())) - .replace("{uniqueId}", device.getUniqueId()) - .replace("{status}", device.getStatus()) - .replace("{deviceId}", String.valueOf(position.getDeviceId())) - .replace("{protocol}", String.valueOf(position.getProtocol())) - .replace("{deviceTime}", String.valueOf(position.getDeviceTime().getTime())) - .replace("{fixTime}", String.valueOf(position.getFixTime().getTime())) - .replace("{valid}", String.valueOf(position.getValid())) - .replace("{latitude}", String.valueOf(position.getLatitude())) - .replace("{longitude}", String.valueOf(position.getLongitude())) - .replace("{altitude}", String.valueOf(position.getAltitude())) - .replace("{speed}", String.valueOf(position.getSpeed())) - .replace("{course}", String.valueOf(position.getCourse())) - .replace("{accuracy}", String.valueOf(position.getAccuracy())) - .replace("{statusCode}", calculateStatus(position)); - - if (position.getAddress() != null) { - request = request.replace( - "{address}", URLEncoder.encode(position.getAddress(), StandardCharsets.UTF_8.name())); - } - - if (request.contains("{attributes}")) { - String attributes = objectMapper.writeValueAsString(position.getAttributes()); - request = request.replace( - "{attributes}", URLEncoder.encode(attributes, StandardCharsets.UTF_8.name())); - } - - if (request.contains("{gprmc}")) { - request = request.replace("{gprmc}", formatSentence(position)); - } - - if (request.contains("{group}")) { - String deviceGroupName = ""; - if (device.getGroupId() != 0) { - Group group = Context.getGroupsManager().getById(device.getGroupId()); - if (group != null) { - deviceGroupName = group.getName(); - } - } - - request = request.replace("{group}", URLEncoder.encode(deviceGroupName, StandardCharsets.UTF_8.name())); - } - - return request; - } - - @Override - protected Position handlePosition(Position position) { - - String url; - if (json) { - url = this.url; - } else { - try { - url = formatRequest(position); - } catch (UnsupportedEncodingException | JsonProcessingException e) { - throw new RuntimeException("Forwarding formatting error", e); - } - } - - Invocation.Builder requestBuilder = client.target(url).request(); - - if (header != null && !header.isEmpty()) { - for (String line: header.split("\\r?\\n")) { - String[] values = line.split(":", 2); - requestBuilder.header(values[0].trim(), values[1].trim()); - } - } - - if (json) { - requestBuilder.async().post(Entity.json(prepareJsonPayload(position))); - } else { - requestBuilder.async().get(); - } - - return position; - } - - private Map prepareJsonPayload(Position position) { - - Map data = new HashMap<>(); - Device device = identityManager.getById(position.getDeviceId()); - - data.put(KEY_POSITION, position); - - if (device != null) { - data.put(KEY_DEVICE, device); - } - - return data; - } - -} diff --git a/src/org/traccar/WindowsService.java b/src/org/traccar/WindowsService.java deleted file mode 100644 index 4a8955608..000000000 --- a/src/org/traccar/WindowsService.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 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. - * 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 com.sun.jna.Pointer; -import com.sun.jna.platform.win32.Advapi32; -import com.sun.jna.platform.win32.WinError; -import com.sun.jna.platform.win32.WinNT; -import com.sun.jna.platform.win32.Winsvc; -import com.sun.jna.platform.win32.Winsvc.HandlerEx; -import com.sun.jna.platform.win32.Winsvc.SC_HANDLE; -import com.sun.jna.platform.win32.Winsvc.SERVICE_DESCRIPTION; -import com.sun.jna.platform.win32.Winsvc.SERVICE_MAIN_FUNCTION; -import com.sun.jna.platform.win32.Winsvc.SERVICE_STATUS; -import com.sun.jna.platform.win32.Winsvc.SERVICE_STATUS_HANDLE; -import com.sun.jna.platform.win32.Winsvc.SERVICE_TABLE_ENTRY; -import jnr.posix.POSIXFactory; - -import java.io.File; -import java.net.URISyntaxException; - -public abstract class WindowsService { - - private static final Advapi32 ADVAPI_32 = Advapi32.INSTANCE; - - private final Object waitObject = new Object(); - - private String serviceName; - private ServiceMain serviceMain; - private ServiceControl serviceControl; - private SERVICE_STATUS_HANDLE serviceStatusHandle; - - public WindowsService(String serviceName) { - this.serviceName = serviceName; - } - - public boolean install( - String displayName, String description, String[] dependencies, - String account, String password, String config) throws URISyntaxException { - - String javaHome = System.getProperty("java.home"); - String javaBinary = javaHome + "\\bin\\java.exe"; - - File jar = new File(WindowsService.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - String command = javaBinary - + " -Duser.dir=\"" + jar.getParentFile().getAbsolutePath() + "\"" - + " -jar \"" + jar.getAbsolutePath() + "\"" - + " --service \"" + config + "\""; - - boolean success = false; - StringBuilder dep = new StringBuilder(); - - if (dependencies != null) { - for (String s : dependencies) { - dep.append(s); - dep.append("\0"); - } - } - dep.append("\0"); - - SERVICE_DESCRIPTION desc = new SERVICE_DESCRIPTION(); - desc.lpDescription = description; - - SC_HANDLE serviceManager = openServiceControlManager(null, Winsvc.SC_MANAGER_ALL_ACCESS); - - if (serviceManager != null) { - SC_HANDLE service = ADVAPI_32.CreateService(serviceManager, serviceName, displayName, - Winsvc.SERVICE_ALL_ACCESS, WinNT.SERVICE_WIN32_OWN_PROCESS, WinNT.SERVICE_AUTO_START, - WinNT.SERVICE_ERROR_NORMAL, - command, - null, null, dep.toString(), account, password); - - if (service != null) { - success = ADVAPI_32.ChangeServiceConfig2(service, Winsvc.SERVICE_CONFIG_DESCRIPTION, desc); - ADVAPI_32.CloseServiceHandle(service); - } - ADVAPI_32.CloseServiceHandle(serviceManager); - } - return success; - } - - public boolean uninstall() { - boolean success = false; - - SC_HANDLE serviceManager = openServiceControlManager(null, Winsvc.SC_MANAGER_ALL_ACCESS); - - if (serviceManager != null) { - SC_HANDLE service = ADVAPI_32.OpenService(serviceManager, serviceName, Winsvc.SERVICE_ALL_ACCESS); - - if (service != null) { - success = ADVAPI_32.DeleteService(service); - ADVAPI_32.CloseServiceHandle(service); - } - ADVAPI_32.CloseServiceHandle(serviceManager); - } - return success; - } - - public boolean start() { - boolean success = false; - - SC_HANDLE serviceManager = openServiceControlManager(null, WinNT.GENERIC_EXECUTE); - - if (serviceManager != null) { - SC_HANDLE service = ADVAPI_32.OpenService(serviceManager, serviceName, WinNT.GENERIC_EXECUTE); - - if (service != null) { - success = ADVAPI_32.StartService(service, 0, null); - ADVAPI_32.CloseServiceHandle(service); - } - ADVAPI_32.CloseServiceHandle(serviceManager); - } - - return success; - } - - public boolean stop() { - boolean success = false; - - SC_HANDLE serviceManager = openServiceControlManager(null, WinNT.GENERIC_EXECUTE); - - if (serviceManager != null) { - SC_HANDLE service = Advapi32.INSTANCE.OpenService(serviceManager, serviceName, WinNT.GENERIC_EXECUTE); - - if (service != null) { - SERVICE_STATUS serviceStatus = new SERVICE_STATUS(); - success = Advapi32.INSTANCE.ControlService(service, Winsvc.SERVICE_CONTROL_STOP, serviceStatus); - Advapi32.INSTANCE.CloseServiceHandle(service); - } - Advapi32.INSTANCE.CloseServiceHandle(serviceManager); - } - - return success; - } - - public void init() throws URISyntaxException { - String path = new File( - WindowsService.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); - - POSIXFactory.getPOSIX().chdir(path); - - serviceMain = new ServiceMain(); - SERVICE_TABLE_ENTRY entry = new SERVICE_TABLE_ENTRY(); - entry.lpServiceName = serviceName; - entry.lpServiceProc = serviceMain; - - Advapi32.INSTANCE.StartServiceCtrlDispatcher((SERVICE_TABLE_ENTRY[]) entry.toArray(2)); - } - - private SC_HANDLE openServiceControlManager(String machine, int access) { - return ADVAPI_32.OpenSCManager(machine, null, access); - } - - private void reportStatus(int status, int win32ExitCode, int waitHint) { - SERVICE_STATUS serviceStatus = new SERVICE_STATUS(); - serviceStatus.dwServiceType = WinNT.SERVICE_WIN32_OWN_PROCESS; - serviceStatus.dwControlsAccepted = Winsvc.SERVICE_ACCEPT_STOP | Winsvc.SERVICE_ACCEPT_SHUTDOWN; - serviceStatus.dwWin32ExitCode = win32ExitCode; - serviceStatus.dwWaitHint = waitHint; - serviceStatus.dwCurrentState = status; - - ADVAPI_32.SetServiceStatus(serviceStatusHandle, serviceStatus); - } - - public abstract void run(); - - private class ServiceMain implements SERVICE_MAIN_FUNCTION { - - public void callback(int dwArgc, Pointer lpszArgv) { - serviceControl = new ServiceControl(); - serviceStatusHandle = ADVAPI_32.RegisterServiceCtrlHandlerEx(serviceName, serviceControl, null); - - reportStatus(Winsvc.SERVICE_START_PENDING, WinError.NO_ERROR, 3000); - reportStatus(Winsvc.SERVICE_RUNNING, WinError.NO_ERROR, 0); - - Thread.currentThread().setContextClassLoader(WindowsService.class.getClassLoader()); - - run(); - - try { - synchronized (waitObject) { - waitObject.wait(); - } - } catch (InterruptedException ex) { - } - - reportStatus(Winsvc.SERVICE_STOPPED, WinError.NO_ERROR, 0); - - // Avoid returning from ServiceMain, which will cause a crash - // See http://support.microsoft.com/kb/201349, which recommends - // having init() wait for this thread. - // Waiting on this thread in init() won't fix the crash, though. - - System.exit(0); - } - - } - - private class ServiceControl implements HandlerEx { - - public int callback(int dwControl, int dwEventType, Pointer lpEventData, Pointer lpContext) { - switch (dwControl) { - case Winsvc.SERVICE_CONTROL_STOP: - case Winsvc.SERVICE_CONTROL_SHUTDOWN: - reportStatus(Winsvc.SERVICE_STOP_PENDING, WinError.NO_ERROR, 5000); - synchronized (waitObject) { - waitObject.notifyAll(); - } - break; - default: - break; - } - return WinError.NO_ERROR; - } - - } - -} diff --git a/src/org/traccar/WrapperContext.java b/src/org/traccar/WrapperContext.java deleted file mode 100644 index 372d3c60d..000000000 --- a/src/org/traccar/WrapperContext.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelProgressivePromise; -import io.netty.channel.ChannelPromise; -import io.netty.util.Attribute; -import io.netty.util.AttributeKey; -import io.netty.util.concurrent.EventExecutor; - -import java.net.SocketAddress; - -public class WrapperContext implements ChannelHandlerContext { - - private ChannelHandlerContext context; - private SocketAddress remoteAddress; - - public WrapperContext(ChannelHandlerContext context, SocketAddress remoteAddress) { - this.context = context; - this.remoteAddress = remoteAddress; - } - - @Override - public Channel channel() { - return context.channel(); - } - - @Override - public EventExecutor executor() { - return context.executor(); - } - - @Override - public String name() { - return context.name(); - } - - @Override - public ChannelHandler handler() { - return context.handler(); - } - - @Override - public boolean isRemoved() { - return context.isRemoved(); - } - - @Override - public ChannelHandlerContext fireChannelRegistered() { - return context.fireChannelRegistered(); - } - - @Override - public ChannelHandlerContext fireChannelUnregistered() { - return context.fireChannelUnregistered(); - } - - @Override - public ChannelHandlerContext fireChannelActive() { - return context.fireChannelActive(); - } - - @Override - public ChannelHandlerContext fireChannelInactive() { - return context.fireChannelInactive(); - } - - @Override - public ChannelHandlerContext fireExceptionCaught(Throwable cause) { - return context.fireExceptionCaught(cause); - } - - @Override - public ChannelHandlerContext fireUserEventTriggered(Object evt) { - return context.fireUserEventTriggered(evt); - } - - @Override - public ChannelHandlerContext fireChannelRead(Object msg) { - if (!(msg instanceof NetworkMessage)) { - msg = new NetworkMessage(msg, remoteAddress); - } - return context.fireChannelRead(msg); - } - - @Override - public ChannelHandlerContext fireChannelReadComplete() { - return context.fireChannelReadComplete(); - } - - @Override - public ChannelHandlerContext fireChannelWritabilityChanged() { - return context.fireChannelWritabilityChanged(); - } - - @Override - public ChannelFuture bind(SocketAddress localAddress) { - return context.bind(localAddress); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress) { - return context.connect(remoteAddress); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { - return context.connect(remoteAddress, localAddress); - } - - @Override - public ChannelFuture disconnect() { - return context.disconnect(); - } - - @Override - public ChannelFuture close() { - return context.close(); - } - - @Override - public ChannelFuture deregister() { - return context.deregister(); - } - - @Override - public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { - return context.bind(localAddress, promise); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { - return context.connect(remoteAddress, promise); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { - return context.connect(remoteAddress, localAddress, promise); - } - - @Override - public ChannelFuture disconnect(ChannelPromise promise) { - return context.disconnect(promise); - } - - @Override - public ChannelFuture close(ChannelPromise promise) { - return context.close(promise); - } - - @Override - public ChannelFuture deregister(ChannelPromise promise) { - return context.deregister(promise); - } - - @Override - public ChannelHandlerContext read() { - return context.read(); - } - - @Override - public ChannelFuture write(Object msg) { - return context.write(msg); - } - - @Override - public ChannelFuture write(Object msg, ChannelPromise promise) { - if (!(msg instanceof NetworkMessage)) { - msg = new NetworkMessage(msg, remoteAddress); - } - return context.write(msg, promise); - } - - @Override - public ChannelHandlerContext flush() { - return context.flush(); - } - - @Override - public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { - return context.writeAndFlush(msg, promise); - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { - return context.writeAndFlush(msg); - } - - @Override - public ChannelPromise newPromise() { - return context.newPromise(); - } - - @Override - public ChannelProgressivePromise newProgressivePromise() { - return context.newProgressivePromise(); - } - - @Override - public ChannelFuture newSucceededFuture() { - return context.newSucceededFuture(); - } - - @Override - public ChannelFuture newFailedFuture(Throwable cause) { - return context.newFailedFuture(cause); - } - - @Override - public ChannelPromise voidPromise() { - return context.voidPromise(); - } - - @Override - public ChannelPipeline pipeline() { - return context.pipeline(); - } - - @Override - public ByteBufAllocator alloc() { - return context.alloc(); - } - - @SuppressWarnings("deprecation") - @Override - public Attribute attr(AttributeKey key) { - return context.attr(key); - } - - @SuppressWarnings("deprecation") - @Override - public boolean hasAttr(AttributeKey key) { - return context.hasAttr(key); - } - -} diff --git a/src/org/traccar/WrapperInboundHandler.java b/src/org/traccar/WrapperInboundHandler.java deleted file mode 100644 index ca33d021f..000000000 --- a/src/org/traccar/WrapperInboundHandler.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandler; - -public class WrapperInboundHandler implements ChannelInboundHandler { - - private ChannelInboundHandler handler; - - public ChannelInboundHandler getWrappedHandler() { - return handler; - } - - public WrapperInboundHandler(ChannelInboundHandler handler) { - this.handler = handler; - } - - @Override - public void channelRegistered(ChannelHandlerContext ctx) throws Exception { - handler.channelRegistered(ctx); - } - - @Override - public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { - handler.channelUnregistered(ctx); - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - handler.channelActive(ctx); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - handler.channelInactive(ctx); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof NetworkMessage) { - NetworkMessage nm = (NetworkMessage) msg; - handler.channelRead(new WrapperContext(ctx, nm.getRemoteAddress()), nm.getMessage()); - } else { - handler.channelRead(ctx, msg); - } - } - - @Override - public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { - handler.channelReadComplete(ctx); - } - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - handler.userEventTriggered(ctx, evt); - } - - @Override - public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { - handler.channelWritabilityChanged(ctx); - } - - @Override - public void handlerAdded(ChannelHandlerContext ctx) throws Exception { - handler.handlerAdded(ctx); - } - - @Override - public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { - handler.handlerRemoved(ctx); - } - - @SuppressWarnings("deprecation") - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - handler.exceptionCaught(ctx, cause); - } - -} diff --git a/src/org/traccar/WrapperOutboundHandler.java b/src/org/traccar/WrapperOutboundHandler.java deleted file mode 100644 index 0136c5b22..000000000 --- a/src/org/traccar/WrapperOutboundHandler.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundHandler; -import io.netty.channel.ChannelPromise; - -import java.net.SocketAddress; - -public class WrapperOutboundHandler implements ChannelOutboundHandler { - - private ChannelOutboundHandler handler; - - public ChannelOutboundHandler getWrappedHandler() { - return handler; - } - - public WrapperOutboundHandler(ChannelOutboundHandler handler) { - this.handler = handler; - } - - @Override - public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception { - handler.bind(ctx, localAddress, promise); - } - - @Override - public void connect( - ChannelHandlerContext ctx, SocketAddress remoteAddress, - SocketAddress localAddress, ChannelPromise promise) throws Exception { - handler.connect(ctx, remoteAddress, localAddress, promise); - } - - @Override - public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - handler.disconnect(ctx, promise); - } - - @Override - public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - handler.close(ctx, promise); - } - - @Override - public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - handler.deregister(ctx, promise); - } - - @Override - public void read(ChannelHandlerContext ctx) throws Exception { - handler.read(ctx); - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - if (msg instanceof NetworkMessage) { - NetworkMessage nm = (NetworkMessage) msg; - handler.write(new WrapperContext(ctx, nm.getRemoteAddress()), nm.getMessage(), promise); - } else { - handler.write(ctx, msg, promise); - } - } - - @Override - public void flush(ChannelHandlerContext ctx) throws Exception { - handler.flush(ctx); - } - - @Override - public void handlerAdded(ChannelHandlerContext ctx) throws Exception { - handler.handlerAdded(ctx); - } - - @Override - public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { - handler.handlerRemoved(ctx); - } - - @SuppressWarnings("deprecation") - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - handler.exceptionCaught(ctx, cause); - } - -} diff --git a/src/org/traccar/api/AsyncSocket.java b/src/org/traccar/api/AsyncSocket.java deleted file mode 100644 index 906d16b5b..000000000 --- a/src/org/traccar/api/AsyncSocket.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.api; - -import com.fasterxml.jackson.core.JsonProcessingException; -import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.api.WebSocketAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.database.ConnectionManager; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Position; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.UpdateListener { - - private static final Logger LOGGER = LoggerFactory.getLogger(AsyncSocket.class); - - private static final String KEY_DEVICES = "devices"; - private static final String KEY_POSITIONS = "positions"; - private static final String KEY_EVENTS = "events"; - - private long userId; - - public AsyncSocket(long userId) { - this.userId = userId; - } - - @Override - public void onWebSocketConnect(Session session) { - super.onWebSocketConnect(session); - - Map> data = new HashMap<>(); - data.put(KEY_POSITIONS, Context.getDeviceManager().getInitialState(userId)); - sendData(data); - - Context.getConnectionManager().addListener(userId, this); - } - - @Override - public void onWebSocketClose(int statusCode, String reason) { - super.onWebSocketClose(statusCode, reason); - - Context.getConnectionManager().removeListener(userId, this); - } - - @Override - public void onUpdateDevice(Device device) { - Map> data = new HashMap<>(); - data.put(KEY_DEVICES, Collections.singletonList(device)); - sendData(data); - } - - @Override - public void onUpdatePosition(Position position) { - Map> data = new HashMap<>(); - data.put(KEY_POSITIONS, Collections.singletonList(position)); - sendData(data); - } - - @Override - public void onUpdateEvent(Event event) { - Map> data = new HashMap<>(); - data.put(KEY_EVENTS, Collections.singletonList(event)); - sendData(data); - } - - private void sendData(Map> data) { - if (!data.isEmpty() && isConnected()) { - try { - getRemote().sendString(Context.getObjectMapper().writeValueAsString(data), null); - } catch (JsonProcessingException e) { - LOGGER.warn("Socket JSON formatting error", e); - } - } - } -} diff --git a/src/org/traccar/api/AsyncSocketServlet.java b/src/org/traccar/api/AsyncSocketServlet.java deleted file mode 100644 index 9318b6fc6..000000000 --- a/src/org/traccar/api/AsyncSocketServlet.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.api; - -import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; -import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; -import org.eclipse.jetty.websocket.servlet.WebSocketCreator; -import org.eclipse.jetty.websocket.servlet.WebSocketServlet; -import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; -import org.traccar.Context; -import org.traccar.api.resource.SessionResource; - -public class AsyncSocketServlet extends WebSocketServlet { - - private static final long ASYNC_TIMEOUT = 10 * 60 * 1000; - - @Override - public void configure(WebSocketServletFactory factory) { - factory.getPolicy().setIdleTimeout(Context.getConfig().getLong("web.timeout", ASYNC_TIMEOUT)); - factory.setCreator(new WebSocketCreator() { - @Override - public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) { - if (req.getSession() != null) { - long userId = (Long) req.getSession().getAttribute(SessionResource.USER_ID_KEY); - return new AsyncSocket(userId); - } else { - return null; - } - } - }); - } - -} diff --git a/src/org/traccar/api/BaseObjectResource.java b/src/org/traccar/api/BaseObjectResource.java deleted file mode 100644 index 7de6a3877..000000000 --- a/src/org/traccar/api/BaseObjectResource.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api; - -import java.sql.SQLException; -import java.util.Set; - -import javax.ws.rs.DELETE; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; - -import org.traccar.Context; -import org.traccar.database.BaseObjectManager; -import org.traccar.database.ExtendedObjectManager; -import org.traccar.database.ManagableObjects; -import org.traccar.database.SimpleObjectManager; -import org.traccar.helper.LogAction; -import org.traccar.model.BaseModel; -import org.traccar.model.Calendar; -import org.traccar.model.Command; -import org.traccar.model.Device; -import org.traccar.model.Group; -import org.traccar.model.GroupedModel; -import org.traccar.model.ScheduledModel; -import org.traccar.model.User; - -public abstract class BaseObjectResource extends BaseResource { - - private Class baseClass; - - public BaseObjectResource(Class baseClass) { - this.baseClass = baseClass; - } - - protected final Class getBaseClass() { - return baseClass; - } - - protected final Set getSimpleManagerItems(BaseObjectManager manager, boolean all, long userId) { - Set result = null; - if (all) { - if (Context.getPermissionsManager().getUserAdmin(getUserId())) { - result = manager.getAllItems(); - } else { - Context.getPermissionsManager().checkManager(getUserId()); - result = ((ManagableObjects) manager).getManagedItems(getUserId()); - } - } else { - if (userId == 0) { - userId = getUserId(); - } - Context.getPermissionsManager().checkUser(getUserId(), userId); - result = ((ManagableObjects) manager).getUserItems(userId); - } - return result; - } - - @POST - public Response add(T entity) throws SQLException { - Context.getPermissionsManager().checkReadonly(getUserId()); - if (baseClass.equals(Device.class)) { - Context.getPermissionsManager().checkDeviceReadonly(getUserId()); - Context.getPermissionsManager().checkDeviceLimit(getUserId()); - } else if (baseClass.equals(Command.class)) { - Context.getPermissionsManager().checkLimitCommands(getUserId()); - } else if (entity instanceof GroupedModel && ((GroupedModel) entity).getGroupId() != 0) { - Context.getPermissionsManager().checkPermission( - Group.class, getUserId(), ((GroupedModel) entity).getGroupId()); - } else if (entity instanceof ScheduledModel && ((ScheduledModel) entity).getCalendarId() != 0) { - Context.getPermissionsManager().checkPermission( - Calendar.class, getUserId(), ((ScheduledModel) entity).getCalendarId()); - } - - BaseObjectManager manager = Context.getManager(baseClass); - manager.addItem(entity); - LogAction.create(getUserId(), entity); - - Context.getDataManager().linkObject(User.class, getUserId(), baseClass, entity.getId(), true); - LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId()); - - if (manager instanceof SimpleObjectManager) { - ((SimpleObjectManager) manager).refreshUserItems(); - } else if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) { - Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); - Context.getPermissionsManager().refreshAllExtendedPermissions(); - } - return Response.ok(entity).build(); - } - - @Path("{id}") - @PUT - public Response update(T entity) throws SQLException { - Context.getPermissionsManager().checkReadonly(getUserId()); - if (baseClass.equals(Device.class)) { - Context.getPermissionsManager().checkDeviceReadonly(getUserId()); - } else if (baseClass.equals(User.class)) { - User before = Context.getPermissionsManager().getUser(entity.getId()); - Context.getPermissionsManager().checkUserUpdate(getUserId(), before, (User) entity); - } else if (baseClass.equals(Command.class)) { - Context.getPermissionsManager().checkLimitCommands(getUserId()); - } else if (entity instanceof GroupedModel && ((GroupedModel) entity).getGroupId() != 0) { - Context.getPermissionsManager().checkPermission( - Group.class, getUserId(), ((GroupedModel) entity).getGroupId()); - } else if (entity instanceof ScheduledModel && ((ScheduledModel) entity).getCalendarId() != 0) { - Context.getPermissionsManager().checkPermission( - Calendar.class, getUserId(), ((ScheduledModel) entity).getCalendarId()); - } - Context.getPermissionsManager().checkPermission(baseClass, getUserId(), entity.getId()); - - Context.getManager(baseClass).updateItem(entity); - LogAction.edit(getUserId(), entity); - - if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) { - Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); - Context.getPermissionsManager().refreshAllExtendedPermissions(); - } - return Response.ok(entity).build(); - } - - @Path("{id}") - @DELETE - public Response remove(@PathParam("id") long id) throws SQLException { - Context.getPermissionsManager().checkReadonly(getUserId()); - if (baseClass.equals(Device.class)) { - Context.getPermissionsManager().checkDeviceReadonly(getUserId()); - } else if (baseClass.equals(Command.class)) { - Context.getPermissionsManager().checkLimitCommands(getUserId()); - } - Context.getPermissionsManager().checkPermission(baseClass, getUserId(), id); - - BaseObjectManager manager = Context.getManager(baseClass); - manager.removeItem(id); - LogAction.remove(getUserId(), baseClass, id); - - if (manager instanceof SimpleObjectManager) { - ((SimpleObjectManager) manager).refreshUserItems(); - if (manager instanceof ExtendedObjectManager) { - ((ExtendedObjectManager) manager).refreshExtendedPermissions(); - } - } - if (baseClass.equals(Group.class) || baseClass.equals(Device.class) || baseClass.equals(User.class)) { - if (baseClass.equals(Group.class)) { - Context.getGroupsManager().updateGroupCache(true); - Context.getDeviceManager().updateDeviceCache(true); - } - Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); - if (baseClass.equals(User.class)) { - Context.getPermissionsManager().refreshAllUsersPermissions(); - } else { - Context.getPermissionsManager().refreshAllExtendedPermissions(); - } - } else if (baseClass.equals(Calendar.class)) { - Context.getGeofenceManager().refreshItems(); - Context.getNotificationManager().refreshItems(); - } - return Response.noContent().build(); - } - -} diff --git a/src/org/traccar/api/BaseResource.java b/src/org/traccar/api/BaseResource.java deleted file mode 100644 index cc272df9c..000000000 --- a/src/org/traccar/api/BaseResource.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 - 2017 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. - * 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.api; - -import javax.ws.rs.core.SecurityContext; - -public class BaseResource { - - @javax.ws.rs.core.Context - private SecurityContext securityContext; - - protected long getUserId() { - UserPrincipal principal = (UserPrincipal) securityContext.getUserPrincipal(); - if (principal != null) { - return principal.getUserId(); - } - return 0; - } -} diff --git a/src/org/traccar/api/CorsResponseFilter.java b/src/org/traccar/api/CorsResponseFilter.java deleted file mode 100644 index 227f80609..000000000 --- a/src/org/traccar/api/CorsResponseFilter.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - * 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.api; - -import io.netty.handler.codec.http.HttpHeaderNames; -import org.traccar.Context; - -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerResponseContext; -import javax.ws.rs.container.ContainerResponseFilter; -import java.io.IOException; - -public class CorsResponseFilter implements ContainerResponseFilter { - - private static final String ORIGIN_ALL = "*"; - private static final String HEADERS_ALL = "origin, content-type, accept, authorization"; - private static final String METHODS_ALL = "GET, POST, PUT, DELETE, OPTIONS"; - - @Override - public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { - if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS.toString())) { - response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS.toString(), HEADERS_ALL); - } - - if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_CREDENTIALS.toString())) { - response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_CREDENTIALS.toString(), true); - } - - if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS.toString())) { - response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS.toString(), METHODS_ALL); - } - - if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString())) { - String origin = request.getHeaderString(HttpHeaderNames.ORIGIN.toString()); - String allowed = Context.getConfig().getString("web.origin"); - - if (origin == null) { - response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString(), ORIGIN_ALL); - } else if (allowed == null || allowed.equals(ORIGIN_ALL) || allowed.contains(origin)) { - response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString(), origin); - } - } - } - -} diff --git a/src/org/traccar/api/ExtendedObjectResource.java b/src/org/traccar/api/ExtendedObjectResource.java deleted file mode 100644 index 007a7b1bd..000000000 --- a/src/org/traccar/api/ExtendedObjectResource.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import javax.ws.rs.GET; -import javax.ws.rs.QueryParam; - -import org.traccar.Context; -import org.traccar.database.ExtendedObjectManager; -import org.traccar.model.BaseModel; - -public class ExtendedObjectResource extends BaseObjectResource { - - public ExtendedObjectResource(Class baseClass) { - super(baseClass); - } - - @GET - public Collection get( - @QueryParam("all") boolean all, @QueryParam("userId") long userId, @QueryParam("groupId") long groupId, - @QueryParam("deviceId") long deviceId, @QueryParam("refresh") boolean refresh) throws SQLException { - - ExtendedObjectManager manager = (ExtendedObjectManager) Context.getManager(getBaseClass()); - if (refresh) { - manager.refreshItems(); - } - - Set result = new HashSet<>(getSimpleManagerItems(manager, all, userId)); - - if (groupId != 0) { - Context.getPermissionsManager().checkGroup(getUserId(), groupId); - result.retainAll(manager.getGroupItems(groupId)); - } - - if (deviceId != 0) { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - result.retainAll(manager.getDeviceItems(deviceId)); - } - return manager.getItems(result); - - } - -} diff --git a/src/org/traccar/api/MediaFilter.java b/src/org/traccar/api/MediaFilter.java deleted file mode 100644 index 53539770f..000000000 --- a/src/org/traccar/api/MediaFilter.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api; - -import java.io.IOException; -import java.sql.SQLException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.traccar.Context; -import org.traccar.Main; -import org.traccar.api.resource.SessionResource; -import org.traccar.database.StatisticsManager; -import org.traccar.helper.Log; -import org.traccar.model.Device; - -public class MediaFilter implements Filter { - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - HttpServletResponse httpResponse = (HttpServletResponse) response; - try { - HttpSession session = ((HttpServletRequest) request).getSession(false); - Long userId = null; - if (session != null) { - userId = (Long) session.getAttribute(SessionResource.USER_ID_KEY); - if (userId != null) { - Context.getPermissionsManager().checkUserEnabled(userId); - Main.getInjector().getInstance(StatisticsManager.class).registerRequest(userId); - } - } - if (userId == null) { - httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); - return; - } - - String path = ((HttpServletRequest) request).getPathInfo(); - String[] parts = path.split("/"); - if (parts.length < 2 || parts.length == 2 && !path.endsWith("/")) { - Context.getPermissionsManager().checkAdmin(userId); - } else { - Device device = Context.getDeviceManager().getByUniqueId(parts[1]); - if (device != null) { - Context.getPermissionsManager().checkDevice(userId, device.getId()); - } else { - httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - } - - chain.doFilter(request, response); - } catch (SecurityException e) { - httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); - httpResponse.getWriter().println(Log.exceptionStack(e)); - } catch (SQLException e) { - httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST); - httpResponse.getWriter().println(Log.exceptionStack(e)); - } - } - - @Override - public void destroy() { - } - -} diff --git a/src/org/traccar/api/ObjectMapperProvider.java b/src/org/traccar/api/ObjectMapperProvider.java deleted file mode 100644 index f81b20917..000000000 --- a/src/org/traccar/api/ObjectMapperProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.api; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.traccar.Context; - -import javax.ws.rs.ext.ContextResolver; -import javax.ws.rs.ext.Provider; - -@Provider -public class ObjectMapperProvider implements ContextResolver { - - @Override - public ObjectMapper getContext(Class type) { - return Context.getObjectMapper(); - } - -} diff --git a/src/org/traccar/api/ResourceErrorHandler.java b/src/org/traccar/api/ResourceErrorHandler.java deleted file mode 100644 index 1d618b08d..000000000 --- a/src/org/traccar/api/ResourceErrorHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.api; - -import org.traccar.helper.Log; - -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; - -public class ResourceErrorHandler implements ExceptionMapper { - - @Override - public Response toResponse(Exception e) { - if (e instanceof WebApplicationException) { - WebApplicationException exception = (WebApplicationException) e; - String message; - if (exception.getCause() != null) { - message = Log.exceptionStack(exception.getCause()); - } else { - message = Log.exceptionStack(exception); - } - return Response.fromResponse(exception.getResponse()).entity(message).build(); - } else { - return Response.status(Response.Status.BAD_REQUEST).entity(Log.exceptionStack(e)).build(); - } - } - -} diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java deleted file mode 100644 index 33b6b37df..000000000 --- a/src/org/traccar/api/SecurityRequestFilter.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.api; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.Main; -import org.traccar.api.resource.SessionResource; -import org.traccar.database.StatisticsManager; -import org.traccar.helper.DataConverter; -import org.traccar.model.User; - -import javax.annotation.security.PermitAll; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.container.ResourceInfo; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; -import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; -import java.sql.SQLException; - -public class SecurityRequestFilter implements ContainerRequestFilter { - - private static final Logger LOGGER = LoggerFactory.getLogger(SecurityRequestFilter.class); - - public static final String AUTHORIZATION_HEADER = "Authorization"; - public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; - public static final String BASIC_REALM = "Basic realm=\"api\""; - public static final String X_REQUESTED_WITH = "X-Requested-With"; - public static final String XML_HTTP_REQUEST = "XMLHttpRequest"; - - public static String[] decodeBasicAuth(String auth) { - auth = auth.replaceFirst("[B|b]asic ", ""); - byte[] decodedBytes = DataConverter.parseBase64(auth); - if (decodedBytes != null && decodedBytes.length > 0) { - return new String(decodedBytes, StandardCharsets.US_ASCII).split(":", 2); - } - return null; - } - - @javax.ws.rs.core.Context - private HttpServletRequest request; - - @javax.ws.rs.core.Context - private ResourceInfo resourceInfo; - - @Override - public void filter(ContainerRequestContext requestContext) { - - if (requestContext.getMethod().equals("OPTIONS")) { - return; - } - - SecurityContext securityContext = null; - - try { - - String authHeader = requestContext.getHeaderString(AUTHORIZATION_HEADER); - if (authHeader != null) { - - try { - String[] auth = decodeBasicAuth(authHeader); - User user = Context.getPermissionsManager().login(auth[0], auth[1]); - if (user != null) { - Main.getInjector().getInstance(StatisticsManager.class).registerRequest(user.getId()); - securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); - } - } catch (SQLException e) { - throw new WebApplicationException(e); - } - - } else if (request.getSession() != null) { - - Long userId = (Long) request.getSession().getAttribute(SessionResource.USER_ID_KEY); - if (userId != null) { - Context.getPermissionsManager().checkUserEnabled(userId); - Main.getInjector().getInstance(StatisticsManager.class).registerRequest(userId); - securityContext = new UserSecurityContext(new UserPrincipal(userId)); - } - - } - - } catch (SecurityException e) { - LOGGER.warn("Authentication error", e); - } - - if (securityContext != null) { - requestContext.setSecurityContext(securityContext); - } else { - Method method = resourceInfo.getResourceMethod(); - if (!method.isAnnotationPresent(PermitAll.class)) { - Response.ResponseBuilder responseBuilder = Response.status(Response.Status.UNAUTHORIZED); - if (!XML_HTTP_REQUEST.equals(request.getHeader(X_REQUESTED_WITH))) { - responseBuilder.header(WWW_AUTHENTICATE, BASIC_REALM); - } - throw new WebApplicationException(responseBuilder.build()); - } - } - - } - -} diff --git a/src/org/traccar/api/SimpleObjectResource.java b/src/org/traccar/api/SimpleObjectResource.java deleted file mode 100644 index a7fcae0e7..000000000 --- a/src/org/traccar/api/SimpleObjectResource.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api; - -import java.sql.SQLException; -import java.util.Collection; - -import javax.ws.rs.GET; -import javax.ws.rs.QueryParam; - -import org.traccar.Context; -import org.traccar.database.BaseObjectManager; -import org.traccar.model.BaseModel; - -public class SimpleObjectResource extends BaseObjectResource { - - public SimpleObjectResource(Class baseClass) { - super(baseClass); - } - - @GET - public Collection get( - @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws SQLException { - - BaseObjectManager manager = Context.getManager(getBaseClass()); - return manager.getItems(getSimpleManagerItems(manager, all, userId)); - } - -} diff --git a/src/org/traccar/api/UserPrincipal.java b/src/org/traccar/api/UserPrincipal.java deleted file mode 100644 index 80e92c2dd..000000000 --- a/src/org/traccar/api/UserPrincipal.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 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. - * 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.api; - -import java.security.Principal; - -public class UserPrincipal implements Principal { - - private long userId; - - public UserPrincipal(long userId) { - this.userId = userId; - } - - public Long getUserId() { - return userId; - } - - @Override - public String getName() { - return null; - } - -} diff --git a/src/org/traccar/api/UserSecurityContext.java b/src/org/traccar/api/UserSecurityContext.java deleted file mode 100644 index 55c0621bc..000000000 --- a/src/org/traccar/api/UserSecurityContext.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 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. - * 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.api; - -import javax.ws.rs.core.SecurityContext; -import java.security.Principal; - -public class UserSecurityContext implements SecurityContext { - - private UserPrincipal principal; - - public UserSecurityContext(UserPrincipal principal) { - this.principal = principal; - } - - @Override - public Principal getUserPrincipal() { - return principal; - } - - @Override - public boolean isUserInRole(String role) { - return true; - } - - @Override - public boolean isSecure() { - return false; - } - - @Override - public String getAuthenticationScheme() { - return BASIC_AUTH; - } - -} diff --git a/src/org/traccar/api/resource/AttributeResource.java b/src/org/traccar/api/resource/AttributeResource.java deleted file mode 100644 index de69d871c..000000000 --- a/src/org/traccar/api/resource/AttributeResource.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api.resource; - -import java.sql.SQLException; - -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.traccar.Context; -import org.traccar.api.ExtendedObjectResource; -import org.traccar.model.Attribute; -import org.traccar.model.Position; -import org.traccar.handler.ComputedAttributesHandler; - -@Path("attributes/computed") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class AttributeResource extends ExtendedObjectResource { - - public AttributeResource() { - super(Attribute.class); - } - - @POST - @Path("test") - public Response test(@QueryParam("deviceId") long deviceId, Attribute entity) { - Context.getPermissionsManager().checkAdmin(getUserId()); - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - Position last = Context.getIdentityManager().getLastPosition(deviceId); - if (last != null) { - Object result = new ComputedAttributesHandler( - Context.getConfig(), - Context.getIdentityManager(), - Context.getAttributesManager()).computeAttribute(entity, last); - if (result != null) { - switch (entity.getType()) { - case "number": - Number numberValue = (Number) result; - return Response.ok(numberValue).build(); - case "boolean": - Boolean booleanValue = (Boolean) result; - return Response.ok(booleanValue).build(); - default: - return Response.ok(result.toString()).build(); - } - } else { - return Response.noContent().build(); - } - } else { - throw new IllegalArgumentException("Device has no last position"); - } - } - - @POST - public Response add(Attribute entity) throws SQLException { - Context.getPermissionsManager().checkAdmin(getUserId()); - return super.add(entity); - } - - @Path("{id}") - @PUT - public Response update(Attribute entity) throws SQLException { - Context.getPermissionsManager().checkAdmin(getUserId()); - return super.update(entity); - } - - @Path("{id}") - @DELETE - public Response remove(@PathParam("id") long id) throws SQLException { - Context.getPermissionsManager().checkAdmin(getUserId()); - return super.remove(id); - } - -} diff --git a/src/org/traccar/api/resource/CalendarResource.java b/src/org/traccar/api/resource/CalendarResource.java deleted file mode 100644 index 9399c34a5..000000000 --- a/src/org/traccar/api/resource/CalendarResource.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api.resource; - -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.traccar.api.SimpleObjectResource; -import org.traccar.model.Calendar; - -@Path("calendars") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class CalendarResource extends SimpleObjectResource { - - public CalendarResource() { - super(Calendar.class); - } - -} diff --git a/src/org/traccar/api/resource/CommandResource.java b/src/org/traccar/api/resource/CommandResource.java deleted file mode 100644 index 703638701..000000000 --- a/src/org/traccar/api/resource/CommandResource.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api.resource; - -import org.traccar.Context; -import org.traccar.api.ExtendedObjectResource; -import org.traccar.database.CommandsManager; -import org.traccar.model.Command; -import org.traccar.model.Typed; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -@Path("commands") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class CommandResource extends ExtendedObjectResource { - - public CommandResource() { - super(Command.class); - } - - @GET - @Path("send") - public Collection get(@QueryParam("deviceId") long deviceId) throws SQLException { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - CommandsManager commandsManager = Context.getCommandsManager(); - Set result = new HashSet<>(commandsManager.getUserItems(getUserId())); - result.retainAll(commandsManager.getSupportedCommands(deviceId)); - return commandsManager.getItems(result); - } - - @POST - @Path("send") - public Response send(Command entity) throws Exception { - Context.getPermissionsManager().checkReadonly(getUserId()); - long deviceId = entity.getDeviceId(); - long id = entity.getId(); - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - if (id != 0) { - Context.getPermissionsManager().checkPermission(Command.class, getUserId(), id); - Context.getPermissionsManager().checkUserDeviceCommand(getUserId(), deviceId, id); - } else { - Context.getPermissionsManager().checkLimitCommands(getUserId()); - } - if (!Context.getCommandsManager().sendCommand(entity)) { - return Response.accepted(entity).build(); - } - return Response.ok(entity).build(); - } - - @GET - @Path("types") - public Collection get(@QueryParam("deviceId") long deviceId, - @QueryParam("textChannel") boolean textChannel) { - if (deviceId != 0) { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - return Context.getCommandsManager().getCommandTypes(deviceId, textChannel); - } else { - return Context.getCommandsManager().getAllCommandTypes(); - } - } -} diff --git a/src/org/traccar/api/resource/DeviceResource.java b/src/org/traccar/api/resource/DeviceResource.java deleted file mode 100644 index f9c9a139d..000000000 --- a/src/org/traccar/api/resource/DeviceResource.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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. - * 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.api.resource; - -import org.traccar.Context; -import org.traccar.api.BaseObjectResource; -import org.traccar.database.DeviceManager; -import org.traccar.helper.LogAction; -import org.traccar.model.Device; -import org.traccar.model.DeviceAccumulators; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -@Path("devices") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class DeviceResource extends BaseObjectResource { - - public DeviceResource() { - super(Device.class); - } - - @GET - public Collection get( - @QueryParam("all") boolean all, @QueryParam("userId") long userId, - @QueryParam("uniqueId") List uniqueIds, - @QueryParam("id") List deviceIds) throws SQLException { - DeviceManager deviceManager = Context.getDeviceManager(); - Set result = null; - if (all) { - if (Context.getPermissionsManager().getUserAdmin(getUserId())) { - result = deviceManager.getAllItems(); - } else { - Context.getPermissionsManager().checkManager(getUserId()); - result = deviceManager.getManagedItems(getUserId()); - } - } else if (uniqueIds.isEmpty() && deviceIds.isEmpty()) { - if (userId == 0) { - userId = getUserId(); - } - Context.getPermissionsManager().checkUser(getUserId(), userId); - if (Context.getPermissionsManager().getUserAdmin(getUserId())) { - result = deviceManager.getAllUserItems(userId); - } else { - result = deviceManager.getUserItems(userId); - } - } else { - result = new HashSet<>(); - for (String uniqueId : uniqueIds) { - Device device = deviceManager.getByUniqueId(uniqueId); - Context.getPermissionsManager().checkDevice(getUserId(), device.getId()); - result.add(device.getId()); - } - for (Long deviceId : deviceIds) { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - result.add(deviceId); - } - } - return deviceManager.getItems(result); - } - - @Path("{id}/accumulators") - @PUT - public Response updateAccumulators(DeviceAccumulators entity) throws SQLException { - if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { - Context.getPermissionsManager().checkManager(getUserId()); - Context.getPermissionsManager().checkPermission(Device.class, getUserId(), entity.getDeviceId()); - } - Context.getDeviceManager().resetDeviceAccumulators(entity); - LogAction.resetDeviceAccumulators(getUserId(), entity.getDeviceId()); - return Response.noContent().build(); - } - -} diff --git a/src/org/traccar/api/resource/DriverResource.java b/src/org/traccar/api/resource/DriverResource.java deleted file mode 100644 index 91aa54c5e..000000000 --- a/src/org/traccar/api/resource/DriverResource.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api.resource; - -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.traccar.api.ExtendedObjectResource; -import org.traccar.model.Driver; - -@Path("drivers") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class DriverResource extends ExtendedObjectResource { - - public DriverResource() { - super(Driver.class); - } - -} diff --git a/src/org/traccar/api/resource/EventResource.java b/src/org/traccar/api/resource/EventResource.java deleted file mode 100644 index e0ccf7020..000000000 --- a/src/org/traccar/api/resource/EventResource.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.traccar.api.resource; - -import java.sql.SQLException; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.traccar.Context; -import org.traccar.api.BaseResource; -import org.traccar.model.Event; -import org.traccar.model.Geofence; -import org.traccar.model.Maintenance; - -@Path("events") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) - -public class EventResource extends BaseResource { - - @Path("{id}") - @GET - public Event get(@PathParam("id") long id) throws SQLException { - Event event = Context.getDataManager().getObject(Event.class, id); - Context.getPermissionsManager().checkDevice(getUserId(), event.getDeviceId()); - if (event.getGeofenceId() != 0) { - Context.getPermissionsManager().checkPermission(Geofence.class, getUserId(), event.getGeofenceId()); - } - if (event.getMaintenanceId() != 0) { - Context.getPermissionsManager().checkPermission(Maintenance.class, getUserId(), event.getMaintenanceId()); - } - return event; - } - -} diff --git a/src/org/traccar/api/resource/GeofenceResource.java b/src/org/traccar/api/resource/GeofenceResource.java deleted file mode 100644 index 58f2c188c..000000000 --- a/src/org/traccar/api/resource/GeofenceResource.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.api.resource; - -import org.traccar.api.ExtendedObjectResource; -import org.traccar.model.Geofence; - -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -@Path("geofences") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class GeofenceResource extends ExtendedObjectResource { - - public GeofenceResource() { - super(Geofence.class); - } - -} diff --git a/src/org/traccar/api/resource/GroupResource.java b/src/org/traccar/api/resource/GroupResource.java deleted file mode 100644 index fcea15d0a..000000000 --- a/src/org/traccar/api/resource/GroupResource.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.api.resource; - -import org.traccar.api.SimpleObjectResource; -import org.traccar.model.Group; - -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -@Path("groups") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class GroupResource extends SimpleObjectResource { - - public GroupResource() { - super(Group.class); - } - -} diff --git a/src/org/traccar/api/resource/MaintenanceResource.java b/src/org/traccar/api/resource/MaintenanceResource.java deleted file mode 100644 index fa1b359ce..000000000 --- a/src/org/traccar/api/resource/MaintenanceResource.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api.resource; - -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.traccar.api.ExtendedObjectResource; -import org.traccar.model.Maintenance; - -@Path("maintenance") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class MaintenanceResource extends ExtendedObjectResource { - - public MaintenanceResource() { - super(Maintenance.class); - } - -} diff --git a/src/org/traccar/api/resource/NotificationResource.java b/src/org/traccar/api/resource/NotificationResource.java deleted file mode 100644 index 9631a52b7..000000000 --- a/src/org/traccar/api/resource/NotificationResource.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.api.resource; - -import java.util.Collection; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.traccar.Context; -import org.traccar.api.ExtendedObjectResource; -import org.traccar.model.Event; -import org.traccar.model.Notification; -import org.traccar.model.Typed; -import org.traccar.notification.MessageException; - - -@Path("notifications") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class NotificationResource extends ExtendedObjectResource { - - public NotificationResource() { - super(Notification.class); - } - - @GET - @Path("types") - public Collection get() { - return Context.getNotificationManager().getAllNotificationTypes(); - } - - @GET - @Path("notificators") - public Collection getNotificators() { - return Context.getNotificatorManager().getAllNotificatorTypes(); - } - - @POST - @Path("test") - public Response testMessage() throws MessageException, InterruptedException { - for (Typed method : Context.getNotificatorManager().getAllNotificatorTypes()) { - Context.getNotificatorManager() - .getNotificator(method.getType()).sendSync(getUserId(), new Event("test", 0), null); - } - return Response.noContent().build(); - } - - @POST - @Path("test/{notificator}") - public Response testMessage(@PathParam("notificator") String notificator) - throws MessageException, InterruptedException { - Context.getNotificatorManager().getNotificator(notificator).sendSync(getUserId(), new Event("test", 0), null); - return Response.noContent().build(); - } - -} diff --git a/src/org/traccar/api/resource/PermissionsResource.java b/src/org/traccar/api/resource/PermissionsResource.java deleted file mode 100644 index b89d9d376..000000000 --- a/src/org/traccar/api/resource/PermissionsResource.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api.resource; - -import java.sql.SQLException; -import java.util.LinkedHashMap; - -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.traccar.Context; -import org.traccar.api.BaseResource; -import org.traccar.helper.LogAction; -import org.traccar.model.Device; -import org.traccar.model.Permission; -import org.traccar.model.User; - -@Path("permissions") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class PermissionsResource extends BaseResource { - - private void checkPermission(Permission permission, boolean link) { - if (!link && permission.getOwnerClass().equals(User.class) - && permission.getPropertyClass().equals(Device.class)) { - if (getUserId() != permission.getOwnerId()) { - Context.getPermissionsManager().checkUser(getUserId(), permission.getOwnerId()); - } else { - Context.getPermissionsManager().checkAdmin(getUserId()); - } - } else { - Context.getPermissionsManager().checkPermission( - permission.getOwnerClass(), getUserId(), permission.getOwnerId()); - } - Context.getPermissionsManager().checkPermission( - permission.getPropertyClass(), getUserId(), permission.getPropertyId()); - } - - @POST - public Response add(LinkedHashMap entity) throws SQLException, ClassNotFoundException { - Context.getPermissionsManager().checkReadonly(getUserId()); - Permission permission = new Permission(entity); - checkPermission(permission, true); - Context.getDataManager().linkObject(permission.getOwnerClass(), permission.getOwnerId(), - permission.getPropertyClass(), permission.getPropertyId(), true); - LogAction.link(getUserId(), permission.getOwnerClass(), permission.getOwnerId(), - permission.getPropertyClass(), permission.getPropertyId()); - Context.getPermissionsManager().refreshPermissions(permission); - return Response.noContent().build(); - } - - @DELETE - public Response remove(LinkedHashMap entity) throws SQLException, ClassNotFoundException { - Context.getPermissionsManager().checkReadonly(getUserId()); - Permission permission = new Permission(entity); - checkPermission(permission, false); - Context.getDataManager().linkObject(permission.getOwnerClass(), permission.getOwnerId(), - permission.getPropertyClass(), permission.getPropertyId(), false); - LogAction.unlink(getUserId(), permission.getOwnerClass(), permission.getOwnerId(), - permission.getPropertyClass(), permission.getPropertyId()); - Context.getPermissionsManager().refreshPermissions(permission); - return Response.noContent().build(); - } - -} diff --git a/src/org/traccar/api/resource/PositionResource.java b/src/org/traccar/api/resource/PositionResource.java deleted file mode 100644 index c031b842f..000000000 --- a/src/org/traccar/api/resource/PositionResource.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.api.resource; - -import org.traccar.Context; -import org.traccar.api.BaseResource; -import org.traccar.helper.DateUtil; -import org.traccar.model.Position; -import org.traccar.web.CsvBuilder; -import org.traccar.web.GpxBuilder; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -@Path("positions") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class PositionResource extends BaseResource { - - public static final String TEXT_CSV = "text/csv"; - public static final String CONTENT_DISPOSITION_VALUE_CSV = "attachment; filename=positions.csv"; - public static final String GPX = "application/gpx+xml"; - public static final String CONTENT_DISPOSITION_VALUE_GPX = "attachment; filename=positions.gpx"; - - @GET - public Collection getJson( - @QueryParam("deviceId") long deviceId, @QueryParam("id") List positionIds, - @QueryParam("from") String from, @QueryParam("to") String to) - throws SQLException { - if (!positionIds.isEmpty()) { - ArrayList positions = new ArrayList<>(); - for (Long positionId : positionIds) { - Position position = Context.getDataManager().getObject(Position.class, positionId); - Context.getPermissionsManager().checkDevice(getUserId(), position.getDeviceId()); - positions.add(position); - } - return positions; - } else if (deviceId == 0) { - return Context.getDeviceManager().getInitialState(getUserId()); - } else { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - return Context.getDataManager().getPositions( - deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to)); - } - } - - @GET - @Produces(TEXT_CSV) - public Response getCsv( - @QueryParam("deviceId") long deviceId, @QueryParam("from") String from, @QueryParam("to") String to) - throws SQLException { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - CsvBuilder csv = new CsvBuilder(); - csv.addHeaderLine(new Position()); - csv.addArray(Context.getDataManager().getPositions( - deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to))); - return Response.ok(csv.build()).header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_CSV).build(); - } - - @GET - @Produces(GPX) - public Response getGpx( - @QueryParam("deviceId") long deviceId, @QueryParam("from") String from, @QueryParam("to") String to) - throws SQLException { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - GpxBuilder gpx = new GpxBuilder(Context.getIdentityManager().getById(deviceId).getName()); - gpx.addPositions(Context.getDataManager().getPositions( - deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to))); - return Response.ok(gpx.build()).header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_GPX).build(); - } - -} diff --git a/src/org/traccar/api/resource/ReportResource.java b/src/org/traccar/api/resource/ReportResource.java deleted file mode 100644 index d371cf987..000000000 --- a/src/org/traccar/api/resource/ReportResource.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.api.resource; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; - -import javax.activation.DataHandler; -import javax.mail.MessagingException; -import javax.mail.internet.MimeBodyPart; -import javax.mail.util.ByteArrayDataSource; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.api.BaseResource; -import org.traccar.helper.DateUtil; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.reports.Events; -import org.traccar.reports.Summary; -import org.traccar.reports.Trips; -import org.traccar.reports.model.StopReport; -import org.traccar.reports.model.SummaryReport; -import org.traccar.reports.model.TripReport; -import org.traccar.reports.Route; -import org.traccar.reports.Stops; - -@Path("reports") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class ReportResource extends BaseResource { - - private static final Logger LOGGER = LoggerFactory.getLogger(ReportResource.class); - - private static final String XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; - private static final String CONTENT_DISPOSITION_VALUE_XLSX = "attachment; filename=report.xlsx"; - - private interface ReportExecutor { - void execute(ByteArrayOutputStream stream) throws SQLException, IOException; - } - - private Response executeReport( - long userId, boolean mail, ReportExecutor executor) throws SQLException, IOException { - final ByteArrayOutputStream stream = new ByteArrayOutputStream(); - if (mail) { - new Thread(() -> { - try { - executor.execute(stream); - - MimeBodyPart attachment = new MimeBodyPart(); - - attachment.setFileName("report.xlsx"); - attachment.setDataHandler(new DataHandler(new ByteArrayDataSource( - stream.toByteArray(), "application/octet-stream"))); - - Context.getMailManager().sendMessage( - userId, "Report", "The report is in the attachment.", attachment); - } catch (SQLException | IOException | MessagingException e) { - LOGGER.warn("Report failed", e); - } - }).start(); - return Response.noContent().build(); - } else { - executor.execute(stream); - return Response.ok(stream.toByteArray()) - .header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_XLSX).build(); - } - } - - @Path("route") - @GET - public Collection getRoute( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { - return Route.getObjects(getUserId(), deviceIds, groupIds, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - } - - @Path("route") - @GET - @Produces(XLSX) - public Response getRouteExcel( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { - return executeReport(getUserId(), mail, stream -> { - Route.getExcel(stream, getUserId(), deviceIds, groupIds, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - }); - } - - @Path("events") - @GET - public Collection getEvents( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("type") final List types, - @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { - return Events.getObjects(getUserId(), deviceIds, groupIds, types, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - } - - @Path("events") - @GET - @Produces(XLSX) - public Response getEventsExcel( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("type") final List types, - @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { - return executeReport(getUserId(), mail, stream -> { - Events.getExcel(stream, getUserId(), deviceIds, groupIds, types, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - }); - } - - @Path("summary") - @GET - public Collection getSummary( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { - return Summary.getObjects(getUserId(), deviceIds, groupIds, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - } - - @Path("summary") - @GET - @Produces(XLSX) - public Response getSummaryExcel( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { - return executeReport(getUserId(), mail, stream -> { - Summary.getExcel(stream, getUserId(), deviceIds, groupIds, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - }); - } - - @Path("trips") - @GET - @Produces(MediaType.APPLICATION_JSON) - public Collection getTrips( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { - return Trips.getObjects(getUserId(), deviceIds, groupIds, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - } - - @Path("trips") - @GET - @Produces(XLSX) - public Response getTripsExcel( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { - return executeReport(getUserId(), mail, stream -> { - Trips.getExcel(stream, getUserId(), deviceIds, groupIds, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - }); - } - - @Path("stops") - @GET - @Produces(MediaType.APPLICATION_JSON) - public Collection getStops( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { - return Stops.getObjects(getUserId(), deviceIds, groupIds, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - } - - @Path("stops") - @GET - @Produces(XLSX) - public Response getStopsExcel( - @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") String from, @QueryParam("to") String to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { - return executeReport(getUserId(), mail, stream -> { - Stops.getExcel(stream, getUserId(), deviceIds, groupIds, - DateUtil.parseDate(from), DateUtil.parseDate(to)); - }); - } - -} diff --git a/src/org/traccar/api/resource/ServerResource.java b/src/org/traccar/api/resource/ServerResource.java deleted file mode 100644 index e7cad2a0c..000000000 --- a/src/org/traccar/api/resource/ServerResource.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015 - 2017 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. - * 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.api.resource; - -import org.traccar.Context; -import org.traccar.api.BaseResource; -import org.traccar.helper.LogAction; -import org.traccar.model.Server; - -import javax.annotation.security.PermitAll; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.sql.SQLException; - -@Path("server") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class ServerResource extends BaseResource { - - @PermitAll - @GET - public Server get() throws SQLException { - return Context.getPermissionsManager().getServer(); - } - - @PUT - public Response update(Server entity) throws SQLException { - Context.getPermissionsManager().checkAdmin(getUserId()); - Context.getPermissionsManager().updateServer(entity); - LogAction.edit(getUserId(), entity); - return Response.ok(entity).build(); - } - - @Path("geocode") - @GET - public String geocode(@QueryParam("latitude") double latitude, @QueryParam("longitude") double longitude) { - if (Context.getGeocoder() != null) { - return Context.getGeocoder().getAddress(latitude, longitude, null); - } else { - throw new RuntimeException("Reverse geocoding is not enabled"); - } - } - -} diff --git a/src/org/traccar/api/resource/SessionResource.java b/src/org/traccar/api/resource/SessionResource.java deleted file mode 100644 index fd331c766..000000000 --- a/src/org/traccar/api/resource/SessionResource.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2015 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. - * 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.api.resource; - -import org.traccar.Context; -import org.traccar.api.BaseResource; -import org.traccar.helper.DataConverter; -import org.traccar.helper.LogAction; -import org.traccar.model.User; - -import javax.annotation.security.PermitAll; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.sql.SQLException; - -@Path("session") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_FORM_URLENCODED) -public class SessionResource extends BaseResource { - - public static final String USER_ID_KEY = "userId"; - public static final String USER_COOKIE_KEY = "user"; - public static final String PASS_COOKIE_KEY = "password"; - - @javax.ws.rs.core.Context - private HttpServletRequest request; - - @PermitAll - @GET - public User get(@QueryParam("token") String token) throws SQLException, UnsupportedEncodingException { - Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY); - if (userId == null) { - Cookie[] cookies = request.getCookies(); - String email = null, password = null; - if (cookies != null) { - for (Cookie cookie : cookies) { - if (cookie.getName().equals(USER_COOKIE_KEY)) { - byte[] emailBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name())); - email = new String(emailBytes, StandardCharsets.UTF_8); - } else if (cookie.getName().equals(PASS_COOKIE_KEY)) { - byte[] passwordBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name())); - password = new String(passwordBytes, StandardCharsets.UTF_8); - } - } - } - if (email != null && password != null) { - User user = Context.getPermissionsManager().login(email, password); - if (user != null) { - userId = user.getId(); - request.getSession().setAttribute(USER_ID_KEY, userId); - } - } else if (token != null) { - User user = Context.getUsersManager().getUserByToken(token); - if (user != null) { - userId = user.getId(); - request.getSession().setAttribute(USER_ID_KEY, userId); - } - } - } - - if (userId != null) { - Context.getPermissionsManager().checkUserEnabled(userId); - return Context.getPermissionsManager().getUser(userId); - } else { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); - } - } - - @PermitAll - @POST - public User add( - @FormParam("email") String email, @FormParam("password") String password) throws SQLException { - User user = Context.getPermissionsManager().login(email, password); - if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId()); - return user; - } else { - throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); - } - } - - @DELETE - public Response remove() { - LogAction.logout(getUserId()); - request.getSession().removeAttribute(USER_ID_KEY); - return Response.noContent().build(); - } - -} diff --git a/src/org/traccar/api/resource/StatisticsResource.java b/src/org/traccar/api/resource/StatisticsResource.java deleted file mode 100644 index e801d4ff3..000000000 --- a/src/org/traccar/api/resource/StatisticsResource.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2016 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. - * 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.api.resource; - -import org.traccar.Context; -import org.traccar.api.BaseResource; -import org.traccar.helper.DateUtil; -import org.traccar.model.Statistics; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import java.sql.SQLException; -import java.util.Collection; - -@Path("statistics") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class StatisticsResource extends BaseResource { - - @GET - public Collection get( - @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { - Context.getPermissionsManager().checkAdmin(getUserId()); - return Context.getDataManager().getStatistics(DateUtil.parseDate(from), DateUtil.parseDate(to)); - } - -} diff --git a/src/org/traccar/api/resource/UserResource.java b/src/org/traccar/api/resource/UserResource.java deleted file mode 100644 index 0b42d8d92..000000000 --- a/src/org/traccar/api/resource/UserResource.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2015 - 2017 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. - * 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.api.resource; - -import org.traccar.Context; -import org.traccar.api.BaseObjectResource; -import org.traccar.database.UsersManager; -import org.traccar.helper.LogAction; -import org.traccar.model.ManagedUser; -import org.traccar.model.User; - -import javax.annotation.security.PermitAll; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.sql.SQLException; -import java.util.Collection; -import java.util.Date; -import java.util.Set; - -@Path("users") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public class UserResource extends BaseObjectResource { - - public UserResource() { - super(User.class); - } - - @GET - public Collection get(@QueryParam("userId") long userId) throws SQLException { - UsersManager usersManager = Context.getUsersManager(); - Set result = null; - if (Context.getPermissionsManager().getUserAdmin(getUserId())) { - if (userId != 0) { - result = usersManager.getUserItems(userId); - } else { - result = usersManager.getAllItems(); - } - } else if (Context.getPermissionsManager().getUserManager(getUserId())) { - result = usersManager.getManagedItems(getUserId()); - } else { - throw new SecurityException("Admin or manager access required"); - } - return usersManager.getItems(result); - } - - @Override - @PermitAll - @POST - public Response add(User entity) throws SQLException { - if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { - Context.getPermissionsManager().checkUserUpdate(getUserId(), new User(), entity); - if (Context.getPermissionsManager().getUserManager(getUserId())) { - Context.getPermissionsManager().checkUserLimit(getUserId()); - } else { - Context.getPermissionsManager().checkRegistration(getUserId()); - entity.setDeviceLimit(Context.getConfig().getInteger("users.defaultDeviceLimit", -1)); - int expirationDays = Context.getConfig().getInteger("users.defaultExpirationDays"); - if (expirationDays > 0) { - entity.setExpirationTime( - new Date(System.currentTimeMillis() + (long) expirationDays * 24 * 3600 * 1000)); - } - } - } - Context.getUsersManager().addItem(entity); - LogAction.create(getUserId(), entity); - if (Context.getPermissionsManager().getUserManager(getUserId())) { - Context.getDataManager().linkObject(User.class, getUserId(), ManagedUser.class, entity.getId(), true); - LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId()); - } - Context.getUsersManager().refreshUserItems(); - return Response.ok(entity).build(); - } - -} diff --git a/src/org/traccar/config/Config.java b/src/org/traccar/config/Config.java deleted file mode 100644 index d8f2a0e99..000000000 --- a/src/org/traccar/config/Config.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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.config; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.InvalidPropertiesFormatException; -import java.util.Properties; - -public class Config { - - private final Properties properties = new Properties(); - - private boolean useEnvironmentVariables; - - public Config() { - } - - public Config(String file) throws IOException { - try { - Properties mainProperties = new Properties(); - try (InputStream inputStream = new FileInputStream(file)) { - mainProperties.loadFromXML(inputStream); - } - - String defaultConfigFile = mainProperties.getProperty("config.default"); - if (defaultConfigFile != null) { - try (InputStream inputStream = new FileInputStream(defaultConfigFile)) { - properties.loadFromXML(inputStream); - } - } - - properties.putAll(mainProperties); // override defaults - - useEnvironmentVariables = Boolean.parseBoolean(System.getenv("CONFIG_USE_ENVIRONMENT_VARIABLES")) - || Boolean.parseBoolean(properties.getProperty("config.useEnvironmentVariables")); - } catch (InvalidPropertiesFormatException e) { - throw new RuntimeException("Configuration file is not a valid XML document", e); - } - } - - public boolean hasKey(ConfigKey key) { - return hasKey(key.getKey()); - } - - @Deprecated - public boolean hasKey(String key) { - return useEnvironmentVariables && System.getenv().containsKey(getEnvironmentVariableName(key)) - || properties.containsKey(key); - } - - public String getString(ConfigKey key) { - return getString(key.getKey()); - } - - @Deprecated - public String getString(String key) { - if (useEnvironmentVariables) { - String value = System.getenv(getEnvironmentVariableName(key)); - if (value != null && !value.isEmpty()) { - return value; - } - } - return properties.getProperty(key); - } - - public String getString(ConfigKey key, String defaultValue) { - return getString(key.getKey(), defaultValue); - } - - @Deprecated - public String getString(String key, String defaultValue) { - return hasKey(key) ? getString(key) : defaultValue; - } - - public boolean getBoolean(ConfigKey key) { - return getBoolean(key.getKey()); - } - - @Deprecated - public boolean getBoolean(String key) { - return Boolean.parseBoolean(getString(key)); - } - - public int getInteger(ConfigKey key) { - return getInteger(key.getKey()); - } - - @Deprecated - public int getInteger(String key) { - return getInteger(key, 0); - } - - public int getInteger(ConfigKey key, int defaultValue) { - return getInteger(key.getKey(), defaultValue); - } - - @Deprecated - public int getInteger(String key, int defaultValue) { - return hasKey(key) ? Integer.parseInt(getString(key)) : defaultValue; - } - - public long getLong(ConfigKey key) { - return getLong(key.getKey()); - } - - @Deprecated - public long getLong(String key) { - return getLong(key, 0); - } - - public long getLong(ConfigKey key, long defaultValue) { - return getLong(key.getKey(), defaultValue); - } - - @Deprecated - public long getLong(String key, long defaultValue) { - return hasKey(key) ? Long.parseLong(getString(key)) : defaultValue; - } - - public double getDouble(ConfigKey key) { - return getDouble(key.getKey()); - } - - @Deprecated - public double getDouble(String key) { - return getDouble(key, 0.0); - } - - public double getDouble(ConfigKey key, double defaultValue) { - return getDouble(key.getKey(), defaultValue); - } - - @Deprecated - public double getDouble(String key, double defaultValue) { - return hasKey(key) ? Double.parseDouble(getString(key)) : defaultValue; - } - - public void setString(ConfigKey key, String value) { - setString(key.getKey(), value); - } - - @Deprecated - public void setString(String key, String value) { - properties.put(key, value); - } - - static String getEnvironmentVariableName(String key) { - return key.replaceAll("\\.", "_").replaceAll("(\\p{Lu})", "_$1").toUpperCase(); - } - -} diff --git a/src/org/traccar/config/ConfigKey.java b/src/org/traccar/config/ConfigKey.java deleted file mode 100644 index 2e54ad392..000000000 --- a/src/org/traccar/config/ConfigKey.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 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. - * 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.config; - -public class ConfigKey { - - private final String key; - private final Class clazz; - - ConfigKey(String key, Class clazz) { - this.key = key; - this.clazz = clazz; - } - - String getKey() { - return key; - } - - Class getValueClass() { - return clazz; - } - -} diff --git a/src/org/traccar/config/ConfigSuffix.java b/src/org/traccar/config/ConfigSuffix.java deleted file mode 100644 index 149b2cd00..000000000 --- a/src/org/traccar/config/ConfigSuffix.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 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. - * 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.config; - -public class ConfigSuffix extends ConfigKey { - - ConfigSuffix(String key, Class clazz) { - super(key, clazz); - } - - public ConfigKey withPrefix(String prefix) { - return new ConfigKey(prefix + getKey(), getValueClass()); - } - -} diff --git a/src/org/traccar/config/Keys.java b/src/org/traccar/config/Keys.java deleted file mode 100644 index 48cf3e558..000000000 --- a/src/org/traccar/config/Keys.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright 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. - * 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.config; - -public final class Keys { - - /** - * Connection timeout value in seconds. Because sometimes there is no way to detect lost TCP connection old - * connections stay in open state. On most systems there is a limit on number of open connection, so this leads to - * problems with establishing new connections when number of devices is high or devices data connections are - * unstable. - */ - public static final ConfigSuffix PROTOCOL_TIMEOUT = new ConfigSuffix( - ".timeout", Integer.class); - - /** - * Server wide connection timeout value in seconds. See protocol timeout for more information. - */ - public static final ConfigKey SERVER_TIMEOUT = new ConfigKey( - "server.timeout", Integer.class); - - /** - * Address for uploading aggregated anonymous usage statistics. Uploaded information is the same you can see on the - * statistics screen in the web app. It does not include any sensitive (e.g. locations). - */ - public static final ConfigKey SERVER_STATISTICS = new ConfigKey( - "server.statistics", Boolean.class); - - /** - * Enable events subsystem. Flag to enable all events handlers. - */ - public static final ConfigKey EVENT_ENABLE = new ConfigKey( - "event.enable", Boolean.class); - - /** - * If true, the event is generated once at the beginning of overspeeding period. - */ - public static final ConfigKey EVENT_OVERSPEED_NOT_REPEAT = new ConfigKey( - "event.overspeed.notRepeat", Boolean.class); - - /** - * Minimal over speed duration to trigger the event. Value in seconds. - */ - public static final ConfigKey EVENT_OVERSPEED_MINIMAL_DURATION = new ConfigKey( - "event.overspeed.minimalDuration", Long.class); - - /** - * Relevant only for geofence speed limits. Use lowest speed limits from all geofences. - */ - public static final ConfigKey EVENT_OVERSPEED_PREFER_LOWEST = new ConfigKey( - "event.overspeed.preferLowest", Boolean.class); - - /** - * Do not generate alert event if same alert was present in last known location. - */ - public static final ConfigKey EVENT_IGNORE_DUPLICATE_ALERTS = new ConfigKey( - "event.ignoreDuplicateAlerts", Boolean.class); - - /** - * List of external handler classes to use in Netty pipeline. - */ - public static final ConfigKey EXTRA_HANDLERS = new ConfigKey( - "extra.handlers", String.class); - - /** - * Enable positions forwarding to other web server. - */ - public static final ConfigKey FORWARD_ENABLE = new ConfigKey( - "forward.enable", Boolean.class); - - /** - * URL to forward positions. Data is passed through URL parameters. For example, {uniqueId} for device identifier, - * {latitude} and {longitude} for coordinates. - */ - public static final ConfigKey FORWARD_URL = new ConfigKey( - "forward.url", String.class); - - /** - * Additional HTTP header, can be used for authorization. - */ - public static final ConfigKey FORWARD_HEADER = new ConfigKey( - "forward.header", String.class); - - /** - * Boolean value to enable forwarding in JSON format. - */ - public static final ConfigKey FORWARD_JSON = new ConfigKey( - "forward.json", Boolean.class); - - /** - * Boolean flag to enable or disable position filtering. - */ - public static final ConfigKey FILTER_ENABLE = new ConfigKey( - "filter.enable", Boolean.class); - - /** - * Filter invalid (valid field is set to false) positions. - */ - public static final ConfigKey FILTER_INVALID = new ConfigKey( - "filter.invalid", Boolean.class); - - /** - * Filter zero coordinates. Zero latitude and longitude are theoretically valid values, but it practice it usually - * indicates invalid GPS data. - */ - public static final ConfigKey FILTER_ZERO = new ConfigKey( - "filter.zero", Boolean.class); - - /** - * Filter duplicate records (duplicates are detected by time value). - */ - public static final ConfigKey FILTER_DUPLICATE = new ConfigKey( - "filter.duplicate", Boolean.class); - - /** - * Filter records with fix time in future. The values is specified in seconds. Records that have fix time more than - * specified number of seconds later than current server time would be filtered out. - */ - public static final ConfigKey FILTER_FUTURE = new ConfigKey( - "filter.future", Long.class); - - /** - * Filter positions with accuracy less than specified value in meters. - */ - public static final ConfigKey FILTER_ACCURACY = new ConfigKey( - "filter.accuracy", Integer.class); - - /** - * Filter cell and wifi locations that are coming from geolocation provider. - */ - public static final ConfigKey FILTER_APPROXIMATE = new ConfigKey( - "filter.approximate", Boolean.class); - - /** - * Filter positions with exactly zero speed values. - */ - public static final ConfigKey FILTER_STATIC = new ConfigKey( - "filter.static", Boolean.class); - - /** - * Filter records by distance. The values is specified in meters. If the new position is less far than this value - * from the last one it gets filtered out. - */ - public static final ConfigKey FILTER_DISTANCE = new ConfigKey( - "filter.distance", Integer.class); - - /** - * Filter records by Maximum Speed value in knots. Can be used to filter jumps to far locations even if they're - * marked as valid. Shouldn't be too low. Start testing with values at about 25000. - */ - public static final ConfigKey FILTER_MAX_SPEED = new ConfigKey( - "filter.maxSpeed", Integer.class); - - /** - * Filter position if time from previous position is less than specified value in seconds. - */ - public static final ConfigKey FILTER_MIN_PERIOD = new ConfigKey( - "filter.minPeriod", Integer.class); - - /** - * Time limit for the filtering in seconds. If the time difference between last position and a new one is more than - * this limit, the new position will not be filtered out. - */ - public static final ConfigKey FILTER_SKIP_LIMIT = new ConfigKey( - "filter.skipLimit", Long.class); - - /** - * Enable attributes skipping. Attribute skipping can be enabled in the config or device attributes. - */ - public static final ConfigKey FILTER_SKIP_ATTRIBUTES_ENABLE = new ConfigKey( - "filter.skipAttributes.enable", Boolean.class); - - /** - * Replaces coordinates with last known if change is less than a 'coordinates.error' meters. Helps to avoid - * coordinates jumps during parking period. - */ - public static final ConfigKey COORDINATES_FILTER = new ConfigKey( - "coordinates.filter", Boolean.class); - - /** - * Distance in meters. Distances below this value gets handled like explained in 'coordinates.filter'. - */ - public static final ConfigKey COORDINATES_MIN_ERROR = new ConfigKey( - "coordinates.minError", Integer.class); - - /** - * Distance in meters. Distances above this value gets handled like explained in 'coordinates.filter', but only if - * Position is also marked as 'invalid'. - */ - public static final ConfigKey COORDINATES_MAX_ERROR = new ConfigKey( - "filter.maxError", Integer.class); - - /** - * Enable to save device IP addresses information. Disabled by default. - */ - public static final ConfigKey PROCESSING_REMOTE_ADDRESS_ENABLE = new ConfigKey( - "processing.remoteAddress.enable", Boolean.class); - - /** - * Enable engine hours calculation on the server side. It uses ignition value to determine engine state. - */ - public static final ConfigKey PROCESSING_ENGINE_HOURS_ENABLE = new ConfigKey( - "processing.engineHours.enable", Boolean.class); - - /** - * Enable copying of missing attributes from last position to the current one. Might be useful if device doesn't - * send some values in every message. - */ - public static final ConfigKey PROCESSING_COPY_ATTRIBUTES_ENABLE = new ConfigKey( - "processing.copyAttributes.enable", Boolean.class); - - /** - * Enable computed attributes processing. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_ENABLE = new ConfigKey( - "processing.computedAttributes.enable", Boolean.class); - - /** - * Enable computed attributes processing. - */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new ConfigKey( - "processing.computedAttributes.deviceAttributes", Boolean.class); - - /** - * Boolean flag to enable or disable reverse geocoder. - */ - public static final ConfigKey GEOCODER_ENABLE = new ConfigKey( - "geocoder.enable", Boolean.class); - - /** - * Reverse geocoder type. Check reverse geocoding documentation for more info. By default (if the value is not - * specified) server uses Google API. - */ - public static final ConfigKey GEOCODER_TYPE = new ConfigKey( - "geocoder.type", String.class); - - /** - * Geocoder server URL. Applicable only to Nominatim and Gisgraphy providers. - */ - public static final ConfigKey GEOCODER_URL = new ConfigKey( - "geocoder.url", String.class); - - /** - * App id for use with Here provider. - */ - public static final ConfigKey GEOCODER_ID = new ConfigKey( - "geocoder.id", String.class); - - /** - * Provider API key. Most providers require API keys. - */ - public static final ConfigKey GEOCODER_KEY = new ConfigKey( - "geocoder.key", String.class); - - /** - * Language parameter for providers that support localization (e.g. Google and Nominatim). - */ - public static final ConfigKey GEOCODER_LANGUAGE = new ConfigKey( - "geocoder.language", String.class); - - /** - * Address format string. Default value is %h %r, %t, %s, %c. See AddressFormat for more info. - */ - public static final ConfigKey GEOCODER_FORMAT = new ConfigKey( - "geocoder.format", String.class); - - /** - * Cache size for geocoding results. - */ - public static final ConfigKey GEOCODER_CACHE_SIZE = new ConfigKey( - "geocoder.cacheSize", Integer.class); - - /** - * Disable automatic reverse geocoding requests for all positions. - */ - public static final ConfigKey GEOCODER_IGNORE_POSITIONS = new ConfigKey( - "geocoder.ignorePositions", Boolean.class); - - /** - * Boolean flag to apply reverse geocoding to invalid positions. - */ - public static final ConfigKey GEOCODER_PROCESS_INVALID_POSITIONS = new ConfigKey( - "geocoder.processInvalidPositions", Boolean.class); - - /** - * Optional parameter to specify minimum distance for new reverse geocoding request. If distance is less than - * specified value (in meters), then Traccar will reuse last known address. - */ - public static final ConfigKey GEOCODER_REUSE_DISTANCE = new ConfigKey( - "geocoder.reuseDistance", Integer.class); - - /** - * Boolean flag to enable LBS location resolution. Some devices send cell towers information and WiFi point when GPS - * location is not available. Traccar can determine coordinates based on that information using third party - * services. Default value is false. - */ - public static final ConfigKey GEOLOCATION_ENABLE = new ConfigKey( - "geolocation.enable", Boolean.class); - - /** - * Provider to use for LBS location. Available options: google, mozilla and opencellid. By default opencellid is - * used. You have to supply a key that you get from corresponding provider. For more information see LBS geolocation - * documentation. - */ - public static final ConfigKey GEOLOCATION_TYPE = new ConfigKey( - "geolocation.type", String.class); - - /** - * Geolocation provider API URL address. Not required for most providers. - */ - public static final ConfigKey GEOLOCATION_URL = new ConfigKey( - "geolocation.url", String.class); - - /** - * Provider API key. OpenCellID service requires API key. - */ - public static final ConfigKey GEOLOCATION_KEY = new ConfigKey( - "geolocation.key", String.class); - - /** - * Boolean flag to apply geolocation to invalid positions. - */ - public static final ConfigKey GEOLOCATION_PROCESS_INVALID_POSITIONS = new ConfigKey( - "geolocation.processInvalidPositions", Boolean.class); - - /** - * Override latitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can be - * N for North or S for South. - */ - public static final ConfigKey LOCATION_LATITUDE_HEMISPHERE = new ConfigKey( - "location.latitudeHemisphere", Boolean.class); - - /** - * Override longitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can - * be E for East or W for West. - */ - public static final ConfigKey LOCATION_LONGITUDE_HEMISPHERE = new ConfigKey( - "location.longitudeHemisphere", Boolean.class); - - private Keys() { - } - -} diff --git a/src/org/traccar/database/ActiveDevice.java b/src/org/traccar/database/ActiveDevice.java deleted file mode 100644 index 207fc454b..000000000 --- a/src/org/traccar/database/ActiveDevice.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - * 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.database; - -import io.netty.channel.Channel; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.model.Command; - -import java.net.SocketAddress; - -public class ActiveDevice { - - private final long deviceId; - private final Protocol protocol; - private final Channel channel; - private final SocketAddress remoteAddress; - - public ActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) { - this.deviceId = deviceId; - this.protocol = protocol; - this.channel = channel; - this.remoteAddress = remoteAddress; - } - - public Channel getChannel() { - return channel; - } - - public long getDeviceId() { - return deviceId; - } - - public void sendCommand(Command command) { - protocol.sendDataCommand(this, command); - } - - public void write(Object message) { - channel.writeAndFlush(new NetworkMessage(message, remoteAddress)); - } - -} diff --git a/src/org/traccar/database/AttributesManager.java b/src/org/traccar/database/AttributesManager.java deleted file mode 100644 index 28816645a..000000000 --- a/src/org/traccar/database/AttributesManager.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import org.traccar.model.Attribute; - -public class AttributesManager extends ExtendedObjectManager { - - public AttributesManager(DataManager dataManager) { - super(dataManager, Attribute.class); - } - - @Override - public void updateCachedItem(Attribute attribute) { - Attribute cachedAttribute = getById(attribute.getId()); - cachedAttribute.setDescription(attribute.getDescription()); - cachedAttribute.setAttribute(attribute.getAttribute()); - cachedAttribute.setExpression(attribute.getExpression()); - cachedAttribute.setType(attribute.getType()); - } - -} diff --git a/src/org/traccar/database/BaseObjectManager.java b/src/org/traccar/database/BaseObjectManager.java deleted file mode 100644 index 8bf9ef860..000000000 --- a/src/org/traccar/database/BaseObjectManager.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.model.BaseModel; - -public class BaseObjectManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(BaseObjectManager.class); - - private final DataManager dataManager; - - private Map items; - private Class baseClass; - - protected BaseObjectManager(DataManager dataManager, Class baseClass) { - this.dataManager = dataManager; - this.baseClass = baseClass; - refreshItems(); - } - - protected final DataManager getDataManager() { - return dataManager; - } - - protected final Class getBaseClass() { - return baseClass; - } - - public T getById(long itemId) { - return items.get(itemId); - } - - public void refreshItems() { - if (dataManager != null) { - try { - Collection databaseItems = dataManager.getObjects(baseClass); - if (items == null) { - items = new ConcurrentHashMap<>(databaseItems.size()); - } - Set databaseItemIds = new HashSet<>(); - for (T item : databaseItems) { - databaseItemIds.add(item.getId()); - if (items.containsKey(item.getId())) { - updateCachedItem(item); - } else { - addNewItem(item); - } - } - for (Long cachedItemId : items.keySet()) { - if (!databaseItemIds.contains(cachedItemId)) { - removeCachedItem(cachedItemId); - } - } - } catch (SQLException error) { - LOGGER.warn("Error refreshing items", error); - } - } - } - - protected void addNewItem(T item) { - items.put(item.getId(), item); - } - - public void addItem(T item) throws SQLException { - dataManager.addObject(item); - addNewItem(item); - } - - protected void updateCachedItem(T item) { - items.put(item.getId(), item); - } - - public void updateItem(T item) throws SQLException { - dataManager.updateObject(item); - updateCachedItem(item); - } - - protected void removeCachedItem(long itemId) { - items.remove(itemId); - } - - public void removeItem(long itemId) throws SQLException { - BaseModel item = getById(itemId); - if (item != null) { - dataManager.removeObject(baseClass, itemId); - removeCachedItem(itemId); - } - } - - public final Collection getItems(Set itemIds) { - Collection result = new LinkedList<>(); - for (long itemId : itemIds) { - result.add(getById(itemId)); - } - return result; - } - - public Set getAllItems() { - return items.keySet(); - } - -} diff --git a/src/org/traccar/database/CalendarManager.java b/src/org/traccar/database/CalendarManager.java deleted file mode 100644 index 44ced1082..000000000 --- a/src/org/traccar/database/CalendarManager.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import org.traccar.model.Calendar; - -public class CalendarManager extends SimpleObjectManager { - - public CalendarManager(DataManager dataManager) { - super(dataManager, Calendar.class); - } - -} diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java deleted file mode 100644 index d6fdd66ca..000000000 --- a/src/org/traccar/database/CommandsManager.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseProtocol; -import org.traccar.Context; -import org.traccar.model.Command; -import org.traccar.model.Typed; -import org.traccar.model.Position; - -public class CommandsManager extends ExtendedObjectManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(CommandsManager.class); - - private final Map> deviceQueues = new ConcurrentHashMap<>(); - - private boolean queueing; - - public CommandsManager(DataManager dataManager, boolean queueing) { - super(dataManager, Command.class); - this.queueing = queueing; - } - - public boolean checkDeviceCommand(long deviceId, long commandId) { - return !getAllDeviceItems(deviceId).contains(commandId); - } - - public boolean sendCommand(Command command) throws Exception { - long deviceId = command.getDeviceId(); - if (command.getId() != 0) { - command = getById(command.getId()).clone(); - command.setDeviceId(deviceId); - } - if (command.getTextChannel()) { - Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); - String phone = Context.getIdentityManager().getById(deviceId).getPhone(); - if (lastPosition != null) { - BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); - protocol.sendTextCommand(phone, command); - } else if (command.getType().equals(Command.TYPE_CUSTOM)) { - if (Context.getSmsManager() != null) { - Context.getSmsManager().sendMessageSync(phone, command.getString(Command.KEY_DATA), true); - } else { - throw new RuntimeException("SMS is not enabled"); - } - } else { - throw new RuntimeException("Command " + command.getType() + " is not supported"); - } - } else { - ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId); - if (activeDevice != null) { - activeDevice.sendCommand(command); - } else if (!queueing) { - throw new RuntimeException("Device is not online"); - } else { - getDeviceQueue(deviceId).add(command); - return false; - } - } - return true; - } - - public Collection getSupportedCommands(long deviceId) { - List result = new ArrayList<>(); - Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); - for (long commandId : getAllDeviceItems(deviceId)) { - Command command = getById(commandId); - if (lastPosition != null) { - BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); - if (command.getTextChannel() && protocol.getSupportedTextCommands().contains(command.getType()) - || !command.getTextChannel() - && protocol.getSupportedDataCommands().contains(command.getType())) { - result.add(commandId); - } - } else if (command.getType().equals(Command.TYPE_CUSTOM)) { - result.add(commandId); - } - } - return result; - } - - public Collection getCommandTypes(long deviceId, boolean textChannel) { - List result = new ArrayList<>(); - Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); - if (lastPosition != null) { - BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); - Collection commands; - commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands(); - for (String commandKey : commands) { - result.add(new Typed(commandKey)); - } - } else { - result.add(new Typed(Command.TYPE_CUSTOM)); - } - return result; - } - - public Collection getAllCommandTypes() { - List result = new ArrayList<>(); - Field[] fields = Command.class.getDeclaredFields(); - for (Field field : fields) { - if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) { - try { - result.add(new Typed(field.get(null).toString())); - } catch (IllegalArgumentException | IllegalAccessException error) { - LOGGER.warn("Get command types error", error); - } - } - } - return result; - } - - private Queue getDeviceQueue(long deviceId) { - if (!deviceQueues.containsKey(deviceId)) { - deviceQueues.put(deviceId, new ConcurrentLinkedQueue()); - } - return deviceQueues.get(deviceId); - } - - public void sendQueuedCommands(ActiveDevice activeDevice) { - Queue deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); - if (deviceQueue != null) { - Command command = deviceQueue.poll(); - while (command != null) { - activeDevice.sendCommand(command); - command = deviceQueue.poll(); - } - } - } - -} diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java deleted file mode 100644 index 8bae1ea93..000000000 --- a/src/org/traccar/database/ConnectionManager.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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. - * 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.database; - -import io.netty.channel.Channel; -import io.netty.util.Timeout; -import io.netty.util.TimerTask; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.GlobalTimer; -import org.traccar.Main; -import org.traccar.Protocol; -import org.traccar.handler.events.MotionEventHandler; -import org.traccar.handler.events.OverspeedEventHandler; -import org.traccar.model.Device; -import org.traccar.model.DeviceState; -import org.traccar.model.Event; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.sql.SQLException; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -public class ConnectionManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class); - - private static final long DEFAULT_TIMEOUT = 600; - - private final long deviceTimeout; - private final boolean enableStatusEvents; - private final boolean updateDeviceState; - - private final Map activeDevices = new ConcurrentHashMap<>(); - private final Map> listeners = new ConcurrentHashMap<>(); - private final Map timeouts = new ConcurrentHashMap<>(); - - public ConnectionManager() { - deviceTimeout = Context.getConfig().getLong("status.timeout", DEFAULT_TIMEOUT) * 1000; - enableStatusEvents = Context.getConfig().getBoolean("event.enable"); - updateDeviceState = Context.getConfig().getBoolean("status.updateDeviceState"); - } - - public void addActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) { - activeDevices.put(deviceId, new ActiveDevice(deviceId, protocol, channel, remoteAddress)); - } - - public void removeActiveDevice(Channel channel) { - for (ActiveDevice activeDevice : activeDevices.values()) { - if (activeDevice.getChannel() == channel) { - updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, null); - activeDevices.remove(activeDevice.getDeviceId()); - break; - } - } - } - - public ActiveDevice getActiveDevice(long deviceId) { - return activeDevices.get(deviceId); - } - - public void updateDevice(final long deviceId, String status, Date time) { - Device device = Context.getIdentityManager().getById(deviceId); - if (device == null) { - return; - } - - String oldStatus = device.getStatus(); - device.setStatus(status); - - if (enableStatusEvents && !status.equals(oldStatus)) { - String eventType; - Map events = new HashMap<>(); - switch (status) { - case Device.STATUS_ONLINE: - eventType = Event.TYPE_DEVICE_ONLINE; - break; - case Device.STATUS_UNKNOWN: - eventType = Event.TYPE_DEVICE_UNKNOWN; - if (updateDeviceState) { - events.putAll(updateDeviceState(deviceId)); - } - break; - default: - eventType = Event.TYPE_DEVICE_OFFLINE; - if (updateDeviceState) { - events.putAll(updateDeviceState(deviceId)); - } - break; - } - events.put(new Event(eventType, deviceId), null); - Context.getNotificationManager().updateEvents(events); - } - - Timeout timeout = timeouts.remove(deviceId); - if (timeout != null) { - timeout.cancel(); - } - - if (time != null) { - device.setLastUpdate(time); - } - - if (status.equals(Device.STATUS_ONLINE)) { - timeouts.put(deviceId, GlobalTimer.getTimer().newTimeout(new TimerTask() { - @Override - public void run(Timeout timeout) { - if (!timeout.isCancelled()) { - updateDevice(deviceId, Device.STATUS_UNKNOWN, null); - } - } - }, deviceTimeout, TimeUnit.MILLISECONDS)); - } - - try { - Context.getDeviceManager().updateDeviceStatus(device); - } catch (SQLException error) { - LOGGER.warn("Update device status error", error); - } - - updateDevice(device); - - if (status.equals(Device.STATUS_ONLINE) && !oldStatus.equals(Device.STATUS_ONLINE)) { - Context.getCommandsManager().sendQueuedCommands(getActiveDevice(deviceId)); - } - } - - public Map updateDeviceState(long deviceId) { - DeviceState deviceState = Context.getDeviceManager().getDeviceState(deviceId); - Map result = new HashMap<>(); - - Map event = Main.getInjector() - .getInstance(MotionEventHandler.class).updateMotionState(deviceState); - if (event != null) { - result.putAll(event); - } - - event = Main.getInjector().getInstance(OverspeedEventHandler.class) - .updateOverspeedState(deviceState, Context.getDeviceManager(). - lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, false)); - if (event != null) { - result.putAll(event); - } - - return result; - } - - public synchronized void updateDevice(Device device) { - for (long userId : Context.getPermissionsManager().getDeviceUsers(device.getId())) { - if (listeners.containsKey(userId)) { - for (UpdateListener listener : listeners.get(userId)) { - listener.onUpdateDevice(device); - } - } - } - } - - public synchronized void updatePosition(Position position) { - long deviceId = position.getDeviceId(); - - for (long userId : Context.getPermissionsManager().getDeviceUsers(deviceId)) { - if (listeners.containsKey(userId)) { - for (UpdateListener listener : listeners.get(userId)) { - listener.onUpdatePosition(position); - } - } - } - } - - public synchronized void updateEvent(long userId, Event event) { - if (listeners.containsKey(userId)) { - for (UpdateListener listener : listeners.get(userId)) { - listener.onUpdateEvent(event); - } - } - } - - public interface UpdateListener { - void onUpdateDevice(Device device); - void onUpdatePosition(Position position); - void onUpdateEvent(Event event); - } - - public synchronized void addListener(long userId, UpdateListener listener) { - if (!listeners.containsKey(userId)) { - listeners.put(userId, new HashSet()); - } - listeners.get(userId).add(listener); - } - - public synchronized void removeListener(long userId, UpdateListener listener) { - if (!listeners.containsKey(userId)) { - listeners.put(userId, new HashSet()); - } - listeners.get(userId).remove(listener); - } - -} diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java deleted file mode 100644 index 8e9071736..000000000 --- a/src/org/traccar/database/DataManager.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright 2012 - 2017 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. - * 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.database; - -import java.beans.Introspector; -import java.io.File; -import java.lang.reflect.Method; -import java.net.URL; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; - -import javax.naming.InitialContext; -import javax.sql.DataSource; - -import liquibase.Contexts; -import liquibase.Liquibase; -import liquibase.database.Database; -import liquibase.database.DatabaseFactory; -import liquibase.exception.LiquibaseException; -import liquibase.resource.FileSystemResourceAccessor; -import liquibase.resource.ResourceAccessor; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.Context; -import org.traccar.helper.DateUtil; -import org.traccar.model.Attribute; -import org.traccar.model.Device; -import org.traccar.model.Driver; -import org.traccar.model.Event; -import org.traccar.model.Geofence; -import org.traccar.model.Group; -import org.traccar.model.Maintenance; -import org.traccar.model.ManagedUser; -import org.traccar.model.Notification; -import org.traccar.model.Permission; -import org.traccar.model.BaseModel; -import org.traccar.model.Calendar; -import org.traccar.model.Command; -import org.traccar.model.Position; -import org.traccar.model.Server; -import org.traccar.model.Statistics; -import org.traccar.model.User; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; - -public class DataManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(DataManager.class); - - public static final String ACTION_SELECT_ALL = "selectAll"; - public static final String ACTION_SELECT = "select"; - public static final String ACTION_INSERT = "insert"; - public static final String ACTION_UPDATE = "update"; - public static final String ACTION_DELETE = "delete"; - - private final Config config; - - private DataSource dataSource; - - private boolean generateQueries; - - private boolean forceLdap; - - public DataManager(Config config) throws Exception { - this.config = config; - - forceLdap = config.getBoolean("ldap.force"); - - initDatabase(); - initDatabaseSchema(); - } - - private void initDatabase() throws Exception { - - String jndiName = config.getString("database.jndi"); - - if (jndiName != null) { - - dataSource = (DataSource) new InitialContext().lookup(jndiName); - - } else { - - String driverFile = config.getString("database.driverFile"); - if (driverFile != null) { - ClassLoader classLoader = ClassLoader.getSystemClassLoader(); - try { - Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class); - method.setAccessible(true); - method.invoke(classLoader, new File(driverFile).toURI().toURL()); - } catch (NoSuchMethodException e) { - Method method = classLoader.getClass() - .getDeclaredMethod("appendToClassPathForInstrumentation", String.class); - method.setAccessible(true); - method.invoke(classLoader, driverFile); - } - } - - String driver = config.getString("database.driver"); - if (driver != null) { - Class.forName(driver); - } - - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setDriverClassName(config.getString("database.driver")); - hikariConfig.setJdbcUrl(config.getString("database.url")); - hikariConfig.setUsername(config.getString("database.user")); - hikariConfig.setPassword(config.getString("database.password")); - hikariConfig.setConnectionInitSql(config.getString("database.checkConnection", "SELECT 1")); - hikariConfig.setIdleTimeout(600000); - - int maxPoolSize = config.getInteger("database.maxPoolSize"); - - if (maxPoolSize != 0) { - hikariConfig.setMaximumPoolSize(maxPoolSize); - } - - generateQueries = config.getBoolean("database.generateQueries"); - - dataSource = new HikariDataSource(hikariConfig); - - } - } - - public static String constructObjectQuery(String action, Class clazz, boolean extended) { - switch (action) { - case ACTION_INSERT: - case ACTION_UPDATE: - StringBuilder result = new StringBuilder(); - StringBuilder fields = new StringBuilder(); - StringBuilder values = new StringBuilder(); - - Set methods = new HashSet<>(Arrays.asList(clazz.getMethods())); - methods.removeAll(Arrays.asList(Object.class.getMethods())); - methods.removeAll(Arrays.asList(BaseModel.class.getMethods())); - for (Method method : methods) { - boolean skip; - if (extended) { - skip = !method.isAnnotationPresent(QueryExtended.class); - } else { - skip = method.isAnnotationPresent(QueryIgnore.class) - || method.isAnnotationPresent(QueryExtended.class) && !action.equals(ACTION_INSERT); - } - if (!skip && method.getName().startsWith("get") && method.getParameterTypes().length == 0) { - String name = Introspector.decapitalize(method.getName().substring(3)); - if (action.equals(ACTION_INSERT)) { - fields.append(name).append(", "); - values.append(":").append(name).append(", "); - } else { - fields.append(name).append(" = :").append(name).append(", "); - } - } - } - fields.setLength(fields.length() - 2); - if (action.equals(ACTION_INSERT)) { - values.setLength(values.length() - 2); - result.append("INSERT INTO ").append(getObjectsTableName(clazz)).append(" ("); - result.append(fields).append(") "); - result.append("VALUES (").append(values).append(")"); - } else { - result.append("UPDATE ").append(getObjectsTableName(clazz)).append(" SET "); - result.append(fields); - result.append(" WHERE id = :id"); - } - return result.toString(); - case ACTION_SELECT_ALL: - return "SELECT * FROM " + getObjectsTableName(clazz); - case ACTION_SELECT: - return "SELECT * FROM " + getObjectsTableName(clazz) + " WHERE id = :id"; - case ACTION_DELETE: - return "DELETE FROM " + getObjectsTableName(clazz) + " WHERE id = :id"; - default: - throw new IllegalArgumentException("Unknown action"); - } - } - - public static String constructPermissionQuery(String action, Class owner, Class property) { - switch (action) { - case ACTION_SELECT_ALL: - return "SELECT " + makeNameId(owner) + ", " + makeNameId(property) + " FROM " - + getPermissionsTableName(owner, property); - case ACTION_INSERT: - return "INSERT INTO " + getPermissionsTableName(owner, property) - + " (" + makeNameId(owner) + ", " + makeNameId(property) + ") VALUES (:" - + makeNameId(owner) + ", :" + makeNameId(property) + ")"; - case ACTION_DELETE: - return "DELETE FROM " + getPermissionsTableName(owner, property) - + " WHERE " + makeNameId(owner) + " = :" + makeNameId(owner) - + " AND " + makeNameId(property) + " = :" + makeNameId(property); - default: - throw new IllegalArgumentException("Unknown action"); - } - } - - private String getQuery(String key) { - String query = config.getString(key); - if (query == null) { - LOGGER.info("Query not provided: " + key); - } - return query; - } - - public String getQuery(String action, Class clazz) { - return getQuery(action, clazz, false); - } - - public String getQuery(String action, Class clazz, boolean extended) { - String queryName; - if (action.equals(ACTION_SELECT_ALL)) { - queryName = "database.select" + clazz.getSimpleName() + "s"; - } else { - queryName = "database." + action.toLowerCase() + clazz.getSimpleName(); - if (extended) { - queryName += "Extended"; - } - } - String query = config.getString(queryName); - if (query == null) { - if (generateQueries) { - query = constructObjectQuery(action, clazz, extended); - config.setString(queryName, query); - } else { - LOGGER.info("Query not provided: " + queryName); - } - } - - return query; - } - - public String getQuery(String action, Class owner, Class property) { - String queryName; - switch (action) { - case ACTION_SELECT_ALL: - queryName = "database.select" + owner.getSimpleName() + property.getSimpleName() + "s"; - break; - case ACTION_INSERT: - queryName = "database.link" + owner.getSimpleName() + property.getSimpleName(); - break; - default: - queryName = "database.unlink" + owner.getSimpleName() + property.getSimpleName(); - break; - } - String query = config.getString(queryName); - if (query == null) { - if (generateQueries) { - query = constructPermissionQuery(action, owner, - property.equals(User.class) ? ManagedUser.class : property); - config.setString(queryName, query); - } else { - LOGGER.info("Query not provided: " + queryName); - } - } - - return query; - } - - private static String getPermissionsTableName(Class owner, Class property) { - String propertyName = property.getSimpleName(); - if (propertyName.equals("ManagedUser")) { - propertyName = "User"; - } - return "tc_" + Introspector.decapitalize(owner.getSimpleName()) - + "_" + Introspector.decapitalize(propertyName); - } - - private static String getObjectsTableName(Class clazz) { - String result = "tc_" + Introspector.decapitalize(clazz.getSimpleName()); - // Add "s" ending if object name is not plural already - if (!result.endsWith("s")) { - result += "s"; - } - return result; - } - - private void initDatabaseSchema() throws SQLException, LiquibaseException { - - if (config.hasKey("database.changelog")) { - - ResourceAccessor resourceAccessor = new FileSystemResourceAccessor(); - - Database database = DatabaseFactory.getInstance().openDatabase( - config.getString("database.url"), - config.getString("database.user"), - config.getString("database.password"), - config.getString("database.driver"), - null, null, null, resourceAccessor); - - Liquibase liquibase = new Liquibase( - config.getString("database.changelog"), resourceAccessor, database); - - liquibase.clearCheckSums(); - - liquibase.update(new Contexts()); - } - } - - public User login(String email, String password) throws SQLException { - User user = QueryBuilder.create(dataSource, getQuery("database.loginUser")) - .setString("email", email.trim()) - .executeQuerySingle(User.class); - LdapProvider ldapProvider = Context.getLdapProvider(); - if (user != null) { - if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) - || !forceLdap && user.isPasswordValid(password)) { - return user; - } - } else { - if (ldapProvider != null && ldapProvider.login(email, password)) { - user = ldapProvider.getUser(email); - Context.getUsersManager().addItem(user); - return user; - } - } - return null; - } - - public void updateDeviceStatus(Device device) throws SQLException { - QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, Device.class, true)) - .setObject(device) - .executeUpdate(); - } - - public Collection getPositions(long deviceId, Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectPositions")) - .setLong("deviceId", deviceId) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Position.class); - } - - public void updateLatestPosition(Position position) throws SQLException { - QueryBuilder.create(dataSource, getQuery("database.updateLatestPosition")) - .setDate("now", new Date()) - .setObject(position) - .executeUpdate(); - } - - public Collection getLatestPositions() throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectLatestPositions")) - .executeQuery(Position.class); - } - - public void clearHistory() throws SQLException { - long historyDays = config.getInteger("database.historyDays"); - if (historyDays != 0) { - Date timeLimit = new Date(System.currentTimeMillis() - historyDays * 24 * 3600 * 1000); - LOGGER.info("Clearing history earlier than " + DateUtil.formatDate(timeLimit, false)); - QueryBuilder.create(dataSource, getQuery("database.deletePositions")) - .setDate("serverTime", timeLimit) - .executeUpdate(); - QueryBuilder.create(dataSource, getQuery("database.deleteEvents")) - .setDate("serverTime", timeLimit) - .executeUpdate(); - } - } - - public Server getServer() throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, Server.class)) - .executeQuerySingle(Server.class); - } - - public Collection getEvents(long deviceId, Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectEvents")) - .setLong("deviceId", deviceId) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Event.class); - } - - public Collection getStatistics(Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectStatistics")) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Statistics.class); - } - - public static Class getClassByName(String name) throws ClassNotFoundException { - switch (name.toLowerCase().replace("id", "")) { - case "device": - return Device.class; - case "group": - return Group.class; - case "user": - return User.class; - case "manageduser": - return ManagedUser.class; - case "geofence": - return Geofence.class; - case "driver": - return Driver.class; - case "attribute": - return Attribute.class; - case "calendar": - return Calendar.class; - case "command": - return Command.class; - case "maintenance": - return Maintenance.class; - case "notification": - return Notification.class; - default: - throw new ClassNotFoundException(); - } - } - - private static String makeNameId(Class clazz) { - String name = clazz.getSimpleName(); - return Introspector.decapitalize(name) + (!name.contains("Id") ? "Id" : ""); - } - - public Collection getPermissions(Class owner, Class property) - throws SQLException, ClassNotFoundException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, owner, property)) - .executePermissionsQuery(); - } - - public void linkObject(Class owner, long ownerId, Class property, long propertyId, boolean link) - throws SQLException { - QueryBuilder.create(dataSource, getQuery(link ? ACTION_INSERT : ACTION_DELETE, owner, property)) - .setLong(makeNameId(owner), ownerId) - .setLong(makeNameId(property), propertyId) - .executeUpdate(); - } - - public T getObject(Class clazz, long entityId) throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT, clazz)) - .setLong("id", entityId) - .executeQuerySingle(clazz); - } - - public Collection getObjects(Class clazz) throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, clazz)) - .executeQuery(clazz); - } - - public void addObject(BaseModel entity) throws SQLException { - entity.setId(QueryBuilder.create(dataSource, getQuery(ACTION_INSERT, entity.getClass()), true) - .setObject(entity) - .executeUpdate()); - } - - public void updateObject(BaseModel entity) throws SQLException { - QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, entity.getClass())) - .setObject(entity) - .executeUpdate(); - if (entity instanceof User && ((User) entity).getHashedPassword() != null) { - QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, User.class, true)) - .setObject(entity) - .executeUpdate(); - } - } - - public void removeObject(Class clazz, long entityId) throws SQLException { - QueryBuilder.create(dataSource, getQuery(ACTION_DELETE, clazz)) - .setLong("id", entityId) - .executeUpdate(); - } - -} diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java deleted file mode 100644 index de4607d1f..000000000 --- a/src/org/traccar/database/DeviceManager.java +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.database; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.DeviceState; -import org.traccar.model.DeviceAccumulators; -import org.traccar.model.Group; -import org.traccar.model.Position; -import org.traccar.model.Server; - -public class DeviceManager extends BaseObjectManager implements IdentityManager, ManagableObjects { - - private static final Logger LOGGER = LoggerFactory.getLogger(DeviceManager.class); - - public static final long DEFAULT_REFRESH_DELAY = 300; - - private final Config config; - private final long dataRefreshDelay; - private boolean lookupGroupsAttribute; - - private Map devicesByUniqueId; - private Map devicesByPhone; - private AtomicLong devicesLastUpdate = new AtomicLong(); - - private final Map positions = new ConcurrentHashMap<>(); - - private final Map deviceStates = new ConcurrentHashMap<>(); - - public DeviceManager(DataManager dataManager) { - super(dataManager, Device.class); - this.config = Context.getConfig(); - if (devicesByPhone == null) { - devicesByPhone = new ConcurrentHashMap<>(); - } - if (devicesByUniqueId == null) { - devicesByUniqueId = new ConcurrentHashMap<>(); - } - dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000; - lookupGroupsAttribute = config.getBoolean("deviceManager.lookupGroupsAttribute"); - refreshLastPositions(); - } - - @Override - public long addUnknownDevice(String uniqueId) { - Device device = new Device(); - device.setName(uniqueId); - device.setUniqueId(uniqueId); - device.setCategory(Context.getConfig().getString("database.registerUnknown.defaultCategory")); - - long defaultGroupId = Context.getConfig().getLong("database.registerUnknown.defaultGroupId"); - if (defaultGroupId != 0) { - device.setGroupId(defaultGroupId); - } - - try { - addItem(device); - - LOGGER.info("Automatically registered device " + uniqueId); - - if (defaultGroupId != 0) { - Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); - Context.getPermissionsManager().refreshAllExtendedPermissions(); - } - - return device.getId(); - } catch (SQLException e) { - LOGGER.warn("Automatic device registration error", e); - return 0; - } - } - - public void updateDeviceCache(boolean force) throws SQLException { - long lastUpdate = devicesLastUpdate.get(); - if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) - && devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { - refreshItems(); - } - } - - @Override - public Device getByUniqueId(String uniqueId) throws SQLException { - boolean forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); - - updateDeviceCache(forceUpdate); - - return devicesByUniqueId.get(uniqueId); - } - - public Device getDeviceByPhone(String phone) { - return devicesByPhone.get(phone); - } - - @Override - public Set getAllItems() { - Set result = super.getAllItems(); - if (result.isEmpty()) { - try { - updateDeviceCache(true); - } catch (SQLException e) { - LOGGER.warn("Update device cache error", e); - } - result = super.getAllItems(); - } - return result; - } - - public Collection getAllDevices() { - return getItems(getAllItems()); - } - - public Set getAllUserItems(long userId) { - return Context.getPermissionsManager().getDevicePermissions(userId); - } - - @Override - public Set getUserItems(long userId) { - if (Context.getPermissionsManager() != null) { - Set result = new HashSet<>(); - for (long deviceId : Context.getPermissionsManager().getDevicePermissions(userId)) { - Device device = getById(deviceId); - if (device != null && !device.getDisabled()) { - result.add(deviceId); - } - } - return result; - } else { - return new HashSet<>(); - } - } - - public Set getAllManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getAllUserItems(userId)); - for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { - result.addAll(getAllUserItems(managedUserId)); - } - return result; - } - - @Override - public Set getManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getUserItems(userId)); - for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { - result.addAll(getUserItems(managedUserId)); - } - return result; - } - - private void putUniqueDeviceId(Device device) { - if (devicesByUniqueId == null) { - devicesByUniqueId = new ConcurrentHashMap<>(getAllItems().size()); - } - devicesByUniqueId.put(device.getUniqueId(), device); - } - - private void putPhone(Device device) { - if (devicesByPhone == null) { - devicesByPhone = new ConcurrentHashMap<>(getAllItems().size()); - } - devicesByPhone.put(device.getPhone(), device); - } - - @Override - protected void addNewItem(Device device) { - super.addNewItem(device); - putUniqueDeviceId(device); - if (device.getPhone() != null && !device.getPhone().isEmpty()) { - putPhone(device); - } - if (Context.getGeofenceManager() != null) { - Position lastPosition = getLastPosition(device.getId()); - if (lastPosition != null) { - device.setGeofenceIds(Context.getGeofenceManager().getCurrentDeviceGeofences(lastPosition)); - } - } - } - - @Override - protected void updateCachedItem(Device device) { - Device cachedDevice = getById(device.getId()); - cachedDevice.setName(device.getName()); - cachedDevice.setGroupId(device.getGroupId()); - cachedDevice.setCategory(device.getCategory()); - cachedDevice.setContact(device.getContact()); - cachedDevice.setModel(device.getModel()); - cachedDevice.setDisabled(device.getDisabled()); - cachedDevice.setAttributes(device.getAttributes()); - if (!device.getUniqueId().equals(cachedDevice.getUniqueId())) { - devicesByUniqueId.remove(cachedDevice.getUniqueId()); - cachedDevice.setUniqueId(device.getUniqueId()); - putUniqueDeviceId(cachedDevice); - } - if (device.getPhone() != null && !device.getPhone().isEmpty() - && !device.getPhone().equals(cachedDevice.getPhone())) { - String phone = cachedDevice.getPhone(); - if (phone != null && !phone.isEmpty()) { - devicesByPhone.remove(phone); - } - cachedDevice.setPhone(device.getPhone()); - putPhone(cachedDevice); - } - } - - @Override - protected void removeCachedItem(long deviceId) { - Device cachedDevice = getById(deviceId); - if (cachedDevice != null) { - String deviceUniqueId = cachedDevice.getUniqueId(); - String phone = cachedDevice.getPhone(); - super.removeCachedItem(deviceId); - devicesByUniqueId.remove(deviceUniqueId); - if (phone != null && !phone.isEmpty()) { - devicesByPhone.remove(phone); - } - } - positions.remove(deviceId); - } - - public void updateDeviceStatus(Device device) throws SQLException { - getDataManager().updateDeviceStatus(device); - Device cachedDevice = getById(device.getId()); - if (cachedDevice != null) { - cachedDevice.setStatus(device.getStatus()); - } - } - - private void refreshLastPositions() { - if (getDataManager() != null) { - try { - for (Position position : getDataManager().getLatestPositions()) { - positions.put(position.getDeviceId(), position); - } - } catch (SQLException error) { - LOGGER.warn("Load latest positions error", error); - } - } - } - - public boolean isLatestPosition(Position position) { - Position lastPosition = getLastPosition(position.getDeviceId()); - return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0; - } - - public void updateLatestPosition(Position position) throws SQLException { - - if (isLatestPosition(position)) { - - getDataManager().updateLatestPosition(position); - - Device device = getById(position.getDeviceId()); - if (device != null) { - device.setPositionId(position.getId()); - } - - positions.put(position.getDeviceId(), position); - - if (Context.getConnectionManager() != null) { - Context.getConnectionManager().updatePosition(position); - } - } - } - - @Override - public Position getLastPosition(long deviceId) { - return positions.get(deviceId); - } - - public Collection getInitialState(long userId) { - - List result = new LinkedList<>(); - - if (Context.getPermissionsManager() != null) { - for (long deviceId : Context.getPermissionsManager().getUserAdmin(userId) - ? getAllUserItems(userId) : getUserItems(userId)) { - if (positions.containsKey(deviceId)) { - result.add(positions.get(deviceId)); - } - } - } - - return result; - } - - @Override - public boolean lookupAttributeBoolean( - long deviceId, String attributeName, boolean defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); - if (result != null) { - return result instanceof String ? Boolean.parseBoolean((String) result) : (Boolean) result; - } - return defaultValue; - } - - @Override - public String lookupAttributeString( - long deviceId, String attributeName, String defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); - return result != null ? (String) result : defaultValue; - } - - @Override - public int lookupAttributeInteger(long deviceId, String attributeName, int defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); - if (result != null) { - return result instanceof String ? Integer.parseInt((String) result) : ((Number) result).intValue(); - } - return defaultValue; - } - - @Override - public long lookupAttributeLong( - long deviceId, String attributeName, long defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); - if (result != null) { - return result instanceof String ? Long.parseLong((String) result) : ((Number) result).longValue(); - } - return defaultValue; - } - - public double lookupAttributeDouble( - long deviceId, String attributeName, double defaultValue, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupConfig); - if (result != null) { - return result instanceof String ? Double.parseDouble((String) result) : ((Number) result).doubleValue(); - } - return defaultValue; - } - - private Object lookupAttribute(long deviceId, String attributeName, boolean lookupConfig) { - Object result = null; - Device device = getById(deviceId); - if (device != null) { - result = device.getAttributes().get(attributeName); - if (result == null && lookupGroupsAttribute) { - long groupId = device.getGroupId(); - while (groupId != 0) { - Group group = Context.getGroupsManager().getById(groupId); - if (group != null) { - result = group.getAttributes().get(attributeName); - if (result != null) { - break; - } - groupId = group.getGroupId(); - } else { - groupId = 0; - } - } - } - if (result == null) { - if (lookupConfig) { - result = Context.getConfig().getString(attributeName); - } else { - Server server = Context.getPermissionsManager().getServer(); - result = server.getAttributes().get(attributeName); - } - } - } - return result; - } - - public void resetDeviceAccumulators(DeviceAccumulators deviceAccumulators) throws SQLException { - Position last = positions.get(deviceAccumulators.getDeviceId()); - if (last != null) { - if (deviceAccumulators.getTotalDistance() != null) { - last.getAttributes().put(Position.KEY_TOTAL_DISTANCE, deviceAccumulators.getTotalDistance()); - } - if (deviceAccumulators.getHours() != null) { - last.getAttributes().put(Position.KEY_HOURS, deviceAccumulators.getHours()); - } - getDataManager().addObject(last); - updateLatestPosition(last); - } else { - throw new IllegalArgumentException(); - } - } - - public DeviceState getDeviceState(long deviceId) { - DeviceState deviceState = deviceStates.get(deviceId); - if (deviceState == null) { - deviceState = new DeviceState(); - deviceStates.put(deviceId, deviceState); - } - return deviceState; - } - - public void setDeviceState(long deviceId, DeviceState deviceState) { - deviceStates.put(deviceId, deviceState); - } - -} diff --git a/src/org/traccar/database/DriversManager.java b/src/org/traccar/database/DriversManager.java deleted file mode 100644 index 930951460..000000000 --- a/src/org/traccar/database/DriversManager.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.traccar.model.Driver; - -public class DriversManager extends ExtendedObjectManager { - - private Map driversByUniqueId; - - public DriversManager(DataManager dataManager) { - super(dataManager, Driver.class); - if (driversByUniqueId == null) { - driversByUniqueId = new ConcurrentHashMap<>(); - } - } - - private void putUniqueDriverId(Driver driver) { - if (driversByUniqueId == null) { - driversByUniqueId = new ConcurrentHashMap<>(getAllItems().size()); - } - driversByUniqueId.put(driver.getUniqueId(), driver); - } - - @Override - protected void addNewItem(Driver driver) { - super.addNewItem(driver); - putUniqueDriverId(driver); - } - - @Override - protected void updateCachedItem(Driver driver) { - Driver cachedDriver = getById(driver.getId()); - cachedDriver.setName(driver.getName()); - if (!driver.getUniqueId().equals(cachedDriver.getUniqueId())) { - driversByUniqueId.remove(cachedDriver.getUniqueId()); - cachedDriver.setUniqueId(driver.getUniqueId()); - putUniqueDriverId(cachedDriver); - } - cachedDriver.setAttributes(driver.getAttributes()); - } - - @Override - protected void removeCachedItem(long driverId) { - Driver cachedDriver = getById(driverId); - if (cachedDriver != null) { - String driverUniqueId = cachedDriver.getUniqueId(); - super.removeCachedItem(driverId); - driversByUniqueId.remove(driverUniqueId); - } - } - - public Driver getDriverByUniqueId(String uniqueId) { - return driversByUniqueId.get(uniqueId); - } -} diff --git a/src/org/traccar/database/ExtendedObjectManager.java b/src/org/traccar/database/ExtendedObjectManager.java deleted file mode 100644 index ceb85b537..000000000 --- a/src/org/traccar/database/ExtendedObjectManager.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.Group; -import org.traccar.model.Permission; -import org.traccar.model.BaseModel; - -public abstract class ExtendedObjectManager extends SimpleObjectManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(ExtendedObjectManager.class); - - private final Map> deviceItems = new ConcurrentHashMap<>(); - private final Map> deviceItemsWithGroups = new ConcurrentHashMap<>(); - private final Map> groupItems = new ConcurrentHashMap<>(); - - protected ExtendedObjectManager(DataManager dataManager, Class baseClass) { - super(dataManager, baseClass); - refreshExtendedPermissions(); - } - - public final Set getGroupItems(long groupId) { - if (!groupItems.containsKey(groupId)) { - groupItems.put(groupId, new HashSet()); - } - return groupItems.get(groupId); - } - - public final Set getDeviceItems(long deviceId) { - if (!deviceItems.containsKey(deviceId)) { - deviceItems.put(deviceId, new HashSet()); - } - return deviceItems.get(deviceId); - } - - public Set getAllDeviceItems(long deviceId) { - if (!deviceItemsWithGroups.containsKey(deviceId)) { - deviceItemsWithGroups.put(deviceId, new HashSet()); - } - return deviceItemsWithGroups.get(deviceId); - } - - @Override - public void removeItem(long itemId) throws SQLException { - super.removeItem(itemId); - refreshExtendedPermissions(); - } - - public void refreshExtendedPermissions() { - if (getDataManager() != null) { - try { - - Collection databaseGroupPermissions = - getDataManager().getPermissions(Group.class, getBaseClass()); - - groupItems.clear(); - for (Permission groupPermission : databaseGroupPermissions) { - getGroupItems(groupPermission.getOwnerId()).add(groupPermission.getPropertyId()); - } - - Collection databaseDevicePermissions = - getDataManager().getPermissions(Device.class, getBaseClass()); - - deviceItems.clear(); - deviceItemsWithGroups.clear(); - - for (Permission devicePermission : databaseDevicePermissions) { - getDeviceItems(devicePermission.getOwnerId()).add(devicePermission.getPropertyId()); - getAllDeviceItems(devicePermission.getOwnerId()).add(devicePermission.getPropertyId()); - } - - for (Device device : Context.getDeviceManager().getAllDevices()) { - long groupId = device.getGroupId(); - while (groupId != 0) { - getAllDeviceItems(device.getId()).addAll(getGroupItems(groupId)); - Group group = Context.getGroupsManager().getById(groupId); - if (group != null) { - groupId = group.getGroupId(); - } else { - groupId = 0; - } - } - } - - } catch (SQLException | ClassNotFoundException error) { - LOGGER.warn("Refresh permissions error", error); - } - } - } -} diff --git a/src/org/traccar/database/GeofenceManager.java b/src/org/traccar/database/GeofenceManager.java deleted file mode 100644 index a32847cf9..000000000 --- a/src/org/traccar/database/GeofenceManager.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.database; - -import java.util.ArrayList; -import java.util.List; - -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.Geofence; -import org.traccar.model.Position; - -public class GeofenceManager extends ExtendedObjectManager { - - public GeofenceManager(DataManager dataManager) { - super(dataManager, Geofence.class); - } - - @Override - public final void refreshExtendedPermissions() { - super.refreshExtendedPermissions(); - recalculateDevicesGeofences(); - } - - public List getCurrentDeviceGeofences(Position position) { - List result = new ArrayList<>(); - for (long geofenceId : getAllDeviceItems(position.getDeviceId())) { - Geofence geofence = getById(geofenceId); - if (geofence != null && geofence.getGeometry() - .containsPoint(position.getLatitude(), position.getLongitude())) { - result.add(geofenceId); - } - } - return result; - } - - public void recalculateDevicesGeofences() { - for (Device device : Context.getDeviceManager().getAllDevices()) { - List deviceGeofenceIds = device.getGeofenceIds(); - if (deviceGeofenceIds == null) { - deviceGeofenceIds = new ArrayList<>(); - } else { - deviceGeofenceIds.clear(); - } - Position lastPosition = Context.getIdentityManager().getLastPosition(device.getId()); - if (lastPosition != null && getAllDeviceItems(device.getId()) != null) { - deviceGeofenceIds.addAll(getCurrentDeviceGeofences(lastPosition)); - } - device.setGeofenceIds(deviceGeofenceIds); - } - } - -} diff --git a/src/org/traccar/database/GroupTree.java b/src/org/traccar/database/GroupTree.java deleted file mode 100644 index 8798f55bc..000000000 --- a/src/org/traccar/database/GroupTree.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2016 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. - * 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.database; - -import org.traccar.model.Device; -import org.traccar.model.Group; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class GroupTree { - - private static class TreeNode { - - private Group group; - private Device device; - private Collection children = new HashSet<>(); - - TreeNode(Group group) { - this.group = group; - } - - TreeNode(Device device) { - this.device = device; - } - - @Override - public int hashCode() { - if (group != null) { - return (int) group.getId(); - } else { - return (int) device.getId(); - } - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof TreeNode)) { - return false; - } - TreeNode other = (TreeNode) obj; - if (other == this) { - return true; - } - if (group != null && other.group != null) { - return group.getId() == other.group.getId(); - } else if (device != null && other.device != null) { - return device.getId() == other.device.getId(); - } - return false; - } - - public Group getGroup() { - return group; - } - - public Device getDevice() { - return device; - } - - public void setParent(TreeNode parent) { - if (parent != null) { - parent.children.add(this); - } - } - - public Collection getChildren() { - return children; - } - - } - - private final Map groupMap = new HashMap<>(); - - public GroupTree(Collection groups, Collection devices) { - - for (Group group : groups) { - groupMap.put(group.getId(), new TreeNode(group)); - } - - for (TreeNode node : groupMap.values()) { - if (node.getGroup().getGroupId() != 0) { - node.setParent(groupMap.get(node.getGroup().getGroupId())); - } - } - - Map deviceMap = new HashMap<>(); - - for (Device device : devices) { - deviceMap.put(device.getId(), new TreeNode(device)); - } - - for (TreeNode node : deviceMap.values()) { - if (node.getDevice().getGroupId() != 0) { - node.setParent(groupMap.get(node.getDevice().getGroupId())); - } - } - - } - - public Collection getGroups(long groupId) { - Set results = new HashSet<>(); - getNodes(results, groupMap.get(groupId)); - Collection groups = new ArrayList<>(); - for (TreeNode node : results) { - if (node.getGroup() != null) { - groups.add(node.getGroup()); - } - } - return groups; - } - - public Collection getDevices(long groupId) { - Set results = new HashSet<>(); - getNodes(results, groupMap.get(groupId)); - Collection devices = new ArrayList<>(); - for (TreeNode node : results) { - if (node.getDevice() != null) { - devices.add(node.getDevice()); - } - } - return devices; - } - - private void getNodes(Set results, TreeNode node) { - if (node != null) { - for (TreeNode child : node.getChildren()) { - results.add(child); - getNodes(results, child); - } - } - } - -} diff --git a/src/org/traccar/database/GroupsManager.java b/src/org/traccar/database/GroupsManager.java deleted file mode 100644 index d8404c614..000000000 --- a/src/org/traccar/database/GroupsManager.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.sql.SQLException; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.Group; - -public class GroupsManager extends BaseObjectManager implements ManagableObjects { - - private static final Logger LOGGER = LoggerFactory.getLogger(GroupsManager.class); - - private AtomicLong groupsLastUpdate = new AtomicLong(); - private final long dataRefreshDelay; - - public GroupsManager(DataManager dataManager) { - super(dataManager, Group.class); - dataRefreshDelay = Context.getConfig().getLong("database.refreshDelay", - DeviceManager.DEFAULT_REFRESH_DELAY) * 1000; - } - - private void checkGroupCycles(Group group) { - Set groups = new HashSet<>(); - while (group != null) { - if (groups.contains(group.getId())) { - throw new IllegalArgumentException("Cycle in group hierarchy"); - } - groups.add(group.getId()); - group = getById(group.getGroupId()); - } - } - - public void updateGroupCache(boolean force) throws SQLException { - long lastUpdate = groupsLastUpdate.get(); - if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) - && groupsLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { - refreshItems(); - } - } - - @Override - public Set getAllItems() { - Set result = super.getAllItems(); - if (result.isEmpty()) { - try { - updateGroupCache(true); - } catch (SQLException e) { - LOGGER.warn("Update group cache error", e); - } - result = super.getAllItems(); - } - return result; - } - - @Override - protected void addNewItem(Group group) { - checkGroupCycles(group); - super.addNewItem(group); - } - - @Override - public void updateItem(Group group) throws SQLException { - checkGroupCycles(group); - super.updateItem(group); - } - - @Override - public Set getUserItems(long userId) { - if (Context.getPermissionsManager() != null) { - return Context.getPermissionsManager().getGroupPermissions(userId); - } else { - return new HashSet<>(); - } - } - - @Override - public Set getManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getUserItems(userId)); - for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { - result.addAll(getUserItems(managedUserId)); - } - return result; - } - -} diff --git a/src/org/traccar/database/IdentityManager.java b/src/org/traccar/database/IdentityManager.java deleted file mode 100644 index 6228a0f75..000000000 --- a/src/org/traccar/database/IdentityManager.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 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. - * 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.database; - -import org.traccar.model.Device; -import org.traccar.model.Position; - -public interface IdentityManager { - - long addUnknownDevice(String uniqueId); - - Device getById(long id); - - Device getByUniqueId(String uniqueId) throws Exception; - - Position getLastPosition(long deviceId); - - boolean isLatestPosition(Position position); - - boolean lookupAttributeBoolean(long deviceId, String attributeName, boolean defaultValue, boolean lookupConfig); - - String lookupAttributeString(long deviceId, String attributeName, String defaultValue, boolean lookupConfig); - - int lookupAttributeInteger(long deviceId, String attributeName, int defaultValue, boolean lookupConfig); - - long lookupAttributeLong(long deviceId, String attributeName, long defaultValue, boolean lookupConfig); - - double lookupAttributeDouble(long deviceId, String attributeName, double defaultValue, boolean lookupConfig); - -} diff --git a/src/org/traccar/database/LdapProvider.java b/src/org/traccar/database/LdapProvider.java deleted file mode 100644 index d8b5c9f52..000000000 --- a/src/org/traccar/database/LdapProvider.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2017 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. - * 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.database; - -import javax.naming.Context; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.InitialDirContext; -import javax.naming.directory.SearchControls; -import javax.naming.directory.SearchResult; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.model.User; - -import java.util.Hashtable; - -public class LdapProvider { - - private static final Logger LOGGER = LoggerFactory.getLogger(LdapProvider.class); - - private String url; - private String searchBase; - private String idAttribute; - private String nameAttribute; - private String mailAttribute; - private String searchFilter; - private String adminFilter; - private String serviceUser; - private String servicePassword; - - public LdapProvider(Config config) { - String url = config.getString("ldap.url"); - if (url != null) { - this.url = url; - } else { - this.url = "ldap://" + config.getString("ldap.server") + ":" + config.getInteger("ldap.port", 389); - } - this.searchBase = config.getString("ldap.base"); - this.idAttribute = config.getString("ldap.idAttribute", "uid"); - this.nameAttribute = config.getString("ldap.nameAttribute", "cn"); - this.mailAttribute = config.getString("ldap.mailAttribute", "mail"); - this.searchFilter = config.getString("ldap.searchFilter", "(" + idAttribute + "=:login)"); - String adminGroup = config.getString("ldap.adminGroup"); - this.adminFilter = config.getString("ldap.adminFilter"); - if (this.adminFilter == null && adminGroup != null) { - this.adminFilter = "(&(" + idAttribute + "=:login)(memberOf=" + adminGroup + "))"; - } - this.serviceUser = config.getString("ldap.user"); - this.servicePassword = config.getString("ldap.password"); - } - - private InitialDirContext auth(String accountName, String password) throws NamingException { - Hashtable env = new Hashtable<>(); - env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); - env.put(Context.PROVIDER_URL, url); - - env.put(Context.SECURITY_AUTHENTICATION, "simple"); - env.put(Context.SECURITY_PRINCIPAL, accountName); - env.put(Context.SECURITY_CREDENTIALS, password); - - return new InitialDirContext(env); - } - - private boolean isAdmin(String accountName) { - if (this.adminFilter != null) { - try { - InitialDirContext context = initContext(); - String searchString = adminFilter.replace(":login", accountName); - SearchControls searchControls = new SearchControls(); - searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - NamingEnumeration results = context.search(searchBase, searchString, searchControls); - if (results.hasMoreElements()) { - results.nextElement(); - if (results.hasMoreElements()) { - LOGGER.warn("Matched multiple users for the accountName: " + accountName); - return false; - } - return true; - } - } catch (NamingException e) { - return false; - } - } - return false; - } - - public InitialDirContext initContext() throws NamingException { - return auth(serviceUser, servicePassword); - } - - private SearchResult lookupUser(String accountName) throws NamingException { - InitialDirContext context = initContext(); - - String searchString = searchFilter.replace(":login", accountName); - - SearchControls searchControls = new SearchControls(); - String[] attributeFilter = {idAttribute, nameAttribute, mailAttribute}; - searchControls.setReturningAttributes(attributeFilter); - searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - - NamingEnumeration results = context.search(searchBase, searchString, searchControls); - - SearchResult searchResult = null; - if (results.hasMoreElements()) { - searchResult = results.nextElement(); - if (results.hasMoreElements()) { - LOGGER.warn("Matched multiple users for the accountName: " + accountName); - return null; - } - } - - return searchResult; - } - - public User getUser(String accountName) { - SearchResult ldapUser; - User user = new User(); - try { - ldapUser = lookupUser(accountName); - if (ldapUser != null) { - Attribute attribute = ldapUser.getAttributes().get(idAttribute); - if (attribute != null) { - user.setLogin((String) attribute.get()); - } else { - user.setLogin(accountName); - } - attribute = ldapUser.getAttributes().get(nameAttribute); - if (attribute != null) { - user.setName((String) attribute.get()); - } else { - user.setName(accountName); - } - attribute = ldapUser.getAttributes().get(mailAttribute); - if (attribute != null) { - user.setEmail((String) attribute.get()); - } else { - user.setEmail(accountName); - } - } - user.setAdministrator(isAdmin(accountName)); - } catch (NamingException e) { - user.setLogin(accountName); - user.setName(accountName); - user.setEmail(accountName); - LOGGER.warn("User lookup error", e); - } - return user; - } - - public boolean login(String username, String password) { - try { - SearchResult ldapUser = lookupUser(username); - if (ldapUser != null) { - auth(ldapUser.getNameInNamespace(), password).close(); - return true; - } - } catch (NamingException e) { - return false; - } - return false; - } - -} diff --git a/src/org/traccar/database/MailManager.java b/src/org/traccar/database/MailManager.java deleted file mode 100644 index 8a2f002cd..000000000 --- a/src/org/traccar/database/MailManager.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.Main; -import org.traccar.model.User; -import org.traccar.notification.PropertiesProvider; - -import javax.mail.BodyPart; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; -import java.util.Date; -import java.util.Properties; - -public final class MailManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(MailManager.class); - - private static Properties getProperties(PropertiesProvider provider) { - Properties properties = new Properties(); - String host = provider.getString("mail.smtp.host"); - if (host != null) { - properties.put("mail.transport.protocol", provider.getString("mail.transport.protocol", "smtp")); - properties.put("mail.smtp.host", host); - properties.put("mail.smtp.port", String.valueOf(provider.getInteger("mail.smtp.port", 25))); - - Boolean starttlsEnable = provider.getBoolean("mail.smtp.starttls.enable"); - if (starttlsEnable != null) { - properties.put("mail.smtp.starttls.enable", String.valueOf(starttlsEnable)); - } - Boolean starttlsRequired = provider.getBoolean("mail.smtp.starttls.required"); - if (starttlsRequired != null) { - properties.put("mail.smtp.starttls.required", String.valueOf(starttlsRequired)); - } - - Boolean sslEnable = provider.getBoolean("mail.smtp.ssl.enable"); - if (sslEnable != null) { - properties.put("mail.smtp.ssl.enable", String.valueOf(sslEnable)); - } - String sslTrust = provider.getString("mail.smtp.ssl.trust"); - if (sslTrust != null) { - properties.put("mail.smtp.ssl.trust", sslTrust); - } - - String sslProtocols = provider.getString("mail.smtp.ssl.protocols"); - if (sslProtocols != null) { - properties.put("mail.smtp.ssl.protocols", sslProtocols); - } - - String username = provider.getString("mail.smtp.username"); - if (username != null) { - properties.put("mail.smtp.username", username); - } - String password = provider.getString("mail.smtp.password"); - if (password != null) { - properties.put("mail.smtp.password", password); - } - String from = provider.getString("mail.smtp.from"); - if (from != null) { - properties.put("mail.smtp.from", from); - } - } - return properties; - } - - public void sendMessage( - long userId, String subject, String body) throws MessagingException { - sendMessage(userId, subject, body, null); - } - - public void sendMessage( - long userId, String subject, String body, MimeBodyPart attachment) throws MessagingException { - User user = Context.getPermissionsManager().getUser(userId); - - Properties properties = null; - if (!Context.getConfig().getBoolean("mail.smtp.ignoreUserConfig")) { - properties = getProperties(new PropertiesProvider(user)); - } - if (properties == null || !properties.containsKey("mail.smtp.host")) { - properties = getProperties(new PropertiesProvider(Context.getConfig())); - } - if (!properties.containsKey("mail.smtp.host")) { - LOGGER.warn("No SMTP configuration found"); - return; - } - - Session session = Session.getInstance(properties); - - MimeMessage message = new MimeMessage(session); - - String from = properties.getProperty("mail.smtp.from"); - if (from != null) { - message.setFrom(new InternetAddress(from)); - } - - message.addRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail())); - message.setSubject(subject); - message.setSentDate(new Date()); - - if (attachment != null) { - Multipart multipart = new MimeMultipart(); - - BodyPart messageBodyPart = new MimeBodyPart(); - messageBodyPart.setContent(body, "text/html; charset=utf-8"); - multipart.addBodyPart(messageBodyPart); - multipart.addBodyPart(attachment); - - message.setContent(multipart); - } else { - message.setContent(body, "text/html; charset=utf-8"); - } - - try (Transport transport = session.getTransport()) { - Main.getInjector().getInstance(StatisticsManager.class).registerMail(); - transport.connect( - properties.getProperty("mail.smtp.host"), - properties.getProperty("mail.smtp.username"), - properties.getProperty("mail.smtp.password")); - transport.sendMessage(message, message.getAllRecipients()); - } - } - -} diff --git a/src/org/traccar/database/MaintenancesManager.java b/src/org/traccar/database/MaintenancesManager.java deleted file mode 100644 index 4e266cb78..000000000 --- a/src/org/traccar/database/MaintenancesManager.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import org.traccar.model.Maintenance; - -public class MaintenancesManager extends ExtendedObjectManager { - - public MaintenancesManager(DataManager dataManager) { - super(dataManager, Maintenance.class); - } - -} diff --git a/src/org/traccar/database/ManagableObjects.java b/src/org/traccar/database/ManagableObjects.java deleted file mode 100644 index ec9549493..000000000 --- a/src/org/traccar/database/ManagableObjects.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.util.Set; - -public interface ManagableObjects { - - Set getUserItems(long userId); - - Set getManagedItems(long userId); - -} diff --git a/src/org/traccar/database/MediaManager.java b/src/org/traccar/database/MediaManager.java deleted file mode 100644 index edade5766..000000000 --- a/src/org/traccar/database/MediaManager.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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.database; - -import io.netty.buffer.ByteBuf; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.SimpleDateFormat; -import java.util.Date; - -public class MediaManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(MediaManager.class); - - private String path; - - public MediaManager(String path) { - this.path = path; - } - - private File createFile(String uniqueId, String name) throws IOException { - Path filePath = Paths.get(path, uniqueId, name); - Path directoryPath = filePath.getParent(); - if (directoryPath != null) { - Files.createDirectories(directoryPath); - } - return filePath.toFile(); - } - - public String writeFile(String uniqueId, ByteBuf buf, String extension) { - if (path != null) { - int size = buf.readableBytes(); - String name = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "." + extension; - try (FileOutputStream output = new FileOutputStream(createFile(uniqueId, name)); - FileChannel fileChannel = output.getChannel()) { - ByteBuffer byteBuffer = buf.nioBuffer(); - int written = 0; - while (written < size) { - written += fileChannel.write(byteBuffer); - } - fileChannel.force(false); - return name; - } catch (IOException e) { - LOGGER.warn("Save media file error", e); - } - } - return null; - } - -} diff --git a/src/org/traccar/database/NotificationManager.java b/src/org/traccar/database/NotificationManager.java deleted file mode 100644 index 09df4c571..000000000 --- a/src/org/traccar/database/NotificationManager.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.sql.SQLException; -import java.util.Date; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.Calendar; -import org.traccar.model.Event; -import org.traccar.model.Notification; -import org.traccar.model.Position; -import org.traccar.model.Typed; - -public class NotificationManager extends ExtendedObjectManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(NotificationManager.class); - - private boolean geocodeOnRequest; - - public NotificationManager(DataManager dataManager) { - super(dataManager, Notification.class); - geocodeOnRequest = Context.getConfig().getBoolean("geocoder.onRequest"); - } - - private Set getEffectiveNotifications(long userId, long deviceId, Date time) { - Set result = new HashSet<>(); - Set deviceNotifications = getAllDeviceItems(deviceId); - for (long itemId : getUserItems(userId)) { - if (getById(itemId).getAlways() || deviceNotifications.contains(itemId)) { - long calendarId = getById(itemId).getCalendarId(); - Calendar calendar = calendarId != 0 ? Context.getCalendarManager().getById(calendarId) : null; - if (calendar == null || calendar.checkMoment(time)) { - result.add(itemId); - } - } - } - return result; - } - - public void updateEvent(Event event, Position position) { - try { - getDataManager().addObject(event); - } catch (SQLException error) { - LOGGER.warn("Event save error", error); - } - - if (position != null && geocodeOnRequest && Context.getGeocoder() != null && position.getAddress() == null) { - position.setAddress(Context.getGeocoder() - .getAddress(position.getLatitude(), position.getLongitude(), null)); - } - - long deviceId = event.getDeviceId(); - Set users = Context.getPermissionsManager().getDeviceUsers(deviceId); - Set usersToForward = null; - if (Context.getEventForwarder() != null) { - usersToForward = new HashSet<>(); - } - for (long userId : users) { - if ((event.getGeofenceId() == 0 - || Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId())) - && (event.getMaintenanceId() == 0 - || Context.getMaintenancesManager().checkItemPermission(userId, event.getMaintenanceId()))) { - if (usersToForward != null) { - usersToForward.add(userId); - } - final Set notificators = new HashSet<>(); - for (long notificationId : getEffectiveNotifications(userId, deviceId, event.getServerTime())) { - Notification notification = getById(notificationId); - if (getById(notificationId).getType().equals(event.getType())) { - boolean filter = false; - if (event.getType().equals(Event.TYPE_ALARM)) { - String alarms = notification.getString("alarms"); - if (alarms == null || !alarms.contains(event.getString(Position.KEY_ALARM))) { - filter = true; - } - } - if (!filter) { - notificators.addAll(notification.getNotificatorsTypes()); - } - } - } - for (String notificator : notificators) { - Context.getNotificatorManager().getNotificator(notificator).sendAsync(userId, event, position); - } - } - } - if (Context.getEventForwarder() != null) { - Context.getEventForwarder().forwardEvent(event, position, usersToForward); - } - } - - public void updateEvents(Map events) { - for (Entry event : events.entrySet()) { - updateEvent(event.getKey(), event.getValue()); - } - } - - public Set getAllNotificationTypes() { - Set types = new HashSet<>(); - Field[] fields = Event.class.getDeclaredFields(); - for (Field field : fields) { - if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) { - try { - types.add(new Typed(field.get(null).toString())); - } catch (IllegalArgumentException | IllegalAccessException error) { - LOGGER.warn("Get event types error", error); - } - } - } - return types; - } -} diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java deleted file mode 100644 index ced0df1c0..000000000 --- a/src/org/traccar/database/PermissionsManager.java +++ /dev/null @@ -1,459 +0,0 @@ -/* - * 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. - * 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.database; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.Attribute; -import org.traccar.model.BaseModel; -import org.traccar.model.Calendar; -import org.traccar.model.Command; -import org.traccar.model.Device; -import org.traccar.model.Driver; -import org.traccar.model.Geofence; -import org.traccar.model.Group; -import org.traccar.model.Maintenance; -import org.traccar.model.ManagedUser; -import org.traccar.model.Notification; -import org.traccar.model.Permission; -import org.traccar.model.Server; -import org.traccar.model.User; - -import java.sql.SQLException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class PermissionsManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(PermissionsManager.class); - - private final DataManager dataManager; - private final UsersManager usersManager; - - private volatile Server server; - - private final Map> groupPermissions = new HashMap<>(); - private final Map> devicePermissions = new HashMap<>(); - private final Map> deviceUsers = new HashMap<>(); - private final Map> groupDevices = new HashMap<>(); - - public PermissionsManager(DataManager dataManager, UsersManager usersManager) { - this.dataManager = dataManager; - this.usersManager = usersManager; - refreshServer(); - refreshDeviceAndGroupPermissions(); - } - - public User getUser(long userId) { - return usersManager.getById(userId); - } - - public Set getGroupPermissions(long userId) { - if (!groupPermissions.containsKey(userId)) { - groupPermissions.put(userId, new HashSet<>()); - } - return groupPermissions.get(userId); - } - - public Set getDevicePermissions(long userId) { - if (!devicePermissions.containsKey(userId)) { - devicePermissions.put(userId, new HashSet<>()); - } - return devicePermissions.get(userId); - } - - private Set getAllDeviceUsers(long deviceId) { - if (!deviceUsers.containsKey(deviceId)) { - deviceUsers.put(deviceId, new HashSet<>()); - } - return deviceUsers.get(deviceId); - } - - public Set getDeviceUsers(long deviceId) { - Device device = Context.getIdentityManager().getById(deviceId); - if (device != null && !device.getDisabled()) { - return getAllDeviceUsers(deviceId); - } else { - Set result = new HashSet<>(); - for (long userId : getAllDeviceUsers(deviceId)) { - if (getUserAdmin(userId)) { - result.add(userId); - } - } - return result; - } - } - - public Set getGroupDevices(long groupId) { - if (!groupDevices.containsKey(groupId)) { - groupDevices.put(groupId, new HashSet<>()); - } - return groupDevices.get(groupId); - } - - public void refreshServer() { - try { - server = dataManager.getServer(); - } catch (SQLException error) { - LOGGER.warn("Refresh server config error", error); - } - } - - public final void refreshDeviceAndGroupPermissions() { - groupPermissions.clear(); - devicePermissions.clear(); - try { - GroupTree groupTree = new GroupTree(Context.getGroupsManager().getItems( - Context.getGroupsManager().getAllItems()), - Context.getDeviceManager().getAllDevices()); - for (Permission groupPermission : dataManager.getPermissions(User.class, Group.class)) { - Set userGroupPermissions = getGroupPermissions(groupPermission.getOwnerId()); - Set userDevicePermissions = getDevicePermissions(groupPermission.getOwnerId()); - userGroupPermissions.add(groupPermission.getPropertyId()); - for (Group group : groupTree.getGroups(groupPermission.getPropertyId())) { - userGroupPermissions.add(group.getId()); - } - for (Device device : groupTree.getDevices(groupPermission.getPropertyId())) { - userDevicePermissions.add(device.getId()); - } - } - - for (Permission devicePermission : dataManager.getPermissions(User.class, Device.class)) { - getDevicePermissions(devicePermission.getOwnerId()).add(devicePermission.getPropertyId()); - } - - groupDevices.clear(); - for (long groupId : Context.getGroupsManager().getAllItems()) { - for (Device device : groupTree.getDevices(groupId)) { - getGroupDevices(groupId).add(device.getId()); - } - } - - } catch (SQLException | ClassNotFoundException error) { - LOGGER.warn("Refresh device permissions error", error); - } - - deviceUsers.clear(); - for (Map.Entry> entry : devicePermissions.entrySet()) { - for (long deviceId : entry.getValue()) { - getAllDeviceUsers(deviceId).add(entry.getKey()); - } - } - } - - public boolean getUserAdmin(long userId) { - User user = getUser(userId); - return user != null && user.getAdministrator(); - } - - public void checkAdmin(long userId) throws SecurityException { - if (!getUserAdmin(userId)) { - throw new SecurityException("Admin access required"); - } - } - - public boolean getUserManager(long userId) { - User user = getUser(userId); - return user != null && user.getUserLimit() != 0; - } - - public void checkManager(long userId) throws SecurityException { - if (!getUserManager(userId)) { - throw new SecurityException("Manager access required"); - } - } - - public void checkManager(long userId, long managedUserId) throws SecurityException { - checkManager(userId); - if (!usersManager.getUserItems(userId).contains(managedUserId)) { - throw new SecurityException("User access denied"); - } - } - - public void checkUserLimit(long userId) throws SecurityException { - int userLimit = getUser(userId).getUserLimit(); - if (userLimit != -1 && usersManager.getUserItems(userId).size() >= userLimit) { - throw new SecurityException("Manager user limit reached"); - } - } - - public void checkDeviceLimit(long userId) throws SecurityException { - int deviceLimit = getUser(userId).getDeviceLimit(); - if (deviceLimit != -1) { - int deviceCount = 0; - if (getUserManager(userId)) { - deviceCount = Context.getDeviceManager().getAllManagedItems(userId).size(); - } else { - deviceCount = Context.getDeviceManager().getAllUserItems(userId).size(); - } - if (deviceCount >= deviceLimit) { - throw new SecurityException("User device limit reached"); - } - } - } - - public boolean getUserReadonly(long userId) { - User user = getUser(userId); - return user != null && user.getReadonly(); - } - - public boolean getUserDeviceReadonly(long userId) { - User user = getUser(userId); - return user != null && user.getDeviceReadonly(); - } - - public boolean getUserLimitCommands(long userId) { - User user = getUser(userId); - return user != null && user.getLimitCommands(); - } - - public void checkReadonly(long userId) throws SecurityException { - if (!getUserAdmin(userId) && (server.getReadonly() || getUserReadonly(userId))) { - throw new SecurityException("Account is readonly"); - } - } - - public void checkDeviceReadonly(long userId) throws SecurityException { - if (!getUserAdmin(userId) && (server.getDeviceReadonly() || getUserDeviceReadonly(userId))) { - throw new SecurityException("Account is device readonly"); - } - } - - public void checkLimitCommands(long userId) throws SecurityException { - if (!getUserAdmin(userId) && (server.getLimitCommands() || getUserLimitCommands(userId))) { - throw new SecurityException("Account has limit sending commands"); - } - } - - public void checkUserDeviceCommand(long userId, long deviceId, long commandId) throws SecurityException { - if (!getUserAdmin(userId) && Context.getCommandsManager().checkDeviceCommand(deviceId, commandId)) { - throw new SecurityException("Command can not be sent to this device"); - } - } - - public void checkUserEnabled(long userId) throws SecurityException { - User user = getUser(userId); - if (user == null) { - throw new SecurityException("Unknown account"); - } - if (user.getDisabled()) { - throw new SecurityException("Account is disabled"); - } - if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) { - throw new SecurityException("Account has expired"); - } - } - - public void checkUserUpdate(long userId, User before, User after) throws SecurityException { - if (before.getAdministrator() != after.getAdministrator() - || before.getDeviceLimit() != after.getDeviceLimit() - || before.getUserLimit() != after.getUserLimit()) { - checkAdmin(userId); - } - User user = getUser(userId); - if (user != null && user.getExpirationTime() != null - && (after.getExpirationTime() == null - || user.getExpirationTime().compareTo(after.getExpirationTime()) < 0)) { - checkAdmin(userId); - } - if (before.getReadonly() != after.getReadonly() - || before.getDeviceReadonly() != after.getDeviceReadonly() - || before.getDisabled() != after.getDisabled() - || before.getLimitCommands() != after.getLimitCommands()) { - if (userId == after.getId()) { - checkAdmin(userId); - } - if (!getUserAdmin(userId)) { - checkManager(userId); - } - } - } - - public void checkUser(long userId, long managedUserId) throws SecurityException { - if (userId != managedUserId && !getUserAdmin(userId)) { - checkManager(userId, managedUserId); - } - } - - public void checkGroup(long userId, long groupId) throws SecurityException { - if (!getGroupPermissions(userId).contains(groupId) && !getUserAdmin(userId)) { - checkManager(userId); - for (long managedUserId : usersManager.getUserItems(userId)) { - if (getGroupPermissions(managedUserId).contains(groupId)) { - return; - } - } - throw new SecurityException("Group access denied"); - } - } - - public void checkDevice(long userId, long deviceId) throws SecurityException { - if (!Context.getDeviceManager().getUserItems(userId).contains(deviceId) && !getUserAdmin(userId)) { - checkManager(userId); - for (long managedUserId : usersManager.getUserItems(userId)) { - if (Context.getDeviceManager().getUserItems(managedUserId).contains(deviceId)) { - return; - } - } - throw new SecurityException("Device access denied"); - } - } - - public void checkRegistration(long userId) { - if (!server.getRegistration() && !getUserAdmin(userId)) { - throw new SecurityException("Registration disabled"); - } - } - - public void checkPermission(Class object, long userId, long objectId) - throws SecurityException { - SimpleObjectManager manager = null; - - if (object.equals(Device.class)) { - checkDevice(userId, objectId); - } else if (object.equals(Group.class)) { - checkGroup(userId, objectId); - } else if (object.equals(User.class) || object.equals(ManagedUser.class)) { - checkUser(userId, objectId); - } else if (object.equals(Geofence.class)) { - manager = Context.getGeofenceManager(); - } else if (object.equals(Attribute.class)) { - manager = Context.getAttributesManager(); - } else if (object.equals(Driver.class)) { - manager = Context.getDriversManager(); - } else if (object.equals(Calendar.class)) { - manager = Context.getCalendarManager(); - } else if (object.equals(Command.class)) { - manager = Context.getCommandsManager(); - } else if (object.equals(Maintenance.class)) { - manager = Context.getMaintenancesManager(); - } else if (object.equals(Notification.class)) { - manager = Context.getNotificationManager(); - } else { - throw new IllegalArgumentException("Unknown object type"); - } - - if (manager != null && !manager.checkItemPermission(userId, objectId) && !getUserAdmin(userId)) { - checkManager(userId); - for (long managedUserId : usersManager.getManagedItems(userId)) { - if (manager.checkItemPermission(managedUserId, objectId)) { - return; - } - } - throw new SecurityException("Type " + object + " access denied"); - } - } - - public void refreshAllUsersPermissions() { - if (Context.getGeofenceManager() != null) { - Context.getGeofenceManager().refreshUserItems(); - } - Context.getCalendarManager().refreshUserItems(); - Context.getDriversManager().refreshUserItems(); - Context.getAttributesManager().refreshUserItems(); - Context.getCommandsManager().refreshUserItems(); - Context.getMaintenancesManager().refreshUserItems(); - if (Context.getNotificationManager() != null) { - Context.getNotificationManager().refreshUserItems(); - } - } - - public void refreshAllExtendedPermissions() { - if (Context.getGeofenceManager() != null) { - Context.getGeofenceManager().refreshExtendedPermissions(); - } - Context.getDriversManager().refreshExtendedPermissions(); - Context.getAttributesManager().refreshExtendedPermissions(); - Context.getCommandsManager().refreshExtendedPermissions(); - Context.getMaintenancesManager().refreshExtendedPermissions(); - } - - public void refreshPermissions(Permission permission) { - if (permission.getOwnerClass().equals(User.class)) { - if (permission.getPropertyClass().equals(Device.class) - || permission.getPropertyClass().equals(Group.class)) { - refreshDeviceAndGroupPermissions(); - refreshAllExtendedPermissions(); - } else if (permission.getPropertyClass().equals(ManagedUser.class)) { - usersManager.refreshUserItems(); - } else if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) { - Context.getGeofenceManager().refreshUserItems(); - } else if (permission.getPropertyClass().equals(Driver.class)) { - Context.getDriversManager().refreshUserItems(); - } else if (permission.getPropertyClass().equals(Attribute.class)) { - Context.getAttributesManager().refreshUserItems(); - } else if (permission.getPropertyClass().equals(Calendar.class)) { - Context.getCalendarManager().refreshUserItems(); - } else if (permission.getPropertyClass().equals(Command.class)) { - Context.getCommandsManager().refreshUserItems(); - } else if (permission.getPropertyClass().equals(Maintenance.class)) { - Context.getMaintenancesManager().refreshUserItems(); - } else if (permission.getPropertyClass().equals(Notification.class) - && Context.getNotificationManager() != null) { - Context.getNotificationManager().refreshUserItems(); - } - } else if (permission.getOwnerClass().equals(Device.class) || permission.getOwnerClass().equals(Group.class)) { - if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) { - Context.getGeofenceManager().refreshExtendedPermissions(); - } else if (permission.getPropertyClass().equals(Driver.class)) { - Context.getDriversManager().refreshExtendedPermissions(); - } else if (permission.getPropertyClass().equals(Attribute.class)) { - Context.getAttributesManager().refreshExtendedPermissions(); - } else if (permission.getPropertyClass().equals(Command.class)) { - Context.getCommandsManager().refreshExtendedPermissions(); - } else if (permission.getPropertyClass().equals(Maintenance.class)) { - Context.getMaintenancesManager().refreshExtendedPermissions(); - } else if (permission.getPropertyClass().equals(Notification.class) - && Context.getNotificationManager() != null) { - Context.getNotificationManager().refreshExtendedPermissions(); - } - } - } - - public Server getServer() { - return server; - } - - public void updateServer(Server server) throws SQLException { - dataManager.updateObject(server); - this.server = server; - } - - public User login(String email, String password) throws SQLException { - User user = dataManager.login(email, password); - if (user != null) { - checkUserEnabled(user.getId()); - return getUser(user.getId()); - } - return null; - } - - public Object lookupAttribute(long userId, String key, Object defaultValue) { - Object preference; - Object serverPreference = server.getAttributes().get(key); - Object userPreference = getUser(userId).getAttributes().get(key); - if (server.getForceSettings()) { - preference = serverPreference != null ? serverPreference : userPreference; - } else { - preference = userPreference != null ? userPreference : serverPreference; - } - return preference != null ? preference : defaultValue; - } - -} diff --git a/src/org/traccar/database/QueryBuilder.java b/src/org/traccar/database/QueryBuilder.java deleted file mode 100644 index 5528b2320..000000000 --- a/src/org/traccar/database/QueryBuilder.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright 2015 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. - * 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.database; - -import com.fasterxml.jackson.core.JsonProcessingException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.MiscFormatter; -import org.traccar.model.Permission; - -import javax.sql.DataSource; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Timestamp; -import java.sql.Types; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public final class QueryBuilder { - - private static final Logger LOGGER = LoggerFactory.getLogger(QueryBuilder.class); - - private final Map> indexMap = new HashMap<>(); - private Connection connection; - private PreparedStatement statement; - private final String query; - private final boolean returnGeneratedKeys; - - private QueryBuilder(DataSource dataSource, String query, boolean returnGeneratedKeys) throws SQLException { - this.query = query; - this.returnGeneratedKeys = returnGeneratedKeys; - if (query != null) { - connection = dataSource.getConnection(); - String parsedQuery = parse(query.trim(), indexMap); - try { - if (returnGeneratedKeys) { - statement = connection.prepareStatement(parsedQuery, Statement.RETURN_GENERATED_KEYS); - } else { - statement = connection.prepareStatement(parsedQuery); - } - } catch (SQLException error) { - connection.close(); - throw error; - } - } - } - - private static String parse(String query, Map> paramMap) { - - int length = query.length(); - StringBuilder parsedQuery = new StringBuilder(length); - boolean inSingleQuote = false; - boolean inDoubleQuote = false; - int index = 1; - - for (int i = 0; i < length; i++) { - - char c = query.charAt(i); - - // String end - if (inSingleQuote) { - if (c == '\'') { - inSingleQuote = false; - } - } else if (inDoubleQuote) { - if (c == '"') { - inDoubleQuote = false; - } - } else { - - // String begin - if (c == '\'') { - inSingleQuote = true; - } else if (c == '"') { - inDoubleQuote = true; - } else if (c == ':' && i + 1 < length - && Character.isJavaIdentifierStart(query.charAt(i + 1))) { - - // Identifier name - int j = i + 2; - while (j < length && Character.isJavaIdentifierPart(query.charAt(j))) { - j++; - } - - String name = query.substring(i + 1, j); - c = '?'; - i += name.length(); - name = name.toLowerCase(); - - // Add to list - List indexList = paramMap.get(name); - if (indexList == null) { - indexList = new LinkedList<>(); - paramMap.put(name, indexList); - } - indexList.add(index); - - index++; - } - } - - parsedQuery.append(c); - } - - return parsedQuery.toString(); - } - - public static QueryBuilder create(DataSource dataSource, String query) throws SQLException { - return new QueryBuilder(dataSource, query, false); - } - - public static QueryBuilder create( - DataSource dataSource, String query, boolean returnGeneratedKeys) throws SQLException { - return new QueryBuilder(dataSource, query, returnGeneratedKeys); - } - - private List indexes(String name) { - name = name.toLowerCase(); - List result = indexMap.get(name); - if (result == null) { - result = new LinkedList<>(); - } - return result; - } - - public QueryBuilder setBoolean(String name, boolean value) throws SQLException { - for (int i : indexes(name)) { - try { - statement.setBoolean(i, value); - } catch (SQLException error) { - statement.close(); - connection.close(); - throw error; - } - } - return this; - } - - public QueryBuilder setInteger(String name, int value) throws SQLException { - for (int i : indexes(name)) { - try { - statement.setInt(i, value); - } catch (SQLException error) { - statement.close(); - connection.close(); - throw error; - } - } - return this; - } - - public QueryBuilder setLong(String name, long value) throws SQLException { - return setLong(name, value, false); - } - - public QueryBuilder setLong(String name, long value, boolean nullIfZero) throws SQLException { - for (int i : indexes(name)) { - try { - if (value == 0 && nullIfZero) { - statement.setNull(i, Types.INTEGER); - } else { - statement.setLong(i, value); - } - } catch (SQLException error) { - statement.close(); - connection.close(); - throw error; - } - } - return this; - } - - public QueryBuilder setDouble(String name, double value) throws SQLException { - for (int i : indexes(name)) { - try { - statement.setDouble(i, value); - } catch (SQLException error) { - statement.close(); - connection.close(); - throw error; - } - } - return this; - } - - public QueryBuilder setString(String name, String value) throws SQLException { - for (int i : indexes(name)) { - try { - if (value == null) { - statement.setNull(i, Types.VARCHAR); - } else { - statement.setString(i, value); - } - } catch (SQLException error) { - statement.close(); - connection.close(); - throw error; - } - } - return this; - } - - public QueryBuilder setDate(String name, Date value) throws SQLException { - for (int i : indexes(name)) { - try { - if (value == null) { - statement.setNull(i, Types.TIMESTAMP); - } else { - statement.setTimestamp(i, new Timestamp(value.getTime())); - } - } catch (SQLException error) { - statement.close(); - connection.close(); - throw error; - } - } - return this; - } - - public QueryBuilder setBlob(String name, byte[] value) throws SQLException { - for (int i : indexes(name)) { - try { - if (value == null) { - statement.setNull(i, Types.BLOB); - } else { - statement.setBytes(i, value); - } - } catch (SQLException error) { - statement.close(); - connection.close(); - throw error; - } - } - return this; - } - - public QueryBuilder setObject(Object object) throws SQLException { - - Method[] methods = object.getClass().getMethods(); - - for (Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 - && !method.isAnnotationPresent(QueryIgnore.class)) { - String name = method.getName().substring(3); - try { - if (method.getReturnType().equals(boolean.class)) { - setBoolean(name, (Boolean) method.invoke(object)); - } else if (method.getReturnType().equals(int.class)) { - setInteger(name, (Integer) method.invoke(object)); - } else if (method.getReturnType().equals(long.class)) { - setLong(name, (Long) method.invoke(object), name.endsWith("Id")); - } else if (method.getReturnType().equals(double.class)) { - setDouble(name, (Double) method.invoke(object)); - } else if (method.getReturnType().equals(String.class)) { - setString(name, (String) method.invoke(object)); - } else if (method.getReturnType().equals(Date.class)) { - setDate(name, (Date) method.invoke(object)); - } else if (method.getReturnType().equals(byte[].class)) { - setBlob(name, (byte[]) method.invoke(object)); - } else { - if (method.getReturnType().equals(Map.class) - && Context.getConfig().getBoolean("database.xml")) { - setString(name, MiscFormatter.toXmlString((Map) method.invoke(object))); - } else { - setString(name, Context.getObjectMapper().writeValueAsString(method.invoke(object))); - } - } - } catch (IllegalAccessException | InvocationTargetException | JsonProcessingException error) { - LOGGER.warn("Get property error", error); - } - } - } - - return this; - } - - private interface ResultSetProcessor { - void process(T object, ResultSet resultSet) throws SQLException; - } - - public T executeQuerySingle(Class clazz) throws SQLException { - Collection result = executeQuery(clazz); - if (!result.isEmpty()) { - return result.iterator().next(); - } else { - return null; - } - } - - private void addProcessors( - List> processors, - final Class parameterType, final Method method, final String name) { - - if (parameterType.equals(boolean.class)) { - processors.add(new ResultSetProcessor() { - @Override - public void process(T object, ResultSet resultSet) throws SQLException { - try { - method.invoke(object, resultSet.getBoolean(name)); - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Set property error", error); - } - } - }); - } else if (parameterType.equals(int.class)) { - processors.add(new ResultSetProcessor() { - @Override - public void process(T object, ResultSet resultSet) throws SQLException { - try { - method.invoke(object, resultSet.getInt(name)); - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Set property error", error); - } - } - }); - } else if (parameterType.equals(long.class)) { - processors.add(new ResultSetProcessor() { - @Override - public void process(T object, ResultSet resultSet) throws SQLException { - try { - method.invoke(object, resultSet.getLong(name)); - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Set property error", error); - } - } - }); - } else if (parameterType.equals(double.class)) { - processors.add(new ResultSetProcessor() { - @Override - public void process(T object, ResultSet resultSet) throws SQLException { - try { - method.invoke(object, resultSet.getDouble(name)); - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Set property error", error); - } - } - }); - } else if (parameterType.equals(String.class)) { - processors.add(new ResultSetProcessor() { - @Override - public void process(T object, ResultSet resultSet) throws SQLException { - try { - method.invoke(object, resultSet.getString(name)); - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Set property error", error); - } - } - }); - } else if (parameterType.equals(Date.class)) { - processors.add(new ResultSetProcessor() { - @Override - public void process(T object, ResultSet resultSet) throws SQLException { - try { - Timestamp timestamp = resultSet.getTimestamp(name); - if (timestamp != null) { - method.invoke(object, new Date(timestamp.getTime())); - } - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Set property error", error); - } - } - }); - } else if (parameterType.equals(byte[].class)) { - processors.add(new ResultSetProcessor() { - @Override - public void process(T object, ResultSet resultSet) throws SQLException { - try { - method.invoke(object, resultSet.getBytes(name)); - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Set property error", error); - } - } - }); - } else { - processors.add(new ResultSetProcessor() { - @Override - public void process(T object, ResultSet resultSet) throws SQLException { - String value = resultSet.getString(name); - if (value != null && !value.isEmpty()) { - try { - method.invoke(object, Context.getObjectMapper().readValue(value, parameterType)); - } catch (InvocationTargetException | IllegalAccessException | IOException error) { - LOGGER.warn("Set property error", error); - } - } - } - }); - } - } - - public Collection executeQuery(Class clazz) throws SQLException { - List result = new LinkedList<>(); - - if (query != null) { - - try { - - try (ResultSet resultSet = statement.executeQuery()) { - - ResultSetMetaData resultMetaData = resultSet.getMetaData(); - - List> processors = new LinkedList<>(); - - Method[] methods = clazz.getMethods(); - - for (final Method method : methods) { - if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 - && !method.isAnnotationPresent(QueryIgnore.class)) { - - final String name = method.getName().substring(3); - - // Check if column exists - boolean column = false; - for (int i = 1; i <= resultMetaData.getColumnCount(); i++) { - if (name.equalsIgnoreCase(resultMetaData.getColumnLabel(i))) { - column = true; - break; - } - } - if (!column) { - continue; - } - - addProcessors(processors, method.getParameterTypes()[0], method, name); - } - } - - while (resultSet.next()) { - try { - T object = clazz.newInstance(); - for (ResultSetProcessor processor : processors) { - processor.process(object, resultSet); - } - result.add(object); - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalArgumentException(); - } - } - } - - } finally { - statement.close(); - connection.close(); - } - } - - return result; - } - - public long executeUpdate() throws SQLException { - - if (query != null) { - try { - statement.execute(); - if (returnGeneratedKeys) { - ResultSet resultSet = statement.getGeneratedKeys(); - if (resultSet.next()) { - return resultSet.getLong(1); - } - } - } finally { - statement.close(); - connection.close(); - } - } - return 0; - } - - public Collection executePermissionsQuery() throws SQLException, ClassNotFoundException { - List result = new LinkedList<>(); - if (query != null) { - try { - try (ResultSet resultSet = statement.executeQuery()) { - ResultSetMetaData resultMetaData = resultSet.getMetaData(); - while (resultSet.next()) { - LinkedHashMap map = new LinkedHashMap<>(); - for (int i = 1; i <= resultMetaData.getColumnCount(); i++) { - String label = resultMetaData.getColumnLabel(i); - map.put(label, resultSet.getLong(label)); - } - result.add(new Permission(map)); - } - } - } finally { - statement.close(); - connection.close(); - } - } - - return result; - } - -} diff --git a/src/org/traccar/database/QueryExtended.java b/src/org/traccar/database/QueryExtended.java deleted file mode 100644 index 07bc2c211..000000000 --- a/src/org/traccar/database/QueryExtended.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface QueryExtended { -} diff --git a/src/org/traccar/database/QueryIgnore.java b/src/org/traccar/database/QueryIgnore.java deleted file mode 100644 index ac835cf2f..000000000 --- a/src/org/traccar/database/QueryIgnore.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 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. - * 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.database; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface QueryIgnore { -} diff --git a/src/org/traccar/database/SimpleObjectManager.java b/src/org/traccar/database/SimpleObjectManager.java deleted file mode 100644 index 15dda4520..000000000 --- a/src/org/traccar/database/SimpleObjectManager.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.sql.SQLException; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.BaseModel; -import org.traccar.model.Permission; -import org.traccar.model.User; - -public abstract class SimpleObjectManager extends BaseObjectManager - implements ManagableObjects { - - private static final Logger LOGGER = LoggerFactory.getLogger(SimpleObjectManager.class); - - private Map> userItems; - - protected SimpleObjectManager(DataManager dataManager, Class baseClass) { - super(dataManager, baseClass); - } - - @Override - public final Set getUserItems(long userId) { - if (!userItems.containsKey(userId)) { - userItems.put(userId, new HashSet()); - } - return userItems.get(userId); - } - - @Override - public Set getManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getUserItems(userId)); - for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { - result.addAll(getUserItems(managedUserId)); - } - return result; - } - - public final boolean checkItemPermission(long userId, long itemId) { - return getUserItems(userId).contains(itemId); - } - - @Override - public void refreshItems() { - super.refreshItems(); - refreshUserItems(); - } - - public final void refreshUserItems() { - if (getDataManager() != null) { - try { - if (userItems != null) { - userItems.clear(); - } else { - userItems = new ConcurrentHashMap<>(); - } - for (Permission permission : getDataManager().getPermissions(User.class, getBaseClass())) { - getUserItems(permission.getOwnerId()).add(permission.getPropertyId()); - } - } catch (SQLException | ClassNotFoundException error) { - LOGGER.warn("Error getting permissions", error); - } - } - } - - @Override - public void removeItem(long itemId) throws SQLException { - super.removeItem(itemId); - refreshUserItems(); - } - -} diff --git a/src/org/traccar/database/StatisticsManager.java b/src/org/traccar/database/StatisticsManager.java deleted file mode 100644 index e59f8e767..000000000 --- a/src/org/traccar/database/StatisticsManager.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.database; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.helper.DateUtil; -import org.traccar.model.Statistics; - -import javax.inject.Inject; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.Form; -import java.sql.SQLException; -import java.util.Calendar; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -public class StatisticsManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsManager.class); - - private static final int SPLIT_MODE = Calendar.DAY_OF_MONTH; - - private final Config config; - private final DataManager dataManager; - private final Client client; - - private AtomicInteger lastUpdate = new AtomicInteger(Calendar.getInstance().get(SPLIT_MODE)); - - private Set users = new HashSet<>(); - private Set devices = new HashSet<>(); - - private int requests; - private int messagesReceived; - private int messagesStored; - private int mailSent; - private int smsSent; - private int geocoderRequests; - private int geolocationRequests; - - @Inject - public StatisticsManager(Config config, DataManager dataManager, Client client) { - this.config = config; - this.dataManager = dataManager; - this.client = client; - } - - private void checkSplit() { - int currentUpdate = Calendar.getInstance().get(SPLIT_MODE); - if (lastUpdate.getAndSet(currentUpdate) != currentUpdate) { - Statistics statistics = new Statistics(); - statistics.setCaptureTime(new Date()); - statistics.setActiveUsers(users.size()); - statistics.setActiveDevices(devices.size()); - statistics.setRequests(requests); - statistics.setMessagesReceived(messagesReceived); - statistics.setMessagesStored(messagesStored); - statistics.setMailSent(mailSent); - statistics.setSmsSent(smsSent); - statistics.setGeocoderRequests(geocoderRequests); - statistics.setGeolocationRequests(geolocationRequests); - - try { - dataManager.addObject(statistics); - } catch (SQLException e) { - LOGGER.warn("Error saving statistics", e); - } - - String url = config.getString(Keys.SERVER_STATISTICS); - if (url != null) { - String time = DateUtil.formatDate(statistics.getCaptureTime()); - - Form form = new Form(); - form.param("version", getClass().getPackage().getImplementationVersion()); - form.param("captureTime", time); - form.param("activeUsers", String.valueOf(statistics.getActiveUsers())); - form.param("activeDevices", String.valueOf(statistics.getActiveDevices())); - form.param("requests", String.valueOf(statistics.getRequests())); - form.param("messagesReceived", String.valueOf(statistics.getMessagesReceived())); - form.param("messagesStored", String.valueOf(statistics.getMessagesStored())); - form.param("mailSent", String.valueOf(statistics.getMailSent())); - form.param("smsSent", String.valueOf(statistics.getSmsSent())); - form.param("geocoderRequests", String.valueOf(statistics.getGeocoderRequests())); - form.param("geolocationRequests", String.valueOf(statistics.getGeolocationRequests())); - - client.target(url).request().async().post(Entity.form(form)); - } - - users.clear(); - devices.clear(); - requests = 0; - messagesReceived = 0; - messagesStored = 0; - mailSent = 0; - smsSent = 0; - geocoderRequests = 0; - geolocationRequests = 0; - } - } - - public synchronized void registerRequest(long userId) { - checkSplit(); - requests += 1; - if (userId != 0) { - users.add(userId); - } - } - - public synchronized void registerMessageReceived() { - checkSplit(); - messagesReceived += 1; - } - - public synchronized void registerMessageStored(long deviceId) { - checkSplit(); - messagesStored += 1; - if (deviceId != 0) { - devices.add(deviceId); - } - } - - public synchronized void registerMail() { - checkSplit(); - mailSent += 1; - } - - public synchronized void registerSms() { - checkSplit(); - smsSent += 1; - } - - public synchronized void registerGeocoderRequest() { - checkSplit(); - geocoderRequests += 1; - } - - public synchronized void registerGeolocationRequest() { - checkSplit(); - geolocationRequests += 1; - } - -} diff --git a/src/org/traccar/database/UsersManager.java b/src/org/traccar/database/UsersManager.java deleted file mode 100644 index 576a9e6c7..000000000 --- a/src/org/traccar/database/UsersManager.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.database; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.traccar.model.User; - -public class UsersManager extends SimpleObjectManager { - - private Map usersTokens; - - public UsersManager(DataManager dataManager) { - super(dataManager, User.class); - if (usersTokens == null) { - usersTokens = new ConcurrentHashMap<>(); - } - } - - private void putToken(User user) { - if (usersTokens == null) { - usersTokens = new ConcurrentHashMap<>(); - } - if (user.getToken() != null) { - usersTokens.put(user.getToken(), user); - } - } - - @Override - protected void addNewItem(User user) { - super.addNewItem(user); - putToken(user); - } - - @Override - protected void updateCachedItem(User user) { - User cachedUser = getById(user.getId()); - super.updateCachedItem(user); - putToken(user); - if (cachedUser.getToken() != null && !cachedUser.getToken().equals(user.getToken())) { - usersTokens.remove(cachedUser.getToken()); - } - } - - @Override - protected void removeCachedItem(long userId) { - User cachedUser = getById(userId); - if (cachedUser != null) { - String userToken = cachedUser.getToken(); - super.removeCachedItem(userId); - if (userToken != null) { - usersTokens.remove(userToken); - } - } - } - - @Override - public Set getManagedItems(long userId) { - Set result = new HashSet<>(); - result.addAll(getUserItems(userId)); - result.add(userId); - return result; - } - - public User getUserByToken(String token) { - return usersTokens.get(token); - } - -} diff --git a/src/org/traccar/geocoder/Address.java b/src/org/traccar/geocoder/Address.java deleted file mode 100644 index fe39da8e1..000000000 --- a/src/org/traccar/geocoder/Address.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2015 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. - * 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.geocoder; - -public class Address { - - private String postcode; - - public String getPostcode() { - return postcode; - } - - public void setPostcode(String postcode) { - this.postcode = postcode; - } - - private String country; - - public String getCountry() { - return country; - } - - public void setCountry(String country) { - this.country = country; - } - - private String state; - - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } - - private String district; - - public String getDistrict() { - return district; - } - - public void setDistrict(String district) { - this.district = district; - } - - private String settlement; - - public String getSettlement() { - return settlement; - } - - public void setSettlement(String settlement) { - this.settlement = settlement; - } - - private String suburb; - - public String getSuburb() { - return suburb; - } - - public void setSuburb(String suburb) { - this.suburb = suburb; - } - - private String street; - - public String getStreet() { - return street; - } - - public void setStreet(String street) { - this.street = street; - } - - private String house; - - public String getHouse() { - return house; - } - - public void setHouse(String house) { - this.house = house; - } - - private String formattedAddress; - - public String getFormattedAddress() { - return formattedAddress; - } - - public void setFormattedAddress(String formattedAddress) { - this.formattedAddress = formattedAddress; - } - -} diff --git a/src/org/traccar/geocoder/AddressFormat.java b/src/org/traccar/geocoder/AddressFormat.java deleted file mode 100644 index ad19432b9..000000000 --- a/src/org/traccar/geocoder/AddressFormat.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015 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. - * 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.geocoder; - -import java.text.FieldPosition; -import java.text.Format; -import java.text.ParsePosition; - -/** - * Available parameters: - * - * %p - postcode - * %c - country - * %s - state - * %d - district - * %t - settlement (town) - * %u - suburb - * %r - street (road) - * %h - house - * %f - formatted address - * - */ -public class AddressFormat extends Format { - - private final String format; - - public AddressFormat() { - this("%h %r, %t, %s, %c"); - } - - public AddressFormat(String format) { - this.format = format; - } - - private static String replace(String s, String key, String value) { - if (value != null) { - s = s.replace(key, value); - } else { - s = s.replaceAll("[, ]*" + key, ""); - } - return s; - } - - @Override - public StringBuffer format(Object o, StringBuffer stringBuffer, FieldPosition fieldPosition) { - Address address = (Address) o; - String result = format; - - result = replace(result, "%p", address.getPostcode()); - result = replace(result, "%c", address.getCountry()); - result = replace(result, "%s", address.getState()); - result = replace(result, "%d", address.getDistrict()); - result = replace(result, "%t", address.getSettlement()); - result = replace(result, "%u", address.getSuburb()); - result = replace(result, "%r", address.getStreet()); - result = replace(result, "%h", address.getHouse()); - result = replace(result, "%f", address.getFormattedAddress()); - - result = result.replaceAll("^[, ]*", ""); - - return stringBuffer.append(result); - } - - @Override - public Address parseObject(String s, ParsePosition parsePosition) { - throw new UnsupportedOperationException(); - } - -} diff --git a/src/org/traccar/geocoder/BanGeocoder.java b/src/org/traccar/geocoder/BanGeocoder.java deleted file mode 100644 index b1f0900a4..000000000 --- a/src/org/traccar/geocoder/BanGeocoder.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018 Olivier Girondel (olivier@biniou.info) - * Copyright 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. - * 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.geocoder; - -/* - * API documentation: https://adresse.data.gouv.fr/api - */ - -import javax.json.JsonArray; -import javax.json.JsonObject; - -public class BanGeocoder extends JsonGeocoder { - - public BanGeocoder(int cacheSize, AddressFormat addressFormat) { - super("https://api-adresse.data.gouv.fr/reverse/?lat=%f&lon=%f", cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonArray result = json.getJsonArray("features"); - - if (result != null && !result.isEmpty()) { - JsonObject location = result.getJsonObject(0).getJsonObject("properties"); - Address address = new Address(); - - address.setCountry("FR"); - if (location.containsKey("postcode")) { - address.setPostcode(location.getString("postcode")); - } - if (location.containsKey("context")) { - address.setDistrict(location.getString("context")); - } - if (location.containsKey("name")) { - address.setStreet(location.getString("name")); - } - if (location.containsKey("city")) { - address.setSettlement(location.getString("city")); - } - if (location.containsKey("housenumber")) { - address.setHouse(location.getString("housenumber")); - } - if (location.containsKey("label")) { - address.setFormattedAddress(location.getString("label")); - } - - return address; - } - - return null; - } - -} diff --git a/src/org/traccar/geocoder/BingMapsGeocoder.java b/src/org/traccar/geocoder/BingMapsGeocoder.java deleted file mode 100644 index 32a26ee0c..000000000 --- a/src/org/traccar/geocoder/BingMapsGeocoder.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) - * Copyright 2017 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. - * 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.geocoder; - -import javax.json.JsonArray; -import javax.json.JsonObject; - -public class BingMapsGeocoder extends JsonGeocoder { - - public BingMapsGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { - super(url + "/Locations/%f,%f?key=" + key + "&include=ciso2", cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonArray result = json.getJsonArray("resourceSets"); - if (result != null) { - JsonObject location = - result.getJsonObject(0).getJsonArray("resources").getJsonObject(0).getJsonObject("address"); - if (location != null) { - Address address = new Address(); - if (location.containsKey("addressLine")) { - address.setStreet(location.getString("addressLine")); - } - if (location.containsKey("locality")) { - address.setSettlement(location.getString("locality")); - } - if (location.containsKey("adminDistrict2")) { - address.setDistrict(location.getString("adminDistrict2")); - } - if (location.containsKey("adminDistrict")) { - address.setState(location.getString("adminDistrict")); - } - if (location.containsKey("countryRegionIso2")) { - address.setCountry(location.getString("countryRegionIso2").toUpperCase()); - } - if (location.containsKey("postalCode")) { - address.setPostcode(location.getString("postalCode")); - } - if (location.containsKey("formattedAddress")) { - address.setFormattedAddress(location.getString("formattedAddress")); - } - return address; - } - } - return null; - } - -} diff --git a/src/org/traccar/geocoder/FactualGeocoder.java b/src/org/traccar/geocoder/FactualGeocoder.java deleted file mode 100644 index c7a68c293..000000000 --- a/src/org/traccar/geocoder/FactualGeocoder.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) - * Copyright 2017 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. - * 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.geocoder; - -import javax.json.JsonObject; - -public class FactualGeocoder extends JsonGeocoder { - - public FactualGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { - super(url + "?latitude=%f&longitude=%f&KEY=" + key, cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonObject result = json.getJsonObject("response").getJsonObject("data"); - if (result != null) { - Address address = new Address(); - if (result.getJsonObject("street_number") != null) { - address.setHouse(result.getJsonObject("street_number").getString("name")); - } - if (result.getJsonObject("street_name") != null) { - address.setStreet(result.getJsonObject("street_name").getString("name")); - } - if (result.getJsonObject("locality") != null) { - address.setSettlement(result.getJsonObject("locality").getString("name")); - } - if (result.getJsonObject("county") != null) { - address.setDistrict(result.getJsonObject("county").getString("name")); - } - if (result.getJsonObject("region") != null) { - address.setState(result.getJsonObject("region").getString("name")); - } - if (result.getJsonObject("country") != null) { - address.setCountry(result.getJsonObject("country").getString("name")); - } - if (result.getJsonObject("postcode") != null) { - address.setPostcode(result.getJsonObject("postcode").getString("name")); - } - return address; - } - return null; - } - -} diff --git a/src/org/traccar/geocoder/GeocodeFarmGeocoder.java b/src/org/traccar/geocoder/GeocodeFarmGeocoder.java deleted file mode 100644 index 39a3300a0..000000000 --- a/src/org/traccar/geocoder/GeocodeFarmGeocoder.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.geocoder; - -import javax.json.JsonObject; - -public class GeocodeFarmGeocoder extends JsonGeocoder { - - private static String formatUrl(String key, String language) { - String url = "https://www.geocode.farm/v3/json/reverse/"; - url += "?lat=%f&lon=%f&country=us&count=1"; - if (key != null) { - url += "&key=" + key; - } - if (language != null) { - url += "&lang=" + language; - } - return url; - } - public GeocodeFarmGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) { - super(formatUrl(key, language), cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - Address address = new Address(); - - JsonObject result = json - .getJsonObject("geocoding_results") - .getJsonArray("RESULTS") - .getJsonObject(0); - - JsonObject resultAddress = result.getJsonObject("ADDRESS"); - - if (result.containsKey("formatted_address")) { - address.setFormattedAddress(result.getString("formatted_address")); - } - if (resultAddress.containsKey("street_number")) { - address.setStreet(resultAddress.getString("street_number")); - } - if (resultAddress.containsKey("street_name")) { - address.setStreet(resultAddress.getString("street_name")); - } - if (resultAddress.containsKey("locality")) { - address.setSettlement(resultAddress.getString("locality")); - } - if (resultAddress.containsKey("admin_1")) { - address.setState(resultAddress.getString("admin_1")); - } - if (resultAddress.containsKey("country")) { - address.setCountry(resultAddress.getString("country")); - } - - return address; - } - -} diff --git a/src/org/traccar/geocoder/GeocodeXyzGeocoder.java b/src/org/traccar/geocoder/GeocodeXyzGeocoder.java deleted file mode 100644 index aca360c3d..000000000 --- a/src/org/traccar/geocoder/GeocodeXyzGeocoder.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 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. - * 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.geocoder; - -import javax.json.JsonObject; - -public class GeocodeXyzGeocoder extends JsonGeocoder { - - private static String formatUrl(String key) { - String url = "https://geocode.xyz/%f,%f?geoit=JSON"; - if (key != null) { - url += "&key=" + key; - } - return url; - } - - public GeocodeXyzGeocoder(String key, int cacheSize, AddressFormat addressFormat) { - super(formatUrl(key), cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - Address address = new Address(); - - if (json.containsKey("stnumber")) { - address.setHouse(json.getString("stnumber")); - } - if (json.containsKey("staddress")) { - address.setStreet(json.getString("staddress")); - } - if (json.containsKey("city")) { - address.setSettlement(json.getString("city")); - } - if (json.containsKey("region")) { - address.setState(json.getString("region")); - } - if (json.containsKey("prov")) { - address.setCountry(json.getString("prov")); - } - if (json.containsKey("postal")) { - address.setPostcode(json.getString("postal")); - } - - return address; - } - -} diff --git a/src/org/traccar/geocoder/Geocoder.java b/src/org/traccar/geocoder/Geocoder.java deleted file mode 100644 index 587a27520..000000000 --- a/src/org/traccar/geocoder/Geocoder.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2012 - 2017 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. - * 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.geocoder; - -public interface Geocoder { - - interface ReverseGeocoderCallback { - - void onSuccess(String address); - - void onFailure(Throwable e); - - } - - String getAddress(double latitude, double longitude, ReverseGeocoderCallback callback); - -} diff --git a/src/org/traccar/geocoder/GeocoderException.java b/src/org/traccar/geocoder/GeocoderException.java deleted file mode 100644 index 608916641..000000000 --- a/src/org/traccar/geocoder/GeocoderException.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2016 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. - * 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.geocoder; - -public class GeocoderException extends RuntimeException { - - public GeocoderException(String message) { - super(message); - } - -} diff --git a/src/org/traccar/geocoder/GisgraphyGeocoder.java b/src/org/traccar/geocoder/GisgraphyGeocoder.java deleted file mode 100644 index 3a173f985..000000000 --- a/src/org/traccar/geocoder/GisgraphyGeocoder.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2017 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. - * 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.geocoder; - -import javax.json.JsonObject; - -public class GisgraphyGeocoder extends JsonGeocoder { - - public GisgraphyGeocoder(AddressFormat addressFormat) { - this("http://services.gisgraphy.com/reversegeocoding/search", 0, addressFormat); - } - - public GisgraphyGeocoder(String url, int cacheSize, AddressFormat addressFormat) { - super(url + "?format=json&lat=%f&lng=%f&from=1&to=1", cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - Address address = new Address(); - - JsonObject result = json.getJsonArray("result").getJsonObject(0); - - if (result.containsKey("streetName")) { - address.setStreet(result.getString("streetName")); - } - if (result.containsKey("city")) { - address.setSettlement(result.getString("city")); - } - if (result.containsKey("state")) { - address.setState(result.getString("state")); - } - if (result.containsKey("countryCode")) { - address.setCountry(result.getString("countryCode")); - } - if (result.containsKey("formatedFull")) { - address.setFormattedAddress(result.getString("formatedFull")); - } - - return address; - } - -} diff --git a/src/org/traccar/geocoder/GoogleGeocoder.java b/src/org/traccar/geocoder/GoogleGeocoder.java deleted file mode 100644 index 9494cab45..000000000 --- a/src/org/traccar/geocoder/GoogleGeocoder.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2012 - 2017 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. - * 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.geocoder; - -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.json.JsonString; - -public class GoogleGeocoder extends JsonGeocoder { - - private static String formatUrl(String key, String language) { - String url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f"; - if (key != null) { - url += "&key=" + key; - } - if (language != null) { - url += "&language=" + language; - } - return url; - } - - public GoogleGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) { - super(formatUrl(key, language), cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonArray results = json.getJsonArray("results"); - - if (!results.isEmpty()) { - Address address = new Address(); - - JsonObject result = (JsonObject) results.get(0); - JsonArray components = result.getJsonArray("address_components"); - - if (result.containsKey("formatted_address")) { - address.setFormattedAddress(result.getString("formatted_address")); - } - - for (JsonObject component : components.getValuesAs(JsonObject.class)) { - - String value = component.getString("short_name"); - - typesLoop: for (JsonString type : component.getJsonArray("types").getValuesAs(JsonString.class)) { - - switch (type.getString()) { - case "street_number": - address.setHouse(value); - break typesLoop; - case "route": - address.setStreet(value); - break typesLoop; - case "locality": - address.setSettlement(value); - break typesLoop; - case "administrative_area_level_2": - address.setDistrict(value); - break typesLoop; - case "administrative_area_level_1": - address.setState(value); - break typesLoop; - case "country": - address.setCountry(value); - break typesLoop; - case "postal_code": - address.setPostcode(value); - break typesLoop; - default: - break; - } - } - } - - return address; - } - - return null; - } - - @Override - protected String parseError(JsonObject json) { - return json.getString("error_message"); - } - -} diff --git a/src/org/traccar/geocoder/HereGeocoder.java b/src/org/traccar/geocoder/HereGeocoder.java deleted file mode 100644 index 756260b52..000000000 --- a/src/org/traccar/geocoder/HereGeocoder.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 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. - * 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.geocoder; - -import javax.json.JsonObject; - -public class HereGeocoder extends JsonGeocoder { - - private static String formatUrl(String id, String key, String language) { - String url = "https://reverse.geocoder.api.here.com/6.2/reversegeocode.json"; - url += "?mode=retrieveAddresses&maxresults=1"; - url += "&prox=%f,%f,0"; - url += "&app_id=" + id; - url += "&app_code=" + key; - if (language != null) { - url += "&language=" + language; - } - return url; - } - - public HereGeocoder(String id, String key, String language, int cacheSize, AddressFormat addressFormat) { - super(formatUrl(id, key, language), cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonObject result = json - .getJsonObject("Response") - .getJsonArray("View") - .getJsonObject(0) - .getJsonArray("Result") - .getJsonObject(0) - .getJsonObject("Location") - .getJsonObject("Address"); - - if (result != null) { - Address address = new Address(); - - if (json.containsKey("Label")) { - address.setFormattedAddress(json.getString("Label")); - } - - if (result.containsKey("HouseNumber")) { - address.setHouse(result.getString("HouseNumber")); - } - if (result.containsKey("Street")) { - address.setStreet(result.getString("Street")); - } - if (result.containsKey("City")) { - address.setSettlement(result.getString("City")); - } - if (result.containsKey("District")) { - address.setDistrict(result.getString("District")); - } - if (result.containsKey("State")) { - address.setState(result.getString("State")); - } - if (result.containsKey("Country")) { - address.setCountry(result.getString("Country").toUpperCase()); - } - if (result.containsKey("PostalCode")) { - address.setPostcode(result.getString("PostalCode")); - } - - return address; - } - - return null; - } - -} diff --git a/src/org/traccar/geocoder/JsonGeocoder.java b/src/org/traccar/geocoder/JsonGeocoder.java deleted file mode 100644 index ed59a1d8d..000000000 --- a/src/org/traccar/geocoder/JsonGeocoder.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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. - * 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.geocoder; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; - -import javax.json.JsonObject; -import javax.ws.rs.ClientErrorException; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.InvocationCallback; -import java.util.AbstractMap; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; - -public abstract class JsonGeocoder implements Geocoder { - - private static final Logger LOGGER = LoggerFactory.getLogger(JsonGeocoder.class); - - private final String url; - private final AddressFormat addressFormat; - - private Map, String> cache; - - public JsonGeocoder(String url, final int cacheSize, AddressFormat addressFormat) { - this.url = url; - this.addressFormat = addressFormat; - if (cacheSize > 0) { - this.cache = Collections.synchronizedMap(new LinkedHashMap, String>() { - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > cacheSize; - } - }); - } - } - - private String handleResponse( - double latitude, double longitude, JsonObject json, ReverseGeocoderCallback callback) { - - Address address = parseAddress(json); - if (address != null) { - String formattedAddress = addressFormat.format(address); - if (cache != null) { - cache.put(new AbstractMap.SimpleImmutableEntry<>(latitude, longitude), formattedAddress); - } - if (callback != null) { - callback.onSuccess(formattedAddress); - } - return formattedAddress; - } else { - String msg = "Empty address. Error: " + parseError(json); - if (callback != null) { - callback.onFailure(new GeocoderException(msg)); - } else { - LOGGER.warn(msg); - } - } - return null; - } - - @Override - public String getAddress( - final double latitude, final double longitude, final ReverseGeocoderCallback callback) { - - if (cache != null) { - String cachedAddress = cache.get(new AbstractMap.SimpleImmutableEntry<>(latitude, longitude)); - if (cachedAddress != null) { - if (callback != null) { - callback.onSuccess(cachedAddress); - } - return cachedAddress; - } - } - - Invocation.Builder request = Context.getClient().target(String.format(url, latitude, longitude)).request(); - - if (callback != null) { - request.async().get(new InvocationCallback() { - @Override - public void completed(JsonObject json) { - handleResponse(latitude, longitude, json, callback); - } - - @Override - public void failed(Throwable throwable) { - callback.onFailure(throwable); - } - }); - } else { - try { - return handleResponse(latitude, longitude, request.get(JsonObject.class), null); - } catch (ClientErrorException e) { - LOGGER.warn("Geocoder network error", e); - } - } - return null; - } - - public abstract Address parseAddress(JsonObject json); - - protected String parseError(JsonObject json) { - return null; - } - -} diff --git a/src/org/traccar/geocoder/MapQuestGeocoder.java b/src/org/traccar/geocoder/MapQuestGeocoder.java deleted file mode 100644 index 4029e3f07..000000000 --- a/src/org/traccar/geocoder/MapQuestGeocoder.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) - * Copyright 2017 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. - * 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.geocoder; - -import javax.json.JsonArray; -import javax.json.JsonObject; - -public class MapQuestGeocoder extends JsonGeocoder { - - public MapQuestGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { - super(url + "?key=" + key + "&location=%f,%f", cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonArray result = json.getJsonArray("results"); - if (result != null) { - JsonArray locations = result.getJsonObject(0).getJsonArray("locations"); - if (locations != null) { - JsonObject location = locations.getJsonObject(0); - - Address address = new Address(); - - if (location.containsKey("street")) { - address.setStreet(location.getString("street")); - } - if (location.containsKey("adminArea5")) { - address.setSettlement(location.getString("adminArea5")); - } - if (location.containsKey("adminArea4")) { - address.setDistrict(location.getString("adminArea4")); - } - if (location.containsKey("adminArea3")) { - address.setState(location.getString("adminArea3")); - } - if (location.containsKey("adminArea1")) { - address.setCountry(location.getString("adminArea1").toUpperCase()); - } - if (location.containsKey("postalCode")) { - address.setPostcode(location.getString("postalCode")); - } - - return address; - } - } - return null; - } - -} diff --git a/src/org/traccar/geocoder/MapmyIndiaGeocoder.java b/src/org/traccar/geocoder/MapmyIndiaGeocoder.java deleted file mode 100644 index 2b70708a1..000000000 --- a/src/org/traccar/geocoder/MapmyIndiaGeocoder.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 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. - * 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.geocoder; - -import javax.json.JsonArray; -import javax.json.JsonObject; - -public class MapmyIndiaGeocoder extends JsonGeocoder { - - public MapmyIndiaGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { - super(url + "/" + key + "/rev_geocode?lat=%f&lng=%f", cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonArray results = json.getJsonArray("results"); - - if (!results.isEmpty()) { - Address address = new Address(); - - JsonObject result = (JsonObject) results.get(0); - - if (result.containsKey("formatted_address")) { - address.setFormattedAddress(result.getString("formatted_address")); - } - - if (result.containsKey("house_number") && !result.getString("house_number").isEmpty()) { - address.setHouse(result.getString("house_number")); - } else if (result.containsKey("house_name") && !result.getString("house_name").isEmpty()) { - address.setHouse(result.getString("house_name")); - } - - if (result.containsKey("street")) { - address.setStreet(result.getString("street")); - } - - if (result.containsKey("locality") && !result.getString("locality").isEmpty()) { - address.setSuburb(result.getString("locality")); - } else if (result.containsKey("sublocality") && !result.getString("sublocality").isEmpty()) { - address.setSuburb(result.getString("sublocality")); - } else if (result.containsKey("subsublocality") && !result.getString("subsublocality").isEmpty()) { - address.setSuburb(result.getString("subsublocality")); - } - - if (result.containsKey("city") && !result.getString("city").isEmpty()) { - address.setSettlement(result.getString("city")); - } else if (result.containsKey("village") && !result.getString("village").isEmpty()) { - address.setSettlement(result.getString("village")); - } - - if (result.containsKey("district")) { - address.setDistrict(result.getString("district")); - } else if (result.containsKey("subDistrict")) { - address.setDistrict(result.getString("subDistrict")); - } - - if (result.containsKey("state")) { - address.setState(result.getString("state")); - } - - if (result.containsKey("pincode")) { - address.setPostcode(result.getString("pincode")); - } - - return address; - } - return null; - } -} diff --git a/src/org/traccar/geocoder/NominatimGeocoder.java b/src/org/traccar/geocoder/NominatimGeocoder.java deleted file mode 100644 index 8db25bf15..000000000 --- a/src/org/traccar/geocoder/NominatimGeocoder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2014 - 2017 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. - * 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.geocoder; - -import javax.json.JsonObject; - -public class NominatimGeocoder extends JsonGeocoder { - - private static String formatUrl(String url, String key, String language) { - if (url == null) { - url = "https://nominatim.openstreetmap.org/reverse"; - } - url += "?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1"; - if (key != null) { - url += "&key=" + key; - } - if (language != null) { - url += "&accept-language=" + language; - } - return url; - } - - public NominatimGeocoder(String url, String key, String language, int cacheSize, AddressFormat addressFormat) { - super(formatUrl(url, key, language), cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonObject result = json.getJsonObject("address"); - - if (result != null) { - Address address = new Address(); - - if (json.containsKey("display_name")) { - address.setFormattedAddress(json.getString("display_name")); - } - - if (result.containsKey("house_number")) { - address.setHouse(result.getString("house_number")); - } - if (result.containsKey("road")) { - address.setStreet(result.getString("road")); - } - if (result.containsKey("suburb")) { - address.setSuburb(result.getString("suburb")); - } - - if (result.containsKey("village")) { - address.setSettlement(result.getString("village")); - } else if (result.containsKey("town")) { - address.setSettlement(result.getString("town")); - } else if (result.containsKey("city")) { - address.setSettlement(result.getString("city")); - } - - if (result.containsKey("state_district")) { - address.setDistrict(result.getString("state_district")); - } else if (result.containsKey("region")) { - address.setDistrict(result.getString("region")); - } - - if (result.containsKey("state")) { - address.setState(result.getString("state")); - } - if (result.containsKey("country_code")) { - address.setCountry(result.getString("country_code").toUpperCase()); - } - if (result.containsKey("postcode")) { - address.setPostcode(result.getString("postcode")); - } - - return address; - } - - return null; - } - -} diff --git a/src/org/traccar/geocoder/OpenCageGeocoder.java b/src/org/traccar/geocoder/OpenCageGeocoder.java deleted file mode 100644 index 822b6e91e..000000000 --- a/src/org/traccar/geocoder/OpenCageGeocoder.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com) - * Copyright 2017 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. - * 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.geocoder; - -import javax.json.JsonArray; -import javax.json.JsonObject; - -public class OpenCageGeocoder extends JsonGeocoder { - - public OpenCageGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) { - super(url + "/json?q=%f,%f&no_annotations=1&key=" + key, cacheSize, addressFormat); - } - - @Override - public Address parseAddress(JsonObject json) { - JsonArray result = json.getJsonArray("results"); - if (result != null) { - JsonObject location = result.getJsonObject(0).getJsonObject("components"); - if (location != null) { - Address address = new Address(); - - if (result.getJsonObject(0).containsKey("formatted")) { - address.setFormattedAddress(result.getJsonObject(0).getString("formatted")); - } - if (location.containsKey("building")) { - address.setHouse(location.getString("building")); - } - if (location.containsKey("house_number")) { - address.setHouse(location.getString("house_number")); - } - if (location.containsKey("road")) { - address.setStreet(location.getString("road")); - } - if (location.containsKey("suburb")) { - address.setSuburb(location.getString("suburb")); - } - if (location.containsKey("city")) { - address.setSettlement(location.getString("city")); - } - if (location.containsKey("city_district")) { - address.setSettlement(location.getString("city_district")); - } - if (location.containsKey("county")) { - address.setDistrict(location.getString("county")); - } - if (location.containsKey("state")) { - address.setState(location.getString("state")); - } - if (location.containsKey("country_code")) { - address.setCountry(location.getString("country_code").toUpperCase()); - } - if (location.containsKey("postcode")) { - address.setPostcode(location.getString("postcode")); - } - - return address; - } - } - return null; - } - -} diff --git a/src/org/traccar/geofence/GeofenceCircle.java b/src/org/traccar/geofence/GeofenceCircle.java deleted file mode 100644 index f6fca63ca..000000000 --- a/src/org/traccar/geofence/GeofenceCircle.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2016 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. - * 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.geofence; - -import java.text.DecimalFormat; -import java.text.ParseException; - -import org.traccar.helper.DistanceCalculator; - -public class GeofenceCircle extends GeofenceGeometry { - - private double centerLatitude; - private double centerLongitude; - private double radius; - - public GeofenceCircle() { - } - - public GeofenceCircle(String wkt) throws ParseException { - fromWkt(wkt); - } - - public GeofenceCircle(double latitude, double longitude, double radius) { - this.centerLatitude = latitude; - this.centerLongitude = longitude; - this.radius = radius; - } - - public double distanceFromCenter(double latitude, double longitude) { - return DistanceCalculator.distance(centerLatitude, centerLongitude, latitude, longitude); - } - - @Override - public boolean containsPoint(double latitude, double longitude) { - return distanceFromCenter(latitude, longitude) <= radius; - } - - @Override - public String toWkt() { - String wkt = ""; - wkt = "CIRCLE ("; - wkt += String.valueOf(centerLatitude); - wkt += " "; - wkt += String.valueOf(centerLongitude); - wkt += ", "; - DecimalFormat format = new DecimalFormat("0.#"); - wkt += format.format(radius); - wkt += ")"; - return wkt; - } - - @Override - public void fromWkt(String wkt) throws ParseException { - if (!wkt.startsWith("CIRCLE")) { - throw new ParseException("Mismatch geometry type", 0); - } - String content = wkt.substring(wkt.indexOf("(") + 1, wkt.indexOf(")")); - if (content == null || content.equals("")) { - throw new ParseException("No content", 0); - } - String[] commaTokens = content.split(","); - if (commaTokens.length != 2) { - throw new ParseException("Not valid content", 0); - } - String[] tokens = commaTokens[0].split("\\s"); - if (tokens.length != 2) { - throw new ParseException("Too much or less coordinates", 0); - } - try { - centerLatitude = Double.parseDouble(tokens[0]); - } catch (NumberFormatException e) { - throw new ParseException(tokens[0] + " is not a double", 0); - } - try { - centerLongitude = Double.parseDouble(tokens[1]); - } catch (NumberFormatException e) { - throw new ParseException(tokens[1] + " is not a double", 0); - } - try { - radius = Double.parseDouble(commaTokens[1]); - } catch (NumberFormatException e) { - throw new ParseException(commaTokens[1] + " is not a double", 0); - } - } -} diff --git a/src/org/traccar/geofence/GeofenceGeometry.java b/src/org/traccar/geofence/GeofenceGeometry.java deleted file mode 100644 index 857ba3414..000000000 --- a/src/org/traccar/geofence/GeofenceGeometry.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2016 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. - * 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.geofence; - -import java.text.ParseException; - -public abstract class GeofenceGeometry { - - public abstract boolean containsPoint(double latitude, double longitude); - - public abstract String toWkt(); - - public abstract void fromWkt(String wkt) throws ParseException; - - public static class Coordinate { - - private double lat; - private double lon; - - public double getLat() { - return lat; - } - - public void setLat(double lat) { - this.lat = lat; - } - - public double getLon() { - return lon; - } - - public void setLon(double lon) { - this.lon = lon; - } - } - -} diff --git a/src/org/traccar/geofence/GeofencePolygon.java b/src/org/traccar/geofence/GeofencePolygon.java deleted file mode 100644 index 2048ba26d..000000000 --- a/src/org/traccar/geofence/GeofencePolygon.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2016 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. - * 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.geofence; - -import java.text.ParseException; -import java.util.ArrayList; - -public class GeofencePolygon extends GeofenceGeometry { - - public GeofencePolygon() { - } - - public GeofencePolygon(String wkt) throws ParseException { - fromWkt(wkt); - } - - private ArrayList coordinates; - - private double[] constant; - private double[] multiple; - - private boolean needNormalize = false; - - private void precalc() { - if (coordinates == null) { - return; - } - - int polyCorners = coordinates.size(); - int i; - int j = polyCorners - 1; - - if (constant != null) { - constant = null; - } - if (multiple != null) { - multiple = null; - } - - constant = new double[polyCorners]; - multiple = new double[polyCorners]; - - boolean hasNegative = false; - boolean hasPositive = false; - for (i = 0; i < polyCorners; i++) { - if (coordinates.get(i).getLon() > 90) { - hasPositive = true; - } else if (coordinates.get(i).getLon() < -90) { - hasNegative = true; - } - } - needNormalize = hasPositive && hasNegative; - - for (i = 0; i < polyCorners; j = i++) { - if (normalizeLon(coordinates.get(j).getLon()) == normalizeLon(coordinates.get(i).getLon())) { - constant[i] = coordinates.get(i).getLat(); - multiple[i] = 0; - } else { - constant[i] = coordinates.get(i).getLat() - - (normalizeLon(coordinates.get(i).getLon()) * coordinates.get(j).getLat()) - / (normalizeLon(coordinates.get(j).getLon()) - normalizeLon(coordinates.get(i).getLon())) - + (normalizeLon(coordinates.get(i).getLon()) * coordinates.get(i).getLat()) - / (normalizeLon(coordinates.get(j).getLon()) - normalizeLon(coordinates.get(i).getLon())); - multiple[i] = (coordinates.get(j).getLat() - coordinates.get(i).getLat()) - / (normalizeLon(coordinates.get(j).getLon()) - normalizeLon(coordinates.get(i).getLon())); - } - } - } - - private double normalizeLon(double lon) { - if (needNormalize && lon < -90) { - return lon + 360; - } - return lon; - } - - @Override - public boolean containsPoint(double latitude, double longitude) { - - int polyCorners = coordinates.size(); - int i; - int j = polyCorners - 1; - double longitudeNorm = normalizeLon(longitude); - boolean oddNodes = false; - - for (i = 0; i < polyCorners; j = i++) { - if (normalizeLon(coordinates.get(i).getLon()) < longitudeNorm - && normalizeLon(coordinates.get(j).getLon()) >= longitudeNorm - || normalizeLon(coordinates.get(j).getLon()) < longitudeNorm - && normalizeLon(coordinates.get(i).getLon()) >= longitudeNorm) { - oddNodes ^= longitudeNorm * multiple[i] + constant[i] < latitude; - } - } - return oddNodes; - } - - @Override - public String toWkt() { - StringBuilder buf = new StringBuilder(); - buf.append("POLYGON (("); - for (Coordinate coordinate : coordinates) { - buf.append(String.valueOf(coordinate.getLat())); - buf.append(" "); - buf.append(String.valueOf(coordinate.getLon())); - buf.append(", "); - } - return buf.substring(0, buf.length() - 2) + "))"; - } - - @Override - public void fromWkt(String wkt) throws ParseException { - if (coordinates == null) { - coordinates = new ArrayList<>(); - } else { - coordinates.clear(); - } - - if (!wkt.startsWith("POLYGON")) { - throw new ParseException("Mismatch geometry type", 0); - } - String content = wkt.substring(wkt.indexOf("((") + 2, wkt.indexOf("))")); - if (content.isEmpty()) { - throw new ParseException("No content", 0); - } - String[] commaTokens = content.split(","); - if (commaTokens.length < 3) { - throw new ParseException("Not valid content", 0); - } - - for (String commaToken : commaTokens) { - String[] tokens = commaToken.trim().split("\\s"); - if (tokens.length != 2) { - throw new ParseException("Here must be two coordinates: " + commaToken, 0); - } - Coordinate coordinate = new Coordinate(); - try { - coordinate.setLat(Double.parseDouble(tokens[0])); - } catch (NumberFormatException e) { - throw new ParseException(tokens[0] + " is not a double", 0); - } - try { - coordinate.setLon(Double.parseDouble(tokens[1])); - } catch (NumberFormatException e) { - throw new ParseException(tokens[1] + " is not a double", 0); - } - coordinates.add(coordinate); - } - precalc(); - } - -} diff --git a/src/org/traccar/geofence/GeofencePolyline.java b/src/org/traccar/geofence/GeofencePolyline.java deleted file mode 100644 index d84f512e3..000000000 --- a/src/org/traccar/geofence/GeofencePolyline.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.geofence; - -import java.text.ParseException; -import java.util.ArrayList; - -import org.traccar.helper.DistanceCalculator; - -public class GeofencePolyline extends GeofenceGeometry { - - private ArrayList coordinates; - private double distance; - - public GeofencePolyline() { - } - - public GeofencePolyline(String wkt, double distance) throws ParseException { - fromWkt(wkt); - this.distance = distance; - } - - @Override - public boolean containsPoint(double latitude, double longitude) { - for (int i = 1; i < coordinates.size(); i++) { - if (DistanceCalculator.distanceToLine( - latitude, longitude, coordinates.get(i - 1).getLat(), coordinates.get(i - 1).getLon(), - coordinates.get(i).getLat(), coordinates.get(i).getLon()) <= distance) { - return true; - } - } - return false; - } - - @Override - public String toWkt() { - StringBuilder buf = new StringBuilder(); - buf.append("LINESTRING ("); - for (Coordinate coordinate : coordinates) { - buf.append(String.valueOf(coordinate.getLat())); - buf.append(" "); - buf.append(String.valueOf(coordinate.getLon())); - buf.append(", "); - } - return buf.substring(0, buf.length() - 2) + ")"; - } - - @Override - public void fromWkt(String wkt) throws ParseException { - if (coordinates == null) { - coordinates = new ArrayList<>(); - } else { - coordinates.clear(); - } - - if (!wkt.startsWith("LINESTRING")) { - throw new ParseException("Mismatch geometry type", 0); - } - String content = wkt.substring(wkt.indexOf("(") + 1, wkt.indexOf(")")); - if (content.isEmpty()) { - throw new ParseException("No content", 0); - } - String[] commaTokens = content.split(","); - if (commaTokens.length < 2) { - throw new ParseException("Not valid content", 0); - } - - for (String commaToken : commaTokens) { - String[] tokens = commaToken.trim().split("\\s"); - if (tokens.length != 2) { - throw new ParseException("Here must be two coordinates: " + commaToken, 0); - } - Coordinate coordinate = new Coordinate(); - try { - coordinate.setLat(Double.parseDouble(tokens[0])); - } catch (NumberFormatException e) { - throw new ParseException(tokens[0] + " is not a double", 0); - } - try { - coordinate.setLon(Double.parseDouble(tokens[1])); - } catch (NumberFormatException e) { - throw new ParseException(tokens[1] + " is not a double", 0); - } - coordinates.add(coordinate); - } - - } - - public void setDistance(double distance) { - this.distance = distance; - } - -} diff --git a/src/org/traccar/geolocation/GeolocationException.java b/src/org/traccar/geolocation/GeolocationException.java deleted file mode 100644 index 5847cc807..000000000 --- a/src/org/traccar/geolocation/GeolocationException.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2016 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. - * 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.geolocation; - -public class GeolocationException extends RuntimeException { - - public GeolocationException(String message) { - super(message); - } - -} diff --git a/src/org/traccar/geolocation/GeolocationProvider.java b/src/org/traccar/geolocation/GeolocationProvider.java deleted file mode 100644 index d9dec6bbb..000000000 --- a/src/org/traccar/geolocation/GeolocationProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.geolocation; - -import org.traccar.model.Network; - -public interface GeolocationProvider { - - interface LocationProviderCallback { - - void onSuccess(double latitude, double longitude, double accuracy); - - void onFailure(Throwable e); - - } - - void getLocation(Network network, LocationProviderCallback callback); - -} diff --git a/src/org/traccar/geolocation/GoogleGeolocationProvider.java b/src/org/traccar/geolocation/GoogleGeolocationProvider.java deleted file mode 100644 index 5901b47cd..000000000 --- a/src/org/traccar/geolocation/GoogleGeolocationProvider.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2016 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. - * 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.geolocation; - -public class GoogleGeolocationProvider extends UniversalGeolocationProvider { - - private static final String URL = "https://www.googleapis.com/geolocation/v1/geolocate"; - - public GoogleGeolocationProvider(String key) { - super(URL, key); - } - -} diff --git a/src/org/traccar/geolocation/MozillaGeolocationProvider.java b/src/org/traccar/geolocation/MozillaGeolocationProvider.java deleted file mode 100644 index c6a73a52b..000000000 --- a/src/org/traccar/geolocation/MozillaGeolocationProvider.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.geolocation; - -public class MozillaGeolocationProvider extends UniversalGeolocationProvider { - - private static final String URL = "https://location.services.mozilla.com/v1/geolocate"; - - public MozillaGeolocationProvider(String key) { - super(URL, key != null ? key : "test"); - } - -} diff --git a/src/org/traccar/geolocation/OpenCellIdGeolocationProvider.java b/src/org/traccar/geolocation/OpenCellIdGeolocationProvider.java deleted file mode 100644 index 768aaf6a2..000000000 --- a/src/org/traccar/geolocation/OpenCellIdGeolocationProvider.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - * 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.geolocation; - -import org.traccar.Context; -import org.traccar.model.CellTower; -import org.traccar.model.Network; - -import javax.json.JsonObject; -import javax.ws.rs.client.InvocationCallback; - -public class OpenCellIdGeolocationProvider implements GeolocationProvider { - - private String url; - - public OpenCellIdGeolocationProvider(String key) { - this("http://opencellid.org/cell/get", key); - } - - public OpenCellIdGeolocationProvider(String url, String key) { - this.url = url + "?format=json&mcc=%d&mnc=%d&lac=%d&cellid=%d&key=" + key; - } - - @Override - public void getLocation(Network network, final LocationProviderCallback callback) { - if (network.getCellTowers() != null && !network.getCellTowers().isEmpty()) { - - CellTower cellTower = network.getCellTowers().iterator().next(); - String request = String.format(url, cellTower.getMobileCountryCode(), cellTower.getMobileNetworkCode(), - cellTower.getLocationAreaCode(), cellTower.getCellId()); - - Context.getClient().target(request).request().async().get(new InvocationCallback() { - @Override - public void completed(JsonObject json) { - if (json.containsKey("lat") && json.containsKey("lon")) { - callback.onSuccess( - json.getJsonNumber("lat").doubleValue(), - json.getJsonNumber("lon").doubleValue(), 0); - } else { - callback.onFailure(new GeolocationException("Coordinates are missing")); - } - } - - @Override - public void failed(Throwable throwable) { - callback.onFailure(throwable); - } - }); - - } else { - callback.onFailure(new GeolocationException("No network information")); - } - } - -} diff --git a/src/org/traccar/geolocation/UniversalGeolocationProvider.java b/src/org/traccar/geolocation/UniversalGeolocationProvider.java deleted file mode 100644 index f71620d8a..000000000 --- a/src/org/traccar/geolocation/UniversalGeolocationProvider.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.geolocation; - -import org.traccar.Context; -import org.traccar.model.Network; - -import javax.json.JsonObject; -import javax.ws.rs.client.AsyncInvoker; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.InvocationCallback; - -public class UniversalGeolocationProvider implements GeolocationProvider { - - private String url; - - public UniversalGeolocationProvider(String url, String key) { - this.url = url + "?key=" + key; - } - - @Override - public void getLocation(Network network, final LocationProviderCallback callback) { - AsyncInvoker invoker = Context.getClient().target(url).request().async(); - invoker.post(Entity.json(network), new InvocationCallback() { - @Override - public void completed(JsonObject json) { - if (json.containsKey("error")) { - callback.onFailure(new GeolocationException(json.getJsonObject("error").getString("message"))); - } else { - JsonObject location = json.getJsonObject("location"); - callback.onSuccess( - location.getJsonNumber("lat").doubleValue(), - location.getJsonNumber("lng").doubleValue(), - json.getJsonNumber("accuracy").doubleValue()); - } - } - - @Override - public void failed(Throwable throwable) { - callback.onFailure(throwable); - } - }); - } - -} diff --git a/src/org/traccar/geolocation/UnwiredGeolocationProvider.java b/src/org/traccar/geolocation/UnwiredGeolocationProvider.java deleted file mode 100644 index 963bcb688..000000000 --- a/src/org/traccar/geolocation/UnwiredGeolocationProvider.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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.geolocation; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.traccar.Context; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.WifiAccessPoint; - -import javax.json.JsonObject; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.InvocationCallback; -import java.util.Collection; - -public class UnwiredGeolocationProvider implements GeolocationProvider { - - private String url; - private String key; - - private ObjectMapper objectMapper; - - private abstract static class NetworkMixIn { - @JsonProperty("mcc") - abstract Integer getHomeMobileCountryCode(); - @JsonProperty("mnc") - abstract Integer getHomeMobileNetworkCode(); - @JsonProperty("radio") - abstract String getRadioType(); - @JsonIgnore - abstract String getCarrier(); - @JsonIgnore - abstract Boolean getConsiderIp(); - @JsonProperty("cells") - abstract Collection getCellTowers(); - @JsonProperty("wifi") - abstract Collection getWifiAccessPoints(); - } - - private abstract static class CellTowerMixIn { - @JsonProperty("radio") - abstract String getRadioType(); - @JsonProperty("mcc") - abstract Integer getMobileCountryCode(); - @JsonProperty("mnc") - abstract Integer getMobileNetworkCode(); - @JsonProperty("lac") - abstract Integer getLocationAreaCode(); - @JsonProperty("cid") - abstract Long getCellId(); - } - - private abstract static class WifiAccessPointMixIn { - @JsonProperty("bssid") - abstract String getMacAddress(); - @JsonProperty("signal") - abstract Integer getSignalStrength(); - } - - public UnwiredGeolocationProvider(String url, String key) { - this.url = url; - this.key = key; - - objectMapper = new ObjectMapper(); - objectMapper.addMixIn(Network.class, NetworkMixIn.class); - objectMapper.addMixIn(CellTower.class, CellTowerMixIn.class); - objectMapper.addMixIn(WifiAccessPoint.class, WifiAccessPointMixIn.class); - } - - @Override - public void getLocation(Network network, final LocationProviderCallback callback) { - ObjectNode json = objectMapper.valueToTree(network); - json.put("token", key); - - Context.getClient().target(url).request().async().post(Entity.json(json), new InvocationCallback() { - @Override - public void completed(JsonObject json) { - if (json.getString("status").equals("error")) { - callback.onFailure(new GeolocationException(json.getString("message"))); - } else { - callback.onSuccess( - json.getJsonNumber("lat").doubleValue(), - json.getJsonNumber("lon").doubleValue(), - json.getJsonNumber("accuracy").doubleValue()); - } - } - - @Override - public void failed(Throwable throwable) { - callback.onFailure(throwable); - } - }); - } - -} diff --git a/src/org/traccar/handler/ComputedAttributesHandler.java b/src/org/traccar/handler/ComputedAttributesHandler.java deleted file mode 100644 index 153da29b9..000000000 --- a/src/org/traccar/handler/ComputedAttributesHandler.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import io.netty.channel.ChannelHandler; -import org.apache.commons.jexl2.JexlEngine; -import org.apache.commons.jexl2.JexlException; -import org.apache.commons.jexl2.MapContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseDataHandler; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.AttributesManager; -import org.traccar.database.IdentityManager; -import org.traccar.model.Attribute; -import org.traccar.model.Device; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class ComputedAttributesHandler extends BaseDataHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(ComputedAttributesHandler.class); - - private final IdentityManager identityManager; - private final AttributesManager attributesManager; - - private final JexlEngine engine; - - private final boolean includeDeviceAttributes; - - public ComputedAttributesHandler( - Config config, IdentityManager identityManager, AttributesManager attributesManager) { - this.identityManager = identityManager; - this.attributesManager = attributesManager; - engine = new JexlEngine(); - engine.setStrict(true); - engine.setFunctions(Collections.singletonMap("math", Math.class)); - includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES); - } - - private MapContext prepareContext(Position position) { - MapContext result = new MapContext(); - if (includeDeviceAttributes) { - Device device = identityManager.getById(position.getDeviceId()); - if (device != null) { - for (Object key : device.getAttributes().keySet()) { - result.set((String) key, device.getAttributes().get(key)); - } - } - } - Set methods = new HashSet<>(Arrays.asList(position.getClass().getMethods())); - methods.removeAll(Arrays.asList(Object.class.getMethods())); - for (Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { - String name = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4); - - try { - if (!method.getReturnType().equals(Map.class)) { - result.set(name, method.invoke(position)); - } else { - for (Object key : ((Map) method.invoke(position)).keySet()) { - result.set((String) key, ((Map) method.invoke(position)).get(key)); - } - } - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Attribute reflection error", error); - } - } - } - return result; - } - - /** - * @deprecated logic needs to be extracted to be used in API resource - */ - @Deprecated - public Object computeAttribute(Attribute attribute, Position position) throws JexlException { - return engine.createExpression(attribute.getExpression()).evaluate(prepareContext(position)); - } - - @Override - protected Position handlePosition(Position position) { - Collection attributes = attributesManager.getItems( - attributesManager.getAllDeviceItems(position.getDeviceId())); - for (Attribute attribute : attributes) { - if (attribute.getAttribute() != null) { - Object result = null; - try { - result = computeAttribute(attribute, position); - } catch (JexlException error) { - LOGGER.warn("Attribute computation error", error); - } - if (result != null) { - try { - switch (attribute.getType()) { - case "number": - Number numberValue = (Number) result; - position.getAttributes().put(attribute.getAttribute(), numberValue); - break; - case "boolean": - Boolean booleanValue = (Boolean) result; - position.getAttributes().put(attribute.getAttribute(), booleanValue); - break; - default: - position.getAttributes().put(attribute.getAttribute(), result.toString()); - } - } catch (ClassCastException error) { - LOGGER.warn("Attribute cast error", error); - } - } - } - } - return position; - } - -} diff --git a/src/org/traccar/handler/CopyAttributesHandler.java b/src/org/traccar/handler/CopyAttributesHandler.java deleted file mode 100644 index 6a0966d33..000000000 --- a/src/org/traccar/handler/CopyAttributesHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler; - -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; -import org.traccar.database.IdentityManager; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class CopyAttributesHandler extends BaseDataHandler { - - private IdentityManager identityManager; - - public CopyAttributesHandler(IdentityManager identityManager) { - this.identityManager = identityManager; - } - - @Override - protected Position handlePosition(Position position) { - String attributesString = identityManager.lookupAttributeString( - position.getDeviceId(), "processing.copyAttributes", "", true); - if (attributesString.isEmpty()) { - attributesString = Position.KEY_DRIVER_UNIQUE_ID; - } else { - attributesString += "," + Position.KEY_DRIVER_UNIQUE_ID; - } - Position last = identityManager.getLastPosition(position.getDeviceId()); - if (last != null) { - for (String attribute : attributesString.split("[ ,]")) { - if (last.getAttributes().containsKey(attribute) && !position.getAttributes().containsKey(attribute)) { - position.getAttributes().put(attribute, last.getAttributes().get(attribute)); - } - } - } - return position; - } - -} diff --git a/src/org/traccar/handler/DefaultDataHandler.java b/src/org/traccar/handler/DefaultDataHandler.java deleted file mode 100644 index 9d8ea044d..000000000 --- a/src/org/traccar/handler/DefaultDataHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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.handler; - -import io.netty.channel.ChannelHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseDataHandler; -import org.traccar.database.DataManager; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class DefaultDataHandler extends BaseDataHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDataHandler.class); - - private final DataManager dataManager; - - public DefaultDataHandler(DataManager dataManager) { - this.dataManager = dataManager; - } - - @Override - protected Position handlePosition(Position position) { - - try { - dataManager.addObject(position); - } catch (Exception error) { - LOGGER.warn("Failed to store position", error); - } - - return position; - } - -} diff --git a/src/org/traccar/handler/DistanceHandler.java b/src/org/traccar/handler/DistanceHandler.java deleted file mode 100644 index a336a884e..000000000 --- a/src/org/traccar/handler/DistanceHandler.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015 Amila Silva - * Copyright 2016 - 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. - * 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.handler; - -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.IdentityManager; -import org.traccar.helper.DistanceCalculator; -import org.traccar.model.Position; - -import java.math.BigDecimal; -import java.math.RoundingMode; - -@ChannelHandler.Sharable -public class DistanceHandler extends BaseDataHandler { - - private final IdentityManager identityManager; - - private final boolean filter; - private final int coordinatesMinError; - private final int coordinatesMaxError; - - public DistanceHandler(Config config, IdentityManager identityManager) { - this.identityManager = identityManager; - this.filter = config.getBoolean(Keys.COORDINATES_FILTER); - this.coordinatesMinError = config.getInteger(Keys.COORDINATES_MIN_ERROR); - this.coordinatesMaxError = config.getInteger(Keys.COORDINATES_MAX_ERROR); - } - - @Override - protected Position handlePosition(Position position) { - - double distance = 0.0; - if (position.getAttributes().containsKey(Position.KEY_DISTANCE)) { - distance = position.getDouble(Position.KEY_DISTANCE); - } - double totalDistance = 0.0; - - Position last = identityManager != null ? identityManager.getLastPosition(position.getDeviceId()) : null; - if (last != null) { - totalDistance = last.getDouble(Position.KEY_TOTAL_DISTANCE); - if (!position.getAttributes().containsKey(Position.KEY_DISTANCE)) { - distance = DistanceCalculator.distance( - position.getLatitude(), position.getLongitude(), - last.getLatitude(), last.getLongitude()); - distance = BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); - } - if (filter && last.getValid() && last.getLatitude() != 0 && last.getLongitude() != 0) { - boolean satisfiesMin = coordinatesMinError == 0 || distance > coordinatesMinError; - boolean satisfiesMax = coordinatesMaxError == 0 - || distance < coordinatesMaxError || position.getValid(); - if (!satisfiesMin || !satisfiesMax) { - position.setLatitude(last.getLatitude()); - position.setLongitude(last.getLongitude()); - distance = 0; - } - } - } - position.set(Position.KEY_DISTANCE, distance); - totalDistance = BigDecimal.valueOf(totalDistance + distance).setScale(2, RoundingMode.HALF_EVEN).doubleValue(); - position.set(Position.KEY_TOTAL_DISTANCE, totalDistance); - - return position; - } - -} diff --git a/src/org/traccar/handler/EngineHoursHandler.java b/src/org/traccar/handler/EngineHoursHandler.java deleted file mode 100644 index 92da84e6b..000000000 --- a/src/org/traccar/handler/EngineHoursHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler; - -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; -import org.traccar.database.IdentityManager; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class EngineHoursHandler extends BaseDataHandler { - - private final IdentityManager identityManager; - - public EngineHoursHandler(IdentityManager identityManager) { - this.identityManager = identityManager; - } - - @Override - protected Position handlePosition(Position position) { - if (!position.getAttributes().containsKey(Position.KEY_HOURS)) { - Position last = identityManager.getLastPosition(position.getDeviceId()); - if (last != null) { - long hours = last.getLong(Position.KEY_HOURS); - if (last.getBoolean(Position.KEY_IGNITION) && position.getBoolean(Position.KEY_IGNITION)) { - hours += position.getFixTime().getTime() - last.getFixTime().getTime(); - } - if (hours != 0) { - position.set(Position.KEY_HOURS, hours); - } - } - } - return position; - } - -} diff --git a/src/org/traccar/handler/FilterHandler.java b/src/org/traccar/handler/FilterHandler.java deleted file mode 100644 index dceaede01..000000000 --- a/src/org/traccar/handler/FilterHandler.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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.handler; - -import io.netty.channel.ChannelHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseDataHandler; -import org.traccar.Context; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class FilterHandler extends BaseDataHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(FilterHandler.class); - - private boolean filterInvalid; - private boolean filterZero; - private boolean filterDuplicate; - private long filterFuture; - private boolean filterApproximate; - private int filterAccuracy; - private boolean filterStatic; - private int filterDistance; - private int filterMaxSpeed; - private long filterMinPeriod; - private long skipLimit; - private boolean skipAttributes; - - public FilterHandler(Config config) { - filterInvalid = config.getBoolean(Keys.FILTER_INVALID); - filterZero = config.getBoolean(Keys.FILTER_ZERO); - filterDuplicate = config.getBoolean(Keys.FILTER_DUPLICATE); - filterFuture = config.getLong(Keys.FILTER_FUTURE) * 1000; - filterAccuracy = config.getInteger(Keys.FILTER_ACCURACY); - filterApproximate = config.getBoolean(Keys.FILTER_APPROXIMATE); - filterStatic = config.getBoolean(Keys.FILTER_STATIC); - filterDistance = config.getInteger(Keys.FILTER_DISTANCE); - filterMaxSpeed = config.getInteger(Keys.FILTER_MAX_SPEED); - filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000; - skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000; - skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE); - } - - private boolean filterInvalid(Position position) { - return filterInvalid && (!position.getValid() - || position.getLatitude() > 90 || position.getLongitude() > 180 - || position.getLatitude() < -90 || position.getLongitude() < -180); - } - - private boolean filterZero(Position position) { - return filterZero && position.getLatitude() == 0.0 && position.getLongitude() == 0.0; - } - - private boolean filterDuplicate(Position position, Position last) { - if (filterDuplicate && last != null && position.getFixTime().equals(last.getFixTime())) { - for (String key : position.getAttributes().keySet()) { - if (!last.getAttributes().containsKey(key)) { - return false; - } - } - return true; - } - return false; - } - - private boolean filterFuture(Position position) { - return filterFuture != 0 && position.getFixTime().getTime() > System.currentTimeMillis() + filterFuture; - } - - private boolean filterAccuracy(Position position) { - return filterAccuracy != 0 && position.getAccuracy() > filterAccuracy; - } - - private boolean filterApproximate(Position position) { - return filterApproximate && position.getBoolean(Position.KEY_APPROXIMATE); - } - - private boolean filterStatic(Position position) { - return filterStatic && position.getSpeed() == 0.0; - } - - private boolean filterDistance(Position position, Position last) { - if (filterDistance != 0 && last != null) { - return position.getDouble(Position.KEY_DISTANCE) < filterDistance; - } - return false; - } - - private boolean filterMaxSpeed(Position position, Position last) { - if (filterMaxSpeed != 0 && last != null) { - double distance = position.getDouble(Position.KEY_DISTANCE); - double time = position.getFixTime().getTime() - last.getFixTime().getTime(); - return UnitsConverter.knotsFromMps(distance / (time / 1000)) > filterMaxSpeed; - } - return false; - } - - private boolean filterMinPeriod(Position position, Position last) { - if (filterMinPeriod != 0 && last != null) { - long time = position.getFixTime().getTime() - last.getFixTime().getTime(); - return time > 0 && time < filterMinPeriod; - } - return false; - } - - private boolean skipLimit(Position position, Position last) { - if (skipLimit != 0 && last != null) { - return (position.getServerTime().getTime() - last.getServerTime().getTime()) > skipLimit; - } - return false; - } - - private boolean skipAttributes(Position position) { - if (skipAttributes) { - String attributesString = Context.getIdentityManager().lookupAttributeString( - position.getDeviceId(), "filter.skipAttributes", "", true); - for (String attribute : attributesString.split("[ ,]")) { - if (position.getAttributes().containsKey(attribute)) { - return true; - } - } - } - return false; - } - - private boolean filter(Position position) { - - StringBuilder filterType = new StringBuilder(); - - Position last = null; - if (Context.getIdentityManager() != null) { - last = Context.getIdentityManager().getLastPosition(position.getDeviceId()); - } - - if (filterInvalid(position)) { - filterType.append("Invalid "); - } - if (filterZero(position)) { - filterType.append("Zero "); - } - if (filterDuplicate(position, last) && !skipLimit(position, last) && !skipAttributes(position)) { - filterType.append("Duplicate "); - } - if (filterFuture(position)) { - filterType.append("Future "); - } - if (filterAccuracy(position)) { - filterType.append("Accuracy "); - } - if (filterApproximate(position)) { - filterType.append("Approximate "); - } - if (filterStatic(position) && !skipLimit(position, last) && !skipAttributes(position)) { - filterType.append("Static "); - } - if (filterDistance(position, last) && !skipLimit(position, last) && !skipAttributes(position)) { - filterType.append("Distance "); - } - if (filterMaxSpeed(position, last)) { - filterType.append("MaxSpeed "); - } - if (filterMinPeriod(position, last)) { - filterType.append("MinPeriod "); - } - - if (filterType.length() > 0) { - - StringBuilder message = new StringBuilder(); - message.append("Position filtered by "); - message.append(filterType.toString()); - message.append("filters from device: "); - message.append(Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId()); - - LOGGER.info(message.toString()); - return true; - } - - return false; - } - - @Override - protected Position handlePosition(Position position) { - if (filter(position)) { - return null; - } - return position; - } - -} diff --git a/src/org/traccar/handler/GeocoderHandler.java b/src/org/traccar/handler/GeocoderHandler.java deleted file mode 100644 index b96f01b3a..000000000 --- a/src/org/traccar/handler/GeocoderHandler.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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.handler; - -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.IdentityManager; -import org.traccar.database.StatisticsManager; -import org.traccar.geocoder.Geocoder; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class GeocoderHandler extends ChannelInboundHandlerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(GeocoderHandler.class); - - private final Geocoder geocoder; - private final IdentityManager identityManager; - private final StatisticsManager statisticsManager; - private final boolean ignorePositions; - private final boolean processInvalidPositions; - private final int geocoderReuseDistance; - - public GeocoderHandler( - Config config, Geocoder geocoder, IdentityManager identityManager, StatisticsManager statisticsManager) { - this.geocoder = geocoder; - this.identityManager = identityManager; - this.statisticsManager = statisticsManager; - ignorePositions = Context.getConfig().getBoolean(Keys.GEOCODER_IGNORE_POSITIONS); - processInvalidPositions = config.getBoolean(Keys.GEOCODER_PROCESS_INVALID_POSITIONS); - geocoderReuseDistance = config.getInteger(Keys.GEOCODER_REUSE_DISTANCE, 0); - } - - @Override - public void channelRead(final ChannelHandlerContext ctx, Object message) { - if (message instanceof Position && !ignorePositions) { - final Position position = (Position) message; - if (processInvalidPositions || position.getValid()) { - if (geocoderReuseDistance != 0) { - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); - if (lastPosition != null && lastPosition.getAddress() != null - && position.getDouble(Position.KEY_DISTANCE) <= geocoderReuseDistance) { - position.setAddress(lastPosition.getAddress()); - ctx.fireChannelRead(position); - return; - } - } - - if (statisticsManager != null) { - statisticsManager.registerGeocoderRequest(); - } - - geocoder.getAddress(position.getLatitude(), position.getLongitude(), - new Geocoder.ReverseGeocoderCallback() { - @Override - public void onSuccess(String address) { - position.setAddress(address); - ctx.fireChannelRead(position); - } - - @Override - public void onFailure(Throwable e) { - LOGGER.warn("Geocoding failed", e); - ctx.fireChannelRead(position); - } - }); - } else { - ctx.fireChannelRead(position); - } - } else { - ctx.fireChannelRead(message); - } - } - -} diff --git a/src/org/traccar/handler/GeolocationHandler.java b/src/org/traccar/handler/GeolocationHandler.java deleted file mode 100644 index c7b39e491..000000000 --- a/src/org/traccar/handler/GeolocationHandler.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - * 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.handler; - -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.StatisticsManager; -import org.traccar.geolocation.GeolocationProvider; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class GeolocationHandler extends ChannelInboundHandlerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(GeolocationHandler.class); - - private final GeolocationProvider geolocationProvider; - private final StatisticsManager statisticsManager; - private final boolean processInvalidPositions; - - public GeolocationHandler( - Config config, GeolocationProvider geolocationProvider, StatisticsManager statisticsManager) { - this.geolocationProvider = geolocationProvider; - this.statisticsManager = statisticsManager; - this.processInvalidPositions = config.getBoolean(Keys.GEOLOCATION_PROCESS_INVALID_POSITIONS); - } - - @Override - public void channelRead(final ChannelHandlerContext ctx, Object message) { - if (message instanceof Position) { - final Position position = (Position) message; - if ((position.getOutdated() || processInvalidPositions && !position.getValid()) - && position.getNetwork() != null) { - if (statisticsManager != null) { - statisticsManager.registerGeolocationRequest(); - } - - geolocationProvider.getLocation(position.getNetwork(), - new GeolocationProvider.LocationProviderCallback() { - @Override - public void onSuccess(double latitude, double longitude, double accuracy) { - position.set(Position.KEY_APPROXIMATE, true); - position.setValid(true); - position.setFixTime(position.getDeviceTime()); - position.setLatitude(latitude); - position.setLongitude(longitude); - position.setAccuracy(accuracy); - position.setAltitude(0); - position.setSpeed(0); - position.setCourse(0); - position.set(Position.KEY_RSSI, 0); - ctx.fireChannelRead(position); - } - - @Override - public void onFailure(Throwable e) { - LOGGER.warn("Geolocation network error", e); - ctx.fireChannelRead(position); - } - }); - } else { - ctx.fireChannelRead(position); - } - } else { - ctx.fireChannelRead(message); - } - } - -} diff --git a/src/org/traccar/handler/HemisphereHandler.java b/src/org/traccar/handler/HemisphereHandler.java deleted file mode 100644 index aff3d8a64..000000000 --- a/src/org/traccar/handler/HemisphereHandler.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.handler; - -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class HemisphereHandler extends BaseDataHandler { - - private int latitudeFactor; - private int longitudeFactor; - - public HemisphereHandler(Config config) { - String latitudeHemisphere = config.getString(Keys.LOCATION_LATITUDE_HEMISPHERE); - if (latitudeHemisphere != null) { - if (latitudeHemisphere.equalsIgnoreCase("N")) { - latitudeFactor = 1; - } else if (latitudeHemisphere.equalsIgnoreCase("S")) { - latitudeFactor = -1; - } - } - String longitudeHemisphere = config.getString(Keys.LOCATION_LATITUDE_HEMISPHERE); - if (longitudeHemisphere != null) { - if (longitudeHemisphere.equalsIgnoreCase("E")) { - longitudeFactor = 1; - } else if (longitudeHemisphere.equalsIgnoreCase("W")) { - longitudeFactor = -1; - } - } - } - - @Override - protected Position handlePosition(Position position) { - if (latitudeFactor != 0) { - position.setLatitude(Math.abs(position.getLatitude()) * latitudeFactor); - } - if (longitudeFactor != 0) { - position.setLongitude(Math.abs(position.getLongitude()) * longitudeFactor); - } - return position; - } - -} diff --git a/src/org/traccar/handler/MotionHandler.java b/src/org/traccar/handler/MotionHandler.java deleted file mode 100644 index e8051dd75..000000000 --- a/src/org/traccar/handler/MotionHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler; - -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class MotionHandler extends BaseDataHandler { - - private double speedThreshold; - - public MotionHandler(double speedThreshold) { - this.speedThreshold = speedThreshold; - } - - @Override - protected Position handlePosition(Position position) { - if (!position.getAttributes().containsKey(Position.KEY_MOTION)) { - position.set(Position.KEY_MOTION, position.getSpeed() > speedThreshold); - } - return position; - } - -} diff --git a/src/org/traccar/handler/NetworkMessageHandler.java b/src/org/traccar/handler/NetworkMessageHandler.java deleted file mode 100644 index b1d926bfa..000000000 --- a/src/org/traccar/handler/NetworkMessageHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 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. - * 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.handler; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import io.netty.channel.socket.DatagramChannel; -import io.netty.channel.socket.DatagramPacket; -import org.traccar.NetworkMessage; - -import java.net.InetSocketAddress; - -public class NetworkMessageHandler extends ChannelDuplexHandler { - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - if (ctx.channel() instanceof DatagramChannel) { - DatagramPacket packet = (DatagramPacket) msg; - ctx.fireChannelRead(new NetworkMessage(packet.content(), packet.sender())); - } else if (msg instanceof ByteBuf) { - ByteBuf buffer = (ByteBuf) msg; - ctx.fireChannelRead(new NetworkMessage(buffer, ctx.channel().remoteAddress())); - } - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { - if (msg instanceof NetworkMessage) { - NetworkMessage message = (NetworkMessage) msg; - if (ctx.channel() instanceof DatagramChannel) { - InetSocketAddress recipient = (InetSocketAddress) message.getRemoteAddress(); - InetSocketAddress sender = (InetSocketAddress) ctx.channel().localAddress(); - ctx.write(new DatagramPacket((ByteBuf) message.getMessage(), recipient, sender), promise); - } else { - ctx.write(message.getMessage(), promise); - } - } else { - ctx.write(msg, promise); - } - } - -} diff --git a/src/org/traccar/handler/OpenChannelHandler.java b/src/org/traccar/handler/OpenChannelHandler.java deleted file mode 100644 index d09d617ab..000000000 --- a/src/org/traccar/handler/OpenChannelHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 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. - * 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.handler; - -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.TrackerServer; - -public class OpenChannelHandler extends ChannelDuplexHandler { - - private final TrackerServer server; - - public OpenChannelHandler(TrackerServer server) { - this.server = server; - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - super.channelActive(ctx); - server.getChannelGroup().add(ctx.channel()); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - super.channelInactive(ctx); - server.getChannelGroup().remove(ctx.channel()); - } - -} diff --git a/src/org/traccar/handler/RemoteAddressHandler.java b/src/org/traccar/handler/RemoteAddressHandler.java deleted file mode 100644 index c09b8c39a..000000000 --- a/src/org/traccar/handler/RemoteAddressHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - * 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.handler; - -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.traccar.model.Position; - -import java.net.InetSocketAddress; - -@ChannelHandler.Sharable -public class RemoteAddressHandler extends ChannelInboundHandlerAdapter { - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - - InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); - String hostAddress = remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : null; - - if (msg instanceof Position) { - Position position = (Position) msg; - position.set(Position.KEY_IP, hostAddress); - } - - ctx.fireChannelRead(msg); - } - -} diff --git a/src/org/traccar/handler/StandardLoggingHandler.java b/src/org/traccar/handler/StandardLoggingHandler.java deleted file mode 100644 index 88010458f..000000000 --- a/src/org/traccar/handler/StandardLoggingHandler.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 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. - * 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.handler; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.NetworkMessage; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; - -public class StandardLoggingHandler extends ChannelDuplexHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(StandardLoggingHandler.class); - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - log(ctx, false, msg); - super.channelRead(ctx, msg); - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - log(ctx, true, msg); - super.write(ctx, msg, promise); - } - - public void log(ChannelHandlerContext ctx, boolean downstream, Object o) { - if (o instanceof NetworkMessage) { - NetworkMessage networkMessage = (NetworkMessage) o; - if (networkMessage.getMessage() instanceof ByteBuf) { - log(ctx, downstream, networkMessage.getRemoteAddress(), (ByteBuf) networkMessage.getMessage()); - } - } else if (o instanceof ByteBuf) { - log(ctx, downstream, ctx.channel().remoteAddress(), (ByteBuf) o); - } - } - - public void log(ChannelHandlerContext ctx, boolean downstream, SocketAddress remoteAddress, ByteBuf buf) { - StringBuilder message = new StringBuilder(); - - message.append("[").append(ctx.channel().id().asShortText()).append(": "); - message.append(((InetSocketAddress) ctx.channel().localAddress()).getPort()); - if (downstream) { - message.append(" > "); - } else { - message.append(" < "); - } - - if (remoteAddress instanceof InetSocketAddress) { - message.append(((InetSocketAddress) remoteAddress).getHostString()); - } else { - message.append("unknown"); - } - message.append("]"); - - message.append(" HEX: "); - message.append(ByteBufUtil.hexDump(buf)); - - LOGGER.info(message.toString()); - } - -} diff --git a/src/org/traccar/handler/events/AlertEventHandler.java b/src/org/traccar/handler/events/AlertEventHandler.java deleted file mode 100644 index 0b7c8d23e..000000000 --- a/src/org/traccar/handler/events/AlertEventHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.handler.events; - -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.IdentityManager; -import org.traccar.model.Event; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class AlertEventHandler extends BaseEventHandler { - - private final IdentityManager identityManager; - private final boolean ignoreDuplicateAlerts; - - public AlertEventHandler(Config config, IdentityManager identityManager) { - this.identityManager = identityManager; - ignoreDuplicateAlerts = config.getBoolean(Keys.EVENT_IGNORE_DUPLICATE_ALERTS); - } - - @Override - protected Map analyzePosition(Position position) { - Object alarm = position.getAttributes().get(Position.KEY_ALARM); - if (alarm != null) { - boolean ignoreAlert = false; - if (ignoreDuplicateAlerts) { - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); - if (lastPosition != null && alarm.equals(lastPosition.getAttributes().get(Position.KEY_ALARM))) { - ignoreAlert = true; - } - } - if (!ignoreAlert) { - Event event = new Event(Event.TYPE_ALARM, position.getDeviceId(), position.getId()); - event.set(Position.KEY_ALARM, (String) alarm); - return Collections.singletonMap(event, position); - } - } - return null; - } - -} diff --git a/src/org/traccar/handler/events/BaseEventHandler.java b/src/org/traccar/handler/events/BaseEventHandler.java deleted file mode 100644 index 41f677f6c..000000000 --- a/src/org/traccar/handler/events/BaseEventHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2016 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. - * 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.handler.events; - -import java.util.Map; - -import org.traccar.BaseDataHandler; -import org.traccar.Context; -import org.traccar.model.Event; -import org.traccar.model.Position; - -public abstract class BaseEventHandler extends BaseDataHandler { - - @Override - protected Position handlePosition(Position position) { - Map events = analyzePosition(position); - if (events != null && Context.getNotificationManager() != null) { - Context.getNotificationManager().updateEvents(events); - } - return position; - } - - protected abstract Map analyzePosition(Position position); - -} diff --git a/src/org/traccar/handler/events/CommandResultEventHandler.java b/src/org/traccar/handler/events/CommandResultEventHandler.java deleted file mode 100644 index cfe676653..000000000 --- a/src/org/traccar/handler/events/CommandResultEventHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 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. - * 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.handler.events; - -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; -import org.traccar.model.Event; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class CommandResultEventHandler extends BaseEventHandler { - - @Override - protected Map analyzePosition(Position position) { - Object commandResult = position.getAttributes().get(Position.KEY_RESULT); - if (commandResult != null) { - Event event = new Event(Event.TYPE_COMMAND_RESULT, position.getDeviceId(), position.getId()); - event.set(Position.KEY_RESULT, (String) commandResult); - return Collections.singletonMap(event, position); - } - return null; - } - -} diff --git a/src/org/traccar/handler/events/DriverEventHandler.java b/src/org/traccar/handler/events/DriverEventHandler.java deleted file mode 100644 index 994df93fa..000000000 --- a/src/org/traccar/handler/events/DriverEventHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler.events; - -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; -import org.traccar.database.IdentityManager; -import org.traccar.model.Event; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class DriverEventHandler extends BaseEventHandler { - - private final IdentityManager identityManager; - - public DriverEventHandler(IdentityManager identityManager) { - this.identityManager = identityManager; - } - - @Override - protected Map analyzePosition(Position position) { - if (!identityManager.isLatestPosition(position)) { - return null; - } - String driverUniqueId = position.getString(Position.KEY_DRIVER_UNIQUE_ID); - if (driverUniqueId != null) { - String oldDriverUniqueId = null; - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); - if (lastPosition != null) { - oldDriverUniqueId = lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); - } - if (!driverUniqueId.equals(oldDriverUniqueId)) { - Event event = new Event(Event.TYPE_DRIVER_CHANGED, position.getDeviceId(), position.getId()); - event.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId); - return Collections.singletonMap(event, position); - } - } - return null; - } - -} diff --git a/src/org/traccar/handler/events/FuelDropEventHandler.java b/src/org/traccar/handler/events/FuelDropEventHandler.java deleted file mode 100644 index 59de61bba..000000000 --- a/src/org/traccar/handler/events/FuelDropEventHandler.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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.handler.events; - -import io.netty.channel.ChannelHandler; -import org.traccar.database.IdentityManager; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Position; - -import java.util.Collections; -import java.util.Map; - -@ChannelHandler.Sharable -public class FuelDropEventHandler extends BaseEventHandler { - - public static final String ATTRIBUTE_FUEL_DROP_THRESHOLD = "fuelDropThreshold"; - - private final IdentityManager identityManager; - - public FuelDropEventHandler(IdentityManager identityManager) { - this.identityManager = identityManager; - } - - @Override - protected Map analyzePosition(Position position) { - - Device device = identityManager.getById(position.getDeviceId()); - if (device == null) { - return null; - } - if (!identityManager.isLatestPosition(position)) { - return null; - } - - double fuelDropThreshold = identityManager - .lookupAttributeDouble(device.getId(), ATTRIBUTE_FUEL_DROP_THRESHOLD, 0, false); - - if (fuelDropThreshold > 0) { - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); - if (position.getAttributes().containsKey(Position.KEY_FUEL_LEVEL) - && lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_FUEL_LEVEL)) { - - double drop = lastPosition.getDouble(Position.KEY_FUEL_LEVEL) - - position.getDouble(Position.KEY_FUEL_LEVEL); - if (drop >= fuelDropThreshold) { - Event event = new Event(Event.TYPE_DEVICE_FUEL_DROP, position.getDeviceId(), position.getId()); - event.set(ATTRIBUTE_FUEL_DROP_THRESHOLD, fuelDropThreshold); - return Collections.singletonMap(event, position); - } - } - } - - return null; - } - -} diff --git a/src/org/traccar/handler/events/GeofenceEventHandler.java b/src/org/traccar/handler/events/GeofenceEventHandler.java deleted file mode 100644 index 067c97957..000000000 --- a/src/org/traccar/handler/events/GeofenceEventHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.handler.events; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.netty.channel.ChannelHandler; -import org.traccar.database.CalendarManager; -import org.traccar.database.GeofenceManager; -import org.traccar.database.IdentityManager; -import org.traccar.model.Calendar; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class GeofenceEventHandler extends BaseEventHandler { - - private final IdentityManager identityManager; - private final GeofenceManager geofenceManager; - private final CalendarManager calendarManager; - - public GeofenceEventHandler( - IdentityManager identityManager, GeofenceManager geofenceManager, CalendarManager calendarManager) { - this.identityManager = identityManager; - this.geofenceManager = geofenceManager; - this.calendarManager = calendarManager; - } - - @Override - protected Map analyzePosition(Position position) { - Device device = identityManager.getById(position.getDeviceId()); - if (device == null) { - return null; - } - if (!identityManager.isLatestPosition(position) || !position.getValid()) { - return null; - } - - List currentGeofences = geofenceManager.getCurrentDeviceGeofences(position); - List oldGeofences = new ArrayList<>(); - if (device.getGeofenceIds() != null) { - oldGeofences.addAll(device.getGeofenceIds()); - } - List newGeofences = new ArrayList<>(currentGeofences); - newGeofences.removeAll(oldGeofences); - oldGeofences.removeAll(currentGeofences); - - device.setGeofenceIds(currentGeofences); - - Map events = new HashMap<>(); - for (long geofenceId : oldGeofences) { - long calendarId = geofenceManager.getById(geofenceId).getCalendarId(); - Calendar calendar = calendarId != 0 ? calendarManager.getById(calendarId) : null; - if (calendar == null || calendar.checkMoment(position.getFixTime())) { - Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position.getDeviceId(), position.getId()); - event.setGeofenceId(geofenceId); - events.put(event, position); - } - } - for (long geofenceId : newGeofences) { - long calendarId = geofenceManager.getById(geofenceId).getCalendarId(); - Calendar calendar = calendarId != 0 ? calendarManager.getById(calendarId) : null; - if (calendar == null || calendar.checkMoment(position.getFixTime())) { - Event event = new Event(Event.TYPE_GEOFENCE_ENTER, position.getDeviceId(), position.getId()); - event.setGeofenceId(geofenceId); - events.put(event, position); - } - } - return events; - } - -} diff --git a/src/org/traccar/handler/events/IgnitionEventHandler.java b/src/org/traccar/handler/events/IgnitionEventHandler.java deleted file mode 100644 index ec133bafc..000000000 --- a/src/org/traccar/handler/events/IgnitionEventHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler.events; - -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; -import org.traccar.database.IdentityManager; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class IgnitionEventHandler extends BaseEventHandler { - - private final IdentityManager identityManager; - - public IgnitionEventHandler(IdentityManager identityManager) { - this.identityManager = identityManager; - } - - @Override - protected Map analyzePosition(Position position) { - Device device = identityManager.getById(position.getDeviceId()); - if (device == null || !identityManager.isLatestPosition(position)) { - return null; - } - - Map result = null; - - if (position.getAttributes().containsKey(Position.KEY_IGNITION)) { - boolean ignition = position.getBoolean(Position.KEY_IGNITION); - - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); - if (lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_IGNITION)) { - boolean oldIgnition = lastPosition.getBoolean(Position.KEY_IGNITION); - - if (ignition && !oldIgnition) { - result = Collections.singletonMap( - new Event(Event.TYPE_IGNITION_ON, position.getDeviceId(), position.getId()), position); - } else if (!ignition && oldIgnition) { - result = Collections.singletonMap( - new Event(Event.TYPE_IGNITION_OFF, position.getDeviceId(), position.getId()), position); - } - } - } - return result; - } - -} diff --git a/src/org/traccar/handler/events/MaintenanceEventHandler.java b/src/org/traccar/handler/events/MaintenanceEventHandler.java deleted file mode 100644 index 93ae74142..000000000 --- a/src/org/traccar/handler/events/MaintenanceEventHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler.events; - -import java.util.HashMap; -import java.util.Map; - -import io.netty.channel.ChannelHandler; -import org.traccar.database.IdentityManager; -import org.traccar.database.MaintenancesManager; -import org.traccar.model.Event; -import org.traccar.model.Maintenance; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class MaintenanceEventHandler extends BaseEventHandler { - - private final IdentityManager identityManager; - private final MaintenancesManager maintenancesManager; - - public MaintenanceEventHandler(IdentityManager identityManager, MaintenancesManager maintenancesManager) { - this.identityManager = identityManager; - this.maintenancesManager = maintenancesManager; - } - - @Override - protected Map analyzePosition(Position position) { - if (identityManager.getById(position.getDeviceId()) == null - || !identityManager.isLatestPosition(position)) { - return null; - } - - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); - if (lastPosition == null) { - return null; - } - - Map events = new HashMap<>(); - for (long maintenanceId : maintenancesManager.getAllDeviceItems(position.getDeviceId())) { - Maintenance maintenance = maintenancesManager.getById(maintenanceId); - if (maintenance.getPeriod() != 0) { - double oldValue = lastPosition.getDouble(maintenance.getType()); - double newValue = position.getDouble(maintenance.getType()); - if (oldValue != 0.0 && newValue != 0.0 - && (long) ((oldValue - maintenance.getStart()) / maintenance.getPeriod()) - < (long) ((newValue - maintenance.getStart()) / maintenance.getPeriod())) { - Event event = new Event(Event.TYPE_MAINTENANCE, position.getDeviceId(), position.getId()); - event.setMaintenanceId(maintenanceId); - event.set(maintenance.getType(), newValue); - events.put(event, position); - } - } - } - - return events; - } - -} diff --git a/src/org/traccar/handler/events/MotionEventHandler.java b/src/org/traccar/handler/events/MotionEventHandler.java deleted file mode 100644 index 9ec02ccfb..000000000 --- a/src/org/traccar/handler/events/MotionEventHandler.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler.events; - -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; -import org.traccar.database.DeviceManager; -import org.traccar.database.IdentityManager; -import org.traccar.model.Device; -import org.traccar.model.DeviceState; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.reports.ReportUtils; -import org.traccar.reports.model.TripsConfig; - -@ChannelHandler.Sharable -public class MotionEventHandler extends BaseEventHandler { - - private final IdentityManager identityManager; - private final DeviceManager deviceManager; - private final TripsConfig tripsConfig; - - public MotionEventHandler(IdentityManager identityManager, DeviceManager deviceManager, TripsConfig tripsConfig) { - this.identityManager = identityManager; - this.deviceManager = deviceManager; - this.tripsConfig = tripsConfig; - } - - private Map newEvent(DeviceState deviceState, boolean newMotion) { - String eventType = newMotion ? Event.TYPE_DEVICE_MOVING : Event.TYPE_DEVICE_STOPPED; - Position position = deviceState.getMotionPosition(); - Event event = new Event(eventType, position.getDeviceId(), position.getId()); - deviceState.setMotionState(newMotion); - deviceState.setMotionPosition(null); - return Collections.singletonMap(event, position); - } - - public Map updateMotionState(DeviceState deviceState) { - Map result = null; - if (deviceState.getMotionState() != null && deviceState.getMotionPosition() != null) { - boolean newMotion = !deviceState.getMotionState(); - Position motionPosition = deviceState.getMotionPosition(); - long currentTime = System.currentTimeMillis(); - long motionTime = motionPosition.getFixTime().getTime() - + (newMotion ? tripsConfig.getMinimalTripDuration() : tripsConfig.getMinimalParkingDuration()); - if (motionTime <= currentTime) { - result = newEvent(deviceState, newMotion); - } - } - return result; - } - - public Map updateMotionState(DeviceState deviceState, Position position) { - return updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION)); - } - - public Map updateMotionState(DeviceState deviceState, Position position, boolean newMotion) { - Map result = null; - Boolean oldMotion = deviceState.getMotionState(); - - long currentTime = position.getFixTime().getTime(); - if (newMotion != oldMotion) { - if (deviceState.getMotionPosition() == null) { - deviceState.setMotionPosition(position); - } - } else { - deviceState.setMotionPosition(null); - } - - Position motionPosition = deviceState.getMotionPosition(); - if (motionPosition != null) { - long motionTime = motionPosition.getFixTime().getTime(); - double distance = ReportUtils.calculateDistance(motionPosition, position, false); - Boolean ignition = null; - if (tripsConfig.getUseIgnition() - && position.getAttributes().containsKey(Position.KEY_IGNITION)) { - ignition = position.getBoolean(Position.KEY_IGNITION); - } - if (newMotion) { - if (motionTime + tripsConfig.getMinimalTripDuration() <= currentTime - || distance >= tripsConfig.getMinimalTripDistance()) { - result = newEvent(deviceState, newMotion); - } - } else { - if (motionTime + tripsConfig.getMinimalParkingDuration() <= currentTime - || ignition != null && !ignition) { - result = newEvent(deviceState, newMotion); - } - } - } - return result; - } - - @Override - protected Map analyzePosition(Position position) { - - long deviceId = position.getDeviceId(); - Device device = identityManager.getById(deviceId); - if (device == null) { - return null; - } - if (!identityManager.isLatestPosition(position) - || !tripsConfig.getProcessInvalidPositions() && !position.getValid()) { - return null; - } - - Map result = null; - DeviceState deviceState = deviceManager.getDeviceState(deviceId); - - if (deviceState.getMotionState() == null) { - deviceState.setMotionState(position.getBoolean(Position.KEY_MOTION)); - } else { - result = updateMotionState(deviceState, position); - } - deviceManager.setDeviceState(deviceId, deviceState); - return result; - } - -} diff --git a/src/org/traccar/handler/events/OverspeedEventHandler.java b/src/org/traccar/handler/events/OverspeedEventHandler.java deleted file mode 100644 index 157bb64e0..000000000 --- a/src/org/traccar/handler/events/OverspeedEventHandler.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.handler.events; - -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.DeviceManager; -import org.traccar.database.GeofenceManager; -import org.traccar.model.Device; -import org.traccar.model.DeviceState; -import org.traccar.model.Event; -import org.traccar.model.Geofence; -import org.traccar.model.Position; - -@ChannelHandler.Sharable -public class OverspeedEventHandler extends BaseEventHandler { - - public static final String ATTRIBUTE_SPEED = "speed"; - public static final String ATTRIBUTE_SPEED_LIMIT = "speedLimit"; - - private final DeviceManager deviceManager; - private final GeofenceManager geofenceManager; - - private final boolean notRepeat; - private final long minimalDuration; - private final boolean preferLowest; - - public OverspeedEventHandler(Config config, DeviceManager deviceManager, GeofenceManager geofenceManager) { - this.deviceManager = deviceManager; - this.geofenceManager = geofenceManager; - notRepeat = config.getBoolean(Keys.EVENT_OVERSPEED_NOT_REPEAT); - minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000; - preferLowest = config.getBoolean(Keys.EVENT_OVERSPEED_PREFER_LOWEST); - } - - private Map newEvent(DeviceState deviceState, double speedLimit) { - Position position = deviceState.getOverspeedPosition(); - Event event = new Event(Event.TYPE_DEVICE_OVERSPEED, position.getDeviceId(), position.getId()); - event.set(ATTRIBUTE_SPEED, deviceState.getOverspeedPosition().getSpeed()); - event.set(ATTRIBUTE_SPEED_LIMIT, speedLimit); - event.setGeofenceId(deviceState.getOverspeedGeofenceId()); - deviceState.setOverspeedState(notRepeat); - deviceState.setOverspeedPosition(null); - deviceState.setOverspeedGeofenceId(0); - return Collections.singletonMap(event, position); - } - - public Map updateOverspeedState(DeviceState deviceState, double speedLimit) { - Map result = null; - if (deviceState.getOverspeedState() != null && !deviceState.getOverspeedState() - && deviceState.getOverspeedPosition() != null && speedLimit != 0) { - long currentTime = System.currentTimeMillis(); - Position overspeedPosition = deviceState.getOverspeedPosition(); - long overspeedTime = overspeedPosition.getFixTime().getTime(); - if (overspeedTime + minimalDuration <= currentTime) { - result = newEvent(deviceState, speedLimit); - } - } - return result; - } - - public Map updateOverspeedState( - DeviceState deviceState, Position position, double speedLimit, long geofenceId) { - Map result = null; - - Boolean oldOverspeed = deviceState.getOverspeedState(); - - long currentTime = position.getFixTime().getTime(); - boolean newOverspeed = position.getSpeed() > speedLimit; - if (newOverspeed && !oldOverspeed) { - if (deviceState.getOverspeedPosition() == null) { - deviceState.setOverspeedPosition(position); - deviceState.setOverspeedGeofenceId(geofenceId); - } - } else if (oldOverspeed && !newOverspeed) { - deviceState.setOverspeedState(false); - deviceState.setOverspeedPosition(null); - deviceState.setOverspeedGeofenceId(0); - } else { - deviceState.setOverspeedPosition(null); - deviceState.setOverspeedGeofenceId(0); - } - Position overspeedPosition = deviceState.getOverspeedPosition(); - if (overspeedPosition != null) { - long overspeedTime = overspeedPosition.getFixTime().getTime(); - if (newOverspeed && overspeedTime + minimalDuration <= currentTime) { - result = newEvent(deviceState, speedLimit); - } - } - return result; - } - - @Override - protected Map analyzePosition(Position position) { - - long deviceId = position.getDeviceId(); - Device device = deviceManager.getById(deviceId); - if (device == null) { - return null; - } - if (!deviceManager.isLatestPosition(position) || !position.getValid()) { - return null; - } - - double speedLimit = deviceManager.lookupAttributeDouble(deviceId, ATTRIBUTE_SPEED_LIMIT, 0, false); - - double geofenceSpeedLimit = 0; - long overspeedGeofenceId = 0; - - if (geofenceManager != null && device.getGeofenceIds() != null) { - for (long geofenceId : device.getGeofenceIds()) { - Geofence geofence = geofenceManager.getById(geofenceId); - if (geofence != null) { - double currentSpeedLimit = geofence.getDouble(ATTRIBUTE_SPEED_LIMIT); - if (currentSpeedLimit > 0 && geofenceSpeedLimit == 0 - || preferLowest && currentSpeedLimit < geofenceSpeedLimit - || !preferLowest && currentSpeedLimit > geofenceSpeedLimit) { - geofenceSpeedLimit = currentSpeedLimit; - overspeedGeofenceId = geofenceId; - } - } - } - } - if (geofenceSpeedLimit > 0) { - speedLimit = geofenceSpeedLimit; - } - - if (speedLimit == 0) { - return null; - } - - Map result = null; - DeviceState deviceState = deviceManager.getDeviceState(deviceId); - - if (deviceState.getOverspeedState() == null) { - deviceState.setOverspeedState(position.getSpeed() > speedLimit); - deviceState.setOverspeedGeofenceId(position.getSpeed() > speedLimit ? overspeedGeofenceId : 0); - } else { - result = updateOverspeedState(deviceState, position, speedLimit, overspeedGeofenceId); - } - - deviceManager.setDeviceState(deviceId, deviceState); - return result; - } - -} diff --git a/src/org/traccar/helper/BcdUtil.java b/src/org/traccar/helper/BcdUtil.java deleted file mode 100644 index c87529e32..000000000 --- a/src/org/traccar/helper/BcdUtil.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - * 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.helper; - -import io.netty.buffer.ByteBuf; - -public final class BcdUtil { - - private BcdUtil() { - } - - public static int readInteger(ByteBuf buf, int digits) { - int result = 0; - - for (int i = 0; i < digits / 2; i++) { - int b = buf.readUnsignedByte(); - result *= 10; - result += b >>> 4; - result *= 10; - result += b & 0x0f; - } - - if (digits % 2 != 0) { - int b = buf.getUnsignedByte(buf.readerIndex()); - result *= 10; - result += b >>> 4; - } - - return result; - } - - public static double readCoordinate(ByteBuf buf) { - int b1 = buf.readUnsignedByte(); - int b2 = buf.readUnsignedByte(); - int b3 = buf.readUnsignedByte(); - int b4 = buf.readUnsignedByte(); - - double value = (b2 & 0xf) * 10 + (b3 >> 4); - value += (((b3 & 0xf) * 10 + (b4 >> 4)) * 10 + (b4 & 0xf)) / 1000.0; - value /= 60; - value += ((b1 >> 4 & 0x7) * 10 + (b1 & 0xf)) * 10 + (b2 >> 4); - - if ((b1 & 0x80) != 0) { - value = -value; - } - - return value; - } - -} diff --git a/src/org/traccar/helper/BitBuffer.java b/src/org/traccar/helper/BitBuffer.java deleted file mode 100644 index f30a4557b..000000000 --- a/src/org/traccar/helper/BitBuffer.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.helper; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -public class BitBuffer { - - private final ByteBuf buffer; - - private int writeByte; - private int writeCount; - - private int readByte; - private int readCount; - - public BitBuffer() { - buffer = Unpooled.buffer(); - } - - public BitBuffer(ByteBuf buffer) { - this.buffer = buffer; - } - - public void writeEncoded(byte[] bytes) { - for (byte b : bytes) { - b -= 48; - if (b > 40) { - b -= 8; - } - write(b); - } - } - - public void write(int b) { - if (writeCount == 0) { - writeByte |= b; - writeCount = 6; - } else { - int remaining = 8 - writeCount; - writeByte <<= remaining; - writeByte |= b >> (6 - remaining); - buffer.writeByte(writeByte); - writeByte = b & ((1 << (6 - remaining)) - 1); - writeCount = 6 - remaining; - } - } - - public int readUnsigned(int length) { - int result = 0; - - while (length > 0) { - if (readCount == 0) { - readByte = buffer.readUnsignedByte(); - readCount = 8; - } - if (readCount >= length) { - result <<= length; - result |= readByte >> (readCount - length); - readByte &= (1 << (readCount - length)) - 1; - readCount -= length; - length = 0; - } else { - result <<= readCount; - result |= readByte; - length -= readCount; - readByte = 0; - readCount = 0; - } - } - - return result; - } - - public int readSigned(int length) { - int result = readUnsigned(length); - int signBit = 1 << (length - 1); - if ((result & signBit) == 0) { - return result; - } else { - result &= signBit - 1; - result += ~(signBit - 1); - return result; - } - } - -} diff --git a/src/org/traccar/helper/BitUtil.java b/src/org/traccar/helper/BitUtil.java deleted file mode 100644 index b6108edff..000000000 --- a/src/org/traccar/helper/BitUtil.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 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. - * 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.helper; - -public final class BitUtil { - - private BitUtil() { - } - - public static boolean check(long number, int index) { - return (number & (1 << index)) != 0; - } - - public static int between(int number, int from, int to) { - return (number >> from) & ((1 << to - from) - 1); - } - - public static int from(int number, int from) { - return number >> from; - } - - public static int to(int number, int to) { - return between(number, 0, to); - } - - public static long between(long number, int from, int to) { - return (number >> from) & ((1L << to - from) - 1L); - } - - public static long from(long number, int from) { - return number >> from; - } - - public static long to(long number, int to) { - return between(number, 0, to); - } - -} diff --git a/src/org/traccar/helper/BufferUtil.java b/src/org/traccar/helper/BufferUtil.java deleted file mode 100644 index 15c619ec5..000000000 --- a/src/org/traccar/helper/BufferUtil.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.helper; - -import java.nio.charset.StandardCharsets; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; - -public final class BufferUtil { - - private BufferUtil() { - } - - public static int indexOf(String needle, ByteBuf haystack) { - ByteBuf needleBuffer = Unpooled.wrappedBuffer(needle.getBytes(StandardCharsets.US_ASCII)); - try { - return ByteBufUtil.indexOf(needleBuffer, haystack); - } finally { - needleBuffer.release(); - } - } - - public static int indexOf(String needle, ByteBuf haystack, int startIndex, int endIndex) { - ByteBuf wrappedHaystack = Unpooled.wrappedBuffer(haystack); - wrappedHaystack.readerIndex(startIndex - haystack.readerIndex()); - wrappedHaystack.writerIndex(endIndex - haystack.readerIndex()); - int result = indexOf(needle, wrappedHaystack); - return result < 0 ? result : haystack.readerIndex() + result; - } - -} diff --git a/src/org/traccar/helper/Checksum.java b/src/org/traccar/helper/Checksum.java deleted file mode 100644 index adfa697c5..000000000 --- a/src/org/traccar/helper/Checksum.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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. - * 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.helper; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.zip.CRC32; - -public final class Checksum { - - private Checksum() { - } - - public static class Algorithm { - - private int poly; - private int init; - private boolean refIn; - private boolean refOut; - private int xorOut; - private int[] table; - - public Algorithm(int bits, int poly, int init, boolean refIn, boolean refOut, int xorOut) { - this.poly = poly; - this.init = init; - this.refIn = refIn; - this.refOut = refOut; - this.xorOut = xorOut; - this.table = bits == 8 ? initTable8() : initTable16(); - } - - private int[] initTable8() { - int[] table = new int[256]; - int crc; - for (int i = 0; i < 256; i++) { - crc = i; - for (int j = 0; j < 8; j++) { - boolean bit = (crc & 0x80) != 0; - crc <<= 1; - if (bit) { - crc ^= poly; - } - } - table[i] = crc & 0xFF; - } - return table; - } - - private int[] initTable16() { - int[] table = new int[256]; - int crc; - for (int i = 0; i < 256; i++) { - crc = i << 8; - for (int j = 0; j < 8; j++) { - boolean bit = (crc & 0x8000) != 0; - crc <<= 1; - if (bit) { - crc ^= poly; - } - } - table[i] = crc & 0xFFFF; - } - return table; - } - - } - - private static int reverse(int value, int bits) { - int result = 0; - for (int i = 0; i < bits; i++) { - result = (result << 1) | (value & 1); - value >>= 1; - } - return result; - } - - public static int crc8(Algorithm algorithm, ByteBuffer buf) { - int crc = algorithm.init; - while (buf.hasRemaining()) { - int b = buf.get() & 0xFF; - if (algorithm.refIn) { - b = reverse(b, 8); - } - crc = algorithm.table[(crc & 0xFF) ^ b]; - } - if (algorithm.refOut) { - crc = reverse(crc, 8); - } - return (crc ^ algorithm.xorOut) & 0xFF; - } - - public static int crc16(Algorithm algorithm, ByteBuffer buf) { - int crc = algorithm.init; - while (buf.hasRemaining()) { - int b = buf.get() & 0xFF; - if (algorithm.refIn) { - b = reverse(b, 8); - } - crc = (crc << 8) ^ algorithm.table[((crc >> 8) & 0xFF) ^ b]; - } - if (algorithm.refOut) { - crc = reverse(crc, 16); - } - return (crc ^ algorithm.xorOut) & 0xFFFF; - } - - public static final Algorithm CRC8_EGTS = new Algorithm(8, 0x31, 0xFF, false, false, 0x00); - public static final Algorithm CRC8_ROHC = new Algorithm(8, 0x07, 0xFF, true, true, 0x00); - - public static final Algorithm CRC16_IBM = new Algorithm(16, 0x8005, 0x0000, true, true, 0x0000); - public static final Algorithm CRC16_X25 = new Algorithm(16, 0x1021, 0xFFFF, true, true, 0xFFFF); - public static final Algorithm CRC16_MODBUS = new Algorithm(16, 0x8005, 0xFFFF, true, true, 0x0000); - public static final Algorithm CRC16_CCITT_FALSE = new Algorithm(16, 0x1021, 0xFFFF, false, false, 0x0000); - public static final Algorithm CRC16_KERMIT = new Algorithm(16, 0x1021, 0x0000, true, true, 0x0000); - public static final Algorithm CRC16_XMODEM = new Algorithm(16, 0x1021, 0x0000, false, false, 0x0000); - - public static int crc32(ByteBuffer buf) { - CRC32 checksum = new CRC32(); - while (buf.hasRemaining()) { - checksum.update(buf.get()); - } - return (int) checksum.getValue(); - } - - public static int xor(ByteBuffer buf) { - int checksum = 0; - while (buf.hasRemaining()) { - checksum ^= buf.get(); - } - return checksum; - } - - public static int xor(String string) { - byte checksum = 0; - for (byte b : string.getBytes(StandardCharsets.US_ASCII)) { - checksum ^= b; - } - return checksum; - } - - public static String nmea(String msg) { - int checksum = 0; - byte[] bytes = msg.getBytes(StandardCharsets.US_ASCII); - for (int i = 1; i < bytes.length; i++) { - checksum ^= bytes[i]; - } - return String.format("*%02x", checksum).toUpperCase(); - } - - public static int sum(ByteBuffer buf) { - byte checksum = 0; - while (buf.hasRemaining()) { - checksum += buf.get(); - } - return checksum; - } - - public static String sum(String msg) { - byte checksum = 0; - for (byte b : msg.getBytes(StandardCharsets.US_ASCII)) { - checksum += b; - } - return String.format("%02X", checksum).toUpperCase(); - } - - public static long luhn(long imei) { - long checksum = 0; - long remain = imei; - - for (int i = 0; remain != 0; i++) { - long digit = remain % 10; - - if (i % 2 == 0) { - digit *= 2; - if (digit >= 10) { - digit = 1 + (digit % 10); - } - } - - checksum += digit; - remain /= 10; - } - - return (10 - (checksum % 10)) % 10; - } - -} diff --git a/src/org/traccar/helper/DataConverter.java b/src/org/traccar/helper/DataConverter.java deleted file mode 100644 index 7abd4ae93..000000000 --- a/src/org/traccar/helper/DataConverter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 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. - * 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.helper; - -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.binary.Hex; - -public final class DataConverter { - - private DataConverter() { - } - - public static byte[] parseHex(String string) { - try { - return Hex.decodeHex(string); - } catch (DecoderException e) { - throw new RuntimeException(e); - } - } - - public static String printHex(byte[] data) { - return Hex.encodeHexString(data); - } - - public static byte[] parseBase64(String string) { - return Base64.decodeBase64(string); - } - - public static String printBase64(byte[] data) { - return Base64.encodeBase64String(data); - } - -} diff --git a/src/org/traccar/helper/DateBuilder.java b/src/org/traccar/helper/DateBuilder.java deleted file mode 100644 index 6e1b779f0..000000000 --- a/src/org/traccar/helper/DateBuilder.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2015 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. - * 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.helper; - -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - -public class DateBuilder { - - private Calendar calendar; - - public DateBuilder() { - this(TimeZone.getTimeZone("UTC")); - } - - public DateBuilder(Date time) { - this(time, TimeZone.getTimeZone("UTC")); - } - - public DateBuilder(TimeZone timeZone) { - this(new Date(0), timeZone); - } - - public DateBuilder(Date time, TimeZone timeZone) { - calendar = Calendar.getInstance(timeZone); - calendar.clear(); - calendar.setTimeInMillis(time.getTime()); - } - - public DateBuilder setYear(int year) { - if (year < 100) { - year += 2000; - } - calendar.set(Calendar.YEAR, year); - return this; - } - - public DateBuilder setMonth(int month) { - calendar.set(Calendar.MONTH, month - 1); - return this; - } - - public DateBuilder setDay(int day) { - calendar.set(Calendar.DAY_OF_MONTH, day); - return this; - } - - public DateBuilder setDate(int year, int month, int day) { - return setYear(year).setMonth(month).setDay(day); - } - - public DateBuilder setDateReverse(int day, int month, int year) { - return setDate(year, month, day); - } - - public DateBuilder setCurrentDate() { - Calendar now = Calendar.getInstance(calendar.getTimeZone()); - return setYear(now.get(Calendar.YEAR)).setMonth(now.get(Calendar.MONTH)).setDay(now.get(Calendar.DAY_OF_MONTH)); - } - - public DateBuilder setHour(int hour) { - calendar.set(Calendar.HOUR_OF_DAY, hour); - return this; - } - - public DateBuilder setMinute(int minute) { - calendar.set(Calendar.MINUTE, minute); - return this; - } - - public DateBuilder addMinute(int minute) { - calendar.add(Calendar.MINUTE, minute); - return this; - } - - public DateBuilder setSecond(int second) { - calendar.set(Calendar.SECOND, second); - return this; - } - - public DateBuilder addSeconds(long seconds) { - calendar.setTimeInMillis(calendar.getTimeInMillis() + seconds * 1000); - return this; - } - - public DateBuilder setMillis(int millis) { - calendar.set(Calendar.MILLISECOND, millis); - return this; - } - - public DateBuilder addMillis(long millis) { - calendar.setTimeInMillis(calendar.getTimeInMillis() + millis); - return this; - } - - public DateBuilder setTime(int hour, int minute, int second) { - return setHour(hour).setMinute(minute).setSecond(second); - } - - public DateBuilder setTimeReverse(int second, int minute, int hour) { - return setHour(hour).setMinute(minute).setSecond(second); - } - - public DateBuilder setTime(int hour, int minute, int second, int millis) { - return setHour(hour).setMinute(minute).setSecond(second).setMillis(millis); - } - - public Date getDate() { - return calendar.getTime(); - } - -} diff --git a/src/org/traccar/helper/DateUtil.java b/src/org/traccar/helper/DateUtil.java deleted file mode 100644 index 20a483e3c..000000000 --- a/src/org/traccar/helper/DateUtil.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2016 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. - * 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.helper; - -import java.text.SimpleDateFormat; -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.Calendar; -import java.util.Date; - -public final class DateUtil { - - private DateUtil() { - } - - public static Date correctDay(Date guess) { - return correctDate(new Date(), guess, Calendar.DAY_OF_MONTH); - } - - public static Date correctYear(Date guess) { - return correctDate(new Date(), guess, Calendar.YEAR); - } - - public static Date correctDate(Date now, Date guess, int field) { - - if (guess.getTime() > now.getTime()) { - Date previous = dateAdd(guess, field, -1); - if (now.getTime() - previous.getTime() < guess.getTime() - now.getTime()) { - return previous; - } - } else if (guess.getTime() < now.getTime()) { - Date next = dateAdd(guess, field, 1); - if (next.getTime() - now.getTime() < now.getTime() - guess.getTime()) { - return next; - } - } - - return guess; - } - - private static Date dateAdd(Date guess, int field, int amount) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(guess); - calendar.add(field, amount); - return calendar.getTime(); - } - - public static Date parseDate(String value) { - return Date.from(Instant.from(DateTimeFormatter.ISO_ZONED_DATE_TIME.parse(value))); - } - - public static String formatDate(Date date) { - return formatDate(date, true); - } - - public static String formatDate(Date date, boolean zoned) { - if (zoned) { - return DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault()).format(date.toInstant()); - } else { - return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); - } - } - -} diff --git a/src/org/traccar/helper/DistanceCalculator.java b/src/org/traccar/helper/DistanceCalculator.java deleted file mode 100644 index 88d4ef8a4..000000000 --- a/src/org/traccar/helper/DistanceCalculator.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 - 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.helper; - -public final class DistanceCalculator { - - private DistanceCalculator() { - } - - private static final double EQUATORIAL_EARTH_RADIUS = 6378.1370; - private static final double DEG_TO_RAD = Math.PI / 180; - - public static double distance(double lat1, double lon1, double lat2, double lon2) { - double dlong = (lon2 - lon1) * DEG_TO_RAD; - double dlat = (lat2 - lat1) * DEG_TO_RAD; - double a = Math.pow(Math.sin(dlat / 2), 2) - + Math.cos(lat1 * DEG_TO_RAD) * Math.cos(lat2 * DEG_TO_RAD) * Math.pow(Math.sin(dlong / 2), 2); - double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - double d = EQUATORIAL_EARTH_RADIUS * c; - return d * 1000; - } - - public static double distanceToLine( - double pointLat, double pointLon, double lat1, double lon1, double lat2, double lon2) { - double d0 = distance(pointLat, pointLon, lat1, lon1); - double d1 = distance(lat1, lon1, lat2, lon2); - double d2 = distance(lat2, lon2, pointLat, pointLon); - if (Math.pow(d0, 2) > Math.pow(d1, 2) + Math.pow(d2, 2)) { - return d2; - } - if (Math.pow(d2, 2) > Math.pow(d1, 2) + Math.pow(d0, 2)) { - return d0; - } - double halfP = (d0 + d1 + d2) * 0.5; - double area = Math.sqrt(halfP * (halfP - d0) * (halfP - d1) * (halfP - d2)); - return 2 * area / d1; - } - -} diff --git a/src/org/traccar/helper/Hashing.java b/src/org/traccar/helper/Hashing.java deleted file mode 100644 index e91310eda..000000000 --- a/src/org/traccar/helper/Hashing.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2015 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. - * 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.helper; - -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.spec.InvalidKeySpecException; - -public final class Hashing { - - public static final int ITERATIONS = 1000; - public static final int SALT_SIZE = 24; - public static final int HASH_SIZE = 24; - - private static SecretKeyFactory factory; - static { - try { - factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - } - - public static class HashingResult { - - private final String hash; - private final String salt; - - public HashingResult(String hash, String salt) { - this.hash = hash; - this.salt = salt; - } - - public String getHash() { - return hash; - } - - public String getSalt() { - return salt; - } - } - - private Hashing() { - } - - private static byte[] function(char[] password, byte[] salt) { - try { - PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, HASH_SIZE * Byte.SIZE); - return factory.generateSecret(spec).getEncoded(); - } catch (InvalidKeySpecException e) { - throw new SecurityException(e); - } - } - - private static final SecureRandom RANDOM = new SecureRandom(); - - public static HashingResult createHash(String password) { - byte[] salt = new byte[SALT_SIZE]; - RANDOM.nextBytes(salt); - byte[] hash = function(password.toCharArray(), salt); - return new HashingResult( - DataConverter.printHex(hash), - DataConverter.printHex(salt)); - } - - public static boolean validatePassword(String password, String hashHex, String saltHex) { - byte[] hash = DataConverter.parseHex(hashHex); - byte[] salt = DataConverter.parseHex(saltHex); - return slowEquals(hash, function(password.toCharArray(), salt)); - } - - /** - * Compares two byte arrays in length-constant time. This comparison method - * is used so that password hashes cannot be extracted from an on-line - * system using a timing attack and then attacked off-line. - */ - private static boolean slowEquals(byte[] a, byte[] b) { - int diff = a.length ^ b.length; - for (int i = 0; i < a.length && i < b.length; i++) { - diff |= a[i] ^ b[i]; - } - return diff == 0; - } - -} diff --git a/src/org/traccar/helper/LocationTree.java b/src/org/traccar/helper/LocationTree.java deleted file mode 100644 index 3aff3ce33..000000000 --- a/src/org/traccar/helper/LocationTree.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2016 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. - * 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.helper; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -public class LocationTree { - - public static class Item { - - private Item left, right; - private float x, y; - private String data; - - public Item(float x, float y) { - this(x, y, null); - } - - public Item(float x, float y, String data) { - this.x = x; - this.y = y; - this.data = data; - } - - public String getData() { - return data; - } - - private float squaredDistance(Item item) { - return (x - item.x) * (x - item.x) + (y - item.y) * (y - item.y); - } - - private float axisSquaredDistance(Item item, int axis) { - if (axis == 0) { - return (x - item.x) * (x - item.x); - } else { - return (y - item.y) * (y - item.y); - } - } - - } - - private Item root; - - private ArrayList> comparators = new ArrayList<>(); - - public LocationTree(List items) { - comparators.add(new Comparator() { - @Override - public int compare(Item o1, Item o2) { - return Float.compare(o1.x, o2.x); - } - }); - comparators.add(new Comparator() { - @Override - public int compare(Item o1, Item o2) { - return Float.compare(o1.y, o2.y); - } - }); - root = createTree(items, 0); - } - - private Item createTree(List items, int depth) { - if (items.isEmpty()) { - return null; - } - Collections.sort(items, comparators.get(depth % 2)); - int currentIndex = items.size() / 2; - Item median = items.get(currentIndex); - median.left = createTree(new ArrayList<>(items.subList(0, currentIndex)), depth + 1); - median.right = createTree(new ArrayList<>(items.subList(currentIndex + 1, items.size())), depth + 1); - return median; - } - - public Item findNearest(Item search) { - return findNearest(root, search, 0); - } - - private Item findNearest(Item current, Item search, int depth) { - int direction = comparators.get(depth % 2).compare(search, current); - - Item next, other; - if (direction < 0) { - next = current.left; - other = current.right; - } else { - next = current.right; - other = current.left; - } - - Item best = current; - if (next != null) { - best = findNearest(next, search, depth + 1); - } - - if (current.squaredDistance(search) < best.squaredDistance(search)) { - best = current; - } - if (other != null && current.axisSquaredDistance(search, depth % 2) < best.squaredDistance(search)) { - Item possibleBest = findNearest(other, search, depth + 1); - if (possibleBest.squaredDistance(search) < best.squaredDistance(search)) { - best = possibleBest; - } - } - - return best; - } - -} diff --git a/src/org/traccar/helper/Log.java b/src/org/traccar/helper/Log.java deleted file mode 100644 index f328e8ce9..000000000 --- a/src/org/traccar/helper/Log.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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.helper; - -import org.traccar.config.Config; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.ConsoleHandler; -import java.util.logging.Formatter; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - -public final class Log { - - private Log() { - } - - private static final String STACK_PACKAGE = "org.traccar"; - private static final int STACK_LIMIT = 3; - - private static class RollingFileHandler extends Handler { - - private String name; - private String suffix; - private Writer writer; - private boolean rotate; - - RollingFileHandler(String name, boolean rotate) { - this.name = name; - this.rotate = rotate; - } - - @Override - public synchronized void publish(LogRecord record) { - if (isLoggable(record)) { - try { - String suffix = ""; - if (rotate) { - suffix = new SimpleDateFormat("yyyyMMdd").format(new Date(record.getMillis())); - if (writer != null && !suffix.equals(this.suffix)) { - writer.close(); - writer = null; - if (!new File(name).renameTo(new File(name + "." + this.suffix))) { - throw new RuntimeException("Log file renaming failed"); - } - } - } - if (writer == null) { - this.suffix = suffix; - writer = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(name, true), StandardCharsets.UTF_8)); - } - writer.write(getFormatter().format(record)); - writer.flush(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @Override - public synchronized void flush() { - if (writer != null) { - try { - writer.flush(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @Override - public synchronized void close() throws SecurityException { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - } - - public static class LogFormatter extends Formatter { - - private boolean fullStackTraces; - - LogFormatter(boolean fullStackTraces) { - this.fullStackTraces = fullStackTraces; - } - - private static String formatLevel(Level level) { - switch (level.getName()) { - case "FINEST": - return "TRACE"; - case "FINER": - case "FINE": - case "CONFIG": - return "DEBUG"; - case "INFO": - return "INFO"; - case "WARNING": - return "WARN"; - case "SEVERE": - default: - return "ERROR"; - } - } - - @Override - public String format(LogRecord record) { - StringBuilder message = new StringBuilder(); - - if (record.getMessage() != null) { - message.append(record.getMessage()); - } - - if (record.getThrown() != null) { - if (message.length() > 0) { - message.append(" - "); - } - if (fullStackTraces) { - StringWriter stringWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(stringWriter); - record.getThrown().printStackTrace(printWriter); - message.append(System.lineSeparator()).append(stringWriter.toString()); - } else { - message.append(exceptionStack(record.getThrown())); - } - } - - return String.format("%1$tF %1$tT %2$5s: %3$s%n", - new Date(record.getMillis()), formatLevel(record.getLevel()), message.toString()); - } - - } - - public static void setupDefaultLogger() { - String path = null; - URL url = ClassLoader.getSystemClassLoader().getResource("."); - if (url != null) { - File jarPath = new File(url.getPath()); - File logsPath = new File(jarPath, "logs"); - if (!logsPath.exists() || !logsPath.isDirectory()) { - logsPath = jarPath; - } - path = new File(logsPath, "tracker-server.log").getPath(); - } - setupLogger(path == null, path, Level.WARNING.getName(), false, true); - } - - public static void setupLogger(Config config) { - setupLogger( - config.getBoolean("logger.console"), - config.getString("logger.file"), - config.getString("logger.level"), - config.getBoolean("logger.fullStackTraces"), - config.getBoolean("logger.rotate")); - } - - private static void setupLogger( - boolean console, String file, String levelString, boolean fullStackTraces, boolean rotate) { - - Logger rootLogger = Logger.getLogger(""); - for (Handler handler : rootLogger.getHandlers()) { - rootLogger.removeHandler(handler); - } - - Handler handler; - if (console) { - handler = new ConsoleHandler(); - } else { - handler = new RollingFileHandler(file, rotate); - } - - handler.setFormatter(new LogFormatter(fullStackTraces)); - - Level level = Level.parse(levelString.toUpperCase()); - rootLogger.setLevel(level); - handler.setLevel(level); - handler.setFilter(record -> record != null && !record.getLoggerName().startsWith("sun")); - - rootLogger.addHandler(handler); - } - - public static String exceptionStack(Throwable exception) { - StringBuilder s = new StringBuilder(); - String exceptionMsg = exception.getMessage(); - if (exceptionMsg != null) { - s.append(exceptionMsg); - s.append(" - "); - } - s.append(exception.getClass().getSimpleName()); - StackTraceElement[] stack = exception.getStackTrace(); - - if (stack.length > 0) { - int count = STACK_LIMIT; - boolean first = true; - boolean skip = false; - String file = ""; - s.append(" ("); - for (StackTraceElement element : stack) { - if (count > 0 && element.getClassName().startsWith(STACK_PACKAGE)) { - if (!first) { - s.append(" < "); - } else { - first = false; - } - - if (skip) { - s.append("... < "); - skip = false; - } - - if (file.equals(element.getFileName())) { - s.append("*"); - } else { - file = element.getFileName(); - s.append(file, 0, file.length() - 5); // remove ".java" - count -= 1; - } - s.append(":").append(element.getLineNumber()); - } else { - skip = true; - } - } - if (skip) { - if (!first) { - s.append(" < "); - } - s.append("..."); - } - s.append(")"); - } - return s.toString(); - } - -} diff --git a/src/org/traccar/helper/LogAction.java b/src/org/traccar/helper/LogAction.java deleted file mode 100644 index db13337b8..000000000 --- a/src/org/traccar/helper/LogAction.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.helper; - -import java.beans.Introspector; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.model.BaseModel; - -public final class LogAction { - - private static final Logger LOGGER = LoggerFactory.getLogger(LogAction.class); - - private LogAction() { - } - - private static final String ACTION_CREATE = "create"; - private static final String ACTION_EDIT = "edit"; - private static final String ACTION_REMOVE = "remove"; - - private static final String ACTION_LINK = "link"; - private static final String ACTION_UNLINK = "unlink"; - - private static final String ACTION_LOGIN = "login"; - private static final String ACTION_LOGOUT = "logout"; - - private static final String ACTION_DEVICE_ACCUMULATORS = "resetDeviceAccumulators"; - - private static final String PATTERN_OBJECT = "user: %d, action: %s, object: %s, id: %d"; - private static final String PATTERN_LINK = "user: %d, action: %s, owner: %s, id: %d, property: %s, id: %d"; - private static final String PATTERN_LOGIN = "user: %d, action: %s"; - private static final String PATTERN_DEVICE_ACCUMULATORS = "user: %d, action: %s, deviceId: %d"; - - public static void create(long userId, BaseModel object) { - logObjectAction(ACTION_CREATE, userId, object.getClass(), object.getId()); - } - - public static void edit(long userId, BaseModel object) { - logObjectAction(ACTION_EDIT, userId, object.getClass(), object.getId()); - } - - public static void remove(long userId, Class clazz, long objectId) { - logObjectAction(ACTION_REMOVE, userId, clazz, objectId); - } - - public static void link(long userId, Class owner, long ownerId, Class property, long propertyId) { - logLinkAction(ACTION_LINK, userId, owner, ownerId, property, propertyId); - } - - public static void unlink(long userId, Class owner, long ownerId, Class property, long propertyId) { - logLinkAction(ACTION_UNLINK, userId, owner, ownerId, property, propertyId); - } - - public static void login(long userId) { - logLoginAction(ACTION_LOGIN, userId); - } - - public static void logout(long userId) { - logLoginAction(ACTION_LOGOUT, userId); - } - - public static void resetDeviceAccumulators(long userId, long deviceId) { - LOGGER.info(String.format( - PATTERN_DEVICE_ACCUMULATORS, userId, ACTION_DEVICE_ACCUMULATORS, deviceId)); - } - - private static void logObjectAction(String action, long userId, Class clazz, long objectId) { - LOGGER.info(String.format( - PATTERN_OBJECT, userId, action, Introspector.decapitalize(clazz.getSimpleName()), objectId)); - } - - private static void logLinkAction(String action, long userId, - Class owner, long ownerId, Class property, long propertyId) { - LOGGER.info(String.format( - PATTERN_LINK, userId, action, - Introspector.decapitalize(owner.getSimpleName()), ownerId, - Introspector.decapitalize(property.getSimpleName()), propertyId)); - } - - private static void logLoginAction(String action, long userId) { - LOGGER.info(String.format(PATTERN_LOGIN, userId, action)); - } - -} diff --git a/src/org/traccar/helper/ObdDecoder.java b/src/org/traccar/helper/ObdDecoder.java deleted file mode 100644 index 1bdcce352..000000000 --- a/src/org/traccar/helper/ObdDecoder.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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. - * 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.helper; - -import org.traccar.model.Position; - -import java.util.AbstractMap; -import java.util.Map; - -public final class ObdDecoder { - - private ObdDecoder() { - } - - private static final int MODE_CURRENT = 0x01; - private static final int MODE_FREEZE_FRAME = 0x02; - private static final int MODE_CODES = 0x03; - - public static Map.Entry decode(int mode, String value) { - switch (mode) { - case MODE_CURRENT: - case MODE_FREEZE_FRAME: - return decodeData( - Integer.parseInt(value.substring(0, 2), 16), - Integer.parseInt(value.substring(2), 16), true); - case MODE_CODES: - return decodeCodes(value); - default: - return null; - } - } - - private static Map.Entry createEntry(String key, Object value) { - return new AbstractMap.SimpleEntry<>(key, value); - } - - public static Map.Entry decodeCodes(String value) { - StringBuilder codes = new StringBuilder(); - for (int i = 0; i < value.length() / 4; i++) { - int numValue = Integer.parseInt(value.substring(i * 4, (i + 1) * 4), 16); - codes.append(' '); - switch (numValue >> 14) { - case 1: - codes.append('C'); - break; - case 2: - codes.append('B'); - break; - case 3: - codes.append('U'); - break; - default: - codes.append('P'); - break; - } - codes.append(String.format("%04X", numValue & 0x3FFF)); - } - if (codes.length() > 0) { - return createEntry(Position.KEY_DTCS, codes.toString().trim()); - } else { - return null; - } - } - - public static Map.Entry decodeData(int pid, int value, boolean convert) { - switch (pid) { - case 0x04: - return createEntry(Position.KEY_ENGINE_LOAD, convert ? value * 100 / 255 : value); - case 0x05: - return createEntry(Position.KEY_COOLANT_TEMP, convert ? value - 40 : value); - case 0x0B: - return createEntry("mapIntake", value); - case 0x0C: - return createEntry(Position.KEY_RPM, convert ? value / 4 : value); - case 0x0D: - return createEntry(Position.KEY_OBD_SPEED, value); - case 0x0F: - return createEntry("intakeTemp", convert ? value - 40 : value); - case 0x11: - return createEntry(Position.KEY_THROTTLE, convert ? value * 100 / 255 : value); - case 0x21: - return createEntry("milDistance", value); - case 0x2F: - return createEntry(Position.KEY_FUEL_LEVEL, convert ? value * 100 / 255 : value); - case 0x31: - return createEntry("clearedDistance", value); - default: - return null; - } - } - -} diff --git a/src/org/traccar/helper/Parser.java b/src/org/traccar/helper/Parser.java deleted file mode 100644 index 1471ec237..000000000 --- a/src/org/traccar/helper/Parser.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright 2015 - 2017 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. - * 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.helper; - -import java.util.Date; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class Parser { - - private int position; - private final Matcher matcher; - - public Parser(Pattern pattern, String input) { - matcher = pattern.matcher(input); - } - - public boolean matches() { - position = 1; - return matcher.matches(); - } - - public boolean find() { - position = 1; - return matcher.find(); - } - - public void skip(int number) { - position += number; - } - - public boolean hasNext() { - return hasNext(1); - } - - public boolean hasNext(int number) { - String value = matcher.group(position); - if (value != null && !value.isEmpty()) { - return true; - } else { - position += number; - return false; - } - } - - public String next() { - return matcher.group(position++); - } - - public Integer nextInt() { - if (hasNext()) { - return Integer.parseInt(next()); - } else { - return null; - } - } - - public int nextInt(int defaultValue) { - if (hasNext()) { - return Integer.parseInt(next()); - } else { - return defaultValue; - } - } - - public Integer nextHexInt() { - if (hasNext()) { - return Integer.parseInt(next(), 16); - } else { - return null; - } - } - - public int nextHexInt(int defaultValue) { - if (hasNext()) { - return Integer.parseInt(next(), 16); - } else { - return defaultValue; - } - } - - public Integer nextBinInt() { - if (hasNext()) { - return Integer.parseInt(next(), 2); - } else { - return null; - } - } - - public int nextBinInt(int defaultValue) { - if (hasNext()) { - return Integer.parseInt(next(), 2); - } else { - return defaultValue; - } - } - - public Long nextLong() { - if (hasNext()) { - return Long.parseLong(next()); - } else { - return null; - } - } - - public Long nextHexLong() { - if (hasNext()) { - return Long.parseLong(next(), 16); - } else { - return null; - } - } - - public long nextLong(long defaultValue) { - return nextLong(10, defaultValue); - } - - public long nextLong(int radix, long defaultValue) { - if (hasNext()) { - return Long.parseLong(next(), radix); - } else { - return defaultValue; - } - } - - public Double nextDouble() { - if (hasNext()) { - return Double.parseDouble(next()); - } else { - return null; - } - } - - public double nextDouble(double defaultValue) { - if (hasNext()) { - return Double.parseDouble(next()); - } else { - return defaultValue; - } - } - - public enum CoordinateFormat { - DEG_DEG, - DEG_HEM, - DEG_MIN_MIN, - DEG_MIN_HEM, - DEG_MIN_MIN_HEM, - HEM_DEG_MIN_MIN, - HEM_DEG, - HEM_DEG_MIN, - HEM_DEG_MIN_HEM - } - - public double nextCoordinate(CoordinateFormat format) { - double coordinate; - String hemisphere = null; - - switch (format) { - case DEG_DEG: - coordinate = Double.parseDouble(next() + '.' + next()); - break; - case DEG_HEM: - coordinate = nextDouble(0); - hemisphere = next(); - break; - case DEG_MIN_MIN: - coordinate = nextInt(0); - coordinate += Double.parseDouble(next() + '.' + next()) / 60; - break; - case DEG_MIN_MIN_HEM: - coordinate = nextInt(0); - coordinate += Double.parseDouble(next() + '.' + next()) / 60; - hemisphere = next(); - break; - case HEM_DEG: - hemisphere = next(); - coordinate = nextDouble(0); - break; - case HEM_DEG_MIN: - hemisphere = next(); - coordinate = nextInt(0); - coordinate += nextDouble(0) / 60; - break; - case HEM_DEG_MIN_HEM: - hemisphere = next(); - coordinate = nextInt(0); - coordinate += nextDouble(0) / 60; - if (hasNext()) { - hemisphere = next(); - } - break; - case HEM_DEG_MIN_MIN: - hemisphere = next(); - coordinate = nextInt(0); - coordinate += Double.parseDouble(next() + '.' + next()) / 60; - break; - case DEG_MIN_HEM: - default: - coordinate = nextInt(0); - coordinate += nextDouble(0) / 60; - hemisphere = next(); - break; - } - - if (hemisphere != null && (hemisphere.equals("S") || hemisphere.equals("W") || hemisphere.equals("-"))) { - coordinate = -Math.abs(coordinate); - } - - return coordinate; - } - - public double nextCoordinate() { - return nextCoordinate(CoordinateFormat.DEG_MIN_HEM); - } - - public enum DateTimeFormat { - HMS, - SMH, - HMS_YMD, - HMS_DMY, - SMH_YMD, - SMH_DMY, - DMY_HMS, - DMY_HMSS, - YMD_HMS, - YMD_HMSS, - } - - public Date nextDateTime(DateTimeFormat format, String timeZone) { - int year = 0, month = 0, day = 0; - int hour = 0, minute = 0, second = 0, millisecond = 0; - - switch (format) { - case HMS: - hour = nextInt(0); - minute = nextInt(0); - second = nextInt(0); - break; - case SMH: - second = nextInt(0); - minute = nextInt(0); - hour = nextInt(0); - break; - case HMS_YMD: - hour = nextInt(0); - minute = nextInt(0); - second = nextInt(0); - year = nextInt(0); - month = nextInt(0); - day = nextInt(0); - break; - case HMS_DMY: - hour = nextInt(0); - minute = nextInt(0); - second = nextInt(0); - day = nextInt(0); - month = nextInt(0); - year = nextInt(0); - break; - case SMH_YMD: - second = nextInt(0); - minute = nextInt(0); - hour = nextInt(0); - year = nextInt(0); - month = nextInt(0); - day = nextInt(0); - break; - case SMH_DMY: - second = nextInt(0); - minute = nextInt(0); - hour = nextInt(0); - day = nextInt(0); - month = nextInt(0); - year = nextInt(0); - break; - case DMY_HMS: - case DMY_HMSS: - day = nextInt(0); - month = nextInt(0); - year = nextInt(0); - hour = nextInt(0); - minute = nextInt(0); - second = nextInt(0); - break; - case YMD_HMS: - case YMD_HMSS: - default: - year = nextInt(0); - month = nextInt(0); - day = nextInt(0); - hour = nextInt(0); - minute = nextInt(0); - second = nextInt(0); - break; - } - - if (format == DateTimeFormat.YMD_HMSS || format == DateTimeFormat.DMY_HMSS) { - millisecond = nextInt(0); // (ddd) - } - - if (year >= 0 && year < 100) { - year += 2000; - } - - DateBuilder dateBuilder; - if (format != DateTimeFormat.HMS && format != DateTimeFormat.SMH) { - if (timeZone != null) { - dateBuilder = new DateBuilder(TimeZone.getTimeZone(timeZone)); - } else { - dateBuilder = new DateBuilder(); - } - dateBuilder.setDate(year, month, day); - } else { - if (timeZone != null) { - dateBuilder = new DateBuilder(new Date(), TimeZone.getTimeZone(timeZone)); - } else { - dateBuilder = new DateBuilder(new Date()); - } - } - - dateBuilder.setTime(hour, minute, second, millisecond); - - return dateBuilder.getDate(); - } - - public Date nextDateTime(DateTimeFormat format) { - return nextDateTime(format, null); - } - - public Date nextDateTime() { - return nextDateTime(DateTimeFormat.YMD_HMS, null); - } - -} diff --git a/src/org/traccar/helper/PatternBuilder.java b/src/org/traccar/helper/PatternBuilder.java deleted file mode 100644 index 5c4638189..000000000 --- a/src/org/traccar/helper/PatternBuilder.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2015 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. - * 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.helper; - -import java.util.ArrayList; -import java.util.regex.Pattern; - -public class PatternBuilder { - - private final ArrayList fragments = new ArrayList<>(); - - public PatternBuilder optional() { - return optional(1); - } - - public PatternBuilder optional(int count) { - fragments.add(fragments.size() - count, "(?:"); - fragments.add(")?"); - return this; - } - - public PatternBuilder expression(String s) { - s = s.replaceAll("\\|$", "\\\\|"); // special case for delimiter - - fragments.add(s); - return this; - } - - public PatternBuilder text(String s) { - fragments.add(s.replaceAll("([\\\\\\.\\[\\{\\(\\)\\*\\+\\?\\^\\$\\|])", "\\\\$1")); - return this; - } - - public PatternBuilder number(String s) { - s = s.replace("dddd", "d{4}").replace("ddd", "d{3}").replace("dd", "d{2}"); - s = s.replace("xxxx", "x{4}").replace("xxx", "x{3}").replace("xx", "x{2}"); - - s = s.replace("d", "\\d").replace("x", "[0-9a-fA-F]").replaceAll("([\\.])", "\\\\$1"); - s = s.replaceAll("\\|$", "\\\\|").replaceAll("^\\|", "\\\\|"); // special case for delimiter - - fragments.add(s); - return this; - } - - public PatternBuilder any() { - fragments.add(".*"); - return this; - } - - public PatternBuilder binary(String s) { - fragments.add(s.replaceAll("(\\p{XDigit}{2})", "\\\\$1")); - return this; - } - - public PatternBuilder or() { - fragments.add("|"); - return this; - } - - public PatternBuilder groupBegin() { - return expression("(?:"); - } - - public PatternBuilder groupEnd() { - return expression(")"); - } - - public PatternBuilder groupEnd(String s) { - return expression(")" + s); - } - - public Pattern compile() { - return Pattern.compile(toString(), Pattern.DOTALL); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - for (String fragment : fragments) { - builder.append(fragment); - } - return builder.toString(); - } - -} diff --git a/src/org/traccar/helper/PatternUtil.java b/src/org/traccar/helper/PatternUtil.java deleted file mode 100644 index 74813e1d9..000000000 --- a/src/org/traccar/helper/PatternUtil.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2015 - 2017 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. - * 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.helper; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.management.ManagementFactory; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -public final class PatternUtil { - - private static final Logger LOGGER = LoggerFactory.getLogger(PatternUtil.class); - - private PatternUtil() { - } - - public static class MatchResult { - private String patternMatch; - private String patternTail; - private String stringMatch; - private String stringTail; - - public String getPatternMatch() { - return patternMatch; - } - - public String getPatternTail() { - return patternTail; - } - - public String getStringMatch() { - return stringMatch; - } - - public String getStringTail() { - return stringTail; - } - } - - public static MatchResult checkPattern(String pattern, String input) { - - if (!ManagementFactory.getRuntimeMXBean().getInputArguments().toString().contains("-agentlib:jdwp")) { - throw new RuntimeException("PatternUtil usage detected"); - } - - MatchResult result = new MatchResult(); - - for (int i = 0; i < pattern.length(); i++) { - try { - Matcher matcher = Pattern.compile("(" + pattern.substring(0, i) + ").*").matcher(input); - if (matcher.matches()) { - result.patternMatch = pattern.substring(0, i); - result.patternTail = pattern.substring(i); - result.stringMatch = matcher.group(1); - result.stringTail = input.substring(matcher.group(1).length()); - } - } catch (PatternSyntaxException error) { - LOGGER.warn("Pattern matching error", error); - } - } - - return result; - } - -} diff --git a/src/org/traccar/helper/SanitizerModule.java b/src/org/traccar/helper/SanitizerModule.java deleted file mode 100644 index af9ac5c2b..000000000 --- a/src/org/traccar/helper/SanitizerModule.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 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. - * 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.helper; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import org.owasp.encoder.Encode; - -import java.io.IOException; - -public class SanitizerModule extends SimpleModule { - - public static class SanitizerSerializer extends StdSerializer { - - protected SanitizerSerializer() { - super(String.class); - } - - @Override - public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeString(Encode.forHtml(value)); - } - - } - - public SanitizerModule() { - addSerializer(new SanitizerSerializer()); - } - -} diff --git a/src/org/traccar/helper/UnitsConverter.java b/src/org/traccar/helper/UnitsConverter.java deleted file mode 100644 index 3dd435df4..000000000 --- a/src/org/traccar/helper/UnitsConverter.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 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. - * 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.helper; - -public final class UnitsConverter { - - private static final double KNOTS_TO_KPH_RATIO = 0.539957; - private static final double KNOTS_TO_MPH_RATIO = 0.868976; - private static final double KNOTS_TO_MPS_RATIO = 1.94384; - private static final double KNOTS_TO_CPS_RATIO = 0.0194384449; - private static final double METERS_TO_FEET_RATIO = 0.3048; - private static final double METERS_TO_MILE_RATIO = 1609.34; - private static final long MILLISECONDS_TO_HOURS_RATIO = 3600000; - private static final long MILLISECONDS_TO_MINUTES_RATIO = 60000; - - private UnitsConverter() { - } - - public static double knotsFromKph(double value) { // km/h - return value * KNOTS_TO_KPH_RATIO; - } - - public static double kphFromKnots(double value) { - return value / KNOTS_TO_KPH_RATIO; - } - - public static double knotsFromMph(double value) { - return value * KNOTS_TO_MPH_RATIO; - } - - public static double mphFromKnots(double value) { - return value / KNOTS_TO_MPH_RATIO; - } - - public static double knotsFromMps(double value) { // m/s - return value * KNOTS_TO_MPS_RATIO; - } - - public static double mpsFromKnots(double value) { - return value / KNOTS_TO_MPS_RATIO; - } - - public static double knotsFromCps(double value) { // cm/s - return value * KNOTS_TO_CPS_RATIO; - } - - public static double feetFromMeters(double value) { - return value / METERS_TO_FEET_RATIO; - } - - public static double metersFromFeet(double value) { - return value * METERS_TO_FEET_RATIO; - } - - public static double milesFromMeters(double value) { - return value / METERS_TO_MILE_RATIO; - } - - public static double metersFromMiles(double value) { - return value * METERS_TO_MILE_RATIO; - } - - public static long msFromHours(long value) { - return value * MILLISECONDS_TO_HOURS_RATIO; - } - - public static long msFromHours(double value) { - return (long) (value * MILLISECONDS_TO_HOURS_RATIO); - } - - public static long msFromMinutes(long value) { - return value * MILLISECONDS_TO_MINUTES_RATIO; - } - -} diff --git a/src/org/traccar/model/Attribute.java b/src/org/traccar/model/Attribute.java deleted file mode 100644 index 45d40b3ec..000000000 --- a/src/org/traccar/model/Attribute.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class Attribute extends BaseModel { - - private String description; - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - private String attribute; - - public String getAttribute() { - return attribute; - } - - public void setAttribute(String attribute) { - this.attribute = attribute; - } - - private String expression; - - public String getExpression() { - return expression; - } - - public void setExpression(String expression) { - this.expression = expression; - } - - private String type; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - -} diff --git a/src/org/traccar/model/BaseModel.java b/src/org/traccar/model/BaseModel.java deleted file mode 100644 index 8bdb916e8..000000000 --- a/src/org/traccar/model/BaseModel.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class BaseModel { - - private long id; - - public final long getId() { - return id; - } - - public final void setId(long id) { - this.id = id; - } - -} diff --git a/src/org/traccar/model/Calendar.java b/src/org/traccar/model/Calendar.java deleted file mode 100644 index 56d3eb74c..000000000 --- a/src/org/traccar/model/Calendar.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.Collection; -import java.util.Date; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import net.fortuna.ical4j.data.CalendarBuilder; -import net.fortuna.ical4j.data.ParserException; -import net.fortuna.ical4j.filter.Filter; -import net.fortuna.ical4j.filter.PeriodRule; -import net.fortuna.ical4j.model.DateTime; -import net.fortuna.ical4j.model.Dur; -import net.fortuna.ical4j.model.Period; -import net.fortuna.ical4j.model.component.CalendarComponent; -import org.apache.commons.collections4.Predicate; -import org.traccar.database.QueryIgnore; - -public class Calendar extends ExtendedModel { - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - private byte[] data; - - public byte[] getData() { - return data.clone(); - } - - public void setData(byte[] data) throws IOException, ParserException { - CalendarBuilder builder = new CalendarBuilder(); - calendar = builder.build(new ByteArrayInputStream(data)); - this.data = data.clone(); - } - - private net.fortuna.ical4j.model.Calendar calendar; - - @QueryIgnore - @JsonIgnore - public net.fortuna.ical4j.model.Calendar getCalendar() { - return calendar; - } - - public boolean checkMoment(Date date) { - if (calendar != null) { - Period period = new Period(new DateTime(date), new Dur(0, 0, 0, 0)); - Predicate periodRule = new PeriodRule<>(period); - Filter filter = new Filter<>(new Predicate[] {periodRule}, Filter.MATCH_ANY); - Collection events = filter.filter(calendar.getComponents(CalendarComponent.VEVENT)); - if (events != null && !events.isEmpty()) { - return true; - } - } - return false; - } - -} diff --git a/src/org/traccar/model/CellTower.java b/src/org/traccar/model/CellTower.java deleted file mode 100644 index 6d1dfbd7f..000000000 --- a/src/org/traccar/model/CellTower.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2016 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. - * 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.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import org.traccar.Context; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public class CellTower { - - public static CellTower from(int mcc, int mnc, int lac, long cid) { - CellTower cellTower = new CellTower(); - cellTower.setMobileCountryCode(mcc); - cellTower.setMobileNetworkCode(mnc); - cellTower.setLocationAreaCode(lac); - cellTower.setCellId(cid); - return cellTower; - } - - public static CellTower from(int mcc, int mnc, int lac, long cid, int rssi) { - CellTower cellTower = CellTower.from(mcc, mnc, lac, cid); - cellTower.setSignalStrength(rssi); - return cellTower; - } - - public static CellTower fromLacCid(int lac, long cid) { - return from( - Context.getConfig().getInteger("geolocation.mcc"), - Context.getConfig().getInteger("geolocation.mnc"), lac, cid); - } - - public static CellTower fromCidLac(long cid, int lac) { - return fromLacCid(lac, cid); - } - - private String radioType; - - public String getRadioType() { - return radioType; - } - - public void setRadioType(String radioType) { - this.radioType = radioType; - } - - private Long cellId; - - public Long getCellId() { - return cellId; - } - - public void setCellId(Long cellId) { - this.cellId = cellId; - } - - private Integer locationAreaCode; - - public Integer getLocationAreaCode() { - return locationAreaCode; - } - - public void setLocationAreaCode(Integer locationAreaCode) { - this.locationAreaCode = locationAreaCode; - } - - private Integer mobileCountryCode; - - public Integer getMobileCountryCode() { - return mobileCountryCode; - } - - public void setMobileCountryCode(Integer mobileCountryCode) { - this.mobileCountryCode = mobileCountryCode; - } - - private Integer mobileNetworkCode; - - public Integer getMobileNetworkCode() { - return mobileNetworkCode; - } - - public void setMobileNetworkCode(Integer mobileNetworkCode) { - this.mobileNetworkCode = mobileNetworkCode; - } - - private Integer signalStrength; - - public Integer getSignalStrength() { - return signalStrength; - } - - public void setSignalStrength(Integer signalStrength) { - this.signalStrength = signalStrength; - } - - public void setOperator(long operator) { - String operatorString = String.valueOf(operator); - mobileCountryCode = Integer.parseInt(operatorString.substring(0, 3)); - mobileNetworkCode = Integer.parseInt(operatorString.substring(3)); - } - -} diff --git a/src/org/traccar/model/Command.java b/src/org/traccar/model/Command.java deleted file mode 100644 index 336fc61f4..000000000 --- a/src/org/traccar/model/Command.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2015 - 2017 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. - * 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.model; - -import org.traccar.database.QueryIgnore; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class Command extends Message implements Cloneable { - - public static final String TYPE_CUSTOM = "custom"; - public static final String TYPE_IDENTIFICATION = "deviceIdentification"; - public static final String TYPE_POSITION_SINGLE = "positionSingle"; - public static final String TYPE_POSITION_PERIODIC = "positionPeriodic"; - public static final String TYPE_POSITION_STOP = "positionStop"; - public static final String TYPE_ENGINE_STOP = "engineStop"; - public static final String TYPE_ENGINE_RESUME = "engineResume"; - public static final String TYPE_ALARM_ARM = "alarmArm"; - public static final String TYPE_ALARM_DISARM = "alarmDisarm"; - public static final String TYPE_SET_TIMEZONE = "setTimezone"; - public static final String TYPE_REQUEST_PHOTO = "requestPhoto"; - public static final String TYPE_POWER_OFF = "powerOff"; - public static final String TYPE_REBOOT_DEVICE = "rebootDevice"; - public static final String TYPE_SEND_SMS = "sendSms"; - public static final String TYPE_SEND_USSD = "sendUssd"; - public static final String TYPE_SOS_NUMBER = "sosNumber"; - public static final String TYPE_SILENCE_TIME = "silenceTime"; - public static final String TYPE_SET_PHONEBOOK = "setPhonebook"; - public static final String TYPE_MESSAGE = "message"; - public static final String TYPE_VOICE_MESSAGE = "voiceMessage"; - public static final String TYPE_OUTPUT_CONTROL = "outputControl"; - public static final String TYPE_VOICE_MONITORING = "voiceMonitoring"; - public static final String TYPE_SET_AGPS = "setAgps"; - public static final String TYPE_SET_INDICATOR = "setIndicator"; - public static final String TYPE_CONFIGURATION = "configuration"; - public static final String TYPE_GET_VERSION = "getVersion"; - public static final String TYPE_FIRMWARE_UPDATE = "firmwareUpdate"; - public static final String TYPE_SET_CONNECTION = "setConnection"; - public static final String TYPE_SET_ODOMETER = "setOdometer"; - public static final String TYPE_GET_MODEM_STATUS = "getModemStatus"; - public static final String TYPE_GET_DEVICE_STATUS = "getDeviceStatus"; - - public static final String TYPE_MODE_POWER_SAVING = "modePowerSaving"; - public static final String TYPE_MODE_DEEP_SLEEP = "modeDeepSleep"; - - public static final String TYPE_ALARM_GEOFENCE = "movementAlarm"; - public static final String TYPE_ALARM_BATTERY = "alarmBattery"; - public static final String TYPE_ALARM_SOS = "alarmSos"; - public static final String TYPE_ALARM_REMOVE = "alarmRemove"; - public static final String TYPE_ALARM_CLOCK = "alarmClock"; - public static final String TYPE_ALARM_SPEED = "alarmSpeed"; - public static final String TYPE_ALARM_FALL = "alarmFall"; - public static final String TYPE_ALARM_VIBRATION = "alarmVibration"; - - public static final String KEY_UNIQUE_ID = "uniqueId"; - public static final String KEY_FREQUENCY = "frequency"; - public static final String KEY_TIMEZONE = "timezone"; - public static final String KEY_DEVICE_PASSWORD = "devicePassword"; - public static final String KEY_RADIUS = "radius"; - public static final String KEY_MESSAGE = "message"; - public static final String KEY_ENABLE = "enable"; - public static final String KEY_DATA = "data"; - public static final String KEY_INDEX = "index"; - public static final String KEY_PHONE = "phone"; - public static final String KEY_SERVER = "server"; - public static final String KEY_PORT = "port"; - - @Override - public Command clone() throws CloneNotSupportedException { - return (Command) super.clone(); - } - - private boolean textChannel; - - public boolean getTextChannel() { - return textChannel; - } - - public void setTextChannel(boolean textChannel) { - this.textChannel = textChannel; - } - - @QueryIgnore - @Override - public long getDeviceId() { - return super.getDeviceId(); - } - - private String description; - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - -} diff --git a/src/org/traccar/model/Device.java b/src/org/traccar/model/Device.java deleted file mode 100644 index 0c9be932d..000000000 --- a/src/org/traccar/model/Device.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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. - * 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.model; - -import java.util.Date; -import java.util.List; - -import org.traccar.database.QueryExtended; -import org.traccar.database.QueryIgnore; - -public class Device extends GroupedModel { - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - private String uniqueId; - - public String getUniqueId() { - return uniqueId; - } - - public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId; - } - - public static final String STATUS_UNKNOWN = "unknown"; - public static final String STATUS_ONLINE = "online"; - public static final String STATUS_OFFLINE = "offline"; - - private String status; - - @QueryIgnore - public String getStatus() { - return status != null ? status : STATUS_OFFLINE; - } - - public void setStatus(String status) { - this.status = status; - } - - private Date lastUpdate; - - @QueryExtended - public Date getLastUpdate() { - if (lastUpdate != null) { - return new Date(lastUpdate.getTime()); - } else { - return null; - } - } - - public void setLastUpdate(Date lastUpdate) { - if (lastUpdate != null) { - this.lastUpdate = new Date(lastUpdate.getTime()); - } else { - this.lastUpdate = null; - } - } - - private long positionId; - - @QueryIgnore - public long getPositionId() { - return positionId; - } - - public void setPositionId(long positionId) { - this.positionId = positionId; - } - - private List geofenceIds; - - @QueryIgnore - public List getGeofenceIds() { - return geofenceIds; - } - - public void setGeofenceIds(List geofenceIds) { - this.geofenceIds = geofenceIds; - } - - private String phone; - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - private String model; - - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - - private String contact; - - public String getContact() { - return contact; - } - - public void setContact(String contact) { - this.contact = contact; - } - - private String category; - - public String getCategory() { - return category; - } - - public void setCategory(String category) { - this.category = category; - } - - private boolean disabled; - - public boolean getDisabled() { - return disabled; - } - - public void setDisabled(boolean disabled) { - this.disabled = disabled; - } - -} diff --git a/src/org/traccar/model/DeviceAccumulators.java b/src/org/traccar/model/DeviceAccumulators.java deleted file mode 100644 index 8a90826c4..000000000 --- a/src/org/traccar/model/DeviceAccumulators.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class DeviceAccumulators { - - private long deviceId; - - public long getDeviceId() { - return deviceId; - } - - public void setDeviceId(long deviceId) { - this.deviceId = deviceId; - } - - private Double totalDistance; - - public Double getTotalDistance() { - return totalDistance; - } - - public void setTotalDistance(Double totalDistance) { - this.totalDistance = totalDistance; - } - - private Long hours; - - public Long getHours() { - return hours; - } - - public void setHours(Long hours) { - this.hours = hours; - } - -} diff --git a/src/org/traccar/model/DeviceState.java b/src/org/traccar/model/DeviceState.java deleted file mode 100644 index 75d6726ee..000000000 --- a/src/org/traccar/model/DeviceState.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class DeviceState { - - private Boolean motionState; - - public void setMotionState(boolean motionState) { - this.motionState = motionState; - } - - public Boolean getMotionState() { - return motionState; - } - - private Position motionPosition; - - public void setMotionPosition(Position motionPosition) { - this.motionPosition = motionPosition; - } - - public Position getMotionPosition() { - return motionPosition; - } - - private Boolean overspeedState; - - public void setOverspeedState(boolean overspeedState) { - this.overspeedState = overspeedState; - } - - public Boolean getOverspeedState() { - return overspeedState; - } - - private Position overspeedPosition; - - public void setOverspeedPosition(Position overspeedPosition) { - this.overspeedPosition = overspeedPosition; - } - - public Position getOverspeedPosition() { - return overspeedPosition; - } - - private long overspeedGeofenceId; - - public void setOverspeedGeofenceId(long overspeedGeofenceId) { - this.overspeedGeofenceId = overspeedGeofenceId; - } - - public long getOverspeedGeofenceId() { - return overspeedGeofenceId; - } - -} diff --git a/src/org/traccar/model/Driver.java b/src/org/traccar/model/Driver.java deleted file mode 100644 index 05f52fd4d..000000000 --- a/src/org/traccar/model/Driver.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class Driver extends ExtendedModel { - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - private String uniqueId; - - public String getUniqueId() { - return uniqueId; - } - - public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId; - } -} diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java deleted file mode 100644 index ee7fcc679..000000000 --- a/src/org/traccar/model/Event.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.model; - -import java.util.Date; - -public class Event extends Message { - - public Event(String type, long deviceId, long positionId) { - this(type, deviceId); - setPositionId(positionId); - } - - public Event(String type, long deviceId) { - setType(type); - setDeviceId(deviceId); - this.serverTime = new Date(); - } - - public Event() { - } - - public static final String ALL_EVENTS = "allEvents"; - - public static final String TYPE_COMMAND_RESULT = "commandResult"; - - public static final String TYPE_DEVICE_ONLINE = "deviceOnline"; - public static final String TYPE_DEVICE_UNKNOWN = "deviceUnknown"; - public static final String TYPE_DEVICE_OFFLINE = "deviceOffline"; - - public static final String TYPE_DEVICE_MOVING = "deviceMoving"; - public static final String TYPE_DEVICE_STOPPED = "deviceStopped"; - - public static final String TYPE_DEVICE_OVERSPEED = "deviceOverspeed"; - public static final String TYPE_DEVICE_FUEL_DROP = "deviceFuelDrop"; - - public static final String TYPE_GEOFENCE_ENTER = "geofenceEnter"; - public static final String TYPE_GEOFENCE_EXIT = "geofenceExit"; - - public static final String TYPE_ALARM = "alarm"; - - public static final String TYPE_IGNITION_ON = "ignitionOn"; - public static final String TYPE_IGNITION_OFF = "ignitionOff"; - - public static final String TYPE_MAINTENANCE = "maintenance"; - - public static final String TYPE_TEXT_MESSAGE = "textMessage"; - - public static final String TYPE_DRIVER_CHANGED = "driverChanged"; - - private Date serverTime; - - public Date getServerTime() { - return serverTime; - } - - public void setServerTime(Date serverTime) { - this.serverTime = serverTime; - } - - private long positionId; - - public long getPositionId() { - return positionId; - } - - public void setPositionId(long positionId) { - this.positionId = positionId; - } - - private long geofenceId = 0; - - public long getGeofenceId() { - return geofenceId; - } - - public void setGeofenceId(long geofenceId) { - this.geofenceId = geofenceId; - } - - private long maintenanceId = 0; - - public long getMaintenanceId() { - return maintenanceId; - } - - public void setMaintenanceId(long maintenanceId) { - this.maintenanceId = maintenanceId; - } - -} diff --git a/src/org/traccar/model/ExtendedModel.java b/src/org/traccar/model/ExtendedModel.java deleted file mode 100644 index 8353d0e66..000000000 --- a/src/org/traccar/model/ExtendedModel.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.model; - -import java.util.LinkedHashMap; -import java.util.Map; - -public class ExtendedModel extends BaseModel { - - private Map attributes = new LinkedHashMap<>(); - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public void set(String key, Boolean value) { - if (value != null) { - attributes.put(key, value); - } - } - - public void set(String key, Byte value) { - if (value != null) { - attributes.put(key, value.intValue()); - } - } - - public void set(String key, Short value) { - if (value != null) { - attributes.put(key, value.intValue()); - } - } - - public void set(String key, Integer value) { - if (value != null) { - attributes.put(key, value); - } - } - - public void set(String key, Long value) { - if (value != null) { - attributes.put(key, value); - } - } - - public void set(String key, Float value) { - if (value != null) { - attributes.put(key, value.doubleValue()); - } - } - - public void set(String key, Double value) { - if (value != null) { - attributes.put(key, value); - } - } - - public void set(String key, String value) { - if (value != null && !value.isEmpty()) { - attributes.put(key, value); - } - } - - public void add(Map.Entry entry) { - if (entry != null && entry.getValue() != null) { - attributes.put(entry.getKey(), entry.getValue()); - } - } - - public String getString(String key) { - if (attributes.containsKey(key)) { - return (String) attributes.get(key); - } else { - return null; - } - } - - public double getDouble(String key) { - if (attributes.containsKey(key)) { - return ((Number) attributes.get(key)).doubleValue(); - } else { - return 0.0; - } - } - - public boolean getBoolean(String key) { - if (attributes.containsKey(key)) { - return (Boolean) attributes.get(key); - } else { - return false; - } - } - - public int getInteger(String key) { - if (attributes.containsKey(key)) { - return ((Number) attributes.get(key)).intValue(); - } else { - return 0; - } - } - - public long getLong(String key) { - if (attributes.containsKey(key)) { - return ((Number) attributes.get(key)).longValue(); - } else { - return 0; - } - } - -} diff --git a/src/org/traccar/model/Geofence.java b/src/org/traccar/model/Geofence.java deleted file mode 100644 index 8560d22e9..000000000 --- a/src/org/traccar/model/Geofence.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2016 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. - * 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.model; - -import java.text.ParseException; - -import org.traccar.Context; -import org.traccar.database.QueryIgnore; -import org.traccar.geofence.GeofenceCircle; -import org.traccar.geofence.GeofenceGeometry; -import org.traccar.geofence.GeofencePolygon; -import org.traccar.geofence.GeofencePolyline; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -public class Geofence extends ScheduledModel { - - public static final String TYPE_GEOFENCE_CILCLE = "geofenceCircle"; - public static final String TYPE_GEOFENCE_POLYGON = "geofencePolygon"; - public static final String TYPE_GEOFENCE_POLYLINE = "geofencePolyline"; - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - private String description; - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - private String area; - - public String getArea() { - return area; - } - - public void setArea(String area) throws ParseException { - - if (area.startsWith("CIRCLE")) { - geometry = new GeofenceCircle(area); - } else if (area.startsWith("POLYGON")) { - geometry = new GeofencePolygon(area); - } else if (area.startsWith("LINESTRING")) { - final double distance = getDouble("polylineDistance"); - geometry = new GeofencePolyline(area, distance > 0 ? distance - : Context.getConfig().getDouble("geofence.polylineDistance", 25)); - } else { - throw new ParseException("Unknown geometry type", 0); - } - - this.area = area; - } - - private GeofenceGeometry geometry; - - @QueryIgnore - @JsonIgnore - public GeofenceGeometry getGeometry() { - return geometry; - } - - @QueryIgnore - @JsonIgnore - public void setGeometry(GeofenceGeometry geometry) { - area = geometry.toWkt(); - this.geometry = geometry; - } -} diff --git a/src/org/traccar/model/Group.java b/src/org/traccar/model/Group.java deleted file mode 100644 index 91ea2319d..000000000 --- a/src/org/traccar/model/Group.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.model; - -public class Group extends GroupedModel { - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - -} diff --git a/src/org/traccar/model/GroupedModel.java b/src/org/traccar/model/GroupedModel.java deleted file mode 100644 index 6b1aa75b1..000000000 --- a/src/org/traccar/model/GroupedModel.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class GroupedModel extends ExtendedModel { - - private long groupId; - - public long getGroupId() { - return groupId; - } - - public void setGroupId(long groupId) { - this.groupId = groupId; - } - -} diff --git a/src/org/traccar/model/Maintenance.java b/src/org/traccar/model/Maintenance.java deleted file mode 100644 index 73f67ea96..000000000 --- a/src/org/traccar/model/Maintenance.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class Maintenance extends ExtendedModel { - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - private String type; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - private double start; - - public double getStart() { - return start; - } - - public void setStart(double start) { - this.start = start; - } - - private double period; - - public double getPeriod() { - return period; - } - - public void setPeriod(double period) { - this.period = period; - } - -} diff --git a/src/org/traccar/model/ManagedUser.java b/src/org/traccar/model/ManagedUser.java deleted file mode 100644 index 03c5ef48d..000000000 --- a/src/org/traccar/model/ManagedUser.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class ManagedUser extends User { - -} diff --git a/src/org/traccar/model/Message.java b/src/org/traccar/model/Message.java deleted file mode 100644 index dad9c20f0..000000000 --- a/src/org/traccar/model/Message.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013 - 2016 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. - * 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.model; - -public class Message extends ExtendedModel { - - private long deviceId; - - public long getDeviceId() { - return deviceId; - } - - public void setDeviceId(long deviceId) { - this.deviceId = deviceId; - } - - private String type; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - -} diff --git a/src/org/traccar/model/MiscFormatter.java b/src/org/traccar/model/MiscFormatter.java deleted file mode 100644 index c6511f063..000000000 --- a/src/org/traccar/model/MiscFormatter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013 - 2016 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. - * 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.model; - - -import java.text.DecimalFormat; -import java.util.Map; - -public final class MiscFormatter { - - private MiscFormatter() { - } - - private static final String XML_ROOT_NODE = "info"; - - private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##"); - - private static String format(Object value) { - if (value instanceof Double || value instanceof Float) { - return DECIMAL_FORMAT.format(value); - } else { - return value.toString(); - } - } - - public static String toXmlString(Map attributes) { - StringBuilder result = new StringBuilder(); - - result.append("<").append(XML_ROOT_NODE).append(">"); - - for (Map.Entry entry : attributes.entrySet()) { - - result.append("<").append(entry.getKey()).append(">"); - result.append(format(entry.getValue())); - result.append(""); - } - - result.append(""); - - return result.toString(); - } - -} diff --git a/src/org/traccar/model/Network.java b/src/org/traccar/model/Network.java deleted file mode 100644 index 2d56950f1..000000000 --- a/src/org/traccar/model/Network.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2016 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. - * 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.model; - -import com.fasterxml.jackson.annotation.JsonInclude; - -import java.util.ArrayList; -import java.util.Collection; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Network { - - public Network() { - } - - public Network(CellTower cellTower) { - addCellTower(cellTower); - } - - private Integer homeMobileCountryCode; - - public Integer getHomeMobileCountryCode() { - return homeMobileCountryCode; - } - - public void setHomeMobileCountryCode(Integer homeMobileCountryCode) { - this.homeMobileCountryCode = homeMobileCountryCode; - } - - private Integer homeMobileNetworkCode; - - public Integer getHomeMobileNetworkCode() { - return homeMobileNetworkCode; - } - - public void setHomeMobileNetworkCode(Integer homeMobileNetworkCode) { - this.homeMobileNetworkCode = homeMobileNetworkCode; - } - - private String radioType = "gsm"; - - public String getRadioType() { - return radioType; - } - - public void setRadioType(String radioType) { - this.radioType = radioType; - } - - private String carrier; - - public String getCarrier() { - return carrier; - } - - public void setCarrier(String carrier) { - this.carrier = carrier; - } - - private Boolean considerIp = false; - - public Boolean getConsiderIp() { - return considerIp; - } - - public void setConsiderIp(Boolean considerIp) { - this.considerIp = considerIp; - } - - private Collection cellTowers; - - public Collection getCellTowers() { - return cellTowers; - } - - public void setCellTowers(Collection cellTowers) { - this.cellTowers = cellTowers; - } - - public void addCellTower(CellTower cellTower) { - if (cellTowers == null) { - cellTowers = new ArrayList<>(); - } - cellTowers.add(cellTower); - } - - private Collection wifiAccessPoints; - - public Collection getWifiAccessPoints() { - return wifiAccessPoints; - } - - public void setWifiAccessPoints(Collection wifiAccessPoints) { - this.wifiAccessPoints = wifiAccessPoints; - } - - public void addWifiAccessPoint(WifiAccessPoint wifiAccessPoint) { - if (wifiAccessPoints == null) { - wifiAccessPoints = new ArrayList<>(); - } - wifiAccessPoints.add(wifiAccessPoint); - } - -} diff --git a/src/org/traccar/model/Notification.java b/src/org/traccar/model/Notification.java deleted file mode 100644 index f1983a03a..000000000 --- a/src/org/traccar/model/Notification.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.model; - -import java.util.HashSet; -import java.util.Set; - -import org.traccar.database.QueryIgnore; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -public class Notification extends ScheduledModel { - - private boolean always; - - public boolean getAlways() { - return always; - } - - public void setAlways(boolean always) { - this.always = always; - } - - private String type; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - - private String notificators; - - public String getNotificators() { - return notificators; - } - - public void setNotificators(String transports) { - this.notificators = transports; - } - - - @JsonIgnore - @QueryIgnore - public Set getNotificatorsTypes() { - final Set result = new HashSet<>(); - if (notificators != null) { - final String[] transportsList = notificators.split(","); - for (String transport : transportsList) { - result.add(transport.trim()); - } - } - return result; - } - -} diff --git a/src/org/traccar/model/Permission.java b/src/org/traccar/model/Permission.java deleted file mode 100644 index 1006b1c47..000000000 --- a/src/org/traccar/model/Permission.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.traccar.database.DataManager; - -public class Permission { - - private Class ownerClass; - private long ownerId; - private Class propertyClass; - private long propertyId; - - public Permission(LinkedHashMap permissionMap) throws ClassNotFoundException { - Iterator> iterator = permissionMap.entrySet().iterator(); - String owner = iterator.next().getKey(); - ownerClass = DataManager.getClassByName(owner); - String property = iterator.next().getKey(); - propertyClass = DataManager.getClassByName(property); - ownerId = permissionMap.get(owner); - propertyId = permissionMap.get(property); - } - - public Class getOwnerClass() { - return ownerClass; - } - - public long getOwnerId() { - return ownerId; - } - - public Class getPropertyClass() { - return propertyClass; - } - - public long getPropertyId() { - return propertyId; - } -} diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java deleted file mode 100644 index 4b327cbd2..000000000 --- a/src/org/traccar/model/Position.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright 2012 - 2016 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. - * 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.model; - -import java.util.Date; - -import org.traccar.database.QueryIgnore; - -public class Position extends Message { - - public static final String KEY_ORIGINAL = "raw"; - public static final String KEY_INDEX = "index"; - public static final String KEY_HDOP = "hdop"; - public static final String KEY_VDOP = "vdop"; - public static final String KEY_PDOP = "pdop"; - public static final String KEY_SATELLITES = "sat"; // in use - public static final String KEY_SATELLITES_VISIBLE = "satVisible"; - public static final String KEY_RSSI = "rssi"; - public static final String KEY_GPS = "gps"; - public static final String KEY_ROAMING = "roaming"; - public static final String KEY_EVENT = "event"; - public static final String KEY_ALARM = "alarm"; - public static final String KEY_STATUS = "status"; - public static final String KEY_ODOMETER = "odometer"; // meters - public static final String KEY_ODOMETER_SERVICE = "serviceOdometer"; // meters - public static final String KEY_ODOMETER_TRIP = "tripOdometer"; // meters - public static final String KEY_HOURS = "hours"; - public static final String KEY_STEPS = "steps"; - public static final String KEY_HEART_RATE = "heartRate"; - public static final String KEY_INPUT = "input"; - public static final String KEY_OUTPUT = "output"; - public static final String KEY_IMAGE = "image"; - public static final String KEY_VIDEO = "video"; - public static final String KEY_AUDIO = "audio"; - - // The units for the below four KEYs currently vary. - // The preferred units of measure are specified in the comment for each. - public static final String KEY_POWER = "power"; // volts - public static final String KEY_BATTERY = "battery"; // volts - public static final String KEY_BATTERY_LEVEL = "batteryLevel"; // percentage - public static final String KEY_FUEL_LEVEL = "fuel"; // liters - public static final String KEY_FUEL_USED = "fuelUsed"; // liters - public static final String KEY_FUEL_CONSUMPTION = "fuelConsumption"; // liters/hour - - public static final String KEY_VERSION_FW = "versionFw"; - public static final String KEY_VERSION_HW = "versionHw"; - public static final String KEY_TYPE = "type"; - public static final String KEY_IGNITION = "ignition"; - public static final String KEY_FLAGS = "flags"; - public static final String KEY_ANTENNA = "antenna"; - public static final String KEY_CHARGE = "charge"; - public static final String KEY_IP = "ip"; - public static final String KEY_ARCHIVE = "archive"; - public static final String KEY_DISTANCE = "distance"; // meters - public static final String KEY_TOTAL_DISTANCE = "totalDistance"; // meters - public static final String KEY_RPM = "rpm"; - public static final String KEY_VIN = "vin"; - public static final String KEY_APPROXIMATE = "approximate"; - public static final String KEY_THROTTLE = "throttle"; - public static final String KEY_MOTION = "motion"; - public static final String KEY_ARMED = "armed"; - public static final String KEY_GEOFENCE = "geofence"; - public static final String KEY_ACCELERATION = "acceleration"; - public static final String KEY_DEVICE_TEMP = "deviceTemp"; // celsius - public static final String KEY_COOLANT_TEMP = "coolantTemp"; // celsius - public static final String KEY_ENGINE_LOAD = "engineLoad"; - public static final String KEY_OPERATOR = "operator"; - public static final String KEY_COMMAND = "command"; - public static final String KEY_BLOCKED = "blocked"; - public static final String KEY_DOOR = "door"; - public static final String KEY_AXLE_WEIGHT = "axleWeight"; - - public static final String KEY_DTCS = "dtcs"; - public static final String KEY_OBD_SPEED = "obdSpeed"; // knots - public static final String KEY_OBD_ODOMETER = "obdOdometer"; // meters - - public static final String KEY_RESULT = "result"; - - public static final String KEY_DRIVER_UNIQUE_ID = "driverUniqueId"; - - // Start with 1 not 0 - public static final String PREFIX_TEMP = "temp"; - public static final String PREFIX_ADC = "adc"; - public static final String PREFIX_IO = "io"; - public static final String PREFIX_COUNT = "count"; - public static final String PREFIX_IN = "in"; - public static final String PREFIX_OUT = "out"; - - public static final String ALARM_GENERAL = "general"; - public static final String ALARM_SOS = "sos"; - public static final String ALARM_VIBRATION = "vibration"; - public static final String ALARM_MOVEMENT = "movement"; - public static final String ALARM_LOW_SPEED = "lowspeed"; - public static final String ALARM_OVERSPEED = "overspeed"; - public static final String ALARM_FALL_DOWN = "fallDown"; - public static final String ALARM_LOW_POWER = "lowPower"; - public static final String ALARM_LOW_BATTERY = "lowBattery"; - public static final String ALARM_FAULT = "fault"; - public static final String ALARM_POWER_OFF = "powerOff"; - public static final String ALARM_POWER_ON = "powerOn"; - public static final String ALARM_DOOR = "door"; - public static final String ALARM_LOCK = "lock"; - public static final String ALARM_UNLOCK = "unlock"; - public static final String ALARM_GEOFENCE = "geofence"; - public static final String ALARM_GEOFENCE_ENTER = "geofenceEnter"; - public static final String ALARM_GEOFENCE_EXIT = "geofenceExit"; - public static final String ALARM_GPS_ANTENNA_CUT = "gpsAntennaCut"; - public static final String ALARM_ACCIDENT = "accident"; - public static final String ALARM_TOW = "tow"; - public static final String ALARM_IDLE = "idle"; - public static final String ALARM_HIGH_RPM = "highRpm"; - public static final String ALARM_ACCELERATION = "hardAcceleration"; - public static final String ALARM_BRAKING = "hardBraking"; - public static final String ALARM_CORNERING = "hardCornering"; - public static final String ALARM_LANE_CHANGE = "laneChange"; - public static final String ALARM_FATIGUE_DRIVING = "fatigueDriving"; - public static final String ALARM_POWER_CUT = "powerCut"; - public static final String ALARM_POWER_RESTORED = "powerRestored"; - public static final String ALARM_JAMMING = "jamming"; - public static final String ALARM_TEMPERATURE = "temperature"; - public static final String ALARM_PARKING = "parking"; - public static final String ALARM_SHOCK = "shock"; - public static final String ALARM_BONNET = "bonnet"; - public static final String ALARM_FOOT_BRAKE = "footBrake"; - public static final String ALARM_FUEL_LEAK = "fuelLeak"; - public static final String ALARM_TAMPERING = "tampering"; - public static final String ALARM_REMOVING = "removing"; - - public Position() { - } - - public Position(String protocol) { - this.protocol = protocol; - this.serverTime = new Date(); - } - - private String protocol; - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - private Date serverTime; - - public Date getServerTime() { - return serverTime; - } - - public void setServerTime(Date serverTime) { - this.serverTime = serverTime; - } - - private Date deviceTime; - - public Date getDeviceTime() { - return deviceTime; - } - - public void setDeviceTime(Date deviceTime) { - this.deviceTime = deviceTime; - } - - private Date fixTime; - - public Date getFixTime() { - return fixTime; - } - - public void setFixTime(Date fixTime) { - this.fixTime = fixTime; - } - - public void setTime(Date time) { - setDeviceTime(time); - setFixTime(time); - } - - private boolean outdated; - - @QueryIgnore - public boolean getOutdated() { - return outdated; - } - - public void setOutdated(boolean outdated) { - this.outdated = outdated; - } - - private boolean valid; - - public boolean getValid() { - return valid; - } - - public void setValid(boolean valid) { - this.valid = valid; - } - - private double latitude; - - public double getLatitude() { - return latitude; - } - - public void setLatitude(double latitude) { - this.latitude = latitude; - } - - private double longitude; - - public double getLongitude() { - return longitude; - } - - public void setLongitude(double longitude) { - this.longitude = longitude; - } - - private double altitude; // value in meters - - public double getAltitude() { - return altitude; - } - - public void setAltitude(double altitude) { - this.altitude = altitude; - } - - private double speed; // value in knots - - public double getSpeed() { - return speed; - } - - public void setSpeed(double speed) { - this.speed = speed; - } - - private double course; - - public double getCourse() { - return course; - } - - public void setCourse(double course) { - this.course = course; - } - - private String address; - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - private double accuracy; - - public double getAccuracy() { - return accuracy; - } - - public void setAccuracy(double accuracy) { - this.accuracy = accuracy; - } - - private Network network; - - public Network getNetwork() { - return network; - } - - public void setNetwork(Network network) { - this.network = network; - } - - @Override - @QueryIgnore - public String getType() { - return super.getType(); - } - -} diff --git a/src/org/traccar/model/ScheduledModel.java b/src/org/traccar/model/ScheduledModel.java deleted file mode 100644 index 9e6a4b9a6..000000000 --- a/src/org/traccar/model/ScheduledModel.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.model; - -public class ScheduledModel extends ExtendedModel { - - private long calendarId; - - public long getCalendarId() { - return calendarId; - } - - public void setCalendarId(long calendarId) { - this.calendarId = calendarId; - } -} diff --git a/src/org/traccar/model/Server.java b/src/org/traccar/model/Server.java deleted file mode 100644 index ad37e7078..000000000 --- a/src/org/traccar/model/Server.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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.model; - -import org.traccar.database.QueryIgnore; - -public class Server extends ExtendedModel { - - @QueryIgnore - public String getVersion() { - return getClass().getPackage().getImplementationVersion(); - } - - public void setVersion(String version) { - } - - private boolean registration; - - public boolean getRegistration() { - return registration; - } - - public void setRegistration(boolean registration) { - this.registration = registration; - } - - private boolean readonly; - - public boolean getReadonly() { - return readonly; - } - - public void setReadonly(boolean readonly) { - this.readonly = readonly; - } - - private boolean deviceReadonly; - - public boolean getDeviceReadonly() { - return deviceReadonly; - } - - public void setDeviceReadonly(boolean deviceReadonly) { - this.deviceReadonly = deviceReadonly; - } - - private String map; - - public String getMap() { - return map; - } - - public void setMap(String map) { - this.map = map; - } - - private String bingKey; - - public String getBingKey() { - return bingKey; - } - - public void setBingKey(String bingKey) { - this.bingKey = bingKey; - } - - private String mapUrl; - - public String getMapUrl() { - return mapUrl; - } - - public void setMapUrl(String mapUrl) { - this.mapUrl = mapUrl; - } - - private double latitude; - - public double getLatitude() { - return latitude; - } - - public void setLatitude(double latitude) { - this.latitude = latitude; - } - - private double longitude; - - public double getLongitude() { - return longitude; - } - - public void setLongitude(double longitude) { - this.longitude = longitude; - } - - private int zoom; - - public int getZoom() { - return zoom; - } - - public void setZoom(int zoom) { - this.zoom = zoom; - } - - private boolean twelveHourFormat; - - public boolean getTwelveHourFormat() { - return twelveHourFormat; - } - - public void setTwelveHourFormat(boolean twelveHourFormat) { - this.twelveHourFormat = twelveHourFormat; - } - - private boolean forceSettings; - - public boolean getForceSettings() { - return forceSettings; - } - - public void setForceSettings(boolean forceSettings) { - this.forceSettings = forceSettings; - } - - private String coordinateFormat; - - public String getCoordinateFormat() { - return coordinateFormat; - } - - public void setCoordinateFormat(String coordinateFormat) { - this.coordinateFormat = coordinateFormat; - } - - private boolean limitCommands; - - public boolean getLimitCommands() { - return limitCommands; - } - - public void setLimitCommands(boolean limitCommands) { - this.limitCommands = limitCommands; - } - - private String poiLayer; - - public String getPoiLayer() { - return poiLayer; - } - - public void setPoiLayer(String poiLayer) { - this.poiLayer = poiLayer; - } -} diff --git a/src/org/traccar/model/Statistics.java b/src/org/traccar/model/Statistics.java deleted file mode 100644 index cb72c91dd..000000000 --- a/src/org/traccar/model/Statistics.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.model; - -import java.util.Date; - -public class Statistics extends ExtendedModel { - - private Date captureTime; - - public Date getCaptureTime() { - return captureTime; - } - - public void setCaptureTime(Date captureTime) { - this.captureTime = captureTime; - } - - private int activeUsers; - - public int getActiveUsers() { - return activeUsers; - } - - public void setActiveUsers(int activeUsers) { - this.activeUsers = activeUsers; - } - - private int activeDevices; - - public int getActiveDevices() { - return activeDevices; - } - - public void setActiveDevices(int activeDevices) { - this.activeDevices = activeDevices; - } - - private int requests; - - public int getRequests() { - return requests; - } - - public void setRequests(int requests) { - this.requests = requests; - } - - private int messagesReceived; - - public int getMessagesReceived() { - return messagesReceived; - } - - public void setMessagesReceived(int messagesReceived) { - this.messagesReceived = messagesReceived; - } - - private int messagesStored; - - public int getMessagesStored() { - return messagesStored; - } - - public void setMessagesStored(int messagesStored) { - this.messagesStored = messagesStored; - } - - private int mailSent; - - public int getMailSent() { - return mailSent; - } - - public void setMailSent(int mailSent) { - this.mailSent = mailSent; - } - - private int smsSent; - - public int getSmsSent() { - return smsSent; - } - - public void setSmsSent(int smsSent) { - this.smsSent = smsSent; - } - - private int geocoderRequests; - - public int getGeocoderRequests() { - return geocoderRequests; - } - - public void setGeocoderRequests(int geocoderRequests) { - this.geocoderRequests = geocoderRequests; - } - - private int geolocationRequests; - - public int getGeolocationRequests() { - return geolocationRequests; - } - - public void setGeolocationRequests(int geolocationRequests) { - this.geolocationRequests = geolocationRequests; - } - -} diff --git a/src/org/traccar/model/Typed.java b/src/org/traccar/model/Typed.java deleted file mode 100644 index 313ec7bcd..000000000 --- a/src/org/traccar/model/Typed.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@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.model; - -public class Typed { - - private String type; - - public Typed(String type) { - this.type = type; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } -} diff --git a/src/org/traccar/model/User.java b/src/org/traccar/model/User.java deleted file mode 100644 index 976b6aac0..000000000 --- a/src/org/traccar/model/User.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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.model; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import org.traccar.database.QueryExtended; -import org.traccar.database.QueryIgnore; -import org.traccar.helper.Hashing; - -import java.util.Date; - -public class User extends ExtendedModel { - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - private String login; - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - private String email; - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email.trim(); - } - - private String phone; - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - private boolean readonly; - - public boolean getReadonly() { - return readonly; - } - - public void setReadonly(boolean readonly) { - this.readonly = readonly; - } - - private boolean administrator; - - public boolean getAdministrator() { - return administrator; - } - - public void setAdministrator(boolean administrator) { - this.administrator = administrator; - } - - private String map; - - public String getMap() { - return map; - } - - public void setMap(String map) { - this.map = map; - } - - private double latitude; - - public double getLatitude() { - return latitude; - } - - public void setLatitude(double latitude) { - this.latitude = latitude; - } - - private double longitude; - - public double getLongitude() { - return longitude; - } - - public void setLongitude(double longitude) { - this.longitude = longitude; - } - - private int zoom; - - public int getZoom() { - return zoom; - } - - public void setZoom(int zoom) { - this.zoom = zoom; - } - - private boolean twelveHourFormat; - - public boolean getTwelveHourFormat() { - return twelveHourFormat; - } - - public void setTwelveHourFormat(boolean twelveHourFormat) { - this.twelveHourFormat = twelveHourFormat; - } - - private String coordinateFormat; - - public String getCoordinateFormat() { - return coordinateFormat; - } - - public void setCoordinateFormat(String coordinateFormat) { - this.coordinateFormat = coordinateFormat; - } - - private boolean disabled; - - public boolean getDisabled() { - return disabled; - } - - public void setDisabled(boolean disabled) { - this.disabled = disabled; - } - - private Date expirationTime; - - public Date getExpirationTime() { - return expirationTime; - } - - public void setExpirationTime(Date expirationTime) { - this.expirationTime = expirationTime; - } - - private int deviceLimit; - - public int getDeviceLimit() { - return deviceLimit; - } - - public void setDeviceLimit(int deviceLimit) { - this.deviceLimit = deviceLimit; - } - - private int userLimit; - - public int getUserLimit() { - return userLimit; - } - - public void setUserLimit(int userLimit) { - this.userLimit = userLimit; - } - - private boolean deviceReadonly; - - public boolean getDeviceReadonly() { - return deviceReadonly; - } - - public void setDeviceReadonly(boolean deviceReadonly) { - this.deviceReadonly = deviceReadonly; - } - - private String token; - - public String getToken() { - return token; - } - - public void setToken(String token) { - if (token != null && !token.isEmpty()) { - if (!token.matches("^[a-zA-Z0-9-]{16,}$")) { - throw new IllegalArgumentException("Illegal token"); - } - this.token = token; - } else { - this.token = null; - } - } - - private boolean limitCommands; - - public boolean getLimitCommands() { - return limitCommands; - } - - public void setLimitCommands(boolean limitCommands) { - this.limitCommands = limitCommands; - } - - private String poiLayer; - - public String getPoiLayer() { - return poiLayer; - } - - public void setPoiLayer(String poiLayer) { - this.poiLayer = poiLayer; - } - - @QueryIgnore - public String getPassword() { - return null; - } - - public void setPassword(String password) { - if (password != null && !password.isEmpty()) { - Hashing.HashingResult hashingResult = Hashing.createHash(password); - hashedPassword = hashingResult.getHash(); - salt = hashingResult.getSalt(); - } - } - - private String hashedPassword; - - @JsonIgnore - @QueryExtended - public String getHashedPassword() { - return hashedPassword; - } - - public void setHashedPassword(String hashedPassword) { - this.hashedPassword = hashedPassword; - } - - private String salt; - - @JsonIgnore - @QueryExtended - public String getSalt() { - return salt; - } - - public void setSalt(String salt) { - this.salt = salt; - } - - public boolean isPasswordValid(String password) { - return Hashing.validatePassword(password, hashedPassword, salt); - } - -} diff --git a/src/org/traccar/model/WifiAccessPoint.java b/src/org/traccar/model/WifiAccessPoint.java deleted file mode 100644 index 87a77f3c0..000000000 --- a/src/org/traccar/model/WifiAccessPoint.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2016 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. - * 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.model; - -import com.fasterxml.jackson.annotation.JsonInclude; - -@JsonInclude(JsonInclude.Include.NON_NULL) -public class WifiAccessPoint { - - public static WifiAccessPoint from(String macAddress, int signalStrength) { - WifiAccessPoint wifiAccessPoint = new WifiAccessPoint(); - wifiAccessPoint.setMacAddress(macAddress); - wifiAccessPoint.setSignalStrength(signalStrength); - return wifiAccessPoint; - } - - public static WifiAccessPoint from(String macAddress, int signalStrength, int channel) { - WifiAccessPoint wifiAccessPoint = from(macAddress, signalStrength); - wifiAccessPoint.setChannel(channel); - return wifiAccessPoint; - } - - private String macAddress; - - public String getMacAddress() { - return macAddress; - } - - public void setMacAddress(String macAddress) { - this.macAddress = macAddress; - } - - private Integer signalStrength; - - public Integer getSignalStrength() { - return signalStrength; - } - - public void setSignalStrength(Integer signalStrength) { - this.signalStrength = signalStrength; - } - - private Integer channel; - - public Integer getChannel() { - return channel; - } - - public void setChannel(Integer channel) { - this.channel = channel; - } - -} diff --git a/src/org/traccar/notification/EventForwarder.java b/src/org/traccar/notification/EventForwarder.java deleted file mode 100644 index c0010ebbd..000000000 --- a/src/org/traccar/notification/EventForwarder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.notification; - -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Geofence; -import org.traccar.model.Maintenance; -import org.traccar.model.Position; - -import javax.ws.rs.client.AsyncInvoker; -import javax.ws.rs.client.Invocation; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -public abstract class EventForwarder { - - private final String url; - private final String header; - - public EventForwarder() { - url = Context.getConfig().getString("event.forward.url", "http://localhost/"); - header = Context.getConfig().getString("event.forward.header"); - } - - private static final String KEY_POSITION = "position"; - private static final String KEY_EVENT = "event"; - private static final String KEY_GEOFENCE = "geofence"; - private static final String KEY_DEVICE = "device"; - private static final String KEY_MAINTENANCE = "maintenance"; - private static final String KEY_USERS = "users"; - - public final void forwardEvent(Event event, Position position, Set users) { - - Invocation.Builder requestBuilder = Context.getClient().target(url).request(); - - if (header != null && !header.isEmpty()) { - for (String line: header.split("\\r?\\n")) { - String[] values = line.split(":", 2); - requestBuilder.header(values[0].trim(), values[1].trim()); - } - } - - executeRequest(event, position, users, requestBuilder.async()); - } - - protected Map preparePayload(Event event, Position position, Set users) { - Map data = new HashMap<>(); - data.put(KEY_EVENT, event); - if (position != null) { - data.put(KEY_POSITION, position); - } - Device device = Context.getIdentityManager().getById(event.getDeviceId()); - if (device != null) { - data.put(KEY_DEVICE, device); - } - if (event.getGeofenceId() != 0) { - Geofence geofence = Context.getGeofenceManager().getById(event.getGeofenceId()); - if (geofence != null) { - data.put(KEY_GEOFENCE, geofence); - } - } - if (event.getMaintenanceId() != 0) { - Maintenance maintenance = Context.getMaintenancesManager().getById(event.getMaintenanceId()); - if (maintenance != null) { - data.put(KEY_MAINTENANCE, maintenance); - } - } - data.put(KEY_USERS, Context.getUsersManager().getItems(users)); - return data; - } - - protected abstract void executeRequest( - Event event, Position position, Set users, AsyncInvoker invoker); - -} diff --git a/src/org/traccar/notification/FullMessage.java b/src/org/traccar/notification/FullMessage.java deleted file mode 100644 index f66537c6e..000000000 --- a/src/org/traccar/notification/FullMessage.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notification; - -public class FullMessage { - - private String subject; - private String body; - - public FullMessage(String subject, String body) { - this.subject = subject; - this.body = body; - } - - public String getSubject() { - return subject; - } - - public String getBody() { - return body; - } -} diff --git a/src/org/traccar/notification/JsonTypeEventForwarder.java b/src/org/traccar/notification/JsonTypeEventForwarder.java deleted file mode 100644 index fcafb964a..000000000 --- a/src/org/traccar/notification/JsonTypeEventForwarder.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.traccar.notification; - -import java.util.Set; - -import org.traccar.model.Event; -import org.traccar.model.Position; - -import javax.ws.rs.client.AsyncInvoker; -import javax.ws.rs.client.Entity; - -public class JsonTypeEventForwarder extends EventForwarder { - - @Override - protected void executeRequest(Event event, Position position, Set users, AsyncInvoker invoker) { - invoker.post(Entity.json(preparePayload(event, position, users))); - } - -} diff --git a/src/org/traccar/notification/MessageException.java b/src/org/traccar/notification/MessageException.java deleted file mode 100644 index 710b927b0..000000000 --- a/src/org/traccar/notification/MessageException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notification; - -public class MessageException extends Exception { - - public MessageException(Throwable cause) { - super(cause); - } - - public MessageException(String message) { - super(message); - } - -} diff --git a/src/org/traccar/notification/NotificationFormatter.java b/src/org/traccar/notification/NotificationFormatter.java deleted file mode 100644 index 2f8100226..000000000 --- a/src/org/traccar/notification/NotificationFormatter.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notification; - -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.util.Locale; - -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.exception.ResourceNotFoundException; -import org.apache.velocity.tools.generic.DateTool; -import org.apache.velocity.tools.generic.NumberTool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.model.User; -import org.traccar.reports.ReportUtils; - -public final class NotificationFormatter { - - private static final Logger LOGGER = LoggerFactory.getLogger(NotificationFormatter.class); - - private NotificationFormatter() { - } - - public static VelocityContext prepareContext(long userId, Event event, Position position) { - - User user = Context.getPermissionsManager().getUser(userId); - Device device = Context.getIdentityManager().getById(event.getDeviceId()); - - VelocityContext velocityContext = new VelocityContext(); - velocityContext.put("user", user); - velocityContext.put("device", device); - velocityContext.put("event", event); - if (position != null) { - velocityContext.put("position", position); - velocityContext.put("speedUnit", ReportUtils.getSpeedUnit(userId)); - velocityContext.put("distanceUnit", ReportUtils.getDistanceUnit(userId)); - velocityContext.put("volumeUnit", ReportUtils.getVolumeUnit(userId)); - } - if (event.getGeofenceId() != 0) { - velocityContext.put("geofence", Context.getGeofenceManager().getById(event.getGeofenceId())); - } - if (event.getMaintenanceId() != 0) { - velocityContext.put("maintenance", Context.getMaintenancesManager().getById(event.getMaintenanceId())); - } - String driverUniqueId = event.getString(Position.KEY_DRIVER_UNIQUE_ID); - if (driverUniqueId != null) { - velocityContext.put("driver", Context.getDriversManager().getDriverByUniqueId(driverUniqueId)); - } - velocityContext.put("webUrl", Context.getVelocityEngine().getProperty("web.url")); - velocityContext.put("dateTool", new DateTool()); - velocityContext.put("numberTool", new NumberTool()); - velocityContext.put("timezone", ReportUtils.getTimezone(userId)); - velocityContext.put("locale", Locale.getDefault()); - return velocityContext; - } - - public static Template getTemplate(Event event, String path) { - - String templateFilePath; - Template template; - - try { - templateFilePath = Paths.get(path, event.getType() + ".vm").toString(); - template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); - } catch (ResourceNotFoundException error) { - LOGGER.warn("Notification template error", error); - templateFilePath = Paths.get(path, "unknown.vm").toString(); - template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); - } - return template; - } - - public static FullMessage formatFullMessage(long userId, Event event, Position position) { - VelocityContext velocityContext = prepareContext(userId, event, position); - String formattedMessage = formatMessage(velocityContext, userId, event, position, "full"); - - return new FullMessage((String) velocityContext.get("subject"), formattedMessage); - } - - public static String formatShortMessage(long userId, Event event, Position position) { - return formatMessage(null, userId, event, position, "short"); - } - - private static String formatMessage(VelocityContext vc, Long userId, Event event, Position position, - String templatePath) { - - VelocityContext velocityContext = vc; - if (velocityContext == null) { - velocityContext = prepareContext(userId, event, position); - } - StringWriter writer = new StringWriter(); - getTemplate(event, templatePath).merge(velocityContext, writer); - - return writer.toString(); - } - -} diff --git a/src/org/traccar/notification/NotificatorManager.java b/src/org/traccar/notification/NotificatorManager.java deleted file mode 100644 index a4080a38d..000000000 --- a/src/org/traccar/notification/NotificatorManager.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notification; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.Typed; -import org.traccar.notificators.NotificatorFirebase; -import org.traccar.notificators.NotificatorMail; -import org.traccar.notificators.NotificatorNull; -import org.traccar.notificators.Notificator; -import org.traccar.notificators.NotificatorSms; -import org.traccar.notificators.NotificatorWeb; - -public final class NotificatorManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorManager.class); - - private static final Notificator NULL_NOTIFICATOR = new NotificatorNull(); - - private final Map notificators = new HashMap<>(); - - public NotificatorManager() { - final String[] types = Context.getConfig().getString("notificator.types", "").split(","); - for (String type : types) { - String defaultNotificator = ""; - switch (type) { - case "web": - defaultNotificator = NotificatorWeb.class.getCanonicalName(); - break; - case "mail": - defaultNotificator = NotificatorMail.class.getCanonicalName(); - break; - case "sms": - defaultNotificator = NotificatorSms.class.getCanonicalName(); - break; - case "firebase": - defaultNotificator = NotificatorFirebase.class.getCanonicalName(); - break; - default: - break; - } - final String className = Context.getConfig() - .getString("notificator." + type + ".class", defaultNotificator); - try { - notificators.put(type, (Notificator) Class.forName(className).newInstance()); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { - LOGGER.warn("Unable to load notificator class for " + type + " " + className + " " + e.getMessage()); - } - } - } - - public Notificator getNotificator(String type) { - final Notificator notificator = notificators.get(type); - if (notificator == null) { - LOGGER.warn("No notificator configured for type : " + type); - return NULL_NOTIFICATOR; - } - return notificator; - } - - public Set getAllNotificatorTypes() { - Set result = new HashSet<>(); - for (String notificator : notificators.keySet()) { - result.add(new Typed(notificator)); - } - return result; - } - -} diff --git a/src/org/traccar/notification/PropertiesProvider.java b/src/org/traccar/notification/PropertiesProvider.java deleted file mode 100644 index f0078feef..000000000 --- a/src/org/traccar/notification/PropertiesProvider.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2016 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. - * 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.notification; - -import org.traccar.config.Config; -import org.traccar.model.ExtendedModel; - -public class PropertiesProvider { - - private Config config; - - private ExtendedModel extendedModel; - - public PropertiesProvider(Config config) { - this.config = config; - } - - public PropertiesProvider(ExtendedModel extendedModel) { - this.extendedModel = extendedModel; - } - - public String getString(String key) { - if (config != null) { - return config.getString(key); - } else { - return extendedModel.getString(key); - } - } - - public String getString(String key, String defaultValue) { - String value = getString(key); - if (value == null) { - value = defaultValue; - } - return value; - } - - public int getInteger(String key, int defaultValue) { - if (config != null) { - return config.getInteger(key, defaultValue); - } else { - Object result = extendedModel.getAttributes().get(key); - if (result != null) { - return result instanceof String ? Integer.parseInt((String) result) : (Integer) result; - } else { - return defaultValue; - } - } - } - - public Boolean getBoolean(String key) { - if (config != null) { - if (config.hasKey(key)) { - return config.getBoolean(key); - } else { - return null; - } - } else { - Object result = extendedModel.getAttributes().get(key); - if (result != null) { - return result instanceof String ? Boolean.valueOf((String) result) : (Boolean) result; - } else { - return null; - } - } - } - -} diff --git a/src/org/traccar/notificators/Notificator.java b/src/org/traccar/notificators/Notificator.java deleted file mode 100644 index 5e40971c6..000000000 --- a/src/org/traccar/notificators/Notificator.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notificators; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.notification.MessageException; - -public abstract class Notificator { - - private static final Logger LOGGER = LoggerFactory.getLogger(Notificator.class); - - public void sendAsync(final long userId, final Event event, final Position position) { - new Thread(new Runnable() { - public void run() { - try { - sendSync(userId, event, position); - } catch (MessageException | InterruptedException error) { - LOGGER.warn("Event send error", error); - } - } - }).start(); - } - - public abstract void sendSync(long userId, Event event, Position position) - throws MessageException, InterruptedException; - -} diff --git a/src/org/traccar/notificators/NotificatorFirebase.java b/src/org/traccar/notificators/NotificatorFirebase.java deleted file mode 100644 index 75d325de2..000000000 --- a/src/org/traccar/notificators/NotificatorFirebase.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notificators; - -import com.fasterxml.jackson.annotation.JsonProperty; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.model.User; -import org.traccar.notification.NotificationFormatter; - -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.InvocationCallback; - -public class NotificatorFirebase extends Notificator { - - private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class); - - private static final String URL = "https://fcm.googleapis.com/fcm/send"; - - private String key; - - public static class Notification { - @JsonProperty("body") - private String body; - } - - public static class Message { - @JsonProperty("registration_ids") - private String[] tokens; - @JsonProperty("notification") - private Notification notification; - } - - public NotificatorFirebase() { - key = Context.getConfig().getString("notificator.firebase.key"); - } - - @Override - public void sendSync(long userId, Event event, Position position) { - final User user = Context.getPermissionsManager().getUser(userId); - if (user.getAttributes().containsKey("notificationTokens")) { - - Notification notification = new Notification(); - notification.body = NotificationFormatter.formatShortMessage(userId, event, position).trim(); - - Message message = new Message(); - message.tokens = user.getString("notificationTokens").split("[, ]"); - message.notification = notification; - - Context.getClient().target(URL).request() - .header("Authorization", "key=" + key) - .async().post(Entity.json(message), new InvocationCallback() { - @Override - public void completed(Object o) { - } - - @Override - public void failed(Throwable throwable) { - LOGGER.warn("Firebase notification error", throwable); - } - }); - } - } - - @Override - public void sendAsync(long userId, Event event, Position position) { - sendSync(userId, event, position); - } - -} diff --git a/src/org/traccar/notificators/NotificatorMail.java b/src/org/traccar/notificators/NotificatorMail.java deleted file mode 100644 index 6b9774c58..000000000 --- a/src/org/traccar/notificators/NotificatorMail.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notificators; - -import org.traccar.Context; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.notification.FullMessage; -import org.traccar.notification.MessageException; -import org.traccar.notification.NotificationFormatter; - -import javax.mail.MessagingException; - -public final class NotificatorMail extends Notificator { - - @Override - public void sendSync(long userId, Event event, Position position) throws MessageException { - try { - FullMessage message = NotificationFormatter.formatFullMessage(userId, event, position); - Context.getMailManager().sendMessage(userId, message.getSubject(), message.getBody()); - } catch (MessagingException e) { - throw new MessageException(e); - } - } - -} diff --git a/src/org/traccar/notificators/NotificatorNull.java b/src/org/traccar/notificators/NotificatorNull.java deleted file mode 100644 index 9364336be..000000000 --- a/src/org/traccar/notificators/NotificatorNull.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notificators; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.model.Event; -import org.traccar.model.Position; - -public final class NotificatorNull extends Notificator { - - private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorNull.class); - - @Override - public void sendAsync(long userId, Event event, Position position) { - LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent"); - } - - @Override - public void sendSync(long userId, Event event, Position position) { - LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent"); - } - -} diff --git a/src/org/traccar/notificators/NotificatorSms.java b/src/org/traccar/notificators/NotificatorSms.java deleted file mode 100644 index d5c791eae..000000000 --- a/src/org/traccar/notificators/NotificatorSms.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notificators; - -import org.traccar.Context; -import org.traccar.Main; -import org.traccar.database.StatisticsManager; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.model.User; -import org.traccar.notification.MessageException; -import org.traccar.notification.NotificationFormatter; -import org.traccar.sms.SmsManager; - -public final class NotificatorSms extends Notificator { - - private final SmsManager smsManager; - - public NotificatorSms() throws ClassNotFoundException, InstantiationException, IllegalAccessException { - final String smsClass = Context.getConfig().getString("notificator.sms.manager.class", ""); - if (smsClass.length() > 0) { - smsManager = (SmsManager) Class.forName(smsClass).newInstance(); - } else { - smsManager = Context.getSmsManager(); - } - } - - @Override - public void sendAsync(long userId, Event event, Position position) { - final User user = Context.getPermissionsManager().getUser(userId); - if (user.getPhone() != null) { - Main.getInjector().getInstance(StatisticsManager.class).registerSms(); - smsManager.sendMessageAsync(user.getPhone(), - NotificationFormatter.formatShortMessage(userId, event, position), false); - } - } - - @Override - public void sendSync(long userId, Event event, Position position) throws MessageException, InterruptedException { - final User user = Context.getPermissionsManager().getUser(userId); - if (user.getPhone() != null) { - Main.getInjector().getInstance(StatisticsManager.class).registerSms(); - smsManager.sendMessageSync(user.getPhone(), - NotificationFormatter.formatShortMessage(userId, event, position), false); - } - } - -} diff --git a/src/org/traccar/notificators/NotificatorWeb.java b/src/org/traccar/notificators/NotificatorWeb.java deleted file mode 100644 index 1d11c0b46..000000000 --- a/src/org/traccar/notificators/NotificatorWeb.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.notificators; - -import org.traccar.Context; -import org.traccar.model.Event; -import org.traccar.model.Position; - -public final class NotificatorWeb extends Notificator { - - @Override - public void sendSync(long userId, Event event, Position position) { - Context.getConnectionManager().updateEvent(userId, event); - } - -} diff --git a/src/org/traccar/protocol/AdmProtocol.java b/src/org/traccar/protocol/AdmProtocol.java deleted file mode 100644 index 08f932ceb..000000000 --- a/src/org/traccar/protocol/AdmProtocol.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -import java.nio.ByteOrder; - -public class AdmProtocol extends BaseProtocol { - - public AdmProtocol() { - setSupportedDataCommands( - Command.TYPE_GET_DEVICE_STATUS, - Command.TYPE_CUSTOM); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 1, -3, 0, true)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new AdmProtocolEncoder()); - pipeline.addLast(new AdmProtocolDecoder(AdmProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AdmProtocolDecoder.java b/src/org/traccar/protocol/AdmProtocolDecoder.java deleted file mode 100644 index 52d1439ed..000000000 --- a/src/org/traccar/protocol/AdmProtocolDecoder.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class AdmProtocolDecoder extends BaseProtocolDecoder { - - public AdmProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int CMD_RESPONSE_SIZE = 0x84; - public static final int MSG_IMEI = 0x03; - public static final int MSG_PHOTO = 0x0A; - public static final int MSG_ADM5 = 0x01; - - private Position decodeData(Channel channel, SocketAddress remoteAddress, ByteBuf buf, int type) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - if (BitUtil.to(type, 2) == 0) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); - position.set(Position.KEY_INDEX, buf.readUnsignedShortLE()); - - int status = buf.readUnsignedShortLE(); - position.set(Position.KEY_STATUS, status); - position.setValid(!BitUtil.check(status, 5)); - position.setLatitude(buf.readFloatLE()); - position.setLongitude(buf.readFloatLE()); - position.setCourse(buf.readUnsignedShortLE() * 0.1); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE() * 0.1)); - - position.set(Position.KEY_ACCELERATION, buf.readUnsignedByte() * 0.1); - position.setAltitude(buf.readShortLE()); - position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte() & 0x0f); - - position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); - - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); - - if (BitUtil.check(type, 2)) { - buf.readUnsignedByte(); // vib - buf.readUnsignedByte(); // vib_count - - int out = buf.readUnsignedByte(); - for (int i = 0; i <= 3; i++) { - position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(out, i) ? 1 : 0); - } - - buf.readUnsignedByte(); // in_alarm - } - - if (BitUtil.check(type, 3)) { - for (int i = 1; i <= 6; i++) { - position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE() * 0.001); - } - } - - if (BitUtil.check(type, 4)) { - for (int i = 1; i <= 2; i++) { - position.set(Position.PREFIX_COUNT + i, buf.readUnsignedIntLE()); - } - } - - if (BitUtil.check(type, 5)) { - for (int i = 1; i <= 3; i++) { - buf.readUnsignedShortLE(); // fuel level - } - for (int i = 1; i <= 3; i++) { - position.set(Position.PREFIX_TEMP + i, buf.readUnsignedByte()); - } - } - - if (BitUtil.check(type, 6)) { - int endIndex = buf.readerIndex() + buf.readUnsignedByte(); - while (buf.readerIndex() < endIndex) { - int mask = buf.readUnsignedByte(); - long value; - switch (BitUtil.from(mask, 6)) { - case 3: - value = buf.readLongLE(); - break; - case 2: - value = buf.readUnsignedIntLE(); - break; - case 1: - value = buf.readUnsignedShortLE(); - break; - default: - value = buf.readUnsignedByte(); - break; - } - int index = BitUtil.to(mask, 6); - switch (index) { - case 1: - position.set(Position.PREFIX_TEMP + 1, value); - break; - case 2: - position.set("humidity", value); - break; - case 3: - position.set("illumination", value); - break; - case 4: - position.set(Position.KEY_BATTERY, value); - break; - default: - position.set("can" + index, value); - break; - } - } - } - - if (BitUtil.check(type, 7)) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - } - - return position; - } - - return null; - } - - private Position parseCommandResponse(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - int responseTextLength = buf.bytesBefore((byte) 0); - if (responseTextLength < 0) { - responseTextLength = CMD_RESPONSE_SIZE - 3; - } - position.set(Position.KEY_RESULT, buf.readSlice(responseTextLength).toString(StandardCharsets.UTF_8)); - - return position; - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedShortLE(); // device id - - int size = buf.readUnsignedByte(); - if (size != CMD_RESPONSE_SIZE) { - int type = buf.readUnsignedByte(); - if (type == MSG_IMEI) { - getDeviceSession(channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.UTF_8)); - } else { - return decodeData(channel, remoteAddress, buf, type); - } - } else { - return parseCommandResponse(channel, remoteAddress, buf); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/AdmProtocolEncoder.java b/src/org/traccar/protocol/AdmProtocolEncoder.java deleted file mode 100644 index e76bc2ddc..000000000 --- a/src/org/traccar/protocol/AdmProtocolEncoder.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Anatoliy Golubev (darth.naihil@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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class AdmProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_GET_DEVICE_STATUS: - return formatCommand(command, "STATUS\r\n"); - - case Command.TYPE_CUSTOM: - return formatCommand(command, "{%s}\r\n", Command.KEY_DATA); - - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/AisProtocol.java b/src/org/traccar/protocol/AisProtocol.java deleted file mode 100644 index 3b9cad7c8..000000000 --- a/src/org/traccar/protocol/AisProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AisProtocol extends BaseProtocol { - - public AisProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new AisProtocolDecoder(AisProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AisProtocolDecoder.java b/src/org/traccar/protocol/AisProtocolDecoder.java deleted file mode 100644 index 8970f3d4a..000000000 --- a/src/org/traccar/protocol/AisProtocolDecoder.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitBuffer; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -public class AisProtocolDecoder extends BaseProtocolDecoder { - - public AisProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("!AIVDM,") - .number("(d+),") // count - .number("(d+),") // index - .number("(d+)?,") // id - .expression(".,") // radio channel - .expression("([^,]+),") // payload - .any() - .compile(); - - private Position decodePayload(Channel channel, SocketAddress remoteAddress, BitBuffer buf) { - - int type = buf.readUnsigned(6); - if (type == 1 || type == 2 || type == 3 || type == 18) { - - buf.readUnsigned(2); - int mmsi = buf.readUnsigned(30); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(mmsi)); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date()); - - if (type == 18) { - buf.readUnsigned(8); // reserved - } else { - position.set(Position.KEY_STATUS, buf.readUnsigned(4)); - position.set("turn", buf.readSigned(8)); - } - - position.setSpeed(buf.readUnsigned(10) * 0.1); - position.setValid(buf.readUnsigned(1) != 0); - position.setLongitude(buf.readSigned(28) * 0.0001 / 60.0); - position.setLatitude(buf.readSigned(27) * 0.0001 / 60.0); - position.setCourse(buf.readUnsigned(12) * 0.1); - - position.set("heading", buf.readUnsigned(9)); - - return position; - - } - - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String[] sentences = ((String) msg).split("\\r\\n"); - - List positions = new ArrayList<>(); - Map buffers = new HashMap<>(); - - for (String sentence : sentences) { - if (!sentence.isEmpty()) { - Parser parser = new Parser(PATTERN, sentence); - if (parser.matches()) { - - int count = parser.nextInt(0); - int index = parser.nextInt(0); - int id = parser.nextInt(0); - - Position position = null; - - if (count == 1) { - BitBuffer bits = new BitBuffer(); - bits.writeEncoded(parser.next().getBytes(StandardCharsets.US_ASCII)); - position = decodePayload(channel, remoteAddress, bits); - } else { - BitBuffer bits = buffers.get(id); - if (bits == null) { - bits = new BitBuffer(); - buffers.put(id, bits); - } - bits.writeEncoded(parser.next().getBytes(StandardCharsets.US_ASCII)); - if (count == index) { - position = decodePayload(channel, remoteAddress, bits); - buffers.remove(id); - } - } - - if (position != null) { - positions.add(position); - } - - } - } - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/AlematicsFrameDecoder.java b/src/org/traccar/protocol/AlematicsFrameDecoder.java deleted file mode 100644 index be7666657..000000000 --- a/src/org/traccar/protocol/AlematicsFrameDecoder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2017 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.LineBasedFrameDecoder; -import org.traccar.NetworkMessage; - -public class AlematicsFrameDecoder extends LineBasedFrameDecoder { - - private static final int MESSAGE_MINIMUM_LENGTH = 2; - - public AlematicsFrameDecoder(int maxFrameLength) { - super(maxFrameLength); - } - - // example of heartbeat: FA F8 00 07 00 03 15 AD 4E 78 3A D2 - - @Override - protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { - return null; - } - - if (buf.getUnsignedShort(buf.readerIndex()) == 0xFAF8) { - ByteBuf heartbeat = buf.readRetainedSlice(12); - if (ctx != null && ctx.channel() != null) { - ctx.channel().writeAndFlush(new NetworkMessage(heartbeat, ctx.channel().remoteAddress())); - } - } - - return super.decode(ctx, buf); - } - -} diff --git a/src/org/traccar/protocol/AlematicsProtocol.java b/src/org/traccar/protocol/AlematicsProtocol.java deleted file mode 100644 index 8da2356b9..000000000 --- a/src/org/traccar/protocol/AlematicsProtocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AlematicsProtocol extends BaseProtocol { - - public AlematicsProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new AlematicsFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new AlematicsProtocolDecoder(AlematicsProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AlematicsProtocolDecoder.java b/src/org/traccar/protocol/AlematicsProtocolDecoder.java deleted file mode 100644 index 25ccf6856..000000000 --- a/src/org/traccar/protocol/AlematicsProtocolDecoder.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class AlematicsProtocolDecoder extends BaseProtocolDecoder { - - public AlematicsProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$T,") - .number("(d+),") // type - .number("(d+),") // index - .number("(d+),") // id - .number("(dddd)(dd)(dd)") // gps date - .number("(dd)(dd)(dd),") // gps time - .number("(dddd)(dd)(dd)") // device date - .number("(dd)(dd)(dd),") // device time - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(-?d+),") // altitude - .number("(d+.d),") // hdop - .number("(d+),") // satellites - .number("(d+),") // input - .number("(d+),") // output - .number("(d+.d+),") // adc - .number("(d+.d+),") // power - .number("(d+),") // odometer - .groupBegin() - .text("0,$S,") - .expression("(.*)") // text message - .or() - .number("(d+),") // extra mask - .expression("(.*)") // extra data - .or() - .any() - .groupEnd() - .compile(); - - private void decodeExtras(Position position, Parser parser) { - - int mask = parser.nextInt(); - String[] data = parser.next().split(","); - - int index = 0; - - if (BitUtil.check(mask, 0)) { - index++; // pulse counter 3 - } - - if (BitUtil.check(mask, 1)) { - position.set(Position.KEY_POWER, Integer.parseInt(data[index++])); - } - - if (BitUtil.check(mask, 2)) { - position.set(Position.KEY_BATTERY, Integer.parseInt(data[index++])); - } - - if (BitUtil.check(mask, 3)) { - position.set(Position.KEY_OBD_SPEED, Integer.parseInt(data[index++])); - } - - if (BitUtil.check(mask, 4)) { - position.set(Position.KEY_RPM, Integer.parseInt(data[index++])); - } - - if (BitUtil.check(mask, 5)) { - position.set(Position.KEY_RSSI, Integer.parseInt(data[index++])); - } - - if (BitUtil.check(mask, 6)) { - index++; // pulse counter 2 - } - - if (BitUtil.check(mask, 7)) { - index++; // magnetic rotation sensor rpm - } - - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - position.set(Position.KEY_TYPE, parser.nextInt()); - position.set(Position.KEY_INDEX, parser.nextInt()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setFixTime(parser.nextDateTime()); - position.setDeviceTime(parser.nextDateTime()); - - position.setValid(true); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); - position.setCourse(parser.nextInt(0)); - position.setAltitude(parser.nextInt(0)); - - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_INPUT, parser.nextInt()); - position.set(Position.KEY_OUTPUT, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextInt()); - - if (parser.hasNext()) { - position.set("text", parser.next()); - } else if (parser.hasNext()) { - decodeExtras(position, parser); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/AnytrekProtocol.java b/src/org/traccar/protocol/AnytrekProtocol.java deleted file mode 100644 index 4ab5833f7..000000000 --- a/src/org/traccar/protocol/AnytrekProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AnytrekProtocol extends BaseProtocol { - - public AnytrekProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, 2, 0)); - pipeline.addLast(new AnytrekProtocolDecoder(AnytrekProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AnytrekProtocolDecoder.java b/src/org/traccar/protocol/AnytrekProtocolDecoder.java deleted file mode 100644 index c48f59c90..000000000 --- a/src/org/traccar/protocol/AnytrekProtocolDecoder.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class AnytrekProtocolDecoder extends BaseProtocolDecoder { - - public AnytrekProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private void sendResponse(Channel channel, SocketAddress remoteAddress, int type) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeShort(0x7878); - response.writeShortLE(1 + 1 + 2 + 1 + 2); // length - response.writeByte(type); - response.writeByte(0); // error - response.writeShortLE(0); // report interval - response.writeByte(0); // clear alarm - response.writeShortLE(0); // checksum - response.writeByte('\r'); - response.writeByte('\n'); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - buf.readUnsignedShortLE(); // size - int type = buf.readUnsignedByte(); - - String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(2); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_VERSION_FW, buf.readUnsignedShortLE()); - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_SATELLITES, BitUtil.to(buf.readUnsignedByte(), 4)); - - double latitude = buf.readUnsignedIntLE() / 1800000.0; - double longitude = buf.readUnsignedIntLE() / 1800000.0; - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - - int flags = buf.readUnsignedShortLE(); - position.setCourse(BitUtil.to(flags, 10)); - position.setValid(BitUtil.check(flags, 12)); - - if (!BitUtil.check(flags, 10)) { - latitude = -latitude; - } - if (BitUtil.check(flags, 11)) { - longitude = -longitude; - } - - position.setLatitude(latitude); - position.setLongitude(longitude); - - buf.readUnsignedIntLE(); // info index - buf.readUnsignedIntLE(); // setting index - - flags = buf.readUnsignedByte(); - position.set(Position.KEY_CHARGE, BitUtil.check(flags, 0)); - position.set(Position.KEY_IGNITION, BitUtil.check(flags, 1)); - position.set(Position.KEY_ALARM, BitUtil.check(flags, 4) ? Position.ALARM_GENERAL : null); - - buf.readUnsignedShortLE(); // charge current - - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - - sendResponse(channel, remoteAddress, type); - - return position; - } - -} diff --git a/src/org/traccar/protocol/ApelProtocol.java b/src/org/traccar/protocol/ApelProtocol.java deleted file mode 100644 index 382aa16af..000000000 --- a/src/org/traccar/protocol/ApelProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; -public class ApelProtocol extends BaseProtocol { - - public ApelProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, 4, 0, true)); - pipeline.addLast(new ApelProtocolDecoder(ApelProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ApelProtocolDecoder.java b/src/org/traccar/protocol/ApelProtocolDecoder.java deleted file mode 100644 index c95a0366a..000000000 --- a/src/org/traccar/protocol/ApelProtocolDecoder.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class ApelProtocolDecoder extends BaseProtocolDecoder { - - private long lastIndex; - private long newIndex; - - public ApelProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final short MSG_NULL = 0; - public static final short MSG_REQUEST_TRACKER_ID = 10; - public static final short MSG_TRACKER_ID = 11; - public static final short MSG_TRACKER_ID_EXT = 12; - public static final short MSG_DISCONNECT = 20; - public static final short MSG_REQUEST_PASSWORD = 30; - public static final short MSG_PASSWORD = 31; - public static final short MSG_REQUEST_STATE_FULL_INFO = 90; - public static final short MSG_STATE_FULL_INFO_T104 = 92; - public static final short MSG_REQUEST_CURRENT_GPS_DATA = 100; - public static final short MSG_CURRENT_GPS_DATA = 101; - public static final short MSG_REQUEST_SENSORS_STATE = 110; - public static final short MSG_SENSORS_STATE = 111; - public static final short MSG_SENSORS_STATE_T100 = 112; - public static final short MSG_SENSORS_STATE_T100_4 = 113; - public static final short MSG_REQUEST_LAST_LOG_INDEX = 120; - public static final short MSG_LAST_LOG_INDEX = 121; - public static final short MSG_REQUEST_LOG_RECORDS = 130; - public static final short MSG_LOG_RECORDS = 131; - public static final short MSG_EVENT = 141; - public static final short MSG_TEXT = 150; - public static final short MSG_ACK_ALARM = 160; - public static final short MSG_SET_TRACKER_MODE = 170; - public static final short MSG_GPRS_COMMAND = 180; - - private void sendSimpleMessage(Channel channel, short type) { - ByteBuf request = Unpooled.buffer(8); - request.writeShortLE(type); - request.writeShortLE(0); - request.writeIntLE(Checksum.crc32(request.nioBuffer(0, 4))); - channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress())); - } - - private void requestArchive(Channel channel) { - if (lastIndex == 0) { - lastIndex = newIndex; - } else if (newIndex > lastIndex) { - ByteBuf request = Unpooled.buffer(14); - request.writeShortLE(MSG_REQUEST_LOG_RECORDS); - request.writeShortLE(6); - request.writeIntLE((int) lastIndex); - request.writeShortLE(512); - request.writeIntLE(Checksum.crc32(request.nioBuffer(0, 10))); - channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - int type = buf.readUnsignedShortLE(); - boolean alarm = (type & 0x8000) != 0; - type = type & 0x7FFF; - buf.readUnsignedShortLE(); // length - - if (alarm) { - sendSimpleMessage(channel, MSG_ACK_ALARM); - } - - if (type == MSG_TRACKER_ID) { - return null; // unsupported authentication type - } - - if (type == MSG_TRACKER_ID_EXT) { - - buf.readUnsignedIntLE(); // id - int length = buf.readUnsignedShortLE(); - buf.skipBytes(length); - length = buf.readUnsignedShortLE(); - getDeviceSession(channel, remoteAddress, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); - - } else if (type == MSG_LAST_LOG_INDEX) { - - long index = buf.readUnsignedIntLE(); - if (index > 0) { - newIndex = index; - requestArchive(channel); - } - - } else if (type == MSG_CURRENT_GPS_DATA || type == MSG_STATE_FULL_INFO_T104 || type == MSG_LOG_RECORDS) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - int recordCount = 1; - if (type == MSG_LOG_RECORDS) { - recordCount = buf.readUnsignedShortLE(); - } - - for (int j = 0; j < recordCount; j++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - int subtype = type; - if (type == MSG_LOG_RECORDS) { - position.set(Position.KEY_ARCHIVE, true); - lastIndex = buf.readUnsignedIntLE() + 1; - position.set(Position.KEY_INDEX, lastIndex); - - subtype = buf.readUnsignedShortLE(); - if (subtype != MSG_CURRENT_GPS_DATA && subtype != MSG_STATE_FULL_INFO_T104) { - buf.skipBytes(buf.readUnsignedShortLE()); - continue; - } - buf.readUnsignedShortLE(); // length - } - - position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); - position.setLatitude(buf.readIntLE() * 180.0 / 0x7FFFFFFF); - position.setLongitude(buf.readIntLE() * 180.0 / 0x7FFFFFFF); - - if (subtype == MSG_STATE_FULL_INFO_T104) { - int speed = buf.readUnsignedByte(); - position.setValid(speed != 255); - position.setSpeed(UnitsConverter.knotsFromKph(speed)); - position.set(Position.KEY_HDOP, buf.readByte()); - } else { - int speed = buf.readShortLE(); - position.setValid(speed != -1); - position.setSpeed(UnitsConverter.knotsFromKph(speed * 0.01)); - } - - position.setCourse(buf.readShortLE() * 0.01); - position.setAltitude(buf.readShortLE()); - - if (subtype == MSG_STATE_FULL_INFO_T104) { - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - position.set(Position.KEY_INPUT, buf.readUnsignedByte()); - position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); - - for (int i = 1; i <= 8; i++) { - position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE()); - } - - position.set(Position.PREFIX_COUNT + 1, buf.readUnsignedIntLE()); - position.set(Position.PREFIX_COUNT + 2, buf.readUnsignedIntLE()); - position.set(Position.PREFIX_COUNT + 3, buf.readUnsignedIntLE()); - } - - positions.add(position); - } - - buf.readUnsignedIntLE(); // crc - - if (type == MSG_LOG_RECORDS) { - requestArchive(channel); - } else { - sendSimpleMessage(channel, MSG_REQUEST_LAST_LOG_INDEX); - } - - return positions; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/AplicomFrameDecoder.java b/src/org/traccar/protocol/AplicomFrameDecoder.java deleted file mode 100644 index 6e81e8202..000000000 --- a/src/org/traccar/protocol/AplicomFrameDecoder.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class AplicomFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - // Skip Alive message - while (buf.isReadable() && Character.isDigit(buf.getByte(buf.readerIndex()))) { - buf.readByte(); - } - - // Check minimum length - if (buf.readableBytes() < 11) { - return null; - } - - // Read flags - int version = buf.getUnsignedByte(buf.readerIndex() + 1); - int offset = 1 + 1 + 3; - if ((version & 0x80) != 0) { - offset += 4; - } - - // Get data length - int length = buf.getUnsignedShort(buf.readerIndex() + offset); - offset += 2; - if ((version & 0x40) != 0) { - offset += 3; - } - length += offset; // add header - - // Return buffer - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/AplicomProtocol.java b/src/org/traccar/protocol/AplicomProtocol.java deleted file mode 100644 index 2b9dbf97c..000000000 --- a/src/org/traccar/protocol/AplicomProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AplicomProtocol extends BaseProtocol { - - public AplicomProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new AplicomFrameDecoder()); - pipeline.addLast(new AplicomProtocolDecoder(AplicomProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AplicomProtocolDecoder.java b/src/org/traccar/protocol/AplicomProtocolDecoder.java deleted file mode 100644 index 215aa0211..000000000 --- a/src/org/traccar/protocol/AplicomProtocolDecoder.java +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Date; - -public class AplicomProtocolDecoder extends BaseProtocolDecoder { - - private static final Logger LOGGER = LoggerFactory.getLogger(AplicomProtocolDecoder.class); - - public AplicomProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final long IMEI_BASE_TC65_V20 = 0x1437207000000L; - private static final long IMEI_BASE_TC65_V28 = 358244010000000L; - private static final long IMEI_BASE_TC65I_V11 = 0x14143B4000000L; - - private static boolean validateImei(long imei) { - return Checksum.luhn(imei / 10) == imei % 10; - } - - private static long imeiFromUnitId(long unitId) { - - if (unitId == 0) { - - return 0; - - } else { - - // Try TC65i - long imei = IMEI_BASE_TC65I_V11 + unitId; - if (validateImei(imei)) { - return imei; - } - - // Try TC65 v2.8 - imei = IMEI_BASE_TC65_V28 + ((unitId + 0xA8180) & 0xFFFFFF); - if (validateImei(imei)) { - return imei; - } - - // Try TC65 v2.0 - imei = IMEI_BASE_TC65_V20 + unitId; - if (validateImei(imei)) { - return imei; - } - - } - - return unitId; - } - - private static final int DEFAULT_SELECTOR_D = 0x0002fC; - private static final int DEFAULT_SELECTOR_E = 0x007ffc; - private static final int DEFAULT_SELECTOR_F = 0x0007fd; - - private static final int EVENT_DATA = 119; - - private void decodeEventData(Position position, ByteBuf buf, int event) { - switch (event) { - case 2: - case 40: - buf.readUnsignedByte(); - break; - case 9: - buf.readUnsignedMedium(); - break; - case 31: - case 32: - buf.readUnsignedShort(); - break; - case 38: - buf.skipBytes(4 * 9); - break; - case 113: - buf.readUnsignedInt(); - buf.readUnsignedByte(); - break; - case 119: - position.set("eventData", ByteBufUtil.hexDump( - buf, buf.readerIndex(), Math.min(buf.readableBytes(), 1024))); - break; - case 121: - case 142: - buf.readLong(); - break; - case 130: - buf.readUnsignedInt(); // incorrect - break; - case 188: - decodeEB(position, buf); - break; - default: - break; - } - } - - private void decodeCanData(ByteBuf buf, Position position) { - - buf.readUnsignedMedium(); // packet identifier - position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); - int count = buf.readUnsignedByte(); - buf.readUnsignedByte(); // batch count - buf.readUnsignedShort(); // selector bit - buf.readUnsignedInt(); // timestamp - - buf.skipBytes(8); - - ArrayList values = new ArrayList<>(count); - - for (int i = 0; i < count; i++) { - values.add(buf.readSlice(8)); - } - - for (int i = 0; i < count; i++) { - ByteBuf value = values.get(i); - switch (buf.readInt()) { - case 0x20D: - position.set(Position.KEY_RPM, value.readShortLE()); - position.set("dieselTemperature", value.readShortLE() * 0.1); - position.set("batteryVoltage", value.readShortLE() * 0.01); - position.set("supplyAirTempDep1", value.readShortLE() * 0.1); - break; - case 0x30D: - position.set("activeAlarm", ByteBufUtil.hexDump(value)); - break; - case 0x40C: - position.set("airTempDep1", value.readShortLE() * 0.1); - position.set("airTempDep2", value.readShortLE() * 0.1); - break; - case 0x40D: - position.set("coldUnitState", ByteBufUtil.hexDump(value)); - break; - case 0x50C: - position.set("defrostTempDep1", value.readShortLE() * 0.1); - position.set("defrostTempDep2", value.readShortLE() * 0.1); - break; - case 0x50D: - position.set("condenserPressure", value.readShortLE() * 0.1); - position.set("suctionPressure", value.readShortLE() * 0.1); - break; - case 0x58C: - value.readByte(); - value.readShort(); // index - switch (value.readByte()) { - case 0x01: - position.set("setpointZone1", value.readIntLE() * 0.1); - break; - case 0x02: - position.set("setpointZone2", value.readIntLE() * 0.1); - break; - case 0x05: - position.set("unitType", value.readIntLE()); - break; - case 0x13: - position.set("dieselHours", value.readIntLE() / 60 / 60); - break; - case 0x14: - position.set("electricHours", value.readIntLE() / 60 / 60); - break; - case 0x17: - position.set("serviceIndicator", value.readIntLE()); - break; - case 0x18: - position.set("softwareVersion", value.readIntLE() * 0.01); - break; - default: - break; - } - break; - default: - LOGGER.warn("Aplicom CAN decoding error", new UnsupportedOperationException()); - break; - } - } - } - - private void decodeD(Position position, ByteBuf buf, int selector, int event) { - - if ((selector & 0x0008) != 0) { - position.setValid((buf.readUnsignedByte() & 0x40) != 0); - } else { - getLastLocation(position, null); - } - - if ((selector & 0x0004) != 0) { - position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000)); - } - - if ((selector & 0x0008) != 0) { - position.setFixTime(new Date(buf.readUnsignedInt() * 1000)); - if (position.getDeviceTime() == null) { - position.setDeviceTime(position.getFixTime()); - } - position.setLatitude(buf.readInt() / 1000000.0); - position.setLongitude(buf.readInt() / 1000000.0); - position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); - } - - if ((selector & 0x0010) != 0) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.set("maximumSpeed", buf.readUnsignedByte()); - position.setCourse(buf.readUnsignedByte() * 2.0); - } - - if ((selector & 0x0040) != 0) { - position.set(Position.KEY_INPUT, buf.readUnsignedByte()); - } - - if ((selector & 0x0020) != 0) { - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShort()); - } - - if ((selector & 0x8000) != 0) { - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); - } - - // Pulse rate 1 - if ((selector & 0x10000) != 0) { - buf.readUnsignedShort(); - buf.readUnsignedInt(); - } - - // Pulse rate 2 - if ((selector & 0x20000) != 0) { - buf.readUnsignedShort(); - buf.readUnsignedInt(); - } - - if ((selector & 0x0080) != 0) { - position.set("trip1", buf.readUnsignedInt()); - } - - if ((selector & 0x0100) != 0) { - position.set("trip2", buf.readUnsignedInt()); - } - - if ((selector & 0x0040) != 0) { - position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); - } - - if ((selector & 0x0200) != 0) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, - String.valueOf(((long) buf.readUnsignedShort()) << 32) + buf.readUnsignedInt()); - } - - if ((selector & 0x0400) != 0) { - buf.readUnsignedByte(); // Keypad - } - - if ((selector & 0x0800) != 0) { - position.setAltitude(buf.readShort()); - } - - if ((selector & 0x2000) != 0) { - buf.readUnsignedShort(); // snapshot counter - } - - if ((selector & 0x4000) != 0) { - buf.skipBytes(8); // state flags - } - - if ((selector & 0x80000) != 0) { - buf.skipBytes(11); // cell info - } - - if ((selector & 0x1000) != 0) { - decodeEventData(position, buf, event); - } - - if (Context.getConfig().getBoolean(getProtocolName() + ".can") - && buf.isReadable() && (selector & 0x1000) != 0 && event == EVENT_DATA) { - decodeCanData(buf, position); - } - } - - private void decodeE(Position position, ByteBuf buf, int selector) { - - if ((selector & 0x0008) != 0) { - position.set("tachographEvent", buf.readUnsignedShort()); - } - - if ((selector & 0x0004) != 0) { - getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); - } else { - getLastLocation(position, null); - } - - if ((selector & 0x0010) != 0) { - String time = buf.readUnsignedByte() + "s " + buf.readUnsignedByte() + "m " + buf.readUnsignedByte() + "h " - + buf.readUnsignedByte() + "M " + buf.readUnsignedByte() + "D " + buf.readUnsignedByte() + "Y " - + buf.readByte() + "m " + buf.readByte() + "h"; - position.set("tachographTime", time); - } - - position.set("workState", buf.readUnsignedByte()); - position.set("driver1State", buf.readUnsignedByte()); - position.set("driver2State", buf.readUnsignedByte()); - - if ((selector & 0x0020) != 0) { - position.set("tachographStatus", buf.readUnsignedByte()); - } - - if ((selector & 0x0040) != 0) { - position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() / 256.0); - } - - if ((selector & 0x0080) != 0) { - position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 5); - } - - if ((selector & 0x0100) != 0) { - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt() * 5); - } - - if ((selector & 0x8000) != 0) { - position.set("kFactor", buf.readUnsignedShort() * 0.001 + " pulses/m"); - } - - if ((selector & 0x0200) != 0) { - position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); - } - - if ((selector & 0x0400) != 0) { - position.set("extraInfo", buf.readUnsignedShort()); - } - - if ((selector & 0x0800) != 0) { - position.set(Position.KEY_VIN, buf.readSlice(18).toString(StandardCharsets.US_ASCII).trim()); - } - - if ((selector & 0x2000) != 0) { - buf.readUnsignedByte(); // card 1 type - buf.readUnsignedByte(); // card 1 country code - String card = buf.readSlice(20).toString(StandardCharsets.US_ASCII).trim(); - if (!card.isEmpty()) { - position.set("card1", card); - } - } - - if ((selector & 0x4000) != 0) { - buf.readUnsignedByte(); // card 2 type - buf.readUnsignedByte(); // card 2 country code - String card = buf.readSlice(20).toString(StandardCharsets.US_ASCII).trim(); - if (!card.isEmpty()) { - position.set("card2", card); - } - } - - if ((selector & 0x10000) != 0) { - int count = buf.readUnsignedByte(); - for (int i = 1; i <= count; i++) { - position.set("driver" + i, buf.readSlice(22).toString(StandardCharsets.US_ASCII).trim()); - position.set("driverTime" + i, buf.readUnsignedInt()); - } - } - } - - private void decodeH(Position position, ByteBuf buf, int selector) { - - if ((selector & 0x0004) != 0) { - getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); - } else { - getLastLocation(position, null); - } - - if ((selector & 0x0040) != 0) { - buf.readUnsignedInt(); // reset time - } - - if ((selector & 0x2000) != 0) { - buf.readUnsignedShort(); // snapshot counter - } - - int index = 1; - while (buf.readableBytes() > 0) { - - position.set("h" + index + "Index", buf.readUnsignedByte()); - - buf.readUnsignedShort(); // length - - int n = buf.readUnsignedByte(); - int m = buf.readUnsignedByte(); - - position.set("h" + index + "XLength", n); - position.set("h" + index + "YLength", m); - - if ((selector & 0x0008) != 0) { - position.set("h" + index + "XType", buf.readUnsignedByte()); - position.set("h" + index + "YType", buf.readUnsignedByte()); - position.set("h" + index + "Parameters", buf.readUnsignedByte()); - } - - boolean percentageFormat = (selector & 0x0020) != 0; - - StringBuilder data = new StringBuilder(); - for (int i = 0; i < n * m; i++) { - if (percentageFormat) { - data.append(buf.readUnsignedByte() * 0.5).append("%").append(" "); - } else { - data.append(buf.readUnsignedShort()).append(" "); - } - } - - position.set("h" + index + "Data", data.toString().trim()); - - position.set("h" + index + "Total", buf.readUnsignedInt()); - - if ((selector & 0x0010) != 0) { - int k = buf.readUnsignedByte(); - - data = new StringBuilder(); - for (int i = 1; i < n; i++) { - if (k == 1) { - data.append(buf.readByte()).append(" "); - } else if (k == 2) { - data.append(buf.readShort()).append(" "); - } - } - position.set("h" + index + "XLimits", data.toString().trim()); - - data = new StringBuilder(); - for (int i = 1; i < m; i++) { - if (k == 1) { - data.append(buf.readByte()).append(" "); - } else if (k == 2) { - data.append(buf.readShort()).append(" "); - } - } - position.set("h" + index + "YLimits", data.toString().trim()); - } - - index += 1; - } - } - - private void decodeEB(Position position, ByteBuf buf) { - - if (buf.readByte() != (byte) 'E' || buf.readByte() != (byte) 'B') { - return; - } - - position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); - position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - position.set("dataValidity", buf.readUnsignedByte()); - position.set("towed", buf.readUnsignedByte()); - buf.readUnsignedShort(); // length - - while (buf.readableBytes() > 0) { - buf.readUnsignedByte(); // towed position - int type = buf.readUnsignedByte(); - int length = buf.readUnsignedByte(); - int end = buf.readerIndex() + length; - - switch (type) { - case 0x01: - position.set("brakeFlags", ByteBufUtil.hexDump(buf.readSlice(length))); - break; - case 0x02: - position.set("wheelSpeed", buf.readUnsignedShort() / 256.0); - position.set("wheelSpeedDifference", buf.readUnsignedShort() / 256.0 - 125.0); - position.set("lateralAcceleration", buf.readUnsignedByte() / 10.0 - 12.5); - position.set("vehicleSpeed", buf.readUnsignedShort() / 256.0); - break; - case 0x03: - position.set(Position.KEY_AXLE_WEIGHT, buf.readUnsignedShort() * 2); - break; - case 0x04: - position.set("tyrePressure", buf.readUnsignedByte() * 10); - position.set("pneumaticPressure", buf.readUnsignedByte() * 5); - break; - case 0x05: - position.set("brakeLining", buf.readUnsignedByte() * 0.4); - position.set("brakeTemperature", buf.readUnsignedByte() * 10); - break; - case 0x06: - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 5L); - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt() * 5L); - position.set(Position.KEY_ODOMETER_SERVICE, (buf.readUnsignedInt() - 2105540607) * 5L); - break; - case 0x0A: - position.set("absStatusCounter", buf.readUnsignedShort()); - position.set("atvbStatusCounter", buf.readUnsignedShort()); - position.set("vdcActiveCounter", buf.readUnsignedShort()); - break; - case 0x0B: - position.set("brakeMinMaxData", ByteBufUtil.hexDump(buf.readSlice(length))); - break; - case 0x0C: - position.set("missingPgn", ByteBufUtil.hexDump(buf.readSlice(length))); - break; - case 0x0D: - buf.readUnsignedByte(); - position.set("towedDetectionStatus", buf.readUnsignedInt()); - buf.skipBytes(17); // vin - break; - case 0x0E: - default: - break; - } - - buf.readerIndex(end); - } - } - - private void decodeF(Position position, ByteBuf buf, int selector) { - - Date deviceTime = null; - - if ((selector & 0x0004) != 0) { - deviceTime = new Date(buf.readUnsignedInt() * 1000); - } - - getLastLocation(position, deviceTime); - - buf.readUnsignedByte(); // data validity - - if ((selector & 0x0008) != 0) { - position.set(Position.KEY_RPM, buf.readUnsignedShort()); - position.set("rpmMax", buf.readUnsignedShort()); - position.set("rpmMin", buf.readUnsignedShort()); - } - - if ((selector & 0x0010) != 0) { - position.set("engineTemp", buf.readShort()); - position.set("engineTempMax", buf.readShort()); - position.set("engineTempMin", buf.readShort()); - } - - if ((selector & 0x0020) != 0) { - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(buf.readUnsignedInt())); - position.set("serviceDistance", buf.readInt()); - position.set("driverActivity", buf.readUnsignedByte()); - position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); - position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); - } - - if ((selector & 0x0040) != 0) { - position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt()); - } - - if ((selector & 0x0080) != 0) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - } - - if ((selector & 0x0100) != 0) { - position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); - position.set("speedMax", buf.readUnsignedByte()); - position.set("speedMin", buf.readUnsignedByte()); - position.set("hardBraking", buf.readUnsignedByte()); - } - - if ((selector & 0x0200) != 0) { - position.set("tachographSpeed", buf.readUnsignedByte()); - position.set("driver1State", buf.readUnsignedByte()); - position.set("driver2State", buf.readUnsignedByte()); - position.set("tachographStatus", buf.readUnsignedByte()); - position.set("overspeedCount", buf.readUnsignedByte()); - } - - if ((selector & 0x0800) != 0) { - position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 0.05); - position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); - position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() / 256.0); - position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.5); - position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); - } - - if ((selector & 0x1000) != 0) { - position.set("ambientTemperature", buf.readUnsignedShort() * 0.03125 - 273); - buf.readUnsignedShort(); // fuel rate - position.set("fuelEconomy", buf.readUnsignedShort() / 512.0); - position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt() * 0.001); - buf.readUnsignedByte(); // pto drive engagement - } - - if ((selector & 0x2000) != 0) { - buf.skipBytes(buf.readUnsignedByte()); // driver identification - } - - if ((selector & 0x4000) != 0) { - position.set("torque", buf.readUnsignedByte()); - position.set("brakePressure1", buf.readUnsignedByte() * 8); - position.set("brakePressure2", buf.readUnsignedByte() * 8); - position.set("grossWeight", buf.readUnsignedShort() * 10); - position.set("exhaustFluid", buf.readUnsignedByte() * 0.4); - buf.readUnsignedByte(); // retarder torque mode - position.set("retarderTorque", buf.readUnsignedByte()); - position.set("retarderSelection", buf.readUnsignedByte() * 0.4); - buf.skipBytes(8); // tell tale status block 1 - buf.skipBytes(8); // tell tale status block 2 - buf.skipBytes(8); // tell tale status block 3 - buf.skipBytes(8); // tell tale status block 4 - } - - if ((selector & 0x8000) != 0) { - position.set("parkingBrakeStatus", buf.readUnsignedByte()); - position.set("doorStatus", buf.readUnsignedByte()); - buf.skipBytes(8); // status per door - position.set("alternatorStatus", buf.readUnsignedByte()); - position.set("selectedGear", buf.readUnsignedByte()); - position.set("currentGear", buf.readUnsignedByte()); - buf.skipBytes(4 * 2); // air suspension pressure - } - - if ((selector & 0x0400) != 0) { - int count = buf.readUnsignedByte(); - for (int i = 0; i < count; i++) { - position.set("axle" + i, buf.readUnsignedShort()); - } - } - - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - char protocol = (char) buf.readByte(); - int version = buf.readUnsignedByte(); - - String imei; - if ((version & 0x80) != 0) { - imei = String.valueOf((buf.readUnsignedInt() << (3 * 8)) | buf.readUnsignedMedium()); - } else { - imei = String.valueOf(imeiFromUnitId(buf.readUnsignedMedium())); - } - - buf.readUnsignedShort(); // length - - int selector = DEFAULT_SELECTOR_D; - if (protocol == 'E') { - selector = DEFAULT_SELECTOR_E; - } else if (protocol == 'F') { - selector = DEFAULT_SELECTOR_F; - } - if ((version & 0x40) != 0) { - selector = buf.readUnsignedMedium(); - } - - Position position = new Position(getProtocolName()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - int event = buf.readUnsignedByte(); - position.set(Position.KEY_EVENT, event); - position.set("eventInfo", buf.readUnsignedByte()); - - if (protocol == 'D') { - decodeD(position, buf, selector, event); - } else if (protocol == 'E') { - decodeE(position, buf, selector); - } else if (protocol == 'H') { - decodeH(position, buf, selector); - } else if (protocol == 'F') { - decodeF(position, buf, selector); - } else { - return null; - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/AppelloProtocol.java b/src/org/traccar/protocol/AppelloProtocol.java deleted file mode 100644 index 1ca4168e4..000000000 --- a/src/org/traccar/protocol/AppelloProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AppelloProtocol extends BaseProtocol { - - public AppelloProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new AppelloProtocolDecoder(AppelloProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AppelloProtocolDecoder.java b/src/org/traccar/protocol/AppelloProtocolDecoder.java deleted file mode 100644 index 47e329234..000000000 --- a/src/org/traccar/protocol/AppelloProtocolDecoder.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class AppelloProtocolDecoder extends BaseProtocolDecoder { - - public AppelloProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("FOLLOWIT,") // brand - .number("(d+),") // imei - .groupBegin() - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .or() - .text("UTCTIME,") - .groupEnd() - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+),") // satellites - .number("(-?d+),") // altitude - .expression("([FL]),") // gps state - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - String imei = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.hasNext(6)) { - position.setTime(parser.nextDateTime()); - } else { - getLastLocation(position, null); - } - - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - - position.setAltitude(parser.nextDouble(0)); - - position.setValid(parser.next().equals("F")); - - return position; - } - -} diff --git a/src/org/traccar/protocol/AppletProtocol.java b/src/org/traccar/protocol/AppletProtocol.java deleted file mode 100644 index 2297dca03..000000000 --- a/src/org/traccar/protocol/AppletProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AppletProtocol extends BaseProtocol { - - public AppletProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(16384)); - pipeline.addLast(new AppletProtocolDecoder(AppletProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AppletProtocolDecoder.java b/src/org/traccar/protocol/AppletProtocolDecoder.java deleted file mode 100644 index 7a995cc24..000000000 --- a/src/org/traccar/protocol/AppletProtocolDecoder.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpResponseStatus; -import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; - -import java.net.SocketAddress; - -public class AppletProtocolDecoder extends BaseHttpProtocolDecoder { - - public AppletProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, request.headers().get("From")); - if (deviceSession != null) { - sendResponse(channel, HttpResponseStatus.OK); - } else { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/AquilaProtocol.java b/src/org/traccar/protocol/AquilaProtocol.java deleted file mode 100644 index 5ca1ec091..000000000 --- a/src/org/traccar/protocol/AquilaProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AquilaProtocol extends BaseProtocol { - - public AquilaProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new AquilaProtocolDecoder(AquilaProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AquilaProtocolDecoder.java b/src/org/traccar/protocol/AquilaProtocolDecoder.java deleted file mode 100644 index 57af5e366..000000000 --- a/src/org/traccar/protocol/AquilaProtocolDecoder.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class AquilaProtocolDecoder extends BaseProtocolDecoder { - - public AquilaProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_A = new PatternBuilder() - .text("$$") - .expression("[^,]*,") // client - .number("(d+),") // device serial number - .number("(d+),") // event - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // validity - .groupBegin() - .number("(d+),") // gsm - .number("(d+),") // speed - .number("(d+),") // distance - .groupBegin() - .number("d+,") // driver code - .number("(d+),") // fuel - .number("([01]),") // io 1 - .number("[01],") // case open switch - .number("[01],") // over speed start - .number("[01],") // over speed end - .number("(?:d+,){3}") // reserved - .number("([01]),") // power status - .number("([01]),") // io 2 - .number("d+,") // reserved - .number("([01]),") // ignition - .number("[01],") // ignition off event - .number("(?:d+,){7}") // reserved - .number("[01],") // corner packet - .number("(?:d+,){8}") // reserved - .number("([01]),") // course bit 0 - .number("([01]),") // course bit 1 - .number("([01]),") // course bit 2 - .number("([01]),") // course bit 3 - .or() - .number("(d+),") // course - .number("(?:d+,){3}") // reserved - .number("[01],") // over speed start - .number("[01],") // over speed end - .number("(?:d+,){3}") // reserved - .number("([01]),") // power status - .number("(?:d+,){2}") // reserved - .number("[01],") // ignition on event - .number("([01]),") // ignition - .number("[01],") // ignition off event - .number("(?:d+,){5}") // reserved - .number("[01],") // low battery - .number("[01],") // corner packet - .number("(?:d+,){6}") // reserved - .number("[01],") // hard acceleration - .number("[01],") // hard braking - .number("[01],[01],[01],[01],") // course bits - .number("(d+),") // external voltage - .number("(d+),") // internal voltage - .number("(?:d+,){6}") // reserved - .expression("P([^,]+),") // obd - .expression("D([^,]+),") // dtcs - .number("-?d+,") // accelerometer x - .number("-?d+,") // accelerometer y - .number("-?d+,") // accelerometer z - .number("d+,") // delta distance - .or() - .number("(d+),") // course - .number("(d+),") // satellites - .number("(d+.d+),") // hdop - .number("(?:d+,){2}") // reserved - .number("(d+),") // adc 1 - .number("([01]),") // di 1 - .number("[01],") // case open - .number("[01],") // over speed start - .number("[01],") // over speed end - .number("(?:[01],){2}") // reserved - .number("[01],") // immobilizer - .number("([01]),") // power status - .number("([01]),") // di 2 - .number("(?:[01],){2}") // reserved - .number("([01]),") // ignition - .number("(?:[01],){6}") // reserved - .number("[01],") // low battery - .number("[01],") // corner packet - .number("(?:[01],){4}") // reserved - .number("[01],") // do 1 - .number("[01],") // reserved - .number("[01],") // hard acceleration - .number("[01],") // hard braking - .number("(?:[01],){4}") // reserved - .number("(d+),") // external voltage - .number("(d+),") // internal voltage - .groupEnd() - .or() - .number("(d+),") // sensor id - .expression("([^,]+),") // sensor data - .groupEnd() - .text("*") - .number("xx") // checksum - .compile(); - - private Position decodeA(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_A, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_EVENT, parser.nextInt(0)); - - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - - position.setTime(parser.nextDateTime()); - - position.setValid(parser.next().equals("A")); - - if (parser.hasNext(3)) { - position.set(Position.KEY_RSSI, parser.nextInt(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - } - - if (parser.hasNext(9)) { - - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); - position.set(Position.PREFIX_IN + 1, parser.next()); - position.set(Position.KEY_CHARGE, parser.next().equals("1")); - position.set(Position.PREFIX_IN + 2, parser.next()); - - position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); - - int course = (parser.nextInt(0) << 3) + (parser.nextInt(0) << 2) - + (parser.nextInt(0) << 1) + parser.nextInt(0); - if (course > 0 && course <= 8) { - position.setCourse((course - 1) * 45); - } - - } else if (parser.hasNext(7)) { - - position.setCourse(parser.nextInt(0)); - - position.set(Position.KEY_CHARGE, parser.next().equals("1")); - position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); - position.set(Position.KEY_POWER, parser.nextInt(0)); - position.set(Position.KEY_BATTERY, parser.nextInt(0)); - - String obd = parser.next(); - position.set("obd", obd.substring(1, obd.length() - 1)); - - String dtcs = parser.next(); - position.set(Position.KEY_DTCS, dtcs.substring(1, dtcs.length() - 1).replace('|', ' ')); - - } else if (parser.hasNext(10)) { - - position.setCourse(parser.nextInt(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_HDOP, parser.nextDouble(0)); - position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); - position.set(Position.PREFIX_IN + 1, parser.nextInt(0)); - position.set(Position.KEY_CHARGE, parser.next().equals("1")); - position.set(Position.PREFIX_IN + 2, parser.nextInt(0)); - position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); - position.set(Position.KEY_POWER, parser.nextInt(0)); - position.set(Position.KEY_BATTERY, parser.nextInt(0)); - - } else if (parser.hasNext(2)) { - - position.set("sensorId", parser.nextInt()); - position.set("sensorData", parser.next()); - - } - - return position; - } - - private static final Pattern PATTERN_B_1 = new PatternBuilder() - .text("$") - .expression("[^,]+,") // header - .expression("[^,]+,") // client - .expression("[^,]+,") // firmware version - .expression(".{2},") // packet type - .number("d+,") // message id - .expression("[LH],") // status - .number("(d+),") // imei - .expression("[^,]+,") // registration number - .number("([01]),") // validity - .number("(dd)(dd)(dddd),") // date (ddmmyyyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // latitude - .expression("([NS]),") - .number("(-?d+.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+),") // speed - .number("(d+),") // course - .number("(d+),") // satellites - .number("(-?d+.d+),") // altitude - .number("(d+.d+),") // pdop - .number("(d+.d+),") // hdop - .expression("[^,]+,") // operator - .number("([01]),") // ignition - .number("([01]),") // charge - .number("(d+.d+),") // power - .number("(d+.d+),") // battery - .number("([01]),") // emergency - .expression("[CO],") // tamper - .number("(d+),") // rssi - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(x+),") // lac - .number("(x+),") // cid - .number("(d+),(x+),(x+),") // cell 1 - .number("(d+),(x+),(x+),") // cell 2 - .number("(d+),(x+),(x+),") // cell 3 - .number("(d+),(x+),(x+),") // cell 4 - .number("([01])+,") // inputs - .number("([01])+,") // outputs - .number("d+,") // frame number - .number("(d+.d+),") // adc1 - .number("(d+.d+),") // adc2 - .number("d+,") // delta distance - .any() - .compile(); - - private static final Pattern PATTERN_B_2 = new PatternBuilder() - .text("$") - .expression("[^,]+,") // header - .expression("[^,]+,") // client - .expression("(.{3}),") // message type - .number("(d+),") // imei - .expression(".{2},") // packet type - .number("(dd)(dd)(dddd)") // date (ddmmyyyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // validity - .number("(-?d+.d+),") // latitude - .expression("([NS]),") - .number("(-?d+.d+),") // longitude - .expression("([EW]),") - .number("(-?d+.d+),") // altitude - .number("(d+.d+),") // speed - .any() - .compile(); - - private Position decodeB2(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_B_2, sentence); - if (!parser.matches()) { - return null; - } - - String type = parser.next(); - String id = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setAltitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - - if (type.equals("EMR") && channel != null) { - String password = Context.getIdentityManager().lookupAttributeString( - deviceSession.getDeviceId(), getProtocolName() + ".password", "aquila123", true); - channel.writeAndFlush(new NetworkMessage( - "#set$" + id + "@" + password + "#EMR_MODE:0*", remoteAddress)); - } - - return position; - } - - private Position decodeB1(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_B_1, sentence); - if (!parser.matches()) { - return null; - } - - String id = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.nextInt() == 1); - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextInt()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - position.setAltitude(parser.nextDouble()); - - position.set(Position.KEY_PDOP, parser.nextDouble()); - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - position.set(Position.KEY_CHARGE, parser.nextInt() == 1); - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - - if (parser.nextInt() == 1) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - - Network network = new Network(); - - int rssi = parser.nextInt(); - int mcc = parser.nextInt(); - int mnc = parser.nextInt(); - - network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt(), rssi)); - for (int i = 0; i < 4; i++) { - rssi = parser.nextInt(); - network.addCellTower(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt(), rssi)); - } - - position.setNetwork(network); - - position.set(Position.KEY_INPUT, parser.nextBinInt()); - position.set(Position.KEY_OUTPUT, parser.nextBinInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); - - return position; - } - - private Position decodeB(Channel channel, SocketAddress remoteAddress, String sentence) { - if (sentence.contains("EMR") || sentence.contains("SEM")) { - return decodeB2(channel, remoteAddress, sentence); - } else { - return decodeB1(channel, remoteAddress, sentence); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("$$")) { - return decodeA(channel, remoteAddress, sentence); - } else { - return decodeB(channel, remoteAddress, sentence); - } - } - -} diff --git a/src/org/traccar/protocol/Ardi01Protocol.java b/src/org/traccar/protocol/Ardi01Protocol.java deleted file mode 100644 index f7826430f..000000000 --- a/src/org/traccar/protocol/Ardi01Protocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Ardi01Protocol extends BaseProtocol { - - public Ardi01Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Ardi01ProtocolDecoder(Ardi01Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Ardi01ProtocolDecoder.java b/src/org/traccar/protocol/Ardi01ProtocolDecoder.java deleted file mode 100644 index 85e9ecfde..000000000 --- a/src/org/traccar/protocol/Ardi01ProtocolDecoder.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Ardi01ProtocolDecoder extends BaseProtocolDecoder { - - public Ardi01ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(d+),") // imei - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // longitude - .number("(-?d+.d+),") // latitude - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(-?d+.?d*),") // altitude - .number("(d+),") // satellites - .number("(d+),") // event - .number("(d+),") // battery - .number("(-?d+)") // temperature - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setLongitude(parser.nextDouble(0)); - position.setLatitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - int satellites = parser.nextInt(0); - position.setValid(satellites >= 3); - position.set(Position.KEY_SATELLITES, satellites); - - position.set(Position.KEY_EVENT, parser.next()); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); - position.set(Position.PREFIX_TEMP + 1, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/ArknavProtocol.java b/src/org/traccar/protocol/ArknavProtocol.java deleted file mode 100644 index 3b485e4a5..000000000 --- a/src/org/traccar/protocol/ArknavProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ArknavProtocol extends BaseProtocol { - - public ArknavProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new ArknavProtocolDecoder(ArknavProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ArknavProtocolDecoder.java b/src/org/traccar/protocol/ArknavProtocolDecoder.java deleted file mode 100644 index 4982e02fc..000000000 --- a/src/org/traccar/protocol/ArknavProtocolDecoder.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class ArknavProtocolDecoder extends BaseProtocolDecoder { - - public ArknavProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(d+),") // imei - .expression(".{6},") // id code - .number("ddd,") // status - .number("Lddd,") // version - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(d+.?d*),") // hdop - .number("(dd):(dd):(dd) ") // time (hh:mm:ss) - .number("(dd)-(dd)-(dd),") // date (dd-mm-yy) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_HDOP, parser.nextDouble(0)); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/ArknavX8Protocol.java b/src/org/traccar/protocol/ArknavX8Protocol.java deleted file mode 100644 index a29bc1ad3..000000000 --- a/src/org/traccar/protocol/ArknavX8Protocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ArknavX8Protocol extends BaseProtocol { - - public ArknavX8Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new ArknavX8ProtocolDecoder(ArknavX8Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ArknavX8ProtocolDecoder.java b/src/org/traccar/protocol/ArknavX8ProtocolDecoder.java deleted file mode 100644 index b570f5423..000000000 --- a/src/org/traccar/protocol/ArknavX8ProtocolDecoder.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class ArknavX8ProtocolDecoder extends BaseProtocolDecoder { - - public ArknavX8ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_1G = new PatternBuilder() - .expression("(..),") // type - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+)([NS]),") // latitude - .number("(d+)(dd.d+)([EW]),") // longitude - .number("(d+.d+),") // speed - .number("(d+),") // course - .number("(d+.d+),") // hdop - .number("(d+)") // status - .compile(); - - private static final Pattern PATTERN_2G = new PatternBuilder() - .expression("..,") // type - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d+),") // satellites - .number("(d+.d+),") // altitude - .number("(d+.d+),") // power - .number("(d+.d+),") // battery - .number("(d+.d+)") // odometer - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.charAt(2) != ',') { - getDeviceSession(channel, remoteAddress, sentence.substring(0, 15)); - return null; - } - - switch (sentence.substring(0, 2)) { - case "1G": - case "1R": - case "1M": - return decode1G(channel, remoteAddress, sentence); - case "2G": - return decode2G(channel, remoteAddress, sentence); - default: - return null; - } - } - - private Position decode1G(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_1G, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_TYPE, parser.next()); - - position.setTime(parser.nextDateTime()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_HDOP, parser.nextDouble(0)); - position.set(Position.KEY_STATUS, parser.next()); - - return position; - } - - private Position decode2G(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_2G, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, parser.nextDateTime()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.setAltitude(parser.nextDouble()); - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1852 / 3600); - - return position; - } - -} diff --git a/src/org/traccar/protocol/ArnaviProtocol.java b/src/org/traccar/protocol/ArnaviProtocol.java deleted file mode 100644 index afe491865..000000000 --- a/src/org/traccar/protocol/ArnaviProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ArnaviProtocol extends BaseProtocol { - - public ArnaviProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new ArnaviProtocolDecoder(ArnaviProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ArnaviProtocolDecoder.java b/src/org/traccar/protocol/ArnaviProtocolDecoder.java deleted file mode 100644 index 7996cf429..000000000 --- a/src/org/traccar/protocol/ArnaviProtocolDecoder.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class ArnaviProtocolDecoder extends BaseProtocolDecoder { - - public ArnaviProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$AV,") - .number("Vd,") // type - .number("(d+),") // device id - .number("(d+),") // index - .number("(d+),") // power - .number("(d+),") // battery - .number("-?d+,") - .expression("[01],") // movement - .expression("([01]),") // ignition - .number("(d+),") // input - .number("d+,d+,") // input 1 - .number("d+,d+,").optional() // input 2 - .expression("[01],") // fix type - .number("(d+),") // satellites - .groupBegin() - .number("(d+.d+)?,") // altitude - .number("(?:d+.d+)?,") // geoid height - .groupEnd("?") - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd.d+)([NS]),") // latitude - .number("(ddd)(dd.d+)([EW]),") // longitude - .number("(d+.d+),") // speed - .number("(d+.d+),") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, parser.nextInt()); - position.set(Position.KEY_POWER, parser.nextInt() * 0.01); - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.01); - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - position.set(Position.KEY_INPUT, parser.nextInt()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - position.setAltitude(parser.nextDouble(0)); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble()); - position.setCourse(parser.nextDouble()); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/AstraProtocol.java b/src/org/traccar/protocol/AstraProtocol.java deleted file mode 100644 index 12b0dfb68..000000000 --- a/src/org/traccar/protocol/AstraProtocol.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AstraProtocol extends BaseProtocol { - - public AstraProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2, -3, 0)); - pipeline.addLast(new AstraProtocolDecoder(AstraProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new AstraProtocolDecoder(AstraProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AstraProtocolDecoder.java b/src/org/traccar/protocol/AstraProtocolDecoder.java deleted file mode 100644 index e6f546b9f..000000000 --- a/src/org/traccar/protocol/AstraProtocolDecoder.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.LinkedList; -import java.util.List; - -public class AstraProtocolDecoder extends BaseProtocolDecoder { - - private static final Logger LOGGER = LoggerFactory.getLogger(AstraProtocolDecoder.class); - - public AstraProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_HEARTBEAT = 0x1A; - public static final int MSG_DATA = 0x10; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(new byte[] {0x06}), remoteAddress)); - } - - buf.readUnsignedByte(); // protocol - buf.readUnsignedShort(); // length - - String imei = String.format("%08d", buf.readUnsignedInt()) + String.format("%07d", buf.readUnsignedMedium()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - while (buf.readableBytes() > 2) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedByte(); // index - - position.setValid(true); - position.setLatitude(buf.readInt() * 0.000001); - position.setLongitude(buf.readInt() * 0.000001); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(1980, 1, 6).addMillis(buf.readUnsignedInt() * 1000L); - position.setTime(dateBuilder.getDate()); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte() * 2)); - position.setCourse(buf.readUnsignedByte() * 2); - - int reason = buf.readUnsignedMedium(); - position.set(Position.KEY_EVENT, reason); - - int status = buf.readUnsignedShort(); - position.set(Position.KEY_STATUS, status); - - position.set(Position.PREFIX_IO + 1, buf.readUnsignedByte()); - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedByte()); - position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); - position.set(Position.KEY_POWER, buf.readUnsignedByte()); - - buf.readUnsignedByte(); // max journey speed - buf.skipBytes(6); // accelerometer - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShort()); - buf.readUnsignedShort(); // journey idle time - - position.setAltitude(buf.readUnsignedByte() * 20); - - int quality = buf.readUnsignedByte(); - position.set(Position.KEY_SATELLITES, quality & 0xf); - position.set(Position.KEY_RSSI, quality >> 4); - - buf.readUnsignedByte(); // geofence events - - if (BitUtil.check(status, 8)) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, buf.readSlice(7).toString(StandardCharsets.US_ASCII)); - position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium() * 1000); - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(buf.readUnsignedShort())); - } - - if (BitUtil.check(status, 6)) { - LOGGER.warn("Extension data is not supported"); - return position; - } - - positions.add(position); - - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/At2000FrameDecoder.java b/src/org/traccar/protocol/At2000FrameDecoder.java deleted file mode 100644 index 5fa82a5f7..000000000 --- a/src/org/traccar/protocol/At2000FrameDecoder.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; -import org.traccar.NetworkMessage; - -public class At2000FrameDecoder extends BaseFrameDecoder { - - private static final int BLOCK_LENGTH = 16; - private static final int ACK_LENGTH = 496; - - private boolean firstPacket = true; - - private ByteBuf currentBuffer; - private int acknowledgedBytes; - - private void sendResponse(Channel channel) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(2 * BLOCK_LENGTH); - response.writeByte(At2000ProtocolDecoder.MSG_ACKNOWLEDGEMENT); - response.writeMedium(1); - response.writeByte(0x00); // success - response.writerIndex(2 * BLOCK_LENGTH); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 5) { - return null; - } - - int length; - if (firstPacket) { - firstPacket = false; - length = buf.getUnsignedMediumLE(buf.readerIndex() + 2); - } else { - length = buf.getUnsignedMediumLE(buf.readerIndex() + 1); - } - - length += BLOCK_LENGTH; - if (length % BLOCK_LENGTH != 0) { - length = (length / BLOCK_LENGTH + 1) * BLOCK_LENGTH; - } - - if ((buf.readableBytes() >= length || buf.readableBytes() % ACK_LENGTH == 0) - && (buf != currentBuffer || buf.readableBytes() > acknowledgedBytes)) { - sendResponse(channel); - currentBuffer = buf; - acknowledgedBytes = buf.readableBytes(); - } - - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/At2000Protocol.java b/src/org/traccar/protocol/At2000Protocol.java deleted file mode 100644 index 5894f3eab..000000000 --- a/src/org/traccar/protocol/At2000Protocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class At2000Protocol extends BaseProtocol { - - public At2000Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new At2000FrameDecoder()); - pipeline.addLast(new At2000ProtocolDecoder(At2000Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/At2000ProtocolDecoder.java b/src/org/traccar/protocol/At2000ProtocolDecoder.java deleted file mode 100644 index 43798eb67..000000000 --- a/src/org/traccar/protocol/At2000ProtocolDecoder.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DataConverter; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class At2000ProtocolDecoder extends BaseProtocolDecoder { - - private static final int BLOCK_LENGTH = 16; - - public At2000ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_ACKNOWLEDGEMENT = 0x00; - public static final int MSG_DEVICE_ID = 0x01; - public static final int MSG_TRACK_REQUEST = 0x88; - public static final int MSG_TRACK_RESPONSE = 0x89; - public static final int MSG_SESSION_END = 0x0c; - - private Cipher cipher; - - private static void sendRequest(Channel channel) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(BLOCK_LENGTH); - response.writeByte(MSG_TRACK_REQUEST); - response.writeMedium(0); - response.writerIndex(BLOCK_LENGTH); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (buf.getUnsignedByte(buf.readerIndex()) == 0x01) { - buf.readUnsignedByte(); // codec id - } - - int type = buf.readUnsignedByte(); - buf.readUnsignedMediumLE(); // length - buf.skipBytes(BLOCK_LENGTH - 1 - 3); - - if (type == MSG_DEVICE_ID) { - - String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); - if (getDeviceSession(channel, remoteAddress, imei) != null) { - - byte[] iv = new byte[BLOCK_LENGTH]; - buf.readBytes(iv); - IvParameterSpec ivSpec = new IvParameterSpec(iv); - - SecretKeySpec keySpec = new SecretKeySpec( - DataConverter.parseHex("000102030405060708090a0b0c0d0e0f"), "AES"); - - cipher = Cipher.getInstance("AES/CBC/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); - - byte[] data = new byte[BLOCK_LENGTH]; - buf.readBytes(data); - cipher.update(data); - - } - - } else if (type == MSG_TRACK_RESPONSE) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - if (buf.capacity() <= BLOCK_LENGTH) { - return null; // empty message - } - - List positions = new LinkedList<>(); - - byte[] data = new byte[buf.capacity() - BLOCK_LENGTH]; - buf.readBytes(data); - buf = Unpooled.wrappedBuffer(cipher.update(data)); - try { - while (buf.readableBytes() >= 63) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedShortLE(); // index - buf.readUnsignedShortLE(); // reserved - - position.setValid(true); - - position.setTime(new Date(buf.readLongLE() * 1000)); - - position.setLatitude(buf.readFloatLE()); - position.setLongitude(buf.readFloatLE()); - position.setAltitude(buf.readFloatLE()); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readFloatLE())); - position.setCourse(buf.readFloatLE()); - - buf.readUnsignedIntLE(); // geozone event - buf.readUnsignedIntLE(); // io events - buf.readUnsignedIntLE(); // geozone value - buf.readUnsignedIntLE(); // io values - buf.readUnsignedShortLE(); // operator - - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); - - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); - - buf.readUnsignedShortLE(); // cid - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - buf.readUnsignedByte(); // current profile - - position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte()); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - positions.add(position); - - } - } finally { - buf.release(); - } - - return positions; - - } - - if (type == MSG_DEVICE_ID) { - sendRequest(channel); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/AtrackFrameDecoder.java b/src/org/traccar/protocol/AtrackFrameDecoder.java deleted file mode 100644 index f071e2d97..000000000 --- a/src/org/traccar/protocol/AtrackFrameDecoder.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; -import org.traccar.helper.BufferUtil; - -import java.nio.charset.StandardCharsets; - -public class AtrackFrameDecoder extends BaseFrameDecoder { - - private static final int KEEPALIVE_LENGTH = 12; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() >= 2) { - - if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) { - - if (buf.readableBytes() >= KEEPALIVE_LENGTH) { - return buf.readRetainedSlice(KEEPALIVE_LENGTH); - } - - } else if (buf.getUnsignedShort(buf.readerIndex()) == 0x4050 && buf.getByte(buf.readerIndex() + 2) != ',') { - - if (buf.readableBytes() > 6) { - int length = buf.getUnsignedShort(buf.readerIndex() + 4) + 4 + 2; - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - } - - } else { - - int lengthStart = buf.indexOf(buf.readerIndex() + 3, buf.writerIndex(), (byte) ',') + 1; - if (lengthStart > 0) { - int lengthEnd = buf.indexOf(lengthStart, buf.writerIndex(), (byte) ','); - if (lengthEnd > 0) { - int length = lengthEnd + Integer.parseInt(buf.toString( - lengthStart, lengthEnd - lengthStart, StandardCharsets.US_ASCII)); - if (buf.readableBytes() > length && buf.getByte(buf.readerIndex() + length) == '\n') { - length += 1; - } - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - } - } else { - int endIndex = BufferUtil.indexOf("\r\n", buf); - if (endIndex > 0) { - return buf.readRetainedSlice(endIndex - buf.readerIndex() + 2); - } - } - - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/AtrackProtocol.java b/src/org/traccar/protocol/AtrackProtocol.java deleted file mode 100644 index 8e5cfe9ff..000000000 --- a/src/org/traccar/protocol/AtrackProtocol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class AtrackProtocol extends BaseProtocol { - - public AtrackProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new AtrackFrameDecoder()); - pipeline.addLast(new AtrackProtocolEncoder()); - pipeline.addLast(new AtrackProtocolDecoder(AtrackProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new AtrackProtocolEncoder()); - pipeline.addLast(new AtrackProtocolDecoder(AtrackProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java deleted file mode 100644 index 71bb6791c..000000000 --- a/src/org/traccar/protocol/AtrackProtocolDecoder.java +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class AtrackProtocolDecoder extends BaseProtocolDecoder { - - private static final int MIN_DATA_LENGTH = 40; - - private boolean longDate; - private boolean decimalFuel; - private boolean custom; - private String form; - - private final Map alarmMap = new HashMap<>(); - - public AtrackProtocolDecoder(Protocol protocol) { - super(protocol); - - longDate = Context.getConfig().getBoolean(getProtocolName() + ".longDate"); - decimalFuel = Context.getConfig().getBoolean(getProtocolName() + ".decimalFuel"); - - custom = Context.getConfig().getBoolean(getProtocolName() + ".custom"); - form = Context.getConfig().getString(getProtocolName() + ".form"); - if (form != null) { - custom = true; - } - - for (String pair : Context.getConfig().getString(getProtocolName() + ".alarmMap", "").split(",")) { - if (!pair.isEmpty()) { - alarmMap.put( - Integer.parseInt(pair.substring(0, pair.indexOf('='))), pair.substring(pair.indexOf('=') + 1)); - } - } - } - - public void setLongDate(boolean longDate) { - this.longDate = longDate; - } - - public void setCustom(boolean custom) { - this.custom = custom; - } - - private static void sendResponse(Channel channel, SocketAddress remoteAddress, long rawId, int index) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(12); - response.writeShort(0xfe02); - response.writeLong(rawId); - response.writeShort(index); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - private static String readString(ByteBuf buf) { - String result = null; - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0); - if (index > buf.readerIndex()) { - result = buf.readSlice(index - buf.readerIndex()).toString(StandardCharsets.US_ASCII); - } - buf.readByte(); - return result; - } - - private void readTextCustomData(Position position, String data, String form) { - CellTower cellTower = new CellTower(); - String[] keys = form.substring(1).split("%"); - String[] values = data.split(",|\r\n"); - for (int i = 0; i < Math.min(keys.length, values.length); i++) { - switch (keys[i]) { - case "SA": - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[i])); - break; - case "MV": - position.set(Position.KEY_POWER, Integer.parseInt(values[i]) * 0.1); - break; - case "BV": - position.set(Position.KEY_BATTERY, Integer.parseInt(values[i]) * 0.1); - break; - case "GQ": - cellTower.setSignalStrength(Integer.parseInt(values[i])); - break; - case "CE": - cellTower.setCellId(Long.parseLong(values[i])); - break; - case "LC": - cellTower.setLocationAreaCode(Integer.parseInt(values[i])); - break; - case "CN": - if (values[i].length() > 3) { - cellTower.setMobileCountryCode(Integer.parseInt(values[i].substring(0, 3))); - cellTower.setMobileNetworkCode(Integer.parseInt(values[i].substring(3))); - } - break; - case "PC": - position.set(Position.PREFIX_COUNT + 1, Integer.parseInt(values[i])); - break; - case "AT": - position.setAltitude(Integer.parseInt(values[i])); - break; - case "RP": - position.set(Position.KEY_RPM, Integer.parseInt(values[i])); - break; - case "GS": - position.set(Position.KEY_RSSI, Integer.parseInt(values[i])); - break; - case "DT": - position.set(Position.KEY_ARCHIVE, Integer.parseInt(values[i]) == 1); - break; - case "VN": - position.set(Position.KEY_VIN, values[i]); - break; - case "TR": - position.set(Position.KEY_THROTTLE, Integer.parseInt(values[i])); - break; - case "ET": - position.set(Position.PREFIX_TEMP + 1, Integer.parseInt(values[i])); - break; - case "FL": - position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(values[i])); - break; - case "FC": - position.set(Position.KEY_FUEL_CONSUMPTION, Integer.parseInt(values[i])); - break; - case "AV1": - position.set(Position.PREFIX_ADC + 1, Integer.parseInt(values[i])); - break; - default: - break; - } - } - - if (cellTower.getMobileCountryCode() != null - && cellTower.getMobileNetworkCode() != null - && cellTower.getCellId() != null - && cellTower.getLocationAreaCode() != null) { - position.setNetwork(new Network(cellTower)); - } else if (cellTower.getSignalStrength() != null) { - position.set(Position.KEY_RSSI, cellTower.getSignalStrength()); - } - } - - private void readBinaryCustomData(Position position, ByteBuf buf, String form) { - CellTower cellTower = new CellTower(); - String[] keys = form.substring(1).split("%"); - for (String key : keys) { - switch (key) { - case "SA": - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - break; - case "MV": - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); - break; - case "BV": - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.1); - break; - case "GQ": - cellTower.setSignalStrength((int) buf.readUnsignedByte()); - break; - case "CE": - cellTower.setCellId(buf.readUnsignedInt()); - break; - case "LC": - cellTower.setLocationAreaCode(buf.readUnsignedShort()); - break; - case "CN": - int combinedMobileCodes = (int) (buf.readUnsignedInt() % 100000); // cccnn - cellTower.setMobileCountryCode(combinedMobileCodes / 100); - cellTower.setMobileNetworkCode(combinedMobileCodes % 100); - break; - case "RL": - buf.readUnsignedByte(); // rxlev - break; - case "PC": - position.set(Position.PREFIX_COUNT + 1, buf.readUnsignedInt()); - break; - case "AT": - position.setAltitude(buf.readUnsignedInt()); - break; - case "RP": - position.set(Position.KEY_RPM, buf.readUnsignedShort()); - break; - case "GS": - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - break; - case "DT": - position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() == 1); - break; - case "VN": - position.set(Position.KEY_VIN, readString(buf)); - break; - case "MF": - buf.readUnsignedShort(); // mass air flow rate - break; - case "EL": - buf.readUnsignedByte(); // engine load - break; - case "TR": - position.set(Position.KEY_THROTTLE, buf.readUnsignedByte()); - break; - case "ET": - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort()); - break; - case "FL": - position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); - break; - case "ML": - buf.readUnsignedByte(); // mil status - break; - case "FC": - position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt()); - break; - case "CI": - readString(buf); // format string - break; - case "AV1": - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - break; - case "NC": - readString(buf); // gsm neighbor cell info - break; - case "SM": - buf.readUnsignedShort(); // max speed between reports - break; - case "GL": - readString(buf); // google link - break; - case "MA": - readString(buf); // mac address - break; - case "PD": - buf.readUnsignedByte(); // pending code status - break; - case "CD": - readString(buf); // sim cid - break; - case "CM": - buf.readLong(); // imsi - break; - case "GN": - buf.skipBytes(60); // g sensor data - break; - case "GV": - buf.skipBytes(6); // maximum g force - break; - case "ME": - buf.readLong(); // imei - break; - case "IA": - buf.readUnsignedByte(); // intake air temperature - break; - case "MP": - buf.readUnsignedByte(); // manifold absolute pressure - break; - default: - break; - } - } - - if (cellTower.getMobileCountryCode() != null - && cellTower.getMobileNetworkCode() != null - && cellTower.getCellId() != null && cellTower.getCellId() != 0 - && cellTower.getLocationAreaCode() != null) { - position.setNetwork(new Network(cellTower)); - } else if (cellTower.getSignalStrength() != null) { - position.set(Position.KEY_RSSI, cellTower.getSignalStrength()); - } - } - - private static final Pattern PATTERN_INFO = new PatternBuilder() - .text("$INFO=") - .number("(d+),") // unit id - .expression("([^,]+),") // model - .expression("([^,]+),") // firmware version - .number("d+,") // imei - .number("d+,") // imsi - .number("d+,") // sim card id - .number("(d+),") // power - .number("(d+),") // battery - .number("(d+),") // satellites - .number("d+,") // gsm status - .number("(d+),") // rssi - .number("d+,") // connection status - .number("d+") // antenna status - .any() - .compile(); - - private Position decodeInfo(Channel channel, SocketAddress remoteAddress, String sentence) { - - Position position = new Position(getProtocolName()); - - getLastLocation(position, null); - - DeviceSession deviceSession; - - if (sentence.startsWith("$INFO")) { - - Parser parser = new Parser(PATTERN_INFO, sentence); - if (!parser.matches()) { - return null; - } - - deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - - position.set("model", parser.next()); - position.set(Position.KEY_VERSION_FW, parser.next()); - position.set(Position.KEY_POWER, parser.nextInt() * 0.1); - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_RSSI, parser.nextInt()); - - } else { - - deviceSession = getDeviceSession(channel, remoteAddress); - - position.set(Position.KEY_RESULT, sentence); - - } - - if (deviceSession == null) { - return null; - } else { - position.setDeviceId(deviceSession.getDeviceId()); - return position; - } - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(d+),") // date and time - .number("d+,") // rtc date and time - .number("d+,") // device date and time - .number("(-?d+),") // longitude - .number("(-?d+),") // latitude - .number("(d+),") // course - .number("(d+),") // report id - .number("(d+.?d*),") // odometer - .number("(d+),") // hdop - .number("(d+),") // inputs - .number("(d+),") // speed - .number("(d+),") // outputs - .number("(d+),") // adc - .number("([^,]+)?,") // driver - .number("(d+),") // temp1 - .number("(d+),") // temp2 - .expression("[^,]*,") // text message - .expression("(.*)") // custom data - .optional(2) - .compile(); - - private List decodeText(Channel channel, SocketAddress remoteAddress, String sentence) { - - int startIndex = 0; - for (int i = 0; i < 4; i++) { - startIndex = sentence.indexOf(',', startIndex + 1); - } - int endIndex = sentence.indexOf(',', startIndex + 1); - - String imei = sentence.substring(startIndex + 1, endIndex); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - String[] lines = sentence.substring(endIndex + 1).split("\r\n"); - - for (String line : lines) { - Position position = decodeTextLine(deviceSession, line); - if (position != null) { - positions.add(position); - } - } - - return positions; - } - - - private Position decodeTextLine(DeviceSession deviceSession, String sentence) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(true); - - String time = parser.next(); - if (time.length() >= 14) { - try { - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(time)); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } else { - position.setTime(new Date(Long.parseLong(time) * 1000)); - } - - position.setLongitude(parser.nextInt() * 0.000001); - position.setLatitude(parser.nextInt() * 0.000001); - position.setCourse(parser.nextInt()); - - position.set(Position.KEY_EVENT, parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 100); - position.set(Position.KEY_HDOP, parser.nextInt() * 0.1); - position.set(Position.KEY_INPUT, parser.nextInt()); - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); - - position.set(Position.KEY_OUTPUT, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextInt()); - - if (parser.hasNext()) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - } - - position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); - position.set(Position.PREFIX_TEMP + 2, parser.nextInt()); - - if (custom) { - String data = parser.next(); - String form = this.form; - if (form == null) { - form = data.substring(0, data.indexOf(',')).substring("%CI".length()); - data = data.substring(data.indexOf(',') + 1); - } - readTextCustomData(position, data, form); - } - - return position; - } - - private List decodeBinary(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - buf.skipBytes(2); // prefix - buf.readUnsignedShort(); // checksum - buf.readUnsignedShort(); // length - int index = buf.readUnsignedShort(); - - long id = buf.readLong(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); - if (deviceSession == null) { - return null; - } - - sendResponse(channel, remoteAddress, id, index); - - List positions = new LinkedList<>(); - - while (buf.readableBytes() >= MIN_DATA_LENGTH) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (longDate) { - - DateBuilder dateBuilder = new DateBuilder() - .setDate(buf.readUnsignedShort(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - buf.skipBytes(7 + 7); - - } else { - position.setFixTime(new Date(buf.readUnsignedInt() * 1000)); - position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000)); - buf.readUnsignedInt(); // send time - } - - position.setValid(true); - position.setLongitude(buf.readInt() * 0.000001); - position.setLatitude(buf.readInt() * 0.000001); - position.setCourse(buf.readUnsignedShort()); - - int type = buf.readUnsignedByte(); - position.set(Position.KEY_TYPE, type); - position.set(Position.KEY_ALARM, alarmMap.get(type)); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); - position.set(Position.KEY_HDOP, buf.readUnsignedShort() * 0.1); - position.set(Position.KEY_INPUT, buf.readUnsignedByte()); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - - position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.001); - - position.set(Position.KEY_DRIVER_UNIQUE_ID, readString(buf)); - - position.set(Position.PREFIX_TEMP + 1, buf.readShort() * 0.1); - position.set(Position.PREFIX_TEMP + 2, buf.readShort() * 0.1); - - String message = readString(buf); - if (message != null && !message.isEmpty()) { - Pattern pattern = Pattern.compile("FULS:F=(\\p{XDigit}+) t=(\\p{XDigit}+) N=(\\p{XDigit}+)"); - Matcher matcher = pattern.matcher(message); - if (matcher.find()) { - int value = Integer.parseInt(matcher.group(3), decimalFuel ? 10 : 16); - position.set(Position.KEY_FUEL_LEVEL, value * 0.1); - } else { - position.set("message", message); - } - } - - if (custom) { - String form = this.form; - if (form == null) { - form = readString(buf).trim().substring("%CI".length()); - } - readBinaryCustomData(position, buf, form); - } - - positions.add(position); - - } - - return positions; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(buf.retain(), remoteAddress)); // keep-alive message - } - return null; - } else if (buf.getByte(buf.readerIndex()) == '$') { - return decodeInfo(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim()); - } else if (buf.getByte(buf.readerIndex() + 2) == ',') { - return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim()); - } else { - return decodeBinary(channel, remoteAddress, buf); - } - } - -} diff --git a/src/org/traccar/protocol/AtrackProtocolEncoder.java b/src/org/traccar/protocol/AtrackProtocolEncoder.java deleted file mode 100644 index 1e085cb26..000000000 --- a/src/org/traccar/protocol/AtrackProtocolEncoder.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class AtrackProtocolEncoder extends BaseProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return Unpooled.copiedBuffer( - command.getString(Command.KEY_DATA) + "\r\n", StandardCharsets.US_ASCII); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/AuroProtocol.java b/src/org/traccar/protocol/AuroProtocol.java deleted file mode 100644 index b8ebdaa75..000000000 --- a/src/org/traccar/protocol/AuroProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AuroProtocol extends BaseProtocol { - - public AuroProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new AuroProtocolDecoder(AuroProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AuroProtocolDecoder.java b/src/org/traccar/protocol/AuroProtocolDecoder.java deleted file mode 100644 index d7916147b..000000000 --- a/src/org/traccar/protocol/AuroProtocolDecoder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class AuroProtocolDecoder extends BaseProtocolDecoder { - - public AuroProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("M(dddd)") // index - .number("Td+") // phone - .number("I(d+)") // imei - .number("Ed+W") - .text("*****") - .number("d{8}d{4}") // local time - .expression(".{8}#.{8}") - .number("d{10}") // status - .number("([-+])(ddd)(dd)(dddd)") // longitude - .number("([-+])(ddd)(dd)(dddd)") // latitude - .number("(dd)(dd)(dddd)") // date (ddmmyyyy) - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("(ddd)") // course - .number("d{6}") - .number("(ddd)") // speed - .number("d") - .number("(dd)") // battery - .expression("([01])") // charging - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - position.set(Position.KEY_INDEX, parser.nextInt(0)); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(true); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setCourse(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - - position.set(Position.KEY_BATTERY, parser.nextInt(0)); - position.set(Position.KEY_CHARGE, parser.nextInt(0) == 1); - - return position; - } - -} diff --git a/src/org/traccar/protocol/AustinNbProtocol.java b/src/org/traccar/protocol/AustinNbProtocol.java deleted file mode 100644 index 32bfc0aae..000000000 --- a/src/org/traccar/protocol/AustinNbProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AustinNbProtocol extends BaseProtocol { - - public AustinNbProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new AustinNbProtocolDecoder(AustinNbProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AustinNbProtocolDecoder.java b/src/org/traccar/protocol/AustinNbProtocolDecoder.java deleted file mode 100644 index dc6f3d280..000000000 --- a/src/org/traccar/protocol/AustinNbProtocolDecoder.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.TimeZone; -import java.util.regex.Pattern; - -public class AustinNbProtocolDecoder extends BaseProtocolDecoder { - - public AustinNbProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(d+);") // imei - .number("(dddd)-(dd)-(dd) ") // date - .number("(dd):(dd):(dd);") // time - .number("(-?d+,d+);") // latitude - .number("(-?d+,d+);") // longitude - .number("(d+);") // azimuth - .number("(d+);") // angle - .number("(d+);") // range - .number("(d+);") // out of range - .expression("(.*)") // operator - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS, TimeZone.getDefault().getID())); - - position.setValid(true); - position.setLatitude(Double.parseDouble(parser.next().replace(',', '.'))); - position.setLongitude(Double.parseDouble(parser.next().replace(',', '.'))); - position.setCourse(parser.nextInt()); - position.set("angle", parser.nextInt()); - position.set("range", parser.nextInt()); - position.set("outOfRange", parser.nextInt()); - position.set("carrier", parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/AutoFonFrameDecoder.java b/src/org/traccar/protocol/AutoFonFrameDecoder.java deleted file mode 100644 index 69f28133f..000000000 --- a/src/org/traccar/protocol/AutoFonFrameDecoder.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2015 Vitaly Litvak (vitavaque@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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class AutoFonFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - // Check minimum length - if (buf.readableBytes() < 12) { - return null; - } - - int length; - switch (buf.getUnsignedByte(buf.readerIndex())) { - case AutoFonProtocolDecoder.MSG_LOGIN: - length = 12; - break; - case AutoFonProtocolDecoder.MSG_LOCATION: - length = 78; - break; - case AutoFonProtocolDecoder.MSG_HISTORY: - length = 257; - break; - case AutoFonProtocolDecoder.MSG_45_LOGIN: - length = 19; - break; - case AutoFonProtocolDecoder.MSG_45_LOCATION: - length = 34; - break; - default: - length = 0; - break; - } - - // Check length and return buffer - if (length != 0 && buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/AutoFonProtocol.java b/src/org/traccar/protocol/AutoFonProtocol.java deleted file mode 100644 index 08b5edc7d..000000000 --- a/src/org/traccar/protocol/AutoFonProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AutoFonProtocol extends BaseProtocol { - - public AutoFonProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new AutoFonFrameDecoder()); - pipeline.addLast(new AutoFonProtocolDecoder(AutoFonProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AutoFonProtocolDecoder.java b/src/org/traccar/protocol/AutoFonProtocolDecoder.java deleted file mode 100644 index aa05ca2d7..000000000 --- a/src/org/traccar/protocol/AutoFonProtocolDecoder.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2015 Vitaly Litvak (vitavaque@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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.LinkedList; -import java.util.List; - -public class AutoFonProtocolDecoder extends BaseProtocolDecoder { - - public AutoFonProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_LOGIN = 0x10; - public static final int MSG_LOCATION = 0x11; - public static final int MSG_HISTORY = 0x12; - - public static final int MSG_45_LOGIN = 0x41; - public static final int MSG_45_LOCATION = 0x02; - - private static double convertCoordinate(int raw) { - int degrees = raw / 1000000; - double minutes = (raw % 1000000) / 10000.0; - return degrees + minutes / 60; - } - - private static double convertCoordinate(short degrees, int minutes) { - double value = degrees + BitUtil.from(minutes, 4) / 600000.0; - if (BitUtil.check(minutes, 0)) { - return value; - } else { - return -value; - } - } - - private Position decodePosition(DeviceSession deviceSession, ByteBuf buf, boolean history) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (!history) { - buf.readUnsignedByte(); // interval - buf.skipBytes(8); // settings - } - position.set(Position.KEY_STATUS, buf.readUnsignedByte()); - if (!history) { - buf.readUnsignedShort(); - } - position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); - buf.skipBytes(6); // time - - if (!history) { - for (int i = 0; i < 2; i++) { - buf.skipBytes(5); // time - buf.readUnsignedShort(); // interval - buf.skipBytes(5); // mode - } - } - - position.set(Position.PREFIX_TEMP + 1, buf.readByte()); - - int rssi = buf.readUnsignedByte(); - CellTower cellTower = CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readUnsignedShort(), buf.readUnsignedShort(), rssi); - position.setNetwork(new Network(cellTower)); - - int valid = buf.readUnsignedByte(); - position.setValid((valid & 0xc0) != 0); - position.set(Position.KEY_SATELLITES, valid & 0x3f); - - DateBuilder dateBuilder = new DateBuilder() - .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - position.setLatitude(convertCoordinate(buf.readInt())); - position.setLongitude(convertCoordinate(buf.readInt())); - position.setAltitude(buf.readShort()); - position.setSpeed(buf.readUnsignedByte()); - position.setCourse(buf.readUnsignedByte() * 2.0); - - position.set(Position.KEY_HDOP, buf.readUnsignedShort()); - - buf.readUnsignedShort(); // reserved - buf.readUnsignedByte(); // checksum - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int type = buf.readUnsignedByte(); - - if (type == MSG_LOGIN || type == MSG_45_LOGIN) { - - if (type == MSG_LOGIN) { - buf.readUnsignedByte(); // hardware version - buf.readUnsignedByte(); // software version - } - - String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - - if (deviceSession != null && channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeBytes("resp_crc=".getBytes(StandardCharsets.US_ASCII)); - response.writeByte(buf.getByte(buf.writerIndex() - 1)); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - return null; - - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - if (type == MSG_LOCATION) { - - return decodePosition(deviceSession, buf, false); - - } else if (type == MSG_HISTORY) { - - int count = buf.readUnsignedByte() & 0x0f; - buf.readUnsignedShort(); // total count - List positions = new LinkedList<>(); - - for (int i = 0; i < count; i++) { - positions.add(decodePosition(deviceSession, buf, true)); - } - - return positions; - - } else if (type == MSG_45_LOCATION) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - short status = buf.readUnsignedByte(); - if (BitUtil.check(status, 7)) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - position.set(Position.KEY_BATTERY, BitUtil.to(status, 7)); - - buf.skipBytes(2); // remaining time - - position.set(Position.PREFIX_TEMP + 1, buf.readByte()); - - buf.skipBytes(2); // timer (interval and units) - buf.readByte(); // mode - buf.readByte(); // gprs sending interval - - buf.skipBytes(6); // mcc, mnc, lac, cid - - int valid = buf.readUnsignedByte(); - position.setValid(BitUtil.from(valid, 6) != 0); - position.set(Position.KEY_SATELLITES, BitUtil.from(valid, 6)); - - int time = buf.readUnsignedMedium(); - int date = buf.readUnsignedMedium(); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(time / 10000, time / 100 % 100, time % 100) - .setDateReverse(date / 10000, date / 100 % 100, date % 100); - position.setTime(dateBuilder.getDate()); - - position.setLatitude(convertCoordinate(buf.readUnsignedByte(), buf.readUnsignedMedium())); - position.setLongitude(convertCoordinate(buf.readUnsignedByte(), buf.readUnsignedMedium())); - position.setSpeed(buf.readUnsignedByte()); - position.setCourse(buf.readUnsignedShort()); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/AutoGradeProtocol.java b/src/org/traccar/protocol/AutoGradeProtocol.java deleted file mode 100644 index c6dbb681e..000000000 --- a/src/org/traccar/protocol/AutoGradeProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AutoGradeProtocol extends BaseProtocol { - - public AutoGradeProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new AutoGradeProtocolDecoder(AutoGradeProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AutoGradeProtocolDecoder.java b/src/org/traccar/protocol/AutoGradeProtocolDecoder.java deleted file mode 100644 index 5052450b5..000000000 --- a/src/org/traccar/protocol/AutoGradeProtocolDecoder.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class AutoGradeProtocolDecoder extends BaseProtocolDecoder { - - public AutoGradeProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("(") - .number("d{12}") // index - .number("(d{15})") // imei - .number("(dd)(dd)(dd)") // date (ddmmyy) - .expression("([AV])") // validity - .number("(d+)(dd.d+)([NS])") // latitude - .number("(d+)(dd.d+)([EW])") // longitude - .number("([d.]{5})") // speed - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("([d.]{6})") // course - .expression("(.)") // status - .number("A(xxxx)") - .number("B(xxxx)") - .number("C(xxxx)") - .number("D(xxxx)") - .number("E(xxxx)") - .number("K(xxxx)") - .number("L(xxxx)") - .number("M(xxxx)") - .number("N(xxxx)") - .number("O(xxxx)") - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - - dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.setCourse(parser.nextDouble(0)); - - int status = parser.next().charAt(0); - position.set(Position.KEY_STATUS, status); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); - - for (int i = 1; i <= 5; i++) { - position.set(Position.PREFIX_ADC + i, parser.next()); - } - - for (int i = 1; i <= 5; i++) { - position.set("can" + i, parser.next()); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/AutoTrackProtocol.java b/src/org/traccar/protocol/AutoTrackProtocol.java deleted file mode 100644 index 6aa7558bf..000000000 --- a/src/org/traccar/protocol/AutoTrackProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; -public class AutoTrackProtocol extends BaseProtocol { - - public AutoTrackProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 5, 2, 2, 0, true)); - pipeline.addLast(new AutoTrackProtocolDecoder(AutoTrackProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AutoTrackProtocolDecoder.java b/src/org/traccar/protocol/AutoTrackProtocolDecoder.java deleted file mode 100644 index 3c1fd256b..000000000 --- a/src/org/traccar/protocol/AutoTrackProtocolDecoder.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; - -public class AutoTrackProtocolDecoder extends BaseProtocolDecoder { - - public AutoTrackProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_LOGIN_REQUEST = 51; - public static final int MSG_LOGIN_CONFIRM = 101; - public static final int MSG_TELEMETRY_1 = 52; - public static final int MSG_TELEMETRY_2 = 66; - public static final int MSG_TELEMETRY_3 = 67; - public static final int MSG_KEEP_ALIVE = 114; - public static final int MSG_TELEMETRY_CONFIRM = 123; - - private Position decodeTelemetry( - Channel channel, SocketAddress remoteAddress, DeviceSession deviceSession, ByteBuf buf) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(1009843200000L + buf.readUnsignedIntLE() * 1000)); // seconds since 2002 - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - position.set(Position.KEY_FUEL_USED, buf.readUnsignedIntLE()); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); - buf.readUnsignedShortLE(); // max speed - - position.set(Position.KEY_INPUT, buf.readUnsignedShortLE()); - buf.readUnsignedIntLE(); // di 3 count - buf.readUnsignedIntLE(); // di 4 count - - for (int i = 0; i < 5; i++) { - position.set(Position.PREFIX_ADC + (i + 1), buf.readUnsignedShortLE()); - } - - position.setCourse(buf.readUnsignedShortLE()); - - position.set(Position.KEY_STATUS, buf.readUnsignedShortLE()); - position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); - position.set(Position.KEY_DRIVER_UNIQUE_ID, buf.readLongLE()); - - int index = buf.readUnsignedShortLE(); - - buf.readUnsignedShortLE(); // checksum - - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeInt(0xF1F1F1F1); // sync - response.writeByte(MSG_TELEMETRY_CONFIRM); - response.writeShortLE(2); // length - response.writeShortLE(index); - response.writeShort(Checksum.crc16(Checksum.CRC16_XMODEM, response.nioBuffer())); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(4); // sync - int type = buf.readUnsignedByte(); - buf.readUnsignedShortLE(); // length - - switch (type) { - case MSG_LOGIN_REQUEST: - String imei = ByteBufUtil.hexDump(buf.readBytes(8)); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - int fuelConst = buf.readUnsignedShortLE(); - int tripConst = buf.readUnsignedShortLE(); - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeInt(0xF1F1F1F1); // sync - response.writeByte(MSG_LOGIN_CONFIRM); - response.writeShortLE(12); // length - response.writeBytes(ByteBufUtil.decodeHexDump(imei)); - response.writeShortLE(fuelConst); - response.writeShortLE(tripConst); - response.writeShort(Checksum.crc16(Checksum.CRC16_XMODEM, response.nioBuffer())); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - return null; - case MSG_TELEMETRY_1: - case MSG_TELEMETRY_2: - case MSG_TELEMETRY_3: - deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - return decodeTelemetry(channel, remoteAddress, deviceSession, buf); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/AvemaProtocol.java b/src/org/traccar/protocol/AvemaProtocol.java deleted file mode 100644 index dbfab4dea..000000000 --- a/src/org/traccar/protocol/AvemaProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class AvemaProtocol extends BaseProtocol { - - public AvemaProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new AvemaProtocolDecoder(AvemaProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/AvemaProtocolDecoder.java b/src/org/traccar/protocol/AvemaProtocolDecoder.java deleted file mode 100644 index 16a31162a..000000000 --- a/src/org/traccar/protocol/AvemaProtocolDecoder.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class AvemaProtocolDecoder extends BaseProtocolDecoder { - - public AvemaProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(d+),") // device id - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // longitude - .number("(-?d+.d+),") // latitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(-?d+),") // altitude - .number("(d+),") // satellites - .number("(d+),") // event - .number("(d+.d+),") // odometer - .number("(d+),") // input - .number("(d+.d+)V,") // adc 1 - .number("(d+.d+)V,") // adc 2 - .number("(d+),") // output - .number("(d),") // roaming - .number("(d+),") // rssi - .number("d,") // communication system - .number("(ddd)") // mcc - .number("(dd),") // mnc - .number("(x+),") // lac - .number("(x+),") // cid - .number("([^,]+)?") // rfid - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(true); - position.setTime(parser.nextDateTime()); - position.setLongitude(parser.nextDouble()); - position.setLatitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); - position.setCourse(parser.nextInt()); - position.setAltitude(parser.nextInt()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_EVENT, parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - position.set(Position.KEY_INPUT, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); - position.set(Position.KEY_OUTPUT, parser.nextInt()); - position.set(Position.KEY_ROAMING, parser.nextInt() == 1); - - int rssi = parser.nextInt(); - position.setNetwork(new Network(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi))); - - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/Avl301Protocol.java b/src/org/traccar/protocol/Avl301Protocol.java deleted file mode 100644 index 71fc7cb26..000000000 --- a/src/org/traccar/protocol/Avl301Protocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Avl301Protocol extends BaseProtocol { - - public Avl301Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, -3, 0)); - pipeline.addLast(new Avl301ProtocolDecoder(Avl301Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Avl301ProtocolDecoder.java b/src/org/traccar/protocol/Avl301ProtocolDecoder.java deleted file mode 100644 index f6b7db2d6..000000000 --- a/src/org/traccar/protocol/Avl301ProtocolDecoder.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class Avl301ProtocolDecoder extends BaseProtocolDecoder { - - public Avl301ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private String readImei(ByteBuf buf) { - int b = buf.readUnsignedByte(); - StringBuilder imei = new StringBuilder(); - imei.append(b & 0x0F); - for (int i = 0; i < 7; i++) { - b = buf.readUnsignedByte(); - imei.append((b & 0xF0) >> 4); - imei.append(b & 0x0F); - } - return imei.toString(); - } - - public static final int MSG_LOGIN = 'L'; - public static final int MSG_STATUS = 'H'; - public static final int MSG_GPS_LBS_STATUS = '$'; - - private void sendResponse(Channel channel, int type) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(5); - response.writeByte('$'); - response.writeByte(type); - response.writeByte('#'); - response.writeByte('\r'); response.writeByte('\n'); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(1); // header - int type = buf.readUnsignedByte(); - buf.readUnsignedByte(); // length - - if (type == MSG_LOGIN) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, readImei(buf)); - if (deviceSession == null) { - sendResponse(channel, type); - } - - } else if (type == MSG_STATUS) { - - sendResponse(channel, type); - - } else if (type == MSG_GPS_LBS_STATUS) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - int gpsLength = buf.readUnsignedByte(); // gps len and sat - position.set(Position.KEY_SATELLITES, gpsLength & 0xf); - - position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); // satellites - - double latitude = buf.readUnsignedInt() / 600000.0; - double longitude = buf.readUnsignedInt() / 600000.0; - position.setSpeed(buf.readUnsignedByte()); - - int union = buf.readUnsignedShort(); // course and flags - position.setCourse(union & 0x03FF); - position.setValid((union & 0x1000) != 0); - if ((union & 0x0400) != 0) { - latitude = -latitude; - } - if ((union & 0x0800) != 0) { - longitude = -longitude; - } - - position.setLatitude(latitude); - position.setLongitude(longitude); - - if ((union & 0x4000) != 0) { - position.set("acc", (union & 0x8000) != 0); - } - - position.setNetwork(new Network( - CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedMedium()))); - - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - int flags = buf.readUnsignedByte(); - position.set("acc", (flags & 0x2) != 0); - - // parse other flags - - position.set(Position.KEY_POWER, buf.readUnsignedByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/BceFrameDecoder.java b/src/org/traccar/protocol/BceFrameDecoder.java deleted file mode 100644 index 381a97696..000000000 --- a/src/org/traccar/protocol/BceFrameDecoder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class BceFrameDecoder extends BaseFrameDecoder { - - private static final int HANDSHAKE_LENGTH = 7; // "#BCE#\r\n" - - private boolean header = true; - - private static byte checksum(ByteBuf buf, int end) { - byte result = 0; - for (int i = 0; i < end; i++) { - result += buf.getByte(buf.readerIndex() + i); - } - return result; - } - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (header && buf.readableBytes() >= HANDSHAKE_LENGTH) { - buf.skipBytes(HANDSHAKE_LENGTH); - header = false; - } - - int end = 8; // IMEI - - while (buf.readableBytes() >= end + 2 + 1 + 1 + 1) { - end += buf.getUnsignedShortLE(buf.readerIndex() + end) + 2; - - if (buf.readableBytes() > end && checksum(buf, end) == buf.getByte(buf.readerIndex() + end)) { - return buf.readRetainedSlice(end + 1); - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/BceProtocol.java b/src/org/traccar/protocol/BceProtocol.java deleted file mode 100644 index 6453a05a9..000000000 --- a/src/org/traccar/protocol/BceProtocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class BceProtocol extends BaseProtocol { - - public BceProtocol() { - setSupportedDataCommands( - Command.TYPE_OUTPUT_CONTROL); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new BceFrameDecoder()); - pipeline.addLast(new BceProtocolEncoder()); - pipeline.addLast(new BceProtocolDecoder(BceProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/BceProtocolDecoder.java b/src/org/traccar/protocol/BceProtocolDecoder.java deleted file mode 100644 index ed810bebb..000000000 --- a/src/org/traccar/protocol/BceProtocolDecoder.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class BceProtocolDecoder extends BaseProtocolDecoder { - - public BceProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final int DATA_TYPE = 7; - - public static final int MSG_ASYNC_STACK = 0xA5; - public static final int MSG_STACK_COFIRM = 0x19; - public static final int MSG_TIME_TRIGGERED = 0xA0; - public static final int MSG_OUTPUT_CONTROL = 0x41; - public static final int MSG_OUTPUT_CONTROL_ACK = 0xC1; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - String imei = String.format("%015d", buf.readLongLE()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - while (buf.readableBytes() > 1) { - - int dataEnd = buf.readUnsignedShortLE() + buf.readerIndex(); - int type = buf.readUnsignedByte(); - - if (type != MSG_ASYNC_STACK && type != MSG_TIME_TRIGGERED) { - return null; - } - - int confirmKey = buf.readUnsignedByte() & 0x7F; - - while (buf.readerIndex() < dataEnd) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - int structEnd = buf.readUnsignedByte() + buf.readerIndex(); - - long time = buf.readUnsignedIntLE(); - if ((time & 0x0f) == DATA_TYPE) { - - time = time >> 4 << 1; - time += 0x47798280; // 01/01/2008 - position.setTime(new Date(time * 1000)); - - // Read masks - int mask; - List masks = new LinkedList<>(); - do { - mask = buf.readUnsignedShortLE(); - masks.add(mask); - } while (BitUtil.check(mask, 15)); - - mask = masks.get(0); - - if (BitUtil.check(mask, 0)) { - position.setValid(true); - position.setLongitude(buf.readFloatLE()); - position.setLatitude(buf.readFloatLE()); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - - int status = buf.readUnsignedByte(); - position.set(Position.KEY_SATELLITES, BitUtil.to(status, 4)); - position.set(Position.KEY_HDOP, BitUtil.from(status, 4)); - - position.setCourse(buf.readUnsignedByte() * 2); - position.setAltitude(buf.readUnsignedShortLE()); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - } - - if (BitUtil.check(mask, 1)) { - position.set(Position.KEY_INPUT, buf.readUnsignedShortLE()); - } - - for (int i = 1; i <= 8; i++) { - if (BitUtil.check(mask, i + 1)) { - position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE()); - } - } - - if (BitUtil.check(mask, 10)) { - buf.skipBytes(4); - } - if (BitUtil.check(mask, 11)) { - buf.skipBytes(4); - } - if (BitUtil.check(mask, 12)) { - buf.skipBytes(2); - } - if (BitUtil.check(mask, 13)) { - buf.skipBytes(2); - } - - if (BitUtil.check(mask, 14)) { - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShortLE(), buf.readUnsignedByte(), - buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), - buf.readUnsignedByte()))); - buf.readUnsignedByte(); - } - - if (BitUtil.check(mask, 0)) { - positions.add(position); - } - } - - buf.readerIndex(structEnd); - } - - // Send response - if (type == MSG_ASYNC_STACK && channel != null) { - ByteBuf response = Unpooled.buffer(8 + 2 + 2 + 1); - response.writeLongLE(Long.parseLong(imei)); - response.writeShortLE(2); - response.writeByte(MSG_STACK_COFIRM); - response.writeByte(confirmKey); - - int checksum = 0; - for (int i = 0; i < response.writerIndex(); i++) { - checksum += response.getUnsignedByte(i); - } - response.writeByte(checksum); - - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/BceProtocolEncoder.java b/src/org/traccar/protocol/BceProtocolEncoder.java deleted file mode 100644 index 1bbf3db12..000000000 --- a/src/org/traccar/protocol/BceProtocolEncoder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -public class BceProtocolEncoder extends BaseProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - if (command.getType().equals(Command.TYPE_OUTPUT_CONTROL)) { - ByteBuf buf = Unpooled.buffer(); - - buf.writeLongLE(Long.parseLong(getUniqueId(command.getDeviceId()))); - buf.writeShortLE(1 + 1 + 3 + 1); // length - buf.writeByte(BceProtocolDecoder.MSG_OUTPUT_CONTROL); - buf.writeByte(command.getInteger(Command.KEY_INDEX) == 1 ? 0x0A : 0x0B); - buf.writeByte(0xFF); // index - buf.writeByte(0x00); // form id - buf.writeShortLE(Integer.parseInt(command.getString(Command.KEY_DATA)) > 0 ? 0x0055 : 0x0000); - buf.writeByte(Checksum.sum(buf.nioBuffer())); - - return buf; - } else { - return null; - } - } - -} diff --git a/src/org/traccar/protocol/BlackKiteProtocol.java b/src/org/traccar/protocol/BlackKiteProtocol.java deleted file mode 100644 index 617a24d7a..000000000 --- a/src/org/traccar/protocol/BlackKiteProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 Vijay Kumar (vijaykumar@zilogic.com) - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class BlackKiteProtocol extends BaseProtocol { - - public BlackKiteProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new GalileoFrameDecoder()); - pipeline.addLast(new BlackKiteProtocolDecoder(BlackKiteProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/BlackKiteProtocolDecoder.java b/src/org/traccar/protocol/BlackKiteProtocolDecoder.java deleted file mode 100644 index dca4b908a..000000000 --- a/src/org/traccar/protocol/BlackKiteProtocolDecoder.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2015 Vijay Kumar (vijaykumar@zilogic.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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -public class BlackKiteProtocolDecoder extends BaseProtocolDecoder { - - public BlackKiteProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final int TAG_IMEI = 0x03; - private static final int TAG_DATE = 0x20; - private static final int TAG_COORDINATES = 0x30; - private static final int TAG_SPEED_COURSE = 0x33; - private static final int TAG_ALTITUDE = 0x34; - private static final int TAG_STATUS = 0x40; - private static final int TAG_DIGITAL_OUTPUTS = 0x45; - private static final int TAG_DIGITAL_INPUTS = 0x46; - private static final int TAG_INPUT_VOLTAGE1 = 0x50; - private static final int TAG_INPUT_VOLTAGE2 = 0x51; - private static final int TAG_INPUT_VOLTAGE3 = 0x52; - private static final int TAG_INPUT_VOLTAGE4 = 0x53; - private static final int TAG_XT1 = 0x60; - private static final int TAG_XT2 = 0x61; - private static final int TAG_XT3 = 0x62; - - private void sendReply(Channel channel, int checksum) { - if (channel != null) { - ByteBuf reply = Unpooled.buffer(3); - reply.writeByte(0x02); - reply.writeShortLE((short) checksum); - channel.writeAndFlush(new NetworkMessage(reply, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedByte(); // header - int length = (buf.readUnsignedShortLE() & 0x7fff) + 3; - - List positions = new LinkedList<>(); - Set tags = new HashSet<>(); - boolean hasLocation = false; - Position position = new Position(getProtocolName()); - - while (buf.readerIndex() < length) { - - // Check if new message started - int tag = buf.readUnsignedByte(); - if (tags.contains(tag)) { - if (hasLocation && position.getFixTime() != null) { - positions.add(position); - } - tags.clear(); - hasLocation = false; - position = new Position(getProtocolName()); - } - tags.add(tag); - - switch (tag) { - - case TAG_IMEI: - getDeviceSession(channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII)); - break; - - case TAG_DATE: - position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); - break; - - case TAG_COORDINATES: - hasLocation = true; - position.setValid((buf.readUnsignedByte() & 0xf0) == 0x00); - position.setLatitude(buf.readIntLE() / 1000000.0); - position.setLongitude(buf.readIntLE() / 1000000.0); - break; - - case TAG_SPEED_COURSE: - position.setSpeed(buf.readUnsignedShortLE() * 0.0539957); - position.setCourse(buf.readUnsignedShortLE() * 0.1); - break; - - case TAG_ALTITUDE: - position.setAltitude(buf.readShortLE()); - break; - - case TAG_STATUS: - int status = buf.readUnsignedShortLE(); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 9)); - if (BitUtil.check(status, 15)) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - position.set(Position.KEY_CHARGE, BitUtil.check(status, 2)); - break; - - case TAG_DIGITAL_INPUTS: - int input = buf.readUnsignedShortLE(); - for (int i = 0; i < 16; i++) { - position.set(Position.PREFIX_IO + (i + 1), BitUtil.check(input, i)); - } - break; - - case TAG_DIGITAL_OUTPUTS: - int output = buf.readUnsignedShortLE(); - for (int i = 0; i < 16; i++) { - position.set(Position.PREFIX_IO + (i + 17), BitUtil.check(output, i)); - } - break; - - case TAG_INPUT_VOLTAGE1: - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE() / 1000.0); - break; - - case TAG_INPUT_VOLTAGE2: - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE() / 1000.0); - break; - - case TAG_INPUT_VOLTAGE3: - position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShortLE() / 1000.0); - break; - - case TAG_INPUT_VOLTAGE4: - position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShortLE() / 1000.0); - break; - - case TAG_XT1: - case TAG_XT2: - case TAG_XT3: - buf.skipBytes(16); - break; - - default: - break; - - } - } - - if (hasLocation && position.getFixTime() != null) { - positions.add(position); - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - sendReply(channel, buf.readUnsignedShortLE()); - - for (Position p : positions) { - p.setDeviceId(deviceSession.getDeviceId()); - } - - if (positions.isEmpty()) { - return null; - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/BoxProtocol.java b/src/org/traccar/protocol/BoxProtocol.java deleted file mode 100644 index dfea15938..000000000 --- a/src/org/traccar/protocol/BoxProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class BoxProtocol extends BaseProtocol { - - public BoxProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new BoxProtocolDecoder(BoxProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/BoxProtocolDecoder.java b/src/org/traccar/protocol/BoxProtocolDecoder.java deleted file mode 100644 index 3635c29e5..000000000 --- a/src/org/traccar/protocol/BoxProtocolDecoder.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class BoxProtocolDecoder extends BaseProtocolDecoder { - - public BoxProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("L,") - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .text("G,") - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(d+.?d*),") // distance - .number("(d+),") // event - .number("(d+)") // status - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("H,")) { - - int index = sentence.indexOf(',', 2) + 1; - String id = sentence.substring(index, sentence.indexOf(',', index)); - getDeviceSession(channel, remoteAddress, id); - - } else if (sentence.startsWith("E,")) { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("A," + sentence.substring(2) + "\r", remoteAddress)); - } - - } else if (sentence.startsWith("L,")) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextDouble()); - - position.set(Position.KEY_ODOMETER_TRIP, parser.nextDouble() * 1000); - position.set(Position.KEY_EVENT, parser.next()); - - int status = parser.nextInt(); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); - position.set(Position.KEY_MOTION, BitUtil.check(status, 1)); - position.setValid(!BitUtil.check(status, 2)); - position.set(Position.KEY_STATUS, status); - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/C2stekProtocol.java b/src/org/traccar/protocol/C2stekProtocol.java deleted file mode 100644 index 804621fd3..000000000 --- a/src/org/traccar/protocol/C2stekProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class C2stekProtocol extends BaseProtocol { - - public C2stekProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, false, "$AP")); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new C2stekProtocolDecoder(C2stekProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/C2stekProtocolDecoder.java b/src/org/traccar/protocol/C2stekProtocolDecoder.java deleted file mode 100644 index 6a31cb2f4..000000000 --- a/src/org/traccar/protocol/C2stekProtocolDecoder.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class C2stekProtocolDecoder extends BaseProtocolDecoder { - - public C2stekProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("PA$") - .number("(d+)") // imei - .text("$") - .expression(".#") // data type - .number("(dd)(dd)(dd)#") // date (yymmdd) - .number("(dd)(dd)(dd)#") // time (hhmmss) - .number("([01])#") // valid - .number("([+-]?d+.d+)#") // latitude - .number("([+-]?d+.d+)#") // longitude - .number("(d+.d+)#") // speed - .number("(d+.d+)#") // course - .number("(-?d+.d+)#") // altitude - .number("(d+)#") // battery - .number("d+#") // geo area alarm - .number("(x+)#") // alarm - .number("([01])") // armed - .number("([01])") // door - .number("([01])#") // ignition - .any() - .text("$AP") - .compile(); - - private String decodeAlarm(int alarm) { - switch (alarm) { - case 0x2: - return Position.ALARM_SHOCK; - case 0x3: - return Position.ALARM_POWER_CUT; - case 0x4: - return Position.ALARM_OVERSPEED; - case 0x5: - return Position.ALARM_SOS; - case 0x6: - return Position.ALARM_DOOR; - case 0xA: - return Position.ALARM_LOW_BATTERY; - case 0xB: - return Position.ALARM_FAULT; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - if (sentence.contains("$20$") && channel != null) { - channel.writeAndFlush(new NetworkMessage(sentence, remoteAddress)); - } - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - position.setValid(parser.nextInt() > 0); - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextDouble()); - position.setAltitude(parser.nextDouble()); - - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); - position.set(Position.KEY_ALARM, decodeAlarm(parser.nextHexInt())); - - position.set(Position.KEY_ARMED, parser.nextInt() > 0); - position.set(Position.KEY_DOOR, parser.nextInt() > 0); - position.set(Position.KEY_IGNITION, parser.nextInt() > 0); - - return position; - } - -} diff --git a/src/org/traccar/protocol/CalAmpProtocol.java b/src/org/traccar/protocol/CalAmpProtocol.java deleted file mode 100644 index 232e72a8c..000000000 --- a/src/org/traccar/protocol/CalAmpProtocol.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class CalAmpProtocol extends BaseProtocol { - - public CalAmpProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CalAmpProtocolDecoder(CalAmpProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CalAmpProtocolDecoder.java b/src/org/traccar/protocol/CalAmpProtocolDecoder.java deleted file mode 100644 index 31416d7f1..000000000 --- a/src/org/traccar/protocol/CalAmpProtocolDecoder.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; - -public class CalAmpProtocolDecoder extends BaseProtocolDecoder { - - public CalAmpProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_NULL = 0; - public static final int MSG_ACK = 1; - public static final int MSG_EVENT_REPORT = 2; - public static final int MSG_ID_REPORT = 3; - public static final int MSG_USER_DATA = 4; - public static final int MSG_APP_DATA = 5; - public static final int MSG_CONFIG = 6; - public static final int MSG_UNIT_REQUEST = 7; - public static final int MSG_LOCATE_REPORT = 8; - public static final int MSG_USER_DATA_ACC = 9; - public static final int MSG_MINI_EVENT_REPORT = 10; - public static final int MSG_MINI_USER_DATA = 11; - - public static final int SERVICE_UNACKNOWLEDGED = 0; - public static final int SERVICE_ACKNOWLEDGED = 1; - public static final int SERVICE_RESPONSE = 2; - - private void sendResponse(Channel channel, SocketAddress remoteAddress, int type, int index, int result) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(10); - response.writeByte(SERVICE_RESPONSE); - response.writeByte(MSG_ACK); - response.writeShort(index); - response.writeByte(type); - response.writeByte(result); - response.writeByte(0); - response.writeMedium(0); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - private Position decodePosition(DeviceSession deviceSession, int type, ByteBuf buf) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - if (type != MSG_MINI_EVENT_REPORT) { - buf.readUnsignedInt(); // fix time - } - position.setLatitude(buf.readInt() * 0.0000001); - position.setLongitude(buf.readInt() * 0.0000001); - if (type != MSG_MINI_EVENT_REPORT) { - position.setAltitude(buf.readInt() * 0.01); - position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedInt())); - } - position.setCourse(buf.readShort()); - if (type == MSG_MINI_EVENT_REPORT) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - } - - if (type == MSG_MINI_EVENT_REPORT) { - position.set(Position.KEY_SATELLITES, buf.getUnsignedByte(buf.readerIndex()) & 0xf); - position.setValid((buf.readUnsignedByte() & 0x20) == 0); - } else { - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.setValid((buf.readUnsignedByte() & 0x08) == 0); - } - - if (type != MSG_MINI_EVENT_REPORT) { - position.set("carrier", buf.readUnsignedShort()); - position.set(Position.KEY_RSSI, buf.readShort()); - } - - position.set("modem", buf.readUnsignedByte()); - - if (type != MSG_MINI_EVENT_REPORT) { - position.set(Position.KEY_HDOP, buf.readUnsignedByte()); - } - - int input = buf.readUnsignedByte(); - position.set(Position.KEY_INPUT, input); - position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); - - if (type != MSG_MINI_EVENT_REPORT) { - position.set(Position.KEY_STATUS, buf.readUnsignedByte()); - } - - if (type == MSG_EVENT_REPORT || type == MSG_MINI_EVENT_REPORT) { - if (type != MSG_MINI_EVENT_REPORT) { - buf.readUnsignedByte(); // event index - } - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - } - - int accType = BitUtil.from(buf.getUnsignedByte(buf.readerIndex()), 6); - int accCount = BitUtil.to(buf.readUnsignedByte(), 6); - - if (type != MSG_MINI_EVENT_REPORT) { - position.set("append", buf.readUnsignedByte()); - } - - if (accType == 1) { - buf.readUnsignedInt(); // threshold - buf.readUnsignedInt(); // mask - } - - for (int i = 0; i < accCount; i++) { - if (buf.readableBytes() >= 4) { - position.set("acc" + i, buf.readUnsignedInt()); - } - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (BitUtil.check(buf.getByte(buf.readerIndex()), 7)) { - - int content = buf.readUnsignedByte(); - - if (BitUtil.check(content, 0)) { - String id = ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())); - getDeviceSession(channel, remoteAddress, id); - } - - if (BitUtil.check(content, 1)) { - buf.skipBytes(buf.readUnsignedByte()); // identifier type - } - - if (BitUtil.check(content, 2)) { - buf.skipBytes(buf.readUnsignedByte()); // authentication - } - - if (BitUtil.check(content, 3)) { - buf.skipBytes(buf.readUnsignedByte()); // routing - } - - if (BitUtil.check(content, 4)) { - buf.skipBytes(buf.readUnsignedByte()); // forwarding - } - - if (BitUtil.check(content, 5)) { - buf.skipBytes(buf.readUnsignedByte()); // response redirection - } - - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - int service = buf.readUnsignedByte(); - int type = buf.readUnsignedByte(); - int index = buf.readUnsignedShort(); - - if (service == SERVICE_ACKNOWLEDGED) { - sendResponse(channel, remoteAddress, type, index, 0); - } - - if (type == MSG_EVENT_REPORT || type == MSG_LOCATE_REPORT || type == MSG_MINI_EVENT_REPORT) { - return decodePosition(deviceSession, type, buf); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/CarTrackProtocol.java b/src/org/traccar/protocol/CarTrackProtocol.java deleted file mode 100644 index e340fba25..000000000 --- a/src/org/traccar/protocol/CarTrackProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class CarTrackProtocol extends BaseProtocol { - - public CarTrackProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new CarTrackProtocolDecoder(CarTrackProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CarTrackProtocolDecoder.java b/src/org/traccar/protocol/CarTrackProtocolDecoder.java deleted file mode 100644 index ce3345826..000000000 --- a/src/org/traccar/protocol/CarTrackProtocolDecoder.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2014 Rohit - * - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class CarTrackProtocolDecoder extends BaseProtocolDecoder { - - public CarTrackProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$$") // header - .number("(d+)") // device id - .text("?").expression("*") - .text("&A") - .number("(dddd)") // command - .text("&B") - .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) - .expression("([AV]),") // validity - .number("(dd)(dd.dddd),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.dddd),") // longitude - .expression("([EW]),") - .number("(d+.d*)?,") // speed - .number("(d+.d*)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .expression("&C([^&]*)") // io - .expression("&D([^&]*)") // odometer - .expression("&E([^&]*)") // alarm - .expression("&Y([^&]*)").optional() // adc - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_COMMAND, parser.next()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.set(Position.PREFIX_IO + 1, parser.next()); - - String odometer = parser.next(); - odometer = odometer.replace(":", "A"); - odometer = odometer.replace(";", "B"); - odometer = odometer.replace("<", "C"); - odometer = odometer.replace("=", "D"); - odometer = odometer.replace(">", "E"); - odometer = odometer.replace("?", "F"); - position.set(Position.KEY_ODOMETER, Integer.parseInt(odometer, 16)); - - parser.next(); // there is no meaningful alarms - position.set(Position.PREFIX_ADC + 1, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/CarcellProtocol.java b/src/org/traccar/protocol/CarcellProtocol.java deleted file mode 100644 index 0c305efcb..000000000 --- a/src/org/traccar/protocol/CarcellProtocol.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class CarcellProtocol extends BaseProtocol { - - public CarcellProtocol() { - setSupportedDataCommands( - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new CarcellProtocolEncoder()); - pipeline.addLast(new CarcellProtocolDecoder(CarcellProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CarcellProtocolDecoder.java b/src/org/traccar/protocol/CarcellProtocolDecoder.java deleted file mode 100644 index 344b2f1ea..000000000 --- a/src/org/traccar/protocol/CarcellProtocolDecoder.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.net.SocketAddress; -import java.util.regex.Pattern; - -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.Parser.CoordinateFormat; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -public class CarcellProtocolDecoder extends BaseProtocolDecoder { - - public CarcellProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("([$%])") // memory flag - .number("(d+),") // imei - .groupBegin() - .number("([NS])(dd)(dd).(dddd),") // latitude - .number("([EW])(ddd)(dd).(dddd),") // longitude - .or() - .text("CEL,") - .number("([NS])(d+.d+),") // latitude - .number("([EW])(d+.d+),") // longitude - .groupEnd() - .number("(d+),") // speed - .number("(d+),") // course - .groupBegin() - .number("([-+]ddd)([-+]ddd)([-+]ddd),") // x,y,z - .or() - .number("(d+),") // accel - .groupEnd() - .number("(d+),") // battery - .number("(d+),") // csq - .number("(d),") // jamming - .number("(d+),") // hdop - .expression("([CG]),?") // clock type - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d),") // block - .number("(d),") // ignition - .groupBegin() - .number("(d),") // cloned - .expression("([AF])") // panic - .number("(d),") // painel - .number("(d+),") // battery voltage - .or() - .number("(dd),") // time until delivery - .expression("([AF])") // panic - .number("(d),") // aux - .number("(d{2,4}),") // battery voltage - .number("(d{20}),") // ccid - .groupEnd() - .number("(xx)") // crc - .any() // full format - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.set(Position.KEY_ARCHIVE, parser.next().equals("%")); - position.setValid(true); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.hasNext(8)) { - position.setLatitude(parser.nextCoordinate(CoordinateFormat.HEM_DEG_MIN_MIN)); - position.setLongitude(parser.nextCoordinate(CoordinateFormat.HEM_DEG_MIN_MIN)); - } - - if (parser.hasNext(4)) { - position.setLatitude(parser.nextCoordinate(CoordinateFormat.HEM_DEG)); - position.setLongitude(parser.nextCoordinate(CoordinateFormat.HEM_DEG)); - } - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); - position.setCourse(parser.nextInt(0)); - - if (parser.hasNext(3)) { - position.set("x", parser.nextInt(0)); - position.set("y", parser.nextInt(0)); - position.set("z", parser.nextInt(0)); - } - - if (parser.hasNext(1)) { - position.set(Position.KEY_ACCELERATION, parser.nextInt(0)); - } - - Double internalBattery = (parser.nextDouble(0) + 100d) * 0.0294d; - position.set(Position.KEY_BATTERY, internalBattery); - position.set(Position.KEY_RSSI, parser.nextInt(0)); - position.set("jamming", parser.next().equals("1")); - position.set(Position.KEY_GPS, parser.nextInt(0)); - - position.set("clockType", parser.next()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.set("blocked", parser.next().equals("1")); - position.set(Position.KEY_IGNITION, parser.next().equals("1")); - - if (parser.hasNext(4)) { - position.set("cloned", parser.next().equals("1")); - - parser.next(); // panic button status - - String painelStatus = parser.next(); - if (painelStatus.equals("1")) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - position.set("painel", painelStatus.equals("2")); - - Double mainVoltage = parser.nextDouble(0) / 100d; - position.set(Position.KEY_POWER, mainVoltage); - } - - if (parser.hasNext(5)) { - position.set("timeUntilDelivery", parser.nextInt(0)); - parser.next(); // panic button status - position.set(Position.KEY_INPUT, parser.next()); - - Double mainVoltage = parser.nextDouble(0) / 100d; - position.set(Position.KEY_POWER, mainVoltage); - - position.set("iccid", parser.next()); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/CarcellProtocolEncoder.java b/src/org/traccar/protocol/CarcellProtocolEncoder.java deleted file mode 100644 index e8f0081a0..000000000 --- a/src/org/traccar/protocol/CarcellProtocolEncoder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2016 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class CarcellProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "$SRVCMD,{%s},BA#\r\n", Command.KEY_UNIQUE_ID); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "$SRVCMD,{%s},BD#\r\n", Command.KEY_UNIQUE_ID); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/CarscopProtocol.java b/src/org/traccar/protocol/CarscopProtocol.java deleted file mode 100644 index 2c754a97f..000000000 --- a/src/org/traccar/protocol/CarscopProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class CarscopProtocol extends BaseProtocol { - - public CarscopProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '^')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new CarscopProtocolDecoder(CarscopProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CarscopProtocolDecoder.java b/src/org/traccar/protocol/CarscopProtocolDecoder.java deleted file mode 100644 index 161666adc..000000000 --- a/src/org/traccar/protocol/CarscopProtocolDecoder.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class CarscopProtocolDecoder extends BaseProtocolDecoder { - - public CarscopProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("*") - .any() - .number("(dd)(dd)(dd)") // time (hhmmss) - .expression("([AV])") // validity - .number("(dd)(dd.dddd)") // latitude - .expression("([NS])") - .number("(ddd)(dd.dddd)") // longitude - .expression("([EW])") - .number("(ddd.d)") // speed - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(ddd.dd)") // course - .groupBegin() - .number("(d{8})") // state - .number("L(d{6})") // odometer - .groupEnd("?") - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - DeviceSession deviceSession; - int index = sentence.indexOf("UB05"); - if (index != -1) { - String imei = sentence.substring(index + 4, index + 4 + 15); - deviceSession = getDeviceSession(channel, remoteAddress, imei); - } else { - deviceSession = getDeviceSession(channel, remoteAddress); - } - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - - dateBuilder.setDate(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.setCourse(parser.nextDouble(0)); - - if (parser.hasNext(2)) { - position.set(Position.KEY_STATUS, parser.next()); - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/CastelProtocol.java b/src/org/traccar/protocol/CastelProtocol.java deleted file mode 100644 index 9b854afc3..000000000 --- a/src/org/traccar/protocol/CastelProtocol.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -import java.nio.ByteOrder; -public class CastelProtocol extends BaseProtocol { - - public CastelProtocol() { - setSupportedDataCommands( - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, -4, 0, true)); - pipeline.addLast(new CastelProtocolEncoder()); - pipeline.addLast(new CastelProtocolDecoder(CastelProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CastelProtocolEncoder()); - pipeline.addLast(new CastelProtocolDecoder(CastelProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CastelProtocolDecoder.java b/src/org/traccar/protocol/CastelProtocolDecoder.java deleted file mode 100644 index 0541adf6f..000000000 --- a/src/org/traccar/protocol/CastelProtocolDecoder.java +++ /dev/null @@ -1,573 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.ObdDecoder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -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; - -public class CastelProtocolDecoder extends BaseProtocolDecoder { - - private static final Map PID_LENGTH_MAP = new HashMap<>(); - - static { - int[] l1 = { - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0b, 0x0d, - 0x0e, 0x0f, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x2c, - 0x2d, 0x2e, 0x2f, 0x30, 0x33, 0x43, 0x45, 0x46, - 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x51, 0x52, - 0x5a - }; - int[] l2 = { - 0x02, 0x03, 0x0a, 0x0c, 0x10, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1f, 0x21, 0x22, - 0x23, 0x31, 0x32, 0x3c, 0x3d, 0x3e, 0x3f, 0x42, - 0x44, 0x4d, 0x4e, 0x50, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59 - }; - int[] l4 = { - 0x00, 0x01, 0x20, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x3b, 0x40, 0x41, 0x4f - }; - for (int i : l1) { - PID_LENGTH_MAP.put(i, 1); - } - for (int i : l2) { - PID_LENGTH_MAP.put(i, 2); - } - for (int i : l4) { - PID_LENGTH_MAP.put(i, 4); - } - } - - public CastelProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final short MSG_SC_LOGIN = 0x1001; - public static final short MSG_SC_LOGIN_RESPONSE = (short) 0x9001; - public static final short MSG_SC_LOGOUT = 0x1002; - public static final short MSG_SC_HEARTBEAT = 0x1003; - public static final short MSG_SC_HEARTBEAT_RESPONSE = (short) 0x9003; - public static final short MSG_SC_GPS = 0x4001; - public static final short MSG_SC_PID_DATA = 0x4002; - public static final short MSG_SC_SUPPORTED_PID = 0x4004; - public static final short MSG_SC_OBD_DATA = 0x4005; - public static final short MSG_SC_DTCS_PASSENGER = 0x4006; - public static final short MSG_SC_DTCS_COMMERCIAL = 0x400B; - public static final short MSG_SC_ALARM = 0x4007; - public static final short MSG_SC_CELL = 0x4008; - public static final short MSG_SC_GPS_SLEEP = 0x4009; - public static final short MSG_SC_FUEL = 0x400E; - public static final short MSG_SC_AGPS_REQUEST = 0x5101; - public static final short MSG_SC_QUERY_RESPONSE = (short) 0xA002; - public static final short MSG_SC_CURRENT_LOCATION = (short) 0xB001; - - public static final short MSG_CC_LOGIN = 0x4001; - public static final short MSG_CC_LOGIN_RESPONSE = (short) 0x8001; - public static final short MSG_CC_HEARTBEAT = 0x4206; - public static final short MSG_CC_PETROL_CONTROL = 0x4583; - public static final short MSG_CC_HEARTBEAT_RESPONSE = (short) 0x8206; - - private Position readPosition(DeviceSession deviceSession, ByteBuf buf) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - double lat = buf.readUnsignedIntLE() / 3600000.0; - double lon = buf.readUnsignedIntLE() / 3600000.0; - position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE())); - position.setCourse(buf.readUnsignedShortLE() * 0.1); - - int flags = buf.readUnsignedByte(); - if ((flags & 0x02) == 0) { - lat = -lat; - } - if ((flags & 0x01) == 0) { - lon = -lon; - } - position.setLatitude(lat); - position.setLongitude(lon); - position.setValid((flags & 0x0C) > 0); - position.set(Position.KEY_SATELLITES, flags >> 4); - - return position; - } - - private Position createPosition(DeviceSession deviceSession) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - return position; - } - - private void decodeObd(Position position, ByteBuf buf, boolean groups) { - - int count = buf.readUnsignedByte(); - - int[] pids = new int[count]; - for (int i = 0; i < count; i++) { - pids[i] = buf.readUnsignedShortLE() & 0xff; - } - - if (groups) { - buf.readUnsignedByte(); // group count - buf.readUnsignedByte(); // group size - } - - for (int i = 0; i < count; i++) { - int value; - switch (PID_LENGTH_MAP.get(pids[i])) { - case 1: - value = buf.readUnsignedByte(); - break; - case 2: - value = buf.readUnsignedShortLE(); - break; - case 4: - value = buf.readIntLE(); - break; - default: - value = 0; - break; - } - position.add(ObdDecoder.decodeData(pids[i], value, false)); - } - } - - private void decodeStat(Position position, ByteBuf buf) { - - buf.readUnsignedIntLE(); // ACC ON time - buf.readUnsignedIntLE(); // UTC time - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedIntLE()); - position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedIntLE()); - buf.readUnsignedShortLE(); // current fuel consumption - position.set(Position.KEY_STATUS, buf.readUnsignedIntLE()); - buf.skipBytes(8); - } - - private void sendResponse( - Channel channel, SocketAddress remoteAddress, - int version, ByteBuf id, short type, ByteBuf content) { - - if (channel != null) { - int length = 2 + 2 + 1 + id.readableBytes() + 2 + 2 + 2; - if (content != null) { - length += content.readableBytes(); - } - - ByteBuf response = Unpooled.buffer(length); - response.writeByte('@'); response.writeByte('@'); - response.writeShortLE(length); - response.writeByte(version); - response.writeBytes(id); - response.writeShort(type); - if (content != null) { - response.writeBytes(content); - content.release(); - } - response.writeShortLE( - Checksum.crc16(Checksum.CRC16_X25, response.nioBuffer(0, response.writerIndex()))); - response.writeByte(0x0D); response.writeByte(0x0A); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - private void sendResponse( - Channel channel, SocketAddress remoteAddress, ByteBuf id, short type) { - - if (channel != null) { - int length = 2 + 2 + id.readableBytes() + 2 + 4 + 8 + 2 + 2; - - ByteBuf response = Unpooled.buffer(length); - response.writeByte('@'); response.writeByte('@'); - response.writeShortLE(length); - response.writeBytes(id); - response.writeShort(type); - response.writeIntLE(0); - for (int i = 0; i < 8; i++) { - response.writeByte(0xff); - } - response.writeShortLE( - Checksum.crc16(Checksum.CRC16_X25, response.nioBuffer(0, response.writerIndex()))); - response.writeByte(0x0D); response.writeByte(0x0A); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - private void decodeAlarm(Position position, int alarm) { - switch (alarm) { - case 0x01: - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - break; - case 0x02: - position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); - break; - case 0x03: - position.set(Position.KEY_ALARM, Position.ALARM_TEMPERATURE); - break; - case 0x04: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 0x05: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 0x06: - position.set(Position.KEY_ALARM, Position.ALARM_IDLE); - break; - case 0x07: - position.set(Position.KEY_ALARM, Position.ALARM_TOW); - break; - case 0x08: - position.set(Position.KEY_ALARM, Position.ALARM_HIGH_RPM); - break; - case 0x09: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_ON); - break; - case 0x0B: - position.set(Position.KEY_ALARM, Position.ALARM_LANE_CHANGE); - break; - case 0x0C: - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - break; - case 0x0E: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); - break; - case 0x16: - position.set(Position.KEY_IGNITION, true); - break; - case 0x17: - position.set(Position.KEY_IGNITION, false); - break; - default: - break; - } - } - - private Object decodeSc( - Channel channel, SocketAddress remoteAddress, ByteBuf buf, - int version, ByteBuf id, short type, DeviceSession deviceSession) { - - if (type == MSG_SC_HEARTBEAT) { - - sendResponse(channel, remoteAddress, version, id, MSG_SC_HEARTBEAT_RESPONSE, null); - - } else if (type == MSG_SC_LOGIN || type == MSG_SC_LOGOUT || type == MSG_SC_GPS - || type == MSG_SC_ALARM || type == MSG_SC_CURRENT_LOCATION || type == MSG_SC_FUEL) { - - if (type == MSG_SC_LOGIN) { - ByteBuf response = Unpooled.buffer(10); - response.writeIntLE(0xFFFFFFFF); - response.writeShortLE(0); - response.writeIntLE((int) (System.currentTimeMillis() / 1000)); - sendResponse(channel, remoteAddress, version, id, MSG_SC_LOGIN_RESPONSE, response); - } - - if (type == MSG_SC_GPS) { - buf.readUnsignedByte(); // historical - } else if (type == MSG_SC_ALARM) { - buf.readUnsignedIntLE(); // alarm - } else if (type == MSG_SC_CURRENT_LOCATION) { - buf.readUnsignedShortLE(); - } - - buf.readUnsignedIntLE(); // ACC ON time - buf.readUnsignedIntLE(); // UTC time - long odometer = buf.readUnsignedIntLE(); - long tripOdometer = buf.readUnsignedIntLE(); - long fuelConsumption = buf.readUnsignedIntLE(); - buf.readUnsignedShortLE(); // current fuel consumption - long status = buf.readUnsignedIntLE(); - buf.skipBytes(8); - - int count = buf.readUnsignedByte(); - - List positions = new LinkedList<>(); - - for (int i = 0; i < count; i++) { - Position position = readPosition(deviceSession, buf); - position.set(Position.KEY_ODOMETER, odometer); - position.set(Position.KEY_ODOMETER_TRIP, tripOdometer); - position.set(Position.KEY_FUEL_CONSUMPTION, fuelConsumption); - position.set(Position.KEY_STATUS, status); - positions.add(position); - } - - if (type == MSG_SC_ALARM) { - int alarmCount = buf.readUnsignedByte(); - for (int i = 0; i < alarmCount; i++) { - if (buf.readUnsignedByte() != 0) { - int alarm = buf.readUnsignedByte(); - for (Position position : positions) { - decodeAlarm(position, alarm); - } - buf.readUnsignedShortLE(); // description - buf.readUnsignedShortLE(); // threshold - } - } - } else if (type == MSG_SC_FUEL) { - for (Position position : positions) { - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); - } - } - - if (!positions.isEmpty()) { - return positions; - } - - } else if (type == MSG_SC_GPS_SLEEP) { - - buf.readUnsignedIntLE(); // device time - - return readPosition(deviceSession, buf); - - } else if (type == MSG_SC_AGPS_REQUEST) { - - return readPosition(deviceSession, buf); - - } else if (type == MSG_SC_PID_DATA) { - - Position position = createPosition(deviceSession); - - decodeStat(position, buf); - - buf.readUnsignedShortLE(); // sample rate - decodeObd(position, buf, true); - - return position; - - } else if (type == MSG_SC_DTCS_PASSENGER) { - - Position position = createPosition(deviceSession); - - decodeStat(position, buf); - - buf.readUnsignedByte(); // flag - position.add(ObdDecoder.decodeCodes(ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())))); - - return position; - - } else if (type == MSG_SC_OBD_DATA) { - - Position position = createPosition(deviceSession); - - decodeStat(position, buf); - - buf.readUnsignedByte(); // flag - decodeObd(position, buf, false); - - return position; - - } else if (type == MSG_SC_CELL) { - - Position position = createPosition(deviceSession); - - decodeStat(position, buf); - - position.setNetwork(new Network( - CellTower.fromLacCid(buf.readUnsignedShortLE(), buf.readUnsignedShortLE()))); - - return position; - - } else if (type == MSG_SC_QUERY_RESPONSE) { - - Position position = createPosition(deviceSession); - - buf.readUnsignedShortLE(); // index - buf.readUnsignedByte(); // response count - buf.readUnsignedByte(); // response index - - int failureCount = buf.readUnsignedByte(); - for (int i = 0; i < failureCount; i++) { - buf.readUnsignedShortLE(); // tag - } - - int successCount = buf.readUnsignedByte(); - for (int i = 0; i < successCount; i++) { - buf.readUnsignedShortLE(); // tag - position.set(Position.KEY_RESULT, - buf.readSlice(buf.readUnsignedShortLE()).toString(StandardCharsets.US_ASCII)); - } - - return position; - - } - - return null; - } - - private Object decodeCc( - Channel channel, SocketAddress remoteAddress, ByteBuf buf, - int version, ByteBuf id, short type, DeviceSession deviceSession) { - - if (type == MSG_CC_HEARTBEAT) { - - sendResponse(channel, remoteAddress, version, id, MSG_CC_HEARTBEAT_RESPONSE, null); - - buf.readUnsignedByte(); // 0x01 for history - int count = buf.readUnsignedByte(); - - List positions = new LinkedList<>(); - - for (int i = 0; i < count; i++) { - Position position = readPosition(deviceSession, buf); - - position.set(Position.KEY_STATUS, buf.readUnsignedIntLE()); - position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - - buf.readUnsignedByte(); // geo-fencing id - buf.readUnsignedByte(); // geo-fencing flags - buf.readUnsignedByte(); // additional flags - - position.setNetwork(new Network( - CellTower.fromLacCid(buf.readUnsignedShortLE(), buf.readUnsignedShortLE()))); - - positions.add(position); - } - - return positions; - - } else if (type == MSG_CC_LOGIN) { - - sendResponse(channel, remoteAddress, version, id, MSG_CC_LOGIN_RESPONSE, null); - - Position position = readPosition(deviceSession, buf); - - position.set(Position.KEY_STATUS, buf.readUnsignedIntLE()); - position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - - buf.readUnsignedByte(); // geo-fencing id - buf.readUnsignedByte(); // geo-fencing flags - buf.readUnsignedByte(); // additional flags - - // GSM_CELL_CODE - // STR_Z - firmware version - // STR_Z - hardware version - - return position; - - } - - return null; - } - - private Object decodeMpip( - Channel channel, SocketAddress remoteAddress, ByteBuf buf, - int version, ByteBuf id, short type, DeviceSession deviceSession) { - - if (type == 0x4001) { - - sendResponse(channel, remoteAddress, version, id, (short) type, null); - - return readPosition(deviceSession, buf); - - } else if (type == 0x2001) { - - sendResponse(channel, remoteAddress, id, (short) 0x1001); - - buf.readUnsignedIntLE(); // index - buf.readUnsignedIntLE(); // unix time - buf.readUnsignedByte(); - - return readPosition(deviceSession, buf); - - } else if (type == 0x4201 || type == 0x4202 || type == 0x4206) { - - return readPosition(deviceSession, buf); - - } else if (type == 0x4204) { - - List positions = new LinkedList<>(); - - for (int i = 0; i < 8; i++) { - Position position = readPosition(deviceSession, buf); - buf.skipBytes(31); - positions.add(position); - } - - return positions; - - } - - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int header = buf.readUnsignedShortLE(); - buf.readUnsignedShortLE(); // length - - int version = -1; - if (header == 0x4040) { - version = buf.readUnsignedByte(); - } - - ByteBuf id = buf.readSlice(20); - short type = buf.readShort(); - - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, id.toString(StandardCharsets.US_ASCII).trim()); - if (deviceSession == null) { - return null; - } - - switch (version) { - case -1: - return decodeMpip(channel, remoteAddress, buf, version, id, type, deviceSession); - case 3: - case 4: - return decodeSc(channel, remoteAddress, buf, version, id, type, deviceSession); - default: - return decodeCc(channel, remoteAddress, buf, version, id, type, deviceSession); - } - } - -} diff --git a/src/org/traccar/protocol/CastelProtocolEncoder.java b/src/org/traccar/protocol/CastelProtocolEncoder.java deleted file mode 100644 index e1f78e7c1..000000000 --- a/src/org/traccar/protocol/CastelProtocolEncoder.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.Context; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class CastelProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeContent(long deviceId, short type, ByteBuf content) { - - ByteBuf buf = Unpooled.buffer(0); - String uniqueId = Context.getIdentityManager().getById(deviceId).getUniqueId(); - - buf.writeByte('@'); - buf.writeByte('@'); - - buf.writeShortLE(2 + 2 + 1 + 20 + 2 + content.readableBytes() + 2 + 2); // length - - buf.writeByte(1); // protocol version - - buf.writeBytes(uniqueId.getBytes(StandardCharsets.US_ASCII)); - buf.writeZero(20 - uniqueId.length()); - - buf.writeShort(type); - buf.writeBytes(content); - - buf.writeShortLE(Checksum.crc16(Checksum.CRC16_X25, buf.nioBuffer())); - - buf.writeByte('\r'); - buf.writeByte('\n'); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - ByteBuf content = Unpooled.buffer(0); - switch (command.getType()) { - case Command.TYPE_ENGINE_STOP: - content.writeByte(1); - return encodeContent(command.getDeviceId(), CastelProtocolDecoder.MSG_CC_PETROL_CONTROL, content); - case Command.TYPE_ENGINE_RESUME: - content.writeByte(0); - return encodeContent(command.getDeviceId(), CastelProtocolDecoder.MSG_CC_PETROL_CONTROL, content); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/CautelaProtocol.java b/src/org/traccar/protocol/CautelaProtocol.java deleted file mode 100644 index 452bdf8d4..000000000 --- a/src/org/traccar/protocol/CautelaProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class CautelaProtocol extends BaseProtocol { - - public CautelaProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new CautelaProtocolDecoder(CautelaProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CautelaProtocolDecoder.java b/src/org/traccar/protocol/CautelaProtocolDecoder.java deleted file mode 100644 index bddf19b41..000000000 --- a/src/org/traccar/protocol/CautelaProtocolDecoder.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class CautelaProtocolDecoder extends BaseProtocolDecoder { - - public CautelaProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(d+),") // type - .number("(d+),") // imei - .number("(dd),(dd),(dd),") // date (ddmmyy) - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(dd)(dd),") // time (hhmm) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - parser.next(); // type - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder(); - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setValid(true); - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - - dateBuilder.setHour(parser.nextInt()).setMinute(parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/CellocatorFrameDecoder.java b/src/org/traccar/protocol/CellocatorFrameDecoder.java deleted file mode 100644 index 7d5499d92..000000000 --- a/src/org/traccar/protocol/CellocatorFrameDecoder.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class CellocatorFrameDecoder extends BaseFrameDecoder { - - private static final int MESSAGE_MINIMUM_LENGTH = 15; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { - return null; - } - - int length = 0; - int type = buf.getUnsignedByte(4); - switch (type) { - case CellocatorProtocolDecoder.MSG_CLIENT_STATUS: - length = 70; - break; - case CellocatorProtocolDecoder.MSG_CLIENT_PROGRAMMING: - length = 31; - break; - case CellocatorProtocolDecoder.MSG_CLIENT_SERIAL_LOG: - length = 70; - break; - case CellocatorProtocolDecoder.MSG_CLIENT_SERIAL: - if (buf.readableBytes() >= 19) { - length = 19 + buf.getUnsignedShortLE(16); - } - break; - case CellocatorProtocolDecoder.MSG_CLIENT_MODULAR: - length = 15 + buf.getUnsignedByte(13); - break; - default: - break; - } - - if (length > 0 && buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/CellocatorProtocol.java b/src/org/traccar/protocol/CellocatorProtocol.java deleted file mode 100644 index a52170dc9..000000000 --- a/src/org/traccar/protocol/CellocatorProtocol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class CellocatorProtocol extends BaseProtocol { - - public CellocatorProtocol() { - setSupportedDataCommands( - Command.TYPE_OUTPUT_CONTROL); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CellocatorFrameDecoder()); - pipeline.addLast(new CellocatorProtocolEncoder()); - pipeline.addLast(new CellocatorProtocolDecoder(CellocatorProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CellocatorProtocolEncoder()); - pipeline.addLast(new CellocatorProtocolDecoder(CellocatorProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/org/traccar/protocol/CellocatorProtocolDecoder.java deleted file mode 100644 index d23f76a93..000000000 --- a/src/org/traccar/protocol/CellocatorProtocolDecoder.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class CellocatorProtocolDecoder extends BaseProtocolDecoder { - - public CellocatorProtocolDecoder(Protocol protocol) { - super(protocol); - } - - static final int MSG_CLIENT_STATUS = 0; - static final int MSG_CLIENT_PROGRAMMING = 3; - static final int MSG_CLIENT_SERIAL_LOG = 7; - static final int MSG_CLIENT_SERIAL = 8; - static final int MSG_CLIENT_MODULAR = 9; - - public static final int MSG_SERVER_ACKNOWLEDGE = 4; - - private byte commandCount; - - private void sendReply(Channel channel, SocketAddress remoteAddress, long deviceId, byte packetNumber) { - if (channel != null) { - ByteBuf reply = Unpooled.buffer(28); - reply.writeByte('M'); - reply.writeByte('C'); - reply.writeByte('G'); - reply.writeByte('P'); - reply.writeByte(MSG_SERVER_ACKNOWLEDGE); - reply.writeIntLE((int) deviceId); - reply.writeByte(commandCount++); - reply.writeIntLE(0); // authentication code - reply.writeByte(0); - reply.writeByte(packetNumber); - reply.writeZero(11); - - byte checksum = 0; - for (int i = 4; i < 27; i++) { - checksum += reply.getByte(i); - } - reply.writeByte(checksum); - - channel.writeAndFlush(new NetworkMessage(reply, remoteAddress)); - } - } - - private String decodeAlarm(short reason) { - switch (reason) { - case 70: - return Position.ALARM_SOS; - case 80: - return Position.ALARM_POWER_CUT; - case 81: - return Position.ALARM_LOW_POWER; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - boolean alternative = buf.getByte(buf.readerIndex() + 3) != 'P'; - - buf.skipBytes(4); // system code - int type = buf.readUnsignedByte(); - long deviceUniqueId = buf.readUnsignedIntLE(); - - if (type != MSG_CLIENT_SERIAL) { - buf.readUnsignedShortLE(); // communication control - } - byte packetNumber = buf.readByte(); - - sendReply(channel, remoteAddress, deviceUniqueId, packetNumber); - - if (type == MSG_CLIENT_STATUS) { - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceUniqueId)); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte()); - position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); - buf.readUnsignedByte(); // protocol version - - position.set(Position.KEY_STATUS, buf.readUnsignedByte() & 0x0f); - - buf.readUnsignedByte(); // operator / configuration flags - buf.readUnsignedByte(); // reason data - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); - - position.set("mode", buf.readUnsignedByte()); - position.set(Position.KEY_INPUT, buf.readUnsignedIntLE()); - - if (alternative) { - buf.readUnsignedByte(); // input - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE()); - } else { - buf.readUnsignedByte(); // operator - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedIntLE()); - } - - position.set(Position.KEY_ODOMETER, buf.readUnsignedMediumLE()); - - buf.skipBytes(6); // multi-purpose data - buf.readUnsignedShortLE(); // fix time - buf.readUnsignedByte(); // location status - buf.readUnsignedByte(); // mode 1 - buf.readUnsignedByte(); // mode 2 - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - position.setValid(true); - - if (alternative) { - position.setLongitude(buf.readIntLE() / 10000000.0); - position.setLatitude(buf.readIntLE() / 10000000.0); - } else { - position.setLongitude(buf.readIntLE() / Math.PI * 180 / 100000000); - position.setLatitude(buf.readIntLE() / Math.PI * 180 / 100000000); - } - - position.setAltitude(buf.readIntLE() * 0.01); - - if (alternative) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedIntLE())); - position.setCourse(buf.readUnsignedShortLE() / 1000.0); - } else { - position.setSpeed(UnitsConverter.knotsFromMps(buf.readUnsignedIntLE() * 0.01)); - position.setCourse(buf.readUnsignedShortLE() / Math.PI * 180.0 / 1000.0); - } - - DateBuilder dateBuilder = new DateBuilder() - .setTimeReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedShortLE()); - position.setTime(dateBuilder.getDate()); - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/CellocatorProtocolEncoder.java b/src/org/traccar/protocol/CellocatorProtocolEncoder.java deleted file mode 100644 index 0382dbbc7..000000000 --- a/src/org/traccar/protocol/CellocatorProtocolEncoder.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.model.Command; - -public class CellocatorProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeContent(long deviceId, int command, int data1, int data2) { - - ByteBuf buf = Unpooled.buffer(0); - buf.writeByte('M'); - buf.writeByte('C'); - buf.writeByte('G'); - buf.writeByte('P'); - buf.writeByte(0); - buf.writeIntLE(Integer.parseInt(getUniqueId(deviceId))); - buf.writeByte(0); // command numerator - buf.writeIntLE(0); // authentication code - buf.writeByte(command); - buf.writeByte(command); - buf.writeByte(data1); - buf.writeByte(data1); - buf.writeByte(data2); - buf.writeByte(data2); - buf.writeIntLE(0); // command specific data - - byte checksum = 0; - for (int i = 4; i < buf.writerIndex(); i++) { - checksum += buf.getByte(i); - } - buf.writeByte(checksum); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_OUTPUT_CONTROL: - int data = Integer.parseInt(command.getString(Command.KEY_DATA)) << 4 - + command.getInteger(Command.KEY_INDEX); - return encodeContent(command.getDeviceId(), 0x03, data, 0); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/CguardProtocol.java b/src/org/traccar/protocol/CguardProtocol.java deleted file mode 100644 index 9157ca35c..000000000 --- a/src/org/traccar/protocol/CguardProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class CguardProtocol extends BaseProtocol { - - public CguardProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new CguardProtocolDecoder(CguardProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CguardProtocolDecoder.java b/src/org/traccar/protocol/CguardProtocolDecoder.java deleted file mode 100644 index d934921f1..000000000 --- a/src/org/traccar/protocol/CguardProtocolDecoder.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class CguardProtocolDecoder extends BaseProtocolDecoder { - - public CguardProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_NV = new PatternBuilder() - .text("NV:") - .number("(dd)(dd)(dd) ") // date (yymmdd) - .number("(dd)(dd)(dd)") // time (hhmmss) - .number(":(-?d+.d+)") // longitude - .number(":(-?d+.d+)") // latitude - .number(":(d+.?d*)") // speed - .number(":(?:NAN|(d+.?d*))") // accuracy - .number(":(?:NAN|(d+.?d*))") // course - .number(":(?:NAN|(d+.?d*))").optional() // altitude - .compile(); - - private static final Pattern PATTERN_BC = new PatternBuilder() - .text("BC:") - .number("(dd)(dd)(dd) ") // date (yymmdd) - .number("(dd)(dd)(dd):") // time (hhmmss) - .expression("(.+)") // data - .compile(); - - private Position decodePosition(DeviceSession deviceSession, String sentence) { - - Parser parser = new Parser(PATTERN_NV, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setValid(true); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - - position.setAccuracy(parser.nextDouble(0)); - - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - return position; - } - - private Position decodeStatus(DeviceSession deviceSession, String sentence) { - - Parser parser = new Parser(PATTERN_BC, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, parser.nextDateTime()); - - String[] data = parser.next().split(":"); - for (int i = 0; i < data.length / 2; i++) { - String key = data[i * 2]; - String value = data[i * 2 + 1]; - switch (key) { - case "CSQ1": - position.set(Position.KEY_RSSI, Integer.parseInt(value)); - break; - case "NSQ1": - position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); - break; - case "BAT1": - if (value.contains(".")) { - position.set(Position.KEY_BATTERY, Double.parseDouble(value)); - } else { - position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(value)); - } - break; - case "PWR1": - position.set(Position.KEY_POWER, Double.parseDouble(value)); - break; - default: - position.set(key.toLowerCase(), value); - break; - } - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("ID:") || sentence.startsWith("IDRO:")) { - getDeviceSession(channel, remoteAddress, sentence.substring(sentence.indexOf(':') + 1)); - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - if (sentence.startsWith("NV:")) { - return decodePosition(deviceSession, sentence); - } else if (sentence.startsWith("BC:")) { - return decodeStatus(deviceSession, sentence); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/CityeasyProtocol.java b/src/org/traccar/protocol/CityeasyProtocol.java deleted file mode 100644 index f4b49c9ff..000000000 --- a/src/org/traccar/protocol/CityeasyProtocol.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class CityeasyProtocol extends BaseProtocol { - - public CityeasyProtocol() { - setSupportedDataCommands( - Command.TYPE_POSITION_SINGLE, - Command.TYPE_POSITION_PERIODIC, - Command.TYPE_POSITION_STOP, - Command.TYPE_SET_TIMEZONE); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0)); - pipeline.addLast(new CityeasyProtocolEncoder()); - pipeline.addLast(new CityeasyProtocolDecoder(CityeasyProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CityeasyProtocolDecoder.java b/src/org/traccar/protocol/CityeasyProtocolDecoder.java deleted file mode 100644 index 9c4c7e11d..000000000 --- a/src/org/traccar/protocol/CityeasyProtocolDecoder.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -public class CityeasyProtocolDecoder extends BaseProtocolDecoder { - - public CityeasyProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .groupBegin() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("([AV]),") // validity - .number("(d+),") // satellites - .number("([NS]),(d+.d+),") // latitude - .number("([EW]),(d+.d+),") // longitude - .number("(d+.d),") // speed - .number("(d+.d),") // hdop - .number("(d+.d)") // altitude - .groupEnd("?").text(";") - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(d+),") // lac - .number("(d+)") // cell - .any() - .compile(); - - public static final int MSG_ADDRESS_REQUEST = 0x0001; - public static final int MSG_STATUS = 0x0002; - public static final int MSG_LOCATION_REPORT = 0x0003; - public static final int MSG_LOCATION_REQUEST = 0x0004; - public static final int MSG_LOCATION_INTERVAL = 0x0005; - public static final int MSG_PHONE_NUMBER = 0x0006; - public static final int MSG_MONITORING = 0x0007; - public static final int MSG_TIMEZONE = 0x0008; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - buf.readUnsignedShort(); // length - - String imei = ByteBufUtil.hexDump(buf.readSlice(7)); - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, imei, imei + Checksum.luhn(Long.parseLong(imei))); - if (deviceSession == null) { - return null; - } - - int type = buf.readUnsignedShort(); - - if (type == MSG_LOCATION_REPORT || type == MSG_LOCATION_REQUEST) { - - String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 8, StandardCharsets.US_ASCII); - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.hasNext(15)) { - - position.setTime(parser.nextDateTime()); - - position.setValid(parser.next().equals("A")); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - - position.setSpeed(parser.nextDouble(0)); - position.set(Position.KEY_HDOP, parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - } else { - - getLastLocation(position, null); - - } - - position.setNetwork(new Network(CellTower.from( - parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)))); - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/CityeasyProtocolEncoder.java b/src/org/traccar/protocol/CityeasyProtocolEncoder.java deleted file mode 100644 index 350fdf0ab..000000000 --- a/src/org/traccar/protocol/CityeasyProtocolEncoder.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - * 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.TimeZone; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -public class CityeasyProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeContent(int type, ByteBuf content) { - - ByteBuf buf = Unpooled.buffer(); - - buf.writeByte('S'); - buf.writeByte('S'); - buf.writeShort(2 + 2 + 2 + content.readableBytes() + 4 + 2 + 2); - buf.writeShort(type); - buf.writeBytes(content); - buf.writeInt(0x0B); - buf.writeShort(Checksum.crc16(Checksum.CRC16_KERMIT, buf.nioBuffer())); - buf.writeByte('\r'); - buf.writeByte('\n'); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - ByteBuf content = Unpooled.buffer(); - - switch (command.getType()) { - case Command.TYPE_POSITION_SINGLE: - return encodeContent(CityeasyProtocolDecoder.MSG_LOCATION_REQUEST, content); - case Command.TYPE_POSITION_PERIODIC: - content.writeShort(command.getInteger(Command.KEY_FREQUENCY)); - return encodeContent(CityeasyProtocolDecoder.MSG_LOCATION_INTERVAL, content); - case Command.TYPE_POSITION_STOP: - content.writeShort(0); - return encodeContent(CityeasyProtocolDecoder.MSG_LOCATION_INTERVAL, content); - case Command.TYPE_SET_TIMEZONE: - int timezone = TimeZone.getTimeZone(command.getString(Command.KEY_TIMEZONE)).getRawOffset() / 60000; - if (timezone < 0) { - content.writeByte(1); - } else { - content.writeByte(0); - } - content.writeShort(Math.abs(timezone)); - return encodeContent(CityeasyProtocolDecoder.MSG_TIMEZONE, content); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/ContinentalProtocol.java b/src/org/traccar/protocol/ContinentalProtocol.java deleted file mode 100644 index bc7928fba..000000000 --- a/src/org/traccar/protocol/ContinentalProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ContinentalProtocol extends BaseProtocol { - - public ContinentalProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0)); - pipeline.addLast(new ContinentalProtocolDecoder(ContinentalProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ContinentalProtocolDecoder.java b/src/org/traccar/protocol/ContinentalProtocolDecoder.java deleted file mode 100644 index 471afa0d6..000000000 --- a/src/org/traccar/protocol/ContinentalProtocolDecoder.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; - -public class ContinentalProtocolDecoder extends BaseProtocolDecoder { - - public ContinentalProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_KEEPALIVE = 0x00; - public static final int MSG_STATUS = 0x02; - public static final int MSG_ACK = 0x06; - public static final int MSG_NACK = 0x15; - - private double readCoordinate(ByteBuf buf, boolean extended) { - long value = buf.readUnsignedInt(); - if (extended ? (value & 0x08000000) != 0 : (value & 0x00800000) != 0) { - value |= extended ? 0xF0000000 : 0xFF000000; - } - return (int) value / (extended ? 360000.0 : 3600.0); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - buf.readUnsignedShort(); // length - buf.readUnsignedByte(); // software version - - long serialNumber = buf.readUnsignedInt(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(serialNumber)); - if (deviceSession == null) { - return null; - } - - buf.readUnsignedByte(); // product - - int type = buf.readUnsignedByte(); - - if (type == MSG_STATUS) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setFixTime(new Date(buf.readUnsignedInt() * 1000L)); - - boolean extended = buf.getUnsignedByte(buf.readerIndex()) != 0; - position.setLatitude(readCoordinate(buf, extended)); - position.setLongitude(readCoordinate(buf, extended)); - - position.setCourse(buf.readUnsignedShort()); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - - position.setValid(buf.readUnsignedByte() > 0); - - position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000L)); - - position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - - int input = buf.readUnsignedShort(); - position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); - position.set(Position.KEY_INPUT, input); - - position.set(Position.KEY_OUTPUT, buf.readUnsignedShort()); - position.set(Position.KEY_BATTERY, buf.readUnsignedByte()); - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - - buf.readUnsignedShort(); // reserved - - if (buf.readableBytes() > 4) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - } - - if (buf.readableBytes() > 4) { - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(buf.readUnsignedInt())); - } - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/CradlepointProtocol.java b/src/org/traccar/protocol/CradlepointProtocol.java deleted file mode 100644 index 4a09e0311..000000000 --- a/src/org/traccar/protocol/CradlepointProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class CradlepointProtocol extends BaseProtocol { - - public CradlepointProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new CradlepointProtocolDecoder(CradlepointProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/CradlepointProtocolDecoder.java b/src/org/traccar/protocol/CradlepointProtocolDecoder.java deleted file mode 100644 index a282131ce..000000000 --- a/src/org/traccar/protocol/CradlepointProtocolDecoder.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.regex.Pattern; - -public class CradlepointProtocolDecoder extends BaseProtocolDecoder { - - public CradlepointProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("([^,]+),") // id - .number("(d{1,6}),") // time (hhmmss) - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+)?,") // speed - .number("(d+.d+)?,") // course - .expression("([^,]+)?,") // carrier - .expression("([^,]+)?,") // serdis - .number("(-?d+)?,") // rsrp - .number("(-?d+)?,") // rssi - .number("(-?d+)?,") // rsrq - .expression("([^,]+)?,") // ecio - .expression("([^,]+)?") // wan ip - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - int time = parser.nextInt(); - DateBuilder dateBuilder = new DateBuilder(new Date()); - dateBuilder.setHour(time / 100 / 100); - dateBuilder.setMinute(time / 100 % 100); - dateBuilder.setSecond(time % 100); - position.setTime(dateBuilder.getDate()); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set("carrid", parser.next()); - position.set("serdis", parser.next()); - position.set("rsrp", parser.nextInt()); - position.set(Position.KEY_RSSI, parser.nextInt()); - position.set("rsrq", parser.nextInt()); - position.set("ecio", parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/DishaProtocol.java b/src/org/traccar/protocol/DishaProtocol.java deleted file mode 100644 index 38f49cc05..000000000 --- a/src/org/traccar/protocol/DishaProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class DishaProtocol extends BaseProtocol { - - public DishaProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new DishaProtocolDecoder(DishaProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/DishaProtocolDecoder.java b/src/org/traccar/protocol/DishaProtocolDecoder.java deleted file mode 100644 index 3223988ab..000000000 --- a/src/org/traccar/protocol/DishaProtocolDecoder.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class DishaProtocolDecoder extends BaseProtocolDecoder { - - public DishaProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$A#A#") - .number("(d+)#") // imei - .expression("([AVMX])#") // validity - .number("(dd)(dd)(dd)#") // time (hhmmss) - .number("(dd)(dd)(dd)#") // date (ddmmyy) - .number("(dd)(dd.d+)#") // latitude - .expression("([NS])#") - .number("(ddd)(dd.d+)#") // longitude - .expression("([EW])#") - .number("(d+.d+)#") // speed - .number("(d+.d+)#") // course - .number("(d+)#") // satellites - .number("(d+.d+)#") // hdop - .number("(d+)#") // gsm - .expression("([012])#") // power mode - .number("(d+)#") // battery - .number("(d+)#") // adc 1 - .number("(d+)#") // adc 2 - .number("d+.d+#") // day distance - .number("(d+.d+)#") // odometer - .expression("([01]+)") // digital inputs - .text("*") - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.next().equals("A")); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_RSSI, parser.nextDouble()); - position.set(Position.KEY_CHARGE, parser.nextInt(0) == 2); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); - - position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); - position.set(Position.PREFIX_ADC + 2, parser.nextInt(0)); - - position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); - position.set(Position.KEY_INPUT, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/DmtHttpProtocol.java b/src/org/traccar/protocol/DmtHttpProtocol.java deleted file mode 100644 index 34568128f..000000000 --- a/src/org/traccar/protocol/DmtHttpProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class DmtHttpProtocol extends BaseProtocol { - - public DmtHttpProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(65535)); - pipeline.addLast(new DmtHttpProtocolDecoder(DmtHttpProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/DmtHttpProtocolDecoder.java b/src/org/traccar/protocol/DmtHttpProtocolDecoder.java deleted file mode 100644 index 987361baf..000000000 --- a/src/org/traccar/protocol/DmtHttpProtocolDecoder.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpResponseStatus; -import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; -import java.io.StringReader; -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.LinkedList; -import java.util.List; -import java.util.TimeZone; - -public class DmtHttpProtocolDecoder extends BaseHttpProtocolDecoder { - - public DmtHttpProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - JsonObject root = Json.createReader( - new StringReader(request.content().toString(StandardCharsets.US_ASCII))).readObject(); - - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, root.getString("IMEI")); - if (deviceSession == null) { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - - List positions = new LinkedList<>(); - - JsonArray records = root.getJsonArray("Records"); - - for (int i = 0; i < records.size(); i++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - JsonObject record = records.getJsonObject(i); - - position.set(Position.KEY_INDEX, record.getInt("SeqNo")); - position.set(Position.KEY_EVENT, record.getInt("Reason")); - - position.setDeviceTime(dateFormat.parse(record.getString("DateUTC"))); - - JsonArray fields = record.getJsonArray("Fields"); - - for (int j = 0; j < fields.size(); j++) { - JsonObject field = fields.getJsonObject(j); - switch (field.getInt("FType")) { - case 0: - position.setFixTime(dateFormat.parse(field.getString("GpsUTC"))); - position.setLatitude(field.getJsonNumber("Lat").doubleValue()); - position.setLongitude(field.getJsonNumber("Long").doubleValue()); - position.setAltitude(field.getInt("Alt")); - position.setSpeed(UnitsConverter.knotsFromCps(field.getInt("Spd"))); - position.setCourse(field.getInt("Head")); - position.setAccuracy(field.getInt("PosAcc")); - position.setValid(field.getInt("GpsStat") > 0); - break; - case 2: - int input = field.getInt("DIn"); - int output = field.getInt("DOut"); - - position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); - - position.set(Position.KEY_INPUT, input); - position.set(Position.KEY_OUTPUT, output); - position.set(Position.KEY_STATUS, field.getInt("DevStat")); - break; - case 6: - JsonObject adc = field.getJsonObject("AnalogueData"); - if (adc.containsKey("1")) { - position.set(Position.KEY_BATTERY, adc.getInt("1") * 0.001); - } - if (adc.containsKey("2")) { - position.set(Position.KEY_POWER, adc.getInt("2") * 0.01); - } - if (adc.containsKey("3")) { - position.set(Position.KEY_DEVICE_TEMP, adc.getInt("3") * 0.01); - } - if (adc.containsKey("4")) { - position.set(Position.KEY_RSSI, adc.getInt("4")); - } - if (adc.containsKey("5")) { - position.set("solarPower", adc.getInt("5") * 0.001); - } - break; - default: - break; - } - } - - positions.add(position); - } - - sendResponse(channel, HttpResponseStatus.OK); - return positions; - } - -} diff --git a/src/org/traccar/protocol/DmtProtocol.java b/src/org/traccar/protocol/DmtProtocol.java deleted file mode 100644 index 78a5243c0..000000000 --- a/src/org/traccar/protocol/DmtProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; -public class DmtProtocol extends BaseProtocol { - - public DmtProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 3, 2, 0, 0, true)); - pipeline.addLast(new DmtProtocolDecoder(DmtProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/DmtProtocolDecoder.java b/src/org/traccar/protocol/DmtProtocolDecoder.java deleted file mode 100644 index c04e90f1d..000000000 --- a/src/org/traccar/protocol/DmtProtocolDecoder.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class DmtProtocolDecoder extends BaseProtocolDecoder { - - public DmtProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_HELLO = 0x00; - public static final int MSG_HELLO_RESPONSE = 0x01; - public static final int MSG_DATA_RECORD = 0x04; - public static final int MSG_COMMIT = 0x05; - public static final int MSG_COMMIT_RESPONSE = 0x06; - public static final int MSG_DATA_RECORD_64 = 0x10; - - public static final int MSG_CANNED_REQUEST_1 = 0x14; - public static final int MSG_CANNED_RESPONSE_1 = 0x15; - public static final int MSG_CANNED_REQUEST_2 = 0x22; - public static final int MSG_CANNED_RESPONSE_2 = 0x23; - - private void sendResponse(Channel channel, int type, ByteBuf content) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(0x02); response.writeByte(0x55); // header - response.writeByte(type); - response.writeShortLE(content != null ? content.readableBytes() : 0); - if (content != null) { - response.writeBytes(content); - content.release(); - } - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - private List decodeFixed64(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - while (buf.readableBytes() >= 64) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readByte(); // type - - position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); - - long time = buf.readUnsignedIntLE(); - position.setTime(new DateBuilder() - .setYear((int) (2000 + (time & 0x3F))) - .setMonth((int) (time >> 6) & 0xF) - .setDay((int) (time >> 10) & 0x1F) - .setHour((int) (time >> 15) & 0x1F) - .setMinute((int) (time >> 20) & 0x3F) - .setSecond((int) (time >> 26) & 0x3F) - .getDate()); - - position.setLongitude(buf.readIntLE() * 0.0000001); - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE())); - position.setCourse(buf.readUnsignedByte() * 2); - position.setAltitude(buf.readShortLE()); - - buf.readUnsignedShortLE(); // position accuracy - buf.readUnsignedByte(); // speed accuracy - - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - - position.setValid(BitUtil.check(buf.readByte(), 0)); - - position.set(Position.KEY_INPUT, buf.readUnsignedIntLE()); - position.set(Position.KEY_OUTPUT, buf.readUnsignedShortLE()); - - for (int i = 1; i <= 5; i++) { - position.set(Position.PREFIX_ADC + i, buf.readShortLE()); - } - - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - - buf.readShortLE(); // accelerometer x - buf.readShortLE(); // accelerometer y - buf.readShortLE(); // accelerometer z - - buf.skipBytes(8); // device id - - position.set(Position.KEY_PDOP, buf.readUnsignedShortLE() * 0.01); - - buf.skipBytes(2); // reserved - - buf.readUnsignedShortLE(); // checksum - - positions.add(position); - } - - return positions; - } - - private List decodeStandard(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - while (buf.isReadable()) { - int recordEnd = buf.readerIndex() + buf.readUnsignedShortLE(); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); - - position.setDeviceTime(new Date(1356998400000L + buf.readUnsignedIntLE() * 1000)); // since 1 Jan 2013 - - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - - while (buf.readerIndex() < recordEnd) { - - int fieldId = buf.readUnsignedByte(); - int fieldLength = buf.readUnsignedByte(); - int fieldEnd = buf.readerIndex() + (fieldLength == 255 ? buf.readUnsignedShortLE() : fieldLength); - - if (fieldId == 0) { - - position.setFixTime(new Date(1356998400000L + buf.readUnsignedIntLE() * 1000)); - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - position.setAltitude(buf.readShortLE()); - position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE())); - - buf.readUnsignedByte(); // speed accuracy - - position.setCourse(buf.readUnsignedByte() * 2); - - position.set(Position.KEY_PDOP, buf.readUnsignedByte() * 0.1); - - position.setAccuracy(buf.readUnsignedByte()); - position.setValid(buf.readUnsignedByte() != 0); - - } else if (fieldId == 2) { - - int input = buf.readIntLE(); - int output = buf.readUnsignedShortLE(); - int status = buf.readUnsignedShortLE(); - - position.set(Position.KEY_IGNITION, BitUtil.check(input, 0)); - - position.set(Position.KEY_INPUT, input); - position.set(Position.KEY_OUTPUT, output); - position.set(Position.KEY_STATUS, status); - - } else if (fieldId == 6) { - - while (buf.readerIndex() < fieldEnd) { - switch (buf.readUnsignedByte()) { - case 1: - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); - break; - case 2: - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); - break; - case 3: - position.set(Position.KEY_DEVICE_TEMP, buf.readShortLE() * 0.01); - break; - case 4: - position.set(Position.KEY_RSSI, buf.readUnsignedShortLE()); - break; - case 5: - position.set("solarPower", buf.readUnsignedShortLE() * 0.001); - break; - default: - break; - } - } - - } - - buf.readerIndex(fieldEnd); - - } - - if (position.getFixTime() == null) { - getLastLocation(position, position.getDeviceTime()); - } - - positions.add(position); - } - - return positions; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - - int type = buf.readUnsignedByte(); - int length = buf.readUnsignedShortLE(); - - if (type == MSG_HELLO) { - - buf.readUnsignedIntLE(); // device serial number - - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII)); - - ByteBuf response = Unpooled.buffer(); - if (length == 51) { - response.writeByte(0); // reserved - response.writeIntLE(0); // reserved - } else { - response.writeIntLE((int) ((System.currentTimeMillis() - 1356998400000L) / 1000)); - response.writeIntLE(deviceSession != null ? 0 : 1); // flags - } - - sendResponse(channel, MSG_HELLO_RESPONSE, response); - - } else if (type == MSG_COMMIT) { - - ByteBuf response = Unpooled.buffer(0); - response.writeByte(1); // flags (success) - sendResponse(channel, MSG_COMMIT_RESPONSE, response); - - } else if (type == MSG_CANNED_REQUEST_1) { - - ByteBuf response = Unpooled.buffer(0); - response.writeBytes(new byte[12]); - sendResponse(channel, MSG_CANNED_RESPONSE_1, response); - - } else if (type == MSG_CANNED_REQUEST_2) { - - sendResponse(channel, MSG_CANNED_RESPONSE_2, null); - - } else if (type == MSG_DATA_RECORD_64) { - - return decodeFixed64(channel, remoteAddress, buf); - - } else if (type == MSG_DATA_RECORD) { - - return decodeStandard(channel, remoteAddress, buf); - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/DwayProtocol.java b/src/org/traccar/protocol/DwayProtocol.java deleted file mode 100644 index 05fd8b6e7..000000000 --- a/src/org/traccar/protocol/DwayProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class DwayProtocol extends BaseProtocol { - - public DwayProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new DwayProtocolDecoder(DwayProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/DwayProtocolDecoder.java b/src/org/traccar/protocol/DwayProtocolDecoder.java deleted file mode 100644 index 9b02c898e..000000000 --- a/src/org/traccar/protocol/DwayProtocolDecoder.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class DwayProtocolDecoder extends BaseProtocolDecoder { - - public DwayProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("AA55,") - .number("d+,") // index - .number("(d+),") // imei - .number("d+,") // type - .number("(dd)(dd)(dd),") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(-?d+),") // altitude - .number(" ?(d+.d+),") // speed - .number("(d+),") // course - .number("([01]{4}),") // input - .number("([01]{4}),") // output - .number("([01]+),") // flags - .number("(d+),") // battery - .number("(d+),") // adc1 - .number("(d+),") // adc2 - .number("(d+)") // driver - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - if (sentence.equals("AA55,HB")) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("55AA,HB,OK\r\n", remoteAddress)); - } - return null; - } - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(true); - position.setTime(parser.nextDateTime()); - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setAltitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_INPUT, parser.nextBinInt()); - position.set(Position.KEY_OUTPUT, parser.nextBinInt()); - - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); - position.set(Position.PREFIX_ADC + 1, parser.nextInt() * 0.001); - position.set(Position.PREFIX_ADC + 2, parser.nextInt() * 0.001); - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/EasyTrackProtocol.java b/src/org/traccar/protocol/EasyTrackProtocol.java deleted file mode 100644 index 74c636d06..000000000 --- a/src/org/traccar/protocol/EasyTrackProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class EasyTrackProtocol extends BaseProtocol { - - public EasyTrackProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "#", "\r\n")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new EasyTrackProtocolDecoder(EasyTrackProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/org/traccar/protocol/EasyTrackProtocolDecoder.java deleted file mode 100644 index 2ddb24f5c..000000000 --- a/src/org/traccar/protocol/EasyTrackProtocolDecoder.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { - - public EasyTrackProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("*").expression("..,") // manufacturer - .number("(d+),") // imei - .expression("([^,]{2}),") // command - .expression("([AV]),") // validity - .number("(xx)(xx)(xx),") // date (yymmdd) - .number("(xx)(xx)(xx),") // time (hhmmss) - .number("(x)(x{7}),") // latitude - .number("(x)(x{7}),") // longitude - .number("(x{4}),") // speed - .number("(x{4}),") // course - .number("(x{8}),") // status - .number("(x+),") // signal - .number("(d+),") // power - .number("(x{4}),") // oil - .number("(x+),?") // odometer - .number("(d+)?") // altitude - .any() - .compile(); - - private String decodeAlarm(long status) { - if ((status & 0x02000000) != 0) { - return Position.ALARM_GEOFENCE_ENTER; - } - if ((status & 0x04000000) != 0) { - return Position.ALARM_GEOFENCE_EXIT; - } - if ((status & 0x08000000) != 0) { - return Position.ALARM_LOW_BATTERY; - } - if ((status & 0x20000000) != 0) { - return Position.ALARM_VIBRATION; - } - if ((status & 0x80000000) != 0) { - return Position.ALARM_OVERSPEED; - } - if ((status & 0x00010000) != 0) { - return Position.ALARM_SOS; - } - if ((status & 0x00040000) != 0) { - return Position.ALARM_POWER_CUT; - } - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_COMMAND, parser.next()); - - position.setValid(parser.next().equals("A")); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(parser.nextHexInt(0), parser.nextHexInt(0), parser.nextHexInt(0)) - .setTime(parser.nextHexInt(0), parser.nextHexInt(0), parser.nextHexInt(0)); - position.setTime(dateBuilder.getDate()); - - if (BitUtil.check(parser.nextHexInt(0), 3)) { - position.setLatitude(-parser.nextHexInt(0) / 600000.0); - } else { - position.setLatitude(parser.nextHexInt(0) / 600000.0); - } - - if (BitUtil.check(parser.nextHexInt(0), 3)) { - position.setLongitude(-parser.nextHexInt(0) / 600000.0); - } else { - position.setLongitude(parser.nextHexInt(0) / 600000.0); - } - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextHexInt(0) / 100.0)); - position.setCourse(parser.nextHexInt(0) / 100.0); - - long status = parser.nextHexLong(); - position.set(Position.KEY_STATUS, status); - position.set(Position.KEY_ALARM, decodeAlarm(status)); - - position.set("signal", parser.next()); - position.set(Position.KEY_POWER, parser.nextDouble(0)); - position.set("oil", parser.nextHexInt(0)); - position.set(Position.KEY_ODOMETER, parser.nextHexInt(0) * 100); - - position.setAltitude(parser.nextDouble(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/EelinkProtocol.java b/src/org/traccar/protocol/EelinkProtocol.java deleted file mode 100644 index de4ea971b..000000000 --- a/src/org/traccar/protocol/EelinkProtocol.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class EelinkProtocol extends BaseProtocol { - - public EelinkProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_POSITION_SINGLE, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_REBOOT_DEVICE); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2)); - pipeline.addLast(new EelinkProtocolEncoder(false)); - pipeline.addLast(new EelinkProtocolDecoder(EelinkProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new EelinkProtocolEncoder(true)); - pipeline.addLast(new EelinkProtocolDecoder(EelinkProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/EelinkProtocolDecoder.java b/src/org/traccar/protocol/EelinkProtocolDecoder.java deleted file mode 100644 index 2a1db2e32..000000000 --- a/src/org/traccar/protocol/EelinkProtocolDecoder.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.socket.DatagramChannel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.regex.Pattern; - -public class EelinkProtocolDecoder extends BaseProtocolDecoder { - - public EelinkProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_LOGIN = 0x01; - public static final int MSG_GPS = 0x02; - public static final int MSG_HEARTBEAT = 0x03; - public static final int MSG_ALARM = 0x04; - public static final int MSG_STATE = 0x05; - public static final int MSG_SMS = 0x06; - public static final int MSG_OBD = 0x07; - public static final int MSG_DOWNLINK = 0x80; - public static final int MSG_DATA = 0x81; - - public static final int MSG_NORMAL = 0x12; - public static final int MSG_WARNING = 0x14; - public static final int MSG_REPORT = 0x15; - public static final int MSG_COMMAND = 0x16; - public static final int MSG_OBD_DATA = 0x17; - public static final int MSG_OBD_BODY = 0x18; - public static final int MSG_OBD_CODE = 0x19; - public static final int MSG_CAMERA_INFO = 0x1E; - public static final int MSG_CAMERA_DATA = 0x1F; - - private String decodeAlarm(Short value) { - switch (value) { - case 0x01: - return Position.ALARM_POWER_OFF; - case 0x02: - return Position.ALARM_SOS; - case 0x03: - return Position.ALARM_LOW_BATTERY; - case 0x04: - return Position.ALARM_VIBRATION; - case 0x08: - case 0x09: - return Position.ALARM_GPS_ANTENNA_CUT; - case 0x81: - return Position.ALARM_LOW_SPEED; - case 0x82: - return Position.ALARM_OVERSPEED; - case 0x83: - return Position.ALARM_GEOFENCE_ENTER; - case 0x84: - return Position.ALARM_GEOFENCE_EXIT; - case 0x85: - return Position.ALARM_ACCIDENT; - case 0x86: - return Position.ALARM_FALL_DOWN; - default: - return null; - } - } - - private void decodeStatus(Position position, int status) { - if (BitUtil.check(status, 1)) { - position.set(Position.KEY_IGNITION, BitUtil.check(status, 2)); - } - if (BitUtil.check(status, 3)) { - position.set(Position.KEY_ARMED, BitUtil.check(status, 4)); - } - if (BitUtil.check(status, 5)) { - position.set(Position.KEY_BLOCKED, !BitUtil.check(status, 6)); - } - if (BitUtil.check(status, 7)) { - position.set(Position.KEY_CHARGE, BitUtil.check(status, 8)); - } - position.set(Position.KEY_STATUS, status); - } - - private Position decodeOld(DeviceSession deviceSession, ByteBuf buf, int type, int index) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, index); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - position.setLatitude(buf.readInt() / 1800000.0); - position.setLongitude(buf.readInt() / 1800000.0); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.setCourse(buf.readUnsignedShort()); - - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedMedium()))); - - position.setValid((buf.readUnsignedByte() & 0x01) != 0); - - if (type == MSG_GPS) { - - if (buf.readableBytes() >= 2) { - decodeStatus(position, buf.readUnsignedShort()); - } - - if (buf.readableBytes() >= 2 * 4) { - - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); - - position.set(Position.KEY_RSSI, buf.readUnsignedShort()); - - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); - - } - - } else if (type == MSG_ALARM) { - - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); - - } else if (type == MSG_STATE) { - - int statusType = buf.readUnsignedByte(); - - position.set(Position.KEY_EVENT, statusType); - - if (statusType == 0x01 || statusType == 0x02 || statusType == 0x03) { - buf.readUnsignedInt(); // device time - if (buf.readableBytes() >= 2) { - decodeStatus(position, buf.readUnsignedShort()); - } - } - - } - - return position; - } - - private Position decodeNew(DeviceSession deviceSession, ByteBuf buf, int type, int index) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, index); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - - int flags = buf.readUnsignedByte(); - - if (BitUtil.check(flags, 0)) { - position.setLatitude(buf.readInt() / 1800000.0); - position.setLongitude(buf.readInt() / 1800000.0); - position.setAltitude(buf.readShort()); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - position.setCourse(buf.readUnsignedShort()); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - } else { - getLastLocation(position, position.getDeviceTime()); - } - - if (BitUtil.check(flags, 1)) { - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readUnsignedShort(), buf.readUnsignedInt(), buf.readUnsignedByte()))); - } - - if (BitUtil.check(flags, 2)) { - buf.skipBytes(7); // bsid1 - } - - if (BitUtil.check(flags, 3)) { - buf.skipBytes(7); // bsid2 - } - - if (BitUtil.check(flags, 4)) { - buf.skipBytes(7); // bss0 - } - - if (BitUtil.check(flags, 5)) { - buf.skipBytes(7); // bss1 - } - - if (BitUtil.check(flags, 6)) { - buf.skipBytes(7); // bss2 - } - - if (type == MSG_WARNING) { - - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); - - } else if (type == MSG_REPORT) { - - buf.readUnsignedByte(); // report type - - } - - if (type == MSG_NORMAL || type == MSG_WARNING || type == MSG_REPORT) { - - int status = buf.readUnsignedShort(); - position.setValid(BitUtil.check(status, 0)); - if (BitUtil.check(status, 1)) { - position.set(Position.KEY_IGNITION, BitUtil.check(status, 2)); - } - position.set(Position.KEY_STATUS, status); - - } - - if (type == MSG_NORMAL) { - - if (buf.readableBytes() >= 2) { - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); - } - - if (buf.readableBytes() >= 4) { - position.set(Position.PREFIX_ADC + 0, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - } - - if (buf.readableBytes() >= 4) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - } - - if (buf.readableBytes() >= 4) { - buf.readUnsignedShort(); // gsm counter - buf.readUnsignedShort(); // gps counter - } - - if (buf.readableBytes() >= 4) { - position.set(Position.KEY_STEPS, buf.readUnsignedShort()); - buf.readUnsignedShort(); // walking time - } - - if (buf.readableBytes() >= 12) { - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0); - position.set("humidity", buf.readUnsignedShort() * 0.1); - position.set("illuminance", buf.readUnsignedInt() / 256.0); - position.set("co2", buf.readUnsignedInt()); - } - - if (buf.readableBytes() >= 2) { - position.set(Position.PREFIX_TEMP + 2, buf.readShort() / 16.0); - } - - } - - return position; - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("Lat:") - .number("([NS])(d+.d+)") // latitude - .any() - .text("Lon:") - .number("([EW])(d+.d+)") // longitude - .any() - .text("Course:") - .number("(d+.d+)") // course - .any() - .text("Speed:") - .number("(d+.d+)") // speed - .any() - .expression("Date ?Time:") - .number("(dddd)-(dd)-(dd) ") // date - .number("(dd):(dd):(dd)") // time - .compile(); - - private Position decodeResult(DeviceSession deviceSession, ByteBuf buf, int index) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, index); - - buf.readUnsignedByte(); // type - buf.readUnsignedInt(); // uid - - String sentence = buf.toString(StandardCharsets.UTF_8); - - Parser parser = new Parser(PATTERN, sentence); - if (parser.matches()) { - - position.setValid(true); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setCourse(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setTime(parser.nextDateTime()); - - } else { - - getLastLocation(position, null); - - position.set(Position.KEY_RESULT, sentence); - - } - - return position; - } - - private Position decodeObd(DeviceSession deviceSession, ByteBuf buf, int index) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); - - while (buf.readableBytes() > 0) { - int pid = buf.readUnsignedByte(); - int value = buf.readInt(); - switch (pid) { - case 0x89: - position.set(Position.KEY_FUEL_CONSUMPTION, value); - break; - case 0x8a: - position.set(Position.KEY_ODOMETER, value * 1000L); - break; - case 0x8b: - position.set(Position.KEY_FUEL_LEVEL, value / 10); - break; - default: - break; - } - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - String uniqueId = null; - DeviceSession deviceSession; - - if (buf.getByte(0) == 'E' && buf.getByte(1) == 'L') { - buf.skipBytes(2 + 2 + 2); // udp header - uniqueId = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); - deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); - } else { - deviceSession = getDeviceSession(channel, remoteAddress); - } - - buf.skipBytes(2); // header - int type = buf.readUnsignedByte(); - buf.readShort(); // length - int index = buf.readUnsignedShort(); - - if (type != MSG_GPS && type != MSG_DATA) { - ByteBuf content = Unpooled.buffer(); - if (type == MSG_LOGIN) { - content.writeInt((int) (System.currentTimeMillis() / 1000)); - content.writeByte(1); // protocol version - content.writeByte(0); // action mask - } - ByteBuf response = EelinkProtocolEncoder.encodeContent( - channel instanceof DatagramChannel, uniqueId, type, index, content); - content.release(); - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - if (type == MSG_LOGIN) { - - if (deviceSession == null) { - getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(buf.readSlice(8)).substring(1)); - } - - } else { - - if (deviceSession == null) { - return null; - } - - if (type == MSG_GPS || type == MSG_ALARM || type == MSG_STATE || type == MSG_SMS) { - - return decodeOld(deviceSession, buf, type, index); - - } else if (type >= MSG_NORMAL && type <= MSG_OBD_CODE) { - - return decodeNew(deviceSession, buf, type, index); - - } else if (type == MSG_HEARTBEAT && buf.readableBytes() >= 2) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - decodeStatus(position, buf.readUnsignedShort()); - - return position; - - } else if (type == MSG_OBD) { - - return decodeObd(deviceSession, buf, index); - - } else if (type == MSG_DOWNLINK) { - - return decodeResult(deviceSession, buf, index); - - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/EelinkProtocolEncoder.java b/src/org/traccar/protocol/EelinkProtocolEncoder.java deleted file mode 100644 index 8f33441fb..000000000 --- a/src/org/traccar/protocol/EelinkProtocolEncoder.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.helper.DataConverter; -import org.traccar.model.Command; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; - -public class EelinkProtocolEncoder extends BaseProtocolEncoder { - - private boolean connectionless; - - public EelinkProtocolEncoder(boolean connectionless) { - this.connectionless = connectionless; - } - - public static int checksum(ByteBuffer buf) { - int sum = 0; - while (buf.hasRemaining()) { - sum = (((sum << 1) | (sum >> 15)) + (buf.get() & 0xFF)) & 0xFFFF; - } - return sum; - } - - public static ByteBuf encodeContent( - boolean connectionless, String uniqueId, int type, int index, ByteBuf content) { - - ByteBuf buf = Unpooled.buffer(); - - if (connectionless) { - buf.writeBytes(DataConverter.parseHex('0' + uniqueId)); - } - - buf.writeByte(0x67); - buf.writeByte(0x67); - buf.writeByte(type); - buf.writeShort(2 + (content != null ? content.readableBytes() : 0)); // length - buf.writeShort(index); - - if (content != null) { - buf.writeBytes(content); - } - - ByteBuf result = Unpooled.buffer(); - - if (connectionless) { - result.writeByte('E'); - result.writeByte('L'); - result.writeShort(2 + buf.readableBytes()); // length - result.writeShort(checksum(buf.nioBuffer())); - } - - result.writeBytes(buf); - buf.release(); - - return result; - } - - private ByteBuf encodeContent(long deviceId, String content) { - - ByteBuf buf = Unpooled.buffer(); - - buf.writeByte(0x01); // command - buf.writeInt(0); // server id - buf.writeBytes(content.getBytes(StandardCharsets.UTF_8)); - - return encodeContent(connectionless, getUniqueId(deviceId), EelinkProtocolDecoder.MSG_DOWNLINK, 0, buf); - } - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return encodeContent(command.getDeviceId(), command.getString(Command.KEY_DATA)); - case Command.TYPE_POSITION_SINGLE: - return encodeContent(command.getDeviceId(), "WHERE#"); - case Command.TYPE_ENGINE_STOP: - return encodeContent(command.getDeviceId(), "RELAY,1#"); - case Command.TYPE_ENGINE_RESUME: - return encodeContent(command.getDeviceId(), "RELAY,0#"); - case Command.TYPE_REBOOT_DEVICE: - return encodeContent(command.getDeviceId(), "RESET#"); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/EgtsFrameDecoder.java b/src/org/traccar/protocol/EgtsFrameDecoder.java deleted file mode 100644 index 84f1f11a7..000000000 --- a/src/org/traccar/protocol/EgtsFrameDecoder.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class EgtsFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 10) { - return null; - } - - int headerLength = buf.getUnsignedByte(buf.readerIndex() + 3); - int frameLength = buf.getUnsignedShortLE(buf.readerIndex() + 5); - - int length = headerLength + frameLength + (frameLength > 0 ? 2 : 0); - - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/EgtsProtocol.java b/src/org/traccar/protocol/EgtsProtocol.java deleted file mode 100644 index 5d4638f37..000000000 --- a/src/org/traccar/protocol/EgtsProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class EgtsProtocol extends BaseProtocol { - - public EgtsProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new EgtsFrameDecoder()); - pipeline.addLast(new EgtsProtocolDecoder(EgtsProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/EgtsProtocolDecoder.java b/src/org/traccar/protocol/EgtsProtocolDecoder.java deleted file mode 100644 index b9fcb2f44..000000000 --- a/src/org/traccar/protocol/EgtsProtocolDecoder.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -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.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class EgtsProtocolDecoder extends BaseProtocolDecoder { - - public EgtsProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int PT_RESPONSE = 0; - public static final int PT_APPDATA = 1; - public static final int PT_SIGNED_APPDATA = 2; - - public static final int SERVICE_AUTH = 1; - public static final int SERVICE_TELEDATA = 2; - public static final int SERVICE_COMMANDS = 4; - public static final int SERVICE_FIRMWARE = 9; - public static final int SERVICE_ECALL = 10; - - public static final int MSG_RECORD_RESPONSE = 0; - public static final int MSG_TERM_IDENTITY = 1; - public static final int MSG_MODULE_DATA = 2; - public static final int MSG_VEHICLE_DATA = 3; - public static final int MSG_AUTH_PARAMS = 4; - public static final int MSG_AUTH_INFO = 5; - public static final int MSG_SERVICE_INFO = 6; - public static final int MSG_RESULT_CODE = 7; - public static final int MSG_POS_DATA = 16; - public static final int MSG_EXT_POS_DATA = 17; - public static final int MSG_AD_SENSORS_DATA = 18; - public static final int MSG_COUNTERS_DATA = 19; - public static final int MSG_STATE_DATA = 20; - public static final int MSG_LOOPIN_DATA = 22; - public static final int MSG_ABS_DIG_SENS_DATA = 23; - public static final int MSG_ABS_AN_SENS_DATA = 24; - public static final int MSG_ABS_CNTR_DATA = 25; - public static final int MSG_ABS_LOOPIN_DATA = 26; - public static final int MSG_LIQUID_LEVEL_SENSOR = 27; - public static final int MSG_PASSENGERS_COUNTERS = 28; - - private int packetId; - - private void sendResponse( - Channel channel, int packetType, int index, int serviceType, int type, ByteBuf content) { - if (channel != null) { - - ByteBuf data = Unpooled.buffer(); - data.writeByte(type); - data.writeShortLE(content.readableBytes()); - data.writeBytes(content); - content.release(); - - ByteBuf record = Unpooled.buffer(); - if (packetType == PT_RESPONSE) { - record.writeShortLE(index); - record.writeByte(0); // success - } - record.writeShortLE(data.readableBytes()); - record.writeShortLE(0); - record.writeByte(0); // flags (possibly 1 << 6) - record.writeByte(serviceType); - record.writeByte(serviceType); - record.writeBytes(data); - data.release(); - int recordChecksum = Checksum.crc16(Checksum.CRC16_CCITT_FALSE, record.nioBuffer()); - - ByteBuf response = Unpooled.buffer(); - response.writeByte(1); // protocol version - response.writeByte(0); // security key id - response.writeByte(0); // flags - response.writeByte(5 + 2 + 2 + 2); // header length - response.writeByte(0); // encoding - response.writeShortLE(record.readableBytes()); - response.writeShortLE(packetId++); - response.writeByte(packetType); - response.writeByte(Checksum.crc8(Checksum.CRC8_EGTS, response.nioBuffer())); - response.writeBytes(record); - record.release(); - response.writeShortLE(recordChecksum); - - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int index = buf.getUnsignedShort(buf.readerIndex() + 5 + 2); - buf.skipBytes(buf.getUnsignedByte(buf.readerIndex() + 3)); - - List positions = new LinkedList<>(); - - while (buf.readableBytes() > 2) { - - int length = buf.readUnsignedShortLE(); - int recordIndex = buf.readUnsignedShortLE(); - int recordFlags = buf.readUnsignedByte(); - - if (BitUtil.check(recordFlags, 0)) { - buf.readUnsignedIntLE(); // object id - } - - if (BitUtil.check(recordFlags, 1)) { - buf.readUnsignedIntLE(); // event id - } - if (BitUtil.check(recordFlags, 2)) { - buf.readUnsignedIntLE(); // time - } - - int serviceType = buf.readUnsignedByte(); - buf.readUnsignedByte(); // recipient service type - - int recordEnd = buf.readerIndex() + length; - - Position position = new Position(getProtocolName()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession != null) { - position.setDeviceId(deviceSession.getDeviceId()); - } - - ByteBuf response = Unpooled.buffer(); - response.writeShortLE(recordIndex); - response.writeByte(0); // success - sendResponse(channel, PT_RESPONSE, index, serviceType, MSG_RECORD_RESPONSE, response); - - while (buf.readerIndex() < recordEnd) { - int type = buf.readUnsignedByte(); - int end = buf.readUnsignedShortLE() + buf.readerIndex(); - - if (type == MSG_TERM_IDENTITY) { - - buf.readUnsignedIntLE(); // object id - int flags = buf.readUnsignedByte(); - - if (BitUtil.check(flags, 0)) { - buf.readUnsignedShortLE(); // home dispatcher identifier - } - if (BitUtil.check(flags, 1)) { - getDeviceSession( - channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII).trim()); - } - if (BitUtil.check(flags, 2)) { - getDeviceSession( - channel, remoteAddress, buf.readSlice(16).toString(StandardCharsets.US_ASCII).trim()); - } - if (BitUtil.check(flags, 3)) { - buf.skipBytes(3); // language identifier - } - if (BitUtil.check(flags, 5)) { - buf.skipBytes(3); // network identifier - } - if (BitUtil.check(flags, 6)) { - buf.readUnsignedShortLE(); // buffer size - } - if (BitUtil.check(flags, 7)) { - getDeviceSession( - channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII).trim()); - } - - response = Unpooled.buffer(); - response.writeByte(0); // success - sendResponse(channel, PT_APPDATA, 0, serviceType, MSG_RESULT_CODE, response); - - } else if (type == MSG_POS_DATA) { - - position.setTime(new Date((buf.readUnsignedIntLE() + 1262304000) * 1000)); // since 2010-01-01 - position.setLatitude(buf.readUnsignedIntLE() * 90.0 / 0xFFFFFFFFL); - position.setLongitude(buf.readUnsignedIntLE() * 180.0 / 0xFFFFFFFFL); - - int flags = buf.readUnsignedByte(); - position.setValid(BitUtil.check(flags, 0)); - if (BitUtil.check(flags, 5)) { - position.setLatitude(-position.getLatitude()); - } - if (BitUtil.check(flags, 6)) { - position.setLongitude(-position.getLongitude()); - } - - int speed = buf.readUnsignedShortLE(); - position.setSpeed(UnitsConverter.knotsFromKph(BitUtil.to(speed, 14) * 0.1)); - position.setCourse(buf.readUnsignedByte() + (BitUtil.check(speed, 15) ? 0x100 : 0)); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedMediumLE() * 100); - position.set(Position.KEY_INPUT, buf.readUnsignedByte()); - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - - if (BitUtil.check(flags, 7)) { - position.setAltitude(buf.readMediumLE()); - } - - } else if (type == MSG_EXT_POS_DATA) { - - int flags = buf.readUnsignedByte(); - - if (BitUtil.check(flags, 0)) { - position.set(Position.KEY_VDOP, buf.readUnsignedShortLE()); - } - if (BitUtil.check(flags, 1)) { - position.set(Position.KEY_HDOP, buf.readUnsignedShortLE()); - } - if (BitUtil.check(flags, 2)) { - position.set(Position.KEY_PDOP, buf.readUnsignedShortLE()); - } - if (BitUtil.check(flags, 3)) { - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - } - - } else if (type == MSG_AD_SENSORS_DATA) { - - buf.readUnsignedByte(); // inputs flags - - position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); - - buf.readUnsignedByte(); // adc flags - - } - - buf.readerIndex(end); - } - - if (serviceType == SERVICE_TELEDATA && deviceSession != null) { - positions.add(position); - } - } - - return positions.isEmpty() ? null : positions; - } - -} diff --git a/src/org/traccar/protocol/EnforaProtocol.java b/src/org/traccar/protocol/EnforaProtocol.java deleted file mode 100644 index f78e4b377..000000000 --- a/src/org/traccar/protocol/EnforaProtocol.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class EnforaProtocol extends BaseProtocol { - - public EnforaProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, -2, 2)); - pipeline.addLast(new EnforaProtocolEncoder()); - pipeline.addLast(new EnforaProtocolDecoder(EnforaProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new EnforaProtocolEncoder()); - pipeline.addLast(new EnforaProtocolDecoder(EnforaProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/EnforaProtocolDecoder.java b/src/org/traccar/protocol/EnforaProtocolDecoder.java deleted file mode 100644 index bfa7a116b..000000000 --- a/src/org/traccar/protocol/EnforaProtocolDecoder.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BufferUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -public class EnforaProtocolDecoder extends BaseProtocolDecoder { - - public EnforaProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("GPRMC,") - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+)?,") // speed - .number("(d+.d+)?,") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .any() - .compile(); - - public static final int IMEI_LENGTH = 15; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - // Find IMEI number - int index = -1; - for (int i = buf.readerIndex(); i < buf.writerIndex() - IMEI_LENGTH; i++) { - index = i; - for (int j = i; j < i + IMEI_LENGTH; j++) { - if (!Character.isDigit((char) buf.getByte(j))) { - index = -1; - break; - } - } - if (index > 0) { - break; - } - } - if (index == -1) { - return null; - } - - String imei = buf.toString(index, IMEI_LENGTH, StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - // Find NMEA sentence - int start = BufferUtil.indexOf("GPRMC", buf); - if (start == -1) { - return null; - } - - String sentence = buf.toString(start, buf.readableBytes() - start, StandardCharsets.US_ASCII); - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/EnforaProtocolEncoder.java b/src/org/traccar/protocol/EnforaProtocolEncoder.java deleted file mode 100644 index a46e6367d..000000000 --- a/src/org/traccar/protocol/EnforaProtocolEncoder.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Jose Castellanos - * - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class EnforaProtocolEncoder extends StringProtocolEncoder { - - private ByteBuf encodeContent(String content) { - - ByteBuf buf = Unpooled.buffer(); - - buf.writeShort(content.length() + 6); - buf.writeShort(0); // index - buf.writeByte(0x04); // command type - buf.writeByte(0); // optional header - buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return encodeContent(command.getString(Command.KEY_DATA)); - case Command.TYPE_ENGINE_STOP: - return encodeContent("AT$IOGP3=1"); - case Command.TYPE_ENGINE_RESUME: - return encodeContent("AT$IOGP3=0"); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/EsealProtocol.java b/src/org/traccar/protocol/EsealProtocol.java deleted file mode 100644 index 7a27c617d..000000000 --- a/src/org/traccar/protocol/EsealProtocol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class EsealProtocol extends BaseProtocol { - - public EsealProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_ALARM_ARM, - Command.TYPE_ALARM_DISARM); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new EsealProtocolEncoder()); - pipeline.addLast(new EsealProtocolDecoder(EsealProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/EsealProtocolDecoder.java b/src/org/traccar/protocol/EsealProtocolDecoder.java deleted file mode 100644 index 7a1fd7022..000000000 --- a/src/org/traccar/protocol/EsealProtocolDecoder.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class EsealProtocolDecoder extends BaseProtocolDecoder { - - private String config; - - public EsealProtocolDecoder(Protocol protocol) { - super(protocol); - config = Context.getConfig().getString(getProtocolName() + ".config"); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("##S,") - .expression("[^,]+,") // device type - .number("(d+),") // device id - .number("d+,") // customer id - .expression("[^,]+,") // firmware version - .expression("([^,]+),") // type - .number("(d+),") // index - .number("(dddd)-(dd)-(dd),") // date - .number("(dd):(dd):(dd),") // time - .number("d+,") // interval - .expression("([AV]),") // validity - .number("(d+.d+)([NS]) ") // latitude - .number("(d+.d+)([EW]),") // longitude - .number("(d+),") // course - .number("(d+),") // speed - .expression("([^,]+),") // door - .number("(d+.d+),") // acceleration - .expression("([^,]+),") // nfc - .number("(d+.d+),") // battery - .number("(-?d+),") // rssi - .text("E##") - .compile(); - - private void sendResponse(Channel channel, String prefix, String type, String payload) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - prefix + type + "," + payload + ",E##\r\n", channel.remoteAddress())); - } - } - - private String decodeAlarm(String type) { - switch (type) { - case "Event-Door": - return Position.ALARM_DOOR; - case "Event-Shock": - return Position.ALARM_SHOCK; - case "Event-Drop": - return Position.ALARM_FALL_DOWN; - case "Event-Lock": - return Position.ALARM_LOCK; - case "Event-RC-Unlock": - return Position.ALARM_UNLOCK; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - String type = parser.next(); - String prefix = sentence.substring(0, sentence.indexOf(type)); - int index = parser.nextInt(); - - position.set(Position.KEY_INDEX, index); - position.set(Position.KEY_ALARM, decodeAlarm(type)); - - switch (type) { - case "Startup": - sendResponse(channel, prefix, type + " ACK", index + "," + config); - break; - case "Normal": - case "Button-Normal": - case "Termination": - case "Event-Door": - case "Event-Shock": - case "Event-Drop": - case "Event-Lock": - case "Event-RC-Unlock": - sendResponse(channel, prefix, type + " ACK", String.valueOf(index)); - break; - default: - break; - } - - position.setTime(parser.nextDateTime()); - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setCourse(parser.nextInt()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); - - switch (parser.next()) { - case "Open": - position.set(Position.KEY_DOOR, true); - break; - case "Close": - position.set(Position.KEY_DOOR, false); - break; - default: - break; - } - - position.set(Position.KEY_ACCELERATION, parser.nextDouble()); - position.set("nfc", parser.next()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.KEY_RSSI, parser.nextInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/EsealProtocolEncoder.java b/src/org/traccar/protocol/EsealProtocolEncoder.java deleted file mode 100644 index b9bcc5b0a..000000000 --- a/src/org/traccar/protocol/EsealProtocolEncoder.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class EsealProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatCommand( - command, "##S,eSeal,{%s},256,3.0.8,{%s},E##", Command.KEY_UNIQUE_ID, Command.KEY_DATA); - case Command.TYPE_ALARM_ARM: - return formatCommand( - command, "##S,eSeal,{%s},256,3.0.8,RC-Power Control,Power OFF,E##", Command.KEY_UNIQUE_ID); - case Command.TYPE_ALARM_DISARM: - return formatCommand( - command, "##S,eSeal,{%s},256,3.0.8,RC-Unlock,E##", Command.KEY_UNIQUE_ID); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/EskyFrameDecoder.java b/src/org/traccar/protocol/EskyFrameDecoder.java deleted file mode 100644 index da24c1273..000000000 --- a/src/org/traccar/protocol/EskyFrameDecoder.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class EskyFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - buf.readerIndex(buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 'E')); - - int endIndex = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 'E'); - if (endIndex > 0) { - return buf.readRetainedSlice(endIndex - buf.readerIndex()); - } else { - return buf.readRetainedSlice(buf.readableBytes()); // assume full frame - } - } - -} diff --git a/src/org/traccar/protocol/EskyProtocol.java b/src/org/traccar/protocol/EskyProtocol.java deleted file mode 100644 index aaa92da58..000000000 --- a/src/org/traccar/protocol/EskyProtocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class EskyProtocol extends BaseProtocol { - - public EskyProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new EskyFrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new EskyProtocolDecoder(EskyProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/EskyProtocolDecoder.java b/src/org/traccar/protocol/EskyProtocolDecoder.java deleted file mode 100644 index 641b2e28f..000000000 --- a/src/org/traccar/protocol/EskyProtocolDecoder.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class EskyProtocolDecoder extends BaseProtocolDecoder { - - public EskyProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("..;") // header - .number("d+;") // index - .number("(d+);") // imei - .text("R;") // data type - .number("(d+)[+;]") // satellites - .number("(dd)(dd)(dd)") // date - .number("(dd)(dd)(dd)[+;]") // time - .number("(-?d+.d+)[+;]") // latitude - .number("(-?d+.d+)[+;]") // longitude - .number("(d+.d+)[+;]") // speed - .number("(d+)[+;]") // course - .groupBegin() - .text("0x").number("(d+)[+;]") // input - .number("(d+)[+;]") // message type - .number("(d+)[+;]") // odometer - .groupEnd("?") - .number("(d+)") // voltage - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - position.setValid(true); - position.setTime(parser.nextDateTime()); - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromMps(parser.nextDouble())); - position.setCourse(parser.nextDouble()); - - if (parser.hasNext(3)) { - position.set(Position.KEY_INPUT, parser.nextHexInt()); - position.set(Position.KEY_EVENT, parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextInt()); - } - - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); - - return position; - } - -} diff --git a/src/org/traccar/protocol/ExtremTracProtocol.java b/src/org/traccar/protocol/ExtremTracProtocol.java deleted file mode 100644 index 692fd4e99..000000000 --- a/src/org/traccar/protocol/ExtremTracProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ExtremTracProtocol extends BaseProtocol { - - public ExtremTracProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new ExtremTracProtocolDecoder(ExtremTracProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ExtremTracProtocolDecoder.java b/src/org/traccar/protocol/ExtremTracProtocolDecoder.java deleted file mode 100644 index 9fde6f0a0..000000000 --- a/src/org/traccar/protocol/ExtremTracProtocolDecoder.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class ExtremTracProtocolDecoder extends BaseProtocolDecoder { - - public ExtremTracProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$GPRMC,") - .number("(d+),") // device id - .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/FifotrackProtocol.java b/src/org/traccar/protocol/FifotrackProtocol.java deleted file mode 100644 index 371e01e55..000000000 --- a/src/org/traccar/protocol/FifotrackProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class FifotrackProtocol extends BaseProtocol { - - public FifotrackProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new FifotrackProtocolDecoder(FifotrackProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/org/traccar/protocol/FifotrackProtocolDecoder.java deleted file mode 100644 index beaa34125..000000000 --- a/src/org/traccar/protocol/FifotrackProtocolDecoder.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.DataConverter; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class FifotrackProtocolDecoder extends BaseProtocolDecoder { - - private ByteBuf photo; - - public FifotrackProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$$") - .number("d+,") // length - .number("(d+),") // imei - .number("x+,") // index - .expression("[^,]+,") // type - .number("(d+)?,") // alarm - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("([AV]),") // validity - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(-?d+),") // altitude - .number("(d+),") // odometer - .number("d+,") // runtime - .number("(xxxx),") // status - .number("(x+)?,") // input - .number("(x+)?,") // output - .number("(d+)|") // mcc - .number("(d+)|") // mnc - .number("(x+)|") // lac - .number("(x+),") // cid - .number("([x|]+)") // adc - .expression(",([^,]+)") // rfid - .expression(",([^*]+)").optional(2) // sensors - .any() - .compile(); - - private static final Pattern PATTERN_PHOTO = new PatternBuilder() - .text("$$") - .number("d+,") // length - .number("(d+),") // imei - .any() - .number(",(d+),") // length - .expression("([^*]+)") // photo id - .text("*") - .number("xx") - .compile(); - - private static final Pattern PATTERN_PHOTO_DATA = new PatternBuilder() - .text("$$") - .number("d+,") // length - .number("(d+),") // imei - .expression("([^*]+),") // photo id - .number("(d+),") // offset - .number("(d+),") // size - .number("(x+)") // data - .text("*") - .number("xx") - .compile(); - - private void requestPhoto(Channel channel, SocketAddress socketAddress, String imei, String file) { - if (channel != null) { - String content = "D06," + file + "," + photo.writerIndex() + "," + Math.min(1024, photo.writableBytes()); - int length = 1 + imei.length() + 1 + content.length() + 5; - String response = String.format("@@%02d,%s,%s*", length, imei, content); - response += Checksum.sum(response) + "\r\n"; - channel.writeAndFlush(new NetworkMessage(response, socketAddress)); - } - } - - private Object decodeLocation( - Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_ALARM, parser.next()); - - position.setTime(parser.nextDateTime()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); - position.setCourse(parser.nextInt(0)); - position.setAltitude(parser.nextInt(0)); - - position.set(Position.KEY_ODOMETER, parser.nextLong(0)); - position.set(Position.KEY_STATUS, parser.nextHexInt(0)); - if (parser.hasNext()) { - position.set(Position.KEY_INPUT, parser.nextHexInt(0)); - } - if (parser.hasNext()) { - position.set(Position.KEY_OUTPUT, parser.nextHexInt(0)); - } - - position.setNetwork(new Network(CellTower.from( - parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); - - String[] adc = parser.next().split("\\|"); - for (int i = 0; i < adc.length; i++) { - position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(adc[i], 16)); - } - - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - if (parser.hasNext()) { - String[] sensors = parser.next().split("\\|"); - for (int i = 0; i < sensors.length; i++) { - position.set(Position.PREFIX_IO + (i + 1), sensors[i]); - } - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - int typeIndex = sentence.indexOf(',', sentence.indexOf(',', sentence.indexOf(',') + 1) + 1) + 1; - String type = sentence.substring(typeIndex, typeIndex + 3); - - if (type.equals("D05")) { - Parser parser = new Parser(PATTERN_PHOTO, sentence); - if (parser.matches()) { - String imei = parser.next(); - int length = parser.nextInt(); - String photoId = parser.next(); - photo = Unpooled.buffer(length); - requestPhoto(channel, remoteAddress, imei, photoId); - } - } else if (type.equals("D06")) { - Parser parser = new Parser(PATTERN_PHOTO_DATA, sentence); - if (parser.matches()) { - String imei = parser.next(); - String photoId = parser.next(); - parser.nextInt(); // offset - parser.nextInt(); // size - photo.writeBytes(DataConverter.parseHex(parser.next())); - requestPhoto(channel, remoteAddress, imei, photoId); - } - } else { - return decodeLocation(channel, remoteAddress, sentence); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/FlespiProtocol.java b/src/org/traccar/protocol/FlespiProtocol.java deleted file mode 100644 index 2c0729b76..000000000 --- a/src/org/traccar/protocol/FlespiProtocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class FlespiProtocol extends BaseProtocol { - - public FlespiProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE)); - pipeline.addLast(new FlespiProtocolDecoder(FlespiProtocol.this)); - } - }); - } -} diff --git a/src/org/traccar/protocol/FlespiProtocolDecoder.java b/src/org/traccar/protocol/FlespiProtocolDecoder.java deleted file mode 100644 index 86da3943e..000000000 --- a/src/org/traccar/protocol/FlespiProtocolDecoder.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpResponseStatus; -import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.model.Position; - -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonNumber; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.json.JsonValue; -import java.io.StringReader; -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder { - - public FlespiProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - JsonArray result = Json.createReader(new StringReader(request.content().toString(StandardCharsets.UTF_8))) - .readArray(); - List positions = new LinkedList<>(); - for (int i = 0; i < result.size(); i++) { - JsonObject message = result.getJsonObject(i); - JsonString ident = message.getJsonString("ident"); - if (ident == null) { - continue; - } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ident.getString()); - if (deviceSession == null) { - continue; - } - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - decodePosition(message, position); - positions.add(position); - } - - sendResponse(channel, HttpResponseStatus.OK); - return positions; - } - - private void decodePosition(JsonObject object, Position position) { - for (Map.Entry param : object.entrySet()) { - String paramName = param.getKey(); - JsonValue paramValue = param.getValue(); - int index = -1; - if (paramName.contains("#")) { - String[] parts = paramName.split("#"); - paramName = parts[0]; - index = Integer.parseInt(parts[1]); - } - if (!decodeParam(paramName, index, paramValue, position)) { - decodeUnknownParam(param.getKey(), param.getValue(), position); - } - } - if (position.getLatitude() == 0 && position.getLongitude() == 0) { - getLastLocation(position, position.getDeviceTime()); - } - } - - private boolean decodeParam(String name, int index, JsonValue value, Position position) { - switch (name) { - case "timestamp": - position.setTime(new Date(((JsonNumber) value).longValue() * 1000)); - return true; - case "position.latitude": - position.setLatitude(((JsonNumber) value).doubleValue()); - return true; - case "position.longitude": - position.setLongitude(((JsonNumber) value).doubleValue()); - return true; - case "position.speed": - position.setSpeed(((JsonNumber) value).doubleValue()); - return true; - case "position.direction": - position.setCourse(((JsonNumber) value).doubleValue()); - return true; - case "position.altitude": - position.setAltitude(((JsonNumber) value).doubleValue()); - return true; - case "position.satellites": - position.set(Position.KEY_SATELLITES, ((JsonNumber) value).intValue()); - return true; - case "position.valid": - position.setValid(value == JsonValue.TRUE); - return true; - case "position.hdop": - position.set(Position.KEY_HDOP, ((JsonNumber) value).doubleValue()); - return true; - case "position.pdop": - position.set(Position.KEY_PDOP, ((JsonNumber) value).doubleValue()); - return true; - case "din": - case "dout": - position.set(name.equals("din") ? Position.KEY_INPUT : Position.KEY_OUTPUT, - ((JsonNumber) value).intValue()); - return true; - case "gps.vehicle.mileage": - position.set(Position.KEY_ODOMETER, ((JsonNumber) value).doubleValue()); - return true; - case "external.powersource.voltage": - position.set(Position.KEY_POWER, ((JsonNumber) value).doubleValue()); - return true; - case "battery.voltage": - position.set(Position.KEY_BATTERY, ((JsonNumber) value).doubleValue()); - return true; - case "fuel.level": - case "can.fuel.level": - position.set(Position.KEY_FUEL_LEVEL, ((JsonNumber) value).doubleValue()); - return true; - case "engine.rpm": - case "can.engine.rpm": - position.set(Position.KEY_RPM, ((JsonNumber) value).doubleValue()); - return true; - case "can.engine.temperature": - position.set(Position.PREFIX_TEMP + (index > 0 ? index : 0), ((JsonNumber) value).doubleValue()); - return true; - case "engine.ignition.status": - position.set(Position.KEY_IGNITION, value == JsonValue.TRUE); - return true; - case "movement.status": - position.set(Position.KEY_MOTION, value == JsonValue.TRUE); - return true; - case "device.temperature": - position.set(Position.KEY_DEVICE_TEMP, ((JsonNumber) value).doubleValue()); - return true; - case "ibutton.code": - position.set(Position.KEY_DRIVER_UNIQUE_ID, ((JsonString) value).getString()); - return true; - case "vehicle.vin": - position.set(Position.KEY_VIN, ((JsonString) value).getString()); - return true; - case "alarm.event.trigger": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - return true; - case "towing.event.trigger": - case "towing.alarm.status": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_TOW); - } - return true; - case "geofence.event.enter": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER); - } - return true; - case "geofence.event.exit": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT); - } - return true; - case "shock.event.trigger": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_SHOCK); - } - return true; - case "overspeeding.event.trigger": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - } - return true; - case "harsh.acceleration.event.trigger": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - } - return true; - case "harsh.braking.event.trigger": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - } - return true; - case "harsh.cornering.event.trigger": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - } - return true; - case "gnss.antenna.cut.status": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); - } - return true; - case "gsm.jamming.event.trigger": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); - } - return true; - case "hood.open.status": - if (value == JsonValue.TRUE) { - position.set(Position.KEY_ALARM, Position.ALARM_BONNET); - } - return true; - default: - return false; - } - } - - private void decodeUnknownParam(String name, JsonValue value, Position position) { - if (value instanceof JsonNumber) { - if (((JsonNumber) value).isIntegral()) { - position.set(name, ((JsonNumber) value).longValue()); - } else { - position.set(name, ((JsonNumber) value).doubleValue()); - } - position.set(name, ((JsonNumber) value).doubleValue()); - } else if (value instanceof JsonString) { - position.set(name, ((JsonString) value).getString()); - } else if (value == JsonValue.TRUE || value == JsonValue.FALSE) { - position.set(name, value == JsonValue.TRUE); - } - } - -} diff --git a/src/org/traccar/protocol/FlexCommProtocol.java b/src/org/traccar/protocol/FlexCommProtocol.java deleted file mode 100644 index 9343ebeb8..000000000 --- a/src/org/traccar/protocol/FlexCommProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.FixedLengthFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class FlexCommProtocol extends BaseProtocol { - - public FlexCommProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new FixedLengthFrameDecoder(2 + 2 + 101 + 5)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new FlexCommProtocolDecoder(FlexCommProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/FlexCommProtocolDecoder.java b/src/org/traccar/protocol/FlexCommProtocolDecoder.java deleted file mode 100644 index 068c0a05c..000000000 --- a/src/org/traccar/protocol/FlexCommProtocolDecoder.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class FlexCommProtocolDecoder extends BaseProtocolDecoder { - - public FlexCommProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("7E") - .number("(dd)") // status - .number("(d{15})") // imei - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)") // time (hhmmss) - .expression("([01])") // valid - .number("(d{9})") // latitude - .number("(d{10})") // longitude - .number("(d{4})") // altitude - .number("(ddd)") // speed - .number("(ddd)") // course - .number("(dd)") // satellites view - .number("(dd)") // satellites used - .number("(dd)") // rssi - .number("(ddd)") // mcc - .number("(ddd)") // mnc - .number("(x{6})") // lac - .number("(x{6})") // cid - .expression("([01])([01])([01])") // input - .expression("([01])([01])") // output - .number("(ddd)") // fuel - .number("(d{4})") // temperature - .number("(ddd)") // battery - .number("(ddd)") // power - .any() - .compile(); - - private static double parseSignedValue(Parser parser, int decimalPoints) { - String stringValue = parser.next(); - boolean negative = stringValue.charAt(0) == '1'; - double value = Integer.parseInt(stringValue.substring(1)) * Math.pow(10, -decimalPoints); - return negative ? -value : value; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - position.set(Position.KEY_STATUS, parser.nextInt()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - position.setValid(parser.next().equals("1")); - position.setLatitude(parseSignedValue(parser, 6)); - position.setLongitude(parseSignedValue(parser, 6)); - position.setAltitude(parseSignedValue(parser, 0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_RSSI, parser.nextInt()); - - position.setNetwork(new Network(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt()))); - - for (int i = 1; i <= 3; i++) { - position.set(Position.PREFIX_IN + i, parser.nextInt()); - } - - for (int i = 1; i <= 2; i++) { - position.set(Position.PREFIX_OUT + i, parser.nextInt()); - } - - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); - position.set(Position.PREFIX_TEMP + 1, parseSignedValue(parser, 0)); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - position.set(Position.KEY_POWER, parser.nextInt() * 0.1); - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("{01}", remoteAddress)); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/FlextrackProtocol.java b/src/org/traccar/protocol/FlextrackProtocol.java deleted file mode 100644 index ddd1d58f0..000000000 --- a/src/org/traccar/protocol/FlextrackProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class FlextrackProtocol extends BaseProtocol { - - public FlextrackProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r")); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new FlextrackProtocolDecoder(FlextrackProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/FlextrackProtocolDecoder.java b/src/org/traccar/protocol/FlextrackProtocolDecoder.java deleted file mode 100644 index 9dce22ede..000000000 --- a/src/org/traccar/protocol/FlextrackProtocolDecoder.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class FlextrackProtocolDecoder extends BaseProtocolDecoder { - - public FlextrackProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_LOGON = new PatternBuilder() - .number("(-?d+),") // index - .text("LOGON,") - .number("(d+),") // node id - .number("(d+)") // iccid - .compile(); - - private static final Pattern PATTERN = new PatternBuilder() - .number("(-?d+),") // index - .text("UNITSTAT,") - .number("(dddd)(dd)(dd),") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("d+,") // node id - .number("([NS])(d+).(d+.d+),") // latitude - .number("([EW])(d+).(d+.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+),") // satellites - .number("(d+),") // battery - .number("(-?d+),") // gsm - .number("(x+),") // state - .number("(ddd)") // mcc - .number("(dd),") // mnc - .number("(-?d+),") // altitude - .number("(d+),") // hdop - .number("(x+),") // cell - .number("d+,") // gps fix time - .number("(x+),") // lac - .number("(d+)") // odometer - .compile(); - - private void sendAcknowledgement(Channel channel, SocketAddress remoteAddress, String index) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(index + ",ACK\r", remoteAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.contains("LOGON")) { - - Parser parser = new Parser(PATTERN_LOGON, sentence); - if (!parser.matches()) { - return null; - } - - sendAcknowledgement(channel, remoteAddress, parser.next()); - - String id = parser.next(); - String iccid = parser.next(); - - getDeviceSession(channel, remoteAddress, iccid, id); - - } else if (sentence.contains("UNITSTAT")) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - sendAcknowledgement(channel, remoteAddress, parser.next()); - - position.setTime(parser.nextDateTime()); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); - position.setCourse(parser.nextInt(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_BATTERY, parser.nextInt(0)); - int rssi = parser.nextInt(0); - position.set(Position.KEY_STATUS, parser.nextHexInt(0)); - - int mcc = parser.nextInt(0); - int mnc = parser.nextInt(0); - - position.setAltitude(parser.nextInt(0)); - - position.set(Position.KEY_HDOP, parser.nextInt(0) * 0.1); - - position.setNetwork(new Network(CellTower.from( - mcc, mnc, parser.nextHexInt(0), parser.nextHexInt(0), rssi))); - - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/FoxProtocol.java b/src/org/traccar/protocol/FoxProtocol.java deleted file mode 100644 index 9bac773b5..000000000 --- a/src/org/traccar/protocol/FoxProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class FoxProtocol extends BaseProtocol { - - public FoxProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new FoxProtocolDecoder(FoxProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/FoxProtocolDecoder.java b/src/org/traccar/protocol/FoxProtocolDecoder.java deleted file mode 100644 index 449f00022..000000000 --- a/src/org/traccar/protocol/FoxProtocolDecoder.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class FoxProtocolDecoder extends BaseProtocolDecoder { - - public FoxProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(d+),") // status id - .expression("([AV]),") // validity - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .expression("[^,]*,") // cell info - .number("([01]+) ") // input - .number("(d+) ") // power - .number("(d+) ") // temperature - .number("(d+) ") // rpm - .number("(d+) ") // fuel - .number("(d+) ") // adc 1 - .number("(d+) ") // adc 2 - .number("([01]+) ") // output - .number("(d+),") // odometer - .expression("(.+)") // status info - .compile(); - - private String getAttribute(String xml, String key) { - int start = xml.indexOf(key + "=\""); - if (start != -1) { - start += key.length() + 2; - int end = xml.indexOf("\"", start); - if (end != -1) { - return xml.substring(start, end); - } - } - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String xml = (String) msg; - String id = getAttribute(xml, "id"); - String data = getAttribute(xml, "data"); - - if (id != null && data != null) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN, data); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_STATUS, parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_INPUT, parser.nextBinInt(0)); - position.set(Position.KEY_POWER, parser.nextDouble(0) * 0.1); - position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); - position.set(Position.KEY_RPM, parser.nextInt(0)); - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); - position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); - position.set(Position.PREFIX_ADC + 2, parser.nextInt(0)); - position.set(Position.KEY_OUTPUT, parser.nextBinInt(0)); - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - - position.set("statusData", parser.next()); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/FreedomProtocol.java b/src/org/traccar/protocol/FreedomProtocol.java deleted file mode 100644 index bc6b92d5f..000000000 --- a/src/org/traccar/protocol/FreedomProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class FreedomProtocol extends BaseProtocol { - - public FreedomProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new FreedomProtocolDecoder(FreedomProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/FreedomProtocolDecoder.java b/src/org/traccar/protocol/FreedomProtocolDecoder.java deleted file mode 100644 index 1d2dd3133..000000000 --- a/src/org/traccar/protocol/FreedomProtocolDecoder.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class FreedomProtocolDecoder extends BaseProtocolDecoder { - - public FreedomProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("IMEI,") - .number("(d+),") // imei - .number("(dddd)/(dd)/(dd), ") // date (yyyy/dd/mm) - .number("(dd):(dd):(dd), ") // time (hh:mm:ss) - .expression("([NS]), ") - .number("Lat:(dd)(d+.d+), ") // latitude - .expression("([EW]), ") - .number("Lon:(ddd)(d+.d+), ") // longitude - .text("Spd:").number("(d+.d+)") // speed - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(true); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - - position.setSpeed(parser.nextDouble(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/FreematicsProtocol.java b/src/org/traccar/protocol/FreematicsProtocol.java deleted file mode 100644 index 999b075a1..000000000 --- a/src/org/traccar/protocol/FreematicsProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class FreematicsProtocol extends BaseProtocol { - - public FreematicsProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new FreematicsProtocolDecoder(FreematicsProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/FreematicsProtocolDecoder.java b/src/org/traccar/protocol/FreematicsProtocolDecoder.java deleted file mode 100644 index ba47699c3..000000000 --- a/src/org/traccar/protocol/FreematicsProtocolDecoder.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class FreematicsProtocolDecoder extends BaseProtocolDecoder { - - public FreematicsProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private Object decodeEvent( - Channel channel, SocketAddress remoteAddress, String sentence) { - - DeviceSession deviceSession = null; - String event = null; - String time = null; - - for (String pair : sentence.split(",")) { - String[] data = pair.split("="); - String key = data[0]; - String value = data[1]; - switch (key) { - case "ID": - case "VIN": - if (deviceSession == null) { - deviceSession = getDeviceSession(channel, remoteAddress, value); - } - break; - case "EV": - event = value; - break; - case "TS": - time = value; - break; - default: - break; - } - } - - if (channel != null && deviceSession != null && event != null && time != null) { - String message = String.format("1#EV=%s,RX=1,TS=%s", event, time); - message += '*' + Checksum.sum(message); - channel.writeAndFlush(new NetworkMessage(message, remoteAddress)); - } - - return null; - } - - private Object decodePosition( - Channel channel, SocketAddress remoteAddress, String sentence) throws Exception { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - Position position = null; - DateBuilder dateBuilder = null; - - for (String pair : sentence.split(",")) { - String[] data = pair.split("[=:]"); - int key = Integer.parseInt(data[0], 16); - String value = data[1]; - switch (key) { - case 0x0: - if (position != null) { - position.setTime(dateBuilder.getDate()); - positions.add(position); - } - position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); - dateBuilder = new DateBuilder(new Date()); - break; - case 0x11: - value = ("000000" + value).substring(value.length()); - dateBuilder.setDateReverse( - Integer.parseInt(value.substring(0, 2)), - Integer.parseInt(value.substring(2, 4)), - Integer.parseInt(value.substring(4))); - break; - case 0x10: - value = ("00000000" + value).substring(value.length()); - dateBuilder.setTime( - Integer.parseInt(value.substring(0, 2)), - Integer.parseInt(value.substring(2, 4)), - Integer.parseInt(value.substring(4, 6)), - Integer.parseInt(value.substring(6)) * 10); - break; - case 0xA: - position.setLatitude(Double.parseDouble(value)); - break; - case 0xB: - position.setLongitude(Double.parseDouble(value)); - break; - case 0xC: - position.setAltitude(Double.parseDouble(value)); - break; - case 0xD: - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(value))); - break; - case 0xE: - position.setCourse(Integer.parseInt(value)); - break; - case 0xF: - position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); - break; - case 0x20: - position.set(Position.KEY_ACCELERATION, value); - break; - case 0x24: - position.set(Position.KEY_BATTERY, Integer.parseInt(value) * 0.01); - break; - case 0x81: - position.set(Position.KEY_RSSI, Integer.parseInt(value)); - break; - case 0x82: - position.set(Position.KEY_DEVICE_TEMP, Integer.parseInt(value) * 0.1); - break; - default: - position.set(data[0], value); - break; - } - } - - if (position != null) { - position.setTime(dateBuilder.getDate()); - positions.add(position); - } - - return positions; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - int startIndex = sentence.indexOf('#'); - int endIndex = sentence.indexOf('*'); - - if (startIndex > 0 && endIndex > 0) { - sentence = sentence.substring(startIndex + 1, endIndex); - - if (sentence.startsWith("EV")) { - return decodeEvent(channel, remoteAddress, sentence); - } else { - return decodePosition(channel, remoteAddress, sentence); - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/GalileoFrameDecoder.java b/src/org/traccar/protocol/GalileoFrameDecoder.java deleted file mode 100644 index c23d26c83..000000000 --- a/src/org/traccar/protocol/GalileoFrameDecoder.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class GalileoFrameDecoder extends BaseFrameDecoder { - - private static final int MESSAGE_MINIMUM_LENGTH = 5; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { - return null; - } - - int length = buf.getUnsignedShortLE(buf.readerIndex() + 1) & 0x7fff; - if (buf.readableBytes() >= (length + MESSAGE_MINIMUM_LENGTH)) { - return buf.readRetainedSlice(length + MESSAGE_MINIMUM_LENGTH); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/GalileoProtocol.java b/src/org/traccar/protocol/GalileoProtocol.java deleted file mode 100644 index 9b7fe1a4b..000000000 --- a/src/org/traccar/protocol/GalileoProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class GalileoProtocol extends BaseProtocol { - - public GalileoProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_OUTPUT_CONTROL); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new GalileoFrameDecoder()); - pipeline.addLast(new GalileoProtocolEncoder()); - pipeline.addLast(new GalileoProtocolDecoder(GalileoProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GalileoProtocolDecoder.java b/src/org/traccar/protocol/GalileoProtocolDecoder.java deleted file mode 100644 index 01c55a9ae..000000000 --- a/src/org/traccar/protocol/GalileoProtocolDecoder.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.UnitsConverter; -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.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class GalileoProtocolDecoder extends BaseProtocolDecoder { - - public GalileoProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private ByteBuf photo; - - private static final Map TAG_LENGTH_MAP = new HashMap<>(); - - static { - int[] l1 = { - 0x01, 0x02, 0x35, 0x43, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd5, 0x88, 0x8a, 0x8b, 0x8c, - 0xa0, 0xaf, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, - 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae - }; - int[] l2 = { - 0x04, 0x10, 0x34, 0x40, 0x41, 0x42, 0x45, 0x46, - 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60, 0x61, - 0x62, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, - 0x77, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xd6, 0xd7, 0xd8, 0xd9, 0xda - }; - int[] l3 = { - 0x63, 0x64, 0x6f, 0x5d, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e - }; - int[] l4 = { - 0x20, 0x33, 0x44, 0x90, 0xc0, 0xc2, 0xc3, 0xd3, - 0xd4, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xf0, 0xf9, - 0x5a, 0x47, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, - 0xf7, 0xf8, 0xe2, 0xe9 - }; - for (int i : l1) { - TAG_LENGTH_MAP.put(i, 1); - } - for (int i : l2) { - TAG_LENGTH_MAP.put(i, 2); - } - for (int i : l3) { - TAG_LENGTH_MAP.put(i, 3); - } - for (int i : l4) { - TAG_LENGTH_MAP.put(i, 4); - } - TAG_LENGTH_MAP.put(0x5b, 7); // variable length - TAG_LENGTH_MAP.put(0x5c, 68); - } - - private static int getTagLength(int tag) { - Integer length = TAG_LENGTH_MAP.get(tag); - if (length == null) { - throw new IllegalArgumentException("Unknown tag: " + tag); - } - return length; - } - - private void sendReply(Channel channel, int header, int checksum) { - if (channel != null) { - ByteBuf reply = Unpooled.buffer(3); - reply.writeByte(header); - reply.writeShortLE((short) checksum); - channel.writeAndFlush(new NetworkMessage(reply, channel.remoteAddress())); - } - } - - private void decodeTag(Position position, ByteBuf buf, int tag) { - if (tag >= 0x50 && tag <= 0x57) { - position.set(Position.PREFIX_ADC + (tag - 0x50), buf.readUnsignedShortLE()); - } else if (tag >= 0x60 && tag <= 0x62) { - position.set("fuel" + (tag - 0x60), buf.readUnsignedShortLE()); - } else if (tag >= 0xa0 && tag <= 0xaf) { - position.set("can8BitR" + (tag - 0xa0 + 15), buf.readUnsignedByte()); - } else if (tag >= 0xb0 && tag <= 0xb9) { - position.set("can16BitR" + (tag - 0xb0 + 5), buf.readUnsignedShortLE()); - } else if (tag >= 0xc4 && tag <= 0xd2) { - position.set("can8BitR" + (tag - 0xc4), buf.readUnsignedByte()); - } else if (tag >= 0xd6 && tag <= 0xda) { - position.set("can16BitR" + (tag - 0xd6), buf.readUnsignedShortLE()); - } else if (tag >= 0xdb && tag <= 0xdf) { - position.set("can32BitR" + (tag - 0xdb), buf.readUnsignedIntLE()); - } else if (tag >= 0xe2 && tag <= 0xe9) { - position.set("userData" + (tag - 0xe2), buf.readUnsignedIntLE()); - } else if (tag >= 0xf0 && tag <= 0xf9) { - position.set("can32BitR" + (tag - 0xf0 + 5), buf.readUnsignedIntLE()); - } else { - decodeTagOther(position, buf, tag); - } - } - - private void decodeTagOther(Position position, ByteBuf buf, int tag) { - switch (tag) { - case 0x01: - position.set(Position.KEY_VERSION_HW, buf.readUnsignedByte()); - break; - case 0x02: - position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); - break; - case 0x04: - position.set("deviceId", buf.readUnsignedShortLE()); - break; - case 0x10: - position.set(Position.KEY_INDEX, buf.readUnsignedShortLE()); - break; - case 0x20: - position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); - break; - case 0x33: - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE() * 0.1)); - position.setCourse(buf.readUnsignedShortLE() * 0.1); - break; - case 0x34: - position.setAltitude(buf.readShortLE()); - break; - case 0x35: - position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); - break; - case 0x40: - position.set(Position.KEY_STATUS, buf.readUnsignedShortLE()); - break; - case 0x41: - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() / 1000.0); - break; - case 0x42: - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() / 1000.0); - break; - case 0x43: - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - break; - case 0x44: - position.set(Position.KEY_ACCELERATION, buf.readUnsignedIntLE()); - break; - case 0x45: - position.set(Position.KEY_OUTPUT, buf.readUnsignedShortLE()); - break; - case 0x46: - position.set(Position.KEY_INPUT, buf.readUnsignedShortLE()); - break; - case 0x48: - position.set("statusExtended", buf.readUnsignedShortLE()); - break; - case 0x58: - position.set("rs2320", buf.readUnsignedShortLE()); - break; - case 0x59: - position.set("rs2321", buf.readUnsignedShortLE()); - break; - case 0x90: - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedIntLE())); - break; - case 0xc0: - position.set("fuelTotal", buf.readUnsignedIntLE() * 0.5); - break; - case 0xc1: - position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4); - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte() - 40); - position.set(Position.KEY_RPM, buf.readUnsignedShortLE() * 0.125); - break; - case 0xc2: - position.set("canB0", buf.readUnsignedIntLE()); - break; - case 0xc3: - position.set("canB1", buf.readUnsignedIntLE()); - break; - case 0xd4: - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - break; - case 0xe0: - position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); - break; - case 0xe1: - position.set(Position.KEY_RESULT, - buf.readSlice(buf.readUnsignedByte()).toString(StandardCharsets.US_ASCII)); - break; - case 0xea: - position.set("userDataArray", ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte()))); - position.set("userDataArray", ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte()))); - break; - default: - buf.skipBytes(getTagLength(tag)); - break; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int header = buf.readUnsignedByte(); - if (header == 0x01) { - return decodePositions(channel, remoteAddress, buf); - } else if (header == 0x07) { - return decodePhoto(channel, remoteAddress, buf); - } - - return null; - } - - private Object decodePositions( - Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { - - int length = (buf.readUnsignedShortLE() & 0x7fff) + 3; - - List positions = new LinkedList<>(); - Set tags = new HashSet<>(); - boolean hasLocation = false; - - DeviceSession deviceSession = null; - Position position = new Position(getProtocolName()); - - while (buf.readerIndex() < length) { - - int tag = buf.readUnsignedByte(); - if (tags.contains(tag)) { - if (hasLocation && position.getFixTime() != null) { - positions.add(position); - } - tags.clear(); - hasLocation = false; - position = new Position(getProtocolName()); // new position starts - } - tags.add(tag); - - if (tag == 0x03) { - deviceSession = getDeviceSession( - channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII)); - } else if (tag == 0x30) { - hasLocation = true; - position.setValid((buf.readUnsignedByte() & 0xf0) == 0x00); - position.setLatitude(buf.readIntLE() / 1000000.0); - position.setLongitude(buf.readIntLE() / 1000000.0); - } else { - decodeTag(position, buf, tag); - } - - } - - if (deviceSession == null) { - deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - } - - if (hasLocation && position.getFixTime() != null) { - positions.add(position); - } else if (position.getAttributes().containsKey(Position.KEY_RESULT)) { - position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, null); - positions.add(position); - } - - sendReply(channel, 0x02, buf.readUnsignedShortLE()); - - for (Position p : positions) { - p.setDeviceId(deviceSession.getDeviceId()); - } - - return positions.isEmpty() ? null : positions; - } - - private Object decodePhoto( - Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { - - int length = buf.readUnsignedShortLE(); - - Position position = null; - - if (length > 1) { - - if (photo == null) { - photo = Unpooled.buffer(); - } - - buf.readUnsignedByte(); // part number - photo.writeBytes(buf, length - 1); - - } else { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId(); - - position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg")); - photo.release(); - photo = null; - - } - - sendReply(channel, 0x07, buf.readUnsignedShortLE()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/GalileoProtocolEncoder.java b/src/org/traccar/protocol/GalileoProtocolEncoder.java deleted file mode 100644 index 3b2145e74..000000000 --- a/src/org/traccar/protocol/GalileoProtocolEncoder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class GalileoProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeText(String uniqueId, String text) { - - ByteBuf buf = Unpooled.buffer(256); - - buf.writeByte(0x01); - buf.writeShortLE(uniqueId.length() + text.length() + 11); - - buf.writeByte(0x03); // imei tag - buf.writeBytes(uniqueId.getBytes(StandardCharsets.US_ASCII)); - - buf.writeByte(0x04); // device id tag - buf.writeShortLE(0); // not needed if imei provided - - buf.writeByte(0xE0); // index tag - buf.writeIntLE(0); // index - - buf.writeByte(0xE1); // command text tag - buf.writeByte(text.length()); - buf.writeBytes(text.getBytes(StandardCharsets.US_ASCII)); - - buf.writeShortLE(Checksum.crc16(Checksum.CRC16_MODBUS, buf.nioBuffer(0, buf.writerIndex()))); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return encodeText(getUniqueId(command.getDeviceId()), command.getString(Command.KEY_DATA)); - case Command.TYPE_OUTPUT_CONTROL: - return encodeText(getUniqueId(command.getDeviceId()), - "Out " + command.getInteger(Command.KEY_INDEX) + "," + command.getString(Command.KEY_DATA)); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/GatorProtocol.java b/src/org/traccar/protocol/GatorProtocol.java deleted file mode 100644 index ca81caefb..000000000 --- a/src/org/traccar/protocol/GatorProtocol.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GatorProtocol extends BaseProtocol { - - public GatorProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2)); - pipeline.addLast(new GatorProtocolDecoder(GatorProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new GatorProtocolDecoder(GatorProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GatorProtocolDecoder.java b/src/org/traccar/protocol/GatorProtocolDecoder.java deleted file mode 100644 index 31500bae6..000000000 --- a/src/org/traccar/protocol/GatorProtocolDecoder.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BcdUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class GatorProtocolDecoder extends BaseProtocolDecoder { - - public GatorProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_HEARTBEAT = 0x21; - public static final int MSG_POSITION_DATA = 0x80; - public static final int MSG_ROLLCALL_RESPONSE = 0x81; - public static final int MSG_ALARM_DATA = 0x82; - public static final int MSG_TERMINAL_STATUS = 0x83; - public static final int MSG_MESSAGE = 0x84; - public static final int MSG_TERMINAL_ANSWER = 0x85; - public static final int MSG_BLIND_AREA = 0x8E; - public static final int MSG_PICTURE_FRAME = 0x54; - public static final int MSG_CAMERA_RESPONSE = 0x56; - public static final int MSG_PICTURE_DATA = 0x57; - - public static String decodeId(int b1, int b2, int b3, int b4) { - - int d1 = 30 + ((b1 >> 7) << 3) + ((b2 >> 7) << 2) + ((b3 >> 7) << 1) + (b4 >> 7); - int d2 = b1 & 0x7f; - int d3 = b2 & 0x7f; - int d4 = b3 & 0x7f; - int d5 = b4 & 0x7f; - - return String.format("%02d%02d%02d%02d%02d", d1, d2, d3, d4, d5); - } - - private void sendResponse(Channel channel, SocketAddress remoteAddress, byte calibration) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(0x24); response.writeByte(0x24); // header - response.writeByte(MSG_HEARTBEAT); // size - response.writeShort(5); - response.writeByte(calibration); - response.writeByte(0); // main order - response.writeByte(0); // slave order - response.writeByte(1); // calibration - response.writeByte(0x0D); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - int type = buf.readUnsignedByte(); - buf.readUnsignedShort(); // length - - String id = decodeId( - buf.readUnsignedByte(), buf.readUnsignedByte(), - buf.readUnsignedByte(), buf.readUnsignedByte()); - - sendResponse(channel, remoteAddress, buf.getByte(buf.writerIndex() - 2)); - - if (type == MSG_POSITION_DATA || type == MSG_ROLLCALL_RESPONSE - || type == MSG_ALARM_DATA || type == MSG_BLIND_AREA) { - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, "1" + id, id); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setYear(BcdUtil.readInteger(buf, 2)) - .setMonth(BcdUtil.readInteger(buf, 2)) - .setDay(BcdUtil.readInteger(buf, 2)) - .setHour(BcdUtil.readInteger(buf, 2)) - .setMinute(BcdUtil.readInteger(buf, 2)) - .setSecond(BcdUtil.readInteger(buf, 2)); - position.setTime(dateBuilder.getDate()); - - position.setLatitude(BcdUtil.readCoordinate(buf)); - position.setLongitude(BcdUtil.readCoordinate(buf)); - position.setSpeed(UnitsConverter.knotsFromKph(BcdUtil.readInteger(buf, 4))); - position.setCourse(BcdUtil.readInteger(buf, 4)); - - int flags = buf.readUnsignedByte(); - position.setValid((flags & 0x80) != 0); - position.set(Position.KEY_SATELLITES, flags & 0x0f); - - position.set(Position.KEY_STATUS, buf.readUnsignedByte()); - position.set("key", buf.readUnsignedByte()); - position.set("oil", buf.readUnsignedShort() / 10.0); - position.set(Position.KEY_POWER, buf.readUnsignedByte() + buf.readUnsignedByte() * 0.01); - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/GenxProtocol.java b/src/org/traccar/protocol/GenxProtocol.java deleted file mode 100644 index c87ba946a..000000000 --- a/src/org/traccar/protocol/GenxProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GenxProtocol extends BaseProtocol { - - public GenxProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new GenxProtocolDecoder(GenxProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GenxProtocolDecoder.java b/src/org/traccar/protocol/GenxProtocolDecoder.java deleted file mode 100644 index 2ae9de7a0..000000000 --- a/src/org/traccar/protocol/GenxProtocolDecoder.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.text.SimpleDateFormat; - -public class GenxProtocolDecoder extends BaseProtocolDecoder { - - private int[] reportColumns; - - public GenxProtocolDecoder(Protocol protocol) { - super(protocol); - setReportColumns(Context.getConfig().getString(getProtocolName() + ".reportColumns", "1,2,3,4")); - } - - public void setReportColumns(String format) { - String[] columns = format.split(","); - reportColumns = new int[columns.length]; - for (int i = 0; i < columns.length; i++) { - reportColumns[i] = Integer.parseInt(columns[i]); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String[] values = ((String) msg).split(","); - - Position position = new Position(getProtocolName()); - position.setValid(true); - - for (int i = 0; i < Math.min(values.length, reportColumns.length); i++) { - switch (reportColumns[i]) { - case 1: - case 28: - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[i]); - if (deviceSession != null) { - position.setDeviceId(deviceSession.getDeviceId()); - } - break; - case 2: - position.setTime(new SimpleDateFormat("MM/dd/yy HH:mm:ss").parse(values[i])); - break; - case 3: - position.setLatitude(Double.parseDouble(values[i])); - break; - case 4: - position.setLongitude(Double.parseDouble(values[i])); - break; - case 11: - position.set(Position.KEY_IGNITION, values[i].equals("ON")); - break; - case 13: - position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(values[i]))); - break; - case 17: - position.setCourse(Integer.parseInt(values[i])); - break; - case 23: - position.set(Position.KEY_ODOMETER, Double.parseDouble(values[i]) * 1000); - break; - case 27: - position.setAltitude(UnitsConverter.metersFromFeet(Integer.parseInt(values[i]))); - break; - case 46: - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[i])); - break; - default: - break; - } - } - - return position.getDeviceId() != 0 ? position : null; - } - -} diff --git a/src/org/traccar/protocol/Gl100Protocol.java b/src/org/traccar/protocol/Gl100Protocol.java deleted file mode 100644 index 063e606db..000000000 --- a/src/org/traccar/protocol/Gl100Protocol.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Gl100Protocol extends BaseProtocol { - - public Gl100Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\0')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Gl100ProtocolDecoder(Gl100Protocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Gl100ProtocolDecoder(Gl100Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Gl100ProtocolDecoder.java b/src/org/traccar/protocol/Gl100ProtocolDecoder.java deleted file mode 100644 index ae0383e5c..000000000 --- a/src/org/traccar/protocol/Gl100ProtocolDecoder.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Gl100ProtocolDecoder extends BaseProtocolDecoder { - - public Gl100ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("+RESP:") - .expression("GT...,") - .number("(d{15}),") // imei - .groupBegin() - .number("d+,") // number - .number("d,") // reserved / geofence id - .number("d+") // reserved / geofence alert // battery - .or() - .number("[^,]*") // calling number - .groupEnd(",") - .expression("([01]),") // gps fix - .number("(d+.d),") // speed - .number("(d+),") // course - .number("(-?d+.d),") // altitude - .number("d*,") // gps accuracy - .number("(-?d+.d+),") // longitude - .number("(-?d+.d+),") // latitude - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.contains("AT+GTHBD=") && channel != null) { - String response = "+RESP:GTHBD,GPRS ACTIVE,"; - response += sentence.substring(9, sentence.lastIndexOf(',')); - response += '\0'; - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); // heartbeat response - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.nextInt(0) == 0); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setLatitude(parser.nextDouble(0)); - - position.setTime(parser.nextDateTime()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/Gl200BinaryProtocolDecoder.java b/src/org/traccar/protocol/Gl200BinaryProtocolDecoder.java deleted file mode 100644 index c3339bea5..000000000 --- a/src/org/traccar/protocol/Gl200BinaryProtocolDecoder.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitBuffer; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class Gl200BinaryProtocolDecoder extends BaseProtocolDecoder { - - public Gl200BinaryProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private Date decodeTime(ByteBuf buf) { - DateBuilder dateBuilder = new DateBuilder() - .setDate(buf.readUnsignedShort(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - return dateBuilder.getDate(); - } - - public static final int MSG_RSP_LCB = 3; - public static final int MSG_RSP_GEO = 8; - public static final int MSG_RSP_COMPRESSED = 100; - - private List decodeLocation(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - List positions = new LinkedList<>(); - - int type = buf.readUnsignedByte(); - - buf.readUnsignedInt(); // mask - buf.readUnsignedShort(); // length - buf.readUnsignedByte(); // device type - buf.readUnsignedShort(); // protocol version - buf.readUnsignedShort(); // firmware version - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.format("%015d", buf.readLong())); - if (deviceSession == null) { - return null; - } - - int battery = buf.readUnsignedByte(); - int power = buf.readUnsignedShort(); - - if (type == MSG_RSP_GEO) { - buf.readUnsignedByte(); // reserved - buf.readUnsignedByte(); // reserved - } - - buf.readUnsignedByte(); // motion status - int satellites = buf.readUnsignedByte(); - - if (type != MSG_RSP_COMPRESSED) { - buf.readUnsignedByte(); // index - } - - if (type == MSG_RSP_LCB) { - buf.readUnsignedByte(); // phone length - for (int b = buf.readUnsignedByte();; b = buf.readUnsignedByte()) { - if ((b & 0xf) == 0xf || (b & 0xf0) == 0xf0) { - break; - } - } - } - - if (type == MSG_RSP_COMPRESSED) { - - int count = buf.readUnsignedShort(); - - BitBuffer bits; - int speed = 0; - int heading = 0; - int latitude = 0; - int longitude = 0; - long time = 0; - - for (int i = 0; i < count; i++) { - - if (time > 0) { - time += 1; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - switch (BitUtil.from(buf.getUnsignedByte(buf.readerIndex()), 8 - 2)) { - case 1: - bits = new BitBuffer(buf.readSlice(3)); - bits.readUnsigned(2); // point attribute - bits.readUnsigned(1); // fix type - speed = bits.readUnsigned(12); - heading = bits.readUnsigned(9); - longitude = buf.readInt(); - latitude = buf.readInt(); - if (time == 0) { - time = buf.readUnsignedInt(); - } - break; - case 2: - bits = new BitBuffer(buf.readSlice(5)); - bits.readUnsigned(2); // point attribute - bits.readUnsigned(1); // fix type - speed += bits.readSigned(7); - heading += bits.readSigned(7); - longitude += bits.readSigned(12); - latitude += bits.readSigned(11); - break; - default: - buf.readUnsignedByte(); // invalid or same - continue; - } - - position.setValid(true); - position.setTime(new Date(time * 1000)); - position.setSpeed(UnitsConverter.knotsFromKph(speed * 0.1)); - position.setCourse(heading); - position.setLongitude(longitude * 0.000001); - position.setLatitude(latitude * 0.000001); - - positions.add(position); - - } - - } else { - - int count = buf.readUnsignedByte(); - - for (int i = 0; i < count; i++) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_BATTERY_LEVEL, battery); - position.set(Position.KEY_POWER, power); - position.set(Position.KEY_SATELLITES, satellites); - - int hdop = buf.readUnsignedByte(); - position.setValid(hdop > 0); - position.set(Position.KEY_HDOP, hdop); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedMedium() * 0.1)); - position.setCourse(buf.readUnsignedShort()); - position.setAltitude(buf.readShort()); - position.setLongitude(buf.readInt() * 0.000001); - position.setLatitude(buf.readInt() * 0.000001); - - position.setTime(decodeTime(buf)); - - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readUnsignedShort(), buf.readUnsignedShort()))); - - buf.readUnsignedByte(); // reserved - - positions.add(position); - - } - - } - - return positions; - } - - public static final int MSG_EVT_BPL = 6; - public static final int MSG_EVT_VGN = 45; - public static final int MSG_EVT_VGF = 46; - public static final int MSG_EVT_UPD = 15; - public static final int MSG_EVT_IDF = 17; - public static final int MSG_EVT_GSS = 21; - public static final int MSG_EVT_GES = 26; - public static final int MSG_EVT_GPJ = 31; - public static final int MSG_EVT_RMD = 35; - public static final int MSG_EVT_JDS = 33; - public static final int MSG_EVT_CRA = 23; - public static final int MSG_EVT_UPC = 34; - - private Position decodeEvent(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - Position position = new Position(getProtocolName()); - - int type = buf.readUnsignedByte(); - - buf.readUnsignedInt(); // mask - buf.readUnsignedShort(); // length - buf.readUnsignedByte(); // device type - buf.readUnsignedShort(); // protocol version - - position.set(Position.KEY_VERSION_FW, String.valueOf(buf.readUnsignedShort())); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.format("%015d", buf.readLong())); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); - position.set(Position.KEY_POWER, buf.readUnsignedShort()); - - buf.readUnsignedByte(); // motion status - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - switch (type) { - case MSG_EVT_BPL: - buf.readUnsignedShort(); // backup battery voltage - break; - case MSG_EVT_VGN: - case MSG_EVT_VGF: - buf.readUnsignedShort(); // reserved - buf.readUnsignedByte(); // report type - buf.readUnsignedInt(); // ignition duration - break; - case MSG_EVT_UPD: - buf.readUnsignedShort(); // code - buf.readUnsignedByte(); // retry - break; - case MSG_EVT_IDF: - buf.readUnsignedInt(); // idling duration - break; - case MSG_EVT_GSS: - buf.readUnsignedByte(); // gps signal status - buf.readUnsignedInt(); // reserved - break; - case MSG_EVT_GES: - buf.readUnsignedShort(); // trigger geo id - buf.readUnsignedByte(); // trigger geo enable - buf.readUnsignedByte(); // trigger mode - buf.readUnsignedInt(); // radius - buf.readUnsignedInt(); // check interval - break; - case MSG_EVT_GPJ: - buf.readUnsignedByte(); // cw jamming value - buf.readUnsignedByte(); // gps jamming state - break; - case MSG_EVT_RMD: - buf.readUnsignedByte(); // roaming state - break; - case MSG_EVT_JDS: - buf.readUnsignedByte(); // jamming state - break; - case MSG_EVT_CRA: - buf.readUnsignedByte(); // crash counter - break; - case MSG_EVT_UPC: - buf.readUnsignedByte(); // command id - buf.readUnsignedShort(); // result - break; - default: - break; - } - - buf.readUnsignedByte(); // count - - int hdop = buf.readUnsignedByte(); - position.setValid(hdop > 0); - position.set(Position.KEY_HDOP, hdop); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedMedium() * 0.1)); - position.setCourse(buf.readUnsignedShort()); - position.setAltitude(buf.readShort()); - position.setLongitude(buf.readInt() * 0.000001); - position.setLatitude(buf.readInt() * 0.000001); - - position.setTime(decodeTime(buf)); - - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readUnsignedShort(), buf.readUnsignedShort()))); - - buf.readUnsignedByte(); // reserved - - return position; - } - - public static final int MSG_INF_GPS = 2; - public static final int MSG_INF_CID = 4; - public static final int MSG_INF_CSQ = 5; - public static final int MSG_INF_VER = 6; - public static final int MSG_INF_BAT = 7; - public static final int MSG_INF_TMZ = 9; - public static final int MSG_INF_GIR = 10; - - private Position decodeInformation(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - Position position = new Position(getProtocolName()); - - int type = buf.readUnsignedByte(); - - buf.readUnsignedInt(); // mask - buf.readUnsignedShort(); // length - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.format("%015d", buf.readLong())); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedByte(); // device type - buf.readUnsignedShort(); // protocol version - - position.set(Position.KEY_VERSION_FW, String.valueOf(buf.readUnsignedShort())); - - if (type == MSG_INF_VER) { - buf.readUnsignedShort(); // hardware version - buf.readUnsignedShort(); // mcu version - buf.readUnsignedShort(); // reserved - } - - buf.readUnsignedByte(); // motion status - buf.readUnsignedByte(); // reserved - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - buf.readUnsignedByte(); // mode - buf.skipBytes(7); // last fix time - buf.readUnsignedByte(); // reserved - buf.readUnsignedByte(); - buf.readUnsignedShort(); // response report mask - buf.readUnsignedShort(); // ign interval - buf.readUnsignedShort(); // igf interval - buf.readUnsignedInt(); // reserved - buf.readUnsignedByte(); // reserved - - if (type == MSG_INF_BAT) { - position.set(Position.KEY_CHARGE, buf.readUnsignedByte() != 0); - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); - } - - buf.skipBytes(10); // iccid - - if (type == MSG_INF_CSQ) { - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - buf.readUnsignedByte(); - } - - buf.readUnsignedByte(); // time zone flags - buf.readUnsignedShort(); // time zone offset - - if (type == MSG_INF_GIR) { - buf.readUnsignedByte(); // gir trigger - buf.readUnsignedByte(); // cell number - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readUnsignedShort(), buf.readUnsignedShort()))); - buf.readUnsignedByte(); // ta - buf.readUnsignedByte(); // rx level - } - - getLastLocation(position, decodeTime(buf)); - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - switch (buf.readSlice(4).toString(StandardCharsets.US_ASCII)) { - case "+RSP": - return decodeLocation(channel, remoteAddress, buf); - case "+INF": - return decodeInformation(channel, remoteAddress, buf); - case "+EVT": - return decodeEvent(channel, remoteAddress, buf); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Gl200FrameDecoder.java b/src/org/traccar/protocol/Gl200FrameDecoder.java deleted file mode 100644 index c192cc28d..000000000 --- a/src/org/traccar/protocol/Gl200FrameDecoder.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseFrameDecoder; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -public class Gl200FrameDecoder extends BaseFrameDecoder { - - private static final int MINIMUM_LENGTH = 11; - - private static final Set BINARY_HEADERS = new HashSet<>( - Arrays.asList("+RSP", "+BSP", "+EVT", "+BVT", "+INF", "+BNF", "+HBD", "+CRD", "+BRD")); - - public static boolean isBinary(ByteBuf buf) { - String header = buf.toString(buf.readerIndex(), 4, StandardCharsets.US_ASCII); - if (header.equals("+ACK")) { - return buf.getByte(buf.readerIndex() + header.length()) != (byte) ':'; - } else { - return BINARY_HEADERS.contains(header); - } - } - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < MINIMUM_LENGTH) { - return null; - } - - if (isBinary(buf)) { - - int length; - switch (buf.toString(buf.readerIndex(), 4, StandardCharsets.US_ASCII)) { - case "+ACK": - length = buf.getUnsignedByte(buf.readerIndex() + 6); - break; - case "+INF": - case "+BNF": - length = buf.getUnsignedShort(buf.readerIndex() + 7); - break; - case "+HBD": - length = buf.getUnsignedByte(buf.readerIndex() + 5); - break; - case "+CRD": - case "+BRD": - length = buf.getUnsignedShort(buf.readerIndex() + 6); - break; - default: - length = buf.getUnsignedShort(buf.readerIndex() + 9); - break; - } - - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - } else { - - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '$'); - if (endIndex < 0) { - endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0); - } - if (endIndex > 0) { - ByteBuf frame = buf.readRetainedSlice(endIndex - buf.readerIndex()); - buf.readByte(); // delimiter - return frame; - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Gl200Protocol.java b/src/org/traccar/protocol/Gl200Protocol.java deleted file mode 100644 index c5343dae0..000000000 --- a/src/org/traccar/protocol/Gl200Protocol.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -import io.netty.handler.codec.string.StringEncoder; - -public class Gl200Protocol extends BaseProtocol { - - public Gl200Protocol() { - setSupportedDataCommands( - Command.TYPE_POSITION_SINGLE, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_IDENTIFICATION, - Command.TYPE_REBOOT_DEVICE); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Gl200FrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Gl200ProtocolEncoder()); - pipeline.addLast(new Gl200ProtocolDecoder(Gl200Protocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Gl200ProtocolEncoder()); - pipeline.addLast(new Gl200ProtocolDecoder(Gl200Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/org/traccar/protocol/Gl200ProtocolDecoder.java deleted file mode 100644 index ca1df7a13..000000000 --- a/src/org/traccar/protocol/Gl200ProtocolDecoder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseProtocolDecoder; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.Protocol; - -import java.net.SocketAddress; - -public class Gl200ProtocolDecoder extends BaseProtocolDecoder { - - private final Gl200TextProtocolDecoder textProtocolDecoder; - private final Gl200BinaryProtocolDecoder binaryProtocolDecoder; - - public Gl200ProtocolDecoder(Protocol protocol) { - super(protocol); - textProtocolDecoder = new Gl200TextProtocolDecoder(protocol); - binaryProtocolDecoder = new Gl200BinaryProtocolDecoder(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (Gl200FrameDecoder.isBinary(buf)) { - return binaryProtocolDecoder.decode(channel, remoteAddress, msg); - } else { - return textProtocolDecoder.decode(channel, remoteAddress, msg); - } - } - -} diff --git a/src/org/traccar/protocol/Gl200ProtocolEncoder.java b/src/org/traccar/protocol/Gl200ProtocolEncoder.java deleted file mode 100644 index 285106c67..000000000 --- a/src/org/traccar/protocol/Gl200ProtocolEncoder.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2016 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class Gl200ProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - initDevicePassword(command, ""); - - switch (command.getType()) { - case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "AT+GTRTO={%s},1,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "AT+GTOUT={%s},1,,,0,0,0,0,0,0,0,,,,,,,FFFF$", - Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "AT+GTOUT={%s},0,,,0,0,0,0,0,0,0,,,,,,,FFFF$", - Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_IDENTIFICATION: - return formatCommand(command, "AT+GTRTO={%s},8,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "AT+GTRTO={%s},3,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java deleted file mode 100644 index aeb57a116..000000000 --- a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ /dev/null @@ -1,1266 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; -import org.traccar.model.WifiAccessPoint; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.LinkedList; -import java.util.List; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { - - private boolean ignoreFixTime; - - public Gl200TextProtocolDecoder(Protocol protocol) { - super(protocol); - - ignoreFixTime = Context.getConfig().getBoolean(getProtocolName() + ".ignoreFixTime"); - } - - private static final Pattern PATTERN_ACK = new PatternBuilder() - .text("+ACK:GT") - .expression("...,") // type - .number("([0-9A-Z]{2}xxxx),") // protocol version - .number("(d{15}|x{14}),") // imei - .any().text(",") - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") // counter - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_INF = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTINF,") - .number("[0-9A-Z]{2}xxxx,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:[0-9A-Z]{17},)?") // vin - .expression("(?:[^,]+)?,") // device name - .number("(xx),") // state - .expression("(?:[0-9Ff]{20})?,") // iccid - .number("(d{1,2}),") // rssi - .number("d{1,2},") - .expression("[01],") // external power - .number("([d.]+)?,") // odometer or external power - .number("d*,") // backup battery or lightness - .number("(d+.d+),") // battery - .expression("([01]),") // charging - .number("(?:d),") // led - .number("(?:d)?,") // gps on need - .number("(?:d)?,") // gps antenna type - .number("(?:d)?,").optional() // gps antenna state - .number("d{14},") // last fix time - .groupBegin() - .number("(d+),") // battery percentage - .number("[d.]*,") // flash type / power - .number("(-?[d.]+)?,,,") // temperature - .or() - .expression("(?:[01])?,").optional() // pin15 mode - .number("(d+)?,") // adc1 - .number("(d+)?,").optional() // adc2 - .number("(xx)?,") // digital input - .number("(xx)?,") // digital output - .number("[-+]dddd,") // timezone - .expression("[01],") // daylight saving - .groupEnd() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") // counter - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_VER = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTVER,") - .number("[0-9A-Z]{2}xxxx,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .expression("([^,]*),") // device type - .number("(xxxx),") // firmware version - .number("(xxxx),") // hardware version - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") // counter - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_LOCATION = new PatternBuilder() - .number("(d{1,2})?,") // hdop - .number("(d{1,3}.d)?,") // speed - .number("(d{1,3})?,") // course - .number("(-?d{1,5}.d)?,") // altitude - .number("(-?d{1,3}.d{6})?,") // longitude - .number("(-?d{1,2}.d{6})?,") // latitude - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(d+)?,") // mcc - .number("(d+)?,") // mnc - .groupBegin() - .number("(d+),") // lac - .number("(d+),") // cid - .or() - .number("(x+)?,") // lac - .number("(x+)?,") // cid - .groupEnd() - .number("(?:d+|(d+.d))?,") // odometer - .compile(); - - private static final Pattern PATTERN_OBD = new PatternBuilder() - .text("+RESP:GTOBD,") - .number("[0-9A-Z]{2}xxxx,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:[0-9A-Z]{17})?,") // vin - .expression("[^,]{0,20},") // device name - .expression("[01],") // report type - .number("x{1,8},") // report mask - .expression("(?:[0-9A-Z]{17})?,") // vin - .number("[01],") // obd connect - .number("(?:d{1,5})?,") // obd voltage - .number("(?:x{8})?,") // support pids - .number("(d{1,5})?,") // engine rpm - .number("(d{1,3})?,") // speed - .number("(-?d{1,3})?,") // coolant temp - .number("(d+.?d*|Inf|NaN)?,") // fuel consumption - .number("(d{1,5})?,") // dtcs cleared distance - .number("(?:d{1,5})?,") - .expression("([01])?,") // obd connect - .number("(d{1,3})?,") // number of dtcs - .number("(x*),") // dtcs - .number("(d{1,3})?,") // throttle - .number("(?:d{1,3})?,") // engine load - .number("(d{1,3})?,") // fuel level - .expression("(?:[0-9A],)?") // obd protocol - .number("(d+),") // odometer - .expression(PATTERN_LOCATION.pattern()) - .number("(d{1,7}.d)?,") // odometer - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_FRI = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:([0-9A-Z]{17}),)?") // vin - .expression("[^,]*,") // device name - .number("(d+)?,") // power - .number("d{1,2},").optional() // report type - .number("d{1,2},").optional() // count - .number(",").optional() // reserved - .number("(d+),").optional() // battery - .expression("((?:") - .expression(PATTERN_LOCATION.pattern()) - .expression(")+)") - .groupBegin() - .number("(d{1,7}.d)?,") // odometer - .number("(d{5}:dd:dd)?,") // hour meter - .number("(x+)?,") // adc 1 - .number("(x+)?,") // adc 2 - .number("(d{1,3})?,") // battery - .number("(?:(xx)(xx)(xx))?,") // device status - .number("(d+)?,") // rpm - .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption - .number("(d+)?,") // fuel level - .or() - .number("(d{1,7}.d)?,").optional() // odometer - .number("(d{1,3})?,") // battery - .groupEnd() - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_ERI = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTERI,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(x{8}),") // mask - .number("(d+)?,") // power - .number("d{1,2},") // report type - .number("d{1,2},") // count - .expression("((?:") - .expression(PATTERN_LOCATION.pattern()) - .expression(")+)") - .number("(d{1,7}.d)?,") // odometer - .number("(d{5}:dd:dd)?,") // hour meter - .number("(x+)?,") // adc 1 - .number("(x+)?,").optional() // adc 2 - .number("(d{1,3})?,") // battery - .number("(?:(xx)(xx)(xx))?,") // device status - .expression("(.*)") // additional data - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_IGN = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTIG[NF],") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("d+,") // ignition off duration - .expression(PATTERN_LOCATION.pattern()) - .number("(d{5}:dd:dd)?,") // hour meter - .number("(d{1,7}.d)?,") // odometer - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_LSW = new PatternBuilder() - .text("+RESP:").expression("GT[LT]SW,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("[01],") // type - .number("([01]),") // state - .expression(PATTERN_LOCATION.pattern()) - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_IDA = new PatternBuilder() - .text("+RESP:GTIDA,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,,") // device name - .number("([^,]+),") // rfid - .expression("[01],") // report type - .number("1,") // count - .expression(PATTERN_LOCATION.pattern()) - .number("(d+.d),") // odometer - .text(",,,,") - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_WIF = new PatternBuilder() - .text("+RESP:GTWIF,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(d+),") // count - .number("((?:x{12},-?d+,,,,)+),,,,") // wifi - .number("(d{1,3}),") // battery - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_GSM = new PatternBuilder() - .text("+RESP:GTGSM,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("(?:STR|CTN|NMR|RTL),") // fix type - .expression("(.*)") // cells - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_PNA = new PatternBuilder() - .text("+RESP:GT").expression("P[NF]A,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .number("(d{15}|x{14}),") // imei - .expression("[^,]*,") // device name - .number("d*,") - .number("(x{1,2}),") // report type - .number("d{1,2},") // count - .expression(PATTERN_LOCATION.pattern()) - .groupBegin() - .number("(d{1,7}.d)?,").optional() // odometer - .number("(d{1,3})?,") // battery - .or() - .number("(d{1,7}.d)?,") // odometer - .groupEnd() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)") // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private static final Pattern PATTERN_BASIC = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF)").text(":") - .expression("GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version - .number("(d{15}|x{14}),") // imei - .any() - .number("(d{1,2})?,") // hdop - .number("(d{1,3}.d)?,") // speed - .number("(d{1,3})?,") // course - .number("(-?d{1,5}.d)?,") // altitude - .number("(-?d{1,3}.d{6})?,") // longitude - .number("(-?d{1,2}.d{6})?,") // latitude - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(x+),") // lac - .number("(x+),").optional(4) // cell - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)").optional(2) // time (hhmmss) - .text(",") - .number("(xxxx)") // count number - .text("$").optional() - .compile(); - - private Object decodeAck(Channel channel, SocketAddress remoteAddress, String sentence, String type) { - Parser parser = new Parser(PATTERN_ACK, sentence); - if (parser.matches()) { - String protocolVersion = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - if (type.equals("HBD")) { - if (channel != null) { - parser.skip(6); - channel.writeAndFlush(new NetworkMessage( - "+SACK:GTHBD," + protocolVersion + "," + parser.next() + "$", remoteAddress)); - } - } else { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, parser.nextDateTime()); - position.setValid(false); - position.set(Position.KEY_RESULT, "Command " + type + " accepted"); - return position; - } - } - return null; - } - - private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { - if (parser.matches()) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession != null) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - return position; - } - } - return null; - } - - private void decodeDeviceTime(Position position, Parser parser) { - if (parser.hasNext(6)) { - if (ignoreFixTime) { - position.setTime(parser.nextDateTime()); - } else { - position.setDeviceTime(parser.nextDateTime()); - } - } - } - - private Long parseHours(String hoursString) { - if (hoursString != null) { - String[] hours = hoursString.split(":"); - return (long) (Integer.parseInt(hours[0]) * 3600 - + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60 : 0) - + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000; - } - return null; - } - - private Object decodeInf(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_INF, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - switch (parser.nextHexInt()) { - case 0x16: - case 0x1A: - case 0x12: - position.set(Position.KEY_IGNITION, false); - position.set(Position.KEY_MOTION, true); - break; - case 0x11: - position.set(Position.KEY_IGNITION, false); - position.set(Position.KEY_MOTION, false); - break; - case 0x21: - position.set(Position.KEY_IGNITION, true); - position.set(Position.KEY_MOTION, false); - break; - case 0x22: - position.set(Position.KEY_IGNITION, true); - position.set(Position.KEY_MOTION, true); - break; - case 0x41: - position.set(Position.KEY_MOTION, false); - break; - case 0x42: - position.set(Position.KEY_MOTION, true); - break; - default: - break; - } - - position.set(Position.KEY_RSSI, parser.nextInt()); - - parser.next(); // odometer or external power - - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.KEY_CHARGE, parser.nextInt() == 1); - - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - - position.set(Position.PREFIX_TEMP + 1, parser.next()); - - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - - getLastLocation(position, parser.nextDateTime()); - - position.set(Position.KEY_INDEX, parser.nextHexInt()); - - return position; - } - - private Object decodeVer(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_VER, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - position.set("deviceType", parser.next()); - position.set(Position.KEY_VERSION_FW, parser.nextHexInt()); - position.set(Position.KEY_VERSION_HW, parser.nextHexInt()); - - getLastLocation(position, parser.nextDateTime()); - - return position; - } - - private void skipLocation(Parser parser) { - parser.skip(19); - } - - private void decodeLocation(Position position, Parser parser) { - Integer hdop = parser.nextInt(); - position.setValid(hdop == null || hdop > 0); - position.set(Position.KEY_HDOP, hdop); - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - if (parser.hasNext(8)) { - position.setValid(true); - position.setLongitude(parser.nextDouble()); - position.setLatitude(parser.nextDouble()); - position.setTime(parser.nextDateTime()); - } else { - getLastLocation(position, null); - } - - if (parser.hasNext(6)) { - int mcc = parser.nextInt(); - int mnc = parser.nextInt(); - if (parser.hasNext(2)) { - position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextInt(), parser.nextInt()))); - } - if (parser.hasNext(2)) { - position.setNetwork(new Network(CellTower.from(mcc, mnc, parser.nextHexInt(), parser.nextHexInt()))); - } - } - - if (parser.hasNext()) { - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - } - } - - private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_OBD, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - position.set(Position.KEY_RPM, parser.nextInt()); - position.set(Position.KEY_OBD_SPEED, parser.nextInt()); - position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); - position.set(Position.KEY_FUEL_CONSUMPTION, parser.next()); - position.set("dtcsClearedDistance", parser.nextInt()); - if (parser.hasNext()) { - position.set("odbConnect", parser.nextInt() == 1); - } - position.set("dtcsNumber", parser.nextInt()); - position.set("dtcsCodes", parser.next()); - position.set(Position.KEY_THROTTLE, parser.nextInt()); - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); - if (parser.hasNext()) { - position.set(Position.KEY_OBD_ODOMETER, parser.nextInt() * 1000); - } - - decodeLocation(position, parser); - - if (parser.hasNext()) { - position.set(Position.KEY_OBD_ODOMETER, (int) (parser.nextDouble() * 1000)); - } - - decodeDeviceTime(position, parser); - - return position; - } - - private Object decodeCan(Channel channel, SocketAddress remoteAddress, String sentence) throws ParseException { - Position position = new Position(getProtocolName()); - - int index = 0; - String[] values = sentence.split(","); - - index += 1; // header - index += 1; // protocol version - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); - position.setDeviceId(deviceSession.getDeviceId()); - - index += 1; // device name - index += 1; // report type - index += 1; // canbus state - long reportMask = Long.parseLong(values[index++], 16); - long reportMaskExt = 0; - - if (BitUtil.check(reportMask, 0)) { - position.set(Position.KEY_VIN, values[index++]); - } - if (BitUtil.check(reportMask, 1)) { - position.set(Position.KEY_IGNITION, Integer.parseInt(values[index++]) > 0); - } - if (BitUtil.check(reportMask, 2)) { - position.set(Position.KEY_OBD_ODOMETER, values[index++]); - } - if (BitUtil.check(reportMask, 3) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_USED, Double.parseDouble(values[index - 1])); - } - if (BitUtil.check(reportMask, 5) && !values[index++].isEmpty()) { - position.set(Position.KEY_RPM, Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMask, 4) && !values[index++].isEmpty()) { - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1]))); - } - if (BitUtil.check(reportMask, 6) && !values[index++].isEmpty()) { - position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMask, 7) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_CONSUMPTION, Double.parseDouble(values[index - 1].substring(1))); - } - if (BitUtil.check(reportMask, 8) && !values[index++].isEmpty()) { - position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[index - 1].substring(1))); - } - if (BitUtil.check(reportMask, 9) && !values[index++].isEmpty()) { - position.set("range", Long.parseLong(values[index - 1]) * 100); - } - if (BitUtil.check(reportMask, 10) && !values[index++].isEmpty()) { - position.set(Position.KEY_THROTTLE, Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMask, 11) && !values[index++].isEmpty()) { - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(values[index - 1]))); - } - if (BitUtil.check(reportMask, 12)) { - position.set("drivingHours", Double.parseDouble(values[index++])); - } - if (BitUtil.check(reportMask, 13)) { - position.set("idleHours", Double.parseDouble(values[index++])); - } - if (BitUtil.check(reportMask, 14) && !values[index++].isEmpty()) { - position.set("idleFuelConsumption", Double.parseDouble(values[index - 1])); - } - if (BitUtil.check(reportMask, 15) && !values[index++].isEmpty()) { - position.set(Position.KEY_AXLE_WEIGHT, Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMask, 16) && !values[index++].isEmpty()) { - position.set("tachographInfo", Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMask, 17) && !values[index++].isEmpty()) { - position.set("indicators", Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMask, 18) && !values[index++].isEmpty()) { - position.set("lights", Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMask, 19) && !values[index++].isEmpty()) { - position.set("doors", Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMask, 20) && !values[index++].isEmpty()) { - position.set("vehicleOverspeed", Double.parseDouble(values[index - 1])); - } - if (BitUtil.check(reportMask, 21) && !values[index++].isEmpty()) { - position.set("engineOverspeed", Double.parseDouble(values[index - 1])); - } - if (BitUtil.check(reportMask, 29)) { - reportMaskExt = Long.parseLong(values[index++], 16); - } - if (BitUtil.check(reportMaskExt, 0) && !values[index++].isEmpty()) { - position.set("adBlueLevel", Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMaskExt, 1) && !values[index++].isEmpty()) { - position.set("axleWeight1", Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMaskExt, 2) && !values[index++].isEmpty()) { - position.set("axleWeight3", Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMaskExt, 3) && !values[index++].isEmpty()) { - position.set("axleWeight4", Integer.parseInt(values[index - 1])); - } - if (BitUtil.check(reportMaskExt, 4)) { - index += 1; // tachograph overspeed - } - if (BitUtil.check(reportMaskExt, 5)) { - index += 1; // tachograph motion - } - if (BitUtil.check(reportMaskExt, 6)) { - index += 1; // tachograph direction - } - if (BitUtil.check(reportMaskExt, 7) && !values[index++].isEmpty()) { - position.set(Position.PREFIX_ADC + 1, Integer.parseInt(values[index - 1]) * 0.001); - } - if (BitUtil.check(reportMaskExt, 8)) { - index += 1; // pedal breaking factor - } - if (BitUtil.check(reportMaskExt, 9)) { - index += 1; // engine breaking factor - } - if (BitUtil.check(reportMaskExt, 10)) { - index += 1; // total accelerator kick-downs - } - if (BitUtil.check(reportMaskExt, 11)) { - index += 1; // total effective engine speed - } - if (BitUtil.check(reportMaskExt, 12)) { - index += 1; // total cruise control time - } - if (BitUtil.check(reportMaskExt, 13)) { - index += 1; // total accelerator kick-down time - } - if (BitUtil.check(reportMaskExt, 14)) { - index += 1; // total brake application - } - if (BitUtil.check(reportMaskExt, 15) && !values[index++].isEmpty()) { - position.set("driver1Card", values[index - 1]); - } - if (BitUtil.check(reportMaskExt, 16) && !values[index++].isEmpty()) { - position.set("driver2Card", values[index - 1]); - } - if (BitUtil.check(reportMaskExt, 17) && !values[index++].isEmpty()) { - position.set("driver1Name", values[index - 1]); - } - if (BitUtil.check(reportMaskExt, 18) && !values[index++].isEmpty()) { - position.set("driver2Name", values[index - 1]); - } - if (BitUtil.check(reportMaskExt, 19) && !values[index++].isEmpty()) { - position.set("registration", values[index - 1]); - } - if (BitUtil.check(reportMaskExt, 20)) { - index += 1; // expansion information - } - if (BitUtil.check(reportMaskExt, 21)) { - index += 1; // rapid brakings - } - if (BitUtil.check(reportMaskExt, 22)) { - index += 1; // rapid accelerations - } - if (BitUtil.check(reportMaskExt, 23)) { - index += 1; // engine torque - } - - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - - if (BitUtil.check(reportMask, 30)) { - while (values[index].isEmpty()) { - index += 1; - } - position.setValid(Integer.parseInt(values[index++]) > 0); - if (!values[index].isEmpty()) { - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - position.setCourse(Integer.parseInt(values[index++])); - position.setAltitude(Double.parseDouble(values[index++])); - position.setLongitude(Double.parseDouble(values[index++])); - position.setLatitude(Double.parseDouble(values[index++])); - position.setTime(dateFormat.parse(values[index++])); - } else { - index += 6; // no location - getLastLocation(position, null); - } - } else { - getLastLocation(position, null); - } - - if (BitUtil.check(reportMask, 31)) { - index += 4; // cell - index += 1; // reserved - } - - if (ignoreFixTime) { - position.setTime(dateFormat.parse(values[index])); - } else { - position.setDeviceTime(dateFormat.parse(values[index])); - } - - return position; - } - - private void decodeStatus(Position position, Parser parser) { - if (parser.hasNext(3)) { - int ignition = parser.nextHexInt(); - if (BitUtil.check(ignition, 4)) { - position.set(Position.KEY_IGNITION, false); - } else if (BitUtil.check(ignition, 5)) { - position.set(Position.KEY_IGNITION, true); - } - position.set(Position.KEY_INPUT, parser.nextHexInt()); - position.set(Position.KEY_OUTPUT, parser.nextHexInt()); - } - } - - private Object decodeFri(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_FRI, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - LinkedList positions = new LinkedList<>(); - - String vin = parser.next(); - Integer power = parser.nextInt(); - Integer battery = parser.nextInt(); - - Parser itemParser = new Parser(PATTERN_LOCATION, parser.next()); - while (itemParser.find()) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_VIN, vin); - - decodeLocation(position, itemParser); - - positions.add(position); - } - - Position position = positions.getLast(); - - skipLocation(parser); - - if (power != null && power > 10) { - position.set(Position.KEY_POWER, power * 0.001); // only on some devices - } - if (battery != null) { - position.set(Position.KEY_BATTERY_LEVEL, battery); - } - - if (parser.hasNext()) { - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - } - position.set(Position.KEY_HOURS, parseHours(parser.next())); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - - decodeStatus(position, parser); - - position.set(Position.KEY_RPM, parser.nextInt()); - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); - - if (parser.hasNext()) { - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - } - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - - decodeDeviceTime(position, parser); - if (ignoreFixTime) { - positions.clear(); - positions.add(position); - } - - return positions; - } - - private Object decodeEri(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_ERI, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - long mask = parser.nextHexLong(); - - LinkedList positions = new LinkedList<>(); - - Integer power = parser.nextInt(); - - Parser itemParser = new Parser(PATTERN_LOCATION, parser.next()); - while (itemParser.find()) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - decodeLocation(position, itemParser); - - positions.add(position); - } - - Position position = positions.getLast(); - - skipLocation(parser); - - if (power != null) { - position.set(Position.KEY_POWER, power * 0.001); - } - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - position.set(Position.KEY_HOURS, parseHours(parser.next())); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - - decodeStatus(position, parser); - - int index = 0; - String[] data = parser.next().split(","); - - index += 1; // device type - - if (BitUtil.check(mask, 0)) { - index += 1; // digital fuel sensor data - } - - if (BitUtil.check(mask, 1)) { - int deviceCount = Integer.parseInt(data[index++]); - for (int i = 1; i <= deviceCount; i++) { - index += 1; // id - index += 1; // type - if (!data[index++].isEmpty()) { - position.set(Position.PREFIX_TEMP + i, (short) Integer.parseInt(data[index - 1], 16) * 0.0625); - } - } - } - - if (BitUtil.check(mask, 2)) { - index += 1; // can data - } - - if (BitUtil.check(mask, 3) || BitUtil.check(mask, 4)) { - int deviceCount = Integer.parseInt(data[index++]); - for (int i = 1; i <= deviceCount; i++) { - index += 1; // type - if (BitUtil.check(mask, 3)) { - position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(data[index++])); - } - if (BitUtil.check(mask, 4)) { - index += 1; // volume - } - } - } - - decodeDeviceTime(position, parser); - if (ignoreFixTime) { - positions.clear(); - positions.add(position); - } - - return positions; - } - - private Object decodeIgn(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_IGN, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - decodeLocation(position, parser); - - position.set(Position.KEY_IGNITION, sentence.contains("IGN")); - position.set(Position.KEY_HOURS, parseHours(parser.next())); - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - - decodeDeviceTime(position, parser); - - return position; - } - - private Object decodeLsw(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_LSW, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - position.set(Position.PREFIX_IN + (sentence.contains("LSW") ? 1 : 2), parser.nextInt() == 1); - - decodeLocation(position, parser); - - decodeDeviceTime(position, parser); - - return position; - } - - private Object decodeIda(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_IDA, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - decodeLocation(position, parser); - - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - - decodeDeviceTime(position, parser); - - return position; - } - - private Object decodeWif(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_WIF, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - getLastLocation(position, null); - - Network network = new Network(); - - parser.nextInt(); // count - Matcher matcher = Pattern.compile("([0-9a-fA-F]{12}),(-?\\d+),,,,").matcher(parser.next()); - while (matcher.find()) { - String mac = matcher.group(1).replaceAll("(..)", "$1:"); - network.addWifiAccessPoint(WifiAccessPoint.from( - mac.substring(0, mac.length() - 1), Integer.parseInt(matcher.group(2)))); - } - - position.setNetwork(network); - - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - - return position; - } - - private Object decodeGsm(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_GSM, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - getLastLocation(position, null); - - Network network = new Network(); - - String[] data = parser.next().split(","); - for (int i = 0; i < 6; i++) { - if (!data[i * 6].isEmpty()) { - network.addCellTower(CellTower.from( - Integer.parseInt(data[i * 6]), Integer.parseInt(data[i * 6 + 1]), - Integer.parseInt(data[i * 6 + 2], 16), Integer.parseInt(data[i * 6 + 3], 16), - Integer.parseInt(data[i * 6 + 4]))); - } - } - - position.setNetwork(network); - - return position; - } - - private Object decodePna(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_PNA, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - getLastLocation(position, null); - - position.set(Position.KEY_ALARM, sentence.contains("PNA") ? Position.ALARM_POWER_ON : Position.ALARM_POWER_OFF); - - return position; - } - - private Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence, String type) { - Parser parser = new Parser(PATTERN, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - int reportType = parser.nextHexInt(); - if (type.equals("NMR")) { - position.set(Position.KEY_MOTION, reportType == 1); - } else if (type.equals("SOS")) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } else if (type.equals("DIS")) { - position.set(Position.PREFIX_IN + reportType / 0x10, reportType % 0x10 == 1); - } else if (type.equals("IGL")) { - position.set(Position.KEY_IGNITION, reportType % 0x10 == 1); - } - - decodeLocation(position, parser); - - if (parser.hasNext()) { - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - } - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - - if (parser.hasNext()) { - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - } - - decodeDeviceTime(position, parser); - - if (Context.getConfig().getBoolean(getProtocolName() + ".ack") && channel != null) { - channel.writeAndFlush(new NetworkMessage("+SACK:" + parser.next() + "$", remoteAddress)); - } - - return position; - } - - private Object decodeBasic(Channel channel, SocketAddress remoteAddress, String sentence, String type) { - Parser parser = new Parser(PATTERN_BASIC, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { - return null; - } - - if (parser.hasNext()) { - int hdop = parser.nextInt(); - position.setValid(hdop > 0); - position.set(Position.KEY_HDOP, hdop); - } - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - if (parser.hasNext(2)) { - position.setLongitude(parser.nextDouble()); - position.setLatitude(parser.nextDouble()); - } else { - getLastLocation(position, null); - } - - if (parser.hasNext(6)) { - position.setTime(parser.nextDateTime()); - } - - if (parser.hasNext(4)) { - position.setNetwork(new Network(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt()))); - } - - decodeDeviceTime(position, parser); - - switch (type) { - case "TOW": - position.set(Position.KEY_ALARM, Position.ALARM_TOW); - break; - case "IDL": - position.set(Position.KEY_ALARM, Position.ALARM_IDLE); - break; - case "PNA": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_ON); - break; - case "PFA": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); - break; - case "EPN": - case "MPN": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); - break; - case "EPF": - case "MPF": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - break; - case "BPL": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case "STT": - position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); - break; - case "SWG": - position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE); - break; - case "TMP": - case "TEM": - position.set(Position.KEY_ALARM, Position.ALARM_TEMPERATURE); - break; - case "JDR": - case "JDS": - position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); - break; - default: - break; - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = ((ByteBuf) msg).toString(StandardCharsets.US_ASCII); - - int typeIndex = sentence.indexOf(":GT"); - if (typeIndex < 0) { - return null; - } - - Object result; - String type = sentence.substring(typeIndex + 3, typeIndex + 6); - if (sentence.startsWith("+ACK")) { - result = decodeAck(channel, remoteAddress, sentence, type); - } else { - switch (type) { - case "INF": - result = decodeInf(channel, remoteAddress, sentence); - break; - case "OBD": - result = decodeObd(channel, remoteAddress, sentence); - break; - case "CAN": - result = decodeCan(channel, remoteAddress, sentence); - break; - case "FRI": - case "GEO": - case "STR": - result = decodeFri(channel, remoteAddress, sentence); - break; - case "ERI": - result = decodeEri(channel, remoteAddress, sentence); - break; - case "IGN": - case "IGF": - result = decodeIgn(channel, remoteAddress, sentence); - break; - case "LSW": - case "TSW": - result = decodeLsw(channel, remoteAddress, sentence); - break; - case "IDA": - result = decodeIda(channel, remoteAddress, sentence); - break; - case "WIF": - result = decodeWif(channel, remoteAddress, sentence); - break; - case "GSM": - result = decodeGsm(channel, remoteAddress, sentence); - break; - case "VER": - result = decodeVer(channel, remoteAddress, sentence); - break; - case "PNA": - case "PFA": - result = decodePna(channel, remoteAddress, sentence); - break; - default: - result = decodeOther(channel, remoteAddress, sentence, type); - break; - } - - if (result == null) { - result = decodeBasic(channel, remoteAddress, sentence, type); - } - - if (result != null) { - if (result instanceof Position) { - ((Position) result).set(Position.KEY_TYPE, type); - } else { - for (Position p : (List) result) { - p.set(Position.KEY_TYPE, type); - } - } - } - } - - return result; - } - -} diff --git a/src/org/traccar/protocol/GlobalSatProtocol.java b/src/org/traccar/protocol/GlobalSatProtocol.java deleted file mode 100644 index 5612515c9..000000000 --- a/src/org/traccar/protocol/GlobalSatProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GlobalSatProtocol extends BaseProtocol { - - public GlobalSatProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '!')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new GlobalSatProtocolDecoder(GlobalSatProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GlobalSatProtocolDecoder.java b/src/org/traccar/protocol/GlobalSatProtocolDecoder.java deleted file mode 100644 index 3d4ab5760..000000000 --- a/src/org/traccar/protocol/GlobalSatProtocolDecoder.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class GlobalSatProtocolDecoder extends BaseProtocolDecoder { - - private String format0; - private String format1; - - public GlobalSatProtocolDecoder(Protocol protocol) { - super(protocol); - - format0 = Context.getConfig().getString(getProtocolName() + ".format0", "TSPRXAB27GHKLMnaicz*U!"); - format1 = Context.getConfig().getString(getProtocolName() + ".format1", "SARY*U!"); - } - - public void setFormat0(String format) { - format0 = format; - } - - public void setFormat1(String format) { - format1 = format; - } - - private Position decodeOriginal(Channel channel, SocketAddress remoteAddress, String sentence) { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("ACK\r", remoteAddress)); - } - - String format; - if (sentence.startsWith("GSr")) { - format = format0; - } else if (sentence.startsWith("GSh")) { - format = format1; - } else { - return null; - } - - // Check that message contains required parameters - if (!format.contains("B") || !format.contains("S") || !(format.contains("1") - || format.contains("2") || format.contains("3")) || !(format.contains("6") - || format.contains("7") || format.contains("8"))) { - return null; - } - - if (format.contains("*")) { - format = format.substring(0, format.indexOf('*')); - sentence = sentence.substring(0, sentence.indexOf('*')); - } - String[] values = sentence.split(","); - - Position position = new Position(getProtocolName()); - - for (int formatIndex = 0, valueIndex = 1; formatIndex < format.length() - && valueIndex < values.length; formatIndex++) { - String value = values[valueIndex]; - - switch (format.charAt(formatIndex)) { - case 'S': - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - break; - case 'A': - if (value.isEmpty()) { - position.setValid(false); - } else { - position.setValid(Integer.parseInt(value) != 1); - } - break; - case 'B': - DateBuilder dateBuilder = new DateBuilder() - .setDay(Integer.parseInt(value.substring(0, 2))) - .setMonth(Integer.parseInt(value.substring(2, 4))) - .setYear(Integer.parseInt(value.substring(4))); - value = values[++valueIndex]; - dateBuilder - .setHour(Integer.parseInt(value.substring(0, 2))) - .setMinute(Integer.parseInt(value.substring(2, 4))) - .setSecond(Integer.parseInt(value.substring(4))); - position.setTime(dateBuilder.getDate()); - break; - case 'C': - valueIndex += 1; - break; - case '1': - double longitude = Double.parseDouble(value.substring(1)); - if (value.charAt(0) == 'W') { - longitude = -longitude; - } - position.setLongitude(longitude); - break; - case '2': - longitude = Double.parseDouble(value.substring(4)) / 60; - longitude += Integer.parseInt(value.substring(1, 4)); - if (value.charAt(0) == 'W') { - longitude = -longitude; - } - position.setLongitude(longitude); - break; - case '3': - position.setLongitude(Double.parseDouble(value) * 0.000001); - break; - case '6': - double latitude = Double.parseDouble(value.substring(1)); - if (value.charAt(0) == 'S') { - latitude = -latitude; - } - position.setLatitude(latitude); - break; - case '7': - latitude = Double.parseDouble(value.substring(3)) / 60; - latitude += Integer.parseInt(value.substring(1, 3)); - if (value.charAt(0) == 'S') { - latitude = -latitude; - } - position.setLatitude(latitude); - break; - case '8': - position.setLatitude(Double.parseDouble(value) * 0.000001); - break; - case 'G': - position.setAltitude(Double.parseDouble(value)); - break; - case 'H': - position.setSpeed(Double.parseDouble(value)); - break; - case 'I': - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(value))); - break; - case 'J': - position.setSpeed(UnitsConverter.knotsFromMph(Double.parseDouble(value))); - break; - case 'K': - position.setCourse(Double.parseDouble(value)); - break; - case 'N': - if (value.endsWith("mV")) { - position.set(Position.KEY_BATTERY, - Integer.parseInt(value.substring(0, value.length() - 2)) / 1000.0); - } else { - position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(value)); - } - break; - default: - // Unsupported - break; - } - - valueIndex += 1; - } - return position; - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$") - .number("(d+),") // imei - .number("d+,") // mode - .number("(d+),") // fix - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([EW])") - .number("(ddd)(dd.d+),") // longitude (dddmm.mmmm) - .expression("([NS])") - .number("(dd)(dd.d+),") // latitude (ddmm.mmmm) - .number("(d+.?d*),") // altitude - .number("(d+.?d*),") // speed - .number("(d+.?d*)?,") // course - .number("(d+)[,*]") // satellites - .number("(d+.?d*)") // hdop - .compile(); - - private Position decodeAlternative(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(!parser.next().equals("1")); - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setAltitude(parser.nextDouble(0)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_HDOP, parser.nextDouble()); - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("GS")) { - return decodeOriginal(channel, remoteAddress, sentence); - } else if (sentence.startsWith("$")) { - return decodeAlternative(channel, remoteAddress, sentence); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/GnxProtocol.java b/src/org/traccar/protocol/GnxProtocol.java deleted file mode 100644 index 3576bf805..000000000 --- a/src/org/traccar/protocol/GnxProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GnxProtocol extends BaseProtocol { - - public GnxProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\n\r")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new GnxProtocolDecoder(GnxProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GnxProtocolDecoder.java b/src/org/traccar/protocol/GnxProtocolDecoder.java deleted file mode 100644 index c9c221a69..000000000 --- a/src/org/traccar/protocol/GnxProtocolDecoder.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class GnxProtocolDecoder extends BaseProtocolDecoder { - - public GnxProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_LOCATION = new PatternBuilder() - .number("(d+),") // imei - .number("d+,") // length - .expression("([01]),") // history - .number("(dd)(dd)(dd),") // device time (hhmmss) - .number("(dd)(dd)(dd),") // device date (ddmmyy) - .number("(dd)(dd)(dd),") // fix time (hhmmss) - .number("(dd)(dd)(dd),") // fix date (ddmmyy) - .number("(d),") // valid - .number("(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd.d+),") // longitude - .expression("([EW]),") - .compile(); - - private static final Pattern PATTERN_MIF = new PatternBuilder() - .text("$GNX_MIF,") - .expression(PATTERN_LOCATION.pattern()) - .expression("[01],") // valid card - .expression("([^,]+),") // rfid - .any() - .compile(); - - private static final Pattern PATTERN_OTHER = new PatternBuilder() - .text("$GNX_") - .expression("...,") - .expression(PATTERN_LOCATION.pattern()) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - String type = sentence.substring(5, 8); - - Pattern pattern; - if (type.equals("MIF")) { - pattern = PATTERN_MIF; - } else { - pattern = PATTERN_OTHER; - } - - Parser parser = new Parser(pattern, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.nextInt(0) == 1) { - position.set(Position.KEY_ARCHIVE, true); - } - - position.setDeviceTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY, "GMT+5:30")); - position.setFixTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY, "GMT+5:30")); - - position.setValid(parser.nextInt(0) != 0); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - - if (type.equals("MIF")) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/GoSafeProtocol.java b/src/org/traccar/protocol/GoSafeProtocol.java deleted file mode 100644 index 853b78a16..000000000 --- a/src/org/traccar/protocol/GoSafeProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GoSafeProtocol extends BaseProtocol { - - public GoSafeProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new GoSafeProtocolDecoder(GoSafeProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/org/traccar/protocol/GoSafeProtocolDecoder.java deleted file mode 100644 index 95ef18f20..000000000 --- a/src/org/traccar/protocol/GoSafeProtocolDecoder.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; - -public class GoSafeProtocolDecoder extends BaseProtocolDecoder { - - public GoSafeProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("*GS") // header - .number("d+,") // protocol version - .number("(d+),") // imei - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("(dd)(dd)(dd),") // date (ddmmyy) - .expression("([^#]*)#?") // data - .compile(); - - private static final Pattern PATTERN_OLD = new PatternBuilder() - .text("*GS") // header - .number("d+,") // protocol version - .number("(d+),") // imei - .text("GPS:") - .number("(dd)(dd)(dd);") // time (hhmmss) - .number("d;").optional() // fix type - .expression("([AV]);") // validity - .number("([NS])(d+.d+);") // latitude - .number("([EW])(d+.d+);") // longitude - .number("(d+)?;") // speed - .number("(d+);") // course - .number("(d+.?d*)").optional() // hdop - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); - - private void decodeFragment(Position position, String fragment) { - int dataIndex = fragment.indexOf(':'); - int index = 0; - String[] values; - if (fragment.length() == dataIndex + 1) { - values = new String[0]; - } else { - values = fragment.substring(dataIndex + 1).split(";"); - } - switch (fragment.substring(0, dataIndex)) { - case "GPS": - position.setValid(values[index++].equals("A")); - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); - position.setLatitude(Double.parseDouble(values[index].substring(1))); - if (values[index++].charAt(0) == 'S') { - position.setLatitude(-position.getLatitude()); - } - position.setLongitude(Double.parseDouble(values[index].substring(1))); - if (values[index++].charAt(0) == 'W') { - position.setLongitude(-position.getLongitude()); - } - if (!values[index++].isEmpty()) { - position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1]))); - } - position.setCourse(Integer.parseInt(values[index++])); - if (index < values.length) { - position.setAltitude(Integer.parseInt(values[index++])); - } - if (index < values.length) { - position.set(Position.KEY_HDOP, Double.parseDouble(values[index++])); - } - if (index < values.length) { - position.set(Position.KEY_VDOP, Double.parseDouble(values[index++])); - } - break; - case "GSM": - index += 1; // registration status - index += 1; // signal strength - position.setNetwork(new Network(CellTower.from( - Integer.parseInt(values[index++]), Integer.parseInt(values[index++]), - Integer.parseInt(values[index++], 16), Integer.parseInt(values[index++], 16), - Integer.parseInt(values[index++])))); - break; - case "COT": - if (index < values.length) { - position.set(Position.KEY_ODOMETER, Long.parseLong(values[index++])); - } - if (index < values.length) { - String[] hours = values[index].split("-"); - position.set(Position.KEY_HOURS, (Integer.parseInt(hours[0]) * 3600 - + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60 : 0) - + (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000); - } - break; - case "ADC": - position.set(Position.KEY_POWER, Double.parseDouble(values[index++])); - if (index < values.length) { - position.set(Position.KEY_BATTERY, Double.parseDouble(values[index++])); - } - if (index < values.length) { - position.set(Position.PREFIX_ADC + 1, Double.parseDouble(values[index++])); - } - if (index < values.length) { - position.set(Position.PREFIX_ADC + 2, Double.parseDouble(values[index++])); - } - break; - case "DTT": - position.set(Position.KEY_STATUS, Integer.parseInt(values[index++], 16)); - if (!values[index++].isEmpty()) { - int io = Integer.parseInt(values[index - 1], 16); - position.set(Position.KEY_IGNITION, BitUtil.check(io, 0)); - position.set(Position.PREFIX_IN + 1, BitUtil.check(io, 1)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(io, 2)); - position.set(Position.PREFIX_IN + 3, BitUtil.check(io, 3)); - position.set(Position.PREFIX_IN + 4, BitUtil.check(io, 4)); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(io, 5)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(io, 6)); - position.set(Position.PREFIX_OUT + 3, BitUtil.check(io, 7)); - } - position.set(Position.KEY_GEOFENCE, values[index++] + values[index++]); - position.set("eventStatus", values[index++]); - if (index < values.length) { - position.set("packetType", values[index++]); - } - break; - case "ETD": - position.set("eventData", values[index++]); - break; - case "OBD": - position.set("obd", values[index++]); - break; - case "TAG": - position.set("tagData", values[index++]); - break; - case "IWD": - if (index < values.length && values[index + 1].equals("0")) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, values[index + 2]); - } - break; - default: - break; - } - } - - private Object decodeData(DeviceSession deviceSession, Date time, String data) { - - List positions = new LinkedList<>(); - Position position = null; - int index = 0; - String[] fragments = data.split(","); - - while (index < fragments.length) { - - if (fragments[index].isEmpty() || Character.isDigit(fragments[index].charAt(0))) { - - if (position != null) { - positions.add(position); - } - - position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(time); - - if (!fragments[index++].isEmpty()) { - position.set(Position.KEY_EVENT, Integer.parseInt(fragments[index - 1])); - } - - } else { - - decodeFragment(position, fragments[index++]); - - } - - } - - if (position != null) { - positions.add(position); - } - - return positions; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("1234", remoteAddress)); - } - - String sentence = (String) msg; - Pattern pattern = PATTERN; - if (sentence.startsWith("*GS02")) { - pattern = PATTERN_OLD; - } - - Parser parser = new Parser(pattern, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - if (pattern == PATTERN_OLD) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_HDOP, parser.next()); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - - } else { - - Date time = new Date(); - if (parser.hasNext(6)) { - time = parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY); - } - - return decodeData(deviceSession, time, parser.next()); - - } - } - -} diff --git a/src/org/traccar/protocol/GotopProtocol.java b/src/org/traccar/protocol/GotopProtocol.java deleted file mode 100644 index 07fe02248..000000000 --- a/src/org/traccar/protocol/GotopProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GotopProtocol extends BaseProtocol { - - public GotopProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new GotopProtocolDecoder(GotopProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GotopProtocolDecoder.java b/src/org/traccar/protocol/GotopProtocolDecoder.java deleted file mode 100644 index 2ef975fe5..000000000 --- a/src/org/traccar/protocol/GotopProtocolDecoder.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class GotopProtocolDecoder extends BaseProtocolDecoder { - - public GotopProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(d+),") // imei - .expression("[^,]+,") // type - .expression("([AV]),") // validity - .number("DATE:(dd)(dd)(dd),") // date (yyddmm) - .number("TIME:(dd)(dd)(dd),") // time (hhmmss) - .number("LAT:(d+.d+)([NS]),") // latitude - .number("LOT:(d+.d+)([EW]),") // longitude - .text("Speed:").number("(d+.d+),") // speed - .expression("([^,]+),") // status - .number("(d+)?") // course - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.next().equals("A")); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - - position.set(Position.KEY_STATUS, parser.next()); - - position.setCourse(parser.nextDouble(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/Gps056FrameDecoder.java b/src/org/traccar/protocol/Gps056FrameDecoder.java deleted file mode 100644 index 0d84bf231..000000000 --- a/src/org/traccar/protocol/Gps056FrameDecoder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -import java.nio.charset.StandardCharsets; - -public class Gps056FrameDecoder extends BaseFrameDecoder { - - private static final int MESSAGE_HEADER = 4; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() >= MESSAGE_HEADER) { - int length = Integer.parseInt(buf.toString(2, 2, StandardCharsets.US_ASCII)) + 5; - if (buf.readableBytes() >= length) { - ByteBuf frame = buf.readRetainedSlice(length); - while (buf.isReadable() && buf.getUnsignedByte(buf.readerIndex()) != '$') { - buf.readByte(); - } - return frame; - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Gps056Protocol.java b/src/org/traccar/protocol/Gps056Protocol.java deleted file mode 100644 index b6ab10a19..000000000 --- a/src/org/traccar/protocol/Gps056Protocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Gps056Protocol extends BaseProtocol { - - public Gps056Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Gps056FrameDecoder()); - pipeline.addLast(new Gps056ProtocolDecoder(Gps056Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Gps056ProtocolDecoder.java b/src/org/traccar/protocol/Gps056ProtocolDecoder.java deleted file mode 100644 index 0ba79bb51..000000000 --- a/src/org/traccar/protocol/Gps056ProtocolDecoder.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; - -public class Gps056ProtocolDecoder extends BaseProtocolDecoder { - - public Gps056ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static void sendResponse(Channel channel, String type, String imei, ByteBuf content) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - String header = "*" + type + imei; - response.writeBytes(header.getBytes(StandardCharsets.US_ASCII)); - if (content != null) { - response.writeBytes(content); - } - response.writeByte('#'); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - private static double decodeCoordinate(ByteBuf buf) { - double degrees = buf.getUnsignedShort(buf.readerIndex()) / 100; - double minutes = buf.readUnsignedShort() % 100 + buf.readUnsignedShort() * 0.0001; - degrees += minutes / 60; - byte hemisphere = buf.readByte(); - if (hemisphere == 'S' || hemisphere == 'W') { - degrees = -degrees; - } - return degrees; - } - - private static void decodeStatus(ByteBuf buf, Position position) { - - position.set(Position.KEY_INPUT, buf.readUnsignedByte()); - position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); - - position.set(Position.PREFIX_ADC + 1, buf.readShortLE() * 5.06); // mV - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - buf.skipBytes(2); // length - - String type = buf.readSlice(7).toString(StandardCharsets.US_ASCII); - String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - if (type.startsWith("LOGN")) { - - ByteBuf content = Unpooled.copiedBuffer("1", StandardCharsets.US_ASCII); - try { - sendResponse(channel, "LGSA" + type.substring(4), imei, content); - } finally { - content.release(); - } - - } else if (type.startsWith("GPSL")) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - - position.setValid(true); - position.setTime(dateBuilder.getDate()); - position.setLatitude(decodeCoordinate(buf)); - position.setLongitude(decodeCoordinate(buf)); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.setCourse(buf.readUnsignedShort()); - - decodeStatus(buf, position); - - sendResponse(channel, "GPSA" + type.substring(4), imei, buf.readSlice(2)); - - return position; - - } else if (type.startsWith("SYNC")) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - decodeStatus(buf, position); - - sendResponse(channel, "SYSA" + type.substring(4), imei, null); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Gps103Protocol.java b/src/org/traccar/protocol/Gps103Protocol.java deleted file mode 100644 index 6272a3fd1..000000000 --- a/src/org/traccar/protocol/Gps103Protocol.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class Gps103Protocol extends BaseProtocol { - - public Gps103Protocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_POSITION_SINGLE, - Command.TYPE_POSITION_PERIODIC, - Command.TYPE_POSITION_STOP, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_ALARM_ARM, - Command.TYPE_ALARM_DISARM, - Command.TYPE_REQUEST_PHOTO); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(2048, false, "\r\n", "\n", ";", "*")); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Gps103ProtocolEncoder()); - pipeline.addLast(new Gps103ProtocolDecoder(Gps103Protocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Gps103ProtocolEncoder()); - pipeline.addLast(new Gps103ProtocolDecoder(Gps103Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/org/traccar/protocol/Gps103ProtocolDecoder.java deleted file mode 100644 index aa02e8ad4..000000000 --- a/src/org/traccar/protocol/Gps103ProtocolDecoder.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DataConverter; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class Gps103ProtocolDecoder extends BaseProtocolDecoder { - - private int photoPackets = 0; - private ByteBuf photo; - - public Gps103ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("imei:") - .number("(d+),") // imei - .expression("([^,]+),") // alarm - .groupBegin() - .number("(dd)/?(dd)/?(dd) ?") // local date (yymmdd) - .number("(dd):?(dd)(?:dd)?,") // local time (hhmmss) - .or() - .number("d*,") - .groupEnd() - .expression("([^,]+)?,") // rfid - .groupBegin() - .text("L,,,") - .number("(x+),,") // lac - .number("(x+),,,") // cid - .or() - .text("F,") - .groupBegin() - .number("(dd)(dd)(dd).d+") // time utc (hhmmss) - .or() - .number("(?:d{1,5}.d+)?") - .groupEnd() - .text(",") - .expression("([AV]),") // validity - .expression("([NS]),").optional() - .number("(d+)(dd.d+),") // latitude (ddmm.mmmm) - .expression("([NS]),").optional() - .expression("([EW]),").optional() - .number("(d+)(dd.d+),") // longitude (dddmm.mmmm) - .expression("([EW])?,").optional() - .number("(d+.?d*)?").optional() // speed - .number(",(d+.?d*)?").optional() // course - .number(",(d+.?d*)?").optional() // altitude - .number(",([01])?").optional() // ignition - .number(",([01])?").optional() // door - .groupBegin() - .number(",(?:(d+.d+)%)?") // fuel 1 - .number(",(?:(d+.d+)%|d+)?") // fuel 2 - .groupEnd("?") - .number(",([-+]?d+)?").optional() // temperature - .groupEnd() - .any() - .compile(); - - private static final Pattern PATTERN_OBD = new PatternBuilder() - .text("imei:") - .number("(d+),") // imei - .expression("OBD,") // type - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d+)?,") // odometer - .number("(d+.d+)?,") // fuel instant - .number("(d+.d+)?,") // fuel average - .number("(d+)?,") // hours - .number("(d+),") // speed - .number("(d+.?d*%),") // power load - .number("(?:([-+]?d+)|[-+]?),") // temperature - .number("(d+.?d*%),") // throttle - .number("(d+),") // rpm - .number("(d+.d+),") // battery - .number("([^;]*)") // dtcs - .any() - .compile(); - - private static final Pattern PATTERN_ALT = new PatternBuilder() - .text("imei:") - .number("(d+),") // imei - .expression("[^,]+,") - .expression("(?:-+|(.+)),") // event - .expression("(?:-+|(.+)),") // sensor id - .expression("(?:-+|(.+)),") // sensor voltage - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(d+),") // rssi - .number("(d),") // gps status - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(-?d+),") // altitude - .number("(d+.d+),") // hdop - .number("(d+),") // satellites - .number("([01]),") // ignition - .number("([01]),") // charge - .expression("(?:-+|(.+))") // error - .any() - .compile(); - - private String decodeAlarm(String value) { - if (value.startsWith("T:")) { - return Position.ALARM_TEMPERATURE; - } else if (value.startsWith("oil")) { - return Position.ALARM_FUEL_LEAK; - } - switch (value) { - case "tracker": - return null; - case "help me": - return Position.ALARM_SOS; - case "low battery": - return Position.ALARM_LOW_BATTERY; - case "stockade": - return Position.ALARM_GEOFENCE; - case "move": - return Position.ALARM_MOVEMENT; - case "speed": - return Position.ALARM_OVERSPEED; - case "acc on": - return Position.ALARM_POWER_ON; - case "acc off": - return Position.ALARM_POWER_OFF; - case "door alarm": - return Position.ALARM_DOOR; - case "ac alarm": - return Position.ALARM_POWER_CUT; - case "accident alarm": - return Position.ALARM_ACCIDENT; - case "sensor alarm": - return Position.ALARM_SHOCK; - case "bonnet alarm": - return Position.ALARM_BONNET; - case "footbrake alarm": - return Position.ALARM_FOOT_BRAKE; - case "DTC": - return Position.ALARM_FAULT; - default: - return null; - } - } - - private Position decodeRegular(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - String imei = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - String alarm = parser.next(); - position.set(Position.KEY_ALARM, decodeAlarm(alarm)); - if (alarm.equals("help me")) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("**,imei:" + imei + ",E;", remoteAddress)); - } - } else if (alarm.startsWith("vt")) { - photoPackets = Integer.parseInt(alarm.substring(2)); - photo = Unpooled.buffer(); - } else if (alarm.equals("acc on")) { - position.set(Position.KEY_IGNITION, true); - } else if (alarm.equals("acc off")) { - position.set(Position.KEY_IGNITION, false); - } else if (alarm.startsWith("T:")) { - position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(alarm.substring(2))); - } else if (alarm.startsWith("oil ")) { - position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(alarm.substring(4))); - } else if (!position.getAttributes().containsKey(Position.KEY_ALARM) && !alarm.equals("tracker")) { - position.set(Position.KEY_EVENT, alarm); - } - - DateBuilder dateBuilder = new DateBuilder() - .setDate(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - int localHours = parser.nextInt(0); - int localMinutes = parser.nextInt(0); - - String rfid = parser.next(); - if (alarm.equals("rfid")) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid); - } - - if (parser.hasNext(2)) { - - getLastLocation(position, null); - - position.setNetwork(new Network(CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0)))); - - } else { - - String utcHours = parser.next(); - String utcMinutes = parser.next(); - - dateBuilder.setTime(localHours, localMinutes, parser.nextInt(0)); - - // Timezone calculation - if (utcHours != null && utcMinutes != null) { - int deltaMinutes = (localHours - Integer.parseInt(utcHours)) * 60; - deltaMinutes += localMinutes - Integer.parseInt(utcMinutes); - if (deltaMinutes <= -12 * 60) { - deltaMinutes += 24 * 60; - } else if (deltaMinutes > 12 * 60) { - deltaMinutes -= 24 * 60; - } - dateBuilder.addMinute(-deltaMinutes); - } - position.setTime(dateBuilder.getDate()); - - position.setValid(parser.next().equals("A")); - position.setFixTime(position.getDeviceTime()); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_HEM)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - if (parser.hasNext()) { - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - } - if (parser.hasNext()) { - position.set(Position.KEY_DOOR, parser.nextInt() == 1); - } - position.set("fuel1", parser.nextDouble()); - position.set("fuel2", parser.nextDouble()); - position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); - - } - - return position; - } - - private Position decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_OBD, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, parser.nextDateTime()); - - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - parser.nextDouble(0); // instant fuel consumption - position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextDouble(0)); - if (parser.hasNext()) { - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(parser.nextInt())); - } - position.set(Position.KEY_OBD_SPEED, parser.nextInt(0)); - position.set(Position.KEY_ENGINE_LOAD, parser.next()); - position.set(Position.KEY_COOLANT_TEMP, parser.nextInt()); - position.set(Position.KEY_THROTTLE, parser.next()); - position.set(Position.KEY_RPM, parser.nextInt(0)); - position.set(Position.KEY_BATTERY, parser.nextDouble(0)); - position.set(Position.KEY_DTCS, parser.next().replace(',', ' ').trim()); - - return position; - } - - - private Position decodeAlternative(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_ALT, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_EVENT, parser.next()); - position.set("sensorId", parser.next()); - position.set("sensorVoltage", parser.nextDouble()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - position.set(Position.KEY_RSSI, parser.nextInt()); - - position.setValid(parser.nextInt() > 0); - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); - position.setCourse(parser.nextInt()); - position.setAltitude(parser.nextInt()); - - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_IGNITION, parser.nextInt() > 0); - position.set(Position.KEY_CHARGE, parser.nextInt() > 0); - position.set("error", parser.next()); - - return position; - } - - private Position decodePhoto(Channel channel, SocketAddress remoteAddress, String sentence) { - - String imei = sentence.substring(5, 5 + 15); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex( - sentence.substring(24, sentence.endsWith(";") ? sentence.length() - 1 : sentence.length()))); - int index = buf.readUnsignedShortLE(); - photo.writeBytes(buf, buf.readerIndex() + 2, buf.readableBytes() - 4); - - if (index + 1 >= photoPackets) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - try { - position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg")); - } finally { - photoPackets = 0; - photo.release(); - photo = null; - } - - return position; - } else { - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.contains("imei:") && sentence.length() <= 30) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("LOAD", remoteAddress)); - Matcher matcher = Pattern.compile("imei:(\\d+),").matcher(sentence); - if (matcher.find()) { - getDeviceSession(channel, remoteAddress, matcher.group(1)); - } - } - return null; - } - - if (!sentence.isEmpty() && Character.isDigit(sentence.charAt(0))) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("ON", remoteAddress)); - } - int start = sentence.indexOf("imei:"); - if (start >= 0) { - sentence = sentence.substring(start); - } else { - return null; - } - } - - if (sentence.substring(21, 21 + 2).equals("vr")) { - return decodePhoto(channel, remoteAddress, sentence); - } else if (sentence.substring(21, 21 + 3).contains("OBD")) { - return decodeObd(channel, remoteAddress, sentence); - } else if (sentence.endsWith("*")) { - return decodeAlternative(channel, remoteAddress, sentence); - } else { - return decodeRegular(channel, remoteAddress, sentence); - } - } - -} diff --git a/src/org/traccar/protocol/Gps103ProtocolEncoder.java b/src/org/traccar/protocol/Gps103ProtocolEncoder.java deleted file mode 100644 index 47ef2f333..000000000 --- a/src/org/traccar/protocol/Gps103ProtocolEncoder.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class Gps103ProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { - - @Override - public String formatValue(String key, Object value) { - - if (key.equals(Command.KEY_FREQUENCY)) { - long frequency = ((Number) value).longValue(); - if (frequency / 60 / 60 > 0) { - return String.format("%02dh", frequency / 60 / 60); - } else if (frequency / 60 > 0) { - return String.format("%02dm", frequency / 60); - } else { - return String.format("%02ds", frequency); - } - } - - return null; - } - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatCommand(command, "**,imei:{%s},{%s}", Command.KEY_UNIQUE_ID, Command.KEY_DATA); - case Command.TYPE_POSITION_STOP: - return formatCommand(command, "**,imei:{%s},A", Command.KEY_UNIQUE_ID); - case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "**,imei:{%s},B", Command.KEY_UNIQUE_ID); - case Command.TYPE_POSITION_PERIODIC: - return formatCommand( - command, "**,imei:{%s},C,{%s}", this, Command.KEY_UNIQUE_ID, Command.KEY_FREQUENCY); - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "**,imei:{%s},J", Command.KEY_UNIQUE_ID); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "**,imei:{%s},K", Command.KEY_UNIQUE_ID); - case Command.TYPE_ALARM_ARM: - return formatCommand(command, "**,imei:{%s},L", Command.KEY_UNIQUE_ID); - case Command.TYPE_ALARM_DISARM: - return formatCommand(command, "**,imei:{%s},M", Command.KEY_UNIQUE_ID); - case Command.TYPE_REQUEST_PHOTO: - return formatCommand(command, "**,imei:{%s},160", Command.KEY_UNIQUE_ID); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/GpsGateProtocol.java b/src/org/traccar/protocol/GpsGateProtocol.java deleted file mode 100644 index a131b6f48..000000000 --- a/src/org/traccar/protocol/GpsGateProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GpsGateProtocol extends BaseProtocol { - - public GpsGateProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\0", "\n", "\r\n")); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new GpsGateProtocolDecoder(GpsGateProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GpsGateProtocolDecoder.java b/src/org/traccar/protocol/GpsGateProtocolDecoder.java deleted file mode 100644 index cc187225b..000000000 --- a/src/org/traccar/protocol/GpsGateProtocolDecoder.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class GpsGateProtocolDecoder extends BaseProtocolDecoder { - - public GpsGateProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_GPRMC = new PatternBuilder() - .text("$GPRMC,") - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+)?,") // speed - .number("(d+.d+)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); - - private static final Pattern PATTERN_FRCMD = new PatternBuilder() - .text("$FRCMD,") - .number("(d+),") // imei - .expression("[^,]*,") // command - .expression("[^,]*,") - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*),") // altitude - .number("(d+.?d*),") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([01])") // validity - .any() - .compile(); - - private void send(Channel channel, SocketAddress remoteAddress, String message) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(message + Checksum.nmea(message) + "\r\n", remoteAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("$FRLIN,")) { - - int beginIndex = sentence.indexOf(',', 7); - if (beginIndex != -1) { - beginIndex += 1; - int endIndex = sentence.indexOf(',', beginIndex); - if (endIndex != -1) { - String imei = sentence.substring(beginIndex, endIndex); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession != null) { - if (channel != null) { - send(channel, remoteAddress, "$FRSES," + channel.id().asShortText()); - } - } else { - send(channel, remoteAddress, "$FRERR,AuthError,Unknown device"); - } - } else { - send(channel, remoteAddress, "$FRERR,AuthError,Parse error"); - } - } else { - send(channel, remoteAddress, "$FRERR,AuthError,Parse error"); - } - - } else if (sentence.startsWith("$FRVER,")) { - - send(channel, remoteAddress, "$FRVER,1,0,GpsGate Server 1.0"); - - } else if (sentence.startsWith("$GPRMC,")) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN_GPRMC, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - - } else if (sentence.startsWith("$FRCMD,")) { - - Parser parser = new Parser(PATTERN_FRCMD, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setAltitude(parser.nextDouble(0)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setValid(parser.next().equals("1")); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/GpsMarkerProtocol.java b/src/org/traccar/protocol/GpsMarkerProtocol.java deleted file mode 100644 index ad23ece48..000000000 --- a/src/org/traccar/protocol/GpsMarkerProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GpsMarkerProtocol extends BaseProtocol { - - public GpsMarkerProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new GpsMarkerProtocolDecoder(GpsMarkerProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GpsMarkerProtocolDecoder.java b/src/org/traccar/protocol/GpsMarkerProtocolDecoder.java deleted file mode 100644 index bbb2c31e2..000000000 --- a/src/org/traccar/protocol/GpsMarkerProtocolDecoder.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class GpsMarkerProtocolDecoder extends BaseProtocolDecoder { - - public GpsMarkerProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$GM") - .number("d") // type - .number("(?:xx)?") // index - .number("(d{15})") // imei - .number("T(dd)(dd)(dd)") // date (ddmmyy) - .number("(dd)(dd)(dd)?") // time (hhmmss) - .expression("([NS])") - .number("(dd)(dd)(dddd)") // latitude - .expression("([EW])") - .number("(ddd)(dd)(dddd)") // longitude - .number("(ddd)") // speed - .number("(ddd)") // course - .number("(x)") // satellites - .number("(dd)") // battery - .number("(d)") // input - .number("(d)") // output - .number("(ddd)") // temperature - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - position.set(Position.PREFIX_TEMP + 1, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/GpsmtaProtocol.java b/src/org/traccar/protocol/GpsmtaProtocol.java deleted file mode 100644 index ce6cc5929..000000000 --- a/src/org/traccar/protocol/GpsmtaProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class GpsmtaProtocol extends BaseProtocol { - - public GpsmtaProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new GpsmtaProtocolDecoder(GpsmtaProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GpsmtaProtocolDecoder.java b/src/org/traccar/protocol/GpsmtaProtocolDecoder.java deleted file mode 100644 index 31f9401b4..000000000 --- a/src/org/traccar/protocol/GpsmtaProtocolDecoder.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.regex.Pattern; - -public class GpsmtaProtocolDecoder extends BaseProtocolDecoder { - - public GpsmtaProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("([^ ]+) ") // uid - .number("(d+) ") // time (unix time) - .number("(-?d+.d+) ") // latitude - .number("(-?d+.d+) ") // longitude - .number("(d+) ") // speed - .number("(d+) ") // course - .number("(d+) ") // accuracy - .number("(d+) ") // altitude - .number("(d+) ") // flags - .number("(d+) ") // battery - .number("(d+) ") // temperature - .number("(d)") // charging status - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - String time = parser.next(); - position.setTime(new Date(Long.parseLong(time) * 1000)); - - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setSpeed(parser.nextInt()); - position.setCourse(parser.nextInt()); - position.setAccuracy(parser.nextInt()); - position.setAltitude(parser.nextInt()); - - position.set(Position.KEY_STATUS, parser.nextInt()); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); - position.set(Position.KEY_CHARGE, parser.nextInt() == 1); - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(time, remoteAddress)); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/GranitFrameDecoder.java b/src/org/traccar/protocol/GranitFrameDecoder.java deleted file mode 100644 index bb7f4be44..000000000 --- a/src/org/traccar/protocol/GranitFrameDecoder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; -import org.traccar.helper.BufferUtil; - -public class GranitFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int indexEnd = BufferUtil.indexOf("\r\n", buf); - if (indexEnd != -1) { - int indexTilde = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '~'); - if (indexTilde != -1 && indexTilde < indexEnd) { - int length = buf.getUnsignedShortLE(indexTilde + 1); - indexEnd = BufferUtil.indexOf("\r\n", buf, indexTilde + 2 + length, buf.writerIndex()); - if (indexEnd == -1) { - return null; - } - } - ByteBuf frame = buf.readRetainedSlice(indexEnd - buf.readerIndex()); - buf.skipBytes(2); - return frame; - } - return null; - } - -} diff --git a/src/org/traccar/protocol/GranitProtocol.java b/src/org/traccar/protocol/GranitProtocol.java deleted file mode 100644 index 6785f2a2e..000000000 --- a/src/org/traccar/protocol/GranitProtocol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class GranitProtocol extends BaseProtocol { - - public GranitProtocol() { - setSupportedDataCommands( - Command.TYPE_IDENTIFICATION, - Command.TYPE_REBOOT_DEVICE, - Command.TYPE_POSITION_SINGLE); - setTextCommandEncoder(new GranitProtocolSmsEncoder()); - setSupportedTextCommands( - Command.TYPE_REBOOT_DEVICE, - Command.TYPE_POSITION_PERIODIC); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new GranitFrameDecoder()); - pipeline.addLast(new GranitProtocolEncoder()); - pipeline.addLast(new GranitProtocolDecoder(GranitProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/GranitProtocolDecoder.java b/src/org/traccar/protocol/GranitProtocolDecoder.java deleted file mode 100644 index 8900e5b39..000000000 --- a/src/org/traccar/protocol/GranitProtocolDecoder.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -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.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -public class GranitProtocolDecoder extends BaseProtocolDecoder { - - private static final int HEADER_LENGTH = 6; - - private double adc1Ratio; - private double adc2Ratio; - private double adc3Ratio; - private double adc4Ratio; - - public GranitProtocolDecoder(Protocol protocol) { - super(protocol); - adc1Ratio = Context.getConfig().getDouble("granit.adc1Ratio", 1); - adc2Ratio = Context.getConfig().getDouble("granit.adc2Ratio", 1); - adc3Ratio = Context.getConfig().getDouble("granit.adc3Ratio", 1); - adc4Ratio = Context.getConfig().getDouble("granit.adc4Ratio", 1); - } - - public static void appendChecksum(ByteBuf buffer, int length) { - buffer.writeByte('*'); - int checksum = Checksum.xor(buffer.nioBuffer(0, length)) & 0xFF; - String checksumString = String.format("%02X", checksum); - buffer.writeBytes(checksumString.getBytes(StandardCharsets.US_ASCII)); - buffer.writeByte('\r'); buffer.writeByte('\n'); - } - - private static void sendResponseCurrent(Channel channel, int deviceId, long time) { - ByteBuf response = Unpooled.buffer(); - response.writeBytes("BB+UGRC~".getBytes(StandardCharsets.US_ASCII)); - response.writeShortLE(6); // length - response.writeInt((int) time); - response.writeShortLE(deviceId); - appendChecksum(response, 16); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - - private static void sendResponseArchive(Channel channel, int deviceId, int packNum) { - ByteBuf response = Unpooled.buffer(); - response.writeBytes("BB+ARCF~".getBytes(StandardCharsets.US_ASCII)); - response.writeShortLE(4); // length - response.writeShortLE(packNum); - response.writeShortLE(deviceId); - appendChecksum(response, 14); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - - private void decodeStructure(ByteBuf buf, Position position) { - short flags = buf.readUnsignedByte(); - position.setValid(BitUtil.check(flags, 7)); - if (BitUtil.check(flags, 1)) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - - short satDel = buf.readUnsignedByte(); - position.set(Position.KEY_SATELLITES, BitUtil.from(satDel, 4)); - - int pdop = BitUtil.to(satDel, 4); - position.set(Position.KEY_PDOP, pdop); - - int lonDegrees = buf.readUnsignedByte(); - int latDegrees = buf.readUnsignedByte(); - int lonMinutes = buf.readUnsignedShortLE(); - int latMinutes = buf.readUnsignedShortLE(); - - double latitude = latDegrees + latMinutes / 60000.0; - double longitude = lonDegrees + lonMinutes / 60000.0; - - if (position.getValid()) { - if (!BitUtil.check(flags, 4)) { - latitude = -latitude; - } - if (!BitUtil.check(flags, 5)) { - longitude = -longitude; - } - } - - position.setLongitude(longitude); - position.setLatitude(latitude); - - position.setSpeed(buf.readUnsignedByte()); - - int course = buf.readUnsignedByte(); - if (BitUtil.check(flags, 6)) { - course = course | 0x100; - } - position.setCourse(course); - - position.set(Position.KEY_DISTANCE, buf.readShortLE()); - - int analogIn1 = buf.readUnsignedByte(); - int analogIn2 = buf.readUnsignedByte(); - int analogIn3 = buf.readUnsignedByte(); - int analogIn4 = buf.readUnsignedByte(); - - int analogInHi = buf.readUnsignedByte(); - - analogIn1 = analogInHi << 8 & 0x300 | analogIn1; - analogIn2 = analogInHi << 6 & 0x300 | analogIn2; - analogIn3 = analogInHi << 4 & 0x300 | analogIn3; - analogIn4 = analogInHi << 2 & 0x300 | analogIn4; - - position.set(Position.PREFIX_ADC + 1, analogIn1 * adc1Ratio); - position.set(Position.PREFIX_ADC + 2, analogIn2 * adc2Ratio); - position.set(Position.PREFIX_ADC + 3, analogIn3 * adc3Ratio); - position.set(Position.PREFIX_ADC + 4, analogIn4 * adc4Ratio); - - position.setAltitude(buf.readUnsignedByte() * 10); - - int output = buf.readUnsignedByte(); - for (int i = 0; i < 8; i++) { - position.set(Position.PREFIX_IO + (i + 1), BitUtil.check(output, i)); - } - buf.readUnsignedByte(); // status message buffer - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int indexTilde = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '~'); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - - if (deviceSession != null && indexTilde == -1) { - String bufString = buf.toString(StandardCharsets.US_ASCII); - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date()); - getLastLocation(position, new Date()); - position.setValid(false); - position.set(Position.KEY_RESULT, bufString); - return position; - } - - if (buf.readableBytes() < HEADER_LENGTH) { - return null; - } - String header = buf.readSlice(HEADER_LENGTH).toString(StandardCharsets.US_ASCII); - - if (header.equals("+RRCB~")) { - - buf.skipBytes(2); // binary length 26 - int deviceId = buf.readUnsignedShortLE(); - deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); - if (deviceSession == null) { - return null; - } - long unixTime = buf.readUnsignedIntLE(); - if (channel != null) { - sendResponseCurrent(channel, deviceId, unixTime); - } - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(unixTime * 1000)); - - decodeStructure(buf, position); - return position; - - } else if (header.equals("+DDAT~")) { - - buf.skipBytes(2); // binary length - int deviceId = buf.readUnsignedShortLE(); - deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); - if (deviceSession == null) { - return null; - } - byte format = buf.readByte(); - if (format != 4) { - return null; - } - byte nblocks = buf.readByte(); - int packNum = buf.readUnsignedShortLE(); - if (channel != null) { - sendResponseArchive(channel, deviceId, packNum); - } - List positions = new ArrayList<>(); - while (nblocks > 0) { - nblocks--; - long unixTime = buf.readUnsignedIntLE(); - int timeIncrement = buf.getUnsignedShortLE(buf.readerIndex() + 120); - for (int i = 0; i < 6; i++) { - if (buf.getUnsignedByte(buf.readerIndex()) != 0xFE) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(new Date((unixTime + i * timeIncrement) * 1000)); - decodeStructure(buf, position); - position.set(Position.KEY_ARCHIVE, true); - positions.add(position); - } else { - buf.skipBytes(20); // skip filled 0xFE structure - } - } - buf.skipBytes(2); // increment - } - return positions; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/GranitProtocolEncoder.java b/src/org/traccar/protocol/GranitProtocolEncoder.java deleted file mode 100644 index 6345ff971..000000000 --- a/src/org/traccar/protocol/GranitProtocolEncoder.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.nio.charset.StandardCharsets; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.model.Command; - -public class GranitProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeCommand(String commandString) { - ByteBuf buffer = Unpooled.buffer(); - buffer.writeBytes(commandString.getBytes(StandardCharsets.US_ASCII)); - GranitProtocolDecoder.appendChecksum(buffer, commandString.length()); - return buffer; - } - - @Override - protected Object encodeCommand(Command command) { - switch (command.getType()) { - case Command.TYPE_IDENTIFICATION: - return encodeCommand("BB+IDNT"); - case Command.TYPE_REBOOT_DEVICE: - return encodeCommand("BB+RESET"); - case Command.TYPE_POSITION_SINGLE: - return encodeCommand("BB+RRCD"); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/GranitProtocolSmsEncoder.java b/src/org/traccar/protocol/GranitProtocolSmsEncoder.java deleted file mode 100644 index 7d5518c17..000000000 --- a/src/org/traccar/protocol/GranitProtocolSmsEncoder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class GranitProtocolSmsEncoder extends StringProtocolEncoder { - - @Override - protected String encodeCommand(Command command) { - switch (command.getType()) { - case Command.TYPE_REBOOT_DEVICE: - return "BB+RESET"; - case Command.TYPE_POSITION_PERIODIC: - return formatCommand(command, "BB+BBMD={%s}", Command.KEY_FREQUENCY); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Gt02Protocol.java b/src/org/traccar/protocol/Gt02Protocol.java deleted file mode 100644 index f412ee720..000000000 --- a/src/org/traccar/protocol/Gt02Protocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Gt02Protocol extends BaseProtocol { - - public Gt02Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0)); - pipeline.addLast(new Gt02ProtocolDecoder(Gt02Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Gt02ProtocolDecoder.java b/src/org/traccar/protocol/Gt02ProtocolDecoder.java deleted file mode 100644 index 78a3fd3ee..000000000 --- a/src/org/traccar/protocol/Gt02ProtocolDecoder.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; - -public class Gt02ProtocolDecoder extends BaseProtocolDecoder { - - public Gt02ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_DATA = 0x10; - public static final int MSG_HEARTBEAT = 0x1A; - public static final int MSG_RESPONSE = 0x1C; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - buf.readByte(); // size - - Position position = new Position(getProtocolName()); - - // Zero for location messages - int power = buf.readUnsignedByte(); - int gsm = buf.readUnsignedByte(); - - String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, buf.readUnsignedShort()); - - int type = buf.readUnsignedByte(); - - if (type == MSG_HEARTBEAT) { - - getLastLocation(position, null); - - position.set(Position.KEY_POWER, power); - position.set(Position.KEY_RSSI, gsm); - - if (channel != null) { - byte[] response = {0x54, 0x68, 0x1A, 0x0D, 0x0A}; - channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(response), remoteAddress)); - } - - } else if (type == MSG_DATA) { - - DateBuilder dateBuilder = new DateBuilder() - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - double latitude = buf.readUnsignedInt() / (60.0 * 30000.0); - double longitude = buf.readUnsignedInt() / (60.0 * 30000.0); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.setCourse(buf.readUnsignedShort()); - - buf.skipBytes(3); // reserved - - long flags = buf.readUnsignedInt(); - position.setValid(BitUtil.check(flags, 0)); - if (!BitUtil.check(flags, 1)) { - latitude = -latitude; - } - if (!BitUtil.check(flags, 2)) { - longitude = -longitude; - } - - position.setLatitude(latitude); - position.setLongitude(longitude); - - } else if (type == MSG_RESPONSE) { - - getLastLocation(position, null); - - position.set(Position.KEY_RESULT, - buf.readSlice(buf.readUnsignedByte()).toString(StandardCharsets.US_ASCII)); - - } else { - - return null; - - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/Gt06FrameDecoder.java b/src/org/traccar/protocol/Gt06FrameDecoder.java deleted file mode 100644 index cc934be42..000000000 --- a/src/org/traccar/protocol/Gt06FrameDecoder.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class Gt06FrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 5) { - return null; - } - - int length = 2 + 2; // head and tail - - if (buf.getByte(buf.readerIndex()) == 0x78) { - length += 1 + buf.getUnsignedByte(buf.readerIndex() + 2); - } else { - length += 2 + buf.getUnsignedShort(buf.readerIndex() + 2); - } - - if (buf.readableBytes() >= length && buf.getUnsignedShort(buf.readerIndex() + length - 2) == 0x0d0a) { - return buf.readRetainedSlice(length); - } - - int endIndex = buf.readerIndex() - 1; - do { - endIndex = buf.indexOf(endIndex + 1, buf.writerIndex(), (byte) 0x0d); - if (endIndex > 0 && buf.writerIndex() > endIndex + 1 && buf.getByte(endIndex + 1) == 0x0a) { - return buf.readRetainedSlice(endIndex + 2 - buf.readerIndex()); - } - } while (endIndex > 0); - - return null; - } - -} diff --git a/src/org/traccar/protocol/Gt06Protocol.java b/src/org/traccar/protocol/Gt06Protocol.java deleted file mode 100644 index 6e5435cd4..000000000 --- a/src/org/traccar/protocol/Gt06Protocol.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class Gt06Protocol extends BaseProtocol { - - public Gt06Protocol() { - setSupportedDataCommands( - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_CUSTOM); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Gt06FrameDecoder()); - pipeline.addLast(new Gt06ProtocolEncoder()); - pipeline.addLast(new Gt06ProtocolDecoder(Gt06Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/org/traccar/protocol/Gt06ProtocolDecoder.java deleted file mode 100644 index 1f8fb66dd..000000000 --- a/src/org/traccar/protocol/Gt06ProtocolDecoder.java +++ /dev/null @@ -1,929 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BcdUtil; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Checksum; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Device; -import org.traccar.model.Network; -import org.traccar.model.Position; -import org.traccar.model.WifiAccessPoint; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; -import java.util.TimeZone; -import java.util.regex.Pattern; - -public class Gt06ProtocolDecoder extends BaseProtocolDecoder { - - private final Map photos = new HashMap<>(); - - public Gt06ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_LOGIN = 0x01; - public static final int MSG_GPS = 0x10; - public static final int MSG_LBS = 0x11; - public static final int MSG_GPS_LBS_1 = 0x12; - public static final int MSG_GPS_LBS_2 = 0x22; - public static final int MSG_STATUS = 0x13; - public static final int MSG_SATELLITE = 0x14; - public static final int MSG_STRING = 0x15; - public static final int MSG_GPS_LBS_STATUS_1 = 0x16; - public static final int MSG_WIFI = 0x17; - public static final int MSG_GPS_LBS_STATUS_2 = 0x26; - public static final int MSG_GPS_LBS_STATUS_3 = 0x27; - public static final int MSG_LBS_MULTIPLE = 0x28; - public static final int MSG_LBS_WIFI = 0x2C; - public static final int MSG_LBS_EXTEND = 0x18; - public static final int MSG_LBS_STATUS = 0x19; - public static final int MSG_GPS_PHONE = 0x1A; - public static final int MSG_GPS_LBS_EXTEND = 0x1E; - public static final int MSG_HEARTBEAT = 0x23; - public static final int MSG_ADDRESS_REQUEST = 0x2A; - public static final int MSG_ADDRESS_RESPONSE = 0x97; - public static final int MSG_AZ735_GPS = 0x32; - public static final int MSG_AZ735_ALARM = 0x33; - public static final int MSG_X1_GPS = 0x34; - public static final int MSG_X1_PHOTO_INFO = 0x35; - public static final int MSG_X1_PHOTO_DATA = 0x36; - public static final int MSG_WIFI_2 = 0x69; - public static final int MSG_COMMAND_0 = 0x80; - public static final int MSG_COMMAND_1 = 0x81; - public static final int MSG_COMMAND_2 = 0x82; - public static final int MSG_TIME_REQUEST = 0x8A; - public static final int MSG_INFO = 0x94; - public static final int MSG_STRING_INFO = 0x21; - public static final int MSG_GPS_2 = 0xA0; - public static final int MSG_LBS_2 = 0xA1; - public static final int MSG_WIFI_3 = 0xA2; - public static final int MSG_FENCE_SINGLE = 0xA3; - public static final int MSG_FENCE_MULTI = 0xA4; - public static final int MSG_LBS_ALARM = 0xA5; - public static final int MSG_LBS_ADDRESS = 0xA7; - public static final int MSG_OBD = 0x8C; - public static final int MSG_DTC = 0x65; - public static final int MSG_PID = 0x66; - - private static boolean isSupported(int type) { - return hasGps(type) || hasLbs(type) || hasStatus(type); - } - - private static boolean hasGps(int type) { - switch (type) { - case MSG_GPS: - case MSG_GPS_LBS_1: - case MSG_GPS_LBS_2: - case MSG_GPS_LBS_STATUS_1: - case MSG_GPS_LBS_STATUS_2: - case MSG_GPS_LBS_STATUS_3: - case MSG_GPS_PHONE: - case MSG_GPS_LBS_EXTEND: - case MSG_GPS_2: - case MSG_FENCE_SINGLE: - case MSG_FENCE_MULTI: - return true; - default: - return false; - } - } - - private static boolean hasLbs(int type) { - switch (type) { - case MSG_LBS: - case MSG_LBS_STATUS: - case MSG_GPS_LBS_1: - case MSG_GPS_LBS_2: - case MSG_GPS_LBS_STATUS_1: - case MSG_GPS_LBS_STATUS_2: - case MSG_GPS_LBS_STATUS_3: - case MSG_GPS_2: - case MSG_FENCE_SINGLE: - case MSG_FENCE_MULTI: - case MSG_LBS_ALARM: - case MSG_LBS_ADDRESS: - return true; - default: - return false; - } - } - - private static boolean hasStatus(int type) { - switch (type) { - case MSG_STATUS: - case MSG_LBS_STATUS: - case MSG_GPS_LBS_STATUS_1: - case MSG_GPS_LBS_STATUS_2: - case MSG_GPS_LBS_STATUS_3: - return true; - default: - return false; - } - } - - private static boolean hasLanguage(int type) { - switch (type) { - case MSG_GPS_PHONE: - case MSG_HEARTBEAT: - case MSG_GPS_LBS_STATUS_3: - case MSG_LBS_MULTIPLE: - case MSG_LBS_2: - case MSG_FENCE_MULTI: - return true; - default: - return false; - } - } - - private void sendResponse(Channel channel, boolean extended, int type, int index, ByteBuf content) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - int length = 5 + (content != null ? content.readableBytes() : 0); - if (extended) { - response.writeShort(0x7979); - response.writeShort(length); - } else { - response.writeShort(0x7878); - response.writeByte(length); - } - response.writeByte(type); - if (content != null) { - response.writeBytes(content); - content.release(); - } - response.writeShort(index); - response.writeShort(Checksum.crc16(Checksum.CRC16_X25, - response.nioBuffer(2, response.writerIndex() - 2))); - response.writeByte('\r'); response.writeByte('\n'); // ending - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - private void sendPhotoRequest(Channel channel, int pictureId) { - ByteBuf photo = photos.get(pictureId); - ByteBuf content = Unpooled.buffer(); - content.writeInt(pictureId); - content.writeInt(photo.writerIndex()); - content.writeShort(Math.min(photo.writableBytes(), 1024)); - sendResponse(channel, false, MSG_X1_PHOTO_DATA, 0, content); - } - - private boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) { - - DateBuilder dateBuilder = new DateBuilder(timezone) - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - if (hasLength && buf.readUnsignedByte() == 0) { - return false; - } - - position.set(Position.KEY_SATELLITES, BitUtil.to(buf.readUnsignedByte(), 4)); - - double latitude = buf.readUnsignedInt() / 60.0 / 30000.0; - double longitude = buf.readUnsignedInt() / 60.0 / 30000.0; - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - - int flags = buf.readUnsignedShort(); - position.setCourse(BitUtil.to(flags, 10)); - position.setValid(BitUtil.check(flags, 12)); - - if (!BitUtil.check(flags, 10)) { - latitude = -latitude; - } - if (BitUtil.check(flags, 11)) { - longitude = -longitude; - } - - position.setLatitude(latitude); - position.setLongitude(longitude); - - if (BitUtil.check(flags, 14)) { - position.set(Position.KEY_IGNITION, BitUtil.check(flags, 15)); - } - - return true; - } - - private boolean decodeLbs(Position position, ByteBuf buf, boolean hasLength) { - - int length = 0; - if (hasLength) { - length = buf.readUnsignedByte(); - if (length == 0) { - return false; - } - } - - int mcc = buf.readUnsignedShort(); - int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte(); - - position.setNetwork(new Network(CellTower.from( - BitUtil.to(mcc, 15), mnc, buf.readUnsignedShort(), buf.readUnsignedMedium()))); - - if (length > 9) { - buf.skipBytes(length - 9); - } - - return true; - } - - private boolean decodeStatus(Position position, ByteBuf buf) { - - int status = buf.readUnsignedByte(); - - position.set(Position.KEY_STATUS, status); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 1)); - position.set(Position.KEY_CHARGE, BitUtil.check(status, 2)); - position.set(Position.KEY_BLOCKED, BitUtil.check(status, 7)); - - switch (BitUtil.between(status, 3, 6)) { - case 1: - position.set(Position.KEY_ALARM, Position.ALARM_SHOCK); - break; - case 2: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - break; - case 3: - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case 4: - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - break; - case 7: - position.set(Position.KEY_ALARM, Position.ALARM_REMOVING); - break; - default: - break; - } - - position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 100 / 6); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); - - return true; - } - - private String decodeAlarm(short value) { - switch (value) { - case 0x01: - return Position.ALARM_SOS; - case 0x02: - return Position.ALARM_POWER_CUT; - case 0x03: - case 0x09: - return Position.ALARM_VIBRATION; - case 0x04: - return Position.ALARM_GEOFENCE_ENTER; - case 0x05: - return Position.ALARM_GEOFENCE_EXIT; - case 0x06: - return Position.ALARM_OVERSPEED; - case 0x0E: - case 0x0F: - return Position.ALARM_LOW_BATTERY; - case 0x11: - return Position.ALARM_POWER_OFF; - case 0x13: - return Position.ALARM_TAMPERING; - case 0x14: - return Position.ALARM_DOOR; - case 0x29: - return Position.ALARM_ACCELERATION; - case 0x30: - return Position.ALARM_BRAKING; - case 0x2A: - case 0x2B: - return Position.ALARM_CORNERING; - case 0x2C: - return Position.ALARM_ACCIDENT; - case 0x23: - return Position.ALARM_FALL_DOWN; - default: - return null; - } - } - - private static final Pattern PATTERN_FUEL = new PatternBuilder() - .text("!AIOIL,") - .number("d+,") // device address - .number("d+.d+,") // output value - .number("(d+.d+),") // temperature - .expression("[^,]+,") // version - .number("dd") // back wave - .number("d") // software status code - .number("d,") // hardware status code - .number("(d+.d+),") // measured value - .expression("[01],") // movement status - .number("d+,") // excited wave times - .number("xx") // checksum - .compile(); - - private Position decodeFuelData(Position position, String sentence) { - Parser parser = new Parser(PATTERN_FUEL, sentence); - if (!parser.matches()) { - return null; - } - - position.set(Position.PREFIX_TEMP + 1, parser.nextDouble(0)); - position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble(0)); - - return position; - } - - private static final Pattern PATTERN_LOCATION = new PatternBuilder() - .text("Current position!") - .number("Lat:([NS])(d+.d+),") // latitude - .number("Lon:([EW])(d+.d+),") // longitude - .text("Course:").number("(d+.d+),") // course - .text("Speed:").number("(d+.d+),") // speed - .text("DateTime:") - .number("(dddd)-(dd)-(dd) +") // date - .number("(dd):(dd):(dd)") // time - .compile(); - - private Position decodeLocationString(Position position, String sentence) { - Parser parser = new Parser(PATTERN_LOCATION, sentence); - if (!parser.matches()) { - return null; - } - - position.setValid(true); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setCourse(parser.nextDouble()); - position.setSpeed(parser.nextDouble()); - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS)); - - return position; - } - - private Object decodeBasic(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - int length = buf.readUnsignedByte(); - int dataLength = length - 5; - int type = buf.readUnsignedByte(); - - DeviceSession deviceSession = null; - if (type != MSG_LOGIN) { - deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - if (deviceSession.getTimeZone() == null) { - deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId())); - } - } - - if (type == MSG_LOGIN) { - - String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); - buf.readUnsignedShort(); // type - - deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession != null && deviceSession.getTimeZone() == null) { - deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId())); - } - - if (dataLength > 10) { - int extensionBits = buf.readUnsignedShort(); - int hours = (extensionBits >> 4) / 100; - int minutes = (extensionBits >> 4) % 100; - int offset = (hours * 60 + minutes) * 60; - if ((extensionBits & 0x8) != 0) { - offset = -offset; - } - if (deviceSession != null) { - TimeZone timeZone = deviceSession.getTimeZone(); - if (timeZone.getRawOffset() == 0) { - timeZone.setRawOffset(offset * 1000); - deviceSession.setTimeZone(timeZone); - } - } - - } - - if (deviceSession != null) { - sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); - } - - } else if (type == MSG_HEARTBEAT) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - int status = buf.readUnsignedByte(); - position.set(Position.KEY_ARMED, BitUtil.check(status, 0)); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 1)); - position.set(Position.KEY_CHARGE, BitUtil.check(status, 2)); - - if (buf.readableBytes() >= 2 + 6) { - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); - } - if (buf.readableBytes() >= 1 + 6) { - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - } - - sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); - - return position; - - } else if (type == MSG_ADDRESS_REQUEST) { - - String response = "NA&&NA&&0##"; - ByteBuf content = Unpooled.buffer(); - content.writeByte(response.length()); - content.writeInt(0); - content.writeBytes(response.getBytes(StandardCharsets.US_ASCII)); - sendResponse(channel, true, MSG_ADDRESS_RESPONSE, 0, content); - - } else if (type == MSG_TIME_REQUEST) { - - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - ByteBuf content = Unpooled.buffer(); - content.writeByte(calendar.get(Calendar.YEAR) - 2000); - content.writeByte(calendar.get(Calendar.MONTH) + 1); - content.writeByte(calendar.get(Calendar.DAY_OF_MONTH)); - content.writeByte(calendar.get(Calendar.HOUR_OF_DAY)); - content.writeByte(calendar.get(Calendar.MINUTE)); - content.writeByte(calendar.get(Calendar.SECOND)); - sendResponse(channel, false, MSG_TIME_REQUEST, 0, content); - - } else if (type == MSG_X1_GPS || type == MSG_X1_PHOTO_INFO) { - - return decodeX1(channel, buf, deviceSession, type); - - } else if (type == MSG_WIFI || type == MSG_WIFI_2) { - - return decodeWifi(channel, buf, deviceSession, type); - - } else if (type == MSG_INFO) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_POWER, buf.readShort() * 0.01); - - return position; - - } else { - - return decodeBasicOther(channel, buf, deviceSession, type, dataLength); - - } - - return null; - } - - private Object decodeX1(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) { - - if (type == MSG_X1_GPS) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedInt(); // data and alarm - - decodeGps(position, buf, false, deviceSession.getTimeZone()); - - buf.readUnsignedShort(); // terminal info - - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedByte(), - buf.readUnsignedShort(), buf.readUnsignedInt()))); - - long driverId = buf.readUnsignedInt(); - if (driverId > 0) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(driverId)); - } - - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01); - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); - - return position; - - } else if (type == MSG_X1_PHOTO_INFO) { - - buf.skipBytes(6); // time - buf.readUnsignedByte(); // fix status - buf.readUnsignedInt(); // latitude - buf.readUnsignedInt(); // longitude - buf.readUnsignedByte(); // camera id - buf.readUnsignedByte(); // photo source - buf.readUnsignedByte(); // picture format - - ByteBuf photo = Unpooled.buffer(buf.readInt()); - int pictureId = buf.readInt(); - photos.put(pictureId, photo); - sendPhotoRequest(channel, pictureId); - - } - - return null; - } - - private Object decodeWifi(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - ByteBuf time = buf.readSlice(6); - DateBuilder dateBuilder = new DateBuilder() - .setYear(BcdUtil.readInteger(time, 2)) - .setMonth(BcdUtil.readInteger(time, 2)) - .setDay(BcdUtil.readInteger(time, 2)) - .setHour(BcdUtil.readInteger(time, 2)) - .setMinute(BcdUtil.readInteger(time, 2)) - .setSecond(BcdUtil.readInteger(time, 2)); - getLastLocation(position, dateBuilder.getDate()); - - Network network = new Network(); - - int wifiCount = buf.getByte(2); - for (int i = 0; i < wifiCount; i++) { - String mac = String.format("%02x:%02x:%02x:%02x:%02x:%02x", - buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(), - buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - network.addWifiAccessPoint(WifiAccessPoint.from(mac, buf.readUnsignedByte())); - } - - int cellCount = buf.readUnsignedByte(); - int mcc = buf.readUnsignedShort(); - int mnc = buf.readUnsignedByte(); - for (int i = 0; i < cellCount; i++) { - network.addCellTower(CellTower.from( - mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte())); - } - - position.setNetwork(network); - - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeShort(0x7878); - response.writeByte(0); - response.writeByte(type); - response.writeBytes(time.resetReaderIndex()); - response.writeByte('\r'); - response.writeByte('\n'); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - - return position; - } - - private Object decodeBasicOther(Channel channel, ByteBuf buf, - DeviceSession deviceSession, int type, int dataLength) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (type == MSG_LBS_MULTIPLE || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI - || type == MSG_LBS_2 || type == MSG_WIFI_3) { - - boolean longFormat = type == MSG_LBS_2 || type == MSG_WIFI_3; - - DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone()) - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - - getLastLocation(position, dateBuilder.getDate()); - - int mcc = buf.readUnsignedShort(); - int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte(); - Network network = new Network(); - for (int i = 0; i < 7; i++) { - int lac = longFormat ? buf.readInt() : buf.readUnsignedShort(); - int cid = longFormat ? (int) buf.readLong() : buf.readUnsignedMedium(); - int rssi = -buf.readUnsignedByte(); - if (lac > 0) { - network.addCellTower(CellTower.from(BitUtil.to(mcc, 15), mnc, lac, cid, rssi)); - } - } - - buf.readUnsignedByte(); // time leads - - if (type != MSG_LBS_MULTIPLE && type != MSG_LBS_2) { - int wifiCount = buf.readUnsignedByte(); - for (int i = 0; i < wifiCount; i++) { - String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:"); - network.addWifiAccessPoint(WifiAccessPoint.from( - mac.substring(0, mac.length() - 1), buf.readUnsignedByte())); - } - } - - position.setNetwork(network); - - } else if (type == MSG_STRING) { - - getLastLocation(position, null); - - int commandLength = buf.readUnsignedByte(); - - if (commandLength > 0) { - buf.readUnsignedByte(); // server flag (reserved) - position.set(Position.KEY_RESULT, - buf.readSlice(commandLength - 1).toString(StandardCharsets.US_ASCII)); - } - - } else if (isSupported(type)) { - - if (hasGps(type)) { - decodeGps(position, buf, false, deviceSession.getTimeZone()); - } else { - getLastLocation(position, null); - } - - if (hasLbs(type)) { - decodeLbs(position, buf, hasStatus(type)); - } - - if (hasStatus(type)) { - decodeStatus(position, buf); - } - - if (type == MSG_GPS_LBS_1 && buf.readableBytes() == 2 + 6) { - int mask = buf.readUnsignedShort(); - position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(mask, 8 + 6)); - if (BitUtil.check(mask, 8 + 4)) { - int value = BitUtil.to(mask, 8 + 1); - if (BitUtil.check(mask, 8 + 1)) { - value = -value; - } - position.set(Position.PREFIX_TEMP + 1, value); - } else { - int value = BitUtil.to(mask, 8 + 2); - if (BitUtil.check(mask, 8 + 5)) { - position.set(Position.PREFIX_ADC + 1, value); - } else { - position.set(Position.PREFIX_ADC + 1, value * 0.1); - } - } - } - - if (type == MSG_GPS_LBS_1 && buf.readableBytes() == 4 + 6) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - } - - if (type == MSG_GPS_LBS_2 && buf.readableBytes() == 3 + 6) { - position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); // reason - position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0); - } - - } else { - - if (dataLength > 0) { - buf.skipBytes(dataLength); - } - if (type != MSG_COMMAND_0 && type != MSG_COMMAND_1 && type != MSG_COMMAND_2) { - sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); - } - return null; - - } - - if (hasLanguage(type)) { - buf.readUnsignedShort(); - } - - if (type == MSG_GPS_LBS_STATUS_3 || type == MSG_FENCE_MULTI) { - position.set(Position.KEY_GEOFENCE, buf.readUnsignedByte()); - } - - sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); - - return position; - } - - private Object decodeExtended(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - if (deviceSession.getTimeZone() == null) { - deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId())); - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedShort(); // length - int type = buf.readUnsignedByte(); - - if (type == MSG_STRING_INFO) { - - buf.readUnsignedInt(); // server flag - String data; - if (buf.readUnsignedByte() == 1) { - data = buf.readSlice(buf.readableBytes() - 6).toString(StandardCharsets.US_ASCII); - } else { - data = buf.readSlice(buf.readableBytes() - 6).toString(StandardCharsets.UTF_16BE); - } - - if (decodeLocationString(position, data) == null) { - getLastLocation(position, null); - position.set(Position.KEY_RESULT, data); - } - - return position; - - } else if (type == MSG_INFO) { - - int subType = buf.readUnsignedByte(); - - getLastLocation(position, null); - - if (subType == 0x00) { - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); - return position; - } else if (subType == 0x05) { - int flags = buf.readUnsignedByte(); - position.set(Position.KEY_DOOR, BitUtil.check(flags, 0)); - position.set(Position.PREFIX_IO + 1, BitUtil.check(flags, 2)); - return position; - } else if (subType == 0x0a) { - buf.skipBytes(8); // imei - buf.skipBytes(8); // imsi - position.set("iccid", ByteBufUtil.hexDump(buf.readSlice(8))); - return position; - } else if (subType == 0x0d) { - if (buf.getByte(buf.readerIndex()) != '!') { - buf.skipBytes(6); - } - return decodeFuelData(position, buf.toString( - buf.readerIndex(), buf.readableBytes() - 4 - 2, StandardCharsets.US_ASCII)); - } - - } else if (type == MSG_X1_PHOTO_DATA) { - - int pictureId = buf.readInt(); - - ByteBuf photo = photos.get(pictureId); - - buf.readUnsignedInt(); // offset - buf.readBytes(photo, buf.readUnsignedShort()); - - if (photo.writableBytes() > 0) { - sendPhotoRequest(channel, pictureId); - } else { - Device device = Context.getDeviceManager().getById(deviceSession.getDeviceId()); - position.set( - Position.KEY_IMAGE, Context.getMediaManager().writeFile(device.getUniqueId(), photo, "jpg")); - photos.remove(pictureId).release(); - } - - } else if (type == MSG_AZ735_GPS || type == MSG_AZ735_ALARM) { - - if (!decodeGps(position, buf, true, deviceSession.getTimeZone())) { - getLastLocation(position, position.getDeviceTime()); - } - - if (decodeLbs(position, buf, true)) { - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - } - - buf.skipBytes(buf.readUnsignedByte()); // additional cell towers - buf.skipBytes(buf.readUnsignedByte()); // wifi access point - - int status = buf.readUnsignedByte(); - position.set(Position.KEY_STATUS, status); - - if (type == MSG_AZ735_ALARM) { - switch (status) { - case 0xA0: - position.set(Position.KEY_ARMED, true); - break; - case 0xA1: - position.set(Position.KEY_ARMED, false); - break; - case 0xA2: - case 0xA3: - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case 0xA4: - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - break; - case 0xA5: - position.set(Position.KEY_ALARM, Position.ALARM_DOOR); - break; - default: - break; - } - } - - buf.skipBytes(buf.readUnsignedByte()); // reserved extension - - sendResponse(channel, true, type, buf.getShort(buf.writerIndex() - 6), null); - - return position; - - } else if (type == MSG_OBD) { - - DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone()) - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - - getLastLocation(position, dateBuilder.getDate()); - - position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0); - - String data = buf.readCharSequence(buf.readableBytes() - 18, StandardCharsets.US_ASCII).toString(); - for (String pair : data.split(",")) { - String[] values = pair.split("="); - switch (Integer.parseInt(values[0].substring(0, 2), 16)) { - case 40: - position.set(Position.KEY_ODOMETER, Integer.parseInt(values[1], 16) * 0.01); - break; - case 43: - position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(values[1], 16) * 0.01); - break; - case 45: - position.set(Position.KEY_COOLANT_TEMP, Integer.parseInt(values[1], 16) * 0.01); - break; - case 53: - position.set(Position.KEY_OBD_SPEED, Integer.parseInt(values[1], 16) * 0.01); - break; - case 54: - position.set(Position.KEY_RPM, Integer.parseInt(values[1], 16) * 0.01); - break; - case 71: - position.set(Position.KEY_FUEL_USED, Integer.parseInt(values[1], 16) * 0.01); - break; - case 73: - position.set(Position.KEY_HOURS, Integer.parseInt(values[1], 16) * 0.01); - break; - case 74: - position.set(Position.KEY_VIN, values[1]); - break; - default: - break; - } - } - - return position; - - } - - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int header = buf.readShort(); - - if (header == 0x7878) { - return decodeBasic(channel, remoteAddress, buf); - } else if (header == 0x7979) { - return decodeExtended(channel, remoteAddress, buf); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Gt06ProtocolEncoder.java b/src/org/traccar/protocol/Gt06ProtocolEncoder.java deleted file mode 100644 index 05560229f..000000000 --- a/src/org/traccar/protocol/Gt06ProtocolEncoder.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.Context; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class Gt06ProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeContent(long deviceId, String content) { - - boolean language = Context.getIdentityManager().lookupAttributeBoolean(deviceId, "gt06.language", false, true); - - ByteBuf buf = Unpooled.buffer(); - - buf.writeByte(0x78); - buf.writeByte(0x78); - - buf.writeByte(1 + 1 + 4 + content.length() + 2 + 2 + (language ? 2 : 0)); // message length - - buf.writeByte(0x80); // message type - - buf.writeByte(4 + content.length()); // command length - buf.writeInt(0); - buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); // command - - if (language) { - buf.writeShort(2); // english language - } - - buf.writeShort(0); // message index - - buf.writeShort(Checksum.crc16(Checksum.CRC16_X25, buf.nioBuffer(2, buf.writerIndex() - 2))); - - buf.writeByte('\r'); - buf.writeByte('\n'); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "gt06.alternative", false, true); - - switch (command.getType()) { - case Command.TYPE_ENGINE_STOP: - return encodeContent(command.getDeviceId(), alternative ? "DYD,123456#" : "Relay,1#"); - case Command.TYPE_ENGINE_RESUME: - return encodeContent(command.getDeviceId(), alternative ? "HFYD,123456#" : "Relay,0#"); - case Command.TYPE_CUSTOM: - return encodeContent(command.getDeviceId(), command.getString(Command.KEY_DATA)); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Gt30Protocol.java b/src/org/traccar/protocol/Gt30Protocol.java deleted file mode 100644 index aa4ad20b1..000000000 --- a/src/org/traccar/protocol/Gt30Protocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Gt30Protocol extends BaseProtocol { - - public Gt30Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Gt30ProtocolDecoder(Gt30Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Gt30ProtocolDecoder.java b/src/org/traccar/protocol/Gt30ProtocolDecoder.java deleted file mode 100644 index abf208a46..000000000 --- a/src/org/traccar/protocol/Gt30ProtocolDecoder.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Gt30ProtocolDecoder extends BaseProtocolDecoder { - - public Gt30ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$$") - .number("x{4}") // length - .expression("(.{14})") // device id - .number("x{4}") // type - .expression("(.)?") // alarm - .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+)?,") // speed - .number("(d+.d+)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .expression("[^\\|]*") - .number("|(d+.d+)") // hdop - .number("|(-?d+)") // altitude - .number("x{4}") // checksum - .compile(); - - private String decodeAlarm(int value) { - switch (value) { - case 0x01: - case 0x02: - case 0x03: - return Position.ALARM_SOS; - case 0x10: - return Position.ALARM_LOW_BATTERY; - case 0x11: - return Position.ALARM_OVERSPEED; - case 0x12: - return Position.ALARM_GEOFENCE; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next().trim()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.hasNext()) { - position.set(Position.KEY_ALARM, decodeAlarm(parser.next().charAt(0))); - } - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_HDOP, parser.nextDouble()); - - position.setAltitude(parser.nextDouble(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/H02FrameDecoder.java b/src/org/traccar/protocol/H02FrameDecoder.java deleted file mode 100644 index 583ad599f..000000000 --- a/src/org/traccar/protocol/H02FrameDecoder.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class H02FrameDecoder extends BaseFrameDecoder { - - private static final int MESSAGE_SHORT = 32; - private static final int MESSAGE_LONG = 45; - - private int messageLength; - - public H02FrameDecoder(int messageLength) { - this.messageLength = messageLength; - } - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - char marker = (char) buf.getByte(buf.readerIndex()); - - while (marker != '*' && marker != '$' && marker != 'X' && buf.readableBytes() > 0) { - buf.skipBytes(1); - if (buf.readableBytes() > 0) { - marker = (char) buf.getByte(buf.readerIndex()); - } - } - - switch (marker) { - case '*': - - // Return text message - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '#'); - if (index != -1) { - ByteBuf result = buf.readRetainedSlice(index + 1 - buf.readerIndex()); - while (buf.isReadable() - && (buf.getByte(buf.readerIndex()) == '\r' || buf.getByte(buf.readerIndex()) == '\n')) { - buf.readByte(); // skip new line - } - return result; - } - - break; - - case '$': - - if (messageLength == 0) { - if (buf.readableBytes() == MESSAGE_LONG) { - messageLength = MESSAGE_LONG; - } else { - messageLength = MESSAGE_SHORT; - } - } - - if (buf.readableBytes() >= messageLength) { - return buf.readRetainedSlice(messageLength); - } - - break; - - case 'X': - - if (buf.readableBytes() >= MESSAGE_SHORT) { - return buf.readRetainedSlice(MESSAGE_SHORT); - } - - break; - - default: - - return null; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/H02Protocol.java b/src/org/traccar/protocol/H02Protocol.java deleted file mode 100644 index 251beac5e..000000000 --- a/src/org/traccar/protocol/H02Protocol.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.Context; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class H02Protocol extends BaseProtocol { - - public H02Protocol() { - setSupportedDataCommands( - Command.TYPE_ALARM_ARM, - Command.TYPE_ALARM_DISARM, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_POSITION_PERIODIC - ); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - int messageLength = Context.getConfig().getInteger(getName() + ".messageLength"); - pipeline.addLast(new H02FrameDecoder(messageLength)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new H02ProtocolEncoder()); - pipeline.addLast(new H02ProtocolDecoder(H02Protocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new H02ProtocolEncoder()); - pipeline.addLast(new H02ProtocolDecoder(H02Protocol.this)); - } - }); - } -} diff --git a/src/org/traccar/protocol/H02ProtocolDecoder.java b/src/org/traccar/protocol/H02ProtocolDecoder.java deleted file mode 100644 index c4443a00b..000000000 --- a/src/org/traccar/protocol/H02ProtocolDecoder.java +++ /dev/null @@ -1,583 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BcdUtil; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; -import java.util.regex.Pattern; - -public class H02ProtocolDecoder extends BaseProtocolDecoder { - - public H02ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static double readCoordinate(ByteBuf buf, boolean lon) { - - int degrees = BcdUtil.readInteger(buf, 2); - if (lon) { - degrees = degrees * 10 + (buf.getUnsignedByte(buf.readerIndex()) >> 4); - } - - double result = 0; - if (lon) { - result = buf.readUnsignedByte() & 0x0f; - } - - int length = 6; - if (lon) { - length = 5; - } - - result = result * 10 + BcdUtil.readInteger(buf, length) * 0.0001; - - result /= 60; - result += degrees; - - return result; - } - - private void processStatus(Position position, long status) { - - if (!BitUtil.check(status, 0)) { - position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION); - } else if (!BitUtil.check(status, 1) || !BitUtil.check(status, 18)) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } else if (!BitUtil.check(status, 2)) { - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - } else if (!BitUtil.check(status, 19)) { - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - } - - position.set(Position.KEY_IGNITION, BitUtil.check(status, 10)); - position.set(Position.KEY_STATUS, status); - - } - - private Integer decodeBattery(int value) { - switch (value) { - case 6: - return 100; - case 5: - return 80; - case 4: - return 60; - case 3: - return 20; - case 2: - return 10; - default: - return null; - } - } - - private Position decodeBinary(ByteBuf buf, Channel channel, SocketAddress remoteAddress) { - - Position position = new Position(getProtocolName()); - - boolean longId = buf.readableBytes() == 42; - - buf.readByte(); // marker - - String id; - if (longId) { - id = ByteBufUtil.hexDump(buf.readSlice(8)).substring(0, 15); - } else { - id = ByteBufUtil.hexDump(buf.readSlice(5)); - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setHour(BcdUtil.readInteger(buf, 2)) - .setMinute(BcdUtil.readInteger(buf, 2)) - .setSecond(BcdUtil.readInteger(buf, 2)) - .setDay(BcdUtil.readInteger(buf, 2)) - .setMonth(BcdUtil.readInteger(buf, 2)) - .setYear(BcdUtil.readInteger(buf, 2)); - position.setTime(dateBuilder.getDate()); - - double latitude = readCoordinate(buf, false); - position.set(Position.KEY_BATTERY_LEVEL, decodeBattery(buf.readUnsignedByte())); - double longitude = readCoordinate(buf, true); - - int flags = buf.readUnsignedByte() & 0x0f; - position.setValid((flags & 0x02) != 0); - if ((flags & 0x04) == 0) { - latitude = -latitude; - } - if ((flags & 0x08) == 0) { - longitude = -longitude; - } - - position.setLatitude(latitude); - position.setLongitude(longitude); - - position.setSpeed(BcdUtil.readInteger(buf, 3)); - position.setCourse((buf.readUnsignedByte() & 0x0f) * 100.0 + BcdUtil.readInteger(buf, 2)); - - processStatus(position, buf.readUnsignedInt()); - - return position; - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("*") - .expression("..,") // manufacturer - .number("(d+)?,") // imei - .groupBegin() - .text("V4,") - .expression("(.*),") // response - .or() - .expression("(V[^,]*),") - .groupEnd() - .number("(?:(dd)(dd)(dd))?,") // time (hhmmss) - .groupBegin() - .expression("([ABV])?,") // validity - .or() - .number("(d+),") // coding scheme - .groupEnd() - .groupBegin() - .number("-(d+)-(d+.d+),") // latitude - .or() - .number("(d+)(dd.d+),") // latitude - .groupEnd() - .expression("([NS]),") - .groupBegin() - .number("-(d+)-(d+.d+),") // longitude - .or() - .number("(d+)(dd.d+),") // longitude - .groupEnd() - .expression("([EW]),") - .number("(d+.?d*),") // speed - .number("(d+.?d*)?,") // course - .number("(?:d+,)?") // battery - .number("(?:(dd)(dd)(dd))?") // date (ddmmyy) - .groupBegin() - .expression(",[^,]*,") - .expression("[^,]*,") - .expression("[^,]*") // sim info - .groupEnd("?") - .groupBegin() - .number(",(x{8})") - .groupBegin() - .number(",(d+),") // odometer - .number("(-?d+),") // temperature - .number("(d+.d+),") // fuel - .number("(-?d+),") // altitude - .number("(x+),") // lac - .number("(x+)") // cid - .or() - .text(",") - .expression("(.*)") // data - .or() - .groupEnd() - .or() - .groupEnd() - .text("#") - .compile(); - - private static final Pattern PATTERN_NBR = new PatternBuilder() - .text("*") - .expression("..,") // manufacturer - .number("(d+),") // imei - .text("NBR,") - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("d+,") // gsm delay time - .number("d+,") // count - .number("((?:d+,d+,d+,)+)") // cells - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(x{8})") // status - .any() - .compile(); - - private static final Pattern PATTERN_LINK = new PatternBuilder() - .text("*") - .expression("..,") // manufacturer - .number("(d+),") // imei - .text("LINK,") - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d+),") // rssi - .number("(d+),") // satellites - .number("(d+),") // battery - .number("(d+),") // steps - .number("(d+),") // turnovers - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(x{8})") // status - .any() - .compile(); - - private static final Pattern PATTERN_V3 = new PatternBuilder() - .text("*") - .expression("..,") // manufacturer - .number("(d+),") // imei - .text("V3,") - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(ddd)") // mcc - .number("(d+),") // mnc - .number("(d+),") // count - .expression("(.*),") // cell info - .number("(x{4}),") // battery - .number("d+,") // reboot info - .text("X,") - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(x{8})") // status - .text("#").optional() - .compile(); - - private static final Pattern PATTERN_VP1 = new PatternBuilder() - .text("*hq,") - .number("(d{15}),") // imei - .text("VP1,") - .groupBegin() - .text("V,") - .number("(d+),") // mcc - .number("(d+),") // mnc - .expression("([^#]+)") // cells - .or() - .expression("[AB],") // validity - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+),") // speed - .number("(d+.d+),") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .groupEnd() - .any() - .compile(); - - private void sendResponse(Channel channel, SocketAddress remoteAddress, String id, String type) { - if (channel != null && id != null) { - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - String response = String.format("*HQ,%s,V4,%s,%s#", id, type, dateFormat.format(new Date())); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - private Position decodeText(String sentence, Channel channel, SocketAddress remoteAddress) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - String id = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.hasNext()) { - position.set(Position.KEY_RESULT, parser.next()); - } - - if (parser.hasNext() && parser.next().equals("V1")) { - sendResponse(channel, remoteAddress, id, "V1"); - } - - DateBuilder dateBuilder = new DateBuilder(); - if (parser.hasNext(3)) { - dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - } - - if (parser.hasNext()) { - position.setValid(parser.next().equals("A")); - } - if (parser.hasNext()) { - parser.nextInt(); // coding scheme - position.setValid(true); - } - - if (parser.hasNext(2)) { - position.setLatitude(-parser.nextCoordinate()); - } - if (parser.hasNext(2)) { - position.setLatitude(parser.nextCoordinate()); - } - - if (parser.hasNext(2)) { - position.setLongitude(-parser.nextCoordinate()); - } - if (parser.hasNext(2)) { - position.setLongitude(parser.nextCoordinate()); - } - - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - if (parser.hasNext(3)) { - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - } else { - position.setTime(new Date()); - } - - if (parser.hasNext()) { - processStatus(position, parser.nextLong(16, 0)); - } - - if (parser.hasNext(6)) { - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); - position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble(0)); - - position.setAltitude(parser.nextInt(0)); - - position.setNetwork(new Network(CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0)))); - } - - if (parser.hasNext(4)) { - String[] values = parser.next().split(","); - for (int i = 0; i < values.length; i++) { - position.set(Position.PREFIX_IO + (i + 1), values[i].trim()); - } - } - - return position; - } - - private Position decodeLbs(String sentence, Channel channel, SocketAddress remoteAddress) { - - Parser parser = new Parser(PATTERN_NBR, sentence); - if (!parser.matches()) { - return null; - } - - String id = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - sendResponse(channel, remoteAddress, id, "NBR"); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - Network network = new Network(); - int mcc = parser.nextInt(0); - int mnc = parser.nextInt(0); - - String[] cells = parser.next().split(","); - for (int i = 0; i < cells.length / 3; i++) { - network.addCellTower(CellTower.from(mcc, mnc, Integer.parseInt(cells[i * 3]), - Integer.parseInt(cells[i * 3 + 1]), Integer.parseInt(cells[i * 3 + 2]))); - } - - position.setNetwork(network); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - getLastLocation(position, dateBuilder.getDate()); - - processStatus(position, parser.nextLong(16, 0)); - - return position; - } - - private Position decodeLink(String sentence, Channel channel, SocketAddress remoteAddress) { - - Parser parser = new Parser(PATTERN_LINK, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.set(Position.KEY_RSSI, parser.nextInt()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - position.set(Position.KEY_STEPS, parser.nextInt()); - position.set("turnovers", parser.nextInt()); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - getLastLocation(position, dateBuilder.getDate()); - - processStatus(position, parser.nextLong(16, 0)); - - return position; - } - - private Position decodeV3(String sentence, Channel channel, SocketAddress remoteAddress) { - - Parser parser = new Parser(PATTERN_V3, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - int mcc = parser.nextInt(); - int mnc = parser.nextInt(); - - int count = parser.nextInt(); - Network network = new Network(); - String[] values = parser.next().split(","); - for (int i = 0; i < count; i++) { - network.addCellTower(CellTower.from( - mcc, mnc, Integer.parseInt(values[i * 4]), Integer.parseInt(values[i * 4 + 1]))); - } - position.setNetwork(network); - - position.set(Position.KEY_BATTERY, parser.nextHexInt()); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - getLastLocation(position, dateBuilder.getDate()); - - processStatus(position, parser.nextLong(16, 0)); - - return position; - } - - private Position decodeVp1(String sentence, Channel channel, SocketAddress remoteAddress) { - - Parser parser = new Parser(PATTERN_VP1, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.hasNext(3)) { - - getLastLocation(position, null); - - int mcc = parser.nextInt(); - int mnc = parser.nextInt(); - - Network network = new Network(); - for (String cell : parser.next().split("Y")) { - String[] values = cell.split(","); - network.addCellTower(CellTower.from(mcc, mnc, - Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2]))); - } - - position.setNetwork(network); - - } else { - - position.setValid(true); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble()); - position.setCourse(parser.nextDouble()); - - position.setTime(new DateBuilder() - .setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)).getDate()); - - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - String marker = buf.toString(0, 1, StandardCharsets.US_ASCII); - - switch (marker) { - case "*": - String sentence = buf.toString(StandardCharsets.US_ASCII).trim(); - int typeStart = sentence.indexOf(',', sentence.indexOf(',') + 1) + 1; - int typeEnd = sentence.indexOf(',', typeStart); - if (typeEnd > 0) { - String type = sentence.substring(typeStart, typeEnd); - switch (type) { - case "NBR": - return decodeLbs(sentence, channel, remoteAddress); - case "LINK": - return decodeLink(sentence, channel, remoteAddress); - case "V3": - return decodeV3(sentence, channel, remoteAddress); - case "VP1": - return decodeVp1(sentence, channel, remoteAddress); - default: - return decodeText(sentence, channel, remoteAddress); - } - } else { - return null; - } - case "$": - return decodeBinary(buf, channel, remoteAddress); - case "X": - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/H02ProtocolEncoder.java b/src/org/traccar/protocol/H02ProtocolEncoder.java deleted file mode 100644 index 614a07dd1..000000000 --- a/src/org/traccar/protocol/H02ProtocolEncoder.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com) - * Copyright 2016 - 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. - * 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 org.traccar.Context; -import org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -import java.util.Date; - -public class H02ProtocolEncoder extends StringProtocolEncoder { - - private static final String MARKER = "HQ"; - - private Object formatCommand(Date time, String uniqueId, String type, String... params) { - - StringBuilder result = new StringBuilder( - String.format("*%s,%s,%s,%4$tH%4$tM%4$tS", MARKER, uniqueId, type, time)); - - for (String param : params) { - result.append(",").append(param); - } - - result.append("#"); - - return result.toString(); - } - - protected Object encodeCommand(Command command, Date time) { - String uniqueId = getUniqueId(command.getDeviceId()); - - switch (command.getType()) { - case Command.TYPE_ALARM_ARM: - return formatCommand(time, uniqueId, "SCF", "0", "0"); - case Command.TYPE_ALARM_DISARM: - return formatCommand(time, uniqueId, "SCF", "1", "1"); - case Command.TYPE_ENGINE_STOP: - return formatCommand(time, uniqueId, "S20", "1", "1"); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(time, uniqueId, "S20", "1", "0"); - case Command.TYPE_POSITION_PERIODIC: - String frequency = command.getAttributes().get(Command.KEY_FREQUENCY).toString(); - if (Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "h02.alternative", false, true)) { - return formatCommand(time, uniqueId, "D1", frequency); - } else { - return formatCommand(time, uniqueId, "S71", "22", frequency); - } - default: - return null; - } - } - - @Override - protected Object encodeCommand(Command command) { - return encodeCommand(command, new Date()); - } - -} diff --git a/src/org/traccar/protocol/HaicomProtocol.java b/src/org/traccar/protocol/HaicomProtocol.java deleted file mode 100644 index 6e5760bd4..000000000 --- a/src/org/traccar/protocol/HaicomProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class HaicomProtocol extends BaseProtocol { - - public HaicomProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '*')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new HaicomProtocolDecoder(HaicomProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/HaicomProtocolDecoder.java b/src/org/traccar/protocol/HaicomProtocolDecoder.java deleted file mode 100644 index dd20f2aeb..000000000 --- a/src/org/traccar/protocol/HaicomProtocolDecoder.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class HaicomProtocolDecoder extends BaseProtocolDecoder { - - public HaicomProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$GPRS") - .number("(d+),") // imei - .expression("([^,]+),") // version - .number("(dd)(dd)(dd),") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d)") // flags - .number("(dd)(d{5})") // latitude - .number("(ddd)(d{5}),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+),") // status - .number("(d+)?,") // gprs counting value - .number("(d+)?,") // gps power saving counting value - .number("(d+),") // switch status - .number("(d+)") // relay status - .expression("(?:[LH]{2})?") // power status - .number("#V(d+)") // battery - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_VERSION_FW, parser.next()); - - position.setTime(parser.nextDateTime()); - - int flags = parser.nextInt(0); - - position.setValid(BitUtil.check(flags, 0)); - - double latitude = parser.nextDouble(0) + parser.nextDouble(0) / 60000; - if (BitUtil.check(flags, 2)) { - position.setLatitude(latitude); - } else { - position.setLatitude(-latitude); - } - - double longitude = parser.nextDouble(0) + parser.nextDouble(0) / 60000; - if (BitUtil.check(flags, 1)) { - position.setLongitude(longitude); - } else { - position.setLongitude(-longitude); - } - - position.setSpeed(parser.nextDouble(0) / 10); - position.setCourse(parser.nextDouble(0) / 10); - - position.set(Position.KEY_STATUS, parser.next()); - position.set("gprsCount", parser.next()); - position.set("powersaveCountdown", parser.next()); - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1); - - return position; - } - -} diff --git a/src/org/traccar/protocol/HomtecsProtocol.java b/src/org/traccar/protocol/HomtecsProtocol.java deleted file mode 100644 index 34dbf0f51..000000000 --- a/src/org/traccar/protocol/HomtecsProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class HomtecsProtocol extends BaseProtocol { - - public HomtecsProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new HomtecsProtocolDecoder(HomtecsProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/HomtecsProtocolDecoder.java b/src/org/traccar/protocol/HomtecsProtocolDecoder.java deleted file mode 100644 index a93572b5c..000000000 --- a/src/org/traccar/protocol/HomtecsProtocolDecoder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class HomtecsProtocolDecoder extends BaseProtocolDecoder { - - public HomtecsProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("([^_]+)") // id - .text("_R") - .number("(x{8}),") // mac ending - .number("(dd)(dd)(dd),") // date (yymmdd) - .number("(dd)(dd)(dd).d+,") // time (hhmmss) - .number("(d+),") // satellites - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(d),") // fix status - .number("(d+.?d*)?,") // hdop - .number("(d+.?d*)?") // altitude - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - String id = parser.next(); - String mac = parser.next(); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id, id + "_R" + mac); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.setValid(parser.nextInt(0) > 0); - - position.set(Position.KEY_HDOP, parser.nextDouble(0)); - - position.setAltitude(parser.nextDouble(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/HuaShengFrameDecoder.java b/src/org/traccar/protocol/HuaShengFrameDecoder.java deleted file mode 100644 index bd52aa9e7..000000000 --- a/src/org/traccar/protocol/HuaShengFrameDecoder.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class HuaShengFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 2) { - return null; - } - - int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0xC0); - if (index != -1) { - ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex()); - - while (buf.readerIndex() <= index) { - int b = buf.readUnsignedByte(); - if (b == 0xDB) { - int ext = buf.readUnsignedByte(); - if (ext == 0xDC) { - result.writeByte(0xC0); - } else if (ext == 0xDD) { - result.writeByte(0xDB); - } - } else { - result.writeByte(b); - } - } - - return result; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/HuaShengProtocol.java b/src/org/traccar/protocol/HuaShengProtocol.java deleted file mode 100644 index 103f2d501..000000000 --- a/src/org/traccar/protocol/HuaShengProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class HuaShengProtocol extends BaseProtocol { - - public HuaShengProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HuaShengFrameDecoder()); - pipeline.addLast(new HuaShengProtocolDecoder(HuaShengProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/org/traccar/protocol/HuaShengProtocolDecoder.java deleted file mode 100644 index 8a937a194..000000000 --- a/src/org/traccar/protocol/HuaShengProtocolDecoder.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; - -public class HuaShengProtocolDecoder extends BaseProtocolDecoder { - - public HuaShengProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_POSITION = 0xAA00; - public static final int MSG_POSITION_RSP = 0xFF01; - public static final int MSG_LOGIN = 0xAA02; - public static final int MSG_LOGIN_RSP = 0xFF03; - public static final int MSG_HSO_REQ = 0x0002; - public static final int MSG_HSO_RSP = 0x0003; - - private void sendResponse(Channel channel, int type, int index, ByteBuf content) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(0xC0); - response.writeShort(0x0100); - response.writeShort(12 + (content != null ? content.readableBytes() : 0)); - response.writeShort(type); - response.writeShort(0); - response.writeInt(index); - if (content != null) { - response.writeBytes(content); - content.release(); - } - response.writeByte(0xC0); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(1); // start marker - buf.readUnsignedByte(); // flag - buf.readUnsignedByte(); // reserved - buf.readUnsignedShort(); // length - - int type = buf.readUnsignedShort(); - - buf.readUnsignedShort(); // checksum - int index = buf.readInt(); - - if (type == MSG_LOGIN) { - - while (buf.readableBytes() > 4) { - int subtype = buf.readUnsignedShort(); - int length = buf.readUnsignedShort() - 4; - if (subtype == 0x0003) { - String imei = buf.readSlice(length).toString(StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession != null && channel != null) { - ByteBuf content = Unpooled.buffer(); - content.writeByte(0); // success - sendResponse(channel, MSG_LOGIN_RSP, index, content); - } - } else { - buf.skipBytes(length); - } - } - - } else if (type == MSG_HSO_REQ) { - - sendResponse(channel, MSG_HSO_RSP, index, null); - - } else if (type == MSG_POSITION) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - int status = buf.readUnsignedShort(); - - position.setValid(BitUtil.check(status, 15)); - - position.set(Position.KEY_STATUS, status); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 14)); - position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - - String time = buf.readSlice(12).toString(StandardCharsets.US_ASCII); - - DateBuilder dateBuilder = new DateBuilder() - .setYear(Integer.parseInt(time.substring(0, 2))) - .setMonth(Integer.parseInt(time.substring(2, 4))) - .setDay(Integer.parseInt(time.substring(4, 6))) - .setHour(Integer.parseInt(time.substring(6, 8))) - .setMinute(Integer.parseInt(time.substring(8, 10))) - .setSecond(Integer.parseInt(time.substring(10, 12))); - position.setTime(dateBuilder.getDate()); - - position.setLongitude(buf.readInt() * 0.00001); - position.setLatitude(buf.readInt() * 0.00001); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - position.setCourse(buf.readUnsignedShort()); - position.setAltitude(buf.readUnsignedShort()); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000); - - while (buf.readableBytes() > 4) { - buf.readUnsignedShort(); // subtype - int length = buf.readUnsignedShort() - 4; - buf.skipBytes(length); - } - - sendResponse(channel, MSG_POSITION_RSP, index, null); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/HuabaoFrameDecoder.java b/src/org/traccar/protocol/HuabaoFrameDecoder.java deleted file mode 100644 index b520f6be9..000000000 --- a/src/org/traccar/protocol/HuabaoFrameDecoder.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class HuabaoFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 2) { - return null; - } - - int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0x7e); - if (index != -1) { - ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex()); - - while (buf.readerIndex() <= index) { - int b = buf.readUnsignedByte(); - if (b == 0x7d) { - int ext = buf.readUnsignedByte(); - if (ext == 0x01) { - result.writeByte(0x7d); - } else if (ext == 0x02) { - result.writeByte(0x7e); - } - } else { - result.writeByte(b); - } - } - - return result; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/HuabaoProtocol.java b/src/org/traccar/protocol/HuabaoProtocol.java deleted file mode 100644 index 44c9f7ac7..000000000 --- a/src/org/traccar/protocol/HuabaoProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class HuabaoProtocol extends BaseProtocol { - - public HuabaoProtocol() { - setSupportedDataCommands( - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HuabaoFrameDecoder()); - pipeline.addLast(new HuabaoProtocolEncoder()); - pipeline.addLast(new HuabaoProtocolDecoder(HuabaoProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/org/traccar/protocol/HuabaoProtocolDecoder.java deleted file mode 100644 index 6e2e1377b..000000000 --- a/src/org/traccar/protocol/HuabaoProtocolDecoder.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BcdUtil; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Checksum; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.LinkedList; -import java.util.List; - -public class HuabaoProtocolDecoder extends BaseProtocolDecoder { - - public HuabaoProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_GENERAL_RESPONSE = 0x8001; - public static final int MSG_TERMINAL_REGISTER = 0x0100; - public static final int MSG_TERMINAL_REGISTER_RESPONSE = 0x8100; - public static final int MSG_TERMINAL_CONTROL = 0x8105; - public static final int MSG_TERMINAL_AUTH = 0x0102; - public static final int MSG_LOCATION_REPORT = 0x0200; - public static final int MSG_LOCATION_BATCH = 0x0704; - public static final int MSG_OIL_CONTROL = 0XA006; - - public static final int RESULT_SUCCESS = 0; - - public static ByteBuf formatMessage(int type, ByteBuf id, ByteBuf data) { - ByteBuf buf = Unpooled.buffer(); - buf.writeByte(0x7e); - buf.writeShort(type); - buf.writeShort(data.readableBytes()); - buf.writeBytes(id); - buf.writeShort(1); // index - buf.writeBytes(data); - data.release(); - buf.writeByte(Checksum.xor(buf.nioBuffer(1, buf.readableBytes() - 1))); - buf.writeByte(0x7e); - return buf; - } - - private void sendGeneralResponse( - Channel channel, SocketAddress remoteAddress, ByteBuf id, int type, int index) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeShort(index); - response.writeShort(type); - response.writeByte(RESULT_SUCCESS); - channel.writeAndFlush(new NetworkMessage( - formatMessage(MSG_GENERAL_RESPONSE, id, response), remoteAddress)); - } - } - - private String decodeAlarm(long value) { - if (BitUtil.check(value, 0)) { - return Position.ALARM_SOS; - } - if (BitUtil.check(value, 1)) { - return Position.ALARM_OVERSPEED; - } - if (BitUtil.check(value, 5)) { - return Position.ALARM_GPS_ANTENNA_CUT; - } - if (BitUtil.check(value, 4) || BitUtil.check(value, 9) - || BitUtil.check(value, 10) || BitUtil.check(value, 11)) { - return Position.ALARM_FAULT; - } - if (BitUtil.check(value, 8)) { - return Position.ALARM_POWER_OFF; - } - if (BitUtil.check(value, 20)) { - return Position.ALARM_GEOFENCE; - } - if (BitUtil.check(value, 29)) { - return Position.ALARM_ACCIDENT; - } - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedByte(); // start marker - int type = buf.readUnsignedShort(); - buf.readUnsignedShort(); // body length - ByteBuf id = buf.readSlice(6); // phone number - int index = buf.readUnsignedShort(); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(id)); - if (deviceSession == null) { - return null; - } - - if (deviceSession.getTimeZone() == null) { - deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId(), "GMT+8")); - } - - if (type == MSG_TERMINAL_REGISTER) { - - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeShort(index); - response.writeByte(RESULT_SUCCESS); - response.writeBytes("authentication".getBytes(StandardCharsets.US_ASCII)); - channel.writeAndFlush(new NetworkMessage( - formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, response), remoteAddress)); - } - - } else if (type == MSG_TERMINAL_AUTH) { - - sendGeneralResponse(channel, remoteAddress, id, type, index); - - } else if (type == MSG_LOCATION_REPORT) { - - return decodeLocation(deviceSession, buf); - - } else if (type == MSG_LOCATION_BATCH) { - - return decodeLocationBatch(deviceSession, buf); - - } - - return null; - } - - private Position decodeLocation(DeviceSession deviceSession, ByteBuf buf) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedInt())); - - int flags = buf.readInt(); - - position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0)); - - position.setValid(BitUtil.check(flags, 1)); - - double lat = buf.readUnsignedInt() * 0.000001; - double lon = buf.readUnsignedInt() * 0.000001; - - if (BitUtil.check(flags, 2)) { - position.setLatitude(-lat); - } else { - position.setLatitude(lat); - } - - if (BitUtil.check(flags, 3)) { - position.setLongitude(-lon); - } else { - position.setLongitude(lon); - } - - position.setAltitude(buf.readShort()); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1)); - position.setCourse(buf.readUnsignedShort()); - - DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone()) - .setYear(BcdUtil.readInteger(buf, 2)) - .setMonth(BcdUtil.readInteger(buf, 2)) - .setDay(BcdUtil.readInteger(buf, 2)) - .setHour(BcdUtil.readInteger(buf, 2)) - .setMinute(BcdUtil.readInteger(buf, 2)) - .setSecond(BcdUtil.readInteger(buf, 2)); - position.setTime(dateBuilder.getDate()); - - while (buf.readableBytes() > 2) { - int subtype = buf.readUnsignedByte(); - int length = buf.readUnsignedByte(); - switch (subtype) { - case 0x01: - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100); - break; - case 0x30: - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - break; - case 0x31: - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - break; - default: - buf.skipBytes(length); - break; - } - } - - return position; - } - - private List decodeLocationBatch(DeviceSession deviceSession, ByteBuf buf) { - - List positions = new LinkedList<>(); - - int count = buf.readUnsignedShort(); - buf.readUnsignedByte(); // location type - - for (int i = 0; i < count; i++) { - int endIndex = buf.readUnsignedShort() + buf.readerIndex(); - positions.add(decodeLocation(deviceSession, buf)); - buf.readerIndex(endIndex); - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/HuabaoProtocolEncoder.java b/src/org/traccar/protocol/HuabaoProtocolEncoder.java deleted file mode 100644 index 7759790c4..000000000 --- a/src/org/traccar/protocol/HuabaoProtocolEncoder.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.Context; -import org.traccar.helper.DataConverter; -import org.traccar.model.Command; - -import java.text.SimpleDateFormat; -import java.util.Date; - -public class HuabaoProtocolEncoder extends BaseProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "huabao.alternative", false, true); - - ByteBuf id = Unpooled.wrappedBuffer( - DataConverter.parseHex(getUniqueId(command.getDeviceId()))); - try { - ByteBuf data = Unpooled.buffer(); - byte[] time = DataConverter.parseHex(new SimpleDateFormat("yyMMddHHmmss").format(new Date())); - - switch (command.getType()) { - case Command.TYPE_ENGINE_STOP: - if (alternative) { - data.writeByte(0x01); - data.writeBytes(time); - return HuabaoProtocolDecoder.formatMessage( - HuabaoProtocolDecoder.MSG_OIL_CONTROL, id, data); - } else { - data.writeByte(0xf0); - return HuabaoProtocolDecoder.formatMessage( - HuabaoProtocolDecoder.MSG_TERMINAL_CONTROL, id, data); - } - case Command.TYPE_ENGINE_RESUME: - if (alternative) { - data.writeByte(0x00); - data.writeBytes(time); - return HuabaoProtocolDecoder.formatMessage( - HuabaoProtocolDecoder.MSG_OIL_CONTROL, id, data); - } else { - data.writeByte(0xf1); - return HuabaoProtocolDecoder.formatMessage( - HuabaoProtocolDecoder.MSG_TERMINAL_CONTROL, id, data); - } - default: - return null; - } - } finally { - id.release(); - } - } - -} diff --git a/src/org/traccar/protocol/HunterProProtocol.java b/src/org/traccar/protocol/HunterProProtocol.java deleted file mode 100644 index 9f6424a57..000000000 --- a/src/org/traccar/protocol/HunterProProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class HunterProProtocol extends BaseProtocol { - - public HunterProProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r")); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new HunterProProtocolDecoder(HunterProProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/HunterProProtocolDecoder.java b/src/org/traccar/protocol/HunterProProtocolDecoder.java deleted file mode 100644 index 06bc12d59..000000000 --- a/src/org/traccar/protocol/HunterProProtocolDecoder.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class HunterProProtocolDecoder extends BaseProtocolDecoder { - - public HunterProProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number(">(d+)<") // identifier - .text("$GPRMC,") - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder(); - dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/IdplProtocol.java b/src/org/traccar/protocol/IdplProtocol.java deleted file mode 100644 index 418178756..000000000 --- a/src/org/traccar/protocol/IdplProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class IdplProtocol extends BaseProtocol { - - public IdplProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new IdplProtocolDecoder(IdplProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/IdplProtocolDecoder.java b/src/org/traccar/protocol/IdplProtocolDecoder.java deleted file mode 100644 index cf3c03d7f..000000000 --- a/src/org/traccar/protocol/IdplProtocolDecoder.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.net.SocketAddress; -import java.util.regex.Pattern; - -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.Parser.CoordinateFormat; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -public class IdplProtocolDecoder extends BaseProtocolDecoder { - - public IdplProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("*ID") // start of frame - .number("(d+),") // command code - .number("(d+),") // imei - .number("(dd)(dd)(dd),") // current date (ddmmyy) - .number("(dd)(dd)(dd),") // current time (hhmmss) - .expression("([A|V]),") // gps fix - .number("(dd)(dd).?(d+),([NS]),") // latitude - .number("(ddd)(dd).?(d+),([EW]),") // longitude - .number("(d{1,3}.dd),") // speed - .number("(d{1,3}.dd),") // course - .number("(d{1,2}),") // sats - .number("(d{1,3}),") // gsm signal strength - .expression("([A|N|S]),") // vehicle status - .expression("([0|1]),") // main power status - .number("(d.dd),") // internal battery voltage - .expression("([0|1]),") // sos alert - .expression("([0|1]),") // body tamper - .expression("([0|1])([0|1]),") // ac status + ign status - .expression("([0|1|2]),") // output1 status - .number("(d{1,3}),") // adc1 - .number("(d{1,3}),") // adc2 - .expression("([0-9A-Z]{3}),") // software version - .expression("([L|R]),") // message type - .number("(x{4})#") // crc - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - position.set(Position.KEY_TYPE, parser.nextInt(0)); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate(CoordinateFormat.DEG_MIN_MIN_HEM)); - position.setLongitude(parser.nextCoordinate(CoordinateFormat.DEG_MIN_MIN_HEM)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_RSSI, parser.nextInt(0)); - position.set("vehicleStatus", parser.next()); - position.set(Position.KEY_POWER, parser.nextInt(0)); - position.set(Position.KEY_BATTERY, parser.nextDouble(0)); - if (parser.nextInt(0) == 1) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - parser.nextInt(0); // body tamper - position.set("acStatus", parser.nextInt(0)); - position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); - position.set(Position.KEY_OUTPUT, parser.nextInt(0)); - position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); - position.set(Position.PREFIX_ADC + 2, parser.nextInt(0)); - position.set(Position.KEY_VERSION_FW, parser.next()); - position.set(Position.KEY_ARCHIVE, parser.next().equals("R")); - - parser.next(); // checksum - - return position; - } - -} diff --git a/src/org/traccar/protocol/IntellitracFrameDecoder.java b/src/org/traccar/protocol/IntellitracFrameDecoder.java deleted file mode 100644 index 8322e65ba..000000000 --- a/src/org/traccar/protocol/IntellitracFrameDecoder.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.LineBasedFrameDecoder; -import org.traccar.NetworkMessage; - -public class IntellitracFrameDecoder extends LineBasedFrameDecoder { - - private static final int MESSAGE_MINIMUM_LENGTH = 0; - - public IntellitracFrameDecoder(int maxFrameLength) { - super(maxFrameLength); - } - - // example of sync header: 0xFA 0xF8 0x1B 0x01 0x81 0x60 0x33 0x3C - - @Override - protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) throws Exception { - - // Check minimum length - if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { - return null; - } - - // Check for sync packet - if (buf.getUnsignedShort(buf.readerIndex()) == 0xFAF8) { - ByteBuf syncMessage = buf.readRetainedSlice(8); - if (ctx != null && ctx.channel() != null) { - ctx.channel().writeAndFlush(new NetworkMessage(syncMessage, ctx.channel().remoteAddress())); - } - } - - return super.decode(ctx, buf); - } - -} diff --git a/src/org/traccar/protocol/IntellitracProtocol.java b/src/org/traccar/protocol/IntellitracProtocol.java deleted file mode 100644 index 3abf40da7..000000000 --- a/src/org/traccar/protocol/IntellitracProtocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class IntellitracProtocol extends BaseProtocol { - - public IntellitracProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new IntellitracFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new IntellitracProtocolDecoder(IntellitracProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/IntellitracProtocolDecoder.java b/src/org/traccar/protocol/IntellitracProtocolDecoder.java deleted file mode 100644 index 897606270..000000000 --- a/src/org/traccar/protocol/IntellitracProtocolDecoder.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class IntellitracProtocolDecoder extends BaseProtocolDecoder { - - public IntellitracProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression(".+,").optional() - .number("(d+),") // identifier - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // longitude - .number("(-?d+.d+),") // latitude - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(-?d+.?d*),") // altitude - .number("(d+),") // satellites - .number("(d+),") // index - .number("(d+),") // input - .number("(d+),?") // output - .number("(d+.d+)?,?") // adc1 - .number("(d+.d+)?,?") // adc2 - .groupBegin() - .number("d{14},d+,") - .number("(d+),") // vss - .number("(d+),") // rpm - .number("(-?d+),") // coolant - .number("(d+),") // fuel - .number("(d+),") // fuel consumption - .number("(-?d+),") // fuel temperature - .number("(d+),") // charger pressure - .number("(d+),") // tpl - .number("(d+),") // axle weight - .number("(d+)") // odometer - .groupEnd("?") - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setValid(true); - position.setLongitude(parser.nextDouble()); - position.setLatitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextDouble()); - position.setAltitude(parser.nextDouble()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_INDEX, parser.nextLong()); - position.set(Position.KEY_INPUT, parser.nextInt()); - position.set(Position.KEY_OUTPUT, parser.nextInt()); - - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); - - // J1939 data - position.set(Position.KEY_OBD_SPEED, parser.nextInt()); - position.set(Position.KEY_RPM, parser.nextInt()); - position.set("coolant", parser.nextInt()); - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); - position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextInt()); - position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); - position.set("chargerPressure", parser.nextInt()); - position.set("tpl", parser.nextInt()); - position.set(Position.KEY_AXLE_WEIGHT, parser.nextInt()); - position.set(Position.KEY_OBD_ODOMETER, parser.nextInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/ItsProtocol.java b/src/org/traccar/protocol/ItsProtocol.java deleted file mode 100644 index f53600dc9..000000000 --- a/src/org/traccar/protocol/ItsProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ItsProtocol extends BaseProtocol { - - public ItsProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '*')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new ItsProtocolDecoder(ItsProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ItsProtocolDecoder.java b/src/org/traccar/protocol/ItsProtocolDecoder.java deleted file mode 100644 index 482f34e65..000000000 --- a/src/org/traccar/protocol/ItsProtocolDecoder.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2018 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class ItsProtocolDecoder extends BaseProtocolDecoder { - - public ItsProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("[^$]*") - .text("$") - .expression(",?[^,]+,") // event - .groupBegin() - .expression("[^,]+,") // vendor - .expression("[^,]+,") // firmware version - .expression("[^,]+,") // type - .number("d+,") - .expression("[LH],") // history - .or() - .expression("[^,]+,") // type - .groupEnd() - .number("(d{15}),") // imei - .groupBegin() - .expression("(..),") // status - .or() - .expression("[^,]*,") // vehicle registration - .number("([01]),") // valid - .groupEnd() - .number("(dd),?(dd),?(dddd),") // date (ddmmyyyy) - .number("(dd),?(dd),?(dd),") // time (hhmmss) - .expression("([AV]),").optional() // valid - .number("(d+.d+),([NS]),") // latitude - .number("(d+.d+),([EW]),") // longitude - .groupBegin() - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(d+),") // satellites - .groupBegin() - .number("(d+.?d*),") // altitude - .number("d+.?d*,") // pdop - .number("d+.?d*,") // hdop - .expression("[^,]*,") - .number("([01]),") // ignition - .number("([01]),") // charging - .number("(d+.?d*),") // power - .number("(d+.?d*),") // battery - .number("[01],") // emergency - .expression("[CO]?,") // tamper - .number("(?:x+,){5}") // main cell - .number("(?:-?x+,){12}") // other cells - .number("([01]{4}),") // inputs - .number("([01]{2}),") // outputs - .groupEnd("?") - .or() - .number("(-?d+.d+),") // altitude - .number("(d+.d+),") // speed - .groupEnd() - .any() - .compile(); - - private String decodeAlarm(String status) { - switch (status) { - case "WD": - case "EA": - return Position.ALARM_SOS; - case "BL": - return Position.ALARM_LOW_BATTERY; - case "HB": - return Position.ALARM_BRAKING; - case "HA": - return Position.ALARM_ACCELERATION; - case "RT": - return Position.ALARM_CORNERING; - case "OS": - return Position.ALARM_OVERSPEED; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (channel != null && sentence.startsWith("$,01,")) { - channel.writeAndFlush(new NetworkMessage("$,1,*", remoteAddress)); - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.hasNext()) { - position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); - } - - if (parser.hasNext()) { - position.setValid(parser.nextInt() == 1); - } - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - if (parser.hasNext()) { - position.setValid(parser.next().equals("A")); - } - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - - if (parser.hasNext(3)) { - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextDouble()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - } - - if (parser.hasNext(7)) { - position.setAltitude(parser.nextDouble()); - position.set(Position.KEY_IGNITION, parser.nextInt() > 0); - position.set(Position.KEY_CHARGE, parser.nextInt() > 0); - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.KEY_INPUT, parser.nextBinInt()); - position.set(Position.KEY_OUTPUT, parser.nextBinInt()); - } - - if (parser.hasNext(2)) { - position.setAltitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/Ivt401Protocol.java b/src/org/traccar/protocol/Ivt401Protocol.java deleted file mode 100644 index fb44e4fe9..000000000 --- a/src/org/traccar/protocol/Ivt401Protocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Ivt401Protocol extends BaseProtocol { - - public Ivt401Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Ivt401ProtocolDecoder(Ivt401Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Ivt401ProtocolDecoder.java b/src/org/traccar/protocol/Ivt401ProtocolDecoder.java deleted file mode 100644 index 63556e7a9..000000000 --- a/src/org/traccar/protocol/Ivt401ProtocolDecoder.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Ivt401ProtocolDecoder extends BaseProtocolDecoder { - - public Ivt401ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("(") - .expression("TL[ABLN],") // header - .number("(d+),") // imei - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("([-+]d+.d+),") // latitude - .number("([-+]d+.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(-?d+.?d*),") // altitude - .number("d+,") // satellites or battery status - .number("(d),") // gps status - .number("(d+),") // rssi - .number("(d+),") // input - .number("(d+),") // output - .number("(d+.d+),") // adc - .number("(d+.d+),") // power - .number("(d+.d+),") // battery - .number("(-?d+.?d*),") // pcb temp - .expression("([^,]+),") // temp - .number("(d+),") // movement - .number("(d+.d+),") // acceleration - .number("(-?d+),") // tilt - .number("(d+),") // trip - .number("(d+),") // odometer - .groupBegin() - .number("([01]),") // overspeed - .number("[01],") // input 2 misuse - .number("[01],") // immobilizer - .number("[01],") // temperature alert - .number("[0-2]+,") // geofence - .number("([0-3]),") // harsh driving - .number("[01],") // reconnect - .number("([01]),") // low battery - .number("([01]),") // power disconnected - .number("[01],") // gps failure - .number("([01]),") // towing - .number("[01],") // server unreachable - .number("[128],") // sleep mode - .expression("([^,]+)?,") // driver id - .number("d+,") // sms count - .groupEnd("?") - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); - position.setCourse(parser.nextInt()); - position.setAltitude(parser.nextDouble()); - position.setValid(parser.nextInt() > 0); - - position.set(Position.KEY_RSSI, parser.nextInt()); - - String input = parser.next(); - for (int i = 0; i < input.length(); i++) { - int value = Character.getNumericValue(input.charAt(i)); - if (value < 2) { - position.set(Position.PREFIX_IN + (i + 1), value > 0); - } - } - - String output = parser.next(); - for (int i = 0; i < output.length(); i++) { - position.set(Position.PREFIX_OUT + (i + 1), Character.getNumericValue(output.charAt(i)) > 0); - } - - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.KEY_DEVICE_TEMP, parser.nextDouble()); - - String temp = parser.next(); - if (temp.startsWith("M")) { - int index = 1; - int startIndex = 1; - int endIndex; - while (startIndex < temp.length()) { - endIndex = temp.indexOf('-', startIndex + 1); - if (endIndex < 0) { - endIndex = temp.indexOf('+', startIndex + 1); - } - if (endIndex < 0) { - endIndex = temp.length(); - } - if (endIndex > 0) { - double value = Double.parseDouble(temp.substring(startIndex, endIndex)); - position.set(Position.PREFIX_TEMP + index++, value); - } - startIndex = endIndex; - } - } else { - position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(temp)); - } - - position.set(Position.KEY_MOTION, parser.nextInt() > 0); - position.set(Position.KEY_ACCELERATION, parser.nextDouble()); - - parser.nextInt(); // tilt - parser.nextInt(); // trip state - - position.set(Position.KEY_ODOMETER, parser.nextLong()); - - if (parser.hasNext(6)) { - position.set(Position.KEY_ALARM, parser.nextInt() == 1 ? Position.ALARM_OVERSPEED : null); - switch (parser.nextInt()) { - case 1: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 2: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 3: - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - break; - default: - break; - } - position.set(Position.KEY_ALARM, parser.nextInt() == 1 ? Position.ALARM_LOW_BATTERY : null); - position.set(Position.KEY_ALARM, parser.nextInt() == 1 ? Position.ALARM_POWER_CUT : null); - position.set(Position.KEY_ALARM, parser.nextInt() == 1 ? Position.ALARM_TOW : null); - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/JpKorjarFrameDecoder.java b/src/org/traccar/protocol/JpKorjarFrameDecoder.java deleted file mode 100644 index 0eb65c8ef..000000000 --- a/src/org/traccar/protocol/JpKorjarFrameDecoder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 Nyash (nyashh@gmail.com) - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class JpKorjarFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 80) { - return null; - } - - int spaceIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ' '); - if (spaceIndex == -1) { - return null; - } - - int endIndex = buf.indexOf(spaceIndex, buf.writerIndex(), (byte) ','); - if (endIndex == -1) { - return null; - } - - return buf.readRetainedSlice(endIndex + 1); - } - -} diff --git a/src/org/traccar/protocol/JpKorjarProtocol.java b/src/org/traccar/protocol/JpKorjarProtocol.java deleted file mode 100644 index fe5b2480d..000000000 --- a/src/org/traccar/protocol/JpKorjarProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016 Nyash (nyashh@gmail.com) - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class JpKorjarProtocol extends BaseProtocol { - - public JpKorjarProtocol() { - addServer(new TrackerServer(false, this.getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new JpKorjarFrameDecoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new JpKorjarProtocolDecoder(JpKorjarProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/JpKorjarProtocolDecoder.java b/src/org/traccar/protocol/JpKorjarProtocolDecoder.java deleted file mode 100644 index a8389d1b1..000000000 --- a/src/org/traccar/protocol/JpKorjarProtocolDecoder.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2016 Nyash (nyashh@gmail.com) - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class JpKorjarProtocolDecoder extends BaseProtocolDecoder { - - public JpKorjarProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("KORJAR.PL,") - .number("(d+),") // imei - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d+.d+)([NS]),") // latitude - .number("(d+.d+)([EW]),") // longitude - .number("(d+.d+),") // speed - .number("(d+),") // course - .number("[FL]:(d+.d+)V,") // battery - .number("([01]) ") // valid - .number("(d+) ") // mcc - .number("(d+) ") // mnc - .number("(x+) ") // lac - .number("(x+),") // cid - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_BATTERY, parser.nextDouble(0)); - - position.setValid(parser.nextInt(0) == 1); - - position.setNetwork(new Network(CellTower.from( - parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); - - return position; - } - -} diff --git a/src/org/traccar/protocol/Jt600FrameDecoder.java b/src/org/traccar/protocol/Jt600FrameDecoder.java deleted file mode 100644 index b5d060ecc..000000000 --- a/src/org/traccar/protocol/Jt600FrameDecoder.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -import java.text.ParseException; - -public class Jt600FrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 10) { - return null; - } - - char type = (char) buf.getByte(buf.readerIndex()); - - if (type == '$') { - boolean longFormat = buf.getUnsignedByte(buf.readerIndex() + 1) == 0x75; - int length = buf.getUnsignedShort(buf.readerIndex() + (longFormat ? 8 : 7)) + 10; - if (length <= buf.readableBytes()) { - return buf.readRetainedSlice(length); - } - } else if (type == '(') { - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ')'); - if (endIndex != -1) { - return buf.readRetainedSlice(endIndex + 1); - } - } else { - throw new ParseException(null, 0); // unknown message - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Jt600Protocol.java b/src/org/traccar/protocol/Jt600Protocol.java deleted file mode 100644 index 97c5fa6ce..000000000 --- a/src/org/traccar/protocol/Jt600Protocol.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class Jt600Protocol extends BaseProtocol { - - public Jt600Protocol() { - setSupportedDataCommands( - Command.TYPE_ENGINE_RESUME, - Command.TYPE_ENGINE_STOP, - Command.TYPE_SET_TIMEZONE, - Command.TYPE_REBOOT_DEVICE); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Jt600FrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Jt600ProtocolEncoder()); - pipeline.addLast(new Jt600ProtocolDecoder(Jt600Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/org/traccar/protocol/Jt600ProtocolDecoder.java deleted file mode 100644 index 1351706e2..000000000 --- a/src/org/traccar/protocol/Jt600ProtocolDecoder.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BcdUtil; -import org.traccar.helper.BitBuffer; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; - -public class Jt600ProtocolDecoder extends BaseProtocolDecoder { - - public Jt600ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static double convertCoordinate(int raw) { - int degrees = raw / 1000000; - double minutes = (raw % 1000000) / 10000.0; - return degrees + minutes / 60; - } - - private void decodeStatus(Position position, ByteBuf buf) { - - int value = buf.readUnsignedByte(); - - position.set(Position.KEY_IGNITION, BitUtil.check(value, 0)); - position.set(Position.KEY_DOOR, BitUtil.check(value, 6)); - - value = buf.readUnsignedByte(); - - position.set(Position.KEY_CHARGE, BitUtil.check(value, 0)); - position.set(Position.KEY_BLOCKED, BitUtil.check(value, 1)); - - if (BitUtil.check(value, 2)) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - if (BitUtil.check(value, 3) || BitUtil.check(value, 4)) { - position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT); - } - if (BitUtil.check(value, 4)) { - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - } - - value = buf.readUnsignedByte(); - - if (BitUtil.check(value, 2)) { - position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING); - } - if (BitUtil.check(value, 3)) { - position.set(Position.KEY_ALARM, Position.ALARM_TOW); - } - - buf.readUnsignedByte(); // reserved - - } - - private List decodeBinary(ByteBuf buf, Channel channel, SocketAddress remoteAddress) { - - List positions = new LinkedList<>(); - - buf.readByte(); // header - - boolean longFormat = buf.getUnsignedByte(buf.readerIndex()) == 0x75; - - String id = String.valueOf(Long.parseLong(ByteBufUtil.hexDump(buf.readSlice(5)))); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - int protocolVersion = 0; - if (longFormat) { - protocolVersion = buf.readUnsignedByte(); - } - - int version = BitUtil.from(buf.readUnsignedByte(), 4); - buf.readUnsignedShort(); // length - - while (buf.readableBytes() > 1) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setDay(BcdUtil.readInteger(buf, 2)) - .setMonth(BcdUtil.readInteger(buf, 2)) - .setYear(BcdUtil.readInteger(buf, 2)) - .setHour(BcdUtil.readInteger(buf, 2)) - .setMinute(BcdUtil.readInteger(buf, 2)) - .setSecond(BcdUtil.readInteger(buf, 2)); - position.setTime(dateBuilder.getDate()); - - double latitude = convertCoordinate(BcdUtil.readInteger(buf, 8)); - double longitude = convertCoordinate(BcdUtil.readInteger(buf, 9)); - - byte flags = buf.readByte(); - position.setValid((flags & 0x1) == 0x1); - if ((flags & 0x2) == 0) { - latitude = -latitude; - } - position.setLatitude(latitude); - if ((flags & 0x4) == 0) { - longitude = -longitude; - } - position.setLongitude(longitude); - - position.setSpeed(BcdUtil.readInteger(buf, 2)); - position.setCourse(buf.readUnsignedByte() * 2.0); - - if (longFormat) { - - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - buf.readUnsignedInt(); // vehicle id combined - - int status = buf.readUnsignedShort(); - position.set(Position.KEY_ALARM, BitUtil.check(status, 1) ? Position.ALARM_GEOFENCE_ENTER : null); - position.set(Position.KEY_ALARM, BitUtil.check(status, 2) ? Position.ALARM_GEOFENCE_EXIT : null); - position.set(Position.KEY_ALARM, BitUtil.check(status, 3) ? Position.ALARM_POWER_CUT : null); - position.set(Position.KEY_ALARM, BitUtil.check(status, 4) ? Position.ALARM_VIBRATION : null); - position.set(Position.KEY_BLOCKED, BitUtil.check(status, 7)); - position.set(Position.KEY_ALARM, BitUtil.check(status, 8 + 3) ? Position.ALARM_LOW_BATTERY : null); - position.set(Position.KEY_ALARM, BitUtil.check(status, 8 + 6) ? Position.ALARM_FAULT : null); - position.set(Position.KEY_STATUS, status); - - int battery = buf.readUnsignedByte(); - if (battery == 0xff) { - position.set(Position.KEY_CHARGE, true); - } else { - position.set(Position.KEY_BATTERY_LEVEL, battery); - } - - CellTower cellTower = CellTower.fromCidLac(buf.readUnsignedShort(), buf.readUnsignedShort()); - cellTower.setSignalStrength((int) buf.readUnsignedByte()); - position.setNetwork(new Network(cellTower)); - - if (protocolVersion == 0x17) { - buf.readUnsignedByte(); // geofence id - buf.skipBytes(3); // reserved - } - - } else if (version == 1) { - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_POWER, buf.readUnsignedByte()); - - buf.readByte(); // other flags and sensors - - position.setAltitude(buf.readUnsignedShort()); - - int cid = buf.readUnsignedShort(); - int lac = buf.readUnsignedShort(); - int rssi = buf.readUnsignedByte(); - - if (cid != 0 && lac != 0) { - CellTower cellTower = CellTower.fromCidLac(cid, lac); - cellTower.setSignalStrength(rssi); - position.setNetwork(new Network(cellTower)); - } else { - position.set(Position.KEY_RSSI, rssi); - } - - } else if (version == 2) { - - int fuel = buf.readUnsignedByte() << 8; - - decodeStatus(position, buf); - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); - - fuel += buf.readUnsignedByte(); - position.set(Position.KEY_FUEL_LEVEL, fuel); - - } else if (version == 3) { - - BitBuffer bitBuffer = new BitBuffer(buf); - - position.set("fuel1", bitBuffer.readUnsigned(12)); - position.set("fuel2", bitBuffer.readUnsigned(12)); - position.set("fuel3", bitBuffer.readUnsigned(12)); - position.set(Position.KEY_ODOMETER, bitBuffer.readUnsigned(20) * 1000); - - int status = bitBuffer.readUnsigned(24); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 0)); - position.set(Position.KEY_STATUS, status); - - } - - positions.add(position); - - } - - buf.readUnsignedByte(); // index - - return positions; - } - - private static final Pattern PATTERN_W01 = new PatternBuilder() - .text("(") - .number("(d+),") // id - .text("W01,") // type - .number("(ddd)(dd.dddd),") // longitude - .expression("([EW]),") - .number("(dd)(dd.dddd),") // latitude - .expression("([NS]),") - .expression("([AV]),") // validity - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+),") // power - .number("(d+),") // gps signal - .number("(d+),") // gsm signal - .number("(d+),") // alert type - .any() - .compile(); - - private Position decodeW01(String sentence, Channel channel, SocketAddress remoteAddress) { - - Parser parser = new Parser(PATTERN_W01, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setLongitude(parser.nextCoordinate()); - position.setLatitude(parser.nextCoordinate()); - position.setValid(parser.next().equals("A")); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_POWER, parser.nextDouble(0)); - position.set(Position.KEY_GPS, parser.nextInt(0)); - position.set(Position.KEY_RSSI, parser.nextInt(0)); - position.set("alertType", parser.nextInt(0)); - - return position; - } - - private static final Pattern PATTERN_U01 = new PatternBuilder() - .text("(") - .number("(d+),") // id - .number("(Udd),") // type - .number("d+,").optional() // alarm - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([TF]),") // validity - .number("(d+.d+),([NS]),") // latitude - .number("(d+.d+),([EW]),") // longitude - .number("(d+.?d*),") // speed - .number("(d+),") // course - .number("(d+),") // satellites - .number("(d+)%,") // battery - .expression("([01]+),") // status - .number("(d+),") // cid - .number("(d+),") // lac - .number("(d+),") // gsm signal - .number("(d+),") // odometer - .number("(d+)") // serial number - .number(",(xx)").optional() // checksum - .any() - .compile(); - - private Position decodeU01(String sentence, Channel channel, SocketAddress remoteAddress) { - - Parser parser = new Parser(PATTERN_U01, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - String type = parser.next(); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setValid(parser.next().equals("T")); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - - position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); - position.set(Position.KEY_STATUS, parser.nextBinInt(0)); - - CellTower cellTower = CellTower.fromCidLac(parser.nextInt(0), parser.nextInt(0)); - cellTower.setSignalStrength(parser.nextInt(0)); - position.setNetwork(new Network(cellTower)); - - position.set(Position.KEY_ODOMETER, parser.nextLong(0) * 1000); - position.set(Position.KEY_INDEX, parser.nextInt(0)); - - if (channel != null) { - if (type.equals("U01") || type.equals("U02") || type.equals("U03")) { - channel.writeAndFlush(new NetworkMessage("(S39)", remoteAddress)); - } else if (type.equals("U06")) { - channel.writeAndFlush(new NetworkMessage("(S20)", remoteAddress)); - } - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - char first = (char) buf.getByte(0); - - if (first == '$') { - return decodeBinary(buf, channel, remoteAddress); - } else if (first == '(') { - String sentence = buf.toString(StandardCharsets.US_ASCII); - if (sentence.contains("W01")) { - return decodeW01(sentence, channel, remoteAddress); - } else { - return decodeU01(sentence, channel, remoteAddress); - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Jt600ProtocolEncoder.java b/src/org/traccar/protocol/Jt600ProtocolEncoder.java deleted file mode 100644 index fe5c63c32..000000000 --- a/src/org/traccar/protocol/Jt600ProtocolEncoder.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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.TimeZone; - -import org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class Jt600ProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_ENGINE_STOP: - return "(S07,0)"; - case Command.TYPE_ENGINE_RESUME: - return "(S07,1)"; - case Command.TYPE_SET_TIMEZONE: - int offset = TimeZone.getTimeZone(command.getString(Command.KEY_TIMEZONE)).getRawOffset() / 60000; - return "(S09,1," + offset + ")"; - case Command.TYPE_REBOOT_DEVICE: - return "(S17)"; - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/KenjiProtocol.java b/src/org/traccar/protocol/KenjiProtocol.java deleted file mode 100644 index 90c0c511c..000000000 --- a/src/org/traccar/protocol/KenjiProtocol.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2016 Carlos Alvarez (carlos.alvarez.rozas@gmail.com) - * Copyright 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class KenjiProtocol extends BaseProtocol { - - public KenjiProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new KenjiProtocolDecoder(KenjiProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/KenjiProtocolDecoder.java b/src/org/traccar/protocol/KenjiProtocolDecoder.java deleted file mode 100644 index 63812242a..000000000 --- a/src/org/traccar/protocol/KenjiProtocolDecoder.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class KenjiProtocolDecoder extends BaseProtocolDecoder { - - public KenjiProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text(">") - .number("C(d{6}),") // device id - .number("M(x{6}),") // alarm - .number("O(x{4}),") // output - .number("I(x{4}),") // input - .number("D(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // valid - .number("([NS])(dd)(dd.d+),") // latitude - .number("([EW])(ddd)(dd.d+),") // longitude - .number("T(d+.d+),") // speed - .number("H(d+.d+),") // course - .number("Y(dd)(dd)(dd),") // date (ddmmyy) - .number("G(d+)") // satellites - .any() - .compile(); - - private String decodeAlarm(int value) { - if (BitUtil.check(value, 2)) { - return Position.ALARM_SOS; - } - if (BitUtil.check(value, 4)) { - return Position.ALARM_LOW_BATTERY; - } - if (BitUtil.check(value, 6)) { - return Position.ALARM_MOVEMENT; - } - if (BitUtil.check(value, 1) || BitUtil.check(value, 10) || BitUtil.check(value, 11)) { - return Position.ALARM_VIBRATION; - } - - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_ALARM, decodeAlarm(parser.nextHexInt(0))); - position.set(Position.KEY_OUTPUT, parser.nextHexInt(0)); - position.set(Position.KEY_INPUT, parser.nextHexInt(0)); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/KhdProtocol.java b/src/org/traccar/protocol/KhdProtocol.java deleted file mode 100644 index cec7158ed..000000000 --- a/src/org/traccar/protocol/KhdProtocol.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class KhdProtocol extends BaseProtocol { - - public KhdProtocol() { - setSupportedDataCommands( - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(512, 3, 2)); - pipeline.addLast(new KhdProtocolEncoder()); - pipeline.addLast(new KhdProtocolDecoder(KhdProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/KhdProtocolDecoder.java b/src/org/traccar/protocol/KhdProtocolDecoder.java deleted file mode 100644 index 0dd5b085a..000000000 --- a/src/org/traccar/protocol/KhdProtocolDecoder.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BcdUtil; -import org.traccar.helper.Checksum; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class KhdProtocolDecoder extends BaseProtocolDecoder { - - public KhdProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private String readSerialNumber(ByteBuf buf) { - int b1 = buf.readUnsignedByte(); - int b2 = buf.readUnsignedByte() - 0x80; - int b3 = buf.readUnsignedByte() - 0x80; - int b4 = buf.readUnsignedByte(); - return String.format("%02d%02d%02d%02d", b1, b2, b3, b4); - } - - public static final int MSG_LOGIN = 0xB1; - public static final int MSG_CONFIRMATION = 0x21; - public static final int MSG_ON_DEMAND = 0x81; - public static final int MSG_POSITION_UPLOAD = 0x80; - public static final int MSG_POSITION_REUPLOAD = 0x8E; - public static final int MSG_ALARM = 0x82; - public static final int MSG_ADMIN_NUMBER = 0x83; - public static final int MSG_SEND_TEXT = 0x84; - public static final int MSG_REPLY = 0x85; - public static final int MSG_SMS_ALARM_SWITCH = 0x86; - public static final int MSG_PERIPHERAL = 0xA3; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - int type = buf.readUnsignedByte(); - buf.readUnsignedShort(); // size - - if (type == MSG_LOGIN || type == MSG_ADMIN_NUMBER || type == MSG_SEND_TEXT - || type == MSG_SMS_ALARM_SWITCH || type == MSG_POSITION_REUPLOAD) { - - ByteBuf response = Unpooled.buffer(); - response.writeByte(0x29); - response.writeByte(0x29); // header - response.writeByte(MSG_CONFIRMATION); - response.writeShort(5); // size - response.writeByte(buf.getByte(buf.writerIndex() - 2)); - response.writeByte(type); - response.writeByte(buf.writerIndex() > 9 ? buf.getByte(9) : 0); // 10th byte - response.writeByte(Checksum.xor(response.nioBuffer())); - response.writeByte(0x0D); // ending - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - } - - if (type == MSG_ON_DEMAND || type == MSG_POSITION_UPLOAD || type == MSG_POSITION_REUPLOAD - || type == MSG_ALARM || type == MSG_REPLY || type == MSG_PERIPHERAL) { - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, readSerialNumber(buf)); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setYear(BcdUtil.readInteger(buf, 2)) - .setMonth(BcdUtil.readInteger(buf, 2)) - .setDay(BcdUtil.readInteger(buf, 2)) - .setHour(BcdUtil.readInteger(buf, 2)) - .setMinute(BcdUtil.readInteger(buf, 2)) - .setSecond(BcdUtil.readInteger(buf, 2)); - position.setTime(dateBuilder.getDate()); - - position.setLatitude(BcdUtil.readCoordinate(buf)); - position.setLongitude(BcdUtil.readCoordinate(buf)); - position.setSpeed(UnitsConverter.knotsFromKph(BcdUtil.readInteger(buf, 4))); - position.setCourse(BcdUtil.readInteger(buf, 4)); - position.setValid((buf.readUnsignedByte() & 0x80) != 0); - - if (type != MSG_ALARM) { - - position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); - position.set(Position.KEY_STATUS, buf.readUnsignedInt()); - position.set(Position.KEY_HDOP, buf.readUnsignedByte()); - position.set(Position.KEY_VDOP, buf.readUnsignedByte()); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - buf.skipBytes(5); // other location data - - if (type == MSG_PERIPHERAL) { - - buf.readUnsignedShort(); // data length - - int dataType = buf.readUnsignedByte(); - - buf.readUnsignedByte(); // content length - - switch (dataType) { - case 0x01: - position.set(Position.KEY_FUEL_LEVEL, - buf.readUnsignedByte() * 100 + buf.readUnsignedByte()); - break; - case 0x02: - position.set(Position.PREFIX_TEMP + 1, - buf.readUnsignedByte() * 100 + buf.readUnsignedByte()); - break; - default: - break; - } - - } - - } - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/KhdProtocolEncoder.java b/src/org/traccar/protocol/KhdProtocolEncoder.java deleted file mode 100644 index c66129283..000000000 --- a/src/org/traccar/protocol/KhdProtocolEncoder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -public class KhdProtocolEncoder extends BaseProtocolEncoder { - - public static final int MSG_CUT_OIL = 0x39; - public static final int MSG_RESUME_OIL = 0x38; - - private ByteBuf encodeCommand(int command, String uniqueId) { - - ByteBuf buf = Unpooled.buffer(); - - buf.writeByte(0x29); - buf.writeByte(0x29); - - buf.writeByte(command); - buf.writeShort(6); // size - - uniqueId = "00000000".concat(uniqueId); - uniqueId = uniqueId.substring(uniqueId.length() - 8); - buf.writeByte(Integer.parseInt(uniqueId.substring(0, 2))); - buf.writeByte(Integer.parseInt(uniqueId.substring(2, 4)) + 0x80); - buf.writeByte(Integer.parseInt(uniqueId.substring(4, 6)) + 0x80); - buf.writeByte(Integer.parseInt(uniqueId.substring(6, 8))); - - buf.writeByte(Checksum.xor(buf.nioBuffer())); - buf.writeByte(0x0D); // ending - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - String uniqueId = getUniqueId(command.getDeviceId()); - - switch (command.getType()) { - case Command.TYPE_ENGINE_STOP: - return encodeCommand(MSG_CUT_OIL, uniqueId); - case Command.TYPE_ENGINE_RESUME: - return encodeCommand(MSG_RESUME_OIL, uniqueId); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/L100FrameDecoder.java b/src/org/traccar/protocol/L100FrameDecoder.java deleted file mode 100644 index 158461895..000000000 --- a/src/org/traccar/protocol/L100FrameDecoder.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -import java.nio.charset.StandardCharsets; - -public class L100FrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 10) { - return null; - } - - if (buf.getCharSequence(buf.readerIndex(), 4, StandardCharsets.US_ASCII).toString().equals("ATL,")) { - return decodeNew(buf); - } else { - return decodeOld(buf); - } - } - - private Object decodeOld(ByteBuf buf) { - - int header = buf.getByte(buf.readerIndex()); - boolean obd = header == 'L' || header == 'H'; - - int index; - if (obd) { - index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*'); - } else { - index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02); - if (index < 0) { - index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x04); - if (index < 0) { - return null; - } - } - } - - index += 2; // checksum - - if (buf.writerIndex() >= index) { - if (!obd) { - buf.skipBytes(2); // header - } - ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex() - 2); - buf.skipBytes(2); // footer - return frame; - } - - return null; - } - - private Object decodeNew(ByteBuf buf) { - - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '@'); - if (index < 0) { - return null; - } - - if (buf.writerIndex() >= index + 1) { - ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex()); - buf.skipBytes(1); // delimiter - return frame; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/L100Protocol.java b/src/org/traccar/protocol/L100Protocol.java deleted file mode 100644 index 942029307..000000000 --- a/src/org/traccar/protocol/L100Protocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class L100Protocol extends BaseProtocol { - - public L100Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new L100FrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new L100ProtocolDecoder(L100Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/L100ProtocolDecoder.java b/src/org/traccar/protocol/L100ProtocolDecoder.java deleted file mode 100644 index 9868de435..000000000 --- a/src/org/traccar/protocol/L100ProtocolDecoder.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.ObdDecoder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class L100ProtocolDecoder extends BaseProtocolDecoder { - - public L100ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("ATL") - .expression(",[^,]+,").optional() - .number("(d{15}),") // imei - .text("$GPRMC,") - .number("(dd)(dd)(dd)") // time (hhmmss.sss) - .number(".(ddd)").optional() - .expression(",([AV]),") // validity - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .any() - .text("#") - .number("([01]+),") // io status - .number("(d+.?d*|N.C),") // adc - .expression("[^,]*,") // reserved - .expression("[^,]*,") // reserved - .number("(d+.?d*),") // odometer - .number("(d+.?d*),") // temperature - .number("(d+.?d*),") // battery - .number("(d+),") // rssi - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(x+),") // lac - .number("(x+)") // cid - .any() - .text("ATL") - .compile(); - - private static final Pattern PATTERN_OBD_LOCATION = new PatternBuilder() - .expression("[LH],") // archive - .text("ATL,") - .number("(d{15}),") // imei - .number("(d+),") // type - .number("(d+),") // index - .groupBegin() - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd)(dd),") // date (ddmmyy) - .expression("([AV]),") // validity - .number("(d+.d+);([NS]),") // latitude - .number("(d+.d+);([EW]),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+.d+),") // odometer - .number("(d+.d+),") // battery - .number("(d+),") // rssi - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(d+),") // lac - .number("(x+),") // cid - .number("#(d)(d)(d)(d),") // status - .number("(d),") // overspeed - .text("ATL,") - .groupEnd("?") - .compile(); - - private static final Pattern PATTERN_OBD_DATA = new PatternBuilder() - .expression("[LH],") // archive - .text("ATLOBD,") - .number("(d{15}),") // imei - .number("d+,") // type - .number("d+,") // index - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd)(dd),") // date (ddmmyy) - .expression("[^,]+,") // obd protocol - .expression("(.+)") // data - .compile(); - - private static final Pattern PATTERN_NEW = new PatternBuilder() - .groupBegin() - .text("ATL,") - .expression("[LH],") // archive - .number("(d{15}),") // imei - .groupEnd("?") - .expression("([NPT]),") // alarm - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // validity - .number("(d+.d+),([NS]),") // latitude - .number("(d+.d+),([EW]),") // longitude - .number("(d+.?d*),") // speed - .expression("(?:GPS|GSM|INV),") - .number("(d+),") // battery - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(d+),") // lac - .number("(d+)") // cid - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("L") || sentence.startsWith("H")) { - if (sentence.substring(2, 8).equals("ATLOBD")) { - return decodeObdData(channel, remoteAddress, sentence); - } else { - return decodeObdLocation(channel, remoteAddress, sentence); - } - } else if (!sentence.contains("$GPRMC")) { - return decodeNew(channel, remoteAddress, sentence); - } else { - return decodeNormal(channel, remoteAddress, sentence); - } - } - - private Object decodeNormal(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_STATUS, parser.next()); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.KEY_ODOMETER, parser.nextDouble()); - position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - - int rssi = parser.nextInt(); - if (rssi > 0) { - position.setNetwork(new Network(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi))); - } - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(String.valueOf((char) 0x01), remoteAddress)); - } - - return position; - } - - private Object decodeObdLocation(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_OBD_LOCATION, sentence); - if (!parser.matches()) { - return null; - } - - String imei = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - int type = parser.nextInt(); - int index = parser.nextInt(); - - if (type == 1) { - if (channel != null) { - String response = "@" + imei + ",00," + index + ","; - response += "*" + (char) Checksum.xor(response); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setSpeed(parser.nextInt()); - position.setCourse(parser.nextInt()); - - position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - - int rssi = parser.nextInt(); - position.setNetwork(new Network(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextHexInt(), rssi))); - - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - parser.next(); // reserved - - switch (parser.nextInt()) { - case 0: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 2: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 1: - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - break; - default: - break; - } - - position.set(Position.KEY_CHARGE, parser.nextInt() == 1); - - if (parser.nextInt() == 1) { - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - } - - return position; - } - - private Object decodeObdData(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_OBD_DATA, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - for (String entry : parser.next().split(",")) { - String[] values = entry.split(":"); - if (values.length == 2 && values[1].charAt(0) != 'X') { - position.add(ObdDecoder.decodeData( - Integer.parseInt(values[0].substring(2), 16), Integer.parseInt(values[1], 16), true)); - } - } - - return position; - } - - private Object decodeNew(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_NEW, sentence); - if (!parser.matches()) { - return null; - } - - String imei = parser.next(); - DeviceSession deviceSession; - if (imei != null) { - deviceSession = getDeviceSession(channel, remoteAddress, imei); - } else { - deviceSession = getDeviceSession(channel, remoteAddress); - } - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - switch (parser.next()) { - case "P": - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - break; - case "T": - position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); - break; - default: - break; - } - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setSpeed(parser.nextDouble()); - - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); - - position.setNetwork(new Network(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextHexInt()))); - - return position; - } - -} diff --git a/src/org/traccar/protocol/LaipacProtocol.java b/src/org/traccar/protocol/LaipacProtocol.java deleted file mode 100644 index 923b08a16..000000000 --- a/src/org/traccar/protocol/LaipacProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class LaipacProtocol extends BaseProtocol { - - public LaipacProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new LaipacProtocolDecoder(LaipacProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/LaipacProtocolDecoder.java b/src/org/traccar/protocol/LaipacProtocolDecoder.java deleted file mode 100644 index 2f3cbb1b9..000000000 --- a/src/org/traccar/protocol/LaipacProtocolDecoder.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class LaipacProtocolDecoder extends BaseProtocolDecoder { - - public LaipacProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$AVRMC,") - .expression("([^,]+),") // identifier - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AVRPavrp]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .number("([EW]),") - .number("(d+.d+),") // speed - .number("(d+.d+),") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .expression("([abZXTSMHFE86430]),") // event code - .expression("([\\d.]+),") // battery voltage - .number("(d+),") // current mileage - .number("(d),") // gps status - .number("(d+),") // adc1 - .number("(d+)") // adc2 - .number(",(xxxx)") // lac - .number("(xxxx),") // cid - .number("(ddd)") // mcc - .number("(ddd)") // mnc - .optional(4) - .text("*") - .number("(xx)") // checksum - .compile(); - - private String decodeAlarm(String event) { - switch (event) { - case "Z": - return Position.ALARM_LOW_BATTERY; - case "X": - return Position.ALARM_GEOFENCE_ENTER; - case "T": - return Position.ALARM_TAMPERING; - case "H": - return Position.ALARM_POWER_OFF; - case "8": - return Position.ALARM_SHOCK; - case "7": - case "4": - return Position.ALARM_GEOFENCE_EXIT; - case "6": - return Position.ALARM_OVERSPEED; - case "3": - return Position.ALARM_SOS; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("$ECHK") && channel != null) { - channel.writeAndFlush(new NetworkMessage(sentence + "\r\n", remoteAddress)); // heartbeat - return null; - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - String status = parser.next(); - String upperCaseStatus = status.toUpperCase(); - position.setValid(upperCaseStatus.equals("A") || upperCaseStatus.equals("R") || upperCaseStatus.equals("P")); - position.set(Position.KEY_STATUS, status); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - String event = parser.next(); - position.set(Position.KEY_ALARM, decodeAlarm(event)); - position.set(Position.KEY_EVENT, event); - position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001); - position.set(Position.KEY_ODOMETER, parser.nextDouble()); - position.set(Position.KEY_GPS, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001); - - Integer lac = parser.nextHexInt(); - Integer cid = parser.nextHexInt(); - Integer mcc = parser.nextInt(); - Integer mnc = parser.nextInt(); - if (lac != null && cid != null && mcc != null && mnc != null) { - position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid))); - } - - String checksum = parser.next(); - - if (channel != null) { - if (event.equals("3")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,d*31\r\n", remoteAddress)); - } else if (event.equals("X") || event.equals("4")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,x*2D\r\n", remoteAddress)); - } else if (event.equals("Z")) { - channel.writeAndFlush(new NetworkMessage("$AVCFG,00000000,z*2F\r\n", remoteAddress)); - } else if (Character.isLowerCase(status.charAt(0))) { - String response = "$EAVACK," + event + "," + checksum; - response += Checksum.nmea(response) + "\r\n"; - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/M2cProtocol.java b/src/org/traccar/protocol/M2cProtocol.java deleted file mode 100644 index 9de8526c3..000000000 --- a/src/org/traccar/protocol/M2cProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class M2cProtocol extends BaseProtocol { - - public M2cProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(32 * 1024, ']')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new M2cProtocolDecoder(M2cProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/M2cProtocolDecoder.java b/src/org/traccar/protocol/M2cProtocolDecoder.java deleted file mode 100644 index 1460bb176..000000000 --- a/src/org/traccar/protocol/M2cProtocolDecoder.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2017 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; - -public class M2cProtocolDecoder extends BaseProtocolDecoder { - - public M2cProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("#M2C,") - .expression("[^,]+,") // model - .expression("[^,]+,") // firmware - .number("d+,") // protocol - .number("(d+),") // imei - .number("(d+),") // index - .expression("([LH]),") // archive - .number("d+,") // priority - .number("(d+),") // event - .number("(dd)(dd)(dd),") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(-?d+),") // altitude - .number("(d+),") // course - .number("(d+.d+),") // speed - .number("(d+),") // satellites - .number("(d+),") // odometer - .number("(d+),") // input - .number("(d+),") // output - .number("(d+),") // power - .number("(d+),") // battery - .number("(d+),") // adc 1 - .number("(d+),") // adc 2 - .number("(d+.?d*),") // temperature - .any() - .compile(); - - private Position decodePosition(Channel channel, SocketAddress remoteAddress, String line) { - - Parser parser = new Parser(PATTERN, line); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, parser.nextInt()); - - if (parser.next().equals("H")) { - position.set(Position.KEY_ARCHIVE, true); - } - - position.set(Position.KEY_EVENT, parser.nextInt()); - - position.setValid(true); - position.setTime(parser.nextDateTime()); - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setAltitude(parser.nextInt()); - position.setCourse(parser.nextInt()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextLong()); - position.set(Position.KEY_INPUT, parser.nextInt()); - position.set(Position.KEY_OUTPUT, parser.nextInt()); - position.set(Position.KEY_POWER, parser.nextInt() * 0.001); - position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001); - position.set(Position.PREFIX_ADC + 1, parser.nextInt()); - position.set(Position.PREFIX_ADC + 2, parser.nextInt()); - position.set(Position.PREFIX_TEMP + 1, parser.nextDouble()); - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - sentence = sentence.substring(1); // remove start symbol - - List positions = new LinkedList<>(); - for (String line : sentence.split("\r\n")) { - if (!line.isEmpty()) { - Position position = decodePosition(channel, remoteAddress, line); - if (position != null) { - positions.add(position); - } - } - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/M2mProtocol.java b/src/org/traccar/protocol/M2mProtocol.java deleted file mode 100644 index dda328a59..000000000 --- a/src/org/traccar/protocol/M2mProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.FixedLengthFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class M2mProtocol extends BaseProtocol { - - public M2mProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new FixedLengthFrameDecoder(23)); - pipeline.addLast(new M2mProtocolDecoder(M2mProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/M2mProtocolDecoder.java b/src/org/traccar/protocol/M2mProtocolDecoder.java deleted file mode 100644 index 21e4a2fd0..000000000 --- a/src/org/traccar/protocol/M2mProtocolDecoder.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class M2mProtocolDecoder extends BaseProtocolDecoder { - - public M2mProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private boolean firstPacket = true; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - // Remove offset - for (int i = 0; i < buf.readableBytes(); i++) { - int b = buf.getByte(i); - if (b != 0x0b) { - buf.setByte(i, b - 0x20); - } - } - - if (firstPacket) { - - firstPacket = false; - - StringBuilder imei = new StringBuilder(); - for (int i = 0; i < 8; i++) { - int b = buf.readByte(); - if (i != 0) { - imei.append(b / 10); - } - imei.append(b % 10); - } - - getDeviceSession(channel, remoteAddress, imei.toString()); - - } else { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setDay(buf.readUnsignedByte() & 0x3f) - .setMonth(buf.readUnsignedByte() & 0x3f) - .setYear(buf.readUnsignedByte()) - .setHour(buf.readUnsignedByte() & 0x3f) - .setMinute(buf.readUnsignedByte() & 0x7f) - .setSecond(buf.readUnsignedByte() & 0x7f); - position.setTime(dateBuilder.getDate()); - - int degrees = buf.readUnsignedByte(); - double latitude = buf.readUnsignedByte(); - latitude += buf.readUnsignedByte() / 100.0; - latitude += buf.readUnsignedByte() / 10000.0; - latitude /= 60; - latitude += degrees; - - int b = buf.readUnsignedByte(); - - degrees = (b & 0x7f) * 100 + buf.readUnsignedByte(); - double longitude = buf.readUnsignedByte(); - longitude += buf.readUnsignedByte() / 100.0; - longitude += buf.readUnsignedByte() / 10000.0; - longitude /= 60; - longitude += degrees; - - if ((b & 0x80) != 0) { - longitude = -longitude; - } - if ((b & 0x40) != 0) { - latitude = -latitude; - } - - position.setValid(true); - position.setLatitude(latitude); - position.setLongitude(longitude); - position.setSpeed(buf.readUnsignedByte()); - - int satellites = buf.readUnsignedByte(); - if (satellites == 0) { - return null; // cell information - } - position.set(Position.KEY_SATELLITES, satellites); - - // decode other data - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/MaestroProtocol.java b/src/org/traccar/protocol/MaestroProtocol.java deleted file mode 100644 index 87453ce7d..000000000 --- a/src/org/traccar/protocol/MaestroProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.FixedLengthFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class MaestroProtocol extends BaseProtocol { - - public MaestroProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new FixedLengthFrameDecoder(160)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new MaestroProtocolDecoder(MaestroProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/MaestroProtocolDecoder.java b/src/org/traccar/protocol/MaestroProtocolDecoder.java deleted file mode 100644 index 37b097414..000000000 --- a/src/org/traccar/protocol/MaestroProtocolDecoder.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class MaestroProtocolDecoder extends BaseProtocolDecoder { - - public MaestroProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("@") - .number("(d+),") // imei - .number("d+,") // index - .expression("[^,]+,") // profile - .expression("([01]),") // validity - .number("(d+.d+),") // battery - .number("(d+),") // gsm - .expression("([01]),") // starter - .expression("([01]),") // ignition - .number("(dd)/(dd)/(dd),") // date (yy/mm/dd) - .number("(dd):(dd):(dd),") // time (hh:mm:ss) - .number("(-?d+.d+),") // longitude - .number("(-?d+.d+),") // latitude - .number("(d+.?d*),") // altitude - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(d+),") // satellites - .number("(d+.?d*),") // hdop - .number("(d+.?d*)") // odometer - .number(",(d+)").optional() // adc - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.nextInt(0) == 1); - - position.set(Position.KEY_BATTERY, parser.nextDouble(0)); - position.set(Position.KEY_RSSI, parser.nextInt(0)); - position.set(Position.KEY_CHARGE, parser.nextInt(0) == 1); - position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_HDOP, parser.nextDouble(0)); - position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1609.34); - - if (parser.hasNext()) { - position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/ManPowerProtocol.java b/src/org/traccar/protocol/ManPowerProtocol.java deleted file mode 100644 index 49d8b1e9f..000000000 --- a/src/org/traccar/protocol/ManPowerProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ManPowerProtocol extends BaseProtocol { - - public ManPowerProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new ManPowerProtocolDecoder(ManPowerProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ManPowerProtocolDecoder.java b/src/org/traccar/protocol/ManPowerProtocolDecoder.java deleted file mode 100644 index 2c7b7eb40..000000000 --- a/src/org/traccar/protocol/ManPowerProtocolDecoder.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class ManPowerProtocolDecoder extends BaseProtocolDecoder { - - public ManPowerProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("simei:") - .number("(d+),") // imei - .expression("[^,]*,[^,]*,") - .expression("([^,]*),") // status - .number("d+,d+,d+.?d*,") - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // validity - .number("(dd)(dd.dddd),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.dddd),") // longitude - .expression("([EW])?,") - .number("(d+.?d*),") // speed - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_STATUS, parser.next()); - - position.setTime(parser.nextDateTime()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/MegastekFrameDecoder.java b/src/org/traccar/protocol/MegastekFrameDecoder.java deleted file mode 100644 index 347fa24b1..000000000 --- a/src/org/traccar/protocol/MegastekFrameDecoder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; -import org.traccar.helper.BufferUtil; - -import java.nio.charset.StandardCharsets; - -public class MegastekFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 10) { - return null; - } - - if (Character.isDigit(buf.getByte(buf.readerIndex()))) { - int length = 4 + Integer.parseInt(buf.toString(buf.readerIndex(), 4, StandardCharsets.US_ASCII)); - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - } else { - while (buf.getByte(buf.readerIndex()) == '\r' || buf.getByte(buf.readerIndex()) == '\n') { - buf.skipBytes(1); - } - int delimiter = BufferUtil.indexOf("\r\n", buf); - if (delimiter == -1) { - delimiter = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '!'); - } - if (delimiter != -1) { - ByteBuf result = buf.readRetainedSlice(delimiter - buf.readerIndex()); - buf.skipBytes(1); - return result; - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/MegastekProtocol.java b/src/org/traccar/protocol/MegastekProtocol.java deleted file mode 100644 index e9f5f9fde..000000000 --- a/src/org/traccar/protocol/MegastekProtocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class MegastekProtocol extends BaseProtocol { - - public MegastekProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new MegastekFrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new MegastekProtocolDecoder(MegastekProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/MegastekProtocolDecoder.java b/src/org/traccar/protocol/MegastekProtocolDecoder.java deleted file mode 100644 index d81cc0eda..000000000 --- a/src/org/traccar/protocol/MegastekProtocolDecoder.java +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class MegastekProtocolDecoder extends BaseProtocolDecoder { - - public MegastekProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_GPRMC = new PatternBuilder() - .text("$GPRMC,") - .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),([NS]),") // latitude - .number("(d+)(dd.d+),([EW]),") // longitude - .number("(d+.d+)?,") // speed - .number("(d+.d+)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() // checksum - .compile(); - - private static final Pattern PATTERN_SIMPLE = new PatternBuilder() - .expression("[FL],") // flag - .expression("([^,]*),") // alarm - .number("imei:(d+),") // imei - .number("(d+/?d*)?,") // satellites - .number("(d+.d+)?,") // altitude - .number("Battery=(d+)%,,?") // battery - .number("(d)?,") // charger - .number("(d+)?,") // mcc - .number("(d+)?,") // mnc - .number("(xxxx),") // lac - .number("(xxxx);") // cid - .any() // checksum - .compile(); - - private static final Pattern PATTERN_ALTERNATIVE = new PatternBuilder() - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(xxxx),") // lac - .number("(xxxx),") // cid - .number("(d+),") // gsm signal - .number("(d+),") // battery - .number("(d+),") // flags - .number("(d+),") // inputs - .number("(?:(d+),)?") // outputs - .number("(d.?d*),") // adc 1 - .groupBegin() - .number("(d.dd),") // adc 2 - .number("(d.dd),") // adc 3 - .groupEnd("?") - .expression("([^;]+);") // alarm - .any() // checksum - .compile(); - - private boolean parseLocation(String location, Position position) { - - Parser parser = new Parser(PATTERN_GPRMC, location); - if (!parser.matches()) { - return false; - } - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return true; - } - - private Position decodeOld(Channel channel, SocketAddress remoteAddress, String sentence) { - - // Detect type - boolean simple = sentence.charAt(3) == ',' || sentence.charAt(6) == ','; - - // Split message - String id; - String location; - String status; - if (simple) { - - int beginIndex = sentence.indexOf(',') + 1; - int endIndex = sentence.indexOf(',', beginIndex); - id = sentence.substring(beginIndex, endIndex); - - beginIndex = endIndex + 1; - endIndex = sentence.indexOf('*', beginIndex); - if (endIndex != -1) { - endIndex += 3; - } else { - endIndex = sentence.length(); - } - location = sentence.substring(beginIndex, endIndex); - - beginIndex = endIndex + 1; - if (beginIndex > sentence.length()) { - beginIndex = endIndex; - } - status = sentence.substring(beginIndex); - - } else { - - int beginIndex = 3; - int endIndex = beginIndex + 16; - id = sentence.substring(beginIndex, endIndex).trim(); - - beginIndex = endIndex + 2; - endIndex = sentence.indexOf('*', beginIndex) + 3; - location = sentence.substring(beginIndex, endIndex); - - beginIndex = endIndex + 1; - status = sentence.substring(beginIndex); - - } - - Position position = new Position(getProtocolName()); - if (!parseLocation(location, position)) { - return null; - } - - if (simple) { - - Parser parser = new Parser(PATTERN_SIMPLE, status); - if (parser.matches()) { - - position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next(), id); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - String sat = parser.next(); - if (sat.contains("/")) { - position.set(Position.KEY_SATELLITES, Integer.parseInt(sat.split("/")[0])); - position.set(Position.KEY_SATELLITES_VISIBLE, Integer.parseInt(sat.split("/")[1])); - } else { - position.set(Position.KEY_SATELLITES, Integer.parseInt(sat)); - } - - position.setAltitude(parser.nextDouble(0)); - - position.set(Position.KEY_BATTERY_LEVEL, parser.nextDouble(0)); - - String charger = parser.next(); - if (charger != null) { - position.set(Position.KEY_CHARGE, Integer.parseInt(charger) == 1); - } - - if (parser.hasNext(4)) { - position.setNetwork(new Network(CellTower.from( - parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); - } - - } else { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - } - - } else { - - Parser parser = new Parser(PATTERN_ALTERNATIVE, status); - if (parser.matches()) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setNetwork(new Network(CellTower.from(parser.nextInt(0), parser.nextInt(0), - parser.nextHexInt(0), parser.nextHexInt(0), parser.nextInt(0)))); - - position.set(Position.KEY_BATTERY_LEVEL, parser.nextDouble()); - - position.set(Position.KEY_FLAGS, parser.next()); - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - position.set(Position.PREFIX_ADC + 3, parser.next()); - position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); - - } - } - - return position; - } - - private static final Pattern PATTERN_NEW = new PatternBuilder() - .number("dddd").optional() - .text("$MGV") - .number("ddd,") - .number("(d+),") // imei - .expression("[^,]*,") // name - .expression("([RS]),") - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),([NS]),") // latitude - .number("(d+)(dd.d+),([EW]),") // longitude - .number("dd,") - .number("(dd),") // satellites - .number("dd,") - .number("(d+.d+),") // hdop - .number("(d+.d+)?,") // speed - .number("(d+.d+)?,") // course - .number("(-?d+.d+),") // altitude - .number("(d+.d+)?,") // odometer - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(xxxx)?,") // lac - .number("(x+)?,") // cid - .number("(d+)?,") // gsm - .groupBegin() - .number("([01]{4})?,") // input - .number("([01]{4})?,") // output - .number("(d+)?,") // adc1 - .number("(d+)?,") // adc2 - .number("(d+)?,") // adc3 - .or() - .number("(d+),") // input - .number("(d+),") // output - .number("(d+),") // adc1 - .number("(d+),") // adc2 - .number("(d+),") // adc3 - .groupEnd() - .groupBegin() - .number("(-?d+.?d*)") // temperature 1 - .or().text(" ") - .groupEnd("?").text(",") - .groupBegin() - .number("(-?d+.?d*)") // temperature 2 - .or().text(" ") - .groupEnd("?").text(",") - .number("(d+)?,") // rfid - .expression("[^,]*,") - .number("(d+)?,") // battery - .expression("([^,]*)") // alert - .any() - .compile(); - - private Position decodeNew(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_NEW, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.next().equals("S")) { - position.set(Position.KEY_ARCHIVE, true); - } - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_HDOP, parser.nextDouble(0)); - - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - if (parser.hasNext()) { - position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); - } - - int mcc = parser.nextInt(); - int mnc = parser.nextInt(); - Integer lac = parser.nextHexInt(); - Integer cid = parser.nextHexInt(); - Integer rssi = parser.nextInt(); - if (lac != null && cid != null) { - CellTower tower = CellTower.from(mcc, mnc, lac, cid); - if (rssi != null) { - tower.setSignalStrength(rssi); - } - position.setNetwork(new Network(tower)); - } - - if (parser.hasNext(5)) { - position.set(Position.KEY_INPUT, parser.nextBinInt(0)); - position.set(Position.KEY_OUTPUT, parser.nextBinInt(0)); - for (int i = 1; i <= 3; i++) { - position.set(Position.PREFIX_ADC + i, parser.nextInt(0)); - } - } - - if (parser.hasNext(5)) { - position.set(Position.KEY_HEART_RATE, parser.nextInt()); - position.set(Position.KEY_STEPS, parser.nextInt()); - position.set("activityTime", parser.nextInt()); - position.set("lightSleepTime", parser.nextInt()); - position.set("deepSleepTime", parser.nextInt()); - } - - for (int i = 1; i <= 2; i++) { - String adc = parser.next(); - if (adc != null) { - position.set(Position.PREFIX_TEMP + i, Double.parseDouble(adc)); - } - } - - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - String battery = parser.next(); - if (battery != null) { - position.set(Position.KEY_BATTERY, Integer.parseInt(battery)); - } - - position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); - - return position; - } - - private String decodeAlarm(String value) { - value = value.toLowerCase(); - if (value.startsWith("geo")) { - if (value.endsWith("in")) { - return Position.ALARM_GEOFENCE_ENTER; - } else if (value.endsWith("out")) { - return Position.ALARM_GEOFENCE_EXIT; - } - } - switch (value) { - case "poweron": - return Position.ALARM_POWER_ON; - case "poweroff": - return Position.ALARM_POWER_ON; - case "sos": - case "help": - return Position.ALARM_SOS; - case "over speed": - case "overspeed": - return Position.ALARM_OVERSPEED; - case "lowspeed": - return Position.ALARM_LOW_SPEED; - case "low battery": - case "lowbattery": - return Position.ALARM_LOW_BATTERY; - case "vib": - return Position.ALARM_VIBRATION; - case "move in": - return Position.ALARM_GEOFENCE_ENTER; - case "move out": - return Position.ALARM_GEOFENCE_EXIT; - case "error": - return Position.ALARM_FAULT; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.contains("$MG")) { - return decodeNew(channel, remoteAddress, sentence); - } else { - return decodeOld(channel, remoteAddress, sentence); - } - } - -} diff --git a/src/org/traccar/protocol/MeiligaoFrameDecoder.java b/src/org/traccar/protocol/MeiligaoFrameDecoder.java deleted file mode 100644 index 52f9ae26d..000000000 --- a/src/org/traccar/protocol/MeiligaoFrameDecoder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class MeiligaoFrameDecoder extends BaseFrameDecoder { - - private static final int MESSAGE_HEADER = 4; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - // Strip not '$' (0x24) bytes from the beginning - while (buf.isReadable() && buf.getUnsignedByte(buf.readerIndex()) != 0x24) { - buf.readByte(); - } - - // Check length and return buffer - if (buf.readableBytes() >= MESSAGE_HEADER) { - int length = buf.getUnsignedShort(buf.readerIndex() + 2); - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/MeiligaoProtocol.java b/src/org/traccar/protocol/MeiligaoProtocol.java deleted file mode 100644 index c307c7318..000000000 --- a/src/org/traccar/protocol/MeiligaoProtocol.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class MeiligaoProtocol extends BaseProtocol { - - public MeiligaoProtocol() { - setSupportedDataCommands( - Command.TYPE_POSITION_SINGLE, - Command.TYPE_POSITION_PERIODIC, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_ALARM_GEOFENCE, - Command.TYPE_SET_TIMEZONE, - Command.TYPE_REQUEST_PHOTO, - Command.TYPE_REBOOT_DEVICE); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new MeiligaoFrameDecoder()); - pipeline.addLast(new MeiligaoProtocolEncoder()); - pipeline.addLast(new MeiligaoProtocolDecoder(MeiligaoProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new MeiligaoProtocolEncoder()); - pipeline.addLast(new MeiligaoProtocolDecoder(MeiligaoProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java deleted file mode 100644 index cbfc3660a..000000000 --- a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -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.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -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 photos = new HashMap<>(); - - public MeiligaoProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .expression("[^\\|]*") - .groupBegin() - .number("|(d+.d+)?") // hdop - .number("|(-?d+.?d*)?") // altitude - .number("|(xxxx)?") // state - .groupBegin() - .number("|(xxxx),(xxxx)") // adc - .number(",(xxxx)").optional() - .number(",(xxxx)").optional() - .number(",(xxxx)").optional() - .number(",(xxxx)").optional() - .number(",(xxxx)").optional() - .number(",(xxxx)").optional() - .groupBegin() - .number("|x{16,20}") // cell - .number("|(xx)") // rssi - .number("|(x{8})") // odometer - .groupBegin() - .number("|(xx)") // satellites - .text("|") - .expression("(.*)") // driver - .groupEnd("?") - .or() - .number("|(d{1,9})") // odometer - .groupBegin() - .number("|(x{5,})") // rfid - .groupEnd("?") - .groupEnd("?") - .groupEnd("?") - .groupEnd("?") - .any() - .compile(); - - private static final Pattern PATTERN_RFID = new PatternBuilder() - .number("|(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW])") - .compile(); - - private static final Pattern PATTERN_OBD = new PatternBuilder() - .number("(d+.d+),") // battery - .number("(d+),") // rpm - .number("(d+),") // speed - .number("(d+.d+),") // throttle - .number("(d+.d+),") // engine load - .number("(-?d+),") // coolant temp - .number("(d+.d+),") // instantaneous fuel - .number("(d+.d+),") // average fuel - .number("(d+.d+),") // driving range - .number("(d+.?d*),") // odometer - .number("(d+.d+),") // single fuel consumption - .number("(d+.d+),") // total fuel consumption - .number("(d+),") // error code count - .number("(d+),") // hard acceleration count - .number("(d+)") // hard brake count - .compile(); - - private static final Pattern PATTERN_OBDA = new PatternBuilder() - .number("(d+),") // total ignition - .number("(d+.d+),") // total driving time - .number("(d+.d+),") // total idling time - .number("(d+),") // average hot start time - .number("(d+),") // average speed - .number("(d+),") // history highest speed - .number("(d+),") // history highest rpm - .number("(d+),") // total hard acceleration - .number("(d+)") // total hard brake - .compile(); - - public static final int MSG_HEARTBEAT = 0x0001; - public static final int MSG_SERVER = 0x0002; - public static final int MSG_LOGIN = 0x5000; - public static final int MSG_LOGIN_RESPONSE = 0x4000; - public static final int MSG_POSITION = 0x9955; - public static final int MSG_POSITION_LOGGED = 0x9016; - public static final int MSG_ALARM = 0x9999; - public static final int MSG_RFID = 0x9966; - public static final int MSG_RETRANSMISSION = 0x6688; - - 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(ByteBuf buf, Channel channel, SocketAddress remoteAddress) { - StringBuilder builder = new StringBuilder(); - - for (int i = 0; i < 7; i++) { - int b = buf.readUnsignedByte(); - - // First digit - int d1 = (b & 0xf0) >> 4; - if (d1 == 0xf) { - break; - } - builder.append(d1); - - // Second digit - int d2 = b & 0x0f; - if (d2 == 0xf) { - break; - } - builder.append(d2); - } - - String id = builder.toString(); - - if (id.length() == 14) { - return getDeviceSession(channel, remoteAddress, id, id + Checksum.luhn(Long.parseLong(id))); - } else { - return getDeviceSession(channel, remoteAddress, id); - } - } - - private static void sendResponse( - Channel channel, SocketAddress remoteAddress, ByteBuf id, int type, ByteBuf msg) { - - if (channel != null) { - ByteBuf buf = Unpooled.buffer( - 2 + 2 + id.readableBytes() + 2 + msg.readableBytes() + 2 + 2); - - buf.writeByte('@'); - buf.writeByte('@'); - buf.writeShort(buf.capacity()); - buf.writeBytes(id); - buf.writeShort(type); - buf.writeBytes(msg); - msg.release(); - buf.writeShort(Checksum.crc16(Checksum.CRC16_CCITT_FALSE, buf.nioBuffer())); - buf.writeByte('\r'); - buf.writeByte('\n'); - - channel.writeAndFlush(new NetworkMessage(buf, remoteAddress)); - } - } - - private String decodeAlarm(short value) { - switch (value) { - case 0x01: - return Position.ALARM_SOS; - case 0x10: - return Position.ALARM_LOW_BATTERY; - case 0x11: - return Position.ALARM_OVERSPEED; - case 0x12: - return Position.ALARM_MOVEMENT; - case 0x13: - return Position.ALARM_GEOFENCE_ENTER; - case 0x14: - return Position.ALARM_ACCIDENT; - case 0x50: - return Position.ALARM_POWER_OFF; - case 0x53: - return Position.ALARM_GPS_ANTENNA_CUT; - case 0x72: - return Position.ALARM_BRAKING; - case 0x73: - return Position.ALARM_ACCELERATION; - default: - return null; - } - } - - private Position decodeRegular(Position position, String sentence) { - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - if (parser.hasNext()) { - position.setSpeed(parser.nextDouble(0)); - } - - if (parser.hasNext()) { - position.setCourse(parser.nextDouble(0)); - } - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_HDOP, parser.nextDouble()); - - if (parser.hasNext()) { - position.setAltitude(parser.nextDouble(0)); - } - - if (parser.hasNext()) { - int status = parser.nextHexInt(); - for (int i = 1; i <= 5; i++) { - position.set(Position.PREFIX_OUT + i, BitUtil.check(status, i - 1)); - } - for (int i = 1; i <= 5; i++) { - position.set(Position.PREFIX_IN + i, BitUtil.check(status, i - 1 + 8)); - } - } - - for (int i = 1; i <= 8; i++) { - position.set(Position.PREFIX_ADC + i, parser.nextHexInt()); - } - - position.set(Position.KEY_RSSI, parser.nextHexInt()); - position.set(Position.KEY_ODOMETER, parser.nextHexLong()); - position.set(Position.KEY_SATELLITES, parser.nextHexInt()); - position.set("driverLicense", parser.next()); - position.set(Position.KEY_ODOMETER, parser.nextLong()); - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - return position; - } - - private Position decodeRfid(Position position, String sentence) { - Parser parser = new Parser(PATTERN_RFID, sentence); - if (!parser.matches()) { - return null; - } - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - return position; - } - - private Position decodeObd(Position position, String sentence) { - Parser parser = new Parser(PATTERN_OBD, sentence); - if (!parser.matches()) { - return null; - } - - getLastLocation(position, null); - - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.KEY_RPM, parser.nextInt()); - position.set(Position.KEY_OBD_SPEED, parser.nextInt()); - position.set(Position.KEY_THROTTLE, parser.nextDouble()); - position.set(Position.KEY_ENGINE_LOAD, parser.nextDouble()); - position.set(Position.KEY_COOLANT_TEMP, parser.nextInt()); - position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextDouble()); - position.set("averageFuelConsumption", parser.nextDouble()); - position.set("drivingRange", parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextDouble()); - position.set("singleFuelConsumption", parser.nextDouble()); - position.set(Position.KEY_FUEL_USED, parser.nextDouble()); - position.set(Position.KEY_DTCS, parser.nextInt()); - position.set("hardAccelerationCount", parser.nextInt()); - position.set("hardBrakingCount", parser.nextInt()); - - return position; - } - - private Position decodeObdA(Position position, String sentence) { - Parser parser = new Parser(PATTERN_OBDA, sentence); - if (!parser.matches()) { - return null; - } - - getLastLocation(position, null); - - position.set("totalIgnitionNo", parser.nextInt(0)); - position.set("totalDrivingTime", parser.nextDouble(0)); - position.set("totalIdlingTime", parser.nextDouble(0)); - position.set("averageHotStartTime", parser.nextInt(0)); - position.set("averageSpeed", parser.nextInt(0)); - position.set("historyHighestSpeed", parser.nextInt(0)); - position.set("historyHighestRpm", parser.nextInt(0)); - position.set("totalHarshAccerleration", parser.nextInt(0)); - position.set("totalHarshBrake", parser.nextInt(0)); - - return position; - } - - private List decodeRetransmission(ByteBuf buf, DeviceSession deviceSession) { - List positions = new LinkedList<>(); - - int count = buf.readUnsignedByte(); - for (int i = 0; i < count; i++) { - - buf.readUnsignedByte(); // alarm - - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\\'); - if (endIndex < 0) { - endIndex = buf.writerIndex() - 4; - } - - String sentence = buf.readSlice(endIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position = decodeRegular(position, sentence); - - if (position != null) { - positions.add(position); - } - - if (buf.readableBytes() > 4) { - buf.readUnsignedByte(); // delimiter - } - - } - - return positions; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - buf.skipBytes(2); // header - buf.readShort(); // length - ByteBuf id = buf.readSlice(7); - int command = buf.readUnsignedShort(); - - if (command == MSG_LOGIN) { - ByteBuf response = Unpooled.wrappedBuffer(new byte[]{0x01}); - sendResponse(channel, remoteAddress, id, MSG_LOGIN_RESPONSE, response); - return null; - } else if (command == MSG_HEARTBEAT) { - ByteBuf response = Unpooled.wrappedBuffer(new byte[]{0x01}); - sendResponse(channel, remoteAddress, id, MSG_HEARTBEAT, response); - return null; - } else if (command == MSG_SERVER) { - ByteBuf response = Unpooled.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, Unpooled.buffer()); - ByteBuf response = Unpooled.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(); - ByteBuf response = Unpooled.copiedBuffer(new byte[]{imageIndex, 0, 0}); - sendResponse(channel, remoteAddress, id, MSG_RETRANSMISSION, response); - return null; - } - - DeviceSession deviceSession = identify(id, channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - 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); - - } else { - - Position position = new Position(getProtocolName()); - - position.setDeviceId(deviceSession.getDeviceId()); - - if (command == MSG_ALARM) { - short alarmCode = buf.readUnsignedByte(); - position.set(Position.KEY_ALARM, decodeAlarm(alarmCode)); - if (alarmCode >= 0x02 && alarmCode <= 0x05) { - position.set(Position.PREFIX_IN + alarmCode, 1); - } else if (alarmCode >= 0x32 && alarmCode <= 0x35) { - position.set(Position.PREFIX_IN + (alarmCode - 0x30), 0); - } - } else if (command == MSG_POSITION_LOGGED) { - buf.skipBytes(6); - } else if (command == MSG_RFID) { - for (int i = 0; i < 15; i++) { - long rfid = buf.readUnsignedInt(); - if (rfid != 0) { - String card = String.format("%010d", rfid); - position.set("card" + (i + 1), card); - 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(); - ByteBuf photo = photos.remove(imageIndex); - try { - position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg")); - } finally { - photo.release(); - } - } - - String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 4, StandardCharsets.US_ASCII); - - 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; - } - - } - } - -} diff --git a/src/org/traccar/protocol/MeiligaoProtocolEncoder.java b/src/org/traccar/protocol/MeiligaoProtocolEncoder.java deleted file mode 100644 index 57cbbe0fc..000000000 --- a/src/org/traccar/protocol/MeiligaoProtocolEncoder.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.helper.Checksum; -import org.traccar.helper.DataConverter; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; -import java.util.TimeZone; - -public class MeiligaoProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeContent(long deviceId, int type, ByteBuf content) { - - ByteBuf buf = Unpooled.buffer(); - - buf.writeByte('@'); - buf.writeByte('@'); - - buf.writeShort(2 + 2 + 7 + 2 + content.readableBytes() + 2 + 2); // message length - - buf.writeBytes(DataConverter.parseHex((getUniqueId(deviceId) + "FFFFFFFFFFFFFF").substring(0, 14))); - - buf.writeShort(type); - - buf.writeBytes(content); - - buf.writeShort(Checksum.crc16(Checksum.CRC16_CCITT_FALSE, buf.nioBuffer())); - - buf.writeByte('\r'); - buf.writeByte('\n'); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - ByteBuf content = Unpooled.buffer(); - - switch (command.getType()) { - case Command.TYPE_POSITION_SINGLE: - 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(), MeiligaoProtocolDecoder.MSG_TRACK_BY_INTERVAL, content); - case Command.TYPE_ENGINE_STOP: - content.writeByte(0x01); - return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL, content); - case Command.TYPE_ENGINE_RESUME: - content.writeByte(0x00); - 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(), 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(), 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(), MeiligaoProtocolDecoder.MSG_REBOOT_GPS, content); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/MeitrackFrameDecoder.java b/src/org/traccar/protocol/MeitrackFrameDecoder.java deleted file mode 100644 index d122bca0c..000000000 --- a/src/org/traccar/protocol/MeitrackFrameDecoder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -import java.nio.charset.StandardCharsets; - -public class MeitrackFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 10) { - return null; - } - - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); - if (index != -1) { - int length = index - buf.readerIndex() + Integer.parseInt( - buf.toString(buf.readerIndex() + 3, index - buf.readerIndex() - 3, StandardCharsets.US_ASCII)); - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/MeitrackProtocol.java b/src/org/traccar/protocol/MeitrackProtocol.java deleted file mode 100644 index c887cd3a0..000000000 --- a/src/org/traccar/protocol/MeitrackProtocol.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class MeitrackProtocol extends BaseProtocol { - - public MeitrackProtocol() { - setSupportedDataCommands( - Command.TYPE_POSITION_SINGLE, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_ALARM_ARM, - Command.TYPE_ALARM_DISARM, - Command.TYPE_REQUEST_PHOTO, - Command.TYPE_SEND_SMS); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new MeitrackFrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new MeitrackProtocolEncoder()); - pipeline.addLast(new MeitrackProtocolDecoder(MeitrackProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new MeitrackProtocolEncoder()); - pipeline.addLast(new MeitrackProtocolDecoder(MeitrackProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/org/traccar/protocol/MeitrackProtocolDecoder.java deleted file mode 100644 index 55260ef0c..000000000 --- a/src/org/traccar/protocol/MeitrackProtocolDecoder.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; - -public class MeitrackProtocolDecoder extends BaseProtocolDecoder { - - private ByteBuf photo; - - public MeitrackProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$$").expression(".") // flag - .number("d+,") // length - .number("(d+),") // imei - .number("xxx,") // command - .number("d+,").optional() - .number("(d+),") // event - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("([AV]),") // validity - .number("(d+),") // satellites - .number("(d+),") // rssi - .number("(d+.?d*),") // speed - .number("(d+),") // course - .number("(d+.?d*),") // hdop - .number("(-?d+),") // altitude - .number("(d+),") // odometer - .number("(d+),") // runtime - .number("(d+)|") // mcc - .number("(d+)|") // mnc - .number("(x+)|") // lac - .number("(x+),") // cid - .number("(x+),") // state - .number("(x+)?|") // adc1 - .number("(x+)?|") // adc2 - .number("(x+)?|") // adc3 - .number("(x+)|") // battery - .number("(x+)?,") // power - .groupBegin() - .expression("([^,]+)?,").optional() // event specific - .expression("[^,]*,") // reserved - .number("(d+)?,") // protocol - .number("(x{4})?") // fuel - .groupBegin() - .number(",(x{6}(?:|x{6})*)?") // temperature - .groupBegin() - .number(",(d+)") // data count - .expression(",([^*]*)") // data - .groupEnd("?") - .groupEnd("?") - .or() - .any() - .groupEnd() - .text("*") - .number("xx") - .text("\r\n").optional() - .compile(); - - private String decodeAlarm(int event) { - switch (event) { - case 1: - return Position.ALARM_SOS; - case 17: - return Position.ALARM_LOW_BATTERY; - case 18: - return Position.ALARM_LOW_POWER; - case 19: - return Position.ALARM_OVERSPEED; - case 20: - return Position.ALARM_GEOFENCE_ENTER; - case 21: - return Position.ALARM_GEOFENCE_EXIT; - case 22: - return Position.ALARM_POWER_RESTORED; - case 23: - return Position.ALARM_POWER_CUT; - case 36: - return Position.ALARM_TOW; - case 44: - return Position.ALARM_JAMMING; - case 78: - return Position.ALARM_ACCIDENT; - case 90: - case 91: - return Position.ALARM_CORNERING; - case 129: - return Position.ALARM_BRAKING; - case 130: - return Position.ALARM_ACCELERATION; - case 135: - return Position.ALARM_FATIGUE_DRIVING; - default: - return null; - } - } - - private Position decodeRegular(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - Parser parser = new Parser(PATTERN, buf.toString(StandardCharsets.US_ASCII)); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - int event = parser.nextInt(0); - position.set(Position.KEY_EVENT, event); - position.set(Position.KEY_ALARM, decodeAlarm(event)); - - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - - position.setTime(parser.nextDateTime()); - - position.setValid(parser.next().equals("A")); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - int rssi = parser.nextInt(0); - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_HDOP, parser.nextDouble()); - - position.setAltitude(parser.nextDouble(0)); - - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - position.set("runtime", parser.next()); - - position.setNetwork(new Network(CellTower.from( - parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0), rssi))); - - position.set(Position.KEY_STATUS, parser.next()); - - for (int i = 1; i <= 3; i++) { - if (parser.hasNext()) { - position.set(Position.PREFIX_ADC + i, parser.nextHexInt(0)); - } - } - - String deviceModel = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getModel(); - if (deviceModel == null) { - deviceModel = ""; - } - switch (deviceModel.toUpperCase()) { - case "MVT340": - case "MVT380": - position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.0 * 2.0 / 1024.0); - position.set(Position.KEY_POWER, parser.nextHexInt(0) * 3.0 * 16.0 / 1024.0); - break; - case "MT90": - position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.3 * 2.0 / 4096.0); - position.set(Position.KEY_POWER, parser.nextHexInt(0)); - break; - case "T1": - case "T3": - case "MVT100": - case "MVT600": - case "MVT800": - case "TC68": - case "TC68S": - position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.3 * 2.0 / 4096.0); - position.set(Position.KEY_POWER, parser.nextHexInt(0) * 3.3 * 16.0 / 4096.0); - break; - case "T311": - case "T322X": - case "T333": - case "T355": - position.set(Position.KEY_BATTERY, parser.nextHexInt(0) / 100.0); - position.set(Position.KEY_POWER, parser.nextHexInt(0) / 100.0); - break; - default: - position.set(Position.KEY_BATTERY, parser.nextHexInt(0)); - position.set(Position.KEY_POWER, parser.nextHexInt(0)); - break; - } - - String eventData = parser.next(); - if (eventData != null && !eventData.isEmpty()) { - switch (event) { - case 37: - position.set(Position.KEY_DRIVER_UNIQUE_ID, eventData); - break; - default: - position.set("eventData", eventData); - break; - } - } - - int protocol = parser.nextInt(0); - - if (parser.hasNext()) { - String fuel = parser.next(); - position.set(Position.KEY_FUEL_LEVEL, - Integer.parseInt(fuel.substring(0, 2), 16) + Integer.parseInt(fuel.substring(2), 16) * 0.01); - } - - if (parser.hasNext()) { - for (String temp : parser.next().split("\\|")) { - int index = Integer.parseInt(temp.substring(0, 2), 16); - if (protocol >= 3) { - double value = (short) Integer.parseInt(temp.substring(2), 16); - position.set(Position.PREFIX_TEMP + index, value * 0.01); - } else { - double value = Byte.parseByte(temp.substring(2, 4), 16); - value += (value < 0 ? -0.01 : 0.01) * Integer.parseInt(temp.substring(4), 16); - position.set(Position.PREFIX_TEMP + index, value); - } - } - } - - if (parser.hasNext(2)) { - parser.nextInt(); // count - decodeDataFields(position, parser.next().split(",")); - } - - return position; - } - - private void decodeDataFields(Position position, String[] values) { - - if (values.length > 1 && !values[1].isEmpty()) { - position.set("tempData", values[1]); - } - - if (values.length > 5 && !values[5].isEmpty()) { - String[] data = values[5].split("\\|"); - boolean started = data[0].charAt(1) == '0'; - position.set("taximeterOn", started); - position.set("taximeterStart", data[1]); - if (data.length > 2) { - position.set("taximeterEnd", data[2]); - position.set("taximeterDistance", Integer.parseInt(data[3])); - position.set("taximeterFare", Integer.parseInt(data[4])); - position.set("taximeterTrip", data[5]); - position.set("taximeterWait", data[6]); - } - } - - } - - private List decodeBinaryC(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - List positions = new LinkedList<>(); - - String flag = buf.toString(2, 1, StandardCharsets.US_ASCII); - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); - - String imei = buf.toString(index + 1, 15, StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - buf.skipBytes(index + 1 + 15 + 1 + 3 + 1 + 2 + 2 + 4); - - while (buf.readableBytes() >= 0x34) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - - position.setLatitude(buf.readIntLE() * 0.000001); - position.setLongitude(buf.readIntLE() * 0.000001); - - position.setTime(new Date((946684800 + buf.readUnsignedIntLE()) * 1000)); // 946684800 = 2000-01-01 - - position.setValid(buf.readUnsignedByte() == 1); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - int rssi = buf.readUnsignedByte(); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); - position.setCourse(buf.readUnsignedShortLE()); - - position.set(Position.KEY_HDOP, buf.readUnsignedShortLE() * 0.1); - - position.setAltitude(buf.readUnsignedShortLE()); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - position.set("runtime", buf.readUnsignedIntLE()); - - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), - buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), - rssi))); - - position.set(Position.KEY_STATUS, buf.readUnsignedShortLE()); - - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); - position.set(Position.KEY_POWER, buf.readUnsignedShortLE()); - - buf.readUnsignedIntLE(); // geo-fence - - positions.add(position); - } - - if (channel != null) { - StringBuilder command = new StringBuilder("@@"); - command.append(flag).append(27 + positions.size() / 10).append(","); - command.append(imei).append(",CCC,").append(positions.size()).append("*"); - int checksum = 0; - for (int i = 0; i < command.length(); i += 1) { - checksum += command.charAt(i); - } - command.append(String.format("%02x", checksum & 0xff).toUpperCase()); - command.append("\r\n"); - channel.writeAndFlush(new NetworkMessage(command.toString(), remoteAddress)); // delete processed data - } - - return positions; - } - - private List decodeBinaryE(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - List positions = new LinkedList<>(); - - buf.readerIndex(buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ',') + 1); - String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); - buf.skipBytes(1 + 3 + 1); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - buf.readUnsignedIntLE(); // remaining cache - int count = buf.readUnsignedShortLE(); - - for (int i = 0; i < count; i++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedShortLE(); // length - buf.readUnsignedShortLE(); // index - - int paramCount = buf.readUnsignedByte(); - for (int j = 0; j < paramCount; j++) { - int id = buf.readUnsignedByte(); - switch (id) { - case 0x01: - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - break; - case 0x05: - position.setValid(buf.readUnsignedByte() > 0); - break; - case 0x06: - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - break; - case 0x07: - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - break; - default: - buf.readUnsignedByte(); - break; - } - } - - paramCount = buf.readUnsignedByte(); - for (int j = 0; j < paramCount; j++) { - int id = buf.readUnsignedByte(); - switch (id) { - case 0x08: - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); - break; - case 0x09: - position.setCourse(buf.readUnsignedShortLE()); - break; - case 0x0B: - position.setAltitude(buf.readShortLE()); - break; - case 0x19: - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01); - break; - case 0x1A: - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01); - break; - default: - buf.readUnsignedShortLE(); - break; - } - } - - paramCount = buf.readUnsignedByte(); - for (int j = 0; j < paramCount; j++) { - int id = buf.readUnsignedByte(); - switch (id) { - case 0x02: - position.setLatitude(buf.readIntLE() * 0.000001); - break; - case 0x03: - position.setLongitude(buf.readIntLE() * 0.000001); - break; - case 0x04: - position.setTime(new Date((946684800 + buf.readUnsignedIntLE()) * 1000)); // 2000-01-01 - break; - case 0x0D: - position.set("runtime", buf.readUnsignedIntLE()); - break; - default: - buf.readUnsignedIntLE(); - break; - } - } - - paramCount = buf.readUnsignedByte(); - for (int j = 0; j < paramCount; j++) { - buf.readUnsignedByte(); // id - buf.skipBytes(buf.readUnsignedByte()); // value - } - - positions.add(position); - } - - return positions; - } - - private void requestPhotoPacket(Channel channel, SocketAddress socketAddress, String imei, String file, int index) { - if (channel != null) { - String content = "D00," + file + "," + index; - int length = 1 + imei.length() + 1 + content.length() + 5; - String response = String.format("@@O%02d,%s,%s*", length, imei, content); - response += Checksum.sum(response) + "\r\n"; - channel.writeAndFlush(new NetworkMessage(response, socketAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); - String imei = buf.toString(index + 1, 15, StandardCharsets.US_ASCII); - index = buf.indexOf(index + 1, buf.writerIndex(), (byte) ','); - String type = buf.toString(index + 1, 3, StandardCharsets.US_ASCII); - - switch (type) { - case "D00": - if (photo == null) { - photo = Unpooled.buffer(); - } - - index = index + 1 + type.length() + 1; - int endIndex = buf.indexOf(index, buf.writerIndex(), (byte) ','); - String file = buf.toString(index, endIndex - index, StandardCharsets.US_ASCII); - index = endIndex + 1; - endIndex = buf.indexOf(index, buf.writerIndex(), (byte) ','); - int total = Integer.parseInt(buf.toString(index, endIndex - index, StandardCharsets.US_ASCII)); - index = endIndex + 1; - endIndex = buf.indexOf(index, buf.writerIndex(), (byte) ','); - int current = Integer.parseInt(buf.toString(index, endIndex - index, StandardCharsets.US_ASCII)); - - buf.readerIndex(endIndex + 1); - photo.writeBytes(buf.readSlice(buf.readableBytes() - 1 - 2 - 2)); - - if (current == total - 1) { - Position position = new Position(getProtocolName()); - position.setDeviceId(getDeviceSession(channel, remoteAddress, imei).getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg")); - photo.release(); - photo = null; - - return position; - } else { - if ((current + 1) % 8 == 0) { - requestPhotoPacket(channel, remoteAddress, imei, file, current + 1); - } - return null; - } - case "D03": - photo = Unpooled.buffer(); - requestPhotoPacket(channel, remoteAddress, imei, "camera_picture.jpg", 0); - return null; - case "CCC": - return decodeBinaryC(channel, remoteAddress, buf); - case "CCE": - return decodeBinaryE(channel, remoteAddress, buf); - default: - return decodeRegular(channel, remoteAddress, buf); - } - } - -} diff --git a/src/org/traccar/protocol/MeitrackProtocolEncoder.java b/src/org/traccar/protocol/MeitrackProtocolEncoder.java deleted file mode 100644 index abb6ec9d4..000000000 --- a/src/org/traccar/protocol/MeitrackProtocolEncoder.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - * 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 org.traccar.Context; -import org.traccar.StringProtocolEncoder; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -import java.util.Map; - -public class MeitrackProtocolEncoder extends StringProtocolEncoder { - - private Object formatCommand(Command command, char dataId, String content) { - String uniqueId = getUniqueId(command.getDeviceId()); - int length = 1 + uniqueId.length() + 1 + content.length() + 5; - String result = String.format("@@%c%02d,%s,%s*", dataId, length, uniqueId, content); - result += Checksum.sum(result) + "\r\n"; - return result; - } - - @Override - protected Object encodeCommand(Command command) { - - Map attributes = command.getAttributes(); - - boolean alternative = Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "meitrack.alternative", false, true); - - switch (command.getType()) { - case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, 'Q', "A10"); - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, 'M', "C01,0,12222"); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, 'M', "C01,0,02222"); - case Command.TYPE_ALARM_ARM: - return formatCommand(command, 'M', alternative ? "B21,1" : "C01,0,22122"); - case Command.TYPE_ALARM_DISARM: - return formatCommand(command, 'M', alternative ? "B21,0" : "C01,0,22022"); - case Command.TYPE_REQUEST_PHOTO: - int index = command.getInteger(Command.KEY_INDEX); - return formatCommand(command, 'D', "D03," + (index > 0 ? index : 1) + ",camera_picture.jpg"); - case Command.TYPE_SEND_SMS: - return formatCommand(command, 'f', "C02,0," - + attributes.get(Command.KEY_PHONE) + "," + attributes.get(Command.KEY_MESSAGE)); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/MilesmateProtocol.java b/src/org/traccar/protocol/MilesmateProtocol.java deleted file mode 100644 index 822711603..000000000 --- a/src/org/traccar/protocol/MilesmateProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class MilesmateProtocol extends BaseProtocol { - - public MilesmateProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new MilesmateProtocolDecoder(MilesmateProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/MilesmateProtocolDecoder.java b/src/org/traccar/protocol/MilesmateProtocolDecoder.java deleted file mode 100644 index 901ceb8f7..000000000 --- a/src/org/traccar/protocol/MilesmateProtocolDecoder.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class MilesmateProtocolDecoder extends BaseProtocolDecoder { - - public MilesmateProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("ApiString={") - .number("A:(d+),") // imei - .number("B:(d+.d+),") // battery - .number("C:(d+.d+),") // adc - .number("D:(dd)(dd)(dd),") // time (hhmmss) - .number("E:(dd)(dd.d+)([NS]),") // latitude - .number("F:(ddd)(dd.d+)([EW]),") // longitude - .number("G:(d+.d+),") // speed - .number("H:(dd)(dd)(dd),") // date (ddmmyy) - .expression("I:[GL],") // location source - .number("J:(d{8}),") // flags - .number("K:(d{7})") // flags - .expression("([AV]),") // validity - .number("L:d{4},") // pin - .number("M:(d+.d+)") // course - .text("}") - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("+##Received OK\n", remoteAddress)); - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - String flags = parser.next(); - position.set(Position.KEY_IGNITION, flags.charAt(0) == '1'); - position.set(Position.KEY_ALARM, flags.charAt(1) == '1' ? Position.ALARM_SOS : null); - position.set(Position.KEY_CHARGE, flags.charAt(5) == '1'); - position.set(Position.KEY_ALARM, flags.charAt(7) == '1' ? Position.ALARM_OVERSPEED : null); - - flags = parser.next(); - position.set(Position.KEY_BLOCKED, flags.charAt(0) == '1'); - position.set(Position.KEY_ALARM, flags.charAt(1) == '1' ? Position.ALARM_TOW : null); - - position.setValid(parser.next().equals("A")); - - position.setCourse(parser.nextDouble()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/MiniFinderProtocol.java b/src/org/traccar/protocol/MiniFinderProtocol.java deleted file mode 100644 index d4a154053..000000000 --- a/src/org/traccar/protocol/MiniFinderProtocol.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class MiniFinderProtocol extends BaseProtocol { - - public MiniFinderProtocol() { - setSupportedDataCommands( - Command.TYPE_SET_TIMEZONE, - Command.TYPE_VOICE_MONITORING, - Command.TYPE_ALARM_SPEED, - Command.TYPE_ALARM_GEOFENCE, - Command.TYPE_ALARM_VIBRATION, - Command.TYPE_SET_AGPS, - Command.TYPE_ALARM_FALL, - Command.TYPE_MODE_POWER_SAVING, - Command.TYPE_MODE_DEEP_SLEEP, - Command.TYPE_SOS_NUMBER, - Command.TYPE_SET_INDICATOR); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new MiniFinderProtocolEncoder()); - pipeline.addLast(new MiniFinderProtocolDecoder(MiniFinderProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/MiniFinderProtocolDecoder.java b/src/org/traccar/protocol/MiniFinderProtocolDecoder.java deleted file mode 100644 index 2b7a960c4..000000000 --- a/src/org/traccar/protocol/MiniFinderProtocolDecoder.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class MiniFinderProtocolDecoder extends BaseProtocolDecoder { - - public MiniFinderProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_FIX = new PatternBuilder() - .number("(d+)/(d+)/(d+),") // date (dd/mm/yy) - .number("(d+):(d+):(d+),") // time (hh:mm:ss) - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .compile(); - - private static final Pattern PATTERN_STATE = new PatternBuilder() - .number("(d+.?d*),") // speed (km/h) - .number("(d+.?d*),") // course - .number("(x+),") // flags - .number("(-?d+.d+),") // altitude (meters) - .number("(d+),") // battery (percentage) - .compile(); - - private static final Pattern PATTERN_A = new PatternBuilder() - .text("!A,") - .expression(PATTERN_FIX.pattern()) - .any() // unknown 3 fields - .compile(); - - private static final Pattern PATTERN_C = new PatternBuilder() - .text("!C,") - .expression(PATTERN_FIX.pattern()) - .expression(PATTERN_STATE.pattern()) - .any() // unknown 3 fields - .compile(); - - private static final Pattern PATTERN_BD = new PatternBuilder() - .expression("![BD],") // B - buffered, D - live - .expression(PATTERN_FIX.pattern()) - .expression(PATTERN_STATE.pattern()) - .number("(d+),") // satellites in use - .number("(d+),") // satellites in view - .number("(d+.?d*)") // hdop - .compile(); - - private void decodeFix(Position position, Parser parser) { - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - } - - private void decodeFlags(Position position, int flags) { - - position.setValid(BitUtil.to(flags, 2) > 0); - if (BitUtil.check(flags, 1)) { - position.set(Position.KEY_APPROXIMATE, true); - } - - if (BitUtil.check(flags, 2)) { - position.set(Position.KEY_ALARM, Position.ALARM_FAULT); - } - if (BitUtil.check(flags, 6)) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - if (BitUtil.check(flags, 7)) { - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - } - if (BitUtil.check(flags, 8)) { - position.set(Position.KEY_ALARM, Position.ALARM_FALL_DOWN); - } - if (BitUtil.check(flags, 9) || BitUtil.check(flags, 10) || BitUtil.check(flags, 11)) { - position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE); - } - if (BitUtil.check(flags, 12)) { - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - } - if (BitUtil.check(flags, 15) || BitUtil.check(flags, 14)) { - position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); - } - - position.set(Position.KEY_RSSI, BitUtil.between(flags, 16, 21)); - position.set(Position.KEY_CHARGE, BitUtil.check(flags, 22)); - } - - private void decodeState(Position position, Parser parser) { - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - - position.setCourse(parser.nextDouble(0)); - if (position.getCourse() > 360) { - position.setCourse(0); - } - - decodeFlags(position, parser.nextHexInt(0)); - - position.setAltitude(parser.nextDouble(0)); - - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("!1,")) { - int index = sentence.indexOf(',', 3); - if (index < 0) { - index = sentence.length(); - } - getDeviceSession(channel, remoteAddress, sentence.substring(3, index)); - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null || !sentence.matches("![3A-D],.*")) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - String type = sentence.substring(1, 2); - position.set(Position.KEY_TYPE, type); - - if (type.equals("3")) { - - getLastLocation(position, null); - - position.set(Position.KEY_RESULT, sentence.substring(3)); - - return position; - - } else if (type.equals("B") || type.equals("D")) { - - Parser parser = new Parser(PATTERN_BD, sentence); - if (!parser.matches()) { - return null; - } - - decodeFix(position, parser); - decodeState(position, parser); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt(0)); - position.set(Position.KEY_HDOP, parser.nextDouble(0)); - - return position; - - } else if (type.equals("C")) { - - Parser parser = new Parser(PATTERN_C, sentence); - if (!parser.matches()) { - return null; - } - - decodeFix(position, parser); - decodeState(position, parser); - - return position; - - } else if (type.equals("A")) { - - Parser parser = new Parser(PATTERN_A, sentence); - if (!parser.matches()) { - return null; - } - - decodeFix(position, parser); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/MiniFinderProtocolEncoder.java b/src/org/traccar/protocol/MiniFinderProtocolEncoder.java deleted file mode 100644 index 7a3d5b226..000000000 --- a/src/org/traccar/protocol/MiniFinderProtocolEncoder.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.TimeZone; - -import org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class MiniFinderProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { - - @Override - public String formatValue(String key, Object value) { - switch (key) { - case Command.KEY_ENABLE: - return (Boolean) value ? "1" : "0"; - case Command.KEY_TIMEZONE: - return String.format("%+03d", TimeZone.getTimeZone((String) value).getRawOffset() / 3600000); - case Command.KEY_INDEX: - switch (((Number) value).intValue()) { - case 0: - return "A"; - case 1: - return "B"; - case 2: - return "C"; - default: - return null; - } - default: - return null; - } - } - - @Override - protected Object encodeCommand(Command command) { - - initDevicePassword(command, "123456"); - - switch (command.getType()) { - case Command.TYPE_SET_TIMEZONE: - return formatCommand(command, "{%s}L{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_TIMEZONE); - case Command.TYPE_VOICE_MONITORING: - return formatCommand(command, "{%s}P{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); - case Command.TYPE_ALARM_SPEED: - return formatCommand(command, "{%s}J1{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); - case Command.TYPE_ALARM_GEOFENCE: - return formatCommand(command, "{%s}R1{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_RADIUS); - case Command.TYPE_ALARM_VIBRATION: - return formatCommand(command, "{%s}W1,{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); - case Command.TYPE_SET_AGPS: - return formatCommand(command, "{%s}AGPS{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); - case Command.TYPE_ALARM_FALL: - return formatCommand(command, "{%s}F{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); - case Command.TYPE_MODE_POWER_SAVING: - return formatCommand(command, "{%s}SP{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); - case Command.TYPE_MODE_DEEP_SLEEP: - return formatCommand(command, "{%s}DS{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE); - case Command.TYPE_SOS_NUMBER: - return formatCommand(command, "{%s}{%s}1,{%s}", this, - Command.KEY_DEVICE_PASSWORD, Command.KEY_INDEX, Command.KEY_PHONE); - case Command.TYPE_SET_INDICATOR: - return formatCommand(command, "{%s}LED{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Mta6Protocol.java b/src/org/traccar/protocol/Mta6Protocol.java deleted file mode 100644 index 632a7df80..000000000 --- a/src/org/traccar/protocol/Mta6Protocol.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.Context; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Mta6Protocol extends BaseProtocol { - - public Mta6Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(65535)); - pipeline.addLast(new Mta6ProtocolDecoder( - Mta6Protocol.this, !Context.getConfig().getBoolean(getName() + ".can"))); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Mta6ProtocolDecoder.java b/src/org/traccar/protocol/Mta6ProtocolDecoder.java deleted file mode 100644 index 88419b871..000000000 --- a/src/org/traccar/protocol/Mta6ProtocolDecoder.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class Mta6ProtocolDecoder extends BaseProtocolDecoder { - - private static final Logger LOGGER = LoggerFactory.getLogger(Mta6ProtocolDecoder.class); - - private final boolean simple; - - public Mta6ProtocolDecoder(Protocol protocol, boolean simple) { - super(protocol); - this.simple = simple; - } - - private void sendContinue(Channel channel) { - FullHttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - - private void sendResponse(Channel channel, short packetId, short packetCount) { - ByteBuf begin = Unpooled.copiedBuffer("#ACK#", StandardCharsets.US_ASCII); - ByteBuf end = Unpooled.buffer(3); - end.writeByte(packetId); - end.writeByte(packetCount); - end.writeByte(0); - - FullHttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(begin, end)); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - - private static class FloatReader { - - private int previousFloat; - - public float readFloat(ByteBuf buf) { - switch (buf.getUnsignedByte(buf.readerIndex()) >> 6) { - case 0: - previousFloat = buf.readInt() << 2; - break; - case 1: - previousFloat = (previousFloat & 0xffffff00) + ((buf.readUnsignedByte() & 0x3f) << 2); - break; - case 2: - previousFloat = (previousFloat & 0xffff0000) + ((buf.readUnsignedShort() & 0x3fff) << 2); - break; - case 3: - previousFloat = (previousFloat & 0xff000000) + ((buf.readUnsignedMedium() & 0x3fffff) << 2); - break; - default: - LOGGER.warn("MTA6 float decoding error", new IllegalArgumentException()); - break; - } - return Float.intBitsToFloat(previousFloat); - } - - } - - private static class TimeReader extends FloatReader { - - private long weekNumber; - - public Date readTime(ByteBuf buf) { - long weekTime = (long) (readFloat(buf) * 1000); - if (weekNumber == 0) { - weekNumber = buf.readUnsignedShort(); - } - - DateBuilder dateBuilder = new DateBuilder().setDate(1980, 1, 6); - dateBuilder.addMillis(weekNumber * 7 * 24 * 60 * 60 * 1000 + weekTime); - - return dateBuilder.getDate(); - } - - } - - private List parseFormatA(DeviceSession deviceSession, ByteBuf buf) { - List positions = new LinkedList<>(); - - FloatReader latitudeReader = new FloatReader(); - FloatReader longitudeReader = new FloatReader(); - TimeReader timeReader = new TimeReader(); - - try { - while (buf.isReadable()) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - short flags = buf.readUnsignedByte(); - - short event = buf.readUnsignedByte(); - if (BitUtil.check(event, 7)) { - if (BitUtil.check(event, 6)) { - buf.skipBytes(8); - } else { - while (BitUtil.check(event, 7)) { - event = buf.readUnsignedByte(); - } - } - } - - position.setLatitude(latitudeReader.readFloat(buf) / Math.PI * 180); - position.setLongitude(longitudeReader.readFloat(buf) / Math.PI * 180); - position.setTime(timeReader.readTime(buf)); - - if (BitUtil.check(flags, 0)) { - buf.readUnsignedByte(); // status - } - - if (BitUtil.check(flags, 1)) { - position.setAltitude(buf.readUnsignedShort()); - } - - if (BitUtil.check(flags, 2)) { - position.setSpeed(buf.readUnsignedShort() & 0x03ff); - position.setCourse(buf.readUnsignedByte()); - } - - if (BitUtil.check(flags, 3)) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000); - } - - if (BitUtil.check(flags, 4)) { - position.set(Position.KEY_FUEL_CONSUMPTION + "Accumulator1", buf.readUnsignedInt()); - position.set(Position.KEY_FUEL_CONSUMPTION + "Accumulator2", buf.readUnsignedInt()); - position.set("hours1", buf.readUnsignedShort()); - position.set("hours2", buf.readUnsignedShort()); - } - - if (BitUtil.check(flags, 5)) { - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() & 0x03ff); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort() & 0x03ff); - position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort() & 0x03ff); - position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShort() & 0x03ff); - } - - if (BitUtil.check(flags, 6)) { - position.set(Position.PREFIX_TEMP + 1, buf.readByte()); - buf.getUnsignedByte(buf.readerIndex()); // control (>> 4) - position.set(Position.KEY_INPUT, buf.readUnsignedShort() & 0x0fff); - buf.readUnsignedShort(); // old sensor state (& 0x0fff) - } - - if (BitUtil.check(flags, 7)) { - position.set(Position.KEY_BATTERY, buf.getUnsignedByte(buf.readerIndex()) >> 2); - position.set(Position.KEY_POWER, buf.readUnsignedShort() & 0x03ff); - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - - position.set(Position.KEY_RSSI, (buf.getUnsignedByte(buf.readerIndex()) >> 4) & 0x07); - - int satellites = buf.readUnsignedByte() & 0x0f; - position.setValid(satellites >= 3); - position.set(Position.KEY_SATELLITES, satellites); - } - positions.add(position); - } - } catch (IndexOutOfBoundsException error) { - LOGGER.warn("MTA6 parsing error", error); - } - - return positions; - } - - private Position parseFormatA1(DeviceSession deviceSession, ByteBuf buf) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - short flags = buf.readUnsignedByte(); - - // Skip events - short event = buf.readUnsignedByte(); - if (BitUtil.check(event, 7)) { - if (BitUtil.check(event, 6)) { - buf.skipBytes(8); - } else { - while (BitUtil.check(event, 7)) { - event = buf.readUnsignedByte(); - } - } - } - - position.setLatitude(new FloatReader().readFloat(buf) / Math.PI * 180); - position.setLongitude(new FloatReader().readFloat(buf) / Math.PI * 180); - position.setTime(new TimeReader().readTime(buf)); - - position.set(Position.KEY_STATUS, buf.readUnsignedByte()); - - if (BitUtil.check(flags, 0)) { - position.setAltitude(buf.readUnsignedShort()); - position.setSpeed(buf.readUnsignedByte()); - position.setCourse(buf.readByte()); - position.set(Position.KEY_ODOMETER, new FloatReader().readFloat(buf)); - } - - if (BitUtil.check(flags, 1)) { - position.set(Position.KEY_FUEL_CONSUMPTION, new FloatReader().readFloat(buf)); - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(new FloatReader().readFloat(buf))); - position.set("tank", buf.readUnsignedByte() * 0.4); - } - - if (BitUtil.check(flags, 2)) { - position.set("engine", buf.readUnsignedShort() * 0.125); - position.set("pedals", buf.readUnsignedByte()); - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedByte() - 40); - position.set(Position.KEY_ODOMETER_SERVICE, buf.readUnsignedShort()); - } - - if (BitUtil.check(flags, 3)) { - position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShort()); - } - - if (BitUtil.check(flags, 4)) { - position.set(Position.PREFIX_TEMP + 1, buf.readByte()); - buf.getUnsignedByte(buf.readerIndex()); // control (>> 4) - position.set(Position.KEY_INPUT, buf.readUnsignedShort() & 0x0fff); - buf.readUnsignedShort(); // old sensor state (& 0x0fff) - } - - if (BitUtil.check(flags, 5)) { - position.set(Position.KEY_BATTERY, buf.getUnsignedByte(buf.readerIndex()) >> 2); - position.set(Position.KEY_POWER, buf.readUnsignedShort() & 0x03ff); - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - - position.set(Position.KEY_RSSI, buf.getUnsignedByte(buf.readerIndex()) >> 5); - - int satellites = buf.readUnsignedByte() & 0x1f; - position.setValid(satellites >= 3); - position.set(Position.KEY_SATELLITES, satellites); - } - - // other data - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - ByteBuf buf = request.content(); - - buf.skipBytes("id=".length()); - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&'); - String uniqueId = buf.toString(buf.readerIndex(), index - buf.readerIndex(), StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); - if (deviceSession == null) { - return null; - } - buf.skipBytes(uniqueId.length()); - buf.skipBytes("&bin=".length()); - - short packetId = buf.readUnsignedByte(); - short offset = buf.readUnsignedByte(); // dataOffset - short packetCount = buf.readUnsignedByte(); - buf.readUnsignedByte(); // reserved - buf.readUnsignedByte(); // timezone - buf.skipBytes(offset - 5); - - if (channel != null) { - sendContinue(channel); - sendResponse(channel, packetId, packetCount); - } - - if (packetId == 0x31 || packetId == 0x32 || packetId == 0x36) { - if (simple) { - return parseFormatA1(deviceSession, buf); - } else { - return parseFormatA(deviceSession, buf); - } - } // else if (0x34 0x38 0x4F 0x59) - - return null; - } - -} diff --git a/src/org/traccar/protocol/MtxProtocol.java b/src/org/traccar/protocol/MtxProtocol.java deleted file mode 100644 index 44372ce83..000000000 --- a/src/org/traccar/protocol/MtxProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class MtxProtocol extends BaseProtocol { - - public MtxProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new MtxProtocolDecoder(MtxProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/MtxProtocolDecoder.java b/src/org/traccar/protocol/MtxProtocolDecoder.java deleted file mode 100644 index d1207bedf..000000000 --- a/src/org/traccar/protocol/MtxProtocolDecoder.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class MtxProtocolDecoder extends BaseProtocolDecoder { - - public MtxProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("#MTX,") - .number("(d+),") // imei - .number("(dddd)(dd)(dd),") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(d+.?d*),") // speed - .number("(d+),") // course - .number("(d+.?d*),") // odometer - .groupBegin() - .number("d+") - .or() - .text("X") - .groupEnd() - .text(",") - .expression("(?:[01]|X),") - .expression("([01]+),") // input - .expression("([01]+),") // output - .number("(d+),") // adc1 - .number("(d+)") // adc2 - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("#ACK", remoteAddress)); - } - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setValid(true); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/MxtFrameDecoder.java b/src/org/traccar/protocol/MxtFrameDecoder.java deleted file mode 100644 index d70e92da1..000000000 --- a/src/org/traccar/protocol/MxtFrameDecoder.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class MxtFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 2) { - return null; - } - - int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0x04); - if (index != -1) { - ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex()); - - while (buf.readerIndex() <= index) { - int b = buf.readUnsignedByte(); - if (b == 0x10) { - result.writeByte(buf.readUnsignedByte() - 0x20); - } else { - result.writeByte(b); - } - } - - return result; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/MxtProtocol.java b/src/org/traccar/protocol/MxtProtocol.java deleted file mode 100644 index dbe43fe45..000000000 --- a/src/org/traccar/protocol/MxtProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class MxtProtocol extends BaseProtocol { - - public MxtProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new MxtFrameDecoder()); - pipeline.addLast(new MxtProtocolDecoder(MxtProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/MxtProtocolDecoder.java b/src/org/traccar/protocol/MxtProtocolDecoder.java deleted file mode 100644 index 7bde85f87..000000000 --- a/src/org/traccar/protocol/MxtProtocolDecoder.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -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.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class MxtProtocolDecoder extends BaseProtocolDecoder { - - public MxtProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_ACK = 0x02; - public static final int MSG_NACK = 0x03; - public static final int MSG_POSITION = 0x31; - - private static void sendResponse(Channel channel, int device, long id, int crc) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(device); - response.writeByte(MSG_ACK); - response.writeIntLE((int) id); - response.writeShortLE(crc); - response.writeShortLE(Checksum.crc16( - Checksum.CRC16_XMODEM, response.nioBuffer())); - - ByteBuf encoded = Unpooled.buffer(); - encoded.writeByte(0x01); // header - while (response.isReadable()) { - int b = response.readByte(); - if (b == 0x01 || b == 0x04 || b == 0x10 || b == 0x11 || b == 0x13) { - encoded.writeByte(0x10); - b += 0x20; - } - encoded.writeByte(b); - } - response.release(); - encoded.writeByte(0x04); // ending - channel.writeAndFlush(new NetworkMessage(encoded, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedByte(); // start - int device = buf.readUnsignedByte(); // device descriptor - int type = buf.readUnsignedByte(); - - long id = buf.readUnsignedIntLE(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); - if (deviceSession == null) { - return null; - } - - if (type == MSG_POSITION) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedByte(); // protocol - int infoGroups = buf.readUnsignedByte(); - - position.set(Position.KEY_INDEX, buf.readUnsignedShortLE()); - - DateBuilder dateBuilder = new DateBuilder().setDate(2000, 1, 1); - - long date = buf.readUnsignedIntLE(); - - long days = BitUtil.from(date, 6 + 6 + 5); - long hours = BitUtil.between(date, 6 + 6, 6 + 6 + 5); - long minutes = BitUtil.between(date, 6, 6 + 6); - long seconds = BitUtil.to(date, 6); - - dateBuilder.addMillis((((days * 24 + hours) * 60 + minutes) * 60 + seconds) * 1000); - - position.setTime(dateBuilder.getDate()); - - position.setValid(true); - position.setLatitude(buf.readIntLE() / 1000000.0); - position.setLongitude(buf.readIntLE() / 1000000.0); - - long flags = buf.readUnsignedIntLE(); - position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0)); - if (BitUtil.check(flags, 1)) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - position.set(Position.KEY_INPUT, BitUtil.between(flags, 2, 7)); - position.set(Position.KEY_OUTPUT, BitUtil.between(flags, 7, 10)); - position.setCourse(BitUtil.between(flags, 10, 13) * 45); - // position.setValid(BitUtil.check(flags, 15)); - position.set(Position.KEY_CHARGE, BitUtil.check(flags, 20)); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - - buf.readUnsignedByte(); // input mask - - if (BitUtil.check(infoGroups, 0)) { - buf.skipBytes(8); // waypoints - } - - if (BitUtil.check(infoGroups, 1)) { - buf.skipBytes(8); // wireless accessory - } - - if (BitUtil.check(infoGroups, 2)) { - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_HDOP, buf.readUnsignedByte()); - position.setAccuracy(buf.readUnsignedByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - buf.readUnsignedShortLE(); // time since boot - position.set(Position.KEY_POWER, buf.readUnsignedByte()); - position.set(Position.PREFIX_TEMP + 1, buf.readByte()); - } - - if (BitUtil.check(infoGroups, 3)) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - } - - if (BitUtil.check(infoGroups, 4)) { - position.set(Position.KEY_HOURS, UnitsConverter.msFromMinutes(buf.readUnsignedIntLE())); - } - - if (BitUtil.check(infoGroups, 5)) { - buf.readUnsignedIntLE(); // reason - } - - if (BitUtil.check(infoGroups, 6)) { - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE()); - } - - if (BitUtil.check(infoGroups, 7)) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedIntLE())); - } - - buf.readerIndex(buf.writerIndex() - 3); - sendResponse(channel, device, id, buf.readUnsignedShortLE()); - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/NavigilFrameDecoder.java b/src/org/traccar/protocol/NavigilFrameDecoder.java deleted file mode 100644 index e8b6bea52..000000000 --- a/src/org/traccar/protocol/NavigilFrameDecoder.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class NavigilFrameDecoder extends BaseFrameDecoder { - - private static final int MESSAGE_HEADER = 20; - private static final long PREAMBLE = 0x2477F5F6; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - // Check minimum length - if (buf.readableBytes() < MESSAGE_HEADER) { - return null; - } - - // Check for preamble - boolean hasPreamble = false; - if (buf.getUnsignedIntLE(buf.readerIndex()) == PREAMBLE) { - hasPreamble = true; - } - - // Check length and return buffer - int length = buf.getUnsignedShortLE(buf.readerIndex() + 6); - if (buf.readableBytes() >= length) { - if (hasPreamble) { - buf.readUnsignedIntLE(); - length -= 4; - } - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/NavigilProtocol.java b/src/org/traccar/protocol/NavigilProtocol.java deleted file mode 100644 index 2c946c39f..000000000 --- a/src/org/traccar/protocol/NavigilProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class NavigilProtocol extends BaseProtocol { - - public NavigilProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new NavigilFrameDecoder()); - pipeline.addLast(new NavigilProtocolDecoder(NavigilProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/NavigilProtocolDecoder.java b/src/org/traccar/protocol/NavigilProtocolDecoder.java deleted file mode 100644 index db5521201..000000000 --- a/src/org/traccar/protocol/NavigilProtocolDecoder.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Checksum; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; - -public class NavigilProtocolDecoder extends BaseProtocolDecoder { - - public NavigilProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final int LEAP_SECONDS_DELTA = 25; - - public static final int MSG_ERROR = 2; - public static final int MSG_INDICATION = 4; - public static final int MSG_CONN_OPEN = 5; - public static final int MSG_CONN_CLOSE = 6; - public static final int MSG_SYSTEM_REPORT = 7; - public static final int MSG_UNIT_REPORT = 8; - public static final int MSG_GEOFENCE_ALARM = 10; - public static final int MSG_INPUT_ALARM = 11; - public static final int MSG_TG2_REPORT = 12; - public static final int MSG_POSITION_REPORT = 13; - public static final int MSG_POSITION_REPORT_2 = 15; - public static final int MSG_SNAPSHOT4 = 17; - public static final int MSG_TRACKING_DATA = 18; - public static final int MSG_MOTION_ALARM = 19; - public static final int MSG_ACKNOWLEDGEMENT = 255; - - private static Date convertTimestamp(long timestamp) { - return new Date((timestamp - LEAP_SECONDS_DELTA) * 1000); - } - - private int senderSequenceNumber = 1; - - private void sendAcknowledgment(Channel channel, int sequenceNumber) { - ByteBuf data = Unpooled.buffer(4); - data.writeShortLE(sequenceNumber); - data.writeShortLE(0); // OK - - ByteBuf header = Unpooled.buffer(20); - header.writeByte(1); header.writeByte(0); - header.writeShortLE(senderSequenceNumber++); - header.writeShortLE(MSG_ACKNOWLEDGEMENT); - header.writeShortLE(header.capacity() + data.capacity()); - header.writeShortLE(0); - header.writeShortLE(Checksum.crc16(Checksum.CRC16_CCITT_FALSE, data.nioBuffer())); - header.writeIntLE(0); - header.writeIntLE((int) (System.currentTimeMillis() / 1000) + LEAP_SECONDS_DELTA); - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(header, data), channel.remoteAddress())); - } - } - - private Position parseUnitReport( - DeviceSession deviceSession, ByteBuf buf, int sequenceNumber) { - Position position = new Position(getProtocolName()); - - position.setValid(true); - position.set(Position.KEY_INDEX, sequenceNumber); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedShortLE(); // report trigger - position.set(Position.KEY_FLAGS, buf.readUnsignedShortLE()); - - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - position.setAltitude(buf.readUnsignedShortLE()); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedShortLE()); - position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedShortLE()); - position.set("gpsAntennaState", buf.readUnsignedShortLE()); - - position.setSpeed(buf.readUnsignedShortLE() * 0.194384); - position.setCourse(buf.readUnsignedShortLE()); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - position.set(Position.KEY_DISTANCE, buf.readUnsignedIntLE()); - - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); - - position.set(Position.KEY_CHARGE, buf.readUnsignedShortLE()); - - position.setTime(convertTimestamp(buf.readUnsignedIntLE())); - - return position; - } - - private Position parseTg2Report( - DeviceSession deviceSession, ByteBuf buf, int sequenceNumber) { - Position position = new Position(getProtocolName()); - - position.setValid(true); - position.set(Position.KEY_INDEX, sequenceNumber); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedShortLE(); // report trigger - buf.readUnsignedByte(); // reserved - buf.readUnsignedByte(); // assisted GPS age - - position.setTime(convertTimestamp(buf.readUnsignedIntLE())); - - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - position.setAltitude(buf.readUnsignedShortLE()); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); - - position.setSpeed(buf.readUnsignedShortLE() * 0.194384); - position.setCourse(buf.readUnsignedShortLE()); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - position.set("maximumSpeed", buf.readUnsignedShortLE()); - position.set("minimumSpeed", buf.readUnsignedShortLE()); - - position.set(Position.PREFIX_IO + 1, buf.readUnsignedShortLE()); // VSAUT1 voltage - position.set(Position.PREFIX_IO + 2, buf.readUnsignedShortLE()); // VSAUT2 voltage - position.set(Position.PREFIX_IO + 3, buf.readUnsignedShortLE()); // solar voltage - - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); - - return position; - } - - private Position parsePositionReport( - DeviceSession deviceSession, ByteBuf buf, int sequenceNumber, long timestamp) { - Position position = new Position(getProtocolName()); - - position.set(Position.KEY_INDEX, sequenceNumber); - position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(convertTimestamp(timestamp)); - - position.setLatitude(buf.readMediumLE() * 0.00002); - position.setLongitude(buf.readMediumLE() * 0.00002); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.setCourse(buf.readUnsignedByte() * 2); - - short flags = buf.readUnsignedByte(); - position.setValid((flags & 0x80) == 0x80 && (flags & 0x40) == 0x40); - - buf.readUnsignedByte(); // reserved - - return position; - } - - private Position parsePositionReport2( - DeviceSession deviceSession, ByteBuf buf, int sequenceNumber, long timestamp) { - Position position = new Position(getProtocolName()); - - position.set(Position.KEY_INDEX, sequenceNumber); - position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(convertTimestamp(timestamp)); - - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - - buf.readUnsignedByte(); // report trigger - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - - short flags = buf.readUnsignedByte(); - position.setValid((flags & 0x80) == 0x80 && (flags & 0x40) == 0x40); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - - return position; - } - - private Position parseSnapshot4( - DeviceSession deviceSession, ByteBuf buf, int sequenceNumber) { - Position position = new Position(getProtocolName()); - - position.set(Position.KEY_INDEX, sequenceNumber); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedByte(); // report trigger - buf.readUnsignedByte(); // position fix source - buf.readUnsignedByte(); // GNSS fix quality - buf.readUnsignedByte(); // GNSS assistance age - - long flags = buf.readUnsignedIntLE(); - position.setValid((flags & 0x0400) == 0x0400); - - position.setTime(convertTimestamp(buf.readUnsignedIntLE())); - - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - position.setAltitude(buf.readUnsignedShortLE()); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte()); - - position.setSpeed(buf.readUnsignedShortLE() * 0.194384); - position.setCourse(buf.readUnsignedShortLE() * 0.1); - - position.set("maximumSpeed", buf.readUnsignedByte()); - position.set("minimumSpeed", buf.readUnsignedByte()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - - position.set(Position.PREFIX_IO + 1, buf.readUnsignedByte()); // supply voltage 1 - position.set(Position.PREFIX_IO + 2, buf.readUnsignedByte()); // supply voltage 2 - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); - - return position; - } - - private Position parseTrackingData( - DeviceSession deviceSession, ByteBuf buf, int sequenceNumber, long timestamp) { - Position position = new Position(getProtocolName()); - - position.set(Position.KEY_INDEX, sequenceNumber); - position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(convertTimestamp(timestamp)); - - buf.readUnsignedByte(); // tracking mode - - short flags = buf.readUnsignedByte(); - position.setValid((flags & 0x01) == 0x01); - - buf.readUnsignedShortLE(); // duration - - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.setCourse(buf.readUnsignedByte() * 2.0); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedByte(); // protocol version - buf.readUnsignedByte(); // version id - int sequenceNumber = buf.readUnsignedShortLE(); - int messageId = buf.readUnsignedShortLE(); - buf.readUnsignedShortLE(); // length - int flags = buf.readUnsignedShortLE(); - buf.readUnsignedShortLE(); // checksum - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedIntLE())); - if (deviceSession == null) { - return null; - } - - long timestamp = buf.readUnsignedIntLE(); - - if ((flags & 0x1) == 0x0) { - sendAcknowledgment(channel, sequenceNumber); - } - - switch (messageId) { - case MSG_UNIT_REPORT: - return parseUnitReport(deviceSession, buf, sequenceNumber); - case MSG_TG2_REPORT: - return parseTg2Report(deviceSession, buf, sequenceNumber); - case MSG_POSITION_REPORT: - return parsePositionReport(deviceSession, buf, sequenceNumber, timestamp); - case MSG_POSITION_REPORT_2: - return parsePositionReport2(deviceSession, buf, sequenceNumber, timestamp); - case MSG_SNAPSHOT4: - return parseSnapshot4(deviceSession, buf, sequenceNumber); - case MSG_TRACKING_DATA: - return parseTrackingData(deviceSession, buf, sequenceNumber, timestamp); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/NavisFrameDecoder.java b/src/org/traccar/protocol/NavisFrameDecoder.java deleted file mode 100644 index 8a0bb0b9a..000000000 --- a/src/org/traccar/protocol/NavisFrameDecoder.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import java.nio.charset.StandardCharsets; -import org.traccar.BaseFrameDecoder; -import org.traccar.BasePipelineFactory; - -public class NavisFrameDecoder extends BaseFrameDecoder { - - private static final int NTCB_HEADER_LENGTH = 16; - private static final int NTCB_LENGTH_OFFSET = 12; - private static final int FLEX_HEADER_LENGTH = 2; - - private int flexDataSize; - - public void setFlexDataSize(int flexDataSize) { - this.flexDataSize = flexDataSize; - } - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.getByte(buf.readerIndex()) == 0x7F) { - return buf.readRetainedSlice(1); // keep alive - } - - if (ctx != null && flexDataSize == 0) { - NavisProtocolDecoder protocolDecoder = - BasePipelineFactory.getHandler(ctx.pipeline(), NavisProtocolDecoder.class); - if (protocolDecoder != null) { - flexDataSize = protocolDecoder.getFlexDataSize(); - } - } - - if (flexDataSize > 0) { - - if (buf.readableBytes() > FLEX_HEADER_LENGTH) { - int length = 0; - String type = buf.toString(buf.readerIndex(), 2, StandardCharsets.US_ASCII); - switch (type) { - // FLEX 1.0 - case "~A": - length = flexDataSize * buf.getByte(buf.readerIndex() + FLEX_HEADER_LENGTH) + 1 + 1; - break; - case "~T": - length = flexDataSize + 4 + 1; - break; - case "~C": - length = flexDataSize + 1; - break; - // FLEX 2.0 (Extra packages) - case "~E": - length++; - for (int i = 0; i < buf.getByte(buf.readerIndex() + FLEX_HEADER_LENGTH); i++) { - if (buf.readableBytes() > FLEX_HEADER_LENGTH + length + 1) { - length += buf.getUnsignedShort(length + FLEX_HEADER_LENGTH) + 2; - } else { - return null; - } - } - length++; - break; - case "~X": - length = buf.getUnsignedShortLE(buf.readerIndex() + FLEX_HEADER_LENGTH) + 4 + 1; - break; - default: - return null; - } - - if (buf.readableBytes() >= FLEX_HEADER_LENGTH + length) { - return buf.readRetainedSlice(buf.readableBytes()); - } - } - - } else { - - if (buf.readableBytes() < NTCB_HEADER_LENGTH) { - return null; - } - - int length = NTCB_HEADER_LENGTH + buf.getUnsignedShortLE(buf.readerIndex() + NTCB_LENGTH_OFFSET); - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/NavisProtocol.java b/src/org/traccar/protocol/NavisProtocol.java deleted file mode 100644 index d5af6838d..000000000 --- a/src/org/traccar/protocol/NavisProtocol.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class NavisProtocol extends BaseProtocol { - - public NavisProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new NavisFrameDecoder()); - pipeline.addLast(new NavisProtocolDecoder(NavisProtocol.this)); - } - }); - } -} diff --git a/src/org/traccar/protocol/NavisProtocolDecoder.java b/src/org/traccar/protocol/NavisProtocolDecoder.java deleted file mode 100644 index 7ba474ae0..000000000 --- a/src/org/traccar/protocol/NavisProtocolDecoder.java +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -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.Checksum.Algorithm; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.LinkedList; -import java.util.List; -import java.util.Date; - -public class NavisProtocolDecoder extends BaseProtocolDecoder { - - private static final int[] FLEX_FIELDS_SIZES = { - 4, 2, 4, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 4, 4, 2, 2, - 4, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 1, 4, 2, 2, 2, 2, 2, 1, 1, 1, 2, 4, 2, 1, - /* FLEX 2.0 */ - 8, 2, 1, 16, 4, 2, 4, 37, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 12, 24, 48, 1, 1, 1, 1, 4, 4, - 1, 4, 2, 6, 2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1 - }; - - private String prefix; - private long deviceUniqueId, serverId; - private int flexDataSize; - private int flexBitFieldSize; - private final byte[] flexBitField = new byte[16]; - - public NavisProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int F10 = 0x01; - public static final int F20 = 0x02; - public static final int F30 = 0x03; - public static final int F40 = 0x04; - public static final int F50 = 0x05; - public static final int F51 = 0x15; - public static final int F52 = 0x25; - public static final int F60 = 0x06; - - public int getFlexDataSize() { - return flexDataSize; - } - - private static boolean isFormat(int type, int... types) { - for (int i : types) { - if (type == i) { - return true; - } - } - return false; - } - - private Position parseNtcbPosition(DeviceSession deviceSession, ByteBuf buf) { - Position position = new Position(getProtocolName()); - - position.setDeviceId(deviceSession.getDeviceId()); - - int format; - if (buf.getUnsignedByte(buf.readerIndex()) == 0) { - format = buf.readUnsignedShortLE(); - } else { - format = buf.readUnsignedByte(); - } - position.set("format", format); - - position.set(Position.KEY_INDEX, buf.readUnsignedIntLE()); - position.set(Position.KEY_EVENT, buf.readUnsignedShortLE()); - - buf.skipBytes(6); // event time - - short armedStatus = buf.readUnsignedByte(); - if (isFormat(format, F10, F20, F30, F40, F50, F51, F52)) { - position.set(Position.KEY_ARMED, BitUtil.to(armedStatus, 7)); - if (BitUtil.check(armedStatus, 7)) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - } else if (isFormat(format, F60)) { - position.set(Position.KEY_ARMED, BitUtil.check(armedStatus, 0)); - if (BitUtil.check(armedStatus, 1)) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - } - - position.set(Position.KEY_STATUS, buf.readUnsignedByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - - if (isFormat(format, F10, F20, F30)) { - int output = buf.readUnsignedShortLE(); - position.set(Position.KEY_OUTPUT, output); - for (int i = 0; i < 16; i++) { - position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(output, i)); - } - } else if (isFormat(format, F50, F51, F52)) { - short extField = buf.readUnsignedByte(); - position.set(Position.KEY_OUTPUT, BitUtil.to(extField, 2)); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(extField, 0)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(extField, 1)); - position.set(Position.KEY_SATELLITES, BitUtil.from(extField, 2)); - } else if (isFormat(format, F40, F60)) { - short output = buf.readUnsignedByte(); - position.set(Position.KEY_OUTPUT, BitUtil.to(output, 4)); - for (int i = 0; i < 4; i++) { - position.set(Position.PREFIX_OUT + (i + 1), BitUtil.check(output, i)); - } - } - - if (isFormat(format, F10, F20, F30, F40)) { - int input = buf.readUnsignedShortLE(); - position.set(Position.KEY_INPUT, input); - if (!isFormat(format, F40)) { - for (int i = 0; i < 16; i++) { - position.set(Position.PREFIX_IN + (i + 1), BitUtil.check(input, i)); - } - } else { - position.set(Position.PREFIX_IN + 1, BitUtil.check(input, 0)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(input, 1)); - position.set(Position.PREFIX_IN + 3, BitUtil.check(input, 2)); - position.set(Position.PREFIX_IN + 4, BitUtil.check(input, 3)); - position.set(Position.PREFIX_IN + 5, BitUtil.between(input, 4, 7)); - position.set(Position.PREFIX_IN + 6, BitUtil.between(input, 7, 10)); - position.set(Position.PREFIX_IN + 7, BitUtil.between(input, 10, 12)); - position.set(Position.PREFIX_IN + 8, BitUtil.between(input, 12, 14)); - } - } else if (isFormat(format, F50, F51, F52, F60)) { - short input = buf.readUnsignedByte(); - position.set(Position.KEY_INPUT, input); - for (int i = 0; i < 8; i++) { - position.set(Position.PREFIX_IN + (i + 1), BitUtil.check(input, i)); - } - } - - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001); - - if (isFormat(format, F10, F20, F30)) { - position.set(Position.PREFIX_TEMP + 1, buf.readShortLE()); - } - - if (isFormat(format, F10, F20, F50, F51, F52, F60)) { - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE()); - } - if (isFormat(format, F60)) { - position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShortLE()); - } - - // Impulse counters - if (isFormat(format, F20, F50, F51, F52, F60)) { - buf.readUnsignedIntLE(); - buf.readUnsignedIntLE(); - } - - if (isFormat(format, F60)) { - // Fuel - buf.readUnsignedShortLE(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - - position.set(Position.PREFIX_TEMP + 1, buf.readByte()); - position.set(Position.PREFIX_TEMP + 2, buf.readByte()); - position.set(Position.PREFIX_TEMP + 3, buf.readByte()); - position.set(Position.PREFIX_TEMP + 4, buf.readByte()); - position.set(Position.KEY_AXLE_WEIGHT, buf.readIntLE()); - position.set(Position.KEY_RPM, buf.readUnsignedShortLE()); - } - - if (isFormat(format, F20, F50, F51, F52, F60)) { - int navSensorState = buf.readUnsignedByte(); - position.setValid(BitUtil.check(navSensorState, 1)); - if (isFormat(format, F60)) { - position.set(Position.KEY_SATELLITES, BitUtil.from(navSensorState, 2)); - } - - DateBuilder dateBuilder = new DateBuilder() - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte() + 1, buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - if (isFormat(format, F60)) { - position.setLatitude(buf.readIntLE() / 600000.0); - position.setLongitude(buf.readIntLE() / 600000.0); - position.setAltitude(buf.readIntLE() * 0.1); - } else { - position.setLatitude(buf.readFloatLE() / Math.PI * 180); - position.setLongitude(buf.readFloatLE() / Math.PI * 180); - } - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readFloatLE())); - position.setCourse(buf.readUnsignedShortLE()); - - position.set(Position.KEY_ODOMETER, buf.readFloatLE() * 1000); - position.set(Position.KEY_DISTANCE, buf.readFloatLE() * 1000); - - // Segment times - buf.readUnsignedShortLE(); - buf.readUnsignedShortLE(); - } - - // Other - if (isFormat(format, F51, F52)) { - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - buf.readUnsignedShortLE(); - buf.readByte(); - buf.readUnsignedShortLE(); - } - - // Four temperature sensors - if (isFormat(format, F40, F52)) { - position.set(Position.PREFIX_TEMP + 1, buf.readByte()); - position.set(Position.PREFIX_TEMP + 2, buf.readByte()); - position.set(Position.PREFIX_TEMP + 3, buf.readByte()); - position.set(Position.PREFIX_TEMP + 4, buf.readByte()); - } - - return position; - } - - private Object processNtcbSingle(DeviceSession deviceSession, Channel channel, ByteBuf buf) { - Position position = parseNtcbPosition(deviceSession, buf); - - ByteBuf response = Unpooled.buffer(7); - response.writeCharSequence("* positions = new LinkedList<>(); - int count = buf.readUnsignedByte(); - - for (int i = 0; i < count; i++) { - Position position = parseNtcbPosition(deviceSession, buf); - if (position.getFixTime() != null) { - positions.add(position); - } - } - - ByteBuf response = Unpooled.buffer(7); - response.writeCharSequence("* positions = new LinkedList<>(); - int count = buf.readUnsignedByte(); - - for (int i = 0; i < count; i++) { - Position position = parser.parsePosition(deviceSession, buf); - if (position.getFixTime() != null) { - positions.add(position); - } - } - - ByteBuf response = Unpooled.buffer(); - response.writeCharSequence(flexHeader, StandardCharsets.US_ASCII); - response.writeByte(count); - sendFlexReply(channel, response); - - return !positions.isEmpty() ? positions : null; - } - - private Object processFlexNegotiation(Channel channel, ByteBuf buf) { - if ((byte) buf.readUnsignedByte() != (byte) 0xB0) { - return null; - } - - short flexProtocolVersion = buf.readUnsignedByte(); - short flexStructVersion = buf.readUnsignedByte(); - if ((flexProtocolVersion == 0x0A || flexProtocolVersion == 0x14) - && (flexStructVersion == 0x0A || flexStructVersion == 0x14)) { - - flexBitFieldSize = buf.readUnsignedByte(); - if (flexBitFieldSize > 122) { - return null; - } - - buf.readBytes(flexBitField, 0, (int) Math.ceil((double) flexBitFieldSize / 8)); - - flexDataSize = 0; - for (int i = 0; i < flexBitFieldSize; i++) { - if (checkFlexBitfield(i)) { - flexDataSize += FLEX_FIELDS_SIZES[i]; - } - } - } else { - flexProtocolVersion = 0x14; - flexStructVersion = 0x14; - } - - ByteBuf response = Unpooled.buffer(9); - response.writeCharSequence("*S")) { - return processHandshake(channel, remoteAddress, buf); - } else { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession != null) { - switch (type) { - case "*>A": - return processNtcbArray(deviceSession, channel, buf); - case "*>T": - return processNtcbSingle(deviceSession, channel, buf); - case "*>F": - buf.skipBytes(3); - return processFlexNegotiation(channel, buf); - default: - break; - } - } - } - - return null; - } - - private Object decodeFlex(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - if (buf.getByte(buf.readerIndex()) == 0x7F) { - return null; // keep alive - } - - String type = buf.toString(buf.readerIndex(), 2, StandardCharsets.US_ASCII); - buf.skipBytes(type.length()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession != null) { - switch (type) { - // FLEX 1.0 - case "~A": - return processFlexArray(this::parseFlexPosition, type, deviceSession, channel, buf); - case "~T": - case "~C": - return processFlexSingle(this::parseFlexPosition, type, deviceSession, channel, buf); - // FLEX 2.0 (extra packages) - case "~E": - return processFlexArray(this::parseFlex20Position, type, deviceSession, channel, buf); - case "~X": - return processFlexSingle(this::parseFlex20Position, type, deviceSession, channel, buf); - default: - break; - } - } - - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (flexDataSize > 0) { - return decodeFlex(channel, remoteAddress, buf); - } else { - return decodeNtcb(channel, remoteAddress, buf); - } - } - -} diff --git a/src/org/traccar/protocol/NeosProtocol.java b/src/org/traccar/protocol/NeosProtocol.java deleted file mode 100644 index e545a9969..000000000 --- a/src/org/traccar/protocol/NeosProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class NeosProtocol extends BaseProtocol { - - public NeosProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new NeosProtocolDecoder(NeosProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/NeosProtocolDecoder.java b/src/org/traccar/protocol/NeosProtocolDecoder.java deleted file mode 100644 index 6b5596dba..000000000 --- a/src/org/traccar/protocol/NeosProtocolDecoder.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class NeosProtocolDecoder extends BaseProtocolDecoder { - - public NeosProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text(">") - .number("(d{8}),") // id - .number("d+,") // status - .number("([01]),") // valid - .number("(dd)(dd)(dd),") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([EW])") - .number("(d+)(dd.d+),") // longitude - .expression("([NS])") - .number("(d+)(dd.d+),") // latitude - .expression("[^,]*,") // response - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+),") // rssi - .expression("[^,]*,") // event data - .number("(d+)-") // adc - .number("(d+),") // battery - .number("0,") - .number("d,") - .number("([01]{8})") // input - .text("*") - .number("xx!") - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("$OK!", remoteAddress)); - } - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.nextInt() > 0); - position.setTime(parser.nextDateTime()); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setSpeed(parser.nextInt()); - position.setCourse(parser.nextInt()); - - position.set(Position.KEY_RSSI, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextInt()); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - position.set(Position.KEY_INPUT, parser.nextBinInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/NoranProtocol.java b/src/org/traccar/protocol/NoranProtocol.java deleted file mode 100644 index 9f3078d6d..000000000 --- a/src/org/traccar/protocol/NoranProtocol.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class NoranProtocol extends BaseProtocol { - - public NoranProtocol() { - setSupportedDataCommands( - Command.TYPE_POSITION_SINGLE, - Command.TYPE_POSITION_PERIODIC, - Command.TYPE_POSITION_STOP, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new NoranProtocolEncoder()); - pipeline.addLast(new NoranProtocolDecoder(NoranProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/NoranProtocolDecoder.java b/src/org/traccar/protocol/NoranProtocolDecoder.java deleted file mode 100644 index 53dae7fd6..000000000 --- a/src/org/traccar/protocol/NoranProtocolDecoder.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; - -public class NoranProtocolDecoder extends BaseProtocolDecoder { - - public NoranProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_UPLOAD_POSITION = 0x0008; - public static final int MSG_UPLOAD_POSITION_NEW = 0x0032; - public static final int MSG_CONTROL = 0x0002; - public static final int MSG_CONTROL_RESPONSE = 0x8009; - public static final int MSG_ALARM = 0x0003; - public static final int MSG_SHAKE_HAND = 0x0000; - public static final int MSG_SHAKE_HAND_RESPONSE = 0x8000; - public static final int MSG_IMAGE_SIZE = 0x0200; - public static final int MSG_IMAGE_PACKET = 0x0201; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedShortLE(); // length - int type = buf.readUnsignedShortLE(); - - if (type == MSG_SHAKE_HAND && channel != null) { - - ByteBuf response = Unpooled.buffer(13); - response.writeCharSequence("\r\n*KW", StandardCharsets.US_ASCII); - response.writeByte(0); - response.writeShortLE(response.capacity()); - response.writeShortLE(MSG_SHAKE_HAND_RESPONSE); - response.writeByte(1); // status - response.writeCharSequence("\r\n", StandardCharsets.US_ASCII); - - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - - } else if (type == MSG_UPLOAD_POSITION || type == MSG_UPLOAD_POSITION_NEW - || type == MSG_CONTROL_RESPONSE || type == MSG_ALARM) { - - boolean newFormat = false; - if (type == MSG_UPLOAD_POSITION && buf.readableBytes() == 48 - || type == MSG_ALARM && buf.readableBytes() == 48 - || type == MSG_CONTROL_RESPONSE && buf.readableBytes() == 57) { - newFormat = true; - } - - Position position = new Position(getProtocolName()); - - if (type == MSG_CONTROL_RESPONSE) { - buf.readUnsignedIntLE(); // GIS ip - buf.readUnsignedIntLE(); // GIS port - } - - position.setValid(BitUtil.check(buf.readUnsignedByte(), 0)); - - short alarm = buf.readUnsignedByte(); - switch (alarm) { - case 1: - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - break; - case 2: - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - break; - case 3: - position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT); - break; - case 9: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF); - break; - default: - break; - } - - if (newFormat) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedIntLE())); - position.setCourse(buf.readFloatLE()); - } else { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.setCourse(buf.readUnsignedShortLE()); - } - position.setLongitude(buf.readFloatLE()); - position.setLatitude(buf.readFloatLE()); - - if (!newFormat) { - long timeValue = buf.readUnsignedIntLE(); - DateBuilder dateBuilder = new DateBuilder() - .setYear((int) BitUtil.from(timeValue, 26)) - .setMonth((int) BitUtil.between(timeValue, 22, 26)) - .setDay((int) BitUtil.between(timeValue, 17, 22)) - .setHour((int) BitUtil.between(timeValue, 12, 17)) - .setMinute((int) BitUtil.between(timeValue, 6, 12)) - .setSecond((int) BitUtil.to(timeValue, 6)); - position.setTime(dateBuilder.getDate()); - } - - ByteBuf rawId; - if (newFormat) { - rawId = buf.readSlice(12); - } else { - rawId = buf.readSlice(11); - } - String id = rawId.toString(StandardCharsets.US_ASCII).replaceAll("[^\\p{Print}]", ""); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - if (newFormat) { - DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); - position.setTime(dateFormat.parse(buf.readSlice(17).toString(StandardCharsets.US_ASCII))); - buf.readByte(); - } - - if (!newFormat) { - position.set(Position.PREFIX_IO + 1, buf.readUnsignedByte()); - position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte()); - } else if (type == MSG_UPLOAD_POSITION_NEW) { - position.set(Position.PREFIX_TEMP + 1, buf.readShortLE()); - position.set(Position.KEY_ODOMETER, buf.readFloatLE()); - } - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/NoranProtocolEncoder.java b/src/org/traccar/protocol/NoranProtocolEncoder.java deleted file mode 100644 index 92826c8b2..000000000 --- a/src/org/traccar/protocol/NoranProtocolEncoder.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class NoranProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeContent(String content) { - - ByteBuf buf = Unpooled.buffer(12 + 56); - - buf.writeCharSequence("\r\n*KW", StandardCharsets.US_ASCII); - buf.writeByte(0); - buf.writeShortLE(buf.capacity()); - buf.writeShortLE(NoranProtocolDecoder.MSG_CONTROL); - buf.writeInt(0); // gis ip - buf.writeShortLE(0); // gis port - buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); - buf.writerIndex(buf.writerIndex() + 50 - content.length()); - buf.writeCharSequence("\r\n", StandardCharsets.US_ASCII); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_POSITION_SINGLE: - return encodeContent("*KW,000,000,000000#"); - case Command.TYPE_POSITION_PERIODIC: - int interval = command.getInteger(Command.KEY_FREQUENCY); - return encodeContent("*KW,000,002,000000," + interval + "#"); - case Command.TYPE_POSITION_STOP: - return encodeContent("*KW,000,002,000000,0#"); - case Command.TYPE_ENGINE_STOP: - return encodeContent("*KW,000,007,000000,0#"); - case Command.TYPE_ENGINE_RESUME: - return encodeContent("*KW,000,007,000000,1#"); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/NvsFrameDecoder.java b/src/org/traccar/protocol/NvsFrameDecoder.java deleted file mode 100644 index e93a58cf6..000000000 --- a/src/org/traccar/protocol/NvsFrameDecoder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class NvsFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 4 + 2) { - return null; - } - - int length; - if (buf.getUnsignedByte(buf.readerIndex()) == 0) { - length = 2 + buf.getUnsignedShort(buf.readerIndex()); - } else { - length = 4 + 2 + buf.getUnsignedShort(buf.readerIndex() + 4) + 2; - } - - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/NvsProtocol.java b/src/org/traccar/protocol/NvsProtocol.java deleted file mode 100644 index d319b22f3..000000000 --- a/src/org/traccar/protocol/NvsProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class NvsProtocol extends BaseProtocol { - - public NvsProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new NvsFrameDecoder()); - pipeline.addLast(new NvsProtocolDecoder(NvsProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/NvsProtocolDecoder.java b/src/org/traccar/protocol/NvsProtocolDecoder.java deleted file mode 100644 index 5d1159f7d..000000000 --- a/src/org/traccar/protocol/NvsProtocolDecoder.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class NvsProtocolDecoder extends BaseProtocolDecoder { - - public NvsProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private void sendResponse(Channel channel, SocketAddress remoteAddress, String response) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - Unpooled.copiedBuffer(response, StandardCharsets.US_ASCII), remoteAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - - if (buf.getUnsignedByte(buf.readerIndex()) == 0) { - - buf.readUnsignedShort(); // length - - String imei = buf.toString(buf.readerIndex(), 15, StandardCharsets.US_ASCII); - - if (getDeviceSession(channel, remoteAddress, imei) != null) { - sendResponse(channel, remoteAddress, "OK"); - } else { - sendResponse(channel, remoteAddress, "NO01"); - } - - } else { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - buf.skipBytes(4); // marker - buf.readUnsignedShort(); // length - buf.readLong(); // imei - buf.readUnsignedByte(); // codec - int count = buf.readUnsignedByte(); - - for (int i = 0; i < count; i++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - - position.set("reason", buf.readUnsignedByte()); - - position.setLongitude(buf.readInt() / 10000000.0); - position.setLatitude(buf.readInt() / 10000000.0); - position.setAltitude(buf.readShort()); - position.setCourse(buf.readUnsignedShort()); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - position.setValid(buf.readUnsignedByte() != 0); - - buf.readUnsignedByte(); // used systems - - buf.readUnsignedByte(); // cause element id - - // Read 1 byte data - int cnt = buf.readUnsignedByte(); - for (int j = 0; j < cnt; j++) { - position.set(Position.PREFIX_IO + buf.readUnsignedByte(), buf.readUnsignedByte()); - } - - // Read 2 byte data - cnt = buf.readUnsignedByte(); - for (int j = 0; j < cnt; j++) { - position.set(Position.PREFIX_IO + buf.readUnsignedByte(), buf.readUnsignedShort()); - } - - // Read 4 byte data - cnt = buf.readUnsignedByte(); - for (int j = 0; j < cnt; j++) { - position.set(Position.PREFIX_IO + buf.readUnsignedByte(), buf.readUnsignedInt()); - } - - // Read 8 byte data - cnt = buf.readUnsignedByte(); - for (int j = 0; j < cnt; j++) { - position.set(Position.PREFIX_IO + buf.readUnsignedByte(), buf.readLong()); - } - - positions.add(position); - } - - return positions; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/NyitechProtocol.java b/src/org/traccar/protocol/NyitechProtocol.java deleted file mode 100644 index 58974be5c..000000000 --- a/src/org/traccar/protocol/NyitechProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; - -public class NyitechProtocol extends BaseProtocol { - - public NyitechProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, -4, 0, true)); - pipeline.addLast(new NyitechProtocolDecoder(NyitechProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/NyitechProtocolDecoder.java b/src/org/traccar/protocol/NyitechProtocolDecoder.java deleted file mode 100644 index e145205f7..000000000 --- a/src/org/traccar/protocol/NyitechProtocolDecoder.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; - -public class NyitechProtocolDecoder extends BaseProtocolDecoder { - - public NyitechProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final short MSG_LOGIN = 0x1001; - public static final short MSG_COMPREHENSIVE_LIVE = 0x2001; - public static final short MSG_COMPREHENSIVE_HISTORY = 0x2002; - public static final short MSG_ALARM = 0x2003; - public static final short MSG_FIXED = 0x2004; - - private void decodeLocation(Position position, ByteBuf buf) { - - DateBuilder dateBuilder = new DateBuilder() - .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - int flags = buf.readUnsignedByte(); - position.setValid(BitUtil.to(flags, 2) > 0); - - double lat = buf.readUnsignedIntLE() / 3600000.0; - double lon = buf.readUnsignedIntLE() / 3600000.0; - - position.setLatitude(BitUtil.check(flags, 2) ? lat : -lat); - position.setLongitude(BitUtil.check(flags, 3) ? lon : -lon); - - position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE())); - position.setCourse(buf.readUnsignedShortLE() * 0.1); - position.setAltitude(buf.readShortLE() * 0.1); - } - - private String decodeAlarm(int type) { - switch (type) { - case 0x09: - return Position.ALARM_ACCELERATION; - case 0x0a: - return Position.ALARM_BRAKING; - case 0x0b: - return Position.ALARM_CORNERING; - case 0x0e: - return Position.ALARM_SOS; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - buf.readUnsignedShortLE(); // length - - String id = buf.readCharSequence(12, StandardCharsets.US_ASCII).toString(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - int type = buf.readUnsignedShortLE(); - - if (type != MSG_LOGIN && type != MSG_COMPREHENSIVE_LIVE - && type != MSG_COMPREHENSIVE_HISTORY && type != MSG_ALARM && type != MSG_FIXED) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (type == MSG_COMPREHENSIVE_LIVE || type == MSG_COMPREHENSIVE_HISTORY) { - buf.skipBytes(6); // time - buf.skipBytes(3); // data - } else if (type == MSG_ALARM) { - buf.readUnsignedShortLE(); // random number - buf.readUnsignedByte(); // tag - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); - buf.readUnsignedShortLE(); // threshold - buf.readUnsignedShortLE(); // value - buf.skipBytes(6); // time - } else if (type == MSG_FIXED) { - buf.skipBytes(6); // time - } - - decodeLocation(position, buf); - - return position; - } - -} diff --git a/src/org/traccar/protocol/ObdDongleProtocol.java b/src/org/traccar/protocol/ObdDongleProtocol.java deleted file mode 100644 index 10a55759b..000000000 --- a/src/org/traccar/protocol/ObdDongleProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ObdDongleProtocol extends BaseProtocol { - - public ObdDongleProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1099, 20, 2, 3, 0)); - pipeline.addLast(new ObdDongleProtocolDecoder(ObdDongleProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ObdDongleProtocolDecoder.java b/src/org/traccar/protocol/ObdDongleProtocolDecoder.java deleted file mode 100644 index 1c9771ce9..000000000 --- a/src/org/traccar/protocol/ObdDongleProtocolDecoder.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class ObdDongleProtocolDecoder extends BaseProtocolDecoder { - - public ObdDongleProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_TYPE_CONNECT = 0x01; - public static final int MSG_TYPE_CONNACK = 0x02; - public static final int MSG_TYPE_PUBLISH = 0x03; - public static final int MSG_TYPE_PUBACK = 0x04; - public static final int MSG_TYPE_PINGREQ = 0x0C; - public static final int MSG_TYPE_PINGRESP = 0x0D; - public static final int MSG_TYPE_DISCONNECT = 0x0E; - - private static void sendResponse(Channel channel, int type, int index, String imei, ByteBuf content) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeShort(0x5555); // header - response.writeShort(index); - response.writeBytes(imei.getBytes(StandardCharsets.US_ASCII)); - response.writeByte(type); - response.writeShort(content.readableBytes()); - response.writeBytes(content); - content.release(); - response.writeByte(0); // checksum - response.writeShort(0xAAAA); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - int index = buf.readUnsignedShort(); - - String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - int type = buf.readUnsignedByte(); - - buf.readUnsignedShort(); // data length - - if (type == MSG_TYPE_CONNECT) { - - ByteBuf response = Unpooled.buffer(); - response.writeByte(1); - response.writeShort(0); - response.writeInt(0); - sendResponse(channel, MSG_TYPE_CONNACK, index, imei, response); - - } else if (type == MSG_TYPE_PUBLISH) { - - int typeMajor = buf.readUnsignedByte(); - int typeMinor = buf.readUnsignedByte(); - - buf.readUnsignedByte(); // event id - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - - int flags = buf.readUnsignedByte(); - - position.setValid(!BitUtil.check(flags, 6)); - - position.set(Position.KEY_SATELLITES, BitUtil.to(flags, 4)); - - double longitude = ((BitUtil.to(buf.readUnsignedShort(), 1) << 24) + buf.readUnsignedMedium()) * 0.00001; - position.setLongitude(BitUtil.check(flags, 5) ? longitude : -longitude); - - double latitude = buf.readUnsignedMedium() * 0.00001; - position.setLatitude(BitUtil.check(flags, 4) ? latitude : -latitude); - - int speedCourse = buf.readUnsignedMedium(); - position.setSpeed(UnitsConverter.knotsFromMph(BitUtil.from(speedCourse, 10) * 0.1)); - position.setCourse(BitUtil.to(speedCourse, 10)); - - ByteBuf response = Unpooled.buffer(); - response.writeByte(typeMajor); - response.writeByte(typeMinor); - sendResponse(channel, MSG_TYPE_PUBACK, index, imei, response); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/OigoProtocol.java b/src/org/traccar/protocol/OigoProtocol.java deleted file mode 100644 index 5056f68aa..000000000 --- a/src/org/traccar/protocol/OigoProtocol.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class OigoProtocol extends BaseProtocol { - - public OigoProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new OigoProtocolDecoder(OigoProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/OigoProtocolDecoder.java b/src/org/traccar/protocol/OigoProtocolDecoder.java deleted file mode 100644 index b9cc71e8c..000000000 --- a/src/org/traccar/protocol/OigoProtocolDecoder.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; - -public class OigoProtocolDecoder extends BaseProtocolDecoder { - - public OigoProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_AR_LOCATION = 0x00; - public static final int MSG_AR_REMOTE_START = 0x10; - - public static final int MSG_ACKNOWLEDGEMENT = 0xE0; - - private Position decodeArMessage(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - buf.skipBytes(1); // header - buf.readUnsignedShort(); // length - - int type = buf.readUnsignedByte(); - - int tag = buf.readUnsignedByte(); - - DeviceSession deviceSession; - switch (BitUtil.to(tag, 3)) { - case 0: - String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); - deviceSession = getDeviceSession(channel, remoteAddress, imei); - break; - case 1: - buf.skipBytes(1); - String meid = buf.readSlice(14).toString(StandardCharsets.US_ASCII); - deviceSession = getDeviceSession(channel, remoteAddress, meid); - break; - default: - deviceSession = getDeviceSession(channel, remoteAddress); - break; - } - - if (deviceSession == null || type != MSG_AR_LOCATION) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - - int mask = buf.readInt(); - - if (BitUtil.check(mask, 0)) { - position.set(Position.KEY_INDEX, buf.readUnsignedShort()); - } - - if (BitUtil.check(mask, 1)) { - int date = buf.readUnsignedByte(); - DateBuilder dateBuilder = new DateBuilder() - .setDate(BitUtil.between(date, 4, 8) + 2010, BitUtil.to(date, 4), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - } - - if (BitUtil.check(mask, 2)) { - buf.skipBytes(5); // device time - } - - if (BitUtil.check(mask, 3)) { - position.setLatitude(buf.readUnsignedInt() * 0.000001 - 90); - position.setLongitude(buf.readUnsignedInt() * 0.000001 - 180.0); - } - - if (BitUtil.check(mask, 4)) { - int status = buf.readUnsignedByte(); - position.setValid(BitUtil.between(status, 4, 8) != 0); - position.set(Position.KEY_SATELLITES, BitUtil.to(status, 4)); - position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); - } - - if (BitUtil.check(mask, 5)) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - } - - if (BitUtil.check(mask, 6)) { - position.setCourse(buf.readUnsignedShort()); - } - - if (BitUtil.check(mask, 7)) { - position.setAltitude(buf.readShort()); - } - - if (BitUtil.check(mask, 8)) { - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - } - - if (BitUtil.check(mask, 9)) { - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); - } - - if (BitUtil.check(mask, 10)) { - position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001); - } - - if (BitUtil.check(mask, 11)) { - buf.skipBytes(2); // gpio - } - - if (BitUtil.check(mask, 12)) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); - } - - if (BitUtil.check(mask, 13)) { - buf.skipBytes(6); // software version - } - - if (BitUtil.check(mask, 14)) { - buf.skipBytes(5); // hardware version - } - - if (BitUtil.check(mask, 15)) { - buf.readUnsignedShort(); // device config - } - - return position; - } - - private double convertCoordinate(long value) { - boolean negative = value < 0; - value = Math.abs(value); - double minutes = (value % 100000) * 0.001; - value /= 100000; - double degrees = value + minutes / 60; - return negative ? -degrees : degrees; - } - - private Position decodeMgMessage(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - buf.readUnsignedByte(); // tag - int flags = buf.getUnsignedByte(buf.readerIndex()); - - DeviceSession deviceSession; - if (BitUtil.check(flags, 6)) { - buf.readUnsignedByte(); // flags - deviceSession = getDeviceSession(channel, remoteAddress); - } else { - String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); - deviceSession = getDeviceSession(channel, remoteAddress, imei); - } - - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.skipBytes(8); // imsi - - int date = buf.readUnsignedShort(); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(2010 + BitUtil.from(date, 12), BitUtil.between(date, 8, 12), BitUtil.to(date, 8)) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), 0); - - position.setValid(true); - position.setLatitude(convertCoordinate(buf.readInt())); - position.setLongitude(convertCoordinate(buf.readInt())); - - position.setAltitude(UnitsConverter.metersFromFeet(buf.readShort())); - position.setCourse(buf.readUnsignedShort()); - position.setSpeed(UnitsConverter.knotsFromMph(buf.readUnsignedByte())); - - position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); - position.set(Position.PREFIX_IO + 1, buf.readUnsignedByte()); - - dateBuilder.setSecond(buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - - int index = buf.readUnsignedByte(); - - position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte()); - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_ODOMETER, (long) (buf.readUnsignedInt() * 1609.34)); - - if (channel != null && BitUtil.check(flags, 7)) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(MSG_ACKNOWLEDGEMENT); - response.writeByte(index); - response.writeByte(0x00); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (buf.getUnsignedByte(buf.readerIndex()) == 0x7e) { - return decodeArMessage(channel, remoteAddress, buf); - } else { - return decodeMgMessage(channel, remoteAddress, buf); - } - } - -} diff --git a/src/org/traccar/protocol/OkoProtocol.java b/src/org/traccar/protocol/OkoProtocol.java deleted file mode 100644 index 9571ccc48..000000000 --- a/src/org/traccar/protocol/OkoProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class OkoProtocol extends BaseProtocol { - - public OkoProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '}')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new OkoProtocolDecoder(OkoProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/OkoProtocolDecoder.java b/src/org/traccar/protocol/OkoProtocolDecoder.java deleted file mode 100644 index 5adf61494..000000000 --- a/src/org/traccar/protocol/OkoProtocolDecoder.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class OkoProtocolDecoder extends BaseProtocolDecoder { - - public OkoProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("{") - .number("(d{15}),").optional() // imei - .number("(dd)(dd)(dd).d+,") // time - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(d+),") // satellites - .number("(d+.d+),") // adc - .number("(xx),") // event - .number("(d+.d+),") // power - .number("d,") // memory status - .number("(xx)") // io - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession; - if (parser.hasNext()) { - deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - } else { - deviceSession = getDeviceSession(channel, remoteAddress); - } - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.KEY_EVENT, parser.next()); - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_INPUT, parser.nextHexInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/OpenGtsProtocol.java b/src/org/traccar/protocol/OpenGtsProtocol.java deleted file mode 100644 index 5ef3260c6..000000000 --- a/src/org/traccar/protocol/OpenGtsProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class OpenGtsProtocol extends BaseProtocol { - - public OpenGtsProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(16384)); - pipeline.addLast(new OpenGtsProtocolDecoder(OpenGtsProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/OpenGtsProtocolDecoder.java b/src/org/traccar/protocol/OpenGtsProtocolDecoder.java deleted file mode 100644 index b76cbfa85..000000000 --- a/src/org/traccar/protocol/OpenGtsProtocolDecoder.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.QueryStringDecoder; -import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -public class OpenGtsProtocolDecoder extends BaseHttpProtocolDecoder { - - private static final Pattern PATTERN = new PatternBuilder() - .text("$GPRMC,") - .number("(dd)(dd)(dd)(?:.d+)?,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+),") // speed - .number("(d+.d+)?,") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .any() - .compile(); - - public OpenGtsProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); - Map> params = decoder.parameters(); - - Position position = new Position(getProtocolName()); - - for (Map.Entry> entry : params.entrySet()) { - String value = entry.getValue().get(0); - switch (entry.getKey()) { - case "id": - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value); - if (deviceSession == null) { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - break; - case "gprmc": - Parser parser = new Parser(PATTERN, value); - if (!parser.matches()) { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble()); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - break; - case "alt": - position.setAltitude(Double.parseDouble(value)); - break; - case "batt": - position.set(Position.KEY_BATTERY_LEVEL, Double.parseDouble(value)); - break; - default: - break; - } - } - - if (position.getDeviceId() != 0) { - sendResponse(channel, HttpResponseStatus.OK); - return position; - } else { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - } - -} diff --git a/src/org/traccar/protocol/OrionFrameDecoder.java b/src/org/traccar/protocol/OrionFrameDecoder.java deleted file mode 100644 index 948806609..000000000 --- a/src/org/traccar/protocol/OrionFrameDecoder.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class OrionFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int length = 6; - - if (buf.readableBytes() >= length) { - - int type = buf.getUnsignedByte(buf.readerIndex() + 2) & 0x0f; - - if (type == OrionProtocolDecoder.MSG_USERLOG && buf.readableBytes() >= length + 5) { - - int index = buf.readerIndex() + 3; - int count = buf.getUnsignedByte(index) & 0x0f; - index += 5; - length += 5; - - for (int i = 0; i < count; i++) { - if (buf.readableBytes() < length) { - return null; - } - int logLength = buf.getUnsignedByte(index + 1); - index += logLength; - length += logLength; - } - - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - } else if (type == OrionProtocolDecoder.MSG_SYSLOG && buf.readableBytes() >= length + 12) { - - length += buf.getUnsignedShortLE(buf.readerIndex() + 8); - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/OrionProtocol.java b/src/org/traccar/protocol/OrionProtocol.java deleted file mode 100644 index 8485ae638..000000000 --- a/src/org/traccar/protocol/OrionProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class OrionProtocol extends BaseProtocol { - - public OrionProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new OrionFrameDecoder()); - pipeline.addLast(new OrionProtocolDecoder(OrionProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/OrionProtocolDecoder.java b/src/org/traccar/protocol/OrionProtocolDecoder.java deleted file mode 100644 index af819989e..000000000 --- a/src/org/traccar/protocol/OrionProtocolDecoder.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.LinkedList; -import java.util.List; - -public class OrionProtocolDecoder extends BaseProtocolDecoder { - - public OrionProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_USERLOG = 0; - public static final int MSG_SYSLOG = 3; - - private static void sendResponse(Channel channel, ByteBuf buf) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(4); - response.writeByte('*'); - response.writeShort(buf.getUnsignedShort(buf.writerIndex() - 2)); - response.writeByte(buf.getUnsignedByte(buf.writerIndex() - 3)); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - private static double convertCoordinate(int raw) { - int degrees = raw / 1000000; - double minutes = (raw % 1000000) / 10000.0; - return degrees + minutes / 60; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - int type = buf.readUnsignedByte() & 0x0f; - - if (type == MSG_USERLOG) { - - int header = buf.readUnsignedByte(); - - if ((header & 0x40) != 0) { - sendResponse(channel, buf); - } - - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, String.valueOf(buf.readUnsignedInt())); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - for (int i = 0; i < (header & 0x0f); i++) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - buf.readUnsignedByte(); // length - position.set(Position.KEY_FLAGS, buf.readUnsignedShortLE()); - - position.setLatitude(convertCoordinate(buf.readIntLE())); - position.setLongitude(convertCoordinate(buf.readIntLE())); - position.setAltitude(buf.readShortLE() / 10.0); - position.setCourse(buf.readUnsignedShortLE()); - position.setSpeed(buf.readUnsignedShortLE() * 0.0539957); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - int satellites = buf.readUnsignedByte(); - position.setValid(satellites >= 3); - position.set(Position.KEY_SATELLITES, satellites); - - positions.add(position); - } - - return positions; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/OsmAndProtocol.java b/src/org/traccar/protocol/OsmAndProtocol.java deleted file mode 100644 index d3aa2fd6f..000000000 --- a/src/org/traccar/protocol/OsmAndProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class OsmAndProtocol extends BaseProtocol { - - public OsmAndProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(16384)); - pipeline.addLast(new OsmAndProtocolDecoder(OsmAndProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/org/traccar/protocol/OsmAndProtocolDecoder.java deleted file mode 100644 index 3bc71de81..000000000 --- a/src/org/traccar/protocol/OsmAndProtocolDecoder.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.QueryStringDecoder; -import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateUtil; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; -import org.traccar.model.WifiAccessPoint; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Map; - -public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder { - - public OsmAndProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); - Map> params = decoder.parameters(); - if (params.isEmpty()) { - decoder = new QueryStringDecoder(request.content().toString(StandardCharsets.US_ASCII), false); - params = decoder.parameters(); - } - - Position position = new Position(getProtocolName()); - position.setValid(true); - - Network network = new Network(); - - for (Map.Entry> entry : params.entrySet()) { - for (String value : entry.getValue()) { - switch (entry.getKey()) { - case "id": - case "deviceid": - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value); - if (deviceSession == null) { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - break; - case "valid": - position.setValid(Boolean.parseBoolean(value) || "1".equals(value)); - break; - case "timestamp": - try { - long timestamp = Long.parseLong(value); - if (timestamp < Integer.MAX_VALUE) { - timestamp *= 1000; - } - position.setTime(new Date(timestamp)); - } catch (NumberFormatException error) { - if (value.contains("T")) { - position.setTime(DateUtil.parseDate(value)); - } else { - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - position.setTime(dateFormat.parse(value)); - } - } - break; - case "lat": - position.setLatitude(Double.parseDouble(value)); - break; - case "lon": - position.setLongitude(Double.parseDouble(value)); - break; - case "location": - String[] location = value.split(","); - position.setLatitude(Double.parseDouble(location[0])); - position.setLongitude(Double.parseDouble(location[1])); - break; - case "cell": - String[] cell = value.split(","); - if (cell.length > 4) { - network.addCellTower(CellTower.from( - Integer.parseInt(cell[0]), Integer.parseInt(cell[1]), - Integer.parseInt(cell[2]), Integer.parseInt(cell[3]), Integer.parseInt(cell[4]))); - } else { - network.addCellTower(CellTower.from( - Integer.parseInt(cell[0]), Integer.parseInt(cell[1]), - Integer.parseInt(cell[2]), Integer.parseInt(cell[3]))); - } - break; - case "wifi": - String[] wifi = value.split(","); - network.addWifiAccessPoint(WifiAccessPoint.from( - wifi[0].replace('-', ':'), Integer.parseInt(wifi[1]))); - break; - case "speed": - position.setSpeed(convertSpeed(Double.parseDouble(value), "kn")); - break; - case "bearing": - case "heading": - position.setCourse(Double.parseDouble(value)); - break; - case "altitude": - position.setAltitude(Double.parseDouble(value)); - break; - case "accuracy": - position.setAccuracy(Double.parseDouble(value)); - break; - case "hdop": - position.set(Position.KEY_HDOP, Double.parseDouble(value)); - break; - case "batt": - position.set(Position.KEY_BATTERY_LEVEL, Double.parseDouble(value)); - break; - case "driverUniqueId": - position.set(Position.KEY_DRIVER_UNIQUE_ID, value); - break; - default: - try { - position.set(entry.getKey(), Double.parseDouble(value)); - } catch (NumberFormatException e) { - switch (value) { - case "true": - position.set(entry.getKey(), true); - break; - case "false": - position.set(entry.getKey(), false); - break; - default: - position.set(entry.getKey(), value); - break; - } - } - break; - } - } - } - - if (position.getFixTime() == null) { - position.setTime(new Date()); - } - - if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { - position.setNetwork(network); - } - - if (position.getLatitude() == 0 && position.getLongitude() == 0) { - getLastLocation(position, position.getDeviceTime()); - } - - if (position.getDeviceId() != 0) { - sendResponse(channel, HttpResponseStatus.OK); - return position; - } else { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - } - -} diff --git a/src/org/traccar/protocol/OwnTracksProtocol.java b/src/org/traccar/protocol/OwnTracksProtocol.java deleted file mode 100644 index 0086371d8..000000000 --- a/src/org/traccar/protocol/OwnTracksProtocol.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2017 Jan-Piet Mens (jpmens@gmail.com) - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class OwnTracksProtocol extends BaseProtocol { - - public OwnTracksProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(16384)); - pipeline.addLast(new OwnTracksProtocolDecoder(OwnTracksProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/OwnTracksProtocolDecoder.java b/src/org/traccar/protocol/OwnTracksProtocolDecoder.java deleted file mode 100644 index 323d97fa3..000000000 --- a/src/org/traccar/protocol/OwnTracksProtocolDecoder.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2017 Jan-Piet Mens (jpmens@gmail.com) - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpResponseStatus; -import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import javax.json.Json; -import javax.json.JsonObject; -import java.io.StringReader; -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class OwnTracksProtocolDecoder extends BaseHttpProtocolDecoder { - - public OwnTracksProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - JsonObject root = Json.createReader( - new StringReader(request.content().toString(StandardCharsets.US_ASCII))).readObject(); - - if (!root.containsKey("_type")) { - sendResponse(channel, HttpResponseStatus.OK); - return null; - } - if (!root.getString("_type").equals("location") - && !root.getString("_type").equals("lwt")) { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - - Position position = new Position(getProtocolName()); - String uniqueId; - - if (root.containsKey("topic")) { - uniqueId = root.getString("topic"); - if (root.containsKey("tid")) { - position.set("tid", root.getString("tid")); - } - } else { - uniqueId = root.getString("tid"); - } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, uniqueId); - if (deviceSession == null) { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - - if (root.getString("_type").equals("lwt")) { - sendResponse(channel, HttpResponseStatus.OK); - return null; - } - - if (root.containsKey("t") && root.getString("t").equals("p")) { - sendResponse(channel, HttpResponseStatus.OK); - return null; - } - - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(root.getJsonNumber("tst").longValue() * 1000)); - if (root.containsKey("sent")) { - position.setDeviceTime(new Date(root.getJsonNumber("sent").longValue() * 1000)); - } - - position.setValid(true); - - position.setLatitude(root.getJsonNumber("lat").doubleValue()); - position.setLongitude(root.getJsonNumber("lon").doubleValue()); - - if (root.containsKey("vel")) { - position.setSpeed(UnitsConverter.knotsFromKph(root.getInt("vel"))); - } - if (root.containsKey("alt")) { - position.setAltitude(root.getInt("alt")); - } - if (root.containsKey("cog")) { - position.setCourse(root.getInt("cog")); - } - if (root.containsKey("acc")) { - position.setAccuracy(root.getInt("acc")); - } - if (root.containsKey("t")) { - String trigger = root.getString("t"); - position.set("t", trigger); - Integer reportType = -1; - if (root.containsKey("rty")) { - reportType = root.getInt("rty"); - } - setEventOrAlarm(position, trigger, reportType); - } - if (root.containsKey("batt")) { - position.set(Position.KEY_BATTERY_LEVEL, root.getInt("batt")); - } - if (root.containsKey("uext")) { - position.set(Position.KEY_POWER, root.getJsonNumber("uext").doubleValue()); - } - if (root.containsKey("ubatt")) { - position.set(Position.KEY_BATTERY, root.getJsonNumber("ubatt").doubleValue()); - } - if (root.containsKey("vin")) { - position.set(Position.KEY_VIN, root.getString("vin")); - } - if (root.containsKey("name")) { - position.set(Position.KEY_VIN, root.getString("name")); - } - if (root.containsKey("rpm")) { - position.set(Position.KEY_RPM, root.getInt("rpm")); - } - if (root.containsKey("ign")) { - position.set(Position.KEY_IGNITION, root.getBoolean("ign")); - } - if (root.containsKey("motion")) { - position.set(Position.KEY_MOTION, root.getBoolean("motion")); - } - if (root.containsKey("odometer")) { - position.set(Position.KEY_ODOMETER, root.getJsonNumber("odometer").doubleValue() * 1000.0); - } - if (root.containsKey("hmc")) { - position.set(Position.KEY_HOURS, root.getJsonNumber("hmc").doubleValue() / 3600.0); - } - - if (root.containsKey("anum")) { - Integer numberOfAnalogueInputs = root.getInt("anum"); - for (Integer i = 0; i < numberOfAnalogueInputs; i++) { - String indexString = String.format("%02d", i); - if (root.containsKey("adda-" + indexString)) { - position.set(Position.PREFIX_ADC + (i + 1), root.getString("adda-" + indexString)); - } - if (root.containsKey("temp_c-" + indexString)) { - position.set(Position.PREFIX_TEMP + (i + 1), - root.getJsonNumber("temp_c-" + indexString).doubleValue()); - } - } - } - - sendResponse(channel, HttpResponseStatus.OK); - return position; - } - - private void setEventOrAlarm(Position position, String trigger, Integer reportType) { - switch (trigger) { - case "9": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case "1": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_ON); - break; - case "i": - position.set(Position.KEY_IGNITION, true); - break; - case "I": - position.set(Position.KEY_IGNITION, false); - break; - case "E": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); - break; - case "e": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - break; - case "!": - position.set(Position.KEY_ALARM, Position.ALARM_TOW); - break; - case "s": - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - break; - case "h": - switch (reportType) { - case 0: - case 3: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 1: - case 4: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 2: - case 5: - default: - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - break; - } - break; - default: - break; - } - } -} diff --git a/src/org/traccar/protocol/PathAwayProtocol.java b/src/org/traccar/protocol/PathAwayProtocol.java deleted file mode 100644 index 6b5d75c5e..000000000 --- a/src/org/traccar/protocol/PathAwayProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class PathAwayProtocol extends BaseProtocol { - - public PathAwayProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(16384)); - pipeline.addLast(new PathAwayProtocolDecoder(PathAwayProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/PathAwayProtocolDecoder.java b/src/org/traccar/protocol/PathAwayProtocolDecoder.java deleted file mode 100644 index 02a15e34a..000000000 --- a/src/org/traccar/protocol/PathAwayProtocolDecoder.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import io.netty.channel.ChannelFutureListener; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; -import io.netty.handler.codec.http.QueryStringDecoder; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class PathAwayProtocolDecoder extends BaseProtocolDecoder { - - public PathAwayProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$PWS,") - .number("d+,") // version - .expression("[^,]*,") // name - .expression("[^,]*,") // icon - .expression("[^,]*,") // color - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(-?d+.?d*),") // altitude - .number("(-?d+.?d*),") // speed - .number("(-?d+.?d*),") // course - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); - - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, decoder.parameters().get("UserName").get(0)); - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN, decoder.parameters().get("LOC").get(0)); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setValid(true); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - if (channel != null) { - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)).addListener(ChannelFutureListener.CLOSE); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/PiligrimProtocol.java b/src/org/traccar/protocol/PiligrimProtocol.java deleted file mode 100644 index d88c1ab72..000000000 --- a/src/org/traccar/protocol/PiligrimProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class PiligrimProtocol extends BaseProtocol { - - public PiligrimProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(16384)); - pipeline.addLast(new PiligrimProtocolDecoder(PiligrimProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/org/traccar/protocol/PiligrimProtocolDecoder.java deleted file mode 100644 index 47aa86da7..000000000 --- a/src/org/traccar/protocol/PiligrimProtocolDecoder.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; -import io.netty.handler.codec.http.QueryStringDecoder; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.LinkedList; -import java.util.List; - -public class PiligrimProtocolDecoder extends BaseProtocolDecoder { - - public PiligrimProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private void sendResponse(Channel channel, String message) { - if (channel != null) { - FullHttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, HttpResponseStatus.OK, - Unpooled.copiedBuffer(message, StandardCharsets.US_ASCII)); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - public static final int MSG_GPS = 0xF1; - public static final int MSG_GPS_SENSORS = 0xF2; - public static final int MSG_EVENTS = 0xF3; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - String uri = request.uri(); - - if (uri.startsWith("/config")) { - - sendResponse(channel, "CONFIG: OK"); - - } else if (uri.startsWith("/addlog")) { - - sendResponse(channel, "ADDLOG: OK"); - - } else if (uri.startsWith("/inform")) { - - sendResponse(channel, "INFORM: OK"); - - } else if (uri.startsWith("/bingps")) { - - sendResponse(channel, "BINGPS: OK"); - - QueryStringDecoder decoder = new QueryStringDecoder(request.uri()); - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, decoder.parameters().get("imei").get(0)); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - ByteBuf buf = request.content(); - - while (buf.readableBytes() > 2) { - - buf.readUnsignedByte(); // header - int type = buf.readUnsignedByte(); - buf.readUnsignedByte(); // length - - if (type == MSG_GPS || type == MSG_GPS_SENSORS) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setDay(buf.readUnsignedByte()) - .setMonth(buf.getByte(buf.readerIndex()) & 0x0f) - .setYear(2010 + (buf.readUnsignedByte() >> 4)) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - position.setTime(dateBuilder.getDate()); - - double latitude = buf.readUnsignedByte(); - latitude += buf.readUnsignedByte() / 60.0; - latitude += buf.readUnsignedByte() / 6000.0; - latitude += buf.readUnsignedByte() / 600000.0; - - double longitude = buf.readUnsignedByte(); - longitude += buf.readUnsignedByte() / 60.0; - longitude += buf.readUnsignedByte() / 6000.0; - longitude += buf.readUnsignedByte() / 600000.0; - - int flags = buf.readUnsignedByte(); - if (BitUtil.check(flags, 0)) { - latitude = -latitude; - } - if (BitUtil.check(flags, 1)) { - longitude = -longitude; - } - position.setLatitude(latitude); - position.setLongitude(longitude); - - int satellites = buf.readUnsignedByte(); - position.set(Position.KEY_SATELLITES, satellites); - position.setValid(satellites >= 3); - - position.setSpeed(buf.readUnsignedByte()); - - double course = buf.readUnsignedByte() << 1; - course += (flags >> 2) & 1; - course += buf.readUnsignedByte() / 100.0; - position.setCourse(course); - - if (type == MSG_GPS_SENSORS) { - double power = buf.readUnsignedByte(); - power += buf.readUnsignedByte() << 8; - position.set(Position.KEY_POWER, power * 0.01); - - double battery = buf.readUnsignedByte(); - battery += buf.readUnsignedByte() << 8; - position.set(Position.KEY_BATTERY, battery * 0.01); - - buf.skipBytes(6); - } - - positions.add(position); - - } else if (type == MSG_EVENTS) { - - buf.skipBytes(13); - } - } - - return positions; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/PretraceProtocol.java b/src/org/traccar/protocol/PretraceProtocol.java deleted file mode 100644 index f753cbdb4..000000000 --- a/src/org/traccar/protocol/PretraceProtocol.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class PretraceProtocol extends BaseProtocol { - - public PretraceProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_POSITION_PERIODIC); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new PretraceProtocolEncoder()); - pipeline.addLast(new PretraceProtocolDecoder(PretraceProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/PretraceProtocolDecoder.java b/src/org/traccar/protocol/PretraceProtocolDecoder.java deleted file mode 100644 index a19384e62..000000000 --- a/src/org/traccar/protocol/PretraceProtocolDecoder.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class PretraceProtocolDecoder extends BaseProtocolDecoder { - - public PretraceProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("(") - .number("(d{15})") // imei - .number("Uddd") // type - .number("d") // gps type - .expression("([AV])") // validity - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("(dd)(dd.dddd)") // latitude - .expression("([NS])") - .number("(ddd)(dd.dddd)") // longitude - .expression("([EW])") - .number("(ddd)") // speed - .number("(ddd)") // course - .number("(xxx)") // altitude - .number("(x{8})") // odometer - .number("(x)") // satellites - .number("(dd)") // hdop - .number("(dd)") // gsm - .expression("(.{8}),&") // state - .expression("(.+)?") // optional data - .text("^") - .number("xx") // checksum - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.next().equals("A")); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); - position.setCourse(parser.nextInt(0)); - position.setAltitude(parser.nextHexInt(0)); - - position.set(Position.KEY_ODOMETER, parser.nextHexInt(0)); - position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); - position.set(Position.KEY_HDOP, parser.nextInt(0)); - position.set(Position.KEY_RSSI, parser.nextInt(0)); - - parser.next(); // state - - if (parser.hasNext()) { - for (String value : parser.next().split(",")) { - switch (value.charAt(0)) { - case 'P': - if (value.charAt(1) == '1') { - if (value.charAt(4) == '%') { - position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(value.substring(2, 4))); - } else { - position.set(Position.KEY_BATTERY, Integer.parseInt(value.substring(2), 16) * 0.01); - } - } else { - position.set(Position.KEY_POWER, Integer.parseInt(value.substring(2), 16) * 0.01); - } - break; - case 'T': - double temperature = Integer.parseInt(value.substring(2), 16) * 0.25; - if (value.charAt(1) == '1') { - position.set(Position.KEY_DEVICE_TEMP, temperature); - } else { - position.set(Position.PREFIX_TEMP + (value.charAt(1) - '0'), temperature); - } - break; - case 'F': - position.set("fuel" + (value.charAt(1) - '0'), Integer.parseInt(value.substring(2), 16) * 0.01); - break; - case 'R': - position.set(Position.KEY_DRIVER_UNIQUE_ID, value.substring(3)); - break; - default: - break; - } - } - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/PretraceProtocolEncoder.java b/src/org/traccar/protocol/PretraceProtocolEncoder.java deleted file mode 100644 index 9cf951e3b..000000000 --- a/src/org/traccar/protocol/PretraceProtocolEncoder.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 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. - * 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 org.traccar.BaseProtocolEncoder; -import org.traccar.Context; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -public class PretraceProtocolEncoder extends BaseProtocolEncoder { - - private String formatCommand(String uniqueId, String data) { - String content = uniqueId + data; - return String.format("(%s^%02X)", content, Checksum.xor(content)); - } - - @Override - protected Object encodeCommand(Command command) { - - String uniqueId = Context.getIdentityManager().getById(command.getDeviceId()).getUniqueId(); - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatCommand(uniqueId, command.getString(Command.KEY_DATA)); - case Command.TYPE_POSITION_PERIODIC: - return formatCommand( - uniqueId, String.format("D221%1$d,%1$d,,", command.getInteger(Command.KEY_FREQUENCY))); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/PricolProtocol.java b/src/org/traccar/protocol/PricolProtocol.java deleted file mode 100644 index 6821cd949..000000000 --- a/src/org/traccar/protocol/PricolProtocol.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.FixedLengthFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class PricolProtocol extends BaseProtocol { - - public PricolProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new FixedLengthFrameDecoder(64)); - pipeline.addLast(new PricolProtocolDecoder(PricolProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new PricolProtocolDecoder(PricolProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/PricolProtocolDecoder.java b/src/org/traccar/protocol/PricolProtocolDecoder.java deleted file mode 100644 index 190c68258..000000000 --- a/src/org/traccar/protocol/PricolProtocolDecoder.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; - -public class PricolProtocolDecoder extends BaseProtocolDecoder { - - public PricolProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedByte(); // header - - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, buf.readSlice(7).toString(StandardCharsets.US_ASCII)); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set("eventType", buf.readUnsignedByte()); - position.set("packetVersion", buf.readUnsignedByte()); - position.set(Position.KEY_STATUS, buf.readUnsignedByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set(Position.KEY_GPS, buf.readUnsignedByte()); - - position.setTime(new DateBuilder() - .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); - - position.setValid(true); - - double lat = buf.getUnsignedShort(buf.readerIndex()) / 100; - lat += (buf.readUnsignedShort() % 100 * 10000 + buf.readUnsignedShort()) / 600000.0; - position.setLatitude(buf.readUnsignedByte() == 'S' ? -lat : lat); - - double lon = buf.getUnsignedMedium(buf.readerIndex()) / 100; - lon += (buf.readUnsignedMedium() % 100 * 10000 + buf.readUnsignedShort()) / 600000.0; - position.setLongitude(buf.readUnsignedByte() == 'W' ? -lon : lon); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - - position.set(Position.KEY_INPUT, buf.readUnsignedShort()); - position.set(Position.KEY_OUTPUT, buf.readUnsignedByte()); - - position.set("analogAlerts", buf.readUnsignedByte()); - position.set("customAlertTypes", buf.readUnsignedShort()); - - for (int i = 1; i <= 5; i++) { - position.set(Position.PREFIX_ADC + i, buf.readUnsignedShort()); - } - - position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); - position.set(Position.KEY_RPM, buf.readUnsignedShort()); - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - Unpooled.copiedBuffer("ACK", StandardCharsets.US_ASCII), remoteAddress)); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/ProgressProtocol.java b/src/org/traccar/protocol/ProgressProtocol.java deleted file mode 100644 index aac84205d..000000000 --- a/src/org/traccar/protocol/ProgressProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; -public class ProgressProtocol extends BaseProtocol { - - public ProgressProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, 4, 0, true)); - pipeline.addLast(new ProgressProtocolDecoder(ProgressProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ProgressProtocolDecoder.java b/src/org/traccar/protocol/ProgressProtocolDecoder.java deleted file mode 100644 index 0025cd9e7..000000000 --- a/src/org/traccar/protocol/ProgressProtocolDecoder.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class ProgressProtocolDecoder extends BaseProtocolDecoder { - - private long lastIndex; - private long newIndex; - - public ProgressProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_NULL = 0; - public static final int MSG_IDENT = 1; - public static final int MSG_IDENT_FULL = 2; - public static final int MSG_POINT = 10; - public static final int MSG_LOG_SYNC = 100; - public static final int MSG_LOGMSG = 101; - public static final int MSG_TEXT = 102; - public static final int MSG_ALARM = 200; - public static final int MSG_ALARM_RECIEVED = 201; - - private void requestArchive(Channel channel) { - if (lastIndex == 0) { - lastIndex = newIndex; - } else if (newIndex > lastIndex) { - ByteBuf request = Unpooled.buffer(12); - request.writeShortLE(MSG_LOG_SYNC); - request.writeShortLE(4); - request.writeIntLE((int) lastIndex); - request.writeIntLE(0); - channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - int type = buf.readUnsignedShortLE(); - buf.readUnsignedShortLE(); // length - - if (type == MSG_IDENT || type == MSG_IDENT_FULL) { - - buf.readUnsignedIntLE(); // id - int length = buf.readUnsignedShortLE(); - buf.skipBytes(length); - length = buf.readUnsignedShortLE(); - buf.skipBytes(length); - length = buf.readUnsignedShortLE(); - String imei = buf.readSlice(length).toString(StandardCharsets.US_ASCII); - getDeviceSession(channel, remoteAddress, imei); - - } else if (type == MSG_POINT || type == MSG_ALARM || type == MSG_LOGMSG) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - int recordCount = 1; - if (type == MSG_LOGMSG) { - recordCount = buf.readUnsignedShortLE(); - } - - for (int j = 0; j < recordCount; j++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (type == MSG_LOGMSG) { - position.set(Position.KEY_ARCHIVE, true); - int subtype = buf.readUnsignedShortLE(); - if (subtype == MSG_ALARM) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - if (buf.readUnsignedShortLE() > buf.readableBytes()) { - lastIndex += 1; - break; // workaround for device bug - } - lastIndex = buf.readUnsignedIntLE(); - position.set(Position.KEY_INDEX, lastIndex); - } else { - newIndex = buf.readUnsignedIntLE(); - } - - position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); - position.setLatitude(buf.readIntLE() * 180.0 / 0x7FFFFFFF); - position.setLongitude(buf.readIntLE() * 180.0 / 0x7FFFFFFF); - position.setSpeed(buf.readUnsignedIntLE() * 0.01); - position.setCourse(buf.readUnsignedShortLE() * 0.01); - position.setAltitude(buf.readUnsignedShortLE() * 0.01); - - int satellites = buf.readUnsignedByte(); - position.setValid(satellites >= 3); - position.set(Position.KEY_SATELLITES, satellites); - - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - - long extraFlags = buf.readLongLE(); - - if (BitUtil.check(extraFlags, 0)) { - int count = buf.readUnsignedShortLE(); - for (int i = 1; i <= count; i++) { - position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE()); - } - } - - if (BitUtil.check(extraFlags, 1)) { - int size = buf.readUnsignedShortLE(); - position.set("can", buf.toString(buf.readerIndex(), size, StandardCharsets.US_ASCII)); - buf.skipBytes(size); - } - - if (BitUtil.check(extraFlags, 2)) { - position.set("passenger", ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedShortLE()))); - } - - if (type == MSG_ALARM) { - position.set(Position.KEY_ALARM, true); - byte[] response = {(byte) 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(response), remoteAddress)); - } - - buf.readUnsignedIntLE(); // crc - - positions.add(position); - } - - requestArchive(channel); - - return positions; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Pt3000Protocol.java b/src/org/traccar/protocol/Pt3000Protocol.java deleted file mode 100644 index 1ad0026a3..000000000 --- a/src/org/traccar/protocol/Pt3000Protocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Pt3000Protocol extends BaseProtocol { - - public Pt3000Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, 'd')); // probably wrong - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Pt3000ProtocolDecoder(Pt3000Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Pt3000ProtocolDecoder.java b/src/org/traccar/protocol/Pt3000ProtocolDecoder.java deleted file mode 100644 index e7f9e062a..000000000 --- a/src/org/traccar/protocol/Pt3000ProtocolDecoder.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Pt3000ProtocolDecoder extends BaseProtocolDecoder { - - public Pt3000ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("%(d+),") // imei - .text("$GPRMC,") - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/Pt502FrameDecoder.java b/src/org/traccar/protocol/Pt502FrameDecoder.java deleted file mode 100644 index 316cd987f..000000000 --- a/src/org/traccar/protocol/Pt502FrameDecoder.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -import java.nio.charset.StandardCharsets; - -public class Pt502FrameDecoder extends BaseFrameDecoder { - - private static final int BINARY_HEADER = 5; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 10) { - return null; - } - - if (buf.getUnsignedByte(buf.readerIndex()) == 0xbf - && buf.toString(buf.readerIndex() + BINARY_HEADER, 4, StandardCharsets.US_ASCII).equals("$PHD")) { - - int length = buf.getUnsignedShortLE(buf.readerIndex() + 3); - if (buf.readableBytes() >= length) { - buf.skipBytes(BINARY_HEADER); - ByteBuf result = buf.readRetainedSlice(length - BINARY_HEADER - 2); - buf.skipBytes(2); // line break - return result; - } - - } else { - - if (buf.getUnsignedByte(buf.readerIndex()) == 0xbf) { - buf.skipBytes(BINARY_HEADER); - } - - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\r'); - if (index < 0) { - index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\n'); - } - - if (index > 0) { - ByteBuf result = buf.readRetainedSlice(index - buf.readerIndex()); - while (buf.isReadable() - && (buf.getByte(buf.readerIndex()) == '\r' || buf.getByte(buf.readerIndex()) == '\n')) { - buf.skipBytes(1); - } - return result; - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Pt502Protocol.java b/src/org/traccar/protocol/Pt502Protocol.java deleted file mode 100644 index 5afb9451d..000000000 --- a/src/org/traccar/protocol/Pt502Protocol.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class Pt502Protocol extends BaseProtocol { - - public Pt502Protocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_SET_TIMEZONE, - Command.TYPE_ALARM_SPEED, - Command.TYPE_OUTPUT_CONTROL, - Command.TYPE_REQUEST_PHOTO); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Pt502FrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Pt502ProtocolEncoder()); - pipeline.addLast(new Pt502ProtocolDecoder(Pt502Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/org/traccar/protocol/Pt502ProtocolDecoder.java deleted file mode 100644 index 12210652b..000000000 --- a/src/org/traccar/protocol/Pt502ProtocolDecoder.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2012 Luis Parada (luis.parada@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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -public class Pt502ProtocolDecoder extends BaseProtocolDecoder { - - private static final int MAX_CHUNK_SIZE = 960; - - private ByteBuf photo; - - public Pt502ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .any().text("$") - .expression("([^,]+),") // type - .number("(d+),") // id - .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) - .expression("([AV]),") // validity - .number("(d+)(dd.dddd),") // latitude - .expression("([NS]),") - .number("(d+)(dd.dddd),") // longitude - .expression("([EW]),") - .number("(d+.d+)?,") // speed - .number("(d+.d+)?,") // course - .number("(dd)(dd)(dd),,,") // date (ddmmyy) - .expression("./") - .expression("([01])+,") // input - .expression("([01])+/") // output - .expression("([^/]+)?/") // adc - .number("(d+)") // odometer - .expression("/([^/]+)?/") // rfid - .number("(xxx)").optional(2) // state - .any() - .compile(); - - private String decodeAlarm(String value) { - switch (value) { - case "IN1": - return Position.ALARM_SOS; - case "GOF": - return Position.ALARM_GEOFENCE; - case "TOW": - return Position.ALARM_TOW; - case "HDA": - return Position.ALARM_ACCELERATION; - case "HDB": - return Position.ALARM_BRAKING; - case "FDA": - return Position.ALARM_FATIGUE_DRIVING; - case "SKA": - return Position.ALARM_VIBRATION; - case "PMA": - return Position.ALARM_MOVEMENT; - case "CPA": - return Position.ALARM_POWER_CUT; - default: - return null; - } - } - - private Position decodePosition(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.set(Position.KEY_ALARM, decodeAlarm(parser.next())); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - - if (parser.hasNext()) { - String[] values = parser.next().split(","); - for (int i = 0; i < values.length; i++) { - position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(values[i], 16)); - } - } - - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - if (parser.hasNext()) { - int value = parser.nextHexInt(0); - position.set(Position.KEY_BATTERY, value >> 8); - position.set(Position.KEY_RSSI, (value >> 4) & 0xf); - position.set(Position.KEY_SATELLITES, value & 0xf); - } - - return position; - } - - private void requestPhotoFragment(Channel channel) { - if (channel != null) { - int offset = photo.writerIndex(); - int size = Math.min(photo.writableBytes(), MAX_CHUNK_SIZE); - channel.writeAndFlush(new NetworkMessage("#PHD" + offset + "," + size + "\r\n", channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int typeEndIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); - String type = buf.toString(buf.readerIndex(), typeEndIndex - buf.readerIndex(), StandardCharsets.US_ASCII); - - if (type.startsWith("$PHD")) { - - int dataIndex = buf.indexOf(typeEndIndex + 1, buf.writerIndex(), (byte) ',') + 1; - buf.readerIndex(dataIndex); - - if (photo != null) { - - photo.writeBytes(buf.readSlice(buf.readableBytes())); - - if (photo.writableBytes() > 0) { - - requestPhotoFragment(channel); - - } else { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId(); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg")); - photo.release(); - photo = null; - - return position; - - } - - } - - } else { - - if (type.startsWith("$PHO")) { - int size = Integer.parseInt(type.split("-")[0].substring(4)); - if (size > 0) { - photo = Unpooled.buffer(size); - requestPhotoFragment(channel); - } - } - - return decodePosition(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII)); - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Pt502ProtocolEncoder.java b/src/org/traccar/protocol/Pt502ProtocolEncoder.java deleted file mode 100644 index ed18208cc..000000000 --- a/src/org/traccar/protocol/Pt502ProtocolEncoder.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2016 - 2017 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. - * 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.TimeZone; - -import org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class Pt502ProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { - - @Override - public String formatValue(String key, Object value) { - if (key.equals(Command.KEY_TIMEZONE)) { - return String.valueOf(TimeZone.getTimeZone((String) value).getRawOffset() / 3600000); - } - - return null; - } - - @Override - protected String formatCommand(Command command, String format, String... keys) { - return formatCommand(command, format, this, keys); - } - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatCommand(command, "{%s}\r\n", Command.KEY_DATA); - case Command.TYPE_OUTPUT_CONTROL: - return formatCommand(command, "#OPC{%s},{%s}\r\n", Command.KEY_INDEX, Command.KEY_DATA); - case Command.TYPE_SET_TIMEZONE: - return formatCommand(command, "#TMZ{%s}\r\n", Command.KEY_TIMEZONE); - case Command.TYPE_ALARM_SPEED: - return formatCommand(command, "#SPD{%s}\r\n", Command.KEY_DATA); - case Command.TYPE_REQUEST_PHOTO: - return formatCommand(command, "#PHO\r\n"); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Pt60Protocol.java b/src/org/traccar/protocol/Pt60Protocol.java deleted file mode 100644 index c502426c5..000000000 --- a/src/org/traccar/protocol/Pt60Protocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Pt60Protocol extends BaseProtocol { - - public Pt60Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "@R#@", "@E#@")); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Pt60ProtocolDecoder(Pt60Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Pt60ProtocolDecoder.java b/src/org/traccar/protocol/Pt60ProtocolDecoder.java deleted file mode 100644 index 6a3fe2734..000000000 --- a/src/org/traccar/protocol/Pt60ProtocolDecoder.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.regex.Pattern; - -public class Pt60ProtocolDecoder extends BaseProtocolDecoder { - - public Pt60ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_G_TRACK = 6; - public static final int MSG_G_STEP_COUNT = 13; - public static final int MSG_G_HEART_RATE = 14; - - public static final int MSG_B_POSITION = 1; - - private static final Pattern PATTERN = new PatternBuilder() - .expression("@(.)#@[,|]") // header - .number("V?dd[,|]") // protocol version - .number("(d+)[,|]") // type - .number("(d+)[,|]") // imei - .number("d+[,|]") // imsi - .groupBegin() - .expression("[^,|]+[,|]").optional() // firmware version - .number("[01][,|]") // state - .number("d+[,|]") // battery - .groupEnd("?") - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd)[,|]") // time (hhmmss) - .expression("(.*)") // data - .expression("[,|]") - .compile(); - - private void sendResponse(Channel channel, SocketAddress remoteAddress, String format, int type, String imei) { - if (channel != null) { - String message; - String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); - if (format.equals("G")) { - message = String.format("@G#@,V01,38,%s,@R#@", time); - } else { - message = String.format("@B#@|01|%03d|%s|0|%s|@E#@", type + 1, imei, time); - } - channel.writeAndFlush(new NetworkMessage(message, remoteAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - String format = parser.next(); - int type = parser.nextInt(); - String imei = parser.next(); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - sendResponse(channel, remoteAddress, format, type, imei); - - if (format.equals("G")) { - - if (type != MSG_G_TRACK && type != MSG_G_STEP_COUNT && type != MSG_G_HEART_RATE) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setDeviceTime(parser.nextDateTime()); - - String[] values = parser.next().split(","); - - if (type == MSG_G_TRACK) { - - position.setValid(true); - position.setFixTime(position.getDeviceTime()); - - String[] coordinates = values[0].split(";"); - position.setLatitude(Double.parseDouble(coordinates[0])); - position.setLongitude(Double.parseDouble(coordinates[1])); - - } else { - - getLastLocation(position, position.getDeviceTime()); - - switch (type) { - case MSG_G_STEP_COUNT: - position.set(Position.KEY_STEPS, Integer.parseInt(values[0])); - break; - case MSG_G_HEART_RATE: - position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[0])); - position.set(Position.KEY_BATTERY, Integer.parseInt(values[1])); - break; - default: - break; - } - - } - - return position; - - } else { - - if (type != MSG_B_POSITION) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setDeviceTime(parser.nextDateTime()); - - String[] values = parser.next().split("\\|"); - - if (Integer.parseInt(values[values.length - 1]) == 2) { - - getLastLocation(position, position.getDeviceTime()); - - Network network = new Network(); - - for (int i = 0; i < values.length - 1; i++) { - String[] cellValues = values[i].split(","); - CellTower tower = new CellTower(); - tower.setCellId(Long.parseLong(cellValues[0])); - tower.setLocationAreaCode(Integer.parseInt(cellValues[1])); - tower.setMobileNetworkCode(Integer.parseInt(cellValues[2])); - tower.setMobileCountryCode(Integer.parseInt(cellValues[3])); - tower.setSignalStrength(Integer.parseInt(cellValues[4])); - network.addCellTower(tower); - } - - position.setNetwork(network); - - - } else { - - position.setValid(true); - position.setFixTime(position.getDeviceTime()); - - position.setLatitude(Double.parseDouble(values[0])); - position.setLongitude(Double.parseDouble(values[1])); - - } - - return position; - - } - } - -} diff --git a/src/org/traccar/protocol/RaveonProtocol.java b/src/org/traccar/protocol/RaveonProtocol.java deleted file mode 100644 index 44faadb3b..000000000 --- a/src/org/traccar/protocol/RaveonProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class RaveonProtocol extends BaseProtocol { - - public RaveonProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new RaveonProtocolDecoder(RaveonProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/RaveonProtocolDecoder.java b/src/org/traccar/protocol/RaveonProtocolDecoder.java deleted file mode 100644 index 50acd20a1..000000000 --- a/src/org/traccar/protocol/RaveonProtocolDecoder.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class RaveonProtocolDecoder extends BaseProtocolDecoder { - - public RaveonProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$PRAVE,") - .number("(d+),") // id - .number("d+,") - .number("(-?)(d+)(dd.d+),") // latitude - .number("(-?)(d+)(dd.d+),") // longitude - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d),") // validity - .number("(d+),") // satellites - .number("(-?d+),") // altitude - .number("(-?d+),") // temperature - .number("(d+.d+),") // power - .number("(d+),") // inputs - .number("(-?d+),") // gsm - .number("(d+),") // speed - .number("(d+),") // course - .expression("([PMACIVSX])?,") // status - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS)); - - position.setValid(parser.nextInt(0) != 0); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - - position.setAltitude(parser.nextInt(0)); - - position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); - position.set(Position.KEY_POWER, parser.nextDouble(0)); - position.set(Position.KEY_INPUT, parser.nextInt(0)); - position.set(Position.KEY_RSSI, parser.nextInt(0)); - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); - position.setCourse(parser.nextInt(0)); - - position.set(Position.KEY_ALARM, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/RecodaProtocol.java b/src/org/traccar/protocol/RecodaProtocol.java deleted file mode 100644 index 0bc9870bc..000000000 --- a/src/org/traccar/protocol/RecodaProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; -public class RecodaProtocol extends BaseProtocol { - - public RecodaProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 4, 4, -8, 0, true)); - pipeline.addLast(new RecodaProtocolDecoder(RecodaProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/RecodaProtocolDecoder.java b/src/org/traccar/protocol/RecodaProtocolDecoder.java deleted file mode 100644 index 04098225f..000000000 --- a/src/org/traccar/protocol/RecodaProtocolDecoder.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class RecodaProtocolDecoder extends BaseProtocolDecoder { - - public RecodaProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_HEARTBEAT = 0x00001001; - public static final int MSG_REQUEST_RESPONSE = 0x20000001; - public static final int MSG_SIGNAL_LINK_REGISTRATION = 0x20001001; - public static final int MSG_EVENT_NOTICE = 0x20002001; - public static final int MSG_GPS_DATA = 0x20001011; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int type = buf.readIntLE(); - buf.readUnsignedIntLE(); // length - - if (type != MSG_HEARTBEAT) { - buf.readUnsignedShortLE(); // version - buf.readUnsignedShortLE(); // index - } - - if (type == MSG_SIGNAL_LINK_REGISTRATION) { - - getDeviceSession(channel, remoteAddress, buf.readSlice(12).toString(StandardCharsets.US_ASCII)); - - } else if (type == MSG_GPS_DATA) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(buf.readLongLE())); - - int flags = buf.readUnsignedByte(); - - if (BitUtil.check(flags, 0)) { - - buf.readUnsignedShortLE(); // declination - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE())); - - position.setLongitude(buf.readUnsignedByte() + buf.readUnsignedByte() / 60.0); - position.setLatitude(buf.readUnsignedByte() + buf.readUnsignedByte() / 60.0); - - position.setLongitude(position.getLongitude() + buf.readUnsignedIntLE() / 3600.0); - position.setLatitude(position.getLatitude() + buf.readUnsignedIntLE() / 3600.0); - - int status = buf.readUnsignedByte(); - - position.setValid(BitUtil.check(status, 0)); - if (BitUtil.check(status, 1)) { - position.setLongitude(-position.getLongitude()); - } - if (!BitUtil.check(status, 2)) { - position.setLatitude(-position.getLatitude()); - } - - } else { - - getLastLocation(position, position.getDeviceTime()); - - } - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/RetranslatorFrameDecoder.java b/src/org/traccar/protocol/RetranslatorFrameDecoder.java deleted file mode 100644 index 4edd09418..000000000 --- a/src/org/traccar/protocol/RetranslatorFrameDecoder.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class RetranslatorFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int length = 4 + buf.getIntLE(buf.readerIndex()); - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } else { - return null; - } - } - -} diff --git a/src/org/traccar/protocol/RetranslatorProtocol.java b/src/org/traccar/protocol/RetranslatorProtocol.java deleted file mode 100644 index fae81f7d2..000000000 --- a/src/org/traccar/protocol/RetranslatorProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class RetranslatorProtocol extends BaseProtocol { - - public RetranslatorProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new RetranslatorFrameDecoder()); - pipeline.addLast(new RetranslatorProtocolDecoder(RetranslatorProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/RetranslatorProtocolDecoder.java b/src/org/traccar/protocol/RetranslatorProtocolDecoder.java deleted file mode 100644 index 0688c9b0e..000000000 --- a/src/org/traccar/protocol/RetranslatorProtocolDecoder.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class RetranslatorProtocolDecoder extends BaseProtocolDecoder { - - public RetranslatorProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(new byte[]{0x11}), remoteAddress)); - } - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedInt(); // length - - int idLength = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex(); - String id = buf.readBytes(idLength).toString(StandardCharsets.US_ASCII); - buf.readByte(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - - buf.readUnsignedInt(); // bit flags - - while (buf.isReadable()) { - - buf.readUnsignedShort(); // block type - int blockEnd = buf.readInt() + buf.readerIndex(); - buf.readUnsignedByte(); // security attribute - int dataType = buf.readUnsignedByte(); - - int nameLength = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex(); - String name = buf.readBytes(nameLength).toString(StandardCharsets.US_ASCII); - buf.readByte(); - - if (name.equals("posinfo")) { - position.setValid(true); - position.setLongitude(buf.readDoubleLE()); - position.setLatitude(buf.readDoubleLE()); - position.setAltitude(buf.readDoubleLE()); - position.setSpeed(buf.readShort()); - position.setCourse(buf.readShort()); - position.set(Position.KEY_SATELLITES, buf.readByte()); - } else { - switch (dataType) { - case 1: - int len = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x00) - buf.readerIndex(); - position.set(name, buf.readBytes(len).toString(StandardCharsets.US_ASCII)); - buf.readByte(); - break; - case 3: - position.set(name, buf.readInt()); - break; - case 4: - position.set(name, buf.readDoubleLE()); - break; - case 5: - position.set(name, buf.readLong()); - break; - default: - break; - } - } - - buf.readerIndex(blockEnd); - - } - - if (position.getLatitude() == 0 && position.getLongitude() == 0) { - getLastLocation(position, position.getDeviceTime()); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/RitiProtocol.java b/src/org/traccar/protocol/RitiProtocol.java deleted file mode 100644 index de1026672..000000000 --- a/src/org/traccar/protocol/RitiProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; -public class RitiProtocol extends BaseProtocol { - - public RitiProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 105, 2, 3, 0, true)); - pipeline.addLast(new RitiProtocolDecoder(RitiProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/RitiProtocolDecoder.java b/src/org/traccar/protocol/RitiProtocolDecoder.java deleted file mode 100644 index 46267ca90..000000000 --- a/src/org/traccar/protocol/RitiProtocolDecoder.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -public class RitiProtocolDecoder extends BaseProtocolDecoder { - - public RitiProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$GPRMC,") - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(buf.readUnsignedShort())); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set("mode", buf.readUnsignedByte()); - position.set(Position.KEY_COMMAND, buf.readUnsignedByte()); - position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.001); - - buf.skipBytes(5); // status - buf.readUnsignedShortLE(); // idleCount - buf.readUnsignedShortLE(); // idleTime in seconds - - position.set(Position.KEY_DISTANCE, buf.readUnsignedIntLE()); - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedIntLE()); - - // Parse GPRMC - int end = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*'); - String gprmc = buf.toString(buf.readerIndex(), end - buf.readerIndex(), StandardCharsets.US_ASCII); - Parser parser = new Parser(PATTERN, gprmc); - if (!parser.matches()) { - return null; - } - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/RoboTrackFrameDecoder.java b/src/org/traccar/protocol/RoboTrackFrameDecoder.java deleted file mode 100644 index 85ed6c76f..000000000 --- a/src/org/traccar/protocol/RoboTrackFrameDecoder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class RoboTrackFrameDecoder extends BaseFrameDecoder { - - private int messageLength(ByteBuf buf) { - switch (buf.getUnsignedByte(buf.readerIndex())) { - case RoboTrackProtocolDecoder.MSG_ID: - return 69; - case RoboTrackProtocolDecoder.MSG_ACK: - return 3; - case RoboTrackProtocolDecoder.MSG_GPS: - case RoboTrackProtocolDecoder.MSG_GSM: - case RoboTrackProtocolDecoder.MSG_IMAGE_START: - return 24; - case RoboTrackProtocolDecoder.MSG_IMAGE_DATA: - return 8 + buf.getUnsignedShortLE(buf.readerIndex() + 1); - case RoboTrackProtocolDecoder.MSG_IMAGE_END: - return 6; - default: - return Integer.MAX_VALUE; - } - } - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int length = messageLength(buf); - - if (buf.readableBytes() >= length) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/RoboTrackProtocol.java b/src/org/traccar/protocol/RoboTrackProtocol.java deleted file mode 100644 index c2c531293..000000000 --- a/src/org/traccar/protocol/RoboTrackProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class RoboTrackProtocol extends BaseProtocol { - - public RoboTrackProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new RoboTrackFrameDecoder()); - pipeline.addLast(new RoboTrackProtocolDecoder(RoboTrackProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/RoboTrackProtocolDecoder.java b/src/org/traccar/protocol/RoboTrackProtocolDecoder.java deleted file mode 100644 index b613f31d7..000000000 --- a/src/org/traccar/protocol/RoboTrackProtocolDecoder.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class RoboTrackProtocolDecoder extends BaseProtocolDecoder { - - public RoboTrackProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_ID = 0x00; - public static final int MSG_ACK = 0x80; - public static final int MSG_GPS = 0x03; - public static final int MSG_GSM = 0x04; - public static final int MSG_IMAGE_START = 0x06; - public static final int MSG_IMAGE_DATA = 0x07; - public static final int MSG_IMAGE_END = 0x08; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int type = buf.readUnsignedByte(); - - if (type == MSG_ID) { - - buf.skipBytes(16); // name - - String imei = buf.readSlice(15).toString(StandardCharsets.US_ASCII); - - if (getDeviceSession(channel, remoteAddress, imei) != null && channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(MSG_ACK); - response.writeByte(0x01); // success - response.writeByte(0x66); // checksum - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - } else if (type == MSG_GPS || type == MSG_GSM) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setDeviceTime(new Date(buf.readUnsignedIntLE() * 1000)); - - if (type == MSG_GPS) { - - position.setValid(true); - position.setFixTime(position.getDeviceTime()); - position.setLatitude(buf.readIntLE() * 0.000001); - position.setLongitude(buf.readIntLE() * 0.000001); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readByte())); - - } else { - - getLastLocation(position, position.getDeviceTime()); - - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShortLE(), buf.readUnsignedShortLE(), - buf.readUnsignedShortLE(), buf.readUnsignedShortLE()))); - - buf.readUnsignedByte(); // reserved - - } - - int value = buf.readUnsignedByte(); - - position.set(Position.KEY_SATELLITES, BitUtil.to(value, 4)); - position.set(Position.KEY_RSSI, BitUtil.between(value, 4, 7)); - position.set(Position.KEY_MOTION, BitUtil.check(value, 7)); - - value = buf.readUnsignedByte(); - - position.set(Position.KEY_CHARGE, BitUtil.check(value, 0)); - - for (int i = 1; i <= 4; i++) { - position.set(Position.PREFIX_IN + i, BitUtil.check(value, i)); - } - - position.set(Position.KEY_BATTERY_LEVEL, BitUtil.from(value, 5) * 100 / 7); - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - - for (int i = 1; i <= 3; i++) { - position.set(Position.PREFIX_ADC + i, buf.readUnsignedShortLE()); - } - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/RuptelaProtocol.java b/src/org/traccar/protocol/RuptelaProtocol.java deleted file mode 100644 index 1ac62570a..000000000 --- a/src/org/traccar/protocol/RuptelaProtocol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class RuptelaProtocol extends BaseProtocol { - - public RuptelaProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_CONFIGURATION, - Command.TYPE_GET_VERSION, - Command.TYPE_FIRMWARE_UPDATE, - Command.TYPE_OUTPUT_CONTROL, - Command.TYPE_SET_CONNECTION, - Command.TYPE_SET_ODOMETER); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, 2, 0)); - pipeline.addLast(new RuptelaProtocolEncoder()); - pipeline.addLast(new RuptelaProtocolDecoder(RuptelaProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/org/traccar/protocol/RuptelaProtocolDecoder.java deleted file mode 100644 index b043b6201..000000000 --- a/src/org/traccar/protocol/RuptelaProtocolDecoder.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DataConverter; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class RuptelaProtocolDecoder extends BaseProtocolDecoder { - - public RuptelaProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_RECORDS = 1; - public static final int MSG_DEVICE_CONFIGURATION = 2; - public static final int MSG_DEVICE_VERSION = 3; - public static final int MSG_FIRMWARE_UPDATE = 4; - public static final int MSG_SET_CONNECTION = 5; - public static final int MSG_SET_ODOMETER = 6; - public static final int MSG_SMS_VIA_GPRS_RESPONSE = 7; - public static final int MSG_SMS_VIA_GPRS = 8; - public static final int MSG_DTCS = 9; - public static final int MSG_SET_IO = 17; - public static final int MSG_EXTENDED_RECORDS = 68; - - private Position decodeCommandResponse(DeviceSession deviceSession, int type, ByteBuf buf) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_TYPE, type); - - switch (type) { - case MSG_DEVICE_CONFIGURATION: - case MSG_DEVICE_VERSION: - case MSG_FIRMWARE_UPDATE: - case MSG_SMS_VIA_GPRS_RESPONSE: - position.set(Position.KEY_RESULT, - buf.toString(buf.readerIndex(), buf.readableBytes() - 2, StandardCharsets.US_ASCII).trim()); - return position; - case MSG_SET_IO: - position.set(Position.KEY_RESULT, - String.valueOf(buf.readUnsignedByte())); - return position; - default: - return null; - } - } - - private long readValue(ByteBuf buf, int length, boolean signed) { - switch (length) { - case 1: - return signed ? buf.readByte() : buf.readUnsignedByte(); - case 2: - return signed ? buf.readShort() : buf.readUnsignedShort(); - case 4: - return signed ? buf.readInt() : buf.readUnsignedInt(); - default: - return buf.readLong(); - } - } - - private void decodeParameter(Position position, int id, ByteBuf buf, int length) { - switch (id) { - case 2: - case 3: - case 4: - position.set("di" + (id - 1), readValue(buf, length, false)); - break; - case 5: - position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); - break; - case 74: - position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1); - break; - case 78: - case 79: - case 80: - position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1); - break; - default: - position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); - break; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedShort(); // data length - - String imei = String.format("%015d", buf.readLong()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - int type = buf.readUnsignedByte(); - - if (type == MSG_RECORDS || type == MSG_EXTENDED_RECORDS) { - - List positions = new LinkedList<>(); - - buf.readUnsignedByte(); // records left - int count = buf.readUnsignedByte(); - - for (int i = 0; i < count; i++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - buf.readUnsignedByte(); // timestamp extension - - if (type == MSG_EXTENDED_RECORDS) { - buf.readUnsignedByte(); // record extension - } - - buf.readUnsignedByte(); // priority (reserved) - - position.setValid(true); - position.setLongitude(buf.readInt() / 10000000.0); - position.setLatitude(buf.readInt() / 10000000.0); - position.setAltitude(buf.readUnsignedShort() / 10.0); - position.setCourse(buf.readUnsignedShort() / 100.0); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - - position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0); - - if (type == MSG_EXTENDED_RECORDS) { - position.set(Position.KEY_EVENT, buf.readUnsignedShort()); - } else { - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - } - - // Read 1 byte data - int cnt = buf.readUnsignedByte(); - for (int j = 0; j < cnt; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 1); - } - - // Read 2 byte data - cnt = buf.readUnsignedByte(); - for (int j = 0; j < cnt; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 2); - } - - // Read 4 byte data - cnt = buf.readUnsignedByte(); - for (int j = 0; j < cnt; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 4); - } - - // Read 8 byte data - cnt = buf.readUnsignedByte(); - for (int j = 0; j < cnt; j++) { - int id = type == MSG_EXTENDED_RECORDS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - decodeParameter(position, id, buf, 8); - } - - positions.add(position); - } - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - Unpooled.wrappedBuffer(DataConverter.parseHex("0002640113bc")), remoteAddress)); - } - - return positions; - - } else if (type == MSG_DTCS) { - - List positions = new LinkedList<>(); - - int count = buf.readUnsignedByte(); - - for (int i = 0; i < count; i++) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedByte(); // reserved - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - - position.setValid(true); - position.setLongitude(buf.readInt() / 10000000.0); - position.setLatitude(buf.readInt() / 10000000.0); - - if (buf.readUnsignedByte() == 2) { - position.set(Position.KEY_ARCHIVE, true); - } - - position.set(Position.KEY_DTCS, buf.readSlice(5).toString(StandardCharsets.US_ASCII)); - - positions.add(position); - } - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - Unpooled.wrappedBuffer(DataConverter.parseHex("00026d01c4a4")), remoteAddress)); - } - - return positions; - - } else { - - return decodeCommandResponse(deviceSession, type, buf); - - } - } - -} diff --git a/src/org/traccar/protocol/RuptelaProtocolEncoder.java b/src/org/traccar/protocol/RuptelaProtocolEncoder.java deleted file mode 100644 index 4242584c9..000000000 --- a/src/org/traccar/protocol/RuptelaProtocolEncoder.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class RuptelaProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeContent(int type, ByteBuf content) { - - ByteBuf buf = Unpooled.buffer(); - - buf.writeShort(1 + content.readableBytes()); - buf.writeByte(100 + type); - buf.writeBytes(content); - buf.writeShort(Checksum.crc16(Checksum.CRC16_KERMIT, buf.nioBuffer(2, buf.writerIndex() - 2))); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - ByteBuf content = Unpooled.buffer(); - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - content.writeBytes(command.getString(Command.KEY_DATA).getBytes(StandardCharsets.US_ASCII)); - return encodeContent(RuptelaProtocolDecoder.MSG_SMS_VIA_GPRS, content); - case Command.TYPE_CONFIGURATION: - content.writeBytes((command.getString(Command.KEY_DATA) + "\r\n").getBytes(StandardCharsets.US_ASCII)); - return encodeContent(RuptelaProtocolDecoder.MSG_DEVICE_CONFIGURATION, content); - case Command.TYPE_GET_VERSION: - return encodeContent(RuptelaProtocolDecoder.MSG_DEVICE_VERSION, content); - case Command.TYPE_FIRMWARE_UPDATE: - content.writeBytes("|FU_STRT*\r\n".getBytes(StandardCharsets.US_ASCII)); - return encodeContent(RuptelaProtocolDecoder.MSG_FIRMWARE_UPDATE, content); - case Command.TYPE_OUTPUT_CONTROL: - content.writeInt(command.getInteger(Command.KEY_INDEX)); - content.writeInt(Integer.parseInt(command.getString(Command.KEY_DATA))); - return encodeContent(RuptelaProtocolDecoder.MSG_SET_IO, content); - case Command.TYPE_SET_CONNECTION: - String c = command.getString(Command.KEY_SERVER) + "," + command.getInteger(Command.KEY_PORT) + ",TCP"; - content.writeBytes(c.getBytes(StandardCharsets.US_ASCII)); - return encodeContent(RuptelaProtocolDecoder.MSG_SET_CONNECTION, content); - case Command.TYPE_SET_ODOMETER: - content.writeInt(Integer.parseInt(command.getString(Command.KEY_DATA))); - return encodeContent(RuptelaProtocolDecoder.MSG_SET_ODOMETER, content); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/SabertekFrameDecoder.java b/src/org/traccar/protocol/SabertekFrameDecoder.java deleted file mode 100644 index ad5000bf8..000000000 --- a/src/org/traccar/protocol/SabertekFrameDecoder.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class SabertekFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int beginIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02); - if (beginIndex >= 0) { - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x03); - if (endIndex >= 0) { - buf.readerIndex(beginIndex + 1); - ByteBuf frame = buf.readRetainedSlice(endIndex - beginIndex - 1); - buf.readerIndex(endIndex + 1); - buf.skipBytes(2); // end line - return frame; - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/SabertekProtocol.java b/src/org/traccar/protocol/SabertekProtocol.java deleted file mode 100644 index 0ec847b60..000000000 --- a/src/org/traccar/protocol/SabertekProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SabertekProtocol extends BaseProtocol { - - public SabertekProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new SabertekFrameDecoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new SabertekProtocolDecoder(SabertekProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SabertekProtocolDecoder.java b/src/org/traccar/protocol/SabertekProtocolDecoder.java deleted file mode 100644 index 3033aa2cc..000000000 --- a/src/org/traccar/protocol/SabertekProtocolDecoder.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.regex.Pattern; - -public class SabertekProtocolDecoder extends BaseProtocolDecoder { - - public SabertekProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text(",") - .number("(d+),") // id - .number("d,") // type - .groupBegin() - .number("d+,") // imei - .number("d+,") // scid - .expression("[^,]*,") // phone - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .groupEnd("?") - .number("(d+),") // battery - .number("(d+),") // rssi - .number("(d+),") // state - .number("(d+),") // events - .number("(d),") // valid - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+),") // altitude - .number("(d+),") // satellites - .number("(d+),") // odometer - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - Unpooled.wrappedBuffer(new byte[]{(byte) (deviceSession != null ? 0x06 : 0x15)}), remoteAddress)); - } - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (parser.hasNext(6)) { - position.setTime(parser.nextDateTime()); - } else { - position.setTime(new Date()); - } - - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - position.set(Position.KEY_RSSI, parser.nextInt()); - - int state = parser.nextInt(); - - position.set(Position.KEY_IGNITION, BitUtil.check(state, 0)); - position.set(Position.KEY_CHARGE, BitUtil.check(state, 1)); - - if (BitUtil.check(state, 2)) { - position.set(Position.KEY_ALARM, Position.ALARM_JAMMING); - } - if (BitUtil.check(state, 3)) { - position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); - } - - int events = parser.nextInt(); - - if (BitUtil.check(events, 0)) { - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - } - if (BitUtil.check(events, 1)) { - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - } - if (BitUtil.check(events, 2)) { - position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); - } - if (BitUtil.check(events, 3)) { - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - } - - position.setValid(parser.nextInt() == 1); - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); - position.setCourse(parser.nextInt()); - position.setAltitude(parser.nextInt()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextInt() * 1000L); - - return position; - } - -} diff --git a/src/org/traccar/protocol/SanavProtocol.java b/src/org/traccar/protocol/SanavProtocol.java deleted file mode 100644 index 6799c57e6..000000000 --- a/src/org/traccar/protocol/SanavProtocol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SanavProtocol extends BaseProtocol { - - public SanavProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new SanavProtocolDecoder(SanavProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new SanavProtocolDecoder(SanavProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SanavProtocolDecoder.java b/src/org/traccar/protocol/SanavProtocolDecoder.java deleted file mode 100644 index 7e1c158e6..000000000 --- a/src/org/traccar/protocol/SanavProtocolDecoder.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class SanavProtocolDecoder extends BaseProtocolDecoder { - - public SanavProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("imei[:=]") - .number("(d+)") // imei - .expression("&?rmc[:=]") - .text("$GPRMC,") - .number("(dd)(dd)(dd).d+,") // time (hhmmss.sss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.d+),") // speed - .number("(d+.d+)?,") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .groupBegin() - .expression("[^*]*") - .text("*") - .number("xx,") - .expression("[^,]+,") // status - .number("(d+),") // io - .groupEnd("?") - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble()); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - if (parser.hasNext()) { - int io = parser.nextHexInt(); - for (int i = 0; i < 5; i++) { - position.set(Position.PREFIX_IN + (i + 1), BitUtil.check(io, i)); - } - position.set(Position.KEY_IGNITION, BitUtil.check(io, 5)); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(io, 6)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(io, 7)); - position.set(Position.KEY_CHARGE, BitUtil.check(io, 8)); - if (!BitUtil.check(io, 9)) { - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - } - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/SatsolProtocol.java b/src/org/traccar/protocol/SatsolProtocol.java deleted file mode 100644 index b69fdd1fe..000000000 --- a/src/org/traccar/protocol/SatsolProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import java.nio.ByteOrder; - -public class SatsolProtocol extends BaseProtocol { - - public SatsolProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1400, 8, 2, 0, 0, true)); - pipeline.addLast(new SatsolProtocolDecoder(SatsolProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SatsolProtocolDecoder.java b/src/org/traccar/protocol/SatsolProtocolDecoder.java deleted file mode 100644 index c457d5620..000000000 --- a/src/org/traccar/protocol/SatsolProtocolDecoder.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -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.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class SatsolProtocolDecoder extends BaseProtocolDecoder { - - public SatsolProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedShortLE(); // checksum - buf.readUnsignedShortLE(); // preamble - long id = buf.readUnsignedIntLE(); - buf.readUnsignedShortLE(); // length - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - while (buf.isReadable()) { - - buf.readUnsignedShortLE(); // checksum - buf.readUnsignedShortLE(); // checksum - buf.readUnsignedShortLE(); // type - int length = buf.readUnsignedShortLE(); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); - position.setLatitude(buf.readUnsignedIntLE() * 0.000001); - position.setLongitude(buf.readUnsignedIntLE() * 0.000001); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE() * 0.01)); - position.setAltitude(buf.readShortLE()); - position.setCourse(buf.readUnsignedShortLE()); - position.setValid(buf.readUnsignedByte() > 0); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - - if (BitUtil.check(buf.readUnsignedByte(), 0)) { - position.set(Position.KEY_ARCHIVE, true); - } - - positions.add(position); - - buf.skipBytes(length); - - } - - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeShortLE(0); - response.writeShortLE(0x4CBF); // preamble - response.writeIntLE((int) id); - response.writeShortLE(0); - response.setShortLE(0, Checksum.crc16( - Checksum.CRC16_CCITT_FALSE, response.nioBuffer(2, response.readableBytes() - 2))); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/SigfoxProtocol.java b/src/org/traccar/protocol/SigfoxProtocol.java deleted file mode 100644 index e2f2cbe1f..000000000 --- a/src/org/traccar/protocol/SigfoxProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SigfoxProtocol extends BaseProtocol { - - public SigfoxProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(65535)); - pipeline.addLast(new SigfoxProtocolDecoder(SigfoxProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/org/traccar/protocol/SigfoxProtocolDecoder.java deleted file mode 100644 index d7836b35d..000000000 --- a/src/org/traccar/protocol/SigfoxProtocolDecoder.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpResponseStatus; -import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DataConverter; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import javax.json.Json; -import javax.json.JsonObject; -import java.io.StringReader; -import java.net.SocketAddress; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { - - public SigfoxProtocolDecoder(Protocol protocol) { - super(protocol); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - JsonObject json = Json.createReader(new StringReader(URLDecoder.decode( - request.content().toString(StandardCharsets.UTF_8).split("=")[0], "UTF-8"))).readObject(); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, json.getString("device")); - if (deviceSession == null) { - sendResponse(channel, HttpResponseStatus.BAD_REQUEST); - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(json.getInt("time") * 1000L)); - - ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(json.getString("data"))); - try { - int type = buf.readUnsignedByte() >> 4; - if (type == 0) { - - position.setValid(true); - position.setLatitude(buf.readIntLE() * 0.0000001); - position.setLongitude(buf.readIntLE() * 0.0000001); - position.setCourse(buf.readUnsignedByte() * 2); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - - position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.025); - - } else { - - getLastLocation(position, position.getDeviceTime()); - - } - } finally { - buf.release(); - } - - position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").doubleValue()); - position.set(Position.KEY_INDEX, json.getInt("seqNumber")); - - sendResponse(channel, HttpResponseStatus.OK); - return position; - } - -} diff --git a/src/org/traccar/protocol/SiwiProtocol.java b/src/org/traccar/protocol/SiwiProtocol.java deleted file mode 100644 index 8963721c8..000000000 --- a/src/org/traccar/protocol/SiwiProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SiwiProtocol extends BaseProtocol { - - public SiwiProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new SiwiProtocolDecoder(SiwiProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SiwiProtocolDecoder.java b/src/org/traccar/protocol/SiwiProtocolDecoder.java deleted file mode 100644 index 6b97f5fe0..000000000 --- a/src/org/traccar/protocol/SiwiProtocolDecoder.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class SiwiProtocolDecoder extends BaseProtocolDecoder { - - public SiwiProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$").expression("[A-Z]+,") // header - .number("(d+),") // device id - .number("d+,") // unit no - .expression("([A-Z]),") // reason - .number("d+,") // command code - .number("[^,]*,") // command value - .expression("([01]),") // ignition - .expression("[01],") // power cut - .expression("[01],") // box open - .number("d+,") // message key - .number("(d+),") // odometer - .number("(d+),") // speed - .number("(d+),") // satellites - .expression("([AV]),") // valid - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(-?d+),") // altitude - .number("(d+),") // course - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd)(dd),") // date (ddmmyy) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_EVENT, parser.next()); - position.set(Position.KEY_IGNITION, parser.next().equals("1")); - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt(0))); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - position.setCourse(parser.nextInt(0)); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY, "IST")); - - return position; - } - -} diff --git a/src/org/traccar/protocol/SkypatrolProtocol.java b/src/org/traccar/protocol/SkypatrolProtocol.java deleted file mode 100644 index 7c6203d86..000000000 --- a/src/org/traccar/protocol/SkypatrolProtocol.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SkypatrolProtocol extends BaseProtocol { - - public SkypatrolProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new SkypatrolProtocolDecoder(SkypatrolProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SkypatrolProtocolDecoder.java b/src/org/traccar/protocol/SkypatrolProtocolDecoder.java deleted file mode 100644 index 3c7ca6dc5..000000000 --- a/src/org/traccar/protocol/SkypatrolProtocolDecoder.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; - -public class SkypatrolProtocolDecoder extends BaseProtocolDecoder { - - private static final Logger LOGGER = LoggerFactory.getLogger(SkypatrolProtocolDecoder.class); - - private final long defaultMask; - - public SkypatrolProtocolDecoder(Protocol protocol) { - super(protocol); - defaultMask = Context.getConfig().getInteger(getProtocolName() + ".mask"); - } - - private static double convertCoordinate(long coordinate) { - int sign = 1; - if (coordinate > 0x7fffffffL) { - sign = -1; - coordinate = 0xffffffffL - coordinate; - } - - long degrees = coordinate / 1000000; - double minutes = (coordinate % 1000000) / 10000.0; - - return sign * (degrees + minutes / 60); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int apiNumber = buf.readUnsignedShort(); - int commandType = buf.readUnsignedByte(); - int messageType = BitUtil.from(buf.readUnsignedByte(), 4); - long mask = defaultMask; - if (buf.readUnsignedByte() == 4) { - mask = buf.readUnsignedInt(); - } - - // Binary position report - if (apiNumber == 5 && commandType == 2 && messageType == 1 && BitUtil.check(mask, 0)) { - - Position position = new Position(getProtocolName()); - - if (BitUtil.check(mask, 1)) { - position.set(Position.KEY_STATUS, buf.readUnsignedInt()); - } - - String id; - if (BitUtil.check(mask, 23)) { - id = buf.toString(buf.readerIndex(), 8, StandardCharsets.US_ASCII).trim(); - buf.skipBytes(8); - } else if (BitUtil.check(mask, 2)) { - id = buf.toString(buf.readerIndex(), 22, StandardCharsets.US_ASCII).trim(); - buf.skipBytes(22); - } else { - LOGGER.warn("No device id field"); - return null; - } - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - if (BitUtil.check(mask, 3)) { - position.set(Position.PREFIX_IO + 1, buf.readUnsignedShort()); - } - - if (BitUtil.check(mask, 4)) { - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - } - - if (BitUtil.check(mask, 5)) { - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); - } - - if (BitUtil.check(mask, 7)) { - buf.readUnsignedByte(); // function category - } - - DateBuilder dateBuilder = new DateBuilder(); - - if (BitUtil.check(mask, 8)) { - dateBuilder.setDateReverse( - buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - } - - if (BitUtil.check(mask, 9)) { - position.setValid(buf.readUnsignedByte() == 1); // gps status - } - - if (BitUtil.check(mask, 10)) { - position.setLatitude(convertCoordinate(buf.readUnsignedInt())); - } - - if (BitUtil.check(mask, 11)) { - position.setLongitude(convertCoordinate(buf.readUnsignedInt())); - } - - if (BitUtil.check(mask, 12)) { - position.setSpeed(buf.readUnsignedShort() / 10.0); - } - - if (BitUtil.check(mask, 13)) { - position.setCourse(buf.readUnsignedShort() / 10.0); - } - - if (BitUtil.check(mask, 14)) { - dateBuilder.setTime( - buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - } - - position.setTime(dateBuilder.getDate()); - - if (BitUtil.check(mask, 15)) { - position.setAltitude(buf.readMedium()); - } - - if (BitUtil.check(mask, 16)) { - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - } - - if (BitUtil.check(mask, 17)) { - position.set(Position.KEY_BATTERY, buf.readUnsignedShort()); - } - - if (BitUtil.check(mask, 20)) { - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); - } - - if (BitUtil.check(mask, 21)) { - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - } - - if (BitUtil.check(mask, 22)) { - buf.skipBytes(6); // time of message generation - } - - if (BitUtil.check(mask, 24)) { - position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001); - } - - if (BitUtil.check(mask, 25)) { - buf.skipBytes(18); // gps overspeed - } - - if (BitUtil.check(mask, 26)) { - buf.skipBytes(54); // cell information - } - - if (BitUtil.check(mask, 28)) { - position.set(Position.KEY_INDEX, buf.readUnsignedShort()); - } - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/SmartSoleProtocol.java b/src/org/traccar/protocol/SmartSoleProtocol.java deleted file mode 100644 index bcf43f68b..000000000 --- a/src/org/traccar/protocol/SmartSoleProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SmartSoleProtocol extends BaseProtocol { - - public SmartSoleProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '$')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new SmartSoleProtocolDecoder(SmartSoleProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SmartSoleProtocolDecoder.java b/src/org/traccar/protocol/SmartSoleProtocolDecoder.java deleted file mode 100644 index 04920c969..000000000 --- a/src/org/traccar/protocol/SmartSoleProtocolDecoder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class SmartSoleProtocolDecoder extends BaseProtocolDecoder { - - public SmartSoleProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("#GTXRP=") - .number("(d+),") // imei - .number("d+,") // report type - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // longitude - .number("(-?d+.d+),") // latitude - .number("(-?d+),") // altitude - .number("(d+),") // speed - .number("([01]),") // valid - .number("(d+),") // satellites - .number("(d+.d+),") // hdop - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d+.d+),") // battery - .number("(d+)") // status - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setFixTime(parser.nextDateTime()); - - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - position.setAltitude(parser.nextInt()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt())); - position.setValid(parser.nextInt() == 1); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_HDOP, parser.nextDouble()); - - position.setDeviceTime(parser.nextDateTime()); - - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.KEY_STATUS, parser.nextInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/SmokeyProtocol.java b/src/org/traccar/protocol/SmokeyProtocol.java deleted file mode 100644 index 482c8347c..000000000 --- a/src/org/traccar/protocol/SmokeyProtocol.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SmokeyProtocol extends BaseProtocol { - - public SmokeyProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new SmokeyProtocolDecoder(SmokeyProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SmokeyProtocolDecoder.java b/src/org/traccar/protocol/SmokeyProtocolDecoder.java deleted file mode 100644 index 9da52e97a..000000000 --- a/src/org/traccar/protocol/SmokeyProtocolDecoder.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; -import org.traccar.model.WifiAccessPoint; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.time.temporal.ChronoUnit; - -public class SmokeyProtocolDecoder extends BaseProtocolDecoder { - - public SmokeyProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_DATE_RECORD = 0; - public static final int MSG_DATE_RECORD_ACK = 1; - - private static void sendResponse( - Channel channel, SocketAddress remoteAddress, ByteBuf id, int index, int report) { - - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeBytes("SM".getBytes(StandardCharsets.US_ASCII)); - response.writeByte(3); // protocol version - response.writeByte(MSG_DATE_RECORD_ACK); - response.writeBytes(id); - response.writeInt( - (int) ChronoUnit.SECONDS.between(Instant.parse("2000-01-01T00:00:00.00Z"), Instant.now())); - response.writeByte(index); - response.writeByte(report - 0x200); - - short checksum = (short) 0xF5A0; - for (int i = 0; i < response.readableBytes(); i += 2) { - checksum ^= response.getShortLE(i); - } - response.writeShort(checksum); - - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - buf.readUnsignedByte(); // protocol version - - int type = buf.readUnsignedByte(); - - ByteBuf id = buf.readSlice(8); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(id)); - if (deviceSession == null) { - return null; - } - - if (type == MSG_DATE_RECORD) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_VERSION_FW, buf.readUnsignedShort()); - - int status = buf.readUnsignedShort(); - position.set(Position.KEY_STATUS, status); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(2000, 1, 1).addSeconds(buf.readUnsignedInt()); - - getLastLocation(position, dateBuilder.getDate()); - - int index = buf.readUnsignedByte(); - position.set(Position.KEY_INDEX, index); - - int report = buf.readUnsignedShort(); - - buf.readUnsignedShort(); // length - - position.set(Position.KEY_BATTERY, buf.readUnsignedShort()); - - Network network = new Network(); - - if (report != 0x0203) { - - int count = 1; - if (report != 0x0200) { - count = buf.readUnsignedByte(); - } - - for (int i = 0; i < count; i++) { - int mcc = buf.readUnsignedShort(); - int mnc = buf.readUnsignedShort(); - int lac = buf.readUnsignedShort(); - int cid = buf.readUnsignedShort(); - if (i == 0) { - buf.readByte(); // timing advance - } - int rssi = buf.readByte(); - network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi)); - } - - } - - if (report == 0x0202 || report == 0x0203) { - - int count = buf.readUnsignedByte(); - - for (int i = 0; i < count; i++) { - buf.readerIndex(buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0) + 1); // ssid - - String mac = String.format("%02x:%02x:%02x:%02x:%02x:%02x", - buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(), - buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()); - - network.addWifiAccessPoint(WifiAccessPoint.from(mac, buf.readByte())); - } - - } - - position.setNetwork(network); - - sendResponse(channel, remoteAddress, id, index, report); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/SpotProtocol.java b/src/org/traccar/protocol/SpotProtocol.java deleted file mode 100644 index bbf0e8d8a..000000000 --- a/src/org/traccar/protocol/SpotProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SpotProtocol extends BaseProtocol { - - public SpotProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(65535)); - pipeline.addLast(new SpotProtocolDecoder(SpotProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SpotProtocolDecoder.java b/src/org/traccar/protocol/SpotProtocolDecoder.java deleted file mode 100644 index da36c2048..000000000 --- a/src/org/traccar/protocol/SpotProtocolDecoder.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 com.fasterxml.jackson.databind.util.ByteBufferBackedInputStream; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpResponseStatus; -import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateUtil; -import org.traccar.model.Position; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import java.net.SocketAddress; -import java.util.LinkedList; -import java.util.List; - -public class SpotProtocolDecoder extends BaseHttpProtocolDecoder { - - private DocumentBuilder documentBuilder; - private XPath xPath; - private XPathExpression messageExpression; - - public SpotProtocolDecoder(Protocol protocol) { - super(protocol); - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); - builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - builderFactory.setXIncludeAware(false); - builderFactory.setExpandEntityReferences(false); - documentBuilder = builderFactory.newDocumentBuilder(); - xPath = XPathFactory.newInstance().newXPath(); - messageExpression = xPath.compile("//messageList/message"); - } catch (ParserConfigurationException | XPathExpressionException e) { - throw new RuntimeException(e); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - FullHttpRequest request = (FullHttpRequest) msg; - - Document document = documentBuilder.parse(new ByteBufferBackedInputStream(request.content().nioBuffer())); - NodeList nodes = (NodeList) messageExpression.evaluate(document, XPathConstants.NODESET); - - List positions = new LinkedList<>(); - - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, xPath.evaluate("esnName", node)); - if (deviceSession != null) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(true); - position.setTime(DateUtil.parseDate(xPath.evaluate("timestamp", node))); - position.setLatitude(Double.parseDouble(xPath.evaluate("latitude", node))); - position.setLongitude(Double.parseDouble(xPath.evaluate("longitude", node))); - - position.set(Position.KEY_EVENT, xPath.evaluate("messageType", node)); - - positions.add(position); - - } - } - - sendResponse(channel, HttpResponseStatus.OK); - return positions; - } - -} diff --git a/src/org/traccar/protocol/StarLinkProtocol.java b/src/org/traccar/protocol/StarLinkProtocol.java deleted file mode 100644 index 5630722ee..000000000 --- a/src/org/traccar/protocol/StarLinkProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class StarLinkProtocol extends BaseProtocol { - - public StarLinkProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StarLinkProtocolDecoder(StarLinkProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/org/traccar/protocol/StarLinkProtocolDecoder.java deleted file mode 100644 index ed5f81c1c..000000000 --- a/src/org/traccar/protocol/StarLinkProtocolDecoder.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.TimeZone; -import java.util.regex.Pattern; - -public class StarLinkProtocolDecoder extends BaseProtocolDecoder { - - private String[] dataTags; - private DateFormat dateFormat; - - public StarLinkProtocolDecoder(Protocol protocol) { - super(protocol); - - String format = Context.getConfig().getString( - getProtocolName() + ".format", "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#," - + "#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#"); - dataTags = format.split(","); - - dateFormat = new SimpleDateFormat( - Context.getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss")); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression(".") // protocol head - .text("SLU") // message head - .number("(x{6}|d{15}),") // id - .number("(d+),") // type - .number("(d+),") // index - .expression("(.+)") // data - .text("*") - .number("xx") // checksum - .compile(); - - public static final int MSG_EVENT_REPORT = 6; - - private double parseCoordinate(String value) { - int minutesIndex = value.indexOf('.') - 2; - double result = Double.parseDouble(value.substring(1, minutesIndex)); - result += Double.parseDouble(value.substring(minutesIndex)) / 60; - return value.charAt(0) == '+' ? result : -result; - } - - private String decodeAlarm(int event) { - switch (event) { - case 6: - return Position.ALARM_OVERSPEED; - case 7: - return Position.ALARM_GEOFENCE_ENTER; - case 8: - return Position.ALARM_GEOFENCE_EXIT; - case 9: - return Position.ALARM_POWER_CUT; - case 11: - return Position.ALARM_LOW_BATTERY; - case 26: - return Position.ALARM_TOW; - case 36: - return Position.ALARM_SOS; - case 42: - return Position.ALARM_JAMMING; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - int type = parser.nextInt(0); - if (type != MSG_EVENT_REPORT) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); - - position.set(Position.KEY_INDEX, parser.nextInt(0)); - - String[] data = parser.next().split(","); - Integer lac = null, cid = null; - int event = 0; - - for (int i = 0; i < Math.min(data.length, dataTags.length); i++) { - if (data[i].isEmpty()) { - continue; - } - switch (dataTags[i]) { - case "#EDT#": - position.setDeviceTime(dateFormat.parse(data[i])); - break; - case "#EID#": - event = Integer.parseInt(data[i]); - position.set(Position.KEY_ALARM, decodeAlarm(event)); - position.set(Position.KEY_EVENT, event); - break; - case "#PDT#": - position.setFixTime(dateFormat.parse(data[i])); - break; - case "#LAT#": - position.setLatitude(parseCoordinate(data[i])); - break; - case "#LONG#": - position.setLongitude(parseCoordinate(data[i])); - break; - case "#SPD#": - position.setSpeed(Double.parseDouble(data[i])); - break; - case "#HEAD#": - position.setCourse(Integer.parseInt(data[i])); - break; - case "#ODO#": - position.set(Position.KEY_ODOMETER, Long.parseLong(data[i]) * 1000); - break; - case "#IN1#": - position.set(Position.PREFIX_IN + 1, Integer.parseInt(data[i])); - break; - case "#IN2#": - position.set(Position.PREFIX_IN + 2, Integer.parseInt(data[i])); - break; - case "#IN3#": - position.set(Position.PREFIX_IN + 3, Integer.parseInt(data[i])); - break; - case "#IN4#": - position.set(Position.PREFIX_IN + 4, Integer.parseInt(data[i])); - break; - case "#OUT1#": - position.set(Position.PREFIX_OUT + 1, Integer.parseInt(data[i])); - break; - case "#OUT2#": - position.set(Position.PREFIX_OUT + 2, Integer.parseInt(data[i])); - break; - case "#OUT3#": - position.set(Position.PREFIX_OUT + 3, Integer.parseInt(data[i])); - break; - case "#OUT4#": - position.set(Position.PREFIX_OUT + 4, Integer.parseInt(data[i])); - break; - case "#LAC#": - if (!data[i].isEmpty()) { - lac = Integer.parseInt(data[i]); - } - break; - case "#CID#": - if (!data[i].isEmpty()) { - cid = Integer.parseInt(data[i]); - } - break; - case "#VIN#": - position.set(Position.KEY_POWER, Double.parseDouble(data[i])); - break; - case "#VBAT#": - position.set(Position.KEY_BATTERY, Double.parseDouble(data[i])); - break; - case "#DEST#": - position.set("destination", data[i]); - break; - case "#IGN#": - position.set(Position.KEY_IGNITION, data[i].equals("1")); - break; - case "#ENG#": - position.set("engine", data[i].equals("1")); - break; - default: - break; - } - } - - if (position.getFixTime() == null) { - getLastLocation(position, null); - } - - if (lac != null && cid != null) { - position.setNetwork(new Network(CellTower.fromLacCid(lac, cid))); - } - - if (event == 20) { - String rfid = data[data.length - 1]; - if (rfid.matches("0+")) { - rfid = data[data.length - 2]; - } - position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/Stl060FrameDecoder.java b/src/org/traccar/protocol/Stl060FrameDecoder.java deleted file mode 100644 index f72474e2b..000000000 --- a/src/org/traccar/protocol/Stl060FrameDecoder.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.CharacterDelimiterFrameDecoder; - -public class Stl060FrameDecoder extends CharacterDelimiterFrameDecoder { - - public Stl060FrameDecoder(int maxFrameLength) { - super(maxFrameLength, '#'); - } - - @Override - protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) throws Exception { - - ByteBuf result = (ByteBuf) super.decode(ctx, buf); - - if (result != null) { - - int index = result.indexOf(result.readerIndex(), result.writerIndex(), (byte) '$'); - if (index == -1) { - return result; - } else { - result.skipBytes(index); - return result.readRetainedSlice(result.readableBytes()); - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Stl060Protocol.java b/src/org/traccar/protocol/Stl060Protocol.java deleted file mode 100644 index 2711e936b..000000000 --- a/src/org/traccar/protocol/Stl060Protocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Stl060Protocol extends BaseProtocol { - - public Stl060Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Stl060FrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Stl060ProtocolDecoder(Stl060Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Stl060ProtocolDecoder.java b/src/org/traccar/protocol/Stl060ProtocolDecoder.java deleted file mode 100644 index 7b0055aa1..000000000 --- a/src/org/traccar/protocol/Stl060ProtocolDecoder.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Stl060ProtocolDecoder extends BaseProtocolDecoder { - - public Stl060ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .any() - .text("$1,") - .number("(d+),") // imei - .text("D001,") // type - .expression("[^,]*,") // vehicle - .number("(dd)/(dd)/(dd),") // date (dd/mm/yy) - .number("(dd):(dd):(dd),") // time (hh:mm:ss) - .number("(dd)(dd).?(d+)([NS]),") // latitude - .number("(ddd)(dd).?(d+)([EW]),") // longitude - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .groupBegin() - .number("(d+),") // odometer - .number("(d+),") // Ignition - .number("(d+),") // di1 - .number("(d+),") // di2 - .number("(d+),") // fuel - .or() - .expression("([01]),") // charging - .expression("([01]),") // ignition - .expression("0,0,") // reserved - .number("(d+),") // di - .expression("([^,]+),") // rfid - .number("(d+),") // odometer - .number("(d+),") // temperature - .number("(d+),") // fuel - .expression("([01]),") // accelerometer - .expression("([01]),") // do1 - .expression("([01]),") // do2 - .groupEnd() - .expression("([AV])") // validity - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - // Old format - if (parser.hasNext(5)) { - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); - position.set(Position.KEY_INPUT, parser.nextInt(0) + parser.nextInt(0) << 1); - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); - } - - // New format - if (parser.hasNext(10)) { - position.set(Position.KEY_CHARGE, parser.nextInt(0) == 1); - position.set(Position.KEY_IGNITION, parser.nextInt(0) == 1); - position.set(Position.KEY_INPUT, parser.nextInt(0)); - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - position.set(Position.KEY_ODOMETER, parser.nextInt(0)); - position.set(Position.PREFIX_TEMP + 1, parser.nextInt(0)); - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); - position.set(Position.KEY_ACCELERATION, parser.nextInt(0) == 1); - position.set(Position.KEY_OUTPUT, parser.nextInt(0) + parser.nextInt(0) << 1); - } - - position.setValid(parser.next().equals("A")); - - return position; - } - -} diff --git a/src/org/traccar/protocol/SuntechProtocol.java b/src/org/traccar/protocol/SuntechProtocol.java deleted file mode 100644 index 29ae114e7..000000000 --- a/src/org/traccar/protocol/SuntechProtocol.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class SuntechProtocol extends BaseProtocol { - - public SuntechProtocol() { - setSupportedDataCommands( - Command.TYPE_OUTPUT_CONTROL, - Command.TYPE_REBOOT_DEVICE, - Command.TYPE_POSITION_SINGLE, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_ALARM_ARM, - Command.TYPE_ALARM_DISARM); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new SuntechProtocolEncoder()); - pipeline.addLast(new SuntechProtocolDecoder(SuntechProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SuntechProtocolDecoder.java b/src/org/traccar/protocol/SuntechProtocolDecoder.java deleted file mode 100644 index 922431021..000000000 --- a/src/org/traccar/protocol/SuntechProtocolDecoder.java +++ /dev/null @@ -1,467 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.TimeZone; - -public class SuntechProtocolDecoder extends BaseProtocolDecoder { - - private int protocolType; - private boolean hbm; - private boolean includeAdc; - private boolean includeTemp; - - public SuntechProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public void setProtocolType(int protocolType) { - this.protocolType = protocolType; - } - - public int getProtocolType(long deviceId) { - return Context.getIdentityManager().lookupAttributeInteger( - deviceId, getProtocolName() + ".protocolType", protocolType, true); - } - - public void setHbm(boolean hbm) { - this.hbm = hbm; - } - - public boolean isHbm(long deviceId) { - return Context.getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".hbm", hbm, true); - } - - public void setIncludeAdc(boolean includeAdc) { - this.includeAdc = includeAdc; - } - - public boolean isIncludeAdc(long deviceId) { - return Context.getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".includeAdc", includeAdc, true); - } - - public void setIncludeTemp(boolean includeTemp) { - this.includeTemp = includeTemp; - } - - public boolean isIncludeTemp(long deviceId) { - return Context.getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".includeTemp", includeTemp, true); - } - - private Position decode9( - Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException { - int index = 1; - - String type = values[index++]; - - if (!type.equals("Location") && !type.equals("Emergency") && !type.equals("Alert")) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - if (type.equals("Emergency") || type.equals("Alert")) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - - if (!type.equals("Alert") || getProtocolType(deviceSession.getDeviceId()) == 0) { - position.set(Position.KEY_VERSION_FW, values[index++]); - } - - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(values[index++] + values[index++])); - - if (getProtocolType(deviceSession.getDeviceId()) == 1) { - index += 1; // cell - } - - position.setLatitude(Double.parseDouble(values[index++])); - position.setLongitude(Double.parseDouble(values[index++])); - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - position.setCourse(Double.parseDouble(values[index++])); - - position.setValid(values[index++].equals("1")); - - if (getProtocolType(deviceSession.getDeviceId()) == 1) { - position.set(Position.KEY_ODOMETER, Integer.parseInt(values[index++])); - } - - return position; - } - - private String decodeEmergency(int value) { - switch (value) { - case 1: - return Position.ALARM_SOS; - case 2: - return Position.ALARM_PARKING; - case 3: - return Position.ALARM_POWER_CUT; - case 5: - case 6: - return Position.ALARM_DOOR; - case 7: - return Position.ALARM_MOVEMENT; - case 8: - return Position.ALARM_SHOCK; - default: - return null; - } - } - - private String decodeAlert(int value) { - switch (value) { - case 1: - return Position.ALARM_OVERSPEED; - case 5: - return Position.ALARM_GEOFENCE_EXIT; - case 6: - return Position.ALARM_GEOFENCE_ENTER; - case 14: - return Position.ALARM_LOW_BATTERY; - case 15: - return Position.ALARM_SHOCK; - case 16: - return Position.ALARM_ACCIDENT; - case 46: - return Position.ALARM_ACCELERATION; - case 47: - return Position.ALARM_BRAKING; - case 48: - return Position.ALARM_ACCIDENT; - case 50: - return Position.ALARM_JAMMING; - default: - return null; - } - } - private Position decode4( - Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException { - int index = 0; - - String type = values[index++].substring(5); - - if (!type.equals("STT") && !type.equals("ALT")) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.set(Position.KEY_TYPE, type); - - position.set(Position.KEY_VERSION_FW, values[index++]); - index += 1; // model - - Network network = new Network(); - - for (int i = 0; i < 7; i++) { - int cid = Integer.parseInt(values[index++]); - int mcc = Integer.parseInt(values[index++]); - int mnc = Integer.parseInt(values[index++]); - int lac, rssi; - if (i == 0) { - rssi = Integer.parseInt(values[index++]); - lac = Integer.parseInt(values[index++]); - } else { - lac = Integer.parseInt(values[index++]); - rssi = Integer.parseInt(values[index++]); - } - index += 1; // timing advance - if (cid > 0) { - network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi)); - } - } - - position.setNetwork(network); - - position.set(Position.KEY_BATTERY, Double.parseDouble(values[index++])); - position.set(Position.KEY_ARCHIVE, values[index++].equals("0") ? true : null); - position.set(Position.KEY_INDEX, Integer.parseInt(values[index++])); - position.set(Position.KEY_STATUS, Integer.parseInt(values[index++])); - - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(values[index++] + values[index++])); - - position.setLatitude(Double.parseDouble(values[index++])); - position.setLongitude(Double.parseDouble(values[index++])); - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - position.setCourse(Double.parseDouble(values[index++])); - - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); - - position.setValid(values[index++].equals("1")); - - return position; - } - - private Position decode2356( - Channel channel, SocketAddress remoteAddress, String protocol, String[] values) throws ParseException { - int index = 0; - - String type = values[index++].substring(5); - - if (!type.equals("STT") && !type.equals("EMG") && !type.equals("EVT") && !type.equals("ALT")) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.set(Position.KEY_TYPE, type); - - if (protocol.equals("ST300") || protocol.equals("ST500") || protocol.equals("ST600")) { - index += 1; // model - } - - position.set(Position.KEY_VERSION_FW, values[index++]); - - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(values[index++] + values[index++])); - - if (!protocol.equals("ST500")) { - long cid = Long.parseLong(values[index++], 16); - if (protocol.equals("ST600")) { - position.setNetwork(new Network(CellTower.from( - Integer.parseInt(values[index++]), Integer.parseInt(values[index++]), - Integer.parseInt(values[index++], 16), cid, Integer.parseInt(values[index++])))); - } - } - - position.setLatitude(Double.parseDouble(values[index++])); - position.setLongitude(Double.parseDouble(values[index++])); - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - position.setCourse(Double.parseDouble(values[index++])); - - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); - - position.setValid(values[index++].equals("1")); - - position.set(Position.KEY_ODOMETER, Integer.parseInt(values[index++])); - position.set(Position.KEY_POWER, Double.parseDouble(values[index++])); - - String io = values[index++]; - if (io.length() == 6) { - position.set(Position.KEY_IGNITION, io.charAt(0) == '1'); - position.set(Position.PREFIX_IN + 1, io.charAt(1) == '1'); - position.set(Position.PREFIX_IN + 2, io.charAt(2) == '1'); - position.set(Position.PREFIX_IN + 3, io.charAt(3) == '1'); - position.set(Position.PREFIX_OUT + 1, io.charAt(4) == '1'); - position.set(Position.PREFIX_OUT + 2, io.charAt(5) == '1'); - } - - switch (type) { - case "STT": - position.set(Position.KEY_STATUS, Integer.parseInt(values[index++])); - position.set(Position.KEY_INDEX, Integer.parseInt(values[index++])); - break; - case "EMG": - position.set(Position.KEY_ALARM, decodeEmergency(Integer.parseInt(values[index++]))); - break; - case "EVT": - position.set(Position.KEY_EVENT, Integer.parseInt(values[index++])); - break; - case "ALT": - position.set(Position.KEY_ALARM, decodeAlert(Integer.parseInt(values[index++]))); - break; - default: - break; - } - - if (isHbm(deviceSession.getDeviceId())) { - - if (index < values.length) { - position.set(Position.KEY_HOURS, UnitsConverter.msFromMinutes(Integer.parseInt(values[index++]))); - } - - if (index < values.length) { - position.set(Position.KEY_BATTERY, Double.parseDouble(values[index++])); - } - - if (index < values.length && values[index++].equals("0")) { - position.set(Position.KEY_ARCHIVE, true); - } - - if (isIncludeAdc(deviceSession.getDeviceId())) { - for (int i = 1; i <= 3; i++) { - if (!values[index++].isEmpty()) { - position.set(Position.PREFIX_ADC + i, Double.parseDouble(values[index - 1])); - } - } - } - - if (values.length - index >= 2) { - String driverUniqueId = values[index++]; - if (values[index++].equals("1") && !driverUniqueId.isEmpty()) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId); - } - } - - if (isIncludeTemp(deviceSession.getDeviceId())) { - for (int i = 1; i <= 3; i++) { - String temperature = values[index++]; - String value = temperature.substring(temperature.indexOf(':') + 1); - if (!value.isEmpty()) { - position.set(Position.PREFIX_TEMP + i, Double.parseDouble(value)); - } - } - - } - - } - - return position; - } - - private Position decodeUniversal( - Channel channel, SocketAddress remoteAddress, String[] values) throws ParseException { - int index = 0; - - String type = values[index++]; - - if (!type.equals("STT")) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - position.set(Position.KEY_TYPE, type); - - int mask = Integer.parseInt(values[index++], 16); - - if (BitUtil.check(mask, 1)) { - index += 1; // model - } - - if (BitUtil.check(mask, 2)) { - position.set(Position.KEY_VERSION_FW, values[index++]); - } - - if (BitUtil.check(mask, 3) && values[index++].equals("0")) { - position.set(Position.KEY_ARCHIVE, true); - } - - if (BitUtil.check(mask, 4) && BitUtil.check(mask, 5)) { - DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(values[index++] + values[index++])); - } - - if (BitUtil.check(mask, 6)) { - index += 1; // cell - } - - if (BitUtil.check(mask, 7)) { - index += 1; // mcc - } - - if (BitUtil.check(mask, 8)) { - index += 1; // mnc - } - - if (BitUtil.check(mask, 9)) { - index += 1; // lac - } - - if (BitUtil.check(mask, 10)) { - position.set(Position.KEY_RSSI, Integer.parseInt(values[index++])); - } - - if (BitUtil.check(mask, 11)) { - position.setLatitude(Double.parseDouble(values[index++])); - } - - if (BitUtil.check(mask, 12)) { - position.setLongitude(Double.parseDouble(values[index++])); - } - - if (BitUtil.check(mask, 13)) { - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++]))); - } - - if (BitUtil.check(mask, 14)) { - position.setCourse(Double.parseDouble(values[index++])); - } - - if (BitUtil.check(mask, 15)) { - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++])); - } - - if (BitUtil.check(mask, 16)) { - position.setValid(values[index++].equals("1")); - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String[] values = ((String) msg).split(";"); - - if (values[0].length() < 5) { - return decodeUniversal(channel, remoteAddress, values); - } else if (values[0].startsWith("ST9")) { - return decode9(channel, remoteAddress, values); - } else if (values[0].startsWith("ST4")) { - return decode4(channel, remoteAddress, values); - } else { - return decode2356(channel, remoteAddress, values[0].substring(0, 5), values); - } - } - -} diff --git a/src/org/traccar/protocol/SuntechProtocolEncoder.java b/src/org/traccar/protocol/SuntechProtocolEncoder.java deleted file mode 100644 index 90fa4aa39..000000000 --- a/src/org/traccar/protocol/SuntechProtocolEncoder.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class SuntechProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "SA200CMD;{%s};02;Reboot\r", Command.KEY_UNIQUE_ID); - case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "SA200GTR;{%s};02;\r", Command.KEY_UNIQUE_ID); - case Command.TYPE_OUTPUT_CONTROL: - if (command.getAttributes().containsKey(Command.KEY_DATA)) { - if (command.getAttributes().get(Command.KEY_DATA).equals("1")) { - return formatCommand(command, "SA200CMD;{%s};02;Enable{%s}\r", - Command.KEY_UNIQUE_ID, Command.KEY_INDEX); - } else { - return formatCommand(command, "SA200CMD;{%s};02;Disable{%s}\r", - Command.KEY_UNIQUE_ID, Command.KEY_INDEX); - } - } - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "SA200CMD;{%s};02;Enable1\r", Command.KEY_UNIQUE_ID); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "SA200CMD;{%s};02;Disable1\r", Command.KEY_UNIQUE_ID); - case Command.TYPE_ALARM_ARM: - return formatCommand(command, "SA200CMD;{%s};02;Enable2\r", Command.KEY_UNIQUE_ID); - case Command.TYPE_ALARM_DISARM: - return formatCommand(command, "SA200CMD;{%s};02;Disable2\r", Command.KEY_UNIQUE_ID); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/SupermateProtocol.java b/src/org/traccar/protocol/SupermateProtocol.java deleted file mode 100644 index 46625ddc7..000000000 --- a/src/org/traccar/protocol/SupermateProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class SupermateProtocol extends BaseProtocol { - - public SupermateProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "#")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new SupermateProtocolDecoder(SupermateProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SupermateProtocolDecoder.java b/src/org/traccar/protocol/SupermateProtocolDecoder.java deleted file mode 100644 index 40a25bb91..000000000 --- a/src/org/traccar/protocol/SupermateProtocolDecoder.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Calendar; -import java.util.regex.Pattern; - -public class SupermateProtocolDecoder extends BaseProtocolDecoder { - - public SupermateProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("d+:") // header - .number("(d+):") // imei - .number("d+:").text("*,") - .number("(d+),") // command id - .expression("([^,]{2}),") // command - .expression("([AV]),") // validity - .number("(xx)(xx)(xx),") // date (yymmdd) - .number("(xx)(xx)(xx),") // time (hhmmss) - .number("(x)(x{7}),") // latitude - .number("(x)(x{7}),") // longitude - .number("(x{4}),") // speed - .number("(x{4}),") // course - .number("(x{12}),") // status - .number("(x+),") // signal - .number("(d+),") // power - .number("(x{4}),") // oil - .number("(x+)?") // odometer - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - String imei = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set("commandId", parser.next()); - position.set(Position.KEY_COMMAND, parser.next()); - - position.setValid(parser.next().equals("A")); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(parser.nextHexInt(0), parser.nextHexInt(0), parser.nextHexInt(0)) - .setTime(parser.nextHexInt(0), parser.nextHexInt(0), parser.nextHexInt(0)); - position.setTime(dateBuilder.getDate()); - - if (parser.nextHexInt(0) == 8) { - position.setLatitude(-parser.nextHexInt(0) / 600000.0); - } else { - position.setLatitude(parser.nextHexInt(0) / 600000.0); - } - - if (parser.nextHexInt(0) == 8) { - position.setLongitude(-parser.nextHexInt(0) / 600000.0); - } else { - position.setLongitude(parser.nextHexInt(0) / 600000.0); - } - - position.setSpeed(parser.nextHexInt(0) / 100.0); - position.setCourse(parser.nextHexInt(0) / 100.0); - - position.set(Position.KEY_STATUS, parser.next()); - position.set("signal", parser.next()); - position.set(Position.KEY_POWER, parser.nextDouble(0)); - position.set("oil", parser.nextHexInt(0)); - position.set(Position.KEY_ODOMETER, parser.nextHexInt(0)); - - if (channel != null) { - Calendar calendar = Calendar.getInstance(); - String content = String.format("#1:%s:1:*,00000000,UP,%02x%02x%02x,%02x%02x%02x#", imei, - calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH), - calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND)); - channel.writeAndFlush(new NetworkMessage( - Unpooled.copiedBuffer(content, StandardCharsets.US_ASCII), remoteAddress)); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/SviasProtocol.java b/src/org/traccar/protocol/SviasProtocol.java deleted file mode 100644 index c6624b7d4..000000000 --- a/src/org/traccar/protocol/SviasProtocol.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import org.traccar.model.Command; - -public class SviasProtocol extends BaseProtocol { - - public SviasProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_POSITION_SINGLE, - Command.TYPE_SET_ODOMETER, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_ALARM_ARM, - Command.TYPE_ALARM_DISARM, - Command.TYPE_ALARM_REMOVE); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "]")); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new SviasProtocolEncoder()); - pipeline.addLast(new SviasProtocolDecoder(SviasProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/SviasProtocolDecoder.java b/src/org/traccar/protocol/SviasProtocolDecoder.java deleted file mode 100644 index 978483175..000000000 --- a/src/org/traccar/protocol/SviasProtocolDecoder.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.PatternBuilder; - -import java.net.SocketAddress; -import java.util.regex.Pattern; -import org.traccar.DeviceSession; -import org.traccar.helper.Parser; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -public class SviasProtocolDecoder extends BaseProtocolDecoder { - - public SviasProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("[") // delimiter - .number("d{4},") // hardware version - .number("d{4},") // software version - .number("d+,") // index - .number("(d+),") // imei - .number("d+,") // hour meter - .number("(d+)(dd)(dd),") // date (dmmyy) - .number("(d+)(dd)(dd),") // time (hmmss) - .number("(-?)(d+)(dd)(d{5}),") // latitude - .number("(-?)(d+)(dd)(d{5}),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+),") // odometer - .number("(d+),") // input - .number("(d+),") // output / status - .number("(d),") - .number("(d),") - .number("(d+),") // power - .number("(d+),") // battery level - .number("(d+),") // rssi - .any() - .compile(); - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) - throws Exception { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("@", remoteAddress)); - } - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN_MIN)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble() * 0.01)); - position.setCourse(parser.nextDouble() * 0.01); - - position.set(Position.KEY_ODOMETER, parser.nextInt() * 100); - - int input = parser.nextInt(); - int output = parser.nextInt(); - - position.set(Position.KEY_ALARM, BitUtil.check(input, 0) ? Position.ALARM_SOS : null); - position.set(Position.KEY_IGNITION, BitUtil.check(input, 4)); - position.setValid(BitUtil.check(output, 0)); - - position.set(Position.KEY_POWER, parser.nextInt() * 0.001); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); - position.set(Position.KEY_RSSI, parser.nextInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/SviasProtocolEncoder.java b/src/org/traccar/protocol/SviasProtocolEncoder.java deleted file mode 100644 index 9fce57223..000000000 --- a/src/org/traccar/protocol/SviasProtocolEncoder.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class SviasProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatCommand(command, "{%s}", Command.KEY_DATA); - case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "AT+STR=1*"); - case Command.TYPE_SET_ODOMETER: - return formatCommand(command, "AT+ODT={%s}*", Command.KEY_DATA); - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "AT+OUT=1,1*"); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "AT+OUT=1,0*"); - case Command.TYPE_ALARM_ARM: - return formatCommand(command, "AT+OUT=2,1*"); - case Command.TYPE_ALARM_DISARM: - return formatCommand(command, "AT+OUT=2,0*"); - case Command.TYPE_ALARM_REMOVE: - return formatCommand(command, "AT+PNC=600*"); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/T55Protocol.java b/src/org/traccar/protocol/T55Protocol.java deleted file mode 100644 index f5ec19094..000000000 --- a/src/org/traccar/protocol/T55Protocol.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class T55Protocol extends BaseProtocol { - - public T55Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new T55ProtocolDecoder(T55Protocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new T55ProtocolDecoder(T55Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/T55ProtocolDecoder.java b/src/org/traccar/protocol/T55ProtocolDecoder.java deleted file mode 100644 index ba231a635..000000000 --- a/src/org/traccar/protocol/T55ProtocolDecoder.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.channels.DatagramChannel; -import java.util.Date; -import java.util.regex.Pattern; - -public class T55ProtocolDecoder extends BaseProtocolDecoder { - - public T55ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_GPRMC = new PatternBuilder() - .text("$GPRMC,") - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d{2,3})(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd),") // date (ddmmyy) - .expression("[^*]+") - .text("*") - .expression("[^,]+") - .number(",(d+)") // satellites - .number(",(d+)") // imei - .expression(",([01])") // ignition - .number(",(d+)") // fuel - .number(",(d+)").optional(7) // battery - .number("((?:,d+)+)?") // parameters - .any() - .compile(); - - private static final Pattern PATTERN_GPGGA = new PatternBuilder() - .text("$GPGGA,") - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .expression("([EW]),") - .any() - .compile(); - - private static final Pattern PATTERN_GPRMA = new PatternBuilder() - .text("$GPRMA,") - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),,,") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .any() - .compile(); - - private static final Pattern PATTERN_TRCCR = new PatternBuilder() - .text("$TRCCR,") - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd).?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(d+.d+),") // speed - .number("(d+.d+),") // course - .number("(-?d+.d+),") // altitude - .number("(d+.?d*),") // battery - .any() - .compile(); - - private Position position = null; - - private Position decodeGprmc( - DeviceSession deviceSession, String sentence, SocketAddress remoteAddress, Channel channel) { - - if (deviceSession != null && channel != null && !(channel instanceof DatagramChannel) - && Context.getIdentityManager().lookupAttributeBoolean( - deviceSession.getDeviceId(), getProtocolName() + ".ack", false, true)) { - channel.writeAndFlush(new NetworkMessage("OK1\r\n", remoteAddress)); - } - - Parser parser = new Parser(PATTERN_GPRMC, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - if (deviceSession != null) { - position.setDeviceId(deviceSession.getDeviceId()); - } - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - if (parser.hasNext(5)) { - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_IGNITION, parser.hasNext() && parser.next().equals("1")); - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt(0)); - position.set(Position.KEY_BATTERY, parser.nextInt()); - } - - if (parser.hasNext()) { - String[] parameters = parser.next().split(","); - for (int i = 1; i < parameters.length; i++) { - position.set(Position.PREFIX_IO + i, parameters[i]); - } - } - - if (deviceSession != null) { - return position; - } else { - this.position = position; // save position - return null; - } - } - - private Position decodeGpgga(DeviceSession deviceSession, String sentence) { - - Parser parser = new Parser(PATTERN_GPGGA, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setCurrentDate() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - return position; - } - - private Position decodeGprma(DeviceSession deviceSession, String sentence) { - - Parser parser = new Parser(PATTERN_GPRMA, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date()); - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - return position; - } - - private Position decodeTrccr(DeviceSession deviceSession, String sentence) { - - Parser parser = new Parser(PATTERN_TRCCR, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - position.set(Position.KEY_BATTERY, parser.nextDouble(0)); - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - DeviceSession deviceSession; - - if (!sentence.startsWith("$") && sentence.contains("$")) { - int index = sentence.indexOf("$"); - String id = sentence.substring(0, index); - if (id.endsWith(",")) { - id = id.substring(0, id.length() - 1); - } else if (id.endsWith("/")) { - id = id.substring(id.indexOf('/') + 1, id.length() - 1); - } - deviceSession = getDeviceSession(channel, remoteAddress, id); - sentence = sentence.substring(index); - } else { - deviceSession = getDeviceSession(channel, remoteAddress); - } - - if (sentence.startsWith("$PGID")) { - getDeviceSession(channel, remoteAddress, sentence.substring(6, sentence.length() - 3)); - } else if (sentence.startsWith("$DEVID")) { - getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.lastIndexOf('*'))); - } else if (sentence.startsWith("$PCPTI")) { - getDeviceSession(channel, remoteAddress, sentence.substring(7, sentence.indexOf(",", 7))); - } else if (sentence.startsWith("IMEI")) { - getDeviceSession(channel, remoteAddress, sentence.substring(5)); - } else if (sentence.startsWith("$IMEI")) { - getDeviceSession(channel, remoteAddress, sentence.substring(6)); - } else if (sentence.startsWith("$GPFID")) { - deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(7)); - if (deviceSession != null && position != null) { - Position position = this.position; - position.setDeviceId(deviceSession.getDeviceId()); - this.position = null; - return position; - } - } else if (sentence.matches("^[0-9A-F]+$")) { - getDeviceSession(channel, remoteAddress, sentence); - } else if (sentence.startsWith("$GPRMC")) { - return decodeGprmc(deviceSession, sentence, remoteAddress, channel); - } else if (sentence.startsWith("$GPGGA") && deviceSession != null) { - return decodeGpgga(deviceSession, sentence); - } else if (sentence.startsWith("$GPRMA") && deviceSession != null) { - return decodeGprma(deviceSession, sentence); - } else if (sentence.startsWith("$TRCCR") && deviceSession != null) { - return decodeTrccr(deviceSession, sentence); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/T57FrameDecoder.java b/src/org/traccar/protocol/T57FrameDecoder.java deleted file mode 100644 index 14ba31453..000000000 --- a/src/org/traccar/protocol/T57FrameDecoder.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -import java.nio.charset.StandardCharsets; - -public class T57FrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 10) { - return null; - } - - String type = buf.toString(buf.readerIndex() + 5, 2, StandardCharsets.US_ASCII); - int count = type.equals("F3") ? 12 : 14; - - int index = 0; - while (index >= 0 && count > 0) { - index = buf.indexOf(index + 1, buf.writerIndex(), (byte) '#'); - if (index > 0) { - count -= 1; - } - } - - return index > 0 ? buf.readRetainedSlice(index + 1 - buf.readerIndex()) : null; - } - -} diff --git a/src/org/traccar/protocol/T57Protocol.java b/src/org/traccar/protocol/T57Protocol.java deleted file mode 100644 index f67f82318..000000000 --- a/src/org/traccar/protocol/T57Protocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class T57Protocol extends BaseProtocol { - - public T57Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new T57FrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new T57ProtocolDecoder(T57Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/T57ProtocolDecoder.java b/src/org/traccar/protocol/T57ProtocolDecoder.java deleted file mode 100644 index 2a3cca3e4..000000000 --- a/src/org/traccar/protocol/T57ProtocolDecoder.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class T57ProtocolDecoder extends BaseProtocolDecoder { - - public T57ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("*T57#") - .number("Fd#") // type - .number("([^#]+)#") // device id - .number("(dd)(dd)(dd)#") // date (ddmmyy) - .number("(dd)(dd)(dd)#") // time (hhmmss) - .number("(dd)(dd.d+)#") // latitude - .expression("([NS])#") - .number("(ddd)(dd.d+)#") // longitude - .expression("([EW])#") - .expression("[^#]+#") - .number("(d+.d+)#") // speed - .number("(d+.d+)#") // altitude - .expression("([AV])") // valid - .number("d#") // fix type - .number("(d+.d+)#") // battery - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble()); - position.setAltitude(parser.nextDouble()); - - position.setValid(parser.next().equals("A")); - - position.set(Position.KEY_BATTERY, parser.nextDouble()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/T800xProtocol.java b/src/org/traccar/protocol/T800xProtocol.java deleted file mode 100644 index 85749d0cf..000000000 --- a/src/org/traccar/protocol/T800xProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class T800xProtocol extends BaseProtocol { - - public T800xProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2, -5, 0)); - pipeline.addLast(new T800xProtocolEncoder()); - pipeline.addLast(new T800xProtocolDecoder(T800xProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/T800xProtocolDecoder.java b/src/org/traccar/protocol/T800xProtocolDecoder.java deleted file mode 100644 index dfb286257..000000000 --- a/src/org/traccar/protocol/T800xProtocolDecoder.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BcdUtil; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class T800xProtocolDecoder extends BaseProtocolDecoder { - - public T800xProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_LOGIN = 0x01; - public static final int MSG_GPS = 0x02; - public static final int MSG_HEARTBEAT = 0x03; - public static final int MSG_ALARM = 0x04; - public static final int MSG_COMMAND = 0x81; - - private void sendResponse(Channel channel, short header, int type, int index, ByteBuf imei) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(15); - response.writeShort(header); - response.writeByte(type); - response.writeShort(response.capacity()); // length - response.writeShort(index); - response.writeBytes(imei); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - private String decodeAlarm(short value) { - switch (value) { - case 1: - return Position.ALARM_POWER_CUT; - case 2: - return Position.ALARM_LOW_BATTERY; - case 3: - return Position.ALARM_SOS; - case 4: - return Position.ALARM_OVERSPEED; - case 5: - return Position.ALARM_GEOFENCE_ENTER; - case 6: - return Position.ALARM_GEOFENCE_EXIT; - case 7: - return Position.ALARM_TOW; - case 8: - case 10: - return Position.ALARM_VIBRATION; - case 21: - return Position.ALARM_JAMMING; - case 23: - return Position.ALARM_POWER_RESTORED; - case 24: - return Position.ALARM_LOW_POWER; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - short header = buf.readShort(); - int type = buf.readUnsignedByte(); - buf.readUnsignedShort(); // length - int index = buf.readUnsignedShort(); - ByteBuf imei = buf.readSlice(8); - - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, ByteBufUtil.hexDump(imei).substring(1)); - if (deviceSession == null) { - return null; - } - - sendResponse(channel, header, type, index, imei); - - if (type == MSG_GPS || type == MSG_ALARM) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_INDEX, index); - - buf.readUnsignedShort(); // acc on interval - buf.readUnsignedShort(); // acc off interval - buf.readUnsignedByte(); // angle compensation - buf.readUnsignedShort(); // distance compensation - - position.set(Position.KEY_RSSI, BitUtil.to(buf.readUnsignedShort(), 7)); - - int status = buf.readUnsignedByte(); - position.set(Position.KEY_SATELLITES, BitUtil.to(status, 5)); - - buf.readUnsignedByte(); // gsensor manager status - buf.readUnsignedByte(); // other flags - buf.readUnsignedByte(); // heartbeat - buf.readUnsignedByte(); // relay status - buf.readUnsignedShort(); // drag alarm setting - - int io = buf.readUnsignedShort(); - position.set(Position.KEY_IGNITION, BitUtil.check(io, 14)); - position.set("ac", BitUtil.check(io, 13)); - - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); - - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); - - buf.readUnsignedByte(); // reserved - - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - - int battery = BcdUtil.readInteger(buf, 2); - if (battery == 0) { - battery = 100; - } - position.set(Position.KEY_BATTERY, battery); - - DateBuilder dateBuilder = new DateBuilder() - .setYear(BcdUtil.readInteger(buf, 2)) - .setMonth(BcdUtil.readInteger(buf, 2)) - .setDay(BcdUtil.readInteger(buf, 2)) - .setHour(BcdUtil.readInteger(buf, 2)) - .setMinute(BcdUtil.readInteger(buf, 2)) - .setSecond(BcdUtil.readInteger(buf, 2)); - - if (BitUtil.check(status, 6)) { - - position.setValid(!BitUtil.check(status, 7)); - position.setTime(dateBuilder.getDate()); - position.setAltitude(buf.readFloatLE()); - position.setLongitude(buf.readFloatLE()); - position.setLatitude(buf.readFloatLE()); - position.setSpeed(UnitsConverter.knotsFromKph(BcdUtil.readInteger(buf, 4) * 0.1)); - position.setCourse(buf.readUnsignedShort()); - - } else { - - getLastLocation(position, dateBuilder.getDate()); - - int mcc = buf.readUnsignedShortLE(); - int mnc = buf.readUnsignedShortLE(); - - if (mcc != 0xffff && mnc != 0xffff) { - Network network = new Network(); - for (int i = 0; i < 3; i++) { - network.addCellTower(CellTower.from( - mcc, mnc, buf.readUnsignedShortLE(), buf.readUnsignedShortLE())); - } - position.setNetwork(network); - } - - } - - if (buf.readableBytes() >= 2) { - position.set(Position.KEY_POWER, BcdUtil.readInteger(buf, 4) * 0.01); - } - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/T800xProtocolEncoder.java b/src/org/traccar/protocol/T800xProtocolEncoder.java deleted file mode 100644 index 1d0f3dabe..000000000 --- a/src/org/traccar/protocol/T800xProtocolEncoder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.traccar.BaseProtocolEncoder; -import org.traccar.helper.DataConverter; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class T800xProtocolEncoder extends BaseProtocolEncoder { - - public static final int MODE_SETTING = 0x01; - public static final int MODE_BROADCAST = 0x02; - public static final int MODE_FORWARD = 0x03; - - private ByteBuf encodeContent(Command command, String content) { - - ByteBuf buf = Unpooled.buffer(); - - buf.writeByte('#'); - buf.writeByte('#'); - buf.writeByte(T800xProtocolDecoder.MSG_COMMAND); - buf.writeShort(7 + 8 + 1 + content.length()); - buf.writeShort(1); // serial number - buf.writeBytes(DataConverter.parseHex("0" + getUniqueId(command.getDeviceId()))); - buf.writeByte(MODE_SETTING); - buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return encodeContent(command, command.getString(Command.KEY_DATA)); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/TaipProtocol.java b/src/org/traccar/protocol/TaipProtocol.java deleted file mode 100644 index b8f40a183..000000000 --- a/src/org/traccar/protocol/TaipProtocol.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TaipProtocol extends BaseProtocol { - - public TaipProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '<')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TaipProtocolDecoder.java b/src/org/traccar/protocol/TaipProtocolDecoder.java deleted file mode 100644 index 8a0cb870b..000000000 --- a/src/org/traccar/protocol/TaipProtocolDecoder.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -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.DateBuilder; -import org.traccar.helper.DateUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.regex.Pattern; - -public class TaipProtocolDecoder extends BaseProtocolDecoder { - - public TaipProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .groupBegin() - .expression("R[EP]V") // type - .groupBegin() - .number("(dd)") // event - .number("(dddd)") // week - .number("(d)") // day - .groupEnd("?") - .number("(d{5})") // seconds - .or() - .expression("(?:RGP|RCQ|RCV|RBR)") // type - .number("(dd)?") // event - .number("(dd)(dd)(dd)") // date (mmddyy) - .number("(dd)(dd)(dd)") // time (hhmmss) - .groupEnd() - .groupBegin() - .number("([-+]dd)(d{5})") // latitude - .number("([-+]ddd)(d{5})") // longitude - .or() - .number("([-+])(dd)(dd.dddd)") // latitude - .number("([-+])(ddd)(dd.dddd)") // longitude - .groupEnd() - .number("(ddd)") // speed - .number("(ddd)") // course - .groupBegin() - .number("([023])") // fix mode - .number("xx") // data age - .number("(xx)") // input - .number("(dd)") // event - .number("(dd)") // hdop - .or() - .groupBegin() - .number("(xx)") // input - .number("(xx)") // satellites - .number("(ddd)") // battery - .number("(x{8})") // odometer - .number("[01]") // gps power - .groupBegin() - .number("([023])") // fix mode - .number("(dd)") // pdop - .number("dd") // satellites - .number("xxxx") // data age - .number("[01]") // modem power - .number("[0-5]") // gsm status - .number("(dd)") // rssi - .number("([-+]dddd)") // temperature 1 - .number("xx") // seconds from last - .number("([-+]dddd)") // temperature 2 - .number("xx") // seconds from last - .groupEnd("?") - .groupEnd("?") - .groupEnd() - .any() - .compile(); - - private Date getTime(long week, long day, long seconds) { - DateBuilder dateBuilder = new DateBuilder() - .setDate(1980, 1, 6) - .addMillis(((week * 7 + day) * 24 * 60 * 60 + seconds) * 1000); - return dateBuilder.getDate(); - } - - private Date getTime(long seconds) { - DateBuilder dateBuilder = new DateBuilder(new Date()) - .setTime(0, 0, 0, 0) - .addMillis(seconds * 1000); - return DateUtil.correctDay(dateBuilder.getDate()); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - int beginIndex = sentence.indexOf('>'); - if (beginIndex != -1) { - sentence = sentence.substring(beginIndex + 1); - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - Boolean valid = null; - Integer event = null; - - if (parser.hasNext(3)) { - event = parser.nextInt(); - position.setTime(getTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0))); - } else if (parser.hasNext()) { - position.setTime(getTime(parser.nextInt(0))); - } - - if (parser.hasNext()) { - event = parser.nextInt(); - } - - if (parser.hasNext(6)) { - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - } - - if (parser.hasNext(4)) { - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG)); - } - if (parser.hasNext(6)) { - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - } - - position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - if (parser.hasNext(4)) { - valid = parser.nextInt() > 0; - int input = parser.nextHexInt(); - position.set(Position.KEY_IGNITION, BitUtil.check(input, 7)); - position.set(Position.KEY_INPUT, input); - event = parser.nextInt(); - position.set(Position.KEY_HDOP, parser.nextInt()); - } - - if (parser.hasNext(4)) { - position.set(Position.KEY_INPUT, parser.nextHexInt(0)); - position.set(Position.KEY_SATELLITES, parser.nextHexInt(0)); - position.set(Position.KEY_BATTERY, parser.nextInt(0)); - position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0)); - } - - if (parser.hasNext(4)) { - valid = parser.nextInt() > 0; - position.set(Position.KEY_PDOP, parser.nextInt()); - position.set(Position.KEY_RSSI, parser.nextInt()); - position.set(Position.PREFIX_TEMP + 1, parser.nextInt() * 0.01); - position.set(Position.PREFIX_TEMP + 2, parser.nextInt() * 0.01); - } - - position.setValid(valid == null || valid); - - if (event != null) { - position.set(Position.KEY_EVENT, event); - switch (event) { - case 22: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 23: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 24: - position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); - break; - case 26: - case 28: - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - break; - default: - break; - } - } - - String[] attributes = null; - beginIndex = sentence.indexOf(';'); - if (beginIndex != -1) { - int endIndex = sentence.indexOf('<', beginIndex); - if (endIndex == -1) { - endIndex = sentence.length(); - } - attributes = sentence.substring(beginIndex, endIndex).split(";"); - } - - return decodeAttributes(channel, remoteAddress, position, attributes); - } - - private Position decodeAttributes( - Channel channel, SocketAddress remoteAddress, Position position, String[] attributes) { - - String uniqueId = null; - DeviceSession deviceSession = null; - String messageIndex = null; - - if (attributes != null) { - for (String attribute : attributes) { - int index = attribute.indexOf('='); - if (index != -1) { - String key = attribute.substring(0, index).toLowerCase(); - String value = attribute.substring(index + 1); - switch (key) { - case "id": - uniqueId = value; - deviceSession = getDeviceSession(channel, remoteAddress, value); - if (deviceSession != null) { - position.setDeviceId(deviceSession.getDeviceId()); - } - break; - case "io": - position.set(Position.KEY_IGNITION, BitUtil.check(value.charAt(0) - '0', 0)); - position.set(Position.KEY_CHARGE, BitUtil.check(value.charAt(0) - '0', 1)); - position.set(Position.KEY_OUTPUT, value.charAt(1) - '0'); - position.set(Position.KEY_INPUT, value.charAt(2) - '0'); - break; - case "ix": - position.set(Position.PREFIX_IO + 1, value); - break; - case "ad": - position.set(Position.PREFIX_ADC + 1, Integer.parseInt(value)); - break; - case "sv": - position.set(Position.KEY_SATELLITES, Integer.parseInt(value)); - break; - case "bl": - position.set(Position.KEY_BATTERY, Integer.parseInt(value) * 0.001); - break; - case "vo": - position.set(Position.KEY_ODOMETER, Long.parseLong(value)); - break; - default: - position.set(key, value); - break; - } - } else if (attribute.startsWith("#")) { - messageIndex = attribute; - } - } - } - - if (deviceSession != null) { - if (channel != null) { - if (messageIndex != null) { - String response = ">ACK;ID=" + uniqueId + ";" + messageIndex + ";*"; - response += String.format("%02X", Checksum.xor(response)) + "<"; - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } else { - channel.writeAndFlush(new NetworkMessage(uniqueId, remoteAddress)); - } - } - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TekFrameDecoder.java b/src/org/traccar/protocol/TekFrameDecoder.java deleted file mode 100644 index 44d2c590e..000000000 --- a/src/org/traccar/protocol/TekFrameDecoder.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; -import org.traccar.helper.BitUtil; - -public class TekFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 17) { - return null; - } - - int length = 17 + buf.getUnsignedByte(16) + (BitUtil.from(buf.getUnsignedByte(15), 6) << 6); - if (buf.readableBytes() >= length) { - return buf.readBytes(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TekProtocol.java b/src/org/traccar/protocol/TekProtocol.java deleted file mode 100644 index c1d78e6f5..000000000 --- a/src/org/traccar/protocol/TekProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TekProtocol extends BaseProtocol { - - public TekProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TekFrameDecoder()); - pipeline.addLast(new TekProtocolDecoder(TekProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TekProtocolDecoder.java b/src/org/traccar/protocol/TekProtocolDecoder.java deleted file mode 100644 index a9101e65f..000000000 --- a/src/org/traccar/protocol/TekProtocolDecoder.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -public class TekProtocolDecoder extends BaseProtocolDecoder { - - public TekProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number(",d+,") - .number("(dd)(dd)(dd).d,") // time (hhmmss) - .number("(dd)(dd.d+)") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+)") // longitude - .expression("([EW]),") - .number("(d+.d+),") // hdop - .number("(d+.d+),") // altitude - .number("(d+),") // fix mode - .number("(d+.d+),") // course - .number("d+.d+,") // speed km - .number("(d+.d+),") // speed kn - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(d+),") // satellites - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedByte(); // product type - buf.readUnsignedByte(); // hardware version - buf.readUnsignedByte(); // firmware version - buf.readUnsignedByte(); // contact reason - buf.readUnsignedByte(); // alarm / status - buf.readUnsignedByte(); // rssi - buf.readUnsignedByte(); // battery / status - - String imei = ByteBufUtil.hexDump(buf.readBytes(8)).substring(1); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - int type = BitUtil.to(buf.readUnsignedByte(), 6); - buf.readUnsignedByte(); // length - - if (type == 4 || type == 8) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - int count = buf.readUnsignedShort(); - buf.readUnsignedByte(); // hours / tickets - buf.readUnsignedByte(); // error code - buf.readUnsignedByte(); // reserved - buf.readUnsignedByte(); // logger speed - buf.readUnsignedByte(); // login time - buf.readUnsignedByte(); // minutes - - for (int i = 0; i < count; i++) { - position.set("rssi" + (i + 1), buf.readUnsignedByte()); - position.set("temp" + (i + 1), buf.readUnsignedByte() - 30); - int data = buf.readUnsignedShort(); - position.set("src" + (i + 1), BitUtil.from(data, 10)); - position.set("ullage" + (i + 1), BitUtil.to(data, 10)); - } - - return position; - - } else if (type == 17) { - - String sentence = buf.toString(StandardCharsets.US_ASCII); - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - position.set(Position.KEY_HDOP, parser.nextDouble()); - - position.setAltitude(parser.nextDouble()); - position.setValid(parser.nextInt() > 0); - position.setCourse(parser.nextDouble()); - position.setSpeed(parser.nextDouble()); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TelemaxProtocol.java b/src/org/traccar/protocol/TelemaxProtocol.java deleted file mode 100644 index 838da9df1..000000000 --- a/src/org/traccar/protocol/TelemaxProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TelemaxProtocol extends BaseProtocol { - - public TelemaxProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new TelemaxProtocolDecoder(TelemaxProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TelemaxProtocolDecoder.java b/src/org/traccar/protocol/TelemaxProtocolDecoder.java deleted file mode 100644 index 9369ab101..000000000 --- a/src/org/traccar/protocol/TelemaxProtocolDecoder.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class TelemaxProtocolDecoder extends BaseProtocolDecoder { - - public TelemaxProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private String readValue(String sentence, int[] index, int length) { - String value = sentence.substring(index[0], index[0] + length); - index[0] += length; - return value; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("%")) { - int length = Integer.parseInt(sentence.substring(1, 3)); - getDeviceSession(channel, remoteAddress, sentence.substring(3, 3 + length)); - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - int[] index = {0}; - - if (!readValue(sentence, index, 1).equals("Y")) { - return null; - } - - readValue(sentence, index, 8); // command id - readValue(sentence, index, 6); // password - readValue(sentence, index, Integer.parseInt(readValue(sentence, index, 2), 16)); // unit id - readValue(sentence, index, 2); // frame count - - readValue(sentence, index, 2); // data format - - int interval = Integer.parseInt(readValue(sentence, index, 4), 16); - - readValue(sentence, index, 2); // info flags - readValue(sentence, index, 2); // version - - int count = Integer.parseInt(readValue(sentence, index, 2), 16); - - Date time = null; - List positions = new LinkedList<>(); - - for (int i = 0; i < count; i++) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - int speed = Integer.parseInt(readValue(sentence, index, 2), 16); - - position.setValid(BitUtil.check(speed, 7)); - position.setSpeed(BitUtil.to(speed, 7)); - - position.setLongitude((Integer.parseInt(readValue(sentence, index, 6), 16) - 5400000) / 30000.0); - position.setLatitude((Integer.parseInt(readValue(sentence, index, 6), 16) - 5400000) / 30000.0); - - if (i == 0 | i == count - 1) { - time = new SimpleDateFormat("yyMMddHHmmss").parse(readValue(sentence, index, 12)); - position.set(Position.KEY_STATUS, readValue(sentence, index, 8)); - } else { - time = new Date(time.getTime() + interval * 1000); - } - - position.setTime(time); - - positions.add(position); - - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/TelicFrameDecoder.java b/src/org/traccar/protocol/TelicFrameDecoder.java deleted file mode 100644 index d1fef1b5b..000000000 --- a/src/org/traccar/protocol/TelicFrameDecoder.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 org.traccar.BaseFrameDecoder; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class TelicFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 4) { - return null; - } - - long length = buf.getUnsignedIntLE(buf.readerIndex()); - - if (length < 1024) { - if (buf.readableBytes() >= length + 4) { - buf.readUnsignedIntLE(); - return buf.readRetainedSlice((int) length); - } - } else { - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0); - if (endIndex >= 0) { - ByteBuf frame = buf.readRetainedSlice(endIndex - buf.readerIndex()); - buf.readByte(); - if (frame.readableBytes() > 0) { - return frame; - } - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TelicProtocol.java b/src/org/traccar/protocol/TelicProtocol.java deleted file mode 100644 index 991befa19..000000000 --- a/src/org/traccar/protocol/TelicProtocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TelicProtocol extends BaseProtocol { - - public TelicProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TelicFrameDecoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new TelicProtocolDecoder(TelicProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TelicProtocolDecoder.java b/src/org/traccar/protocol/TelicProtocolDecoder.java deleted file mode 100644 index 6d5e8f21e..000000000 --- a/src/org/traccar/protocol/TelicProtocolDecoder.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class TelicProtocolDecoder extends BaseProtocolDecoder { - - public TelicProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("dddd") - .number("(d{6}|d{15})") // device id - .number("(d{1,2}),") // type - .number("d{12},") // event time - .number("d+,") - .number("(dd)(dd)(dd)") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .groupBegin() - .number("(ddd)(dd)(dddd),") // longitude - .number("(dd)(dd)(dddd),") // latitude - .or() - .number("(-?d+),") // longitude - .number("(-?d+),") // latitude - .groupEnd() - .number("(d),") // validity - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+)?,") // satellites - .expression("(?:[^,]*,){7}") - .number("(d+),") // battery - .any() - .compile(); - - private String decodeAlarm(int eventId) { - - switch (eventId) { - case 1: - return Position.ALARM_POWER_ON; - case 2: - return Position.ALARM_SOS; - case 5: - return Position.ALARM_POWER_OFF; - case 7: - return Position.ALARM_GEOFENCE_ENTER; - case 8: - return Position.ALARM_GEOFENCE_EXIT; - case 22: - return Position.ALARM_LOW_BATTERY; - case 25: - return Position.ALARM_MOVEMENT; - default: - return null; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - int event = parser.nextInt(0); - position.set(Position.KEY_EVENT, event); - - position.set(Position.KEY_ALARM, decodeAlarm(event)); - - if (event == 11) { - position.set(Position.KEY_IGNITION, true); - } else if (event == 12) { - position.set(Position.KEY_IGNITION, false); - } - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - if (parser.hasNext(6)) { - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); - } - - if (parser.hasNext(2)) { - position.setLongitude(parser.nextDouble(0) / 10000); - position.setLatitude(parser.nextDouble(0) / 10000); - } - - position.setValid(parser.nextInt(0) != 1); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - if (parser.hasNext()) { - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - } - - position.set(Position.KEY_BATTERY, parser.nextInt(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/TeltonikaFrameDecoder.java b/src/org/traccar/protocol/TeltonikaFrameDecoder.java deleted file mode 100644 index 4d4d79d8d..000000000 --- a/src/org/traccar/protocol/TeltonikaFrameDecoder.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 org.traccar.BaseFrameDecoder; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class TeltonikaFrameDecoder extends BaseFrameDecoder { - - private static final int MESSAGE_MINIMUM_LENGTH = 12; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - // Check minimum length - if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) { - return null; - } - - // Read packet - int length = buf.getUnsignedShort(buf.readerIndex()); - if (length > 0) { - if (buf.readableBytes() >= (length + 2)) { - return buf.readRetainedSlice(length + 2); - } - } else { - int dataLength = buf.getInt(buf.readerIndex() + 4); - if (buf.readableBytes() >= (dataLength + 12)) { - return buf.readRetainedSlice(dataLength + 12); - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TeltonikaProtocol.java b/src/org/traccar/protocol/TeltonikaProtocol.java deleted file mode 100644 index eef9662d7..000000000 --- a/src/org/traccar/protocol/TeltonikaProtocol.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class TeltonikaProtocol extends BaseProtocol { - - public TeltonikaProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TeltonikaFrameDecoder()); - pipeline.addLast(new TeltonikaProtocolEncoder()); - pipeline.addLast(new TeltonikaProtocolDecoder(TeltonikaProtocol.this, false)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TeltonikaProtocolEncoder()); - pipeline.addLast(new TeltonikaProtocolDecoder(TeltonikaProtocol.this, true)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java deleted file mode 100644 index 974d2c106..000000000 --- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ /dev/null @@ -1,597 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -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; -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 photos = new HashMap<>(); - - public void setExtended(boolean extended) { - this.extended = extended; - } - - public TeltonikaProtocolDecoder(Protocol protocol, boolean connectionless) { - super(protocol); - this.connectionless = connectionless; - this.extended = Context.getConfig().getBoolean(getProtocolName() + ".extended"); - } - - private void parseIdentification(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - int length = buf.readUnsignedShort(); - String imei = buf.toString(buf.readerIndex(), length, StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - - if (channel != null) { - ByteBuf response = Unpooled.buffer(1); - if (deviceSession != null) { - response.writeByte(1); - } else { - response.writeByte(0); - } - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - public static final int CODEC_GH3000 = 0x07; - public static final int CODEC_8 = 0x08; - public static final int CODEC_8_EXT = 0x8E; - public static final int CODEC_12 = 0x0C; - public static final int CODEC_16 = 0x10; - - 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() - 10))); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - private void decodeSerial(Channel channel, SocketAddress remoteAddress, Position position, ByteBuf buf) { - - getLastLocation(position, null); - - 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(); - } - } - - } - - } 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) { - switch (length) { - case 1: - return signed ? buf.readByte() : buf.readUnsignedByte(); - case 2: - return signed ? buf.readShort() : buf.readUnsignedShort(); - case 4: - return signed ? buf.readInt() : buf.readUnsignedInt(); - default: - return buf.readLong(); - } - } - - private void decodeOtherParameter(Position position, int id, ByteBuf buf, int length) { - switch (id) { - case 1: - case 2: - case 3: - case 4: - position.set("di" + id, readValue(buf, length, false)); - break; - case 9: - position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false)); - break; - case 17: - position.set("axisX", readValue(buf, length, true)); - break; - case 18: - position.set("axisY", readValue(buf, length, true)); - break; - case 19: - position.set("axisZ", readValue(buf, length, true)); - break; - case 21: - position.set(Position.KEY_RSSI, readValue(buf, length, false)); - break; - case 25: - case 26: - case 27: - case 28: - position.set(Position.PREFIX_TEMP + (id - 24), readValue(buf, length, true) * 0.1); - break; - case 66: - position.set(Position.KEY_POWER, readValue(buf, length, false) * 0.001); - break; - case 67: - position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); - break; - case 69: - position.set("gpsStatus", readValue(buf, length, false)); - break; - case 72: - case 73: - case 74: - position.set(Position.PREFIX_TEMP + (id - 71), readValue(buf, length, true) * 0.1); - break; - case 78: - long driverUniqueId = readValue(buf, length, false); - if (driverUniqueId != 0) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId)); - } - break; - case 80: - position.set("workMode", readValue(buf, length, false)); - break; - case 129: - case 130: - case 131: - case 132: - case 133: - case 134: - String driver = id == 129 || id == 132 ? "" : position.getString("driver1"); - position.set("driver" + (id >= 132 ? 2 : 1), - driver + buf.readSlice(length).toString(StandardCharsets.US_ASCII).trim()); - break; - case 179: - position.set(Position.PREFIX_OUT + 1, readValue(buf, length, false) == 1); - break; - case 180: - position.set(Position.PREFIX_OUT + 2, readValue(buf, length, false) == 1); - break; - case 181: - position.set(Position.KEY_PDOP, readValue(buf, length, false) * 0.1); - break; - case 182: - position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1); - break; - case 236: - if (readValue(buf, length, false) == 1) { - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - } - break; - case 237: - position.set(Position.KEY_MOTION, readValue(buf, length, false) == 0); - break; - case 238: - switch ((int) readValue(buf, length, false)) { - case 1: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 2: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 3: - position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); - break; - default: - break; - } - break; - case 239: - position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1); - break; - case 240: - position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1); - break; - case 241: - position.set(Position.KEY_OPERATOR, readValue(buf, length, false)); - break; - default: - position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); - break; - } - } - - private void decodeGh3000Parameter(Position position, int id, ByteBuf buf, int length) { - switch (id) { - case 1: - position.set(Position.KEY_BATTERY_LEVEL, readValue(buf, length, false)); - break; - case 2: - position.set("usbConnected", readValue(buf, length, false) == 1); - break; - case 5: - position.set("uptime", readValue(buf, length, false)); - break; - case 20: - position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1); - break; - case 21: - position.set(Position.KEY_VDOP, readValue(buf, length, false) * 0.1); - break; - case 22: - position.set(Position.KEY_PDOP, readValue(buf, length, false) * 0.1); - break; - case 67: - position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001); - break; - case 221: - position.set("button", readValue(buf, length, false)); - break; - case 222: - if (readValue(buf, length, false) == 1) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - break; - case 240: - position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1); - break; - case 244: - position.set(Position.KEY_ROAMING, readValue(buf, length, false) == 1); - break; - default: - position.set(Position.PREFIX_IO + id, readValue(buf, length, false)); - break; - } - } - - private void decodeParameter(Position position, int id, ByteBuf buf, int length, int codec) { - if (codec == CODEC_GH3000) { - decodeGh3000Parameter(position, id, buf, length); - } else { - decodeOtherParameter(position, id, buf, length); - } - } - - private void decodeNetwork(Position position) { - long cid = position.getLong(Position.PREFIX_IO + 205); - int lac = position.getInteger(Position.PREFIX_IO + 206); - if (cid != 0 && lac != 0) { - CellTower cellTower = CellTower.fromLacCid(lac, cid); - long operator = position.getInteger(Position.KEY_OPERATOR); - if (operator != 0) { - cellTower.setOperator(operator); - } - position.setNetwork(new Network(cellTower)); - } - } - - private int readExtByte(ByteBuf buf, int codec, int... codecs) { - boolean ext = false; - for (int c : codecs) { - if (codec == c) { - ext = true; - break; - } - } - if (ext) { - return buf.readUnsignedShort(); - } else { - return buf.readUnsignedByte(); - } - } - - private void decodeLocation(Position position, ByteBuf buf, int codec) { - - int globalMask = 0x0f; - - if (codec == CODEC_GH3000) { - - long time = buf.readUnsignedInt() & 0x3fffffff; - time += 1167609600; // 2007-01-01 00:00:00 - - globalMask = buf.readUnsignedByte(); - if (BitUtil.check(globalMask, 0)) { - - position.setTime(new Date(time * 1000)); - - int locationMask = buf.readUnsignedByte(); - - if (BitUtil.check(locationMask, 0)) { - position.setLatitude(buf.readFloat()); - position.setLongitude(buf.readFloat()); - } - - if (BitUtil.check(locationMask, 1)) { - position.setAltitude(buf.readUnsignedShort()); - } - - if (BitUtil.check(locationMask, 2)) { - position.setCourse(buf.readUnsignedByte() * 360.0 / 256); - } - - if (BitUtil.check(locationMask, 3)) { - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - } - - if (BitUtil.check(locationMask, 4)) { - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - } - - if (BitUtil.check(locationMask, 5)) { - CellTower cellTower = CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort()); - - if (BitUtil.check(locationMask, 6)) { - cellTower.setSignalStrength((int) buf.readUnsignedByte()); - } - - if (BitUtil.check(locationMask, 7)) { - cellTower.setOperator(buf.readUnsignedInt()); - } - - position.setNetwork(new Network(cellTower)); - - } else { - if (BitUtil.check(locationMask, 6)) { - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - } - if (BitUtil.check(locationMask, 7)) { - position.set(Position.KEY_OPERATOR, buf.readUnsignedInt()); - } - } - - } else { - - getLastLocation(position, new Date(time * 1000)); - - } - - } else { - - position.setTime(new Date(buf.readLong())); - - position.set("priority", buf.readUnsignedByte()); - - position.setLongitude(buf.readInt() / 10000000.0); - position.setLatitude(buf.readInt() / 10000000.0); - position.setAltitude(buf.readShort()); - position.setCourse(buf.readUnsignedShort()); - - int satellites = buf.readUnsignedByte(); - position.set(Position.KEY_SATELLITES, satellites); - - position.setValid(satellites != 0); - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - - position.set(Position.KEY_EVENT, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16)); - if (codec == CODEC_16) { - buf.readUnsignedByte(); // generation type - } - - readExtByte(buf, codec, CODEC_8_EXT); // total IO data records - - } - - // Read 1 byte data - if (BitUtil.check(globalMask, 1)) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 1, codec); - } - } - - // Read 2 byte data - if (BitUtil.check(globalMask, 2)) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 2, codec); - } - } - - // Read 4 byte data - if (BitUtil.check(globalMask, 3)) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 4, codec); - } - } - - // Read 8 byte data - if (codec == CODEC_8 || codec == CODEC_8_EXT || codec == CODEC_16) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - decodeOtherParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 8); - } - } - - // Read 16 byte data - if (extended) { - int cnt = readExtByte(buf, codec, CODEC_8_EXT); - for (int j = 0; j < cnt; j++) { - int id = readExtByte(buf, codec, CODEC_8_EXT, CODEC_16); - position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(16))); - } - } - - // Read X byte data - if (codec == CODEC_8_EXT) { - int cnt = buf.readUnsignedShort(); - for (int j = 0; j < cnt; j++) { - int id = buf.readUnsignedShort(); - int length = buf.readUnsignedShort(); - if (id == 256) { - position.set(Position.KEY_VIN, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); - } else { - position.set(Position.PREFIX_IO + id, ByteBufUtil.hexDump(buf.readSlice(length))); - } - } - } - - decodeNetwork(position); - - } - - private List parseData( - Channel channel, SocketAddress remoteAddress, ByteBuf buf, int locationPacketId, String... imei) { - List positions = new LinkedList<>(); - - if (!connectionless) { - buf.readUnsignedInt(); // data length - } - - int codec = buf.readUnsignedByte(); - int count = buf.readUnsignedByte(); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - - if (deviceSession == null) { - return null; - } - - for (int i = 0; i < count; i++) { - Position position = new Position(getProtocolName()); - - position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); - - if (codec == CODEC_12) { - decodeSerial(channel, remoteAddress, position, buf); - } else { - decodeLocation(position, buf, codec); - } - - if (!position.getOutdated() || !position.getAttributes().isEmpty()) { - positions.add(position); - } - } - - if (channel != null) { - if (connectionless) { - ByteBuf response = Unpooled.buffer(); - response.writeShort(5); - response.writeShort(0); - response.writeByte(0x01); - response.writeByte(locationPacketId); - response.writeByte(count); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } else { - ByteBuf response = Unpooled.buffer(); - response.writeInt(count); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - return positions.isEmpty() ? null : positions; - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (connectionless) { - return decodeUdp(channel, remoteAddress, buf); - } else { - return decodeTcp(channel, remoteAddress, buf); - } - } - - private Object decodeTcp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { - - if (buf.getUnsignedShort(0) > 0) { - parseIdentification(channel, remoteAddress, buf); - } else { - buf.skipBytes(4); - return parseData(channel, remoteAddress, buf, 0); - } - - return null; - } - - private Object decodeUdp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception { - - buf.readUnsignedShort(); // length - buf.readUnsignedShort(); // packet id - buf.readUnsignedByte(); // packet type - int locationPacketId = buf.readUnsignedByte(); - String imei = buf.readSlice(buf.readUnsignedShort()).toString(StandardCharsets.US_ASCII); - - return parseData(channel, remoteAddress, buf, locationPacketId, imei); - - } - -} diff --git a/src/org/traccar/protocol/TeltonikaProtocolEncoder.java b/src/org/traccar/protocol/TeltonikaProtocolEncoder.java deleted file mode 100644 index 944cec024..000000000 --- a/src/org/traccar/protocol/TeltonikaProtocolEncoder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 org.traccar.BaseProtocolEncoder; -import org.traccar.helper.Checksum; -import org.traccar.model.Command; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -import java.nio.charset.StandardCharsets; - -public class TeltonikaProtocolEncoder extends BaseProtocolEncoder { - - private ByteBuf encodeContent(String content) { - - ByteBuf buf = Unpooled.buffer(); - - buf.writeInt(0); - buf.writeInt(content.length() + 10); - buf.writeByte(TeltonikaProtocolDecoder.CODEC_12); - buf.writeByte(1); // quantity - buf.writeByte(5); // type - buf.writeInt(content.length() + 2); - buf.writeBytes(content.getBytes(StandardCharsets.US_ASCII)); - buf.writeByte('\r'); - buf.writeByte('\n'); - buf.writeByte(1); // quantity - buf.writeInt(Checksum.crc16(Checksum.CRC16_IBM, buf.nioBuffer(8, buf.writerIndex() - 8))); - - return buf; - } - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return encodeContent(command.getString(Command.KEY_DATA)); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/ThinkRaceProtocol.java b/src/org/traccar/protocol/ThinkRaceProtocol.java deleted file mode 100644 index ca1237cef..000000000 --- a/src/org/traccar/protocol/ThinkRaceProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class ThinkRaceProtocol extends BaseProtocol { - - public ThinkRaceProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2 + 12 + 1 + 1, 2, 2, 0)); - pipeline.addLast(new ThinkRaceProtocolDecoder(ThinkRaceProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/ThinkRaceProtocolDecoder.java b/src/org/traccar/protocol/ThinkRaceProtocolDecoder.java deleted file mode 100644 index 0928b25e0..000000000 --- a/src/org/traccar/protocol/ThinkRaceProtocolDecoder.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class ThinkRaceProtocolDecoder extends BaseProtocolDecoder { - - public ThinkRaceProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_LOGIN = 0x80; - public static final int MSG_GPS = 0x90; - - private static double convertCoordinate(long raw, boolean negative) { - long degrees = raw / 1000000; - double minutes = (raw % 1000000) * 0.0001; - double result = degrees + minutes / 60; - if (negative) { - result = -result; - } - return result; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - ByteBuf id = buf.readSlice(12); - buf.readUnsignedByte(); // separator - int type = buf.readUnsignedByte(); - buf.readUnsignedShort(); // length - - if (type == MSG_LOGIN) { - - int command = buf.readUnsignedByte(); // 0x00 - heartbeat - - if (command == 0x01) { - String imei = buf.toString(buf.readerIndex(), 15, StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession != null && channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(0x48); response.writeByte(0x52); // header - response.writeBytes(id); - response.writeByte(0x2c); // separator - response.writeByte(type); - response.writeShort(0x0002); // length - response.writeShort(0x8000); - response.writeShort(0x0000); // checksum - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - } else if (type == MSG_GPS) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - - int flags = buf.readUnsignedByte(); - - position.setValid(true); - position.setLatitude(convertCoordinate(buf.readUnsignedInt(), !BitUtil.check(flags, 0))); - position.setLongitude(convertCoordinate(buf.readUnsignedInt(), !BitUtil.check(flags, 1))); - - position.setSpeed(buf.readUnsignedByte()); - position.setCourse(buf.readUnsignedByte()); - - position.setNetwork(new Network( - CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort()))); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Tk102Protocol.java b/src/org/traccar/protocol/Tk102Protocol.java deleted file mode 100644 index 9f2463cd6..000000000 --- a/src/org/traccar/protocol/Tk102Protocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Tk102Protocol extends BaseProtocol { - - public Tk102Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1 + 1 + 10, 1, 1, 0)); - pipeline.addLast(new Tk102ProtocolDecoder(Tk102Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Tk102ProtocolDecoder.java b/src/org/traccar/protocol/Tk102ProtocolDecoder.java deleted file mode 100644 index da0c6928b..000000000 --- a/src/org/traccar/protocol/Tk102ProtocolDecoder.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -public class Tk102ProtocolDecoder extends BaseProtocolDecoder { - - public Tk102ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_LOGIN_REQUEST = 0x80; - public static final int MSG_LOGIN_REQUEST_2 = 0x21; - public static final int MSG_LOGIN_RESPONSE = 0x00; - public static final int MSG_HEARTBEAT_REQUEST = 0xF0; - public static final int MSG_HEARTBEAT_RESPONSE = 0xFF; - public static final int MSG_REPORT_ONCE = 0x90; - public static final int MSG_REPORT_INTERVAL = 0x93; - - public static final int MODE_GPRS = 0x30; - public static final int MODE_GPRS_SMS = 0x33; - - private static final Pattern PATTERN = new PatternBuilder() - .text("(") - .expression("[A-Z]+") - .number("(dd)(dd)(dd)") // time (hhmmss) - .expression("([AV])") // validity - .number("(dd)(dd.dddd)([NS])") // latitude - .number("(ddd)(dd.dddd)([EW])") // longitude - .number("(ddd.ddd)") // speed - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .text(")") - .compile(); - - private void sendResponse(Channel channel, int type, ByteBuf dataSequence, ByteBuf content) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte('['); - response.writeByte(type); - response.writeBytes(dataSequence); - response.writeByte(content.readableBytes()); - response.writeBytes(content); - content.release(); - response.writeByte(']'); - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(1); // header - int type = buf.readUnsignedByte(); - ByteBuf dataSequence = buf.readSlice(10); - int length = buf.readUnsignedByte(); - - if (type == MSG_LOGIN_REQUEST || type == MSG_LOGIN_REQUEST_2) { - - ByteBuf data = buf.readSlice(length); - - String id; - if (type == MSG_LOGIN_REQUEST) { - id = data.toString(StandardCharsets.US_ASCII); - } else { - id = data.copy(1, 15).toString(StandardCharsets.US_ASCII); - } - - if (getDeviceSession(channel, remoteAddress, id) != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(MODE_GPRS); - response.writeBytes(data); - sendResponse(channel, MSG_LOGIN_RESPONSE, dataSequence, response); - } - - } else if (type == MSG_HEARTBEAT_REQUEST) { - - sendResponse(channel, MSG_HEARTBEAT_RESPONSE, dataSequence, buf.readRetainedSlice(length)); - - } else { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Tk103FrameDecoder.java b/src/org/traccar/protocol/Tk103FrameDecoder.java deleted file mode 100644 index b61a42563..000000000 --- a/src/org/traccar/protocol/Tk103FrameDecoder.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2017 Valerii Vyshniak (val@val.one) - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class Tk103FrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 2) { - return null; - } - - int frameStartIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '('); - if (frameStartIndex == -1) { - buf.clear(); - return null; - } - - int frameEndIndex, freeTextSymbolCounter; - for (frameEndIndex = frameStartIndex, freeTextSymbolCounter = 0;; frameEndIndex++) { - int freeTextIndex = frameEndIndex; - frameEndIndex = buf.indexOf(frameEndIndex, buf.writerIndex(), (byte) ')'); - if (frameEndIndex == -1) { - break; - } - for (;; freeTextIndex++, freeTextSymbolCounter++) { - freeTextIndex = buf.indexOf(freeTextIndex, frameEndIndex, (byte) '$'); - if (freeTextIndex == -1 || freeTextIndex >= frameEndIndex) { - break; - } - } - if (freeTextSymbolCounter % 2 == 0) { - break; - } - } - - if (frameEndIndex == -1) { - while (buf.readableBytes() > 1024) { - int discardUntilIndex = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) '('); - if (discardUntilIndex == -1) { - buf.clear(); - } else { - buf.readerIndex(discardUntilIndex); - } - } - return null; - } - - buf.readerIndex(frameStartIndex); - - return buf.readRetainedSlice(frameEndIndex + 1 - frameStartIndex); - } - -} diff --git a/src/org/traccar/protocol/Tk103Protocol.java b/src/org/traccar/protocol/Tk103Protocol.java deleted file mode 100644 index fa83133e2..000000000 --- a/src/org/traccar/protocol/Tk103Protocol.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017 Christoph Krey (c@ckrey.de) - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class Tk103Protocol extends BaseProtocol { - - public Tk103Protocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_GET_DEVICE_STATUS, - Command.TYPE_IDENTIFICATION, - Command.TYPE_MODE_DEEP_SLEEP, - Command.TYPE_MODE_POWER_SAVING, - Command.TYPE_ALARM_SOS, - Command.TYPE_SET_CONNECTION, - Command.TYPE_SOS_NUMBER, - Command.TYPE_POSITION_SINGLE, - Command.TYPE_POSITION_PERIODIC, - Command.TYPE_POSITION_STOP, - Command.TYPE_GET_VERSION, - Command.TYPE_POWER_OFF, - Command.TYPE_REBOOT_DEVICE, - Command.TYPE_SET_ODOMETER, - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME, - Command.TYPE_OUTPUT_CONTROL); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Tk103FrameDecoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Tk103ProtocolEncoder()); - pipeline.addLast(new Tk103ProtocolDecoder(Tk103Protocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Tk103ProtocolEncoder()); - pipeline.addLast(new Tk103ProtocolDecoder(Tk103Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/org/traccar/protocol/Tk103ProtocolDecoder.java deleted file mode 100644 index 9e28b5051..000000000 --- a/src/org/traccar/protocol/Tk103ProtocolDecoder.java +++ /dev/null @@ -1,453 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; -import org.traccar.model.WifiAccessPoint; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Tk103ProtocolDecoder extends BaseProtocolDecoder { - - private boolean decodeLow; - - public Tk103ProtocolDecoder(Protocol protocol) { - super(protocol); - decodeLow = Context.getConfig().getBoolean(getProtocolName() + ".decodeLow"); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("(").optional() - .number("(d+)(,)?") // device id - .expression("(.{4}),?") // command - .number("(d*)") - .number("(dd)(dd)(dd),?") // date (mmddyy if comma-delimited, otherwise yyddmm) - .expression("([AV]),?") // validity - .number("(d+)(dd.d+)") // latitude - .expression("([NS]),?") - .number("(d+)(dd.d+)") // longitude - .expression("([EW]),?") - .number("(d+.d)(?:d*,)?") // speed - .number("(dd)(dd)(dd),?") // time (hhmmss) - .groupBegin() - .number("(?:([d.]{6})|(dd)),?") // course - .number("([01])") // charge - .number("([01])") // ignition - .number("(x)") // io - .number("(x)") // io - .number("(x)") // io - .number("(xxx)") // fuel - .number("L(x+)") // odometer - .or() - .number("(d+.d+)") // course - .groupEnd() - .any() - .number("([+-]ddd.d)?") // temperature - .text(")").optional() - .compile(); - - private static final Pattern PATTERN_BATTERY = new PatternBuilder() - .text("(").optional() - .number("(d+),") // device id - .text("ZC20,") - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d+),") // battery level - .number("(d+),") // battery voltage - .number("(d+),") // power voltage - .number("d+") // installed - .any() - .compile(); - - private static final Pattern PATTERN_NETWORK = new PatternBuilder() - .text("(").optional() - .number("(d{12})") // device id - .text("BZ00,") - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(x+),") // lac - .number("(x+),") // cid - .any() - .compile(); - - private static final Pattern PATTERN_LBSWIFI = new PatternBuilder() - .text("(").optional() - .number("(d+),") // device id - .expression("(.{4}),") // command - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(d+),") // lac - .number("(d+),") // cid - .number("(d+),") // number of wifi macs - .number("((?:(?:xx:){5}(?:xx)\\*[-+]?d+\\*d+,)*)") - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd)") // time (hhmmss) - .any() - .compile(); - - private static final Pattern PATTERN_COMMAND_RESULT = new PatternBuilder() - .text("(").optional() - .number("(d+),") // device id - .expression(".{4},") // command - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("\\$([\\s\\S]*?)(?:\\$|$)") // message - .any() - .compile(); - - private String decodeAlarm(int value) { - switch (value) { - case 1: - return Position.ALARM_ACCIDENT; - case 2: - return Position.ALARM_SOS; - case 3: - return Position.ALARM_VIBRATION; - case 4: - return Position.ALARM_LOW_SPEED; - case 5: - return Position.ALARM_OVERSPEED; - case 6: - return Position.ALARM_GEOFENCE_EXIT; - default: - return null; - } - } - - private void decodeType(Position position, String type, String data) { - switch (type) { - case "BO01": - position.set(Position.KEY_ALARM, decodeAlarm(data.charAt(0) - '0')); - break; - case "ZC11": - case "DW31": - case "DW51": - position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); - break; - case "ZC12": - case "DW32": - case "DW52": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case "ZC13": - case "DW33": - case "DW53": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - break; - case "ZC15": - case "DW35": - case "DW55": - position.set(Position.KEY_IGNITION, true); - break; - case "ZC16": - case "DW36": - case "DW56": - position.set(Position.KEY_IGNITION, false); - break; - case "ZC29": - case "DW42": - case "DW62": - position.set(Position.KEY_IGNITION, true); - break; - case "ZC17": - case "DW37": - case "DW57": - position.set(Position.KEY_ALARM, Position.ALARM_REMOVING); - break; - case "ZC25": - case "DW3E": - case "DW5E": - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - break; - case "ZC26": - case "DW3F": - case "DW5F": - position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); - break; - case "ZC27": - case "DW40": - case "DW60": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); - break; - default: - break; - } - } - - private Integer decodeBattery(int value) { - switch (value) { - case 6: - return 100; - case 5: - return 80; - case 4: - return 50; - case 3: - return 20; - case 2: - return 10; - default: - return null; - } - } - - private Position decodeBattery(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_BATTERY, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - int batterylevel = parser.nextInt(0); - if (batterylevel != 255) { - position.set(Position.KEY_BATTERY_LEVEL, decodeBattery(batterylevel)); - } - - int battery = parser.nextInt(0); - if (battery != 65535) { - position.set(Position.KEY_BATTERY, battery * 0.01); - } - - int power = parser.nextInt(0); - if (power != 65535) { - position.set(Position.KEY_POWER, power * 0.1); - } - - return position; - } - - private Position decodeNetwork(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_NETWORK, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.setNetwork(new Network(CellTower.from( - parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); - - return position; - } - - private Position decodeLbsWifi(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_LBSWIFI, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - decodeType(position, parser.next(), "0"); - - getLastLocation(position, null); - - Network network = new Network(); - - network.addCellTower(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt())); - - int wifiCount = parser.nextInt(); - if (parser.hasNext()) { - String[] wifimacs = parser.next().split(","); - if (wifimacs.length == wifiCount) { - for (int i = 0; i < wifiCount; i++) { - String[] wifiinfo = wifimacs[i].split("\\*"); - network.addWifiAccessPoint(WifiAccessPoint.from( - wifiinfo[0], Integer.parseInt(wifiinfo[1]), Integer.parseInt(wifiinfo[2]))); - } - } - } - - if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { - position.setNetwork(network); - } - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - return position; - } - - private Position decodeCommandResult(Channel channel, SocketAddress remoteAddress, String sentence) { - Parser parser = new Parser(PATTERN_COMMAND_RESULT, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.set(Position.KEY_RESULT, parser.next()); - - return position; - - } - -@Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (channel != null) { - String id = sentence.substring(1, 13); - String type = sentence.substring(13, 17); - if (type.equals("BP00")) { - channel.writeAndFlush(new NetworkMessage("(" + id + "AP01HSO)", remoteAddress)); - return null; - } else if (type.equals("BP05")) { - channel.writeAndFlush(new NetworkMessage("(" + id + "AP05)", remoteAddress)); - } - } - - if (sentence.contains("ZC20")) { - return decodeBattery(channel, remoteAddress, sentence); - } else if (sentence.contains("BZ00")) { - return decodeNetwork(channel, remoteAddress, sentence); - } else if (sentence.contains("ZC03")) { - return decodeCommandResult(channel, remoteAddress, sentence); - } else if (sentence.contains("DW5")) { - return decodeLbsWifi(channel, remoteAddress, sentence); - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - boolean alternative = parser.next() != null; - - decodeType(position, parser.next(), parser.next()); - - DateBuilder dateBuilder = new DateBuilder(); - if (alternative) { - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - } else { - dateBuilder.setDate(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - } - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - position.setSpeed(convertSpeed(parser.nextDouble(0), "kmh")); - - dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - if (parser.hasNext()) { - position.setCourse(parser.nextDouble()); - } - if (parser.hasNext()) { - position.setCourse(parser.nextDouble()); - } - - if (parser.hasNext(7)) { - position.set(Position.KEY_CHARGE, parser.nextInt() == 0); - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - - int mask1 = parser.nextHexInt(); - position.set(Position.PREFIX_IN + 2, BitUtil.check(mask1, 0) ? 1 : 0); - position.set("panic", BitUtil.check(mask1, 1) ? 1 : 0); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(mask1, 2) ? 1 : 0); - if (decodeLow || BitUtil.check(mask1, 3)) { - position.set(Position.KEY_BLOCKED, BitUtil.check(mask1, 3) ? 1 : 0); - } - - int mask2 = parser.nextHexInt(); - for (int i = 0; i < 3; i++) { - if (decodeLow || BitUtil.check(mask2, i)) { - position.set("hs" + (3 - i), BitUtil.check(mask2, i) ? 1 : 0); - } - } - if (decodeLow || BitUtil.check(mask2, 3)) { - position.set(Position.KEY_DOOR, BitUtil.check(mask2, 3) ? 1 : 0); - } - - int mask3 = parser.nextHexInt(); - for (int i = 1; i <= 3; i++) { - if (decodeLow || BitUtil.check(mask3, i)) { - position.set("ls" + (3 - i + 1), BitUtil.check(mask3, i) ? 1 : 0); - } - } - - position.set(Position.KEY_FUEL_LEVEL, parser.nextHexInt()); - position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0)); - } - - if (parser.hasNext()) { - position.setCourse(parser.nextDouble()); - } - - if (parser.hasNext()) { - position.set(Position.PREFIX_TEMP + 1, parser.nextDouble(0)); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/org/traccar/protocol/Tk103ProtocolEncoder.java deleted file mode 100644 index 98edc8cb5..000000000 --- a/src/org/traccar/protocol/Tk103ProtocolEncoder.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017 Christoph Krey (c@ckrey.de) - * Copyright 2017 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. - * 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 org.traccar.Context; -import org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class Tk103ProtocolEncoder extends StringProtocolEncoder { - - private final boolean forceAlternative; - - public Tk103ProtocolEncoder() { - this.forceAlternative = false; - } - - public Tk103ProtocolEncoder(boolean forceAlternative) { - this.forceAlternative = forceAlternative; - } - - private String formatAlt(Command command, String format, String... keys) { - return formatCommand(command, "[begin]sms2," + format + ",[end]", keys); - } - - @Override - protected Object encodeCommand(Command command) { - - boolean alternative = forceAlternative || Context.getIdentityManager().lookupAttributeBoolean( - command.getDeviceId(), "tk103.alternative", false, true); - - initDevicePassword(command, "123456"); - - if (alternative) { - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatAlt(command, "{%s}", Command.KEY_DATA); - case Command.TYPE_GET_VERSION: - return formatAlt(command, "*about*"); - case Command.TYPE_POWER_OFF: - return formatAlt(command, "*turnoff*"); - case Command.TYPE_REBOOT_DEVICE: - return formatAlt(command, "88888888"); - case Command.TYPE_POSITION_SINGLE: - return formatAlt(command, "*getposl*"); - case Command.TYPE_POSITION_PERIODIC: - return formatAlt(command, "*routetrack*99*"); - case Command.TYPE_POSITION_STOP: - return formatAlt(command, "*routetrackoff*"); - case Command.TYPE_GET_DEVICE_STATUS: - return formatAlt(command, "*status*"); - case Command.TYPE_IDENTIFICATION: - return formatAlt(command, "999999"); - case Command.TYPE_MODE_DEEP_SLEEP: - return formatAlt(command, command.getBoolean(Command.KEY_ENABLE) ? "*sleep*2*" : "*sleepoff*"); - case Command.TYPE_MODE_POWER_SAVING: - return formatAlt(command, command.getBoolean(Command.KEY_ENABLE) ? "*sleepv*" : "*sleepoff*"); - case Command.TYPE_ALARM_SOS: - return formatAlt(command, command.getBoolean(Command.KEY_ENABLE) ? "*soson*" : "*sosoff*"); - case Command.TYPE_SET_CONNECTION: - return formatAlt(command, "*setip*%s*{%s}*", - command.getString(Command.KEY_SERVER).replace(".", "*"), Command.KEY_PORT); - case Command.TYPE_SOS_NUMBER: - return formatAlt(command, "*master*{%s}*{%s}*", Command.KEY_DEVICE_PASSWORD, Command.KEY_PHONE); - default: - return null; - } - } else { - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatCommand(command, "({%s}{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA); - case Command.TYPE_GET_VERSION: - return formatCommand(command, "({%s}AP07)", Command.KEY_UNIQUE_ID); - case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "({%s}AT00)", Command.KEY_UNIQUE_ID); - case Command.TYPE_SET_ODOMETER: - return formatCommand(command, "({%s}AX01)", Command.KEY_UNIQUE_ID); - case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "({%s}AP00)", Command.KEY_UNIQUE_ID); - case Command.TYPE_POSITION_PERIODIC: - return formatCommand(command, "({%s}AR00%s0000)", Command.KEY_UNIQUE_ID, - String.format("%04X", command.getInteger(Command.KEY_FREQUENCY))); - case Command.TYPE_POSITION_STOP: - return formatCommand(command, "({%s}AR0000000000)", Command.KEY_UNIQUE_ID); - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "({%s}AV010)", Command.KEY_UNIQUE_ID); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "({%s}AV011)", Command.KEY_UNIQUE_ID); - case Command.TYPE_OUTPUT_CONTROL: - return formatCommand(command, "({%s}AV00{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA); - default: - return null; - } - } - } - -} diff --git a/src/org/traccar/protocol/Tlt2hProtocol.java b/src/org/traccar/protocol/Tlt2hProtocol.java deleted file mode 100644 index 12fd92afa..000000000 --- a/src/org/traccar/protocol/Tlt2hProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Tlt2hProtocol extends BaseProtocol { - - public Tlt2hProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(32 * 1024, "##\r\n")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Tlt2hProtocolDecoder(Tlt2hProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/org/traccar/protocol/Tlt2hProtocolDecoder.java deleted file mode 100644 index f67ff88db..000000000 --- a/src/org/traccar/protocol/Tlt2hProtocolDecoder.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; - -public class Tlt2hProtocolDecoder extends BaseProtocolDecoder { - - public Tlt2hProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_HEADER = new PatternBuilder() - .number("#(d+)#") // imei - .any() - .expression("([^#]+)#") // status - .number("d+") // number of records - .compile(); - - private static final Pattern PATTERN_POSITION = new PatternBuilder() - .number("#(x+)?") // cell info - .text("$GPRMC,") - .number("(dd)(dd)(dd).d+,") // time (hhmmss.sss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d+)(dd.d+),") // longitude - .number("([EW]),") - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .any() - .compile(); - - private void decodeStatus(Position position, String status) { - switch (status) { - case "AUTOSTART": - case "AUTO": - position.set(Position.KEY_IGNITION, true); - break; - case "AUTOSTOP": - case "AUTOLOW": - position.set(Position.KEY_IGNITION, false); - break; - case "TOWED": - position.set(Position.KEY_ALARM, Position.ALARM_TOW); - break; - case "SOS": - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - break; - case "DEF": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - break; - case "BLP": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case "CLP": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); - break; - case "OS": - position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT); - break; - case "RS": - position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER); - break; - case "OVERSPEED": - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - break; - default: - break; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - sentence = sentence.trim(); - - String header = sentence.substring(0, sentence.indexOf('\r')); - Parser parser = new Parser(PATTERN_HEADER, header); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - String status = parser.next(); - - String[] messages = sentence.substring(sentence.indexOf('\n') + 1).split("\r\n"); - List positions = new LinkedList<>(); - - for (String message : messages) { - parser = new Parser(PATTERN_POSITION, message); - if (parser.matches()) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - parser.next(); // base station info - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - decodeStatus(position, status); - - positions.add(position); - } - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/TlvProtocol.java b/src/org/traccar/protocol/TlvProtocol.java deleted file mode 100644 index 94f5da94f..000000000 --- a/src/org/traccar/protocol/TlvProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TlvProtocol extends BaseProtocol { - - public TlvProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\0')); - pipeline.addLast(new TlvProtocolDecoder(TlvProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TlvProtocolDecoder.java b/src/org/traccar/protocol/TlvProtocolDecoder.java deleted file mode 100644 index 36cf7859f..000000000 --- a/src/org/traccar/protocol/TlvProtocolDecoder.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -public class TlvProtocolDecoder extends BaseProtocolDecoder { - - public TlvProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private void sendResponse(Channel channel, SocketAddress remoteAddress, String type, String... arguments) { - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeCharSequence(type, StandardCharsets.US_ASCII); - for (String argument : arguments) { - response.writeByte(argument.length()); - response.writeCharSequence(argument, StandardCharsets.US_ASCII); - } - response.writeByte(0); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - } - - private String readArgument(ByteBuf buf) { - return buf.readSlice(buf.readUnsignedByte()).toString(StandardCharsets.US_ASCII); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - String type = buf.readSlice(2).toString(StandardCharsets.US_ASCII); - - if (channel != null) { - switch (type) { - case "0A": - case "0C": - sendResponse(channel, remoteAddress, type); - break; - case "0B": - sendResponse(channel, remoteAddress, type, "1482202689", "10", "20", "15"); - break; - case "0E": - case "0F": - sendResponse(channel, remoteAddress, type, "30", "Unknown"); - break; - default: - break; - } - } - - if (type.equals("0E")) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, readArgument(buf)); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(true); - position.setTime(new Date(Long.parseLong(readArgument(buf)) * 1000)); - - readArgument(buf); // location identifier - - position.setLongitude(Double.parseDouble(readArgument(buf))); - position.setLatitude(Double.parseDouble(readArgument(buf))); - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(readArgument(buf)))); - position.setCourse(Double.parseDouble(readArgument(buf))); - - position.set(Position.KEY_SATELLITES, Integer.parseInt(readArgument(buf))); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TmgFrameDecoder.java b/src/org/traccar/protocol/TmgFrameDecoder.java deleted file mode 100644 index 205adaa51..000000000 --- a/src/org/traccar/protocol/TmgFrameDecoder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseFrameDecoder; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class TmgFrameDecoder extends BaseFrameDecoder { - - private boolean isLetter(byte c) { - return c >= 'a' && c <= 'z'; - } - - private int findHeader(ByteBuf buffer) { - int guessedIndex = buffer.indexOf(buffer.readerIndex(), buffer.writerIndex(), (byte) '$'); - while (guessedIndex != -1 && buffer.writerIndex() - guessedIndex >= 5) { - if (buffer.getByte(guessedIndex + 4) == ',' - && isLetter(buffer.getByte(guessedIndex + 1)) - && isLetter(buffer.getByte(guessedIndex + 2)) - && isLetter(buffer.getByte(guessedIndex + 3))) { - return guessedIndex; - } - guessedIndex = buffer.indexOf(guessedIndex, buffer.writerIndex(), (byte) '$'); - } - return -1; - } - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int beginIndex = findHeader(buf); - - if (beginIndex >= 0) { - - buf.readerIndex(beginIndex); - - int endIndex = buf.indexOf(beginIndex, buf.writerIndex(), (byte) '\n'); - - if (endIndex >= 0) { - ByteBuf frame = buf.readRetainedSlice(endIndex - beginIndex); - buf.readByte(); // delimiter - return frame; - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TmgProtocol.java b/src/org/traccar/protocol/TmgProtocol.java deleted file mode 100644 index 020332ce7..000000000 --- a/src/org/traccar/protocol/TmgProtocol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TmgProtocol extends BaseProtocol { - - public TmgProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TmgFrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new TmgProtocolDecoder(TmgProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TmgProtocolDecoder.java b/src/org/traccar/protocol/TmgProtocolDecoder.java deleted file mode 100644 index d27849f8c..000000000 --- a/src/org/traccar/protocol/TmgProtocolDecoder.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class TmgProtocolDecoder extends BaseProtocolDecoder { - - public TmgProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$") - .expression("(...),") // type - .expression("[LH],").optional() // history - .number("(d+),") // imei - .number("(dd)(dd)(dddd),") // date (ddmmyyyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(d),") // status - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(ddd)(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .groupBegin() - .number("(-?d+.?d*),") // altitude - .number("(d+.d+),") // hdop - .number("(d+),") // satellites - .number("(d+),") // visible satellites - .number("([^,]*),") // operator - .number("(d+),") // rssi - .number("[^,]*,") // cid - .expression("([01]),") // ignition - .number("(d+.?d*),") // battery - .number("(d+.?d*),") // power - .expression("([01]+),") // input - .expression("([01]+),") // output - .expression("[01]+,") // temper status - .number("(d+.?d*)[^,]*,") // adc1 - .number("(d+.?d*)[^,]*,") // adc2 - .number("d+.?d*,") // trip meter - .expression("([^,]*),") // software version - .expression("([^,]*),").optional() // rfid - .or() - .number("[^,]*,") // cid - .number("(d+),") // rssi - .number("(d+),") // satellites - .number("[^,]*,") // battery level - .expression("([01]),") // ignition - .expression("([LH]{4}),") // input - .expression("[NT]{4},") // tamper status - .expression("([LH]{2}),") // output - .number("(d+.d+),") // adc1 - .number("(d+.d+),") // adc1 - .number("[^,]*,") // device id - .number("(d+),") // odometer - .groupEnd() - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - String type = parser.next(); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - switch (type) { - case "rmv": - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - break; - case "ebl": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); - break; - case "ibl": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case "tmp": - case "smt": - case "btt": - position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING); - break; - case "ion": - position.set(Position.KEY_IGNITION, true); - break; - case "iof": - position.set(Position.KEY_IGNITION, false); - break; - default: - break; - } - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setValid(parser.nextInt() > 0); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextDouble()); - - if (parser.hasNext(15)) { - - position.setAltitude(parser.nextDouble()); - - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt()); - position.set(Position.KEY_OPERATOR, parser.next()); - position.set(Position.KEY_RSSI, parser.nextInt()); - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - position.set(Position.KEY_POWER, parser.nextDouble()); - - int input = parser.nextBinInt(); - int output = parser.nextBinInt(); - - if (!BitUtil.check(input, 0)) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - - position.set(Position.KEY_INPUT, input); - position.set(Position.KEY_OUTPUT, output); - - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); - position.set(Position.KEY_VERSION_FW, parser.next()); - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - } - - if (parser.hasNext(6)) { - - position.set(Position.KEY_RSSI, parser.nextInt()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_IGNITION, parser.nextInt() == 1); - - char[] input = parser.next().toCharArray(); - for (int i = 0; i < input.length; i++) { - position.set(Position.PREFIX_IN + (i + 1), input[i] == 'H'); - } - - char[] output = parser.next().toCharArray(); - for (int i = 0; i < output.length; i++) { - position.set(Position.PREFIX_OUT + (i + 1), output[i] == 'H'); - } - - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextInt()); - - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/TopflytechProtocol.java b/src/org/traccar/protocol/TopflytechProtocol.java deleted file mode 100644 index 303072bdb..000000000 --- a/src/org/traccar/protocol/TopflytechProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TopflytechProtocol extends BaseProtocol { - - public TopflytechProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new TopflytechProtocolDecoder(TopflytechProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TopflytechProtocolDecoder.java b/src/org/traccar/protocol/TopflytechProtocolDecoder.java deleted file mode 100644 index 6de053c32..000000000 --- a/src/org/traccar/protocol/TopflytechProtocolDecoder.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class TopflytechProtocolDecoder extends BaseProtocolDecoder { - - public TopflytechProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("(") - .number("(d+)") // imei - .any() - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd)") // time (hhmmss) - .expression("([AV])") - .number("(dd)(dd.dddd)([NS])") // latitude - .number("(ddd)(dd.dddd)([EW])") // longitude - .number("(ddd.d)") // speed - .number("(d+.d+)") // course - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - return position; - } - -} diff --git a/src/org/traccar/protocol/TotemFrameDecoder.java b/src/org/traccar/protocol/TotemFrameDecoder.java deleted file mode 100644 index 3fa5abc7a..000000000 --- a/src/org/traccar/protocol/TotemFrameDecoder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -import java.nio.charset.StandardCharsets; - -import org.traccar.BaseFrameDecoder; -import org.traccar.helper.BufferUtil; - -public class TotemFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 10) { - return null; - } - - int beginIndex = BufferUtil.indexOf("$$", buf); - if (beginIndex == -1) { - return null; - } else if (beginIndex > buf.readerIndex()) { - buf.readerIndex(beginIndex); - } - - int length; - - if (buf.getByte(buf.readerIndex() + 2) == (byte) '0') { - length = Integer.parseInt(buf.toString(buf.readerIndex() + 2, 4, StandardCharsets.US_ASCII)); - } else { - length = Integer.parseInt(buf.toString(buf.readerIndex() + 2, 2, StandardCharsets.US_ASCII), 16); - } - - if (length <= buf.readableBytes()) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TotemProtocol.java b/src/org/traccar/protocol/TotemProtocol.java deleted file mode 100644 index 66e1ec4f1..000000000 --- a/src/org/traccar/protocol/TotemProtocol.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class TotemProtocol extends BaseProtocol { - - public TotemProtocol() { - setSupportedDataCommands( - Command.TYPE_ENGINE_RESUME, - Command.TYPE_ENGINE_STOP - ); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TotemFrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new TotemProtocolEncoder()); - pipeline.addLast(new TotemProtocolDecoder(TotemProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TotemProtocolDecoder.java b/src/org/traccar/protocol/TotemProtocolDecoder.java deleted file mode 100644 index cd7f684b8..000000000 --- a/src/org/traccar/protocol/TotemProtocolDecoder.java +++ /dev/null @@ -1,444 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -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.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class TotemProtocolDecoder extends BaseProtocolDecoder { - - public TotemProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN1 = new PatternBuilder() - .text("$$") // header - .number("xx") // length - .number("(d+)|") // imei - .expression("(..)") // alarm - .text("$GPRMC,") - .number("(dd)(dd)(dd).d+,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(d+)(dd.d+),([NS]),") // latitude - .number("(d+)(dd.d+),([EW]),") // longitude - .number("(d+.?d*)?,") // speed - .number("(d+.?d*)?,") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .expression("[^*]*").text("*") - .number("xx|") // checksum - .number("(d+.d+)|") // pdop - .number("(d+.d+)|") // hdop - .number("(d+.d+)|") // vdop - .number("(d+)|") // io status - .number("d+|") // battery time - .number("d") // charged - .number("(ddd)") // battery - .number("(dddd)|") // power - .number("(d+)|").optional() // adc - .number("x*(xxxx)") // lac - .number("(xxxx)|") // cid - .number("(d+)|") // temperature - .number("(d+.d+)|") // odometer - .number("d+|") // serial number - .any() - .number("xxxx") // checksum - .any() - .compile(); - - private static final Pattern PATTERN2 = new PatternBuilder() - .text("$$") // header - .number("xx") // length - .number("(d+)|") // imei - .expression("(..)") // alarm type - .number("(dd)(dd)(dd)") // date (ddmmyy) - .number("(dd)(dd)(dd)|") // time (hhmmss) - .expression("([AV])|") // validity - .number("(d+)(dd.d+)|") // latitude - .expression("([NS])|") - .number("(d+)(dd.d+)|") // longitude - .expression("([EW])|") - .number("(d+.d+)?|") // speed - .number("(d+)?|") // course - .number("(d+.d+)|") // hdop - .number("(d+)|") // io status - .number("d") // charged - .number("(dd)") // battery - .number("(dd)|") // external power - .number("(d+)|") // adc - .number("(xxxx)") // lac - .number("(xxxx)|") // cid - .number("(d+)|") // temperature - .number("(d+.d+)|") // odometer - .number("d+|") // serial number - .number("xxxx") // checksum - .any() - .compile(); - - private static final Pattern PATTERN3 = new PatternBuilder() - .text("$$") // header - .number("xx") // length - .number("(d+)|") // imei - .expression("(..)") // alarm type - .number("(dd)(dd)(dd)") // date (ddmmyy) - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("(xxxx)") // io status - .expression("[01]") // charging - .number("(dd)") // battery - .number("(dd)") // external power - .number("(dddd)") // adc 1 - .number("(dddd)") // adc 2 - .number("(ddd)") // temperature 1 - .number("(ddd)") // temperature 2 - .number("(xxxx)") // lac - .number("(xxxx)") // cid - .expression("([AV])") // validity - .number("(dd)") // satellites - .number("(ddd)") // course - .number("(ddd)") // speed - .number("(dd.d)") // pdop - .number("(d{7})") // odometer - .number("(dd)(dd.dddd)([NS])") // latitude - .number("(ddd)(dd.dddd)([EW])") // longitude - .number("dddd") // serial number - .number("xxxx") // checksum - .any() - .compile(); - - private static final Pattern PATTERN4 = new PatternBuilder() - .text("$$") // header - .number("dddd") // length - .number("(xx)") // type - .number("(d+)|") // imei - .number("(x{8})") // status - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("(dd)") // battery - .number("(dd)") // external power - .number("(dddd)") // adc 1 - .groupBegin() - .groupBegin() - .number("(dddd)") // adc 2 - .number("(dddd)") // adc 3 - .number("(dddd)") // adc 4 - .groupEnd("?") - .number("(dddd)") // temperature 1 - .number("(dddd)?") // temperature 2 - .groupEnd("?") - .number("(xxxx)") // lac - .number("(xxxx)") // cid - .groupBegin() - .number("(dd)") // mcc - .number("(ddd)") // mnc - .groupEnd("?") - .number("(dd)") // satellites - .number("(dd)") // gsm (rssi) - .number("(ddd)") // course - .number("(ddd)") // speed - .number("(dd.d)") // hdop - .number("(d{7})") // odometer - .number("(dd)(dd.dddd)([NS])") // latitude - .number("(ddd)(dd.dddd)([EW])") // longitude - .number("dddd") // serial number - .number("xx") // checksum - .any() - .compile(); - - private String decodeAlarm123(int value) { - switch (value) { - case 0x01: - return Position.ALARM_SOS; - case 0x10: - return Position.ALARM_LOW_BATTERY; - case 0x11: - return Position.ALARM_OVERSPEED; - case 0x30: - return Position.ALARM_PARKING; - case 0x42: - return Position.ALARM_GEOFENCE_EXIT; - case 0x43: - return Position.ALARM_GEOFENCE_ENTER; - default: - return null; - } - } - - private String decodeAlarm4(int value) { - switch (value) { - case 0x01: - return Position.ALARM_SOS; - case 0x02: - return Position.ALARM_OVERSPEED; - case 0x04: - return Position.ALARM_GEOFENCE_EXIT; - case 0x05: - return Position.ALARM_GEOFENCE_ENTER; - case 0x40: - return Position.ALARM_SHOCK; - case 0x42: - return Position.ALARM_ACCELERATION; - case 0x43: - return Position.ALARM_BRAKING; - default: - return null; - } - } - - private boolean decode12(Position position, Parser parser, Pattern pattern) { - - if (parser.hasNext()) { - position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16))); - } - DateBuilder dateBuilder = new DateBuilder(); - int year = 0, month = 0, day = 0; - if (pattern == PATTERN2) { - day = parser.nextInt(0); - month = parser.nextInt(0); - year = parser.nextInt(0); - } - dateBuilder.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - if (pattern == PATTERN1) { - day = parser.nextInt(0); - month = parser.nextInt(0); - year = parser.nextInt(0); - } - if (year == 0) { - return false; // ignore invalid data - } - dateBuilder.setDate(year, month, day); - position.setTime(dateBuilder.getDate()); - - if (pattern == PATTERN1) { - position.set(Position.KEY_PDOP, parser.nextDouble()); - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_VDOP, parser.nextDouble()); - } else { - position.set(Position.KEY_HDOP, parser.nextDouble()); - } - - int io = parser.nextBinInt(); - position.set(Position.KEY_STATUS, io); - if (pattern == PATTERN1) { - position.set(Position.KEY_ALARM, BitUtil.check(io, 0) ? Position.ALARM_SOS : null); - position.set(Position.PREFIX_IN + 3, BitUtil.check(io, 4)); - position.set(Position.PREFIX_IN + 4, BitUtil.check(io, 5)); - position.set(Position.PREFIX_IN + 1, BitUtil.check(io, 6)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(io, 7)); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(io, 8)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(io, 9)); - position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.01); - } else { - position.set(Position.KEY_ANTENNA, BitUtil.check(io, 0)); - position.set(Position.KEY_CHARGE, BitUtil.check(io, 1)); - for (int i = 1; i <= 6; i++) { - position.set(Position.PREFIX_IN + i, BitUtil.check(io, 1 + i)); - } - for (int i = 1; i <= 4; i++) { - position.set(Position.PREFIX_OUT + i, BitUtil.check(io, 7 + i)); - } - position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1); - } - - position.set(Position.KEY_POWER, parser.nextDouble(0)); - position.set(Position.PREFIX_ADC + 1, parser.next()); - - int lac = parser.nextHexInt(0); - int cid = parser.nextHexInt(0); - if (lac != 0 && cid != 0) { - position.setNetwork(new Network(CellTower.fromLacCid(lac, cid))); - } - - position.set(Position.PREFIX_TEMP + 1, parser.next()); - position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); - - return true; - } - - private boolean decode3(Position position, Parser parser) { - - if (parser.hasNext()) { - position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16))); - } - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.set(Position.PREFIX_IO + 1, parser.next()); - position.set(Position.KEY_BATTERY, parser.nextDouble(0) * 0.1); - position.set(Position.KEY_POWER, parser.nextDouble(0)); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - position.set(Position.PREFIX_TEMP + 1, parser.next()); - position.set(Position.PREFIX_TEMP + 2, parser.next()); - - position.setNetwork(new Network( - CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0)))); - - position.setValid(parser.next().equals("A")); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.setCourse(parser.nextDouble(0)); - position.setSpeed(parser.nextDouble(0)); - position.set(Position.KEY_PDOP, parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - return true; - } - - private boolean decode4(Position position, Parser parser) { - - long status = parser.nextHexLong(); - - position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 1) ? Position.ALARM_SOS : null); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 32 - 2)); - position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 3) ? Position.ALARM_OVERSPEED : null); - position.set(Position.KEY_CHARGE, BitUtil.check(status, 32 - 4)); - position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 5) ? Position.ALARM_GEOFENCE_EXIT : null); - position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 6) ? Position.ALARM_GEOFENCE_ENTER : null); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(status, 32 - 9)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(status, 32 - 10)); - position.set(Position.PREFIX_OUT + 3, BitUtil.check(status, 32 - 11)); - position.set(Position.PREFIX_OUT + 4, BitUtil.check(status, 32 - 12)); - position.set(Position.PREFIX_IN + 2, BitUtil.check(status, 32 - 13)); - position.set(Position.PREFIX_IN + 3, BitUtil.check(status, 32 - 14)); - position.set(Position.PREFIX_IN + 4, BitUtil.check(status, 32 - 15)); - position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 16) ? Position.ALARM_SHOCK : null); - position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 18) ? Position.ALARM_LOW_BATTERY : null); - position.set(Position.KEY_ALARM, BitUtil.check(status, 32 - 22) ? Position.ALARM_JAMMING : null); - - - position.setTime(parser.nextDateTime()); - - position.set(Position.KEY_BATTERY, parser.nextDouble() * 0.1); - position.set(Position.KEY_POWER, parser.nextDouble()); - - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - position.set(Position.PREFIX_ADC + 3, parser.next()); - position.set(Position.PREFIX_ADC + 4, parser.next()); - position.set(Position.PREFIX_TEMP + 1, parser.next()); - - if (parser.hasNext()) { - position.set(Position.PREFIX_TEMP + 2, parser.next()); - position.setValid(BitUtil.check(status, 32 - 20)); - } else { - position.setValid(BitUtil.check(status, 32 - 18)); - } - - int lac = parser.nextHexInt(); - int cid = parser.nextHexInt(); - CellTower cellTower; - if (parser.hasNext(2)) { - int mnc = parser.nextInt(); - int mcc = parser.nextInt(); - cellTower = CellTower.from(mcc, mnc, lac, cid); - } else { - cellTower = CellTower.fromLacCid(lac, cid); - } - position.set(Position.KEY_SATELLITES, parser.nextInt()); - cellTower.setSignalStrength(parser.nextInt()); - position.setNetwork(new Network(cellTower)); - - position.setCourse(parser.nextDouble()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextInt() * 1000); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - return true; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - Pattern pattern = PATTERN3; - if (sentence.charAt(2) == '0') { - pattern = PATTERN4; - } else if (sentence.contains("$GPRMC")) { - pattern = PATTERN1; - } else { - int index = sentence.indexOf('|'); - if (index != -1 && sentence.indexOf('|', index + 1) != -1) { - pattern = PATTERN2; - } - } - - Parser parser = new Parser(pattern, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - if (pattern == PATTERN4) { - position.set(Position.KEY_ALARM, decodeAlarm4(parser.nextHexInt())); - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - boolean result; - if (pattern == PATTERN1 || pattern == PATTERN2) { - result = decode12(position, parser, pattern); - } else if (pattern == PATTERN3) { - result = decode3(position, parser); - } else { - result = decode4(position, parser); - } - - if (channel != null) { - if (pattern == PATTERN4) { - String response = "$$0014AA" + sentence.substring(sentence.length() - 6, sentence.length() - 2); - response += String.format("%02X", Checksum.xor(response)).toUpperCase(); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } else { - channel.writeAndFlush(new NetworkMessage("ACK OK\r\n", remoteAddress)); - } - } - - return result ? position : null; - } - -} diff --git a/src/org/traccar/protocol/TotemProtocolEncoder.java b/src/org/traccar/protocol/TotemProtocolEncoder.java deleted file mode 100644 index b5049859d..000000000 --- a/src/org/traccar/protocol/TotemProtocolEncoder.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 Irving Gonzalez - * Copyright 2015 - 2016 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class TotemProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - initDevicePassword(command, "000000"); - - switch (command.getType()) { - // Assuming PIN 8 (Output C) is the power wire, like manual says but it can be PIN 5,7,8 - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "*{%s},025,C,1#", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "*{%s},025,C,0#", Command.KEY_DEVICE_PASSWORD); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Tr20Protocol.java b/src/org/traccar/protocol/Tr20Protocol.java deleted file mode 100644 index 3eee9d9c3..000000000 --- a/src/org/traccar/protocol/Tr20Protocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Tr20Protocol extends BaseProtocol { - - public Tr20Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Tr20ProtocolDecoder(Tr20Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Tr20ProtocolDecoder.java b/src/org/traccar/protocol/Tr20ProtocolDecoder.java deleted file mode 100644 index c2e6c381f..000000000 --- a/src/org/traccar/protocol/Tr20ProtocolDecoder.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Tr20ProtocolDecoder extends BaseProtocolDecoder { - - public Tr20ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_PING = new PatternBuilder() - .text("%%") - .expression("[^,]+,") - .number("(d+)") - .compile(); - - private static final Pattern PATTERN_DATA = new PatternBuilder() - .text("%%") - .expression("([^,]+),") // id - .expression("([AL]),") // validity - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([NS])") - .number("(dd)(dd.d+)") // latitude - .expression("([EW])") - .number("(ddd)(dd.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(?:NA|[FC]?(-?d+)),") // temperature - .number("(x{8}),") // status - .number("(d+)") // event - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN_PING, (String) msg); - if (parser.matches()) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - "&&" + parser.next() + "\r\n", remoteAddress)); // keep-alive response - } - return null; - } - - parser = new Parser(PATTERN_DATA, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.next().equals("A")); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextDouble()); - - position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); - position.set(Position.KEY_STATUS, parser.nextHexLong()); - position.set(Position.KEY_EVENT, parser.nextInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/Tr900Protocol.java b/src/org/traccar/protocol/Tr900Protocol.java deleted file mode 100644 index b70521b35..000000000 --- a/src/org/traccar/protocol/Tr900Protocol.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Tr900Protocol extends BaseProtocol { - - public Tr900Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Tr900ProtocolDecoder(Tr900Protocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Tr900ProtocolDecoder(Tr900Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Tr900ProtocolDecoder.java b/src/org/traccar/protocol/Tr900ProtocolDecoder.java deleted file mode 100644 index 319194c21..000000000 --- a/src/org/traccar/protocol/Tr900ProtocolDecoder.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Tr900ProtocolDecoder extends BaseProtocolDecoder { - - public Tr900ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number(">(d+),") // id - .number("d+,") // period - .number("(d),") // fix - .number("(dd)(dd)(dd),") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([EW])") - .number("(ddd)(dd.d+),") // longitude - .expression("([NS])") - .number("(dd)(dd.d+),") // latitude - .expression("[^,]*,") // command - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(d+),") // gsm - .number("(d+),") // event - .number("(d+)-") // adc - .number("(d+),") // battery - .number("d+,") // impulses - .number("(d+),") // input - .number("(d+)") // status - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(parser.nextInt(0) == 1); - - position.setTime(parser.nextDateTime()); - - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN)); - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_RSSI, parser.nextDouble()); - position.set(Position.KEY_EVENT, parser.nextInt(0)); - position.set(Position.PREFIX_ADC + 1, parser.nextInt(0)); - position.set(Position.KEY_BATTERY, parser.nextInt(0)); - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_STATUS, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/TrackboxProtocol.java b/src/org/traccar/protocol/TrackboxProtocol.java deleted file mode 100644 index 5da5abd64..000000000 --- a/src/org/traccar/protocol/TrackboxProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TrackboxProtocol extends BaseProtocol { - - public TrackboxProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new TrackboxProtocolDecoder(TrackboxProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TrackboxProtocolDecoder.java b/src/org/traccar/protocol/TrackboxProtocolDecoder.java deleted file mode 100644 index db8022738..000000000 --- a/src/org/traccar/protocol/TrackboxProtocolDecoder.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class TrackboxProtocolDecoder extends BaseProtocolDecoder { - - public TrackboxProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(dd)(dd)(dd).(ddd),") // time (hhmmss.sss) - .number("(dd)(dd.dddd)([NS]),") // latitude - .number("(ddd)(dd.dddd)([EW]),") // longitude - .number("(d+.d),") // hdop - .number("(-?d+.?d*),") // altitude - .number("(d),") // fix type - .number("(d+.d+),") // course - .number("d+.d+,") // speed (kph) - .number("(d+.d+),") // speed (knots) - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(d+)") // satellites - .compile(); - - private void sendResponse(Channel channel, SocketAddress remoteAddress) { - if (channel != null) { - channel.writeAndFlush(new NetworkMessage("=OK=\r\n", remoteAddress)); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("a=connect")) { - String id = sentence.substring(sentence.indexOf("i=") + 2); - if (getDeviceSession(channel, remoteAddress, id) != null) { - sendResponse(channel, remoteAddress); - } - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - sendResponse(channel, remoteAddress); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - position.set(Position.KEY_HDOP, parser.nextDouble()); - - position.setAltitude(parser.nextDouble(0)); - - int fix = parser.nextInt(0); - position.set(Position.KEY_GPS, fix); - position.setValid(fix > 0); - - position.setCourse(parser.nextDouble(0)); - position.setSpeed(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/TrakMateProtocol.java b/src/org/traccar/protocol/TrakMateProtocol.java deleted file mode 100644 index bda5df10f..000000000 --- a/src/org/traccar/protocol/TrakMateProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TrakMateProtocol extends BaseProtocol { - - public TrakMateProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new TrakMateProtocolDecoder(TrakMateProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TrakMateProtocolDecoder.java b/src/org/traccar/protocol/TrakMateProtocolDecoder.java deleted file mode 100644 index 4d5cb18f5..000000000 --- a/src/org/traccar/protocol/TrakMateProtocolDecoder.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class TrakMateProtocolDecoder extends BaseProtocolDecoder { - - public TrakMateProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_SRT = new PatternBuilder() - .text("^TMSRT|") - .expression("([^ ]+)|") // uid - .number("(d+.d+)|") // latitude - .number("(d+.d+)|") // longitude - .number("(dd)(dd)(dd)|") // time (hhmmss) - .number("(dd)(dd)(dd)|") // date (ddmmyy) - .number("(d+.d+)|") // software ver - .number("(d+.d+)|") // Hardware ver - .any() - .compile(); - - private static final Pattern PATTERN_PER = new PatternBuilder() - .text("^TM") - .expression("...|") // type - .expression("([^ ]+)|") // uid - .number("(d+)|") // seq - .number("(d+.d+)|") // latitude - .number("(d+.d+)|") // longitude - .number("(dd)(dd)(dd)|") // time (hhmmss) - .number("(dd)(dd)(dd)|") // date (ddmmyy) - .number("(d+.d+)|") // speed - .number("(d+.d+)|") // heading - .number("(d+)|").optional() // satellites - .number("([01])|") // ignition - .groupBegin() - .number("(d+)|") // dop1 - .number("(d+)|") // dop2 - .number("(d+.d+)|") // analog - .number("(d+.d+)|") // internal battery - .or() - .number("-?d+ -?d+ -?d+|") // accelerometer - .number("([01])|") // movement - .groupEnd() - .number("(d+.d+)|") // vehicle battery - .number("(d+.d+)|") // gps odometer - .number("(d+.d+)|").optional() // pulse odometer - .number("([01])|") // main power status - .number("([01])|") // gps data validity - .number("([01])|") // live or cache - .any() - .compile(); - - private static final Pattern PATTERN_ALT = new PatternBuilder() - .text("^TMALT|") - .expression("([^ ]+)|") // uid - .number("(d+)|") // seq - .number("(d+)|") // Alert type - .number("(d+)|") // Alert status - .number("(d+.d+)|") // latitude - .number("(d+.d+)|") // longitude - .number("(dd)(dd)(dd)|") // time (hhmmss) - .number("(dd)(dd)(dd)|") // date (ddmmyy) - .number("(d+.d+)|") // speed - .number("(d+.d+)|") // heading - .any() - .compile(); - - private String decodeAlarm(int value) { - switch (value) { - case 1: - return Position.ALARM_SOS; - case 3: - return Position.ALARM_GEOFENCE; - case 4: - return Position.ALARM_POWER_CUT; - default: - return null; - } - } - - private Object decodeSrt(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_SRT, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - position.set(Position.KEY_VERSION_FW, parser.next()); - position.set(Position.KEY_VERSION_HW, parser.next()); - - return position; - } - - private Object decodeAlt(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN_ALT, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - parser.next(); // seq - position.set(Position.KEY_ALARM, decodeAlarm(parser.nextInt())); - parser.next(); // alert status or data - - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - position.setSpeed(parser.nextDouble()); - position.setCourse(parser.nextDouble()); - - return position; - } - - private Object decodePer(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN_PER, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - parser.next(); // seq - - position.setLatitude(parser.nextDouble()); - position.setLongitude(parser.nextDouble()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - position.setSpeed(parser.nextDouble()); - position.setCourse(parser.nextDouble()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_IGNITION, parser.nextInt() > 0); - - if (parser.hasNext(4)) { - position.set("dop1", parser.nextInt()); - position.set("dop2", parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - } - - if (parser.hasNext()) { - position.set(Position.KEY_MOTION, parser.nextInt(0) > 0); - } - - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextDouble()); - position.set("pulseOdometer", parser.nextDouble()); - position.set(Position.KEY_STATUS, parser.nextInt()); - - position.setValid(parser.nextInt() > 0); - - position.set(Position.KEY_ARCHIVE, parser.nextInt() > 0); - - return position; - } - - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - int typeIndex = sentence.indexOf("^TM"); - if (typeIndex < 0) { - return null; - } - - String type = sentence.substring(typeIndex + 3, typeIndex + 6); - switch (type) { - case "ALT": - return decodeAlt(channel, remoteAddress, sentence); - case "SRT": - return decodeSrt(channel, remoteAddress, sentence); - default: - return decodePer(channel, remoteAddress, sentence); - } - } - -} diff --git a/src/org/traccar/protocol/TramigoFrameDecoder.java b/src/org/traccar/protocol/TramigoFrameDecoder.java deleted file mode 100644 index aaaaccb60..000000000 --- a/src/org/traccar/protocol/TramigoFrameDecoder.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class TramigoFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode(ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 20) { - return null; - } - - int length; - if (buf.getUnsignedByte(buf.readerIndex()) == 0x80) { - length = buf.getUnsignedShortLE(buf.readerIndex() + 6); - } else { - length = buf.getUnsignedShort(buf.readerIndex() + 6); - } - - if (length >= buf.readableBytes()) { - return buf.readRetainedSlice(length); - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TramigoProtocol.java b/src/org/traccar/protocol/TramigoProtocol.java deleted file mode 100644 index f683ccc5d..000000000 --- a/src/org/traccar/protocol/TramigoProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TramigoProtocol extends BaseProtocol { - - public TramigoProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TramigoFrameDecoder()); - pipeline.addLast(new TramigoProtocolDecoder(TramigoProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TramigoProtocolDecoder.java b/src/org/traccar/protocol/TramigoProtocolDecoder.java deleted file mode 100644 index e42e2f670..000000000 --- a/src/org/traccar/protocol/TramigoProtocolDecoder.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class TramigoProtocolDecoder extends BaseProtocolDecoder { - - public TramigoProtocolDecoder(Protocol protocol) { - super(protocol); - } - - public static final int MSG_COMPACT = 0x0100; - public static final int MSG_FULL = 0x00FE; - - private static final String[] DIRECTIONS = new String[] {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}; - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - int protocol = buf.readUnsignedByte(); - boolean legacy = protocol == 0x80; - - buf.readUnsignedByte(); // version id - int index = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE(); - int type = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE(); - buf.readUnsignedShort(); // length - buf.readUnsignedShort(); // mask - buf.readUnsignedShort(); // checksum - long id = legacy ? buf.readUnsignedInt() : buf.readUnsignedIntLE(); - buf.readUnsignedInt(); // time - - Position position = new Position(getProtocolName()); - position.set(Position.KEY_INDEX, index); - position.setValid(true); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id)); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - if (protocol == 0x01 && (type == MSG_COMPACT || type == MSG_FULL)) { - - // need to send ack? - - buf.readUnsignedShortLE(); // report trigger - buf.readUnsignedShortLE(); // state flag - - position.setLatitude(buf.readUnsignedIntLE() * 0.0000001); - position.setLongitude(buf.readUnsignedIntLE() * 0.0000001); - - position.set(Position.KEY_RSSI, buf.readUnsignedShortLE()); - position.set(Position.KEY_SATELLITES, buf.readUnsignedShortLE()); - position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedShortLE()); - position.set("gpsAntennaStatus", buf.readUnsignedShortLE()); - - position.setSpeed(buf.readUnsignedShortLE() * 0.194384); - position.setCourse(buf.readUnsignedShortLE()); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE()); - - position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE()); - - position.set(Position.KEY_CHARGE, buf.readUnsignedShortLE()); - - position.setTime(new Date(buf.readUnsignedIntLE() * 1000)); - - // parse other data - - return position; - - } else if (legacy) { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage( - Unpooled.copiedBuffer("gprs,ack," + index, StandardCharsets.US_ASCII), remoteAddress)); - } - - String sentence = buf.toString(StandardCharsets.US_ASCII); - - Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)"); - Matcher matcher = pattern.matcher(sentence); - if (!matcher.find()) { - return null; - } - position.setLatitude(Double.parseDouble(matcher.group(1))); - position.setLongitude(Double.parseDouble(matcher.group(2))); - - pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h"); - matcher = pattern.matcher(sentence); - if (matcher.find()) { - for (int i = 0; i < DIRECTIONS.length; i++) { - if (matcher.group(1).equals(DIRECTIONS[i])) { - position.setCourse(i * 45.0); - break; - } - } - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(matcher.group(2)))); - } - - pattern = Pattern.compile("(\\d{1,2}:\\d{2}(:\\d{2})? \\w{3} \\d{1,2})"); - matcher = pattern.matcher(sentence); - if (!matcher.find()) { - return null; - } - DateFormat dateFormat = new SimpleDateFormat( - matcher.group(2) != null ? "HH:mm:ss MMM d yyyy" : "HH:mm MMM d yyyy", Locale.ENGLISH); - position.setTime(DateUtil.correctYear( - dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR)))); - - if (sentence.contains("Ignition on detected")) { - position.set(Position.KEY_IGNITION, true); - } else if (sentence.contains("Ignition off detected")) { - position.set(Position.KEY_IGNITION, false); - } - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/TrvProtocol.java b/src/org/traccar/protocol/TrvProtocol.java deleted file mode 100644 index 99a164cf1..000000000 --- a/src/org/traccar/protocol/TrvProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TrvProtocol extends BaseProtocol { - - public TrvProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new TrvProtocolDecoder(TrvProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TrvProtocolDecoder.java b/src/org/traccar/protocol/TrvProtocolDecoder.java deleted file mode 100644 index b63385187..000000000 --- a/src/org/traccar/protocol/TrvProtocolDecoder.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; -import org.traccar.model.WifiAccessPoint; - -import java.net.SocketAddress; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.regex.Pattern; - -public class TrvProtocolDecoder extends BaseProtocolDecoder { - - public TrvProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("[A-Z]{2,3}") - .number("APdd") - .number("(dd)(dd)(dd)") // date (yymmdd) - .expression("([AV])") // validity - .number("(dd)(dd.d+)") // latitude - .expression("([NS])") - .number("(ddd)(dd.d+)") // longitude - .expression("([EW])") - .number("(ddd.d)") // speed - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("([d.]{6})") // course - .number("(ddd)") // gsm - .number("(ddd)") // satellites - .number("(ddd)") // battery - .number("(d)") // acc - .number("(dd)") // arm status - .number("(dd),") // working mode - .number("(d+),") // mcc - .number("(d+),") // mnc - .number("(d+),") // lac - .number("(d+)") // cell - .any() - .compile(); - - private static final Pattern PATTERN_HEATRBEAT = new PatternBuilder() - .expression("[A-Z]{2,3}") - .text("CP01,") - .number("(ddd)") // gsm - .number("(ddd)") // gps - .number("(ddd)") // battery - .number("(d)") // acc - .number("(dd)") // arm status - .number("(dd)") // working mode - .groupBegin() - .number("(ddd)") // interval - .number("d") // vibration alarm - .number("ddd") // vibration sensitivity - .number("d") // automatic arm - .number("dddd") // automatic arm time - .number("(d)") // blocked - .number("(d)") // power status - .number("(d)") // movement status - .groupEnd("?") - .any() - .compile(); - - private static final Pattern PATTERN_LBS = new PatternBuilder() - .expression("[A-Z]{2,3}") - .text("AP02,") - .expression("[^,]+,") // language - .number("[01],") // reply - .number("d+,") // cell count - .number("(d+),") // mcc - .number("(d+),") // mnc - .expression("(") - .groupBegin() - .number("d+|") // lac - .number("d+|") // cid - .number("d+,") // rssi - .groupEnd("+") - .expression(")") - .number("d+,") // wifi count - .expression("(.*)") // wifi - .compile(); - - private Boolean decodeOptionalValue(Parser parser, int activeValue) { - int value = parser.nextInt(); - if (value != 0) { - return value == activeValue; - } - return null; - } - - private void decodeCommon(Position position, Parser parser) { - - position.set(Position.KEY_RSSI, parser.nextInt()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_BATTERY, parser.nextInt()); - position.set(Position.KEY_IGNITION, decodeOptionalValue(parser, 1)); - position.set(Position.KEY_ARMED, decodeOptionalValue(parser, 1)); - - int mode = parser.nextInt(); - if (mode != 0) { - position.set("mode", mode); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - String id = sentence.startsWith("TRV") ? sentence.substring(0, 3) : sentence.substring(0, 2); - String type = sentence.substring(id.length(), id.length() + 4); - - if (channel != null) { - String responseHeader = id + (char) (type.charAt(0) + 1) + type.substring(1); - if (type.equals("AP00") && id.equals("IW")) { - String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); - channel.writeAndFlush(new NetworkMessage(responseHeader + "," + time + ",0#", remoteAddress)); - } else if (type.equals("AP14")) { - channel.writeAndFlush(new NetworkMessage(responseHeader + ",0.000,0.000#", remoteAddress)); - } else { - channel.writeAndFlush(new NetworkMessage(responseHeader + "#", remoteAddress)); - } - } - - if (type.equals("AP00")) { - getDeviceSession(channel, remoteAddress, sentence.substring(id.length() + type.length())); - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - if (type.equals("CP01")) { - - Parser parser = new Parser(PATTERN_HEATRBEAT, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - decodeCommon(position, parser); - - if (parser.hasNext(3)) { - position.set(Position.KEY_BLOCKED, decodeOptionalValue(parser, 2)); - position.set(Position.KEY_CHARGE, decodeOptionalValue(parser, 1)); - position.set(Position.KEY_MOTION, decodeOptionalValue(parser, 1)); - } - - return position; - - } else if (type.equals("AP01") || type.equals("AP10")) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - - dateBuilder.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - position.setCourse(parser.nextDouble()); - - decodeCommon(position, parser); - - position.setNetwork(new Network(CellTower.from( - parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt()))); - - return position; - - } else if (type.equals("AP02")) { - - Parser parser = new Parser(PATTERN_LBS, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - int mcc = parser.nextInt(); - int mnc = parser.nextInt(); - - Network network = new Network(); - - for (String cell : parser.next().split(",")) { - if (!cell.isEmpty()) { - String[] values = cell.split("\\|"); - network.addCellTower(CellTower.from( - mcc, mnc, - Integer.parseInt(values[0]), - Integer.parseInt(values[1]), - Integer.parseInt(values[2]))); - } - } - - for (String wifi : parser.next().split("&")) { - if (!wifi.isEmpty()) { - String[] values = wifi.split("\\|"); - network.addWifiAccessPoint(WifiAccessPoint.from(values[1], Integer.parseInt(values[2]))); - } - } - - position.setNetwork(network); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Tt8850Protocol.java b/src/org/traccar/protocol/Tt8850Protocol.java deleted file mode 100644 index 66a13da9e..000000000 --- a/src/org/traccar/protocol/Tt8850Protocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Tt8850Protocol extends BaseProtocol { - - public Tt8850Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "$")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Tt8850ProtocolDecoder(Tt8850Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Tt8850ProtocolDecoder.java b/src/org/traccar/protocol/Tt8850ProtocolDecoder.java deleted file mode 100644 index 1010528c4..000000000 --- a/src/org/traccar/protocol/Tt8850ProtocolDecoder.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Tt8850ProtocolDecoder extends BaseProtocolDecoder { - - public Tt8850ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .binary("0004,") - .number("xxxx,") - .expression("[01],") - .expression("GT...,") - .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version - .expression("([^,]+),") // imei - .any() - .number("(d{1,2})?,") // gps accuracy - .number("(d{1,3}.d)?,") // speed - .number("(d{1,3})?,") // course - .number("(-?d{1,5}.d)?,") // altitude - .number("(-?d{1,3}.d{6}),") // longitude - .number("(-?d{1,2}.d{6}),") // latitude - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(0ddd)?,") // mcc - .number("(0ddd)?,") // mnc - .number("(xxxx)?,") // lac - .number("(xxxx)?,") // cell - .any() - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(xxxx)") - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setValid(true); - position.setAccuracy(parser.nextInt(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setLatitude(parser.nextDouble(0)); - - position.setTime(parser.nextDateTime()); - - if (parser.hasNext(4)) { - position.setNetwork(new Network( - CellTower.from(parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0)))); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/TytanProtocol.java b/src/org/traccar/protocol/TytanProtocol.java deleted file mode 100644 index 32e9acae1..000000000 --- a/src/org/traccar/protocol/TytanProtocol.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class TytanProtocol extends BaseProtocol { - - public TytanProtocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new TytanProtocolDecoder(TytanProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TytanProtocolDecoder.java b/src/org/traccar/protocol/TytanProtocolDecoder.java deleted file mode 100644 index 93d3a63d2..000000000 --- a/src/org/traccar/protocol/TytanProtocolDecoder.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -public class TytanProtocolDecoder extends BaseProtocolDecoder { - - public TytanProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private void decodeExtraData(Position position, ByteBuf buf, int end) { - while (buf.readerIndex() < end) { - - int type = buf.readUnsignedByte(); - int length = buf.readUnsignedByte(); - if (length == 255) { - length += buf.readUnsignedByte(); - } - - int n; - - switch (type) { - case 2: - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedMedium()); - break; - case 5: - position.set(Position.KEY_INPUT, buf.readUnsignedByte()); - break; - case 6: - n = buf.readUnsignedByte() >> 4; - if (n < 2) { - position.set(Position.PREFIX_ADC + n, buf.readFloat()); - } else { - position.set("di" + (n - 2), buf.readFloat()); - } - break; - case 7: - int alarm = buf.readUnsignedByte(); - buf.readUnsignedByte(); - if (BitUtil.check(alarm, 5)) { - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - } - break; - case 8: - position.set("antihijack", buf.readUnsignedByte()); - break; - case 9: - position.set("unauthorized", ByteBufUtil.hexDump(buf.readSlice(8))); - break; - case 10: - position.set("authorized", ByteBufUtil.hexDump(buf.readSlice(8))); - break; - case 24: - for (int i = 0; i < length / 2; i++) { - position.set(Position.PREFIX_TEMP + buf.readUnsignedByte(), buf.readByte()); - } - break; - case 28: - position.set(Position.KEY_AXLE_WEIGHT, buf.readUnsignedShort()); - buf.readUnsignedByte(); - break; - case 90: - position.set(Position.KEY_POWER, buf.readFloat()); - break; - case 101: - position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte()); - break; - case 102: - position.set(Position.KEY_RPM, buf.readUnsignedByte() * 50); - break; - case 107: - int fuel = buf.readUnsignedShort(); - int fuelFormat = fuel >> 14; - if (fuelFormat == 1) { - position.set("fuelValue", (fuel & 0x3fff) * 0.4 + "%"); - } else if (fuelFormat == 2) { - position.set("fuelValue", (fuel & 0x3fff) * 0.5 + " l"); - } else if (fuelFormat == 3) { - position.set("fuelValue", (fuel & 0x3fff) * -0.5 + " l"); - } - break; - case 108: - position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 5); - break; - case 150: - position.set(Position.KEY_DOOR, buf.readUnsignedByte()); - break; - default: - buf.skipBytes(length); - break; - } - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.readUnsignedByte(); // protocol - buf.readUnsignedShort(); // length - int index = buf.readUnsignedByte() >> 3; - - if (channel != null) { - ByteBuf response = Unpooled.copiedBuffer("^" + index, StandardCharsets.US_ASCII); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - String id = String.valueOf(buf.readUnsignedInt()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - List positions = new LinkedList<>(); - - while (buf.readableBytes() > 2) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - int end = buf.readerIndex() + buf.readUnsignedByte(); - - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - - int flags = buf.readUnsignedByte(); - position.set(Position.KEY_SATELLITES, BitUtil.from(flags, 2)); - position.setValid(BitUtil.to(flags, 2) > 0); - - // Latitude - double lat = buf.readUnsignedMedium(); - lat = lat * -180 / 16777216 + 90; - position.setLatitude(lat); - - // Longitude - double lon = buf.readUnsignedMedium(); - lon = lon * 360 / 16777216 - 180; - position.setLongitude(lon); - - // Status - flags = buf.readUnsignedByte(); - position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0)); - position.set(Position.KEY_RSSI, BitUtil.between(flags, 2, 5)); - position.setCourse((BitUtil.from(flags, 5) * 45 + 180) % 360); - - // Speed - int speed = buf.readUnsignedByte(); - if (speed < 250) { - position.setSpeed(UnitsConverter.knotsFromKph(speed)); - } - - decodeExtraData(position, buf, end); - - positions.add(position); - } - - return positions; - } - -} diff --git a/src/org/traccar/protocol/TzoneProtocol.java b/src/org/traccar/protocol/TzoneProtocol.java deleted file mode 100644 index 6e855d138..000000000 --- a/src/org/traccar/protocol/TzoneProtocol.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import io.netty.handler.codec.LengthFieldBasedFrameDecoder; - -public class TzoneProtocol extends BaseProtocol { - - public TzoneProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 2, 2, 0)); - pipeline.addLast(new TzoneProtocolDecoder(TzoneProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/TzoneProtocolDecoder.java b/src/org/traccar/protocol/TzoneProtocolDecoder.java deleted file mode 100644 index 87b44a4b2..000000000 --- a/src/org/traccar/protocol/TzoneProtocolDecoder.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; - -public class TzoneProtocolDecoder extends BaseProtocolDecoder { - - public TzoneProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private String decodeAlarm(Short value) { - switch (value) { - case 0x01: - return Position.ALARM_SOS; - case 0x10: - return Position.ALARM_LOW_BATTERY; - case 0x11: - return Position.ALARM_OVERSPEED; - case 0x14: - return Position.ALARM_BRAKING; - case 0x15: - return Position.ALARM_ACCELERATION; - case 0x30: - return Position.ALARM_PARKING; - case 0x42: - return Position.ALARM_GEOFENCE_EXIT; - case 0x43: - return Position.ALARM_GEOFENCE_ENTER; - default: - return null; - } - } - - private boolean decodeGps(Position position, ByteBuf buf, int hardware) { - - int blockLength = buf.readUnsignedShort(); - int blockEnd = buf.readerIndex() + blockLength; - - if (blockLength < 22) { - return false; - } - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - - double lat; - double lon; - - if (hardware == 0x10A || hardware == 0x10B) { - lat = buf.readUnsignedInt() / 600000.0; - lon = buf.readUnsignedInt() / 600000.0; - } else { - lat = buf.readUnsignedInt() / 100000.0 / 60.0; - lon = buf.readUnsignedInt() / 100000.0 / 60.0; - } - - position.setFixTime(new DateBuilder() - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); - - position.setSpeed(buf.readUnsignedShort() * 0.01); - - position.set(Position.KEY_ODOMETER, buf.readUnsignedMedium()); - - int flags = buf.readUnsignedShort(); - position.setCourse(BitUtil.to(flags, 9)); - if (!BitUtil.check(flags, 10)) { - lat = -lat; - } - position.setLatitude(lat); - if (BitUtil.check(flags, 9)) { - lon = -lon; - } - position.setLongitude(lon); - position.setValid(BitUtil.check(flags, 11)); - - buf.readerIndex(blockEnd); - - return true; - } - - private void decodeCards(Position position, ByteBuf buf) { - - int index = 1; - for (int i = 0; i < 4; i++) { - - int blockLength = buf.readUnsignedShort(); - int blockEnd = buf.readerIndex() + blockLength; - - if (blockLength > 0) { - - int count = buf.readUnsignedByte(); - for (int j = 0; j < count; j++) { - - int length = buf.readUnsignedByte(); - - boolean odd = length % 2 != 0; - if (odd) { - length += 1; - } - - String num = ByteBufUtil.hexDump(buf.readSlice(length / 2)); - - if (odd) { - num = num.substring(1); - } - - position.set("card" + index, num); - } - } - - buf.readerIndex(blockEnd); - } - - } - - private void decodePassengers(Position position, ByteBuf buf) { - - int blockLength = buf.readUnsignedShort(); - int blockEnd = buf.readerIndex() + blockLength; - - if (blockLength > 0) { - - position.set("passengersOn", buf.readUnsignedMedium()); - position.set("passengersOff", buf.readUnsignedMedium()); - - } - - buf.readerIndex(blockEnd); - - } - - private void decodeTags(Position position, ByteBuf buf) { - - int blockLength = buf.readUnsignedShort(); - int blockEnd = buf.readerIndex() + blockLength; - - if (blockLength > 0) { - - buf.readUnsignedByte(); // tag type - - int count = buf.readUnsignedByte(); - int tagLength = buf.readUnsignedByte(); - - for (int i = 1; i <= count; i++) { - int tagEnd = buf.readerIndex() + tagLength; - - buf.readUnsignedByte(); // status - buf.readUnsignedShortLE(); // battery voltage - - position.set(Position.PREFIX_TEMP + i, (buf.readShortLE() & 0x3fff) * 0.1); - - buf.readUnsignedByte(); // humidity - buf.readUnsignedByte(); // rssi - - buf.readerIndex(tagEnd); - } - - } - - buf.readerIndex(blockEnd); - - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(2); // header - buf.readUnsignedShort(); // length - if (buf.readUnsignedShort() != 0x2424) { - return null; - } - int hardware = buf.readUnsignedShort(); - long firmware = buf.readUnsignedInt(); - - String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_VERSION_HW, hardware); - position.set(Position.KEY_VERSION_FW, firmware); - - position.setDeviceTime(new DateBuilder() - .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()) - .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()).getDate()); - - // GPS info - - if (hardware == 0x406 || !decodeGps(position, buf, hardware)) { - - getLastLocation(position, position.getDeviceTime()); - - } - - // LBS info - - int blockLength = buf.readUnsignedShort(); - int blockEnd = buf.readerIndex() + blockLength; - - if (blockLength > 0 && (hardware == 0x10A || hardware == 0x10B || hardware == 0x406)) { - position.setNetwork(new Network( - CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort()))); - } - - buf.readerIndex(blockEnd); - - // Status info - - blockLength = buf.readUnsignedShort(); - blockEnd = buf.readerIndex() + blockLength; - - if (blockLength >= 13) { - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); - position.set("terminalInfo", buf.readUnsignedByte()); - - int status = buf.readUnsignedByte(); - position.set(Position.PREFIX_OUT + 1, BitUtil.check(status, 0)); - position.set(Position.PREFIX_OUT + 2, BitUtil.check(status, 1)); - status = buf.readUnsignedByte(); - position.set(Position.PREFIX_IN + 1, BitUtil.check(status, 4)); - if (BitUtil.check(status, 0)) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set("gsmStatus", buf.readUnsignedByte()); - position.set(Position.KEY_BATTERY, buf.readUnsignedShort()); - position.set(Position.KEY_POWER, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort()); - position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort()); - } - - if (blockLength >= 15) { - position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort()); - } - - buf.readerIndex(blockEnd); - - if (hardware == 0x10B) { - - decodeCards(position, buf); - - buf.skipBytes(buf.readUnsignedShort()); // temperature - buf.skipBytes(buf.readUnsignedShort()); // lock - - decodePassengers(position, buf); - - } - - if (hardware == 0x406) { - - decodeTags(position, buf); - - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/UlbotechFrameDecoder.java b/src/org/traccar/protocol/UlbotechFrameDecoder.java deleted file mode 100644 index f141dc9b7..000000000 --- a/src/org/traccar/protocol/UlbotechFrameDecoder.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 org.traccar.BaseFrameDecoder; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class UlbotechFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 2) { - return null; - } - - if (buf.getUnsignedByte(buf.readerIndex()) == 0xF8) { - - int index = buf.indexOf(buf.readerIndex() + 1, buf.writerIndex(), (byte) 0xF8); - if (index != -1) { - ByteBuf result = Unpooled.buffer(index + 1 - buf.readerIndex()); - - while (buf.readerIndex() <= index) { - int b = buf.readUnsignedByte(); - if (b == 0xF7) { - int ext = buf.readUnsignedByte(); - if (ext == 0x00) { - result.writeByte(0xF7); - } else if (ext == 0x0F) { - result.writeByte(0xF8); - } - } else { - result.writeByte(b); - } - } - - return result; - } - - } else { - - int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '#'); - if (index != -1) { - return buf.readRetainedSlice(index + 1 - buf.readerIndex()); - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/UlbotechProtocol.java b/src/org/traccar/protocol/UlbotechProtocol.java deleted file mode 100644 index b99ec1cc6..000000000 --- a/src/org/traccar/protocol/UlbotechProtocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class UlbotechProtocol extends BaseProtocol { - - public UlbotechProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new UlbotechFrameDecoder()); - pipeline.addLast(new UlbotechProtocolDecoder(UlbotechProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/org/traccar/protocol/UlbotechProtocolDecoder.java deleted file mode 100644 index 0a2a59e23..000000000 --- a/src/org/traccar/protocol/UlbotechProtocolDecoder.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -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.DateBuilder; -import org.traccar.helper.ObdDecoder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.regex.Pattern; - -public class UlbotechProtocolDecoder extends BaseProtocolDecoder { - - public UlbotechProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final short DATA_GPS = 0x01; - private static final short DATA_LBS = 0x02; - private static final short DATA_STATUS = 0x03; - private static final short DATA_ODOMETER = 0x04; - private static final short DATA_ADC = 0x05; - private static final short DATA_GEOFENCE = 0x06; - private static final short DATA_OBD2 = 0x07; - private static final short DATA_FUEL = 0x08; - private static final short DATA_OBD2_ALARM = 0x09; - private static final short DATA_HARSH_DRIVER = 0x0A; - private static final short DATA_CANBUS = 0x0B; - private static final short DATA_J1708 = 0x0C; - private static final short DATA_VIN = 0x0D; - private static final short DATA_RFID = 0x0E; - private static final short DATA_EVENT = 0x10; - - private void decodeObd(Position position, ByteBuf buf, int length) { - - int end = buf.readerIndex() + length; - - while (buf.readerIndex() < end) { - int parameterLength = buf.getUnsignedByte(buf.readerIndex()) >> 4; - int mode = buf.readUnsignedByte() & 0x0F; - position.add(ObdDecoder.decode(mode, ByteBufUtil.hexDump(buf.readSlice(parameterLength - 1)))); - } - } - - private void decodeJ1708(Position position, ByteBuf buf, int length) { - - int end = buf.readerIndex() + length; - - while (buf.readerIndex() < end) { - int mark = buf.readUnsignedByte(); - int len = BitUtil.between(mark, 0, 6); - int type = BitUtil.between(mark, 6, 8); - int id = buf.readUnsignedByte(); - if (type == 3) { - id += 256; - } - String value = ByteBufUtil.hexDump(buf.readSlice(len - 1)); - if (type == 2 || type == 3) { - position.set("pid" + id, value); - } - } - } - - private void decodeDriverBehavior(Position position, ByteBuf buf) { - - int value = buf.readUnsignedByte(); - - if (BitUtil.check(value, 0)) { - position.set("rapidAcceleration", true); - } - if (BitUtil.check(value, 1)) { - position.set("roughBraking", true); - } - if (BitUtil.check(value, 2)) { - position.set("harshCourse", true); - } - if (BitUtil.check(value, 3)) { - position.set("noWarmUp", true); - } - if (BitUtil.check(value, 4)) { - position.set("longIdle", true); - } - if (BitUtil.check(value, 5)) { - position.set("fatigueDriving", true); - } - if (BitUtil.check(value, 6)) { - position.set("roughTerrain", true); - } - if (BitUtil.check(value, 7)) { - position.set("highRpm", true); - } - } - - private String decodeAlarm(int alarm) { - if (BitUtil.check(alarm, 0)) { - return Position.ALARM_POWER_OFF; - } - if (BitUtil.check(alarm, 1)) { - return Position.ALARM_MOVEMENT; - } - if (BitUtil.check(alarm, 2)) { - return Position.ALARM_OVERSPEED; - } - if (BitUtil.check(alarm, 4)) { - return Position.ALARM_GEOFENCE; - } - if (BitUtil.check(alarm, 10)) { - return Position.ALARM_SOS; - } - return null; - } - - private void decodeAdc(Position position, ByteBuf buf, int length) { - for (int i = 0; i < length / 2; i++) { - int value = buf.readUnsignedShort(); - int id = BitUtil.from(value, 12); - value = BitUtil.to(value, 12); - switch (id) { - case 0: - position.set(Position.KEY_POWER, value * (100 + 10) / 4096.0 - 10); - break; - case 1: - position.set(Position.PREFIX_TEMP + 1, value * (125 + 55) / 4096.0 - 55); - break; - case 2: - position.set(Position.KEY_BATTERY, value * (100 + 10) / 4096.0 - 10); - break; - case 3: - position.set(Position.PREFIX_ADC + 1, value * (100 + 10) / 4096.0 - 10); - break; - default: - position.set(Position.PREFIX_IO + id, value); - break; - } - } - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("*TS") - .number("dd,") // protocol version - .number("(d{15}),") // device id - .number("(dd)(dd)(dd)") // time - .number("(dd)(dd)(dd),") // date - .expression("([^#]+)") // command - .text("#") - .compile(); - - private Object decodeText(Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)) - .setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - getLastLocation(position, dateBuilder.getDate()); - - position.set(Position.KEY_RESULT, parser.next()); - - return position; - } - - private Object decodeBinary(Channel channel, SocketAddress remoteAddress, ByteBuf buf) { - - buf.readUnsignedByte(); // header - buf.readUnsignedByte(); // version - buf.readUnsignedByte(); // type - - String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - if (deviceSession.getTimeZone() == null) { - deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId())); - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - long seconds = buf.readUnsignedInt() & 0x7fffffffL; - seconds += 946684800L; // 2000-01-01 00:00 - seconds -= deviceSession.getTimeZone().getRawOffset() / 1000; - Date time = new Date(seconds * 1000); - - boolean hasLocation = false; - - while (buf.readableBytes() > 3) { - - int type = buf.readUnsignedByte(); - int length = type == DATA_CANBUS ? buf.readUnsignedShort() : buf.readUnsignedByte(); - - switch (type) { - - case DATA_GPS: - hasLocation = true; - position.setValid(true); - position.setLatitude(buf.readInt() / 1000000.0); - position.setLongitude(buf.readInt() / 1000000.0); - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - position.setCourse(buf.readUnsignedShort()); - position.set(Position.KEY_HDOP, buf.readUnsignedShort()); - break; - - case DATA_LBS: - if (length == 11) { - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readUnsignedShort(), buf.readUnsignedInt(), -buf.readUnsignedByte()))); - } else { - position.setNetwork(new Network(CellTower.from( - buf.readUnsignedShort(), buf.readUnsignedShort(), - buf.readUnsignedShort(), buf.readUnsignedShort(), -buf.readUnsignedByte()))); - } - if (length > 9 && length != 11) { - buf.skipBytes(length - 9); - } - break; - - case DATA_STATUS: - int status = buf.readUnsignedShort(); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 9)); - position.set(Position.KEY_STATUS, status); - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedShort())); - break; - - case DATA_ODOMETER: - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt()); - break; - - case DATA_ADC: - decodeAdc(position, buf, length); - break; - - case DATA_GEOFENCE: - position.set("geofenceIn", buf.readUnsignedInt()); - position.set("geofenceAlarm", buf.readUnsignedInt()); - break; - - case DATA_OBD2: - decodeObd(position, buf, length); - break; - - case DATA_FUEL: - position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt() / 10000.0); - break; - - case DATA_OBD2_ALARM: - decodeObd(position, buf, length); - break; - - case DATA_HARSH_DRIVER: - decodeDriverBehavior(position, buf); - break; - - case DATA_CANBUS: - position.set("can", ByteBufUtil.hexDump(buf.readSlice(length))); - break; - - case DATA_J1708: - decodeJ1708(position, buf, length); - break; - - case DATA_VIN: - position.set(Position.KEY_VIN, buf.readSlice(length).toString(StandardCharsets.US_ASCII)); - break; - - case DATA_RFID: - position.set(Position.KEY_DRIVER_UNIQUE_ID, - buf.readSlice(length - 1).toString(StandardCharsets.US_ASCII)); - position.set("authorized", buf.readUnsignedByte() != 0); - break; - - case DATA_EVENT: - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - if (length > 1) { - position.set("eventMask", buf.readUnsignedInt()); - } - break; - - default: - buf.skipBytes(length); - break; - } - } - - if (!hasLocation) { - getLastLocation(position, time); - } else { - position.setTime(time); - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (buf.getUnsignedByte(buf.readerIndex()) == 0xF8) { - - if (channel != null) { - ByteBuf response = Unpooled.buffer(); - response.writeByte(0xF8); - response.writeByte(DATA_GPS); - response.writeByte(0xFE); - response.writeShort(buf.getShort(response.writerIndex() - 1 - 2)); - response.writeShort(Checksum.crc16(Checksum.CRC16_XMODEM, response.nioBuffer(1, 4))); - response.writeByte(0xF8); - channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); - } - - return decodeBinary(channel, remoteAddress, buf); - } else { - - if (channel != null) { - channel.writeAndFlush(new NetworkMessage(Unpooled.copiedBuffer(String.format("*TS01,ACK:%04X#", - Checksum.crc16(Checksum.CRC16_XMODEM, buf.nioBuffer(1, buf.writerIndex() - 2))), - StandardCharsets.US_ASCII), remoteAddress)); - } - - return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII)); - } - } - -} diff --git a/src/org/traccar/protocol/UproProtocol.java b/src/org/traccar/protocol/UproProtocol.java deleted file mode 100644 index 4e60ffeb6..000000000 --- a/src/org/traccar/protocol/UproProtocol.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class UproProtocol extends BaseProtocol { - - public UproProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new UproProtocolDecoder(UproProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/UproProtocolDecoder.java b/src/org/traccar/protocol/UproProtocolDecoder.java deleted file mode 100644 index dc7a9200d..000000000 --- a/src/org/traccar/protocol/UproProtocolDecoder.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -public class UproProtocolDecoder extends BaseProtocolDecoder { - - public UproProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_HEADER = new PatternBuilder() - .text("*") - .expression("(..20)") // head - .expression("([01])") // ack - .number("(d+),") // device id - .expression("(.)") // type - .expression("(.)") // subtype - .any() - .compile(); - - private static final Pattern PATTERN_LOCATION = new PatternBuilder() - .number("(dd)(dd)(dd)") // time (hhmmss) - .number("(dd)(dd)(dddd)") // latitude - .number("(ddd)(dd)(dddd)") // longitude - .number("(d)") // flags - .number("(dd)") // speed - .number("(dd)") // course - .number("(dd)(dd)(dd)") // date (ddmmyy) - .compile(); - - private void decodeLocation(Position position, String data) { - Parser parser = new Parser(PATTERN_LOCATION, data); - if (parser.matches()) { - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(true); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN)); - - int flags = parser.nextInt(0); - position.setValid(BitUtil.check(flags, 0)); - if (!BitUtil.check(flags, 1)) { - position.setLatitude(-position.getLatitude()); - } - if (!BitUtil.check(flags, 2)) { - position.setLongitude(-position.getLongitude()); - } - - position.setSpeed(parser.nextInt(0) * 2); - position.setCourse(parser.nextInt(0) * 10); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (buf.getByte(buf.readerIndex()) != '*') { - return null; - } - - int headerIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&'); - if (headerIndex < 0) { - headerIndex = buf.writerIndex(); - } - String header = buf.readSlice(headerIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII); - - Parser parser = new Parser(PATTERN_HEADER, header); - if (!parser.matches()) { - return null; - } - - String head = parser.next(); - boolean reply = parser.next().equals("1"); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - String type = parser.next(); - String subtype = parser.next(); - - if (reply && channel != null) { - channel.writeAndFlush(new NetworkMessage("*" + head + "Y" + type + subtype + "#", remoteAddress)); - } - - while (buf.isReadable()) { - - buf.readByte(); // skip delimiter - - byte dataType = buf.readByte(); - - int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '&'); - if (delimiterIndex < 0) { - delimiterIndex = buf.writerIndex(); - } - - ByteBuf data = buf.readSlice(delimiterIndex - buf.readerIndex()); - - switch (dataType) { - case 'A': - decodeLocation(position, data.toString(StandardCharsets.US_ASCII)); - break; - case 'B': - position.set(Position.KEY_STATUS, data.toString(StandardCharsets.US_ASCII)); - break; - case 'C': - long odometer = 0; - while (data.isReadable()) { - odometer <<= 4; - odometer += data.readByte() - (byte) '0'; - } - position.set(Position.KEY_ODOMETER, odometer * 2 * 1852 / 3600); - break; - case 'F': - position.setSpeed( - Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1); - break; - case 'K': - position.set("statusExtended", data.toString(StandardCharsets.US_ASCII)); - break; - case 'P': - if (data.readableBytes() >= 16) { - position.setNetwork(new Network(CellTower.from( - Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)), - Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)), - Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16), - Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII), 16)))); - } - break; - case 'Q': - position.set("obdPid", ByteBufUtil.hexDump(data)); - break; - case 'R': - if (head.startsWith("HQ")) { - position.set(Position.KEY_RSSI, - Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); - position.set(Position.KEY_SATELLITES, - Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); - } else { - position.set("odbTravel", ByteBufUtil.hexDump(data)); - } - break; - case 'S': - position.set("obdTraffic", ByteBufUtil.hexDump(data)); - break; - case 'T': - position.set(Position.KEY_BATTERY_LEVEL, - Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII))); - break; - case 'V': - position.set(Position.KEY_POWER, - Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1); - break; - default: - break; - } - - } - - if (position.getLatitude() != 0 && position.getLongitude() != 0) { - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/V680Protocol.java b/src/org/traccar/protocol/V680Protocol.java deleted file mode 100644 index dc0922cd4..000000000 --- a/src/org/traccar/protocol/V680Protocol.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class V680Protocol extends BaseProtocol { - - public V680Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##")); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new V680ProtocolDecoder(V680Protocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new V680ProtocolDecoder(V680Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/V680ProtocolDecoder.java b/src/org/traccar/protocol/V680ProtocolDecoder.java deleted file mode 100644 index 0342404a6..000000000 --- a/src/org/traccar/protocol/V680ProtocolDecoder.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class V680ProtocolDecoder extends BaseProtocolDecoder { - - public V680ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .groupBegin() - .number("#(d+)#") // imei - .expression("([^#]*)#") // user - .groupEnd("?") - .number("(d+)#") // fix - .expression("([^#]+)#") // password - .expression("([^#]+)#") // event - .number("(d+)#") // packet number - .expression("([^#]+)?#?") // gsm base station - .expression("(?:[^#]+#)?") - .number("(d+.d+),([EW]),") // longitude - .number("(d+.d+),([NS]),") // latitude - .number("(d+.d+),") // speed - .number("(d+.?d*)?#") // course - .number("(dd)(dd)(dd)#") // date (ddmmyy) - .number("(dd)(dd)(dd)") // time (hhmmss) - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - sentence = sentence.trim(); - - if (sentence.length() == 16) { - - getDeviceSession(channel, remoteAddress, sentence.substring(1, sentence.length())); - - } else { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession; - if (parser.hasNext()) { - deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - } else { - deviceSession = getDeviceSession(channel, remoteAddress); - } - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.set("user", parser.next()); - position.setValid(parser.nextInt(0) > 0); - position.set("password", parser.next()); - position.set(Position.KEY_EVENT, parser.next()); - position.set("packet", parser.next()); - position.set("lbsData", parser.next()); - - double lon = parser.nextDouble(0); - boolean west = parser.next().equals("W"); - double lat = parser.nextDouble(0); - boolean south = parser.next().equals("S"); - - if (lat > 90 || lon > 180) { - int lonDegrees = (int) (lon * 0.01); - lon = (lon - lonDegrees * 100) / 60.0; - lon += lonDegrees; - - int latDegrees = (int) (lat * 0.01); - lat = (lat - latDegrees * 100) / 60.0; - lat += latDegrees; - } - - position.setLongitude(west ? -lon : lon); - position.setLatitude(south ? -lat : lat); - - position.setSpeed(parser.nextDouble(0)); - position.setCourse(parser.nextDouble(0)); - - int day = parser.nextInt(0); - int month = parser.nextInt(0); - if (day == 0 && month == 0) { - return null; // invalid date - } - - DateBuilder dateBuilder = new DateBuilder() - .setDate(parser.nextInt(0), month, day) - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - return position; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/VisiontekProtocol.java b/src/org/traccar/protocol/VisiontekProtocol.java deleted file mode 100644 index 2c6af45a8..000000000 --- a/src/org/traccar/protocol/VisiontekProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class VisiontekProtocol extends BaseProtocol { - - public VisiontekProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#')); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new VisiontekProtocolDecoder(VisiontekProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/VisiontekProtocolDecoder.java b/src/org/traccar/protocol/VisiontekProtocolDecoder.java deleted file mode 100644 index c4787bda2..000000000 --- a/src/org/traccar/protocol/VisiontekProtocolDecoder.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2014 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class VisiontekProtocolDecoder extends BaseProtocolDecoder { - - public VisiontekProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("$1,") - .expression("([^,]+),") // identifier - .number("(d+),").optional() // imei - .number("(dd),(dd),(dd),") // date (dd,mm,yy) - .number("(dd),(dd),(dd),") // time (hh,mm,ss) - .groupBegin() - .number("(dd)(dd).?(d+)([NS]),") // latitude - .number("(ddd)(dd).?(d+)([EW]),") // longitude - .or() - .number("(dd.d+)([NS]),") // latitude - .number("(ddd.d+)([EW]),") // longitude - .groupEnd() - .number("(d+.?d+),") // speed - .number("(d+),") // course - .groupBegin() - .number("(d+),") // altitude - .number("(d+),") // satellites - .number("(d+),") // odometer - .number("([01]),") // ignition - .number("([01]),") // input 1 - .number("([01]),") // input 2 - .number("([01]),") // immobilizer - .number("([01]),") // external battery status - .number("(d+),") // gsm - .or() - .number("(d+.d),") // hdop - .number("(d+),") // altitude - .number("(d+),") // odometer - .number("([01],[01],[01],[01]),") // input - .number("([01],[01],[01],[01]),") // output - .number("(d+.?d*),") // adc 1 - .number("(d+.?d*),") // adc 2 - .groupEnd("?") - .any() - .expression("([AV])") // validity - .number(",(d{10})").optional() // rfid - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next(), parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - if (parser.hasNext(8)) { - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); - } - if (parser.hasNext(4)) { - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - } - - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble( - parser.next().replace(".", "")) / 10)); - - position.setCourse(parser.nextDouble(0)); - - if (parser.hasNext(9)) { - position.setAltitude(parser.nextDouble(0)); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000); - position.set(Position.KEY_IGNITION, parser.next().equals("1")); - position.set(Position.PREFIX_IO + 1, parser.next()); - position.set(Position.PREFIX_IO + 2, parser.next()); - position.set("immobilizer", parser.next()); - position.set(Position.KEY_CHARGE, parser.next().equals("1")); - position.set(Position.KEY_RSSI, parser.nextDouble()); - } - - if (parser.hasNext(7)) { - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.setAltitude(parser.nextDouble(0)); - position.set(Position.KEY_ODOMETER, parser.nextInt(0) * 1000); - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - } - - position.setValid(parser.next().equals("A")); - - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/Vt200FrameDecoder.java b/src/org/traccar/protocol/Vt200FrameDecoder.java deleted file mode 100644 index 0fd83e715..000000000 --- a/src/org/traccar/protocol/Vt200FrameDecoder.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseFrameDecoder; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class Vt200FrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ')') + 1; - if (endIndex > 0) { - - ByteBuf frame = Unpooled.buffer(); - - while (buf.readerIndex() < endIndex) { - int b = buf.readByte(); - if (b == '=') { - frame.writeByte(buf.readByte() ^ '='); - } else { - frame.writeByte(b); - } - } - - return frame; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/Vt200Protocol.java b/src/org/traccar/protocol/Vt200Protocol.java deleted file mode 100644 index 2a9ef6ab5..000000000 --- a/src/org/traccar/protocol/Vt200Protocol.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Vt200Protocol extends BaseProtocol { - - public Vt200Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Vt200FrameDecoder()); - pipeline.addLast(new Vt200ProtocolDecoder(Vt200Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Vt200ProtocolDecoder.java b/src/org/traccar/protocol/Vt200ProtocolDecoder.java deleted file mode 100644 index b1564abd9..000000000 --- a/src/org/traccar/protocol/Vt200ProtocolDecoder.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.BcdUtil; -import org.traccar.helper.BitUtil; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Arrays; -import java.util.Date; - -public class Vt200ProtocolDecoder extends BaseProtocolDecoder { - - public Vt200ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static double decodeCoordinate(int value) { - int degrees = value / 1000000; - int minutes = value % 1000000; - return degrees + minutes * 0.0001 / 60; - } - - protected Date decodeDate(ByteBuf buf) { - DateBuilder dateBuilder = new DateBuilder() - .setDateReverse(BcdUtil.readInteger(buf, 2), BcdUtil.readInteger(buf, 2), BcdUtil.readInteger(buf, 2)) - .setTime(BcdUtil.readInteger(buf, 2), BcdUtil.readInteger(buf, 2), BcdUtil.readInteger(buf, 2)); - return dateBuilder.getDate(); - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(1); // header - - String id = ByteBufUtil.hexDump(buf.readSlice(6)); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - int type = buf.readUnsignedShort(); - buf.readUnsignedShort(); // length - - if (type == 0x2086 || type == 0x2084 || type == 0x2082) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - buf.readUnsignedByte(); // data type - buf.readUnsignedShort(); // trip id - - position.setTime(decodeDate(buf)); - - position.setLatitude(decodeCoordinate(BcdUtil.readInteger(buf, 8))); - position.setLongitude(decodeCoordinate(BcdUtil.readInteger(buf, 9))); - - int flags = buf.readUnsignedByte(); - position.setValid(BitUtil.check(flags, 0)); - if (!BitUtil.check(flags, 1)) { - position.setLatitude(-position.getLatitude()); - } - if (!BitUtil.check(flags, 2)) { - position.setLongitude(-position.getLongitude()); - } - - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.setCourse(buf.readUnsignedByte() * 2); - - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000); - position.set(Position.KEY_STATUS, buf.readUnsignedInt()); - - // additional data - - return position; - - } else if (type == 0x3088) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - buf.readUnsignedShort(); // trip id - buf.skipBytes(8); // imei - buf.skipBytes(8); // imsi - - position.set("tripStart", decodeDate(buf).getTime()); - position.set("tripEnd", decodeDate(buf).getTime()); - position.set("drivingTime", buf.readUnsignedShort()); - - position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt()); - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); - - position.set("maxSpeed", UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - position.set("maxRpm", buf.readUnsignedShort()); - position.set("maxTemp", buf.readUnsignedByte() - 40); - position.set("hardAccelerationCount", buf.readUnsignedByte()); - position.set("hardBrakingCount", buf.readUnsignedByte()); - - for (String speedType : Arrays.asList("over", "high", "normal", "low")) { - position.set(speedType + "SpeedTime", buf.readUnsignedShort()); - position.set(speedType + "SpeedDistance", buf.readUnsignedInt()); - position.set(speedType + "SpeedFuel", buf.readUnsignedInt()); - } - - position.set("idleTime", buf.readUnsignedShort()); - position.set("idleFuel", buf.readUnsignedInt()); - - position.set("hardCorneringCount", buf.readUnsignedByte()); - position.set("overspeedCount", buf.readUnsignedByte()); - position.set("overheatCount", buf.readUnsignedShort()); - position.set("laneChangeCount", buf.readUnsignedByte()); - position.set("emergencyRefueling", buf.readUnsignedByte()); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/VtfmsFrameDecoder.java b/src/org/traccar/protocol/VtfmsFrameDecoder.java deleted file mode 100644 index 62a189960..000000000 --- a/src/org/traccar/protocol/VtfmsFrameDecoder.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseFrameDecoder; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class VtfmsFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ')'); - if (endIndex > 0) { - endIndex += 1 + 3; - if (buf.writerIndex() >= endIndex) { - return buf.readRetainedSlice(endIndex - buf.readerIndex()); - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/VtfmsProtocol.java b/src/org/traccar/protocol/VtfmsProtocol.java deleted file mode 100644 index 2826a86e6..000000000 --- a/src/org/traccar/protocol/VtfmsProtocol.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import io.netty.handler.codec.string.StringDecoder; - -public class VtfmsProtocol extends BaseProtocol { - - public VtfmsProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new VtfmsFrameDecoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new VtfmsProtocolDecoder(VtfmsProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new VtfmsProtocolDecoder(VtfmsProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/VtfmsProtocolDecoder.java b/src/org/traccar/protocol/VtfmsProtocolDecoder.java deleted file mode 100644 index 17fac4311..000000000 --- a/src/org/traccar/protocol/VtfmsProtocolDecoder.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class VtfmsProtocolDecoder extends BaseProtocolDecoder { - - private static final String[] DIRECTIONS = new String[] {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}; - - public VtfmsProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("(") - .number("(d{15}),") // imei - .number("[0-9A-Z]{3}dd,") // packet count - .number("(dd),") // packet id - .number("[^,]*,") // reserved - .number("(d+)?,") // rssi - .number("(?:d+)?,") // fix status - .number("(d+)?,") // satellites - .number("[^,]*,") // reserved - .expression("([AV]),") // validity - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(dd)(dd)(dd),") // time (ddmmyy) - .number("(-?d+.d+),") // latitude - .number("(-?d+.d+),") // longitude - .number("(?:(d+)|([NESW]{1,2})),") // course - .number("(d+),") // speed - .number("(d+),") // hours - .number("(d+),") // idle hours - .expression("[KNT],") // antenna status - .number("(d+),") // odometer - .expression("([01]),") // power status - .number("(d+.d+),") // power voltage - .number("[^,]*,") // reserved - .number("(d+)?,") // fuel level - .number("(d+.d+)?,") // adc 1 - .number("[^,]*,") // reserved - .number("(d+.d+)?,") // adc 2 - .expression("([01]),") // di 1 - .expression("([01]),") // di 2 - .expression("([01]),") // di 3 - .expression("([01]),") // di 4 - .expression("([01]),") // do 1 - .expression("([01]),") // do 2 - .expression("([01]),") // do 3 - .number("[^,]*,") // reserved - .number("[^,]*") // reserved - .text(")") - .number("ddd") // checksum - .compile(); - - private String decodeAlarm(int value) { - switch (value) { - case 10: - return Position.ALARM_OVERSPEED; - case 14: - return Position.ALARM_POWER_CUT; - case 15: - return Position.ALARM_POWER_RESTORED; - case 32: - return Position.ALARM_BRAKING; - case 33: - return Position.ALARM_ACCELERATION; - default: - return null; - } - } - - private double convertToDegrees(double value) { - double degrees = Math.floor(value / 100); - return degrees + (value - degrees * 100) / 60; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.set(Position.KEY_ALARM, decodeAlarm(parser.nextInt())); - position.set(Position.KEY_RSSI, parser.nextInt()); - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - position.setValid(parser.next().equals("A")); - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS_DMY)); - - double latitude = parser.nextDouble(); - double longitude = parser.nextDouble(); - if (Math.abs(latitude) > 90 || Math.abs(longitude) > 180) { - position.setLatitude(convertToDegrees(latitude)); - position.setLongitude(convertToDegrees(longitude)); - } else { - position.setLatitude(latitude); - position.setLongitude(longitude); - } - - position.setCourse(parser.nextDouble(0)); - if (parser.hasNext()) { - String direction = parser.next(); - for (int i = 0; i < DIRECTIONS.length; i++) { - if (direction.equals(DIRECTIONS[i])) { - position.setCourse(i * 45.0); - break; - } - } - } - - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(parser.nextInt())); - position.set("idleHours", parser.nextInt()); - position.set(Position.KEY_ODOMETER, parser.nextInt() * 100); - position.set(Position.KEY_CHARGE, parser.next().equals("1")); - position.set(Position.KEY_POWER, parser.nextDouble()); - position.set(Position.KEY_FUEL_LEVEL, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.PREFIX_ADC + 2, parser.nextDouble()); - position.set(Position.PREFIX_IN + 1, parser.nextInt()); - position.set(Position.PREFIX_IN + 2, parser.nextInt()); - position.set(Position.PREFIX_IN + 3, parser.nextInt()); - position.set(Position.PREFIX_IN + 4, parser.nextInt()); - position.set(Position.PREFIX_OUT + 1, parser.nextInt()); - position.set(Position.PREFIX_OUT + 2, parser.nextInt()); - position.set(Position.PREFIX_OUT + 3, parser.nextInt()); - - return position; - } - -} diff --git a/src/org/traccar/protocol/WatchFrameDecoder.java b/src/org/traccar/protocol/WatchFrameDecoder.java deleted file mode 100644 index f99bd52e2..000000000 --- a/src/org/traccar/protocol/WatchFrameDecoder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.BaseFrameDecoder; - -public class WatchFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ']') + 1; - if (endIndex > 0) { - ByteBuf frame = Unpooled.buffer(); - while (buf.readerIndex() < endIndex) { - byte b1 = buf.readByte(); - if (b1 == '}') { - byte b2 = buf.readByte(); - switch (b2) { - case 0x01: - frame.writeByte('}'); - break; - case 0x02: - frame.writeByte('['); - break; - case 0x03: - frame.writeByte(']'); - break; - case 0x04: - frame.writeByte(','); - break; - case 0x05: - frame.writeByte('*'); - break; - default: - throw new IllegalArgumentException(String.format( - "unexpected byte at %d: 0x%02x", buf.readerIndex() - 1, b2)); - } - } else { - frame.writeByte(b1); - } - } - return frame; - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/WatchProtocol.java b/src/org/traccar/protocol/WatchProtocol.java deleted file mode 100644 index fe285e70d..000000000 --- a/src/org/traccar/protocol/WatchProtocol.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -public class WatchProtocol extends BaseProtocol { - - public WatchProtocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_POSITION_SINGLE, - Command.TYPE_POSITION_PERIODIC, - Command.TYPE_SOS_NUMBER, - Command.TYPE_ALARM_SOS, - Command.TYPE_ALARM_BATTERY, - Command.TYPE_REBOOT_DEVICE, - Command.TYPE_POWER_OFF, - Command.TYPE_ALARM_REMOVE, - Command.TYPE_SILENCE_TIME, - Command.TYPE_ALARM_CLOCK, - Command.TYPE_SET_PHONEBOOK, - Command.TYPE_MESSAGE, - Command.TYPE_VOICE_MESSAGE, - Command.TYPE_SET_TIMEZONE, - Command.TYPE_SET_INDICATOR); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new WatchFrameDecoder()); - pipeline.addLast(new WatchProtocolEncoder()); - pipeline.addLast(new WatchProtocolDecoder(WatchProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/WatchProtocolDecoder.java b/src/org/traccar/protocol/WatchProtocolDecoder.java deleted file mode 100644 index 70b207e9b..000000000 --- a/src/org/traccar/protocol/WatchProtocolDecoder.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.BitUtil; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; -import org.traccar.model.WifiAccessPoint; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.regex.Pattern; - -public class WatchProtocolDecoder extends BaseProtocolDecoder { - - private static final Logger LOGGER = LoggerFactory.getLogger(WatchProtocolDecoder.class); - - public WatchProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN_POSITION = new PatternBuilder() - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([AV]),") // validity - .number(" *(-?d+.d+),") // latitude - .expression("([NS]),") - .number(" *(-?d+.d+),") // longitude - .expression("([EW])?,") - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(d+.?d*),") // altitude - .number("(d+),") // satellites - .number("(d+),") // rssi - .number("(d+),") // battery - .number("(d+),") // steps - .number("d+,") // tumbles - .number("(x+),") // status - .expression("(.*)") // cell and wifi - .compile(); - - private void sendResponse(Channel channel, String id, String index, String content) { - if (channel != null) { - String response; - if (index != null) { - response = String.format("[%s*%s*%s*%04x*%s]", - manufacturer, id, index, content.length(), content); - } else { - response = String.format("[%s*%s*%04x*%s]", - manufacturer, id, content.length(), content); - } - ByteBuf buf = Unpooled.copiedBuffer(response, StandardCharsets.US_ASCII); - channel.writeAndFlush(new NetworkMessage(buf, channel.remoteAddress())); - } - } - - private String decodeAlarm(int status) { - if (BitUtil.check(status, 0)) { - return Position.ALARM_LOW_BATTERY; - } else if (BitUtil.check(status, 1)) { - return Position.ALARM_GEOFENCE_EXIT; - } else if (BitUtil.check(status, 2)) { - return Position.ALARM_GEOFENCE_ENTER; - } else if (BitUtil.check(status, 3)) { - return Position.ALARM_OVERSPEED; - } else if (BitUtil.check(status, 16)) { - return Position.ALARM_SOS; - } else if (BitUtil.check(status, 17)) { - return Position.ALARM_LOW_BATTERY; - } else if (BitUtil.check(status, 18)) { - return Position.ALARM_GEOFENCE_EXIT; - } else if (BitUtil.check(status, 19)) { - return Position.ALARM_GEOFENCE_ENTER; - } else if (BitUtil.check(status, 20)) { - return Position.ALARM_REMOVING; - } else if (BitUtil.check(status, 21)) { - return Position.ALARM_FALL_DOWN; - } - return null; - } - - private Position decodePosition(DeviceSession deviceSession, String data) { - - Parser parser = new Parser(PATTERN_POSITION, data); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt(0)); - position.set(Position.KEY_RSSI, parser.nextInt(0)); - position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0)); - - position.set(Position.KEY_STEPS, parser.nextInt(0)); - - int status = parser.nextHexInt(0); - position.set(Position.KEY_ALARM, decodeAlarm(status)); - if (BitUtil.check(status, 4)) { - position.set(Position.KEY_MOTION, true); - } - - String[] values = parser.next().split(","); - int index = 0; - - Network network = new Network(); - - int cellCount = Integer.parseInt(values[index++]); - index += 1; // timing advance - int mcc = Integer.parseInt(values[index++]); - int mnc = Integer.parseInt(values[index++]); - - for (int i = 0; i < cellCount; i++) { - network.addCellTower(CellTower.from(mcc, mnc, - Integer.parseInt(values[index++]), Integer.parseInt(values[index++]), - Integer.parseInt(values[index++]))); - } - - if (index < values.length && !values[index].isEmpty()) { - int wifiCount = Integer.parseInt(values[index++]); - - for (int i = 0; i < wifiCount; i++) { - index += 1; // wifi name - network.addWifiAccessPoint(WifiAccessPoint.from( - values[index++], Integer.parseInt(values[index++]))); - } - } - - if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) { - position.setNetwork(network); - } - - return position; - } - - private boolean hasIndex; - private String manufacturer; - - public boolean getHasIndex() { - return hasIndex; - } - - public String getManufacturer() { - return manufacturer; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - buf.skipBytes(1); // '[' header - manufacturer = buf.readSlice(2).toString(StandardCharsets.US_ASCII); - buf.skipBytes(1); // '*' delimiter - - int idIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*'); - String id = buf.readSlice(idIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id); - if (deviceSession == null) { - return null; - } - - buf.skipBytes(1); // '*' delimiter - - String index = null; - int contentIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*'); - if (contentIndex + 5 < buf.writerIndex() && buf.getByte(contentIndex + 5) == '*' - && buf.toString(contentIndex + 1, 4, StandardCharsets.US_ASCII).matches("\\p{XDigit}+")) { - int indexLength = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*') - buf.readerIndex(); - hasIndex = true; - index = buf.readSlice(indexLength).toString(StandardCharsets.US_ASCII); - buf.skipBytes(1); // '*' delimiter - } - - buf.skipBytes(4); // length - buf.skipBytes(1); // '*' delimiter - - buf.writerIndex(buf.writerIndex() - 1); // ']' ignore ending - - contentIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); - if (contentIndex < 0) { - contentIndex = buf.writerIndex(); - } - - String type = buf.readSlice(contentIndex - buf.readerIndex()).toString(StandardCharsets.US_ASCII); - - if (contentIndex < buf.writerIndex()) { - buf.readerIndex(contentIndex + 1); - } - - if (type.equals("INIT")) { - - sendResponse(channel, id, index, "INIT,1"); - - } else if (type.equals("LK")) { - - sendResponse(channel, id, index, "LK"); - - if (buf.isReadable()) { - String[] values = buf.toString(StandardCharsets.US_ASCII).split(","); - if (values.length >= 3) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[2])); - - return position; - } - } - - } else if (type.equals("UD") || type.equals("UD2") || type.equals("UD3") - || type.equals("AL") || type.equals("WT")) { - - Position position = decodePosition(deviceSession, buf.toString(StandardCharsets.US_ASCII)); - - if (type.equals("AL")) { - if (position != null) { - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - } - sendResponse(channel, id, index, "AL"); - } - - return position; - - } else if (type.equals("TKQ")) { - - sendResponse(channel, id, index, "TKQ"); - - } else if (type.equals("PULSE") || type.equals("heart") || type.equals("bphrt")) { - - if (buf.isReadable()) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, new Date()); - - String[] values = buf.toString(StandardCharsets.US_ASCII).split(","); - int valueIndex = 0; - - if (type.equals("bphrt")) { - position.set("pressureHigh", values[valueIndex++]); - position.set("pressureLow", values[valueIndex++]); - } - position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[valueIndex])); - - return position; - - } - - } else if (type.equals("img")) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - int timeIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ','); - buf.readerIndex(timeIndex + 12 + 2); - position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(id, buf, "jpg")); - - return position; - - } else if (type.equals("TK")) { - - if (buf.readableBytes() == 1) { - byte result = buf.readByte(); - if (result != '1') { - LOGGER.warn(type + "," + result); - } - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_AUDIO, Context.getMediaManager().writeFile(id, buf, "amr")); - - return position; - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/WatchProtocolEncoder.java b/src/org/traccar/protocol/WatchProtocolEncoder.java deleted file mode 100644 index 264aec81f..000000000 --- a/src/org/traccar/protocol/WatchProtocolEncoder.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2016 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.StringProtocolEncoder; -import org.traccar.helper.DataConverter; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; - -public class WatchProtocolEncoder extends StringProtocolEncoder implements StringProtocolEncoder.ValueFormatter { - - @Override - public String formatValue(String key, Object value) { - if (key.equals(Command.KEY_TIMEZONE)) { - double offset = TimeZone.getTimeZone((String) value).getRawOffset() / 3600000.0; - DecimalFormat fmt = new DecimalFormat("+#.##;-#.##", DecimalFormatSymbols.getInstance(Locale.US)); - return fmt.format(offset); - } else if (key.equals(Command.KEY_MESSAGE)) { - return DataConverter.printHex(value.toString().getBytes(StandardCharsets.UTF_16BE)); - } else if (key.equals(Command.KEY_ENABLE)) { - return (boolean) value ? "1" : "0"; - } - - return null; - } - - protected ByteBuf formatTextCommand(Channel channel, Command command, String format, String... keys) { - String content = formatCommand(command, format, this, keys); - ByteBuf buf = Unpooled.copiedBuffer(content, StandardCharsets.US_ASCII); - - return formatBinaryCommand(channel, command, "", buf); - } - - protected ByteBuf formatBinaryCommand(Channel channel, Command command, String textPrefix, ByteBuf data) { - boolean hasIndex = false; - String manufacturer = "CS"; - if (channel != null) { - WatchProtocolDecoder decoder = channel.pipeline().get(WatchProtocolDecoder.class); - if (decoder != null) { - hasIndex = decoder.getHasIndex(); - manufacturer = decoder.getManufacturer(); - } - } - - ByteBuf buf = Unpooled.buffer(); - buf.writeByte('['); - buf.writeCharSequence(manufacturer, StandardCharsets.US_ASCII); - buf.writeByte('*'); - buf.writeCharSequence(getUniqueId(command.getDeviceId()), StandardCharsets.US_ASCII); - buf.writeByte('*'); - if (hasIndex) { - buf.writeCharSequence("0001", StandardCharsets.US_ASCII); - buf.writeByte('*'); - } - buf.writeCharSequence(String.format("%04x", data.readableBytes() + textPrefix.length()), - StandardCharsets.US_ASCII); - buf.writeByte('*'); - buf.writeCharSequence(textPrefix, StandardCharsets.US_ASCII); - buf.writeBytes(data); - buf.writeByte(']'); - - return buf; - } - - private static Map mapping = new HashMap<>(); - - static { - mapping.put((byte) 0x7d, (byte) 0x01); - mapping.put((byte) 0x5B, (byte) 0x02); - mapping.put((byte) 0x5D, (byte) 0x03); - mapping.put((byte) 0x2C, (byte) 0x04); - mapping.put((byte) 0x2A, (byte) 0x05); - } - - private ByteBuf getBinaryData(Command command) { - byte[] data = DataConverter.parseHex(command.getString(Command.KEY_DATA)); - - int encodedLength = data.length; - for (byte b : data) { - if (mapping.containsKey(b)) { - encodedLength += 1; - } - } - - int index = 0; - byte[] encodedData = new byte[encodedLength]; - - for (byte b : data) { - Byte replacement = mapping.get(b); - if (replacement != null) { - encodedData[index] = 0x7D; - index += 1; - encodedData[index] = replacement; - } else { - encodedData[index] = b; - } - index += 1; - } - - return Unpooled.copiedBuffer(encodedData); - } - - @Override - protected Object encodeCommand(Channel channel, Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatTextCommand(channel, command, command.getString(Command.KEY_DATA)); - case Command.TYPE_POSITION_SINGLE: - return formatTextCommand(channel, command, "RG"); - case Command.TYPE_SOS_NUMBER: - return formatTextCommand(channel, command, "SOS{%s},{%s}", Command.KEY_INDEX, Command.KEY_PHONE); - case Command.TYPE_ALARM_SOS: - return formatTextCommand(channel, command, "SOSSMS,{%s}", Command.KEY_ENABLE); - case Command.TYPE_ALARM_BATTERY: - return formatTextCommand(channel, command, "LOWBAT,{%s}", Command.KEY_ENABLE); - case Command.TYPE_REBOOT_DEVICE: - return formatTextCommand(channel, command, "RESET"); - case Command.TYPE_POWER_OFF: - return formatTextCommand(channel, command, "POWEROFF"); - case Command.TYPE_ALARM_REMOVE: - return formatTextCommand(channel, command, "REMOVE,{%s}", Command.KEY_ENABLE); - case Command.TYPE_SILENCE_TIME: - return formatTextCommand(channel, command, "SILENCETIME,{%s}", Command.KEY_DATA); - case Command.TYPE_ALARM_CLOCK: - return formatTextCommand(channel, command, "REMIND,{%s}", Command.KEY_DATA); - case Command.TYPE_SET_PHONEBOOK: - return formatTextCommand(channel, command, "PHB,{%s}", Command.KEY_DATA); - case Command.TYPE_MESSAGE: - return formatTextCommand(channel, command, "MESSAGE,{%s}", Command.KEY_MESSAGE); - case Command.TYPE_VOICE_MESSAGE: - return formatBinaryCommand(channel, command, "TK,", getBinaryData(command)); - case Command.TYPE_POSITION_PERIODIC: - return formatTextCommand(channel, command, "UPLOAD,{%s}", Command.KEY_FREQUENCY); - case Command.TYPE_SET_TIMEZONE: - return formatTextCommand(channel, command, "LZ,,{%s}", Command.KEY_TIMEZONE); - case Command.TYPE_SET_INDICATOR: - return formatTextCommand(channel, command, "FLOWER,{%s}", Command.KEY_DATA); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/WialonProtocol.java b/src/org/traccar/protocol/WialonProtocol.java deleted file mode 100644 index 06b54dceb..000000000 --- a/src/org/traccar/protocol/WialonProtocol.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.Context; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -import io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; - -import java.nio.charset.StandardCharsets; -public class WialonProtocol extends BaseProtocol { - - public WialonProtocol() { - setSupportedDataCommands( - Command.TYPE_REBOOT_DEVICE, - Command.TYPE_SEND_USSD, - Command.TYPE_IDENTIFICATION, - Command.TYPE_OUTPUT_CONTROL); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(4 * 1024)); - pipeline.addLast(new StringEncoder()); - boolean utf8 = Context.getConfig().getBoolean(getName() + ".utf8"); - if (utf8) { - pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8)); - } else { - pipeline.addLast(new StringDecoder()); - } - pipeline.addLast(new WialonProtocolEncoder()); - pipeline.addLast(new WialonProtocolDecoder(WialonProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/WialonProtocolDecoder.java b/src/org/traccar/protocol/WialonProtocolDecoder.java deleted file mode 100644 index de7073b67..000000000 --- a/src/org/traccar/protocol/WialonProtocolDecoder.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class WialonProtocolDecoder extends BaseProtocolDecoder { - - public WialonProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("(dd)(dd)(dd);") // date (ddmmyy) - .number("(dd)(dd)(dd);") // time (hhmmss) - .number("(dd)(dd.d+);") // latitude - .expression("([NS]);") - .number("(ddd)(dd.d+);") // longitude - .expression("([EW]);") - .number("(d+.?d*)?;") // speed - .number("(d+.?d*)?;") // course - .number("(?:NA|(-?d+.?d*));") // altitude - .number("(?:NA|(d+))") // satellites - .groupBegin().text(";") - .number("(?:NA|(d+.?d*));") // hdop - .number("(?:NA|(d+));") // inputs - .number("(?:NA|(d+));") // outputs - .expression("(?:NA|([^;]*));") // adc - .expression("(?:NA|([^;]*));") // ibutton - .expression("(?:NA|(.*))") // params - .groupEnd("?") - .compile(); - - private void sendResponse(Channel channel, SocketAddress remoteAddress, String prefix, Integer number) { - if (channel != null) { - StringBuilder response = new StringBuilder(prefix); - if (number != null) { - response.append(number); - } - response.append("\r\n"); - channel.writeAndFlush(new NetworkMessage(response.toString(), remoteAddress)); - } - } - - private Position decodePosition(Channel channel, SocketAddress remoteAddress, String substring) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession == null) { - return null; - } - - Parser parser = new Parser(PATTERN, substring); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); - - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - if (parser.hasNext()) { - int satellites = parser.nextInt(0); - position.setValid(satellites >= 3); - position.set(Position.KEY_SATELLITES, satellites); - } - - position.set(Position.KEY_HDOP, parser.nextDouble()); - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - - if (parser.hasNext()) { - String[] values = parser.next().split(","); - for (int i = 0; i < values.length; i++) { - position.set(Position.PREFIX_ADC + (i + 1), values[i]); - } - } - - position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next()); - - if (parser.hasNext()) { - String[] values = parser.next().split(","); - for (String param : values) { - Matcher paramParser = Pattern.compile("(.*):[1-3]:(.*)").matcher(param); - if (paramParser.matches()) { - try { - position.set(paramParser.group(1).toLowerCase(), Double.parseDouble(paramParser.group(2))); - } catch (NumberFormatException e) { - position.set(paramParser.group(1).toLowerCase(), paramParser.group(2)); - } - } - } - } - - return position; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - if (sentence.startsWith("#L#")) { - - String[] values = sentence.substring(3).split(";"); - - String imei = values[0].indexOf('.') >= 0 ? values[1] : values[0]; - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession != null) { - sendResponse(channel, remoteAddress, "#AL#", 1); - } - - } else if (sentence.startsWith("#P#")) { - - sendResponse(channel, remoteAddress, "#AP#", null); // heartbeat - - } else if (sentence.startsWith("#SD#") || sentence.startsWith("#D#")) { - - Position position = decodePosition( - channel, remoteAddress, sentence.substring(sentence.indexOf('#', 1) + 1)); - - if (position != null) { - sendResponse(channel, remoteAddress, "#AD#", 1); - return position; - } - - } else if (sentence.startsWith("#B#")) { - - String[] messages = sentence.substring(sentence.indexOf('#', 1) + 1).split("\\|"); - List positions = new LinkedList<>(); - - for (String message : messages) { - Position position = decodePosition(channel, remoteAddress, message); - if (position != null) { - position.set(Position.KEY_ARCHIVE, true); - positions.add(position); - } - } - - sendResponse(channel, remoteAddress, "#AB#", messages.length); - if (!positions.isEmpty()) { - return positions; - } - - } else if (sentence.startsWith("#M#")) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - if (deviceSession != null) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, new Date()); - position.setValid(false); - position.set(Position.KEY_RESULT, sentence.substring(sentence.indexOf('#', 1) + 1)); - sendResponse(channel, remoteAddress, "#AM#", 1); - return position; - } - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/WialonProtocolEncoder.java b/src/org/traccar/protocol/WialonProtocolEncoder.java deleted file mode 100644 index 9ff1631eb..000000000 --- a/src/org/traccar/protocol/WialonProtocolEncoder.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class WialonProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - switch (command.getType()) { - case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "reboot\r\n"); - case Command.TYPE_SEND_USSD: - return formatCommand(command, "USSD:{%s}\r\n", Command.KEY_PHONE); - case Command.TYPE_IDENTIFICATION: - return formatCommand(command, "VER?\r\n"); - case Command.TYPE_OUTPUT_CONTROL: - return formatCommand(command, "L{%s}={%s}\r\n", Command.KEY_INDEX, Command.KEY_DATA); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/WondexFrameDecoder.java b/src/org/traccar/protocol/WondexFrameDecoder.java deleted file mode 100644 index 39d83d761..000000000 --- a/src/org/traccar/protocol/WondexFrameDecoder.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 org.traccar.BaseFrameDecoder; -import org.traccar.NetworkMessage; -import org.traccar.helper.BufferUtil; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class WondexFrameDecoder extends BaseFrameDecoder { - - private static final int KEEP_ALIVE_LENGTH = 8; - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < KEEP_ALIVE_LENGTH) { - return null; - } - - if (buf.getUnsignedByte(buf.readerIndex()) == 0xD0) { - - // Send response - ByteBuf frame = buf.readRetainedSlice(KEEP_ALIVE_LENGTH); - if (channel != null) { - frame.retain(); - channel.writeAndFlush(new NetworkMessage(frame, channel.remoteAddress())); - } - return frame; - - } else { - - int index = BufferUtil.indexOf("\r\n", buf); - if (index != -1) { - ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex()); - buf.skipBytes(2); - return frame; - } - - } - - return null; - } - -} diff --git a/src/org/traccar/protocol/WondexProtocol.java b/src/org/traccar/protocol/WondexProtocol.java deleted file mode 100644 index 8c6283d66..000000000 --- a/src/org/traccar/protocol/WondexProtocol.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -import io.netty.handler.codec.string.StringEncoder; - -public class WondexProtocol extends BaseProtocol { - - public WondexProtocol() { - setTextCommandEncoder(new WondexProtocolEncoder()); - setSupportedCommands( - Command.TYPE_GET_DEVICE_STATUS, - Command.TYPE_GET_MODEM_STATUS, - Command.TYPE_REBOOT_DEVICE, - Command.TYPE_POSITION_SINGLE, - Command.TYPE_GET_VERSION, - Command.TYPE_IDENTIFICATION); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new WondexFrameDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new WondexProtocolEncoder()); - pipeline.addLast(new WondexProtocolDecoder(WondexProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new WondexProtocolEncoder()); - pipeline.addLast(new WondexProtocolDecoder(WondexProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/WondexProtocolDecoder.java b/src/org/traccar/protocol/WondexProtocolDecoder.java deleted file mode 100644 index b85ae2656..000000000 --- a/src/org/traccar/protocol/WondexProtocolDecoder.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.regex.Pattern; - -public class WondexProtocolDecoder extends BaseProtocolDecoder { - - public WondexProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("[^d]*") // header - .number("(d+),") // device identifier - .number("(dddd)(dd)(dd)") // date (yyyymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("(-?d+.d+),") // longitude - .number("(-?d+.d+),") // latitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(-?d+.?d*),") // altitude - .number("(d+),") // satellites - .number("(d+),?") // event - .number("(d+.d+)V,").optional() // battery - .number("(d+.d+)?,?") // odometer - .number("(d+)?,?") // input - .number("(d+.d+)?,?") // adc1 - .number("(d+.d+)?,?") // adc2 - .number("(d+)?") // output - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - if (buf.getUnsignedByte(0) == 0xD0) { - - long deviceId = ((Long.reverseBytes(buf.getLong(0))) >> 32) & 0xFFFFFFFFL; - getDeviceSession(channel, remoteAddress, String.valueOf(deviceId)); - - return null; - } else if (buf.toString(StandardCharsets.US_ASCII).startsWith("$OK:") - || buf.toString(StandardCharsets.US_ASCII).startsWith("$ERR:") - || buf.toString(StandardCharsets.US_ASCII).startsWith("$MSG:")) { - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - getLastLocation(position, new Date()); - position.set(Position.KEY_RESULT, buf.toString(StandardCharsets.US_ASCII)); - - return position; - - } else { - - Parser parser = new Parser(PATTERN, buf.toString(StandardCharsets.US_ASCII)); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setLongitude(parser.nextDouble(0)); - position.setLatitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - - int satellites = parser.nextInt(0); - position.setValid(satellites != 0); - position.set(Position.KEY_SATELLITES, satellites); - - position.set(Position.KEY_EVENT, parser.next()); - position.set(Position.KEY_BATTERY, parser.nextDouble()); - if (parser.hasNext()) { - position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000); - } - position.set(Position.KEY_INPUT, parser.next()); - position.set(Position.PREFIX_ADC + 1, parser.next()); - position.set(Position.PREFIX_ADC + 2, parser.next()); - position.set(Position.KEY_OUTPUT, parser.next()); - - return position; - - } - - } - -} diff --git a/src/org/traccar/protocol/WondexProtocolEncoder.java b/src/org/traccar/protocol/WondexProtocolEncoder.java deleted file mode 100644 index f9e8eeb9b..000000000 --- a/src/org/traccar/protocol/WondexProtocolEncoder.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2016 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class WondexProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - initDevicePassword(command, "0000"); - - switch (command.getType()) { - case Command.TYPE_REBOOT_DEVICE: - return formatCommand(command, "$WP+REBOOT={%s}", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_GET_DEVICE_STATUS: - return formatCommand(command, "$WP+TEST={%s}", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_GET_MODEM_STATUS: - return formatCommand(command, "$WP+GSMINFO={%s}", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_IDENTIFICATION: - return formatCommand(command, "$WP+IMEI={%s}", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "$WP+GETLOCATION={%s}", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_GET_VERSION: - return formatCommand(command, "$WP+VER={%s}", Command.KEY_DEVICE_PASSWORD); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/WristbandProtocol.java b/src/org/traccar/protocol/WristbandProtocol.java deleted file mode 100644 index 1e5ef2c01..000000000 --- a/src/org/traccar/protocol/WristbandProtocol.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class WristbandProtocol extends BaseProtocol { - - public WristbandProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2, 3, 0)); - pipeline.addLast(new WristbandProtocolDecoder(WristbandProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/WristbandProtocolDecoder.java b/src/org/traccar/protocol/WristbandProtocolDecoder.java deleted file mode 100644 index 7f2b0af85..000000000 --- a/src/org/traccar/protocol/WristbandProtocolDecoder.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.CellTower; -import org.traccar.model.Network; -import org.traccar.model.Position; -import org.traccar.model.WifiAccessPoint; - -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; - -public class WristbandProtocolDecoder extends BaseProtocolDecoder { - - public WristbandProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private void sendResponse( - Channel channel, String imei, String version, int type, String data) { - - if (channel != null) { - String sentence = String.format("YX%s|%s|0|{F%02d#%s}\r\n", imei, version, type, data); - ByteBuf response = Unpooled.buffer(); - if (type != 91) { - response.writeBytes(new byte[]{0x00, 0x01, 0x02}); - response.writeShort(sentence.length()); - } - response.writeCharSequence(sentence, StandardCharsets.US_ASCII); - if (type != 91) { - response.writeBytes(new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0xFC}); - } - channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); - } - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("..") // header - .number("(d+)|") // imei - .number("([vV]d+.d+)|") // version - .number("d+|") // model - .text("{") - .number("F(d+)") // function - .groupBegin() - .text("#") - .expression("(.*)") // data - .groupEnd("?") - .text("}") - .text("\r\n") - .compile(); - - private Position decodePosition(DeviceSession deviceSession, String sentence) throws ParseException { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - String[] values = sentence.split(","); - - position.setValid(true); - position.setLongitude(Double.parseDouble(values[0])); - position.setLatitude(Double.parseDouble(values[1])); - position.setTime(new SimpleDateFormat("yyyyMMddHHmm").parse(values[2])); - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[3]))); - - return position; - } - - private Position decodeStatus(DeviceSession deviceSession, String sentence) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(sentence.split(",")[0])); - - return position; - } - - private Position decodeNetwork(DeviceSession deviceSession, String sentence, boolean wifi) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - Network network = new Network(); - String[] fragments = sentence.split("\\|"); - - if (wifi) { - for (String item : fragments[0].split("_")) { - String[] values = item.split(","); - network.addWifiAccessPoint(WifiAccessPoint.from(values[0], Integer.parseInt(values[1]))); - } - } - - for (String item : fragments[wifi ? 1 : 0].split(":")) { - String[] values = item.split(","); - int lac = Integer.parseInt(values[0]); - int mnc = Integer.parseInt(values[1]); - int mcc = Integer.parseInt(values[2]); - int cid = Integer.parseInt(values[3]); - int rssi = Integer.parseInt(values[4]); - network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi)); - } - - position.setNetwork(network); - - return position; - } - - private List decodeMessage( - Channel channel, SocketAddress remoteAddress, String sentence) throws ParseException { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - String imei = parser.next(); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - - String version = parser.next(); - int type = parser.nextInt(); - - List positions = new LinkedList<>(); - String data = parser.next(); - - switch (type) { - case 90: - sendResponse(channel, imei, version, type, getServer(channel, ',')); - break; - case 91: - String time = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); - sendResponse(channel, imei, version, type, time + "|" + getServer(channel, ',')); - break; - case 1: - positions.add(decodeStatus(deviceSession, data)); - sendResponse(channel, imei, version, type, data.split(",")[1]); - break; - case 2: - for (String fragment : data.split("\\|")) { - positions.add(decodePosition(deviceSession, fragment)); - } - break; - case 3: - case 4: - positions.add(decodeNetwork(deviceSession, data, type == 3)); - break; - case 64: - sendResponse(channel, imei, version, type, data); - break; - default: - break; - } - - return positions.isEmpty() ? null : positions; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - buf.skipBytes(3); // header - buf.readUnsignedShort(); // length - - String sentence = buf.toString(buf.readerIndex(), buf.readableBytes() - 3, StandardCharsets.US_ASCII); - - buf.skipBytes(3); // footer - - return decodeMessage(channel, remoteAddress, sentence); - } - -} diff --git a/src/org/traccar/protocol/XexunFrameDecoder.java b/src/org/traccar/protocol/XexunFrameDecoder.java deleted file mode 100644 index 114e94061..000000000 --- a/src/org/traccar/protocol/XexunFrameDecoder.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseFrameDecoder; -import org.traccar.helper.BufferUtil; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class XexunFrameDecoder extends BaseFrameDecoder { - - @Override - protected Object decode( - ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { - - if (buf.readableBytes() < 80) { - return null; - } - - int beginIndex = BufferUtil.indexOf("GPRMC", buf); - if (beginIndex == -1) { - beginIndex = BufferUtil.indexOf("GNRMC", buf); - if (beginIndex == -1) { - return null; - } - } - - int identifierIndex = BufferUtil.indexOf("imei:", buf, beginIndex, buf.writerIndex()); - if (identifierIndex == -1) { - return null; - } - - int endIndex = buf.indexOf(identifierIndex, buf.writerIndex(), (byte) ','); - if (endIndex == -1) { - return null; - } - - buf.skipBytes(beginIndex - buf.readerIndex()); - - return buf.readRetainedSlice(endIndex - beginIndex + 1); - } - -} diff --git a/src/org/traccar/protocol/XexunProtocol.java b/src/org/traccar/protocol/XexunProtocol.java deleted file mode 100644 index 0005270fb..000000000 --- a/src/org/traccar/protocol/XexunProtocol.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.Context; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -import io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; - -public class XexunProtocol extends BaseProtocol { - - public XexunProtocol() { - setSupportedDataCommands( - Command.TYPE_ENGINE_STOP, - Command.TYPE_ENGINE_RESUME); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - boolean full = Context.getConfig().getBoolean(getName() + ".extended"); - if (full) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); // tracker bug \n\r - } else { - pipeline.addLast(new XexunFrameDecoder()); - } - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new XexunProtocolEncoder()); - pipeline.addLast(new XexunProtocolDecoder(XexunProtocol.this, full)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/XexunProtocolDecoder.java b/src/org/traccar/protocol/XexunProtocolDecoder.java deleted file mode 100644 index 5e2d0c05e..000000000 --- a/src/org/traccar/protocol/XexunProtocolDecoder.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class XexunProtocolDecoder extends BaseProtocolDecoder { - - private final boolean full; - - public XexunProtocolDecoder(Protocol protocol, boolean full) { - super(protocol); - this.full = full; - } - - private static final Pattern PATTERN_BASIC = new PatternBuilder() - .expression("G[PN]RMC,") - .number("(?:(dd)(dd)(dd))?.?d*,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(d*?)(d?d.d+),([NS]),") // latitude - .number("(d*?)(d?d.d+),([EW])?,") // longitude - .number("(d+.?d*),") // speed - .number("(d+.?d*)?,") // course - .number("(?:(dd)(dd)(dd))?,") // date (ddmmyy) - .expression("[^*]*").text("*") - .number("xx") // checksum - .expression("\\r\\n").optional() - .expression(",([FL]),") // signal - .expression("([^,]*),").optional() // alarm - .any() - .number("imei:(d+),") // imei - .compile(); - - private static final Pattern PATTERN_FULL = new PatternBuilder() - .any() - .number("(d+),") // serial - .expression("([^,]+)?,") // phone number - .expression(PATTERN_BASIC.pattern()) - .number("(d+),") // satellites - .number("(-?d+.d+)?,") // altitude - .number("[FL]:(d+.d+)V") // power - .any() - .compile(); - - private String decodeStatus(Position position, String value) { - if (value != null) { - switch (value.toLowerCase()) { - case "acc on": - case "accstart": - position.set(Position.KEY_IGNITION, true); - break; - case "acc off": - case "accstop": - position.set(Position.KEY_IGNITION, false); - break; - case "help me!": - position.set(Position.KEY_ALARM, Position.ALARM_SOS); - break; - case "low battery": - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - case "move!": - case "moved!": - position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); - break; - default: - break; - } - } - return null; - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Pattern pattern = PATTERN_BASIC; - if (full) { - pattern = PATTERN_FULL; - } - - Parser parser = new Parser(pattern, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - if (full) { - position.set("serial", parser.next()); - position.set("number", parser.next()); - } - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - position.setSpeed(convertSpeed(parser.nextDouble(0), "kn")); - - position.setCourse(parser.nextDouble(0)); - - dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0)); - position.setTime(dateBuilder.getDate()); - - position.set("signal", parser.next()); - - decodeStatus(position, parser.next()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - if (full) { - position.set(Position.KEY_SATELLITES, parser.nextInt()); - - position.setAltitude(parser.nextDouble(0)); - - position.set(Position.KEY_POWER, parser.nextDouble(0)); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/XexunProtocolEncoder.java b/src/org/traccar/protocol/XexunProtocolEncoder.java deleted file mode 100644 index 515cfbbd0..000000000 --- a/src/org/traccar/protocol/XexunProtocolEncoder.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2016 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class XexunProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - initDevicePassword(command, "123456"); - - switch (command.getType()) { - case Command.TYPE_ENGINE_STOP: - return formatCommand(command, "powercar{%s} 11", Command.KEY_DEVICE_PASSWORD); - case Command.TYPE_ENGINE_RESUME: - return formatCommand(command, "powercar{%s} 00", Command.KEY_DEVICE_PASSWORD); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/XirgoProtocol.java b/src/org/traccar/protocol/XirgoProtocol.java deleted file mode 100644 index 4979fda5d..000000000 --- a/src/org/traccar/protocol/XirgoProtocol.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.CharacterDelimiterFrameDecoder; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; - -public class XirgoProtocol extends BaseProtocol { - - public XirgoProtocol() { - setSupportedDataCommands( - Command.TYPE_OUTPUT_CONTROL); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##")); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new XirgoProtocolEncoder()); - pipeline.addLast(new XirgoProtocolDecoder(XirgoProtocol.this)); - } - }); - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new XirgoProtocolEncoder()); - pipeline.addLast(new XirgoProtocolDecoder(XirgoProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/XirgoProtocolDecoder.java b/src/org/traccar/protocol/XirgoProtocolDecoder.java deleted file mode 100644 index 6d215e672..000000000 --- a/src/org/traccar/protocol/XirgoProtocolDecoder.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright 2015 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class XirgoProtocolDecoder extends BaseProtocolDecoder { - - private Boolean newFormat; - private String form; - - public XirgoProtocolDecoder(Protocol protocol) { - super(protocol); - form = Context.getConfig().getString(getProtocolName() + ".form"); - } - - public void setForm(String form) { - this.form = form; - } - - private static final Pattern PATTERN_OLD = new PatternBuilder() - .text("$$") - .number("(d+),") // imei - .number("(d+),") // event - .number("(dddd)/(dd)/(dd),") // date (yyyy/mm/dd) - .number("(dd):(dd):(dd),") // time (hh:mm:ss) - .number("(-?d+.?d*),") // latitude - .number("(-?d+.?d*),") // longitude - .number("(-?d+.?d*),") // altitude - .number("(d+.?d*),") // speed - .number("(d+.?d*),") // course - .number("(d+),") // satellites - .number("(d+.?d*),") // hdop - .number("(d+.d+),") // battery - .number("(d+),") // gsm - .number("(d+.?d*),") // odometer - .number("(d+),") // gps - .any() - .compile(); - - private static final Pattern PATTERN_NEW = new PatternBuilder() - .text("$$") - .number("(d+),") // imei - .number("(d+),") // event - .number("(dddd)/(dd)/(dd),") // date (yyyy/mm/dd) - .number("(dd):(dd):(dd),") // time (hh:mm:ss) - .number("(-?d+.?d*),") // latitude - .number("(-?d+.?d*),") // longitude - .number("(-?d+.?d*),") // altitude - .number("(d+.?d*),") // speed - .number("d+.?d*,") // acceleration - .number("d+.?d*,") // deceleration - .number("d+,") - .number("(d+.?d*),") // course - .number("(d+),") // satellites - .number("(d+.?d*),") // hdop - .number("(d+.?d*),") // odometer - .number("(d+.?d*),") // fuel consumption - .number("(d+.d+),") // battery - .number("(d+),") // gsm - .number("(d+),") // gps - .groupBegin() - .number("d,") // reset mode - .expression("([01])") // input 1 - .expression("([01])") // input 1 - .expression("([01])") // input 1 - .expression("([01]),") // output 1 - .number("(d+.?d*),") // adc 1 - .number("(d+.?d*),") // fuel level - .number("d+,") // engine load - .number("(d+),") // engine hours - .number("(d+),") // oil pressure - .number("(d+),") // oil level - .number("(-?d+),") // oil temperature - .number("(d+),") // coolant pressure - .number("(d+),") // coolant level - .number("(-?d+)") // coolant temperature - .groupEnd("?") - .any() - .compile(); - - private void decodeEvent(Position position, int event) { - - position.set(Position.KEY_EVENT, event); - - switch (event) { - case 4001: - case 4003: - case 6011: - case 6013: - position.set(Position.KEY_IGNITION, true); - break; - case 4002: - case 4004: - case 6012: - case 6014: - position.set(Position.KEY_IGNITION, false); - break; - case 4005: - position.set(Position.KEY_CHARGE, false); - break; - case 6002: - position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED); - break; - case 6006: - position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - break; - case 6007: - position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - break; - case 6008: - position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER); - break; - case 6009: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT); - break; - case 6010: - position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED); - break; - case 6016: - position.set(Position.KEY_ALARM, Position.ALARM_IDLE); - break; - case 6017: - position.set(Position.KEY_ALARM, Position.ALARM_TOW); - break; - case 6030: - case 6071: - position.set(Position.KEY_MOTION, true); - break; - case 6031: - position.set(Position.KEY_MOTION, false); - break; - case 6032: - position.set(Position.KEY_ALARM, Position.ALARM_PARKING); - break; - case 6090: - position.set(Position.KEY_ALARM, Position.ALARM_REMOVING); - break; - case 6091: - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - default: - break; - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - if (form != null) { - return decodeCustom(channel, remoteAddress, sentence); - } else { - return decodeFixed(channel, remoteAddress, sentence); - } - } - - - private Object decodeCustom( - Channel channel, SocketAddress remoteAddress, String sentence) { - - String[] keys = form.split(","); - String[] values = sentence.replace("$$", "").replace("##", "").split(","); - - Position position = new Position(getProtocolName()); - DateBuilder dateBuilder = new DateBuilder(); - - for (int i = 0; i < Math.min(keys.length, values.length); i++) { - switch (keys[i]) { - case "UID": - case "IM": - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[i]); - if (deviceSession != null) { - position.setDeviceId(deviceSession.getDeviceId()); - } - break; - case "EV": - decodeEvent(position, Integer.parseInt(values[i])); - break; - case "D": - String[] date = values[i].split("/"); - dateBuilder.setMonth(Integer.parseInt(date[0])); - dateBuilder.setDay(Integer.parseInt(date[1])); - dateBuilder.setYear(Integer.parseInt(date[2])); - break; - case "T": - String[] time = values[i].split(":"); - dateBuilder.setHour(Integer.parseInt(time[0])); - dateBuilder.setMinute(Integer.parseInt(time[1])); - dateBuilder.setSecond(Integer.parseInt(time[2])); - break; - case "LT": - position.setLatitude(Double.parseDouble(values[i])); - break; - case "LN": - position.setLongitude(Double.parseDouble(values[i])); - break; - case "AL": - position.setAltitude(Integer.parseInt(values[i])); - break; - case "GSPT": - position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[i]))); - break; - case "HD": - if (values[i].contains(".")) { - position.setCourse(Double.parseDouble(values[i])); - } else { - position.setCourse(Integer.parseInt(values[i]) * 0.1); - } - break; - case "SV": - position.set(Position.KEY_SATELLITES, Integer.parseInt(values[i])); - break; - case "BV": - position.set(Position.KEY_BATTERY, Double.parseDouble(values[i])); - break; - case "CQ": - position.set(Position.KEY_RSSI, Integer.parseInt(values[i])); - break; - case "MI": - position.set(Position.KEY_ODOMETER, Integer.parseInt(values[i])); - break; - case "GS": - position.setValid(Integer.parseInt(values[i]) == 3); - break; - case "SI": - position.set("iccid", values[i]); - break; - case "IG": - int ignition = Integer.parseInt(values[i]); - if (ignition > 0) { - position.set(Position.KEY_IGNITION, ignition == 1); - } - break; - case "OT": - position.set(Position.KEY_OUTPUT, Integer.parseInt(values[i])); - break; - default: - break; - } - } - - position.setTime(dateBuilder.getDate()); - - return position.getDeviceId() > 0 ? position : null; - } - - private Object decodeFixed( - Channel channel, SocketAddress remoteAddress, String sentence) { - - Parser parser; - if (newFormat == null) { - parser = new Parser(PATTERN_NEW, sentence); - if (parser.matches()) { - newFormat = true; - } else { - parser = new Parser(PATTERN_OLD, sentence); - if (parser.matches()) { - newFormat = false; - } else { - return null; - } - } - } else { - if (newFormat) { - parser = new Parser(PATTERN_NEW, sentence); - } else { - parser = new Parser(PATTERN_OLD, sentence); - } - if (!parser.matches()) { - return null; - } - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - decodeEvent(position, parser.nextInt()); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_HDOP, parser.nextDouble()); - - if (newFormat) { - position.set(Position.KEY_ODOMETER, UnitsConverter.metersFromMiles(parser.nextDouble(0))); - position.set(Position.KEY_FUEL_CONSUMPTION, parser.next()); - } - - position.set(Position.KEY_BATTERY, parser.nextDouble(0)); - position.set(Position.KEY_RSSI, parser.nextDouble()); - - if (!newFormat) { - position.set(Position.KEY_ODOMETER, UnitsConverter.metersFromMiles(parser.nextDouble(0))); - } - - position.setValid(parser.nextInt(0) == 1); - - if (newFormat && parser.hasNext(13)) { - position.set(Position.PREFIX_IN + 1, parser.nextInt()); - position.set(Position.PREFIX_IN + 2, parser.nextInt()); - position.set(Position.PREFIX_IN + 3, parser.nextInt()); - position.set(Position.PREFIX_OUT + 1, parser.nextInt()); - position.set(Position.PREFIX_ADC + 1, parser.nextDouble()); - position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble()); - position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(parser.nextInt())); - position.set("oilPressure", parser.nextInt()); - position.set("oilLevel", parser.nextInt()); - position.set("oilTemp", parser.nextInt()); - position.set("coolantPressure", parser.nextInt()); - position.set("coolantLevel", parser.nextInt()); - position.set("coolantTemp", parser.nextInt()); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/XirgoProtocolEncoder.java b/src/org/traccar/protocol/XirgoProtocolEncoder.java deleted file mode 100644 index dd5e30cca..000000000 --- a/src/org/traccar/protocol/XirgoProtocolEncoder.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2017 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. - * 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 org.traccar.StringProtocolEncoder; -import org.traccar.model.Command; - -public class XirgoProtocolEncoder extends StringProtocolEncoder { - - @Override - protected Object encodeCommand(Command command) { - - switch (command.getType()) { - case Command.TYPE_OUTPUT_CONTROL: - return String.format("+XT:7005,%d,1", command.getInteger(Command.KEY_DATA) + 1); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Xrb28Protocol.java b/src/org/traccar/protocol/Xrb28Protocol.java deleted file mode 100644 index b1f1c34fb..000000000 --- a/src/org/traccar/protocol/Xrb28Protocol.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; -import org.traccar.model.Command; - -import java.nio.charset.StandardCharsets; - -public class Xrb28Protocol extends BaseProtocol { - - public Xrb28Protocol() { - setSupportedDataCommands( - Command.TYPE_CUSTOM, - Command.TYPE_POSITION_SINGLE, - Command.TYPE_POSITION_PERIODIC, - Command.TYPE_ALARM_ARM, - Command.TYPE_ALARM_DISARM); - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder(StandardCharsets.ISO_8859_1)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new Xrb28ProtocolEncoder()); - pipeline.addLast(new Xrb28ProtocolDecoder(Xrb28Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Xrb28ProtocolDecoder.java b/src/org/traccar/protocol/Xrb28ProtocolDecoder.java deleted file mode 100644 index 938394d6b..000000000 --- a/src/org/traccar/protocol/Xrb28ProtocolDecoder.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.DateBuilder; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.model.Command; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Xrb28ProtocolDecoder extends BaseProtocolDecoder { - - private String pendingCommand; - - public void setPendingCommand(String pendingCommand) { - this.pendingCommand = pendingCommand; - } - - public Xrb28ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .text("*") - .expression("....,") - .expression("..,") // vendor - .number("d{15},") // imei - .expression("..,") // type - .number("0,") // reserved - .number("(dd)(dd)(dd).d+,") // time (hhmmss) - .expression("([AV]),") // validity - .number("(dd)(dd.d+),") // latitude - .expression("([NS]),") - .number("(d{2,3})(dd.d+),") // longitude - .expression("([EW]),") - .number("(d+),") // satellites - .number("(d+.d+),") // hdop - .number("(dd)(dd)(dd),") // date (ddmmyy) - .number("(-?d+.?d*),") // altitude - .expression(".,") // height unit - .expression(".#") // mode - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(9, 24)); - if (deviceSession == null) { - return null; - } - - String type = sentence.substring(25, 27); - if (channel != null) { - if (type.matches("L0|L1|W0|E1")) { - channel.write(new NetworkMessage( - "\u00ff\u00ff*SCOS" + sentence.substring(5, 27) + "#\n", - remoteAddress)); - } else if (type.equals("R0") && pendingCommand != null) { - String command = pendingCommand.equals(Command.TYPE_ALARM_ARM) ? "L1," : "L0,"; - channel.write(new NetworkMessage( - "\u00ff\u00ff*SCOS" + sentence.substring(5, 25) + command + sentence.substring(30) + "\n", - remoteAddress)); - pendingCommand = null; - } - } - - if (!type.startsWith("D")) { - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - getLastLocation(position, null); - - String payload = sentence.substring(25, sentence.length() - 1); - - int index = 0; - String[] values = payload.substring(3).split(","); - - switch (type) { - case "Q0": - position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.01); - position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[index++])); - position.set(Position.KEY_RSSI, Integer.parseInt(values[index++])); - break; - case "H0": - position.set(Position.KEY_BLOCKED, Integer.parseInt(values[index++]) > 0); - position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.01); - position.set(Position.KEY_RSSI, Integer.parseInt(values[index++])); - position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[index++])); - break; - case "W0": - switch (Integer.parseInt(values[index++])) { - case 1: - position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT); - break; - case 2: - position.set(Position.KEY_ALARM, Position.ALARM_FALL_DOWN); - break; - case 3: - position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY); - break; - default: - break; - } - break; - case "E0": - position.set(Position.KEY_ALARM, Position.ALARM_FAULT); - position.set("error", Integer.parseInt(values[index++])); - break; - case "S1": - position.set(Position.KEY_EVENT, Integer.parseInt(values[index++])); - break; - case "R0": - case "L0": - case "L1": - case "S4": - case "S5": - case "S6": - case "S7": - case "V0": - case "G0": - case "K0": - case "I0": - case "M0": - position.set(Position.KEY_RESULT, payload); - break; - default: - break; - } - - return !position.getAttributes().isEmpty() ? position : null; - - } else { - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - - DateBuilder dateBuilder = new DateBuilder() - .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); - - position.setValid(parser.next().equals("A")); - position.setLatitude(parser.nextCoordinate()); - position.setLongitude(parser.nextCoordinate()); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_HDOP, parser.nextDouble()); - - dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); - position.setTime(dateBuilder.getDate()); - - position.setAltitude(parser.nextDouble()); - - return position; - - } - } - -} diff --git a/src/org/traccar/protocol/Xrb28ProtocolEncoder.java b/src/org/traccar/protocol/Xrb28ProtocolEncoder.java deleted file mode 100644 index 617639312..000000000 --- a/src/org/traccar/protocol/Xrb28ProtocolEncoder.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolEncoder; -import org.traccar.model.Command; - -public class Xrb28ProtocolEncoder extends BaseProtocolEncoder { - - private String formatCommand(Command command, String content) { - return String.format("\u00ff\u00ff*SCOS,OM,%s,%s#\n", getUniqueId(command.getDeviceId()), content); - } - - @Override - protected Object encodeCommand(Channel channel, Command command) { - - switch (command.getType()) { - case Command.TYPE_CUSTOM: - return formatCommand(command, command.getString(Command.KEY_DATA)); - case Command.TYPE_POSITION_SINGLE: - return formatCommand(command, "D0"); - case Command.TYPE_POSITION_PERIODIC: - return formatCommand(command, "D1," + command.getInteger(Command.KEY_FREQUENCY)); - case Command.TYPE_ENGINE_STOP: - case Command.TYPE_ALARM_DISARM: - if (channel != null) { - Xrb28ProtocolDecoder decoder = channel.pipeline().get(Xrb28ProtocolDecoder.class); - if (decoder != null) { - decoder.setPendingCommand(command.getType()); - } - } - return formatCommand(command, "R0,0,20,1234," + System.currentTimeMillis() / 1000); - default: - return null; - } - } - -} diff --git a/src/org/traccar/protocol/Xt013Protocol.java b/src/org/traccar/protocol/Xt013Protocol.java deleted file mode 100644 index ebb3c123f..000000000 --- a/src/org/traccar/protocol/Xt013Protocol.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -import io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; - -public class Xt013Protocol extends BaseProtocol { - - public Xt013Protocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new Xt013ProtocolDecoder(Xt013Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Xt013ProtocolDecoder.java b/src/org/traccar/protocol/Xt013ProtocolDecoder.java deleted file mode 100644 index f49fb9563..000000000 --- a/src/org/traccar/protocol/Xt013ProtocolDecoder.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2015 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class Xt013ProtocolDecoder extends BaseProtocolDecoder { - - public Xt013ProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .number("HI,d+").optional() - .text("TK,") - .number("(d+),") // imei - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .number("([+-]d+.d+),") // latitude - .number("([+-]d+.d+),") // longitude - .number("(d+),") // speed - .number("(d+),") // course - .number("d+,") - .number("(d+),") // altitude - .expression("([FL]),") // gps fix - .number("d+,") - .number("(d+),") // gps level - .number("x+,") - .number("x+,") - .number("(d+),") // gsm level - .expression("[^,]*,") - .number("(d+.d+),") // battery - .number("(d),") // charging - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - Parser parser = new Parser(PATTERN, (String) msg); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setLatitude(parser.nextDouble(0)); - position.setLongitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0))); - position.setCourse(parser.nextDouble(0)); - position.setAltitude(parser.nextDouble(0)); - position.setValid(parser.next().equals("F")); - - position.set(Position.KEY_SATELLITES, parser.nextInt()); - position.set(Position.KEY_RSSI, parser.nextDouble()); - position.set(Position.KEY_BATTERY, parser.nextDouble(0)); - position.set(Position.KEY_CHARGE, parser.next().equals("1")); - - return position; - } - -} diff --git a/src/org/traccar/protocol/Xt2400Protocol.java b/src/org/traccar/protocol/Xt2400Protocol.java deleted file mode 100644 index 9427876c8..000000000 --- a/src/org/traccar/protocol/Xt2400Protocol.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class Xt2400Protocol extends BaseProtocol { - - public Xt2400Protocol() { - addServer(new TrackerServer(true, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new Xt2400ProtocolDecoder(Xt2400Protocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/org/traccar/protocol/Xt2400ProtocolDecoder.java deleted file mode 100644 index 819011a50..000000000 --- a/src/org/traccar/protocol/Xt2400ProtocolDecoder.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2017 - 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. - * 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 io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.Context; -import org.traccar.DeviceSession; -import org.traccar.Protocol; -import org.traccar.helper.DataConverter; -import org.traccar.helper.UnitsConverter; -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.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class Xt2400ProtocolDecoder extends BaseProtocolDecoder { - - public Xt2400ProtocolDecoder(Protocol protocol) { - super(protocol); - - String config = Context.getConfig().getString(getProtocolName() + ".config"); - if (config != null) { - setConfig(config); - } - } - - private static final Map TAG_LENGTH_MAP = new HashMap<>(); - - static { - int[] l1 = { - 0x01, 0x02, 0x04, 0x0b, 0x0c, 0x0d, 0x12, 0x13, - 0x16, 0x17, 0x1c, 0x1f, 0x23, 0x2c, 0x2d, 0x30, - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x40, 0x41, - 0x53, 0x66, 0x69, 0x6a, 0x93, 0x94, 0x96 - }; - int[] l2 = { - 0x05, 0x09, 0x0a, 0x14, 0x15, 0x1d, 0x1e, 0x24, - 0x26, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x57, 0x58, 0x59, 0x5a, 0x6b, 0x6f, 0x7A, - 0x7B, 0x7C, 0x7d, 0x7E, 0x7F, 0x80, 0x81, 0x82, - 0x83, 0x84, 0x85, 0x86 - }; - int[] l4 = { - 0x03, 0x06, 0x07, 0x08, 0x0e, 0x0f, 0x10, 0x11, - 0x18, 0x19, 0x1a, 0x1b, 0x20, 0x21, 0x22, 0x2e, - 0x2f, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, - 0x51, 0x52, 0x54, 0x55, 0x56, 0x5b, 0x5c, 0x5d, - 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x68, 0x6e, 0x71, - 0x72, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d - }; - for (int i : l1) { - TAG_LENGTH_MAP.put(i, 1); - } - for (int i : l2) { - TAG_LENGTH_MAP.put(i, 2); - } - for (int i : l4) { - TAG_LENGTH_MAP.put(i, 4); - } - TAG_LENGTH_MAP.put(0x95, 24); - } - - private static int getTagLength(int tag) { - Integer length = TAG_LENGTH_MAP.get(tag); - if (length == null) { - throw new IllegalArgumentException("Unknown tag: " + tag); - } - return length; - } - - private Map formats = new HashMap<>(); - - public void setConfig(String configString) { - Pattern pattern = Pattern.compile(":wycfg pcr\\[\\d+\\] ([0-9a-fA-F]{2})[0-9a-fA-F]{2}([0-9a-fA-F]+)"); - Matcher matcher = pattern.matcher(configString); - while (matcher.find()) { - formats.put(Short.parseShort(matcher.group(1), 16), DataConverter.parseHex(matcher.group(2))); - } - } - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ByteBuf buf = (ByteBuf) msg; - - byte[] format = null; - if (formats.size() > 1) { - format = formats.get(buf.getUnsignedByte(buf.readerIndex())); - } else if (!formats.isEmpty()) { - format = formats.values().iterator().next(); - } - - if (format == null) { - return null; - } - - Position position = new Position(getProtocolName()); - - for (byte tag : format) { - switch (tag) { - case 0x03: - DeviceSession deviceSession = getDeviceSession( - channel, remoteAddress, String.valueOf(buf.readUnsignedInt())); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - break; - case 0x04: - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - break; - case 0x05: - position.set(Position.KEY_INDEX, buf.readUnsignedShort()); - break; - case 0x06: - position.setTime(new Date(buf.readUnsignedInt() * 1000)); - break; - case 0x07: - position.setLatitude(buf.readInt() * 0.000001); - break; - case 0x08: - position.setLongitude(buf.readInt() * 0.000001); - break; - case 0x09: - position.setAltitude(buf.readShort() * 0.1); - break; - case 0x0a: - position.setCourse(buf.readShort() * 0.1); - break; - case 0x0b: - position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte())); - break; - case 0x10: - position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt()); - break; - case 0x12: - position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1); - break; - case 0x13: - position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); - break; - case 0x14: - position.set(Position.KEY_RSSI, buf.readShort()); - break; - case 0x16: - position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.1); - break; - case 0x17: - position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); - break; - case 0x57: - position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(buf.readUnsignedShort())); - break; - case 0x65: - position.set(Position.KEY_VIN, buf.readSlice(17).toString(StandardCharsets.US_ASCII)); - break; - case 0x73: - position.set(Position.KEY_VERSION_FW, buf.readSlice(16).toString(StandardCharsets.US_ASCII).trim()); - break; - default: - buf.skipBytes(getTagLength(tag)); - break; - } - } - - if (position.getLatitude() != 0 && position.getLongitude() != 0) { - position.setValid(true); - } else { - getLastLocation(position, position.getDeviceTime()); - } - - return position; - } - -} diff --git a/src/org/traccar/protocol/YwtProtocol.java b/src/org/traccar/protocol/YwtProtocol.java deleted file mode 100644 index c525b75cf..000000000 --- a/src/org/traccar/protocol/YwtProtocol.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * 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 io.netty.handler.codec.LineBasedFrameDecoder; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import org.traccar.BaseProtocol; -import org.traccar.PipelineBuilder; -import org.traccar.TrackerServer; - -public class YwtProtocol extends BaseProtocol { - - public YwtProtocol() { - addServer(new TrackerServer(false, getName()) { - @Override - protected void addProtocolHandlers(PipelineBuilder pipeline) { - pipeline.addLast(new LineBasedFrameDecoder(1024)); - pipeline.addLast(new StringEncoder()); - pipeline.addLast(new StringDecoder()); - pipeline.addLast(new YwtProtocolDecoder(YwtProtocol.this)); - } - }); - } - -} diff --git a/src/org/traccar/protocol/YwtProtocolDecoder.java b/src/org/traccar/protocol/YwtProtocolDecoder.java deleted file mode 100644 index bf5a23fa7..000000000 --- a/src/org/traccar/protocol/YwtProtocolDecoder.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2013 - 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. - * 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 io.netty.channel.Channel; -import org.traccar.BaseProtocolDecoder; -import org.traccar.DeviceSession; -import org.traccar.NetworkMessage; -import org.traccar.Protocol; -import org.traccar.helper.Parser; -import org.traccar.helper.PatternBuilder; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -import java.net.SocketAddress; -import java.util.regex.Pattern; - -public class YwtProtocolDecoder extends BaseProtocolDecoder { - - public YwtProtocolDecoder(Protocol protocol) { - super(protocol); - } - - private static final Pattern PATTERN = new PatternBuilder() - .expression("%(..),") // type - .number("(d+):") // unit identifier - .number("d+,") // subtype - .number("(dd)(dd)(dd)") // date (yymmdd) - .number("(dd)(dd)(dd),") // time (hhmmss) - .expression("([EW])") - .number("(ddd.d{6}),") // longitude - .expression("([NS])") - .number("(dd.d{6}),") // latitude - .number("(d+)?,") // altitude - .number("(d+),") // speed - .number("(d+),") // course - .number("(d+),") // satellite - .expression("([^,]+),") // report identifier - .expression("([-0-9a-fA-F]+)") // status - .any() - .compile(); - - @Override - protected Object decode( - Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - String sentence = (String) msg; - - // Synchronization - if (sentence.startsWith("%SN") && channel != null) { - int start = sentence.indexOf(':'); - int end = start; - for (int i = 0; i < 4; i++) { - end = sentence.indexOf(',', end + 1); - } - if (end == -1) { - end = sentence.length(); - } - - channel.writeAndFlush(new NetworkMessage("%AT+SN=" + sentence.substring(start, end), remoteAddress)); - return null; - } - - Parser parser = new Parser(PATTERN, sentence); - if (!parser.matches()) { - return null; - } - - Position position = new Position(getProtocolName()); - - String type = parser.next(); - - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - position.setTime(parser.nextDateTime()); - - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG)); - position.setAltitude(parser.nextDouble(0)); - position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); - position.setCourse(parser.nextDouble()); - - int satellites = parser.nextInt(); - position.setValid(satellites != 0); - position.set(Position.KEY_SATELLITES, satellites); - - String reportId = parser.next(); - - position.set(Position.KEY_STATUS, parser.next()); - - // Send response - if ((type.equals("KP") || type.equals("EP")) && channel != null) { - channel.writeAndFlush(new NetworkMessage("%AT+" + type + "=" + reportId + "\r\n", remoteAddress)); - } - - return position; - } - -} diff --git a/src/org/traccar/reports/Events.java b/src/org/traccar/reports/Events.java deleted file mode 100644 index 66d9e708d..000000000 --- a/src/org/traccar/reports/Events.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; - -import org.apache.poi.ss.util.WorkbookUtil; -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Geofence; -import org.traccar.model.Group; -import org.traccar.model.Maintenance; -import org.traccar.reports.model.DeviceReport; - -public final class Events { - - private Events() { - } - - public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Collection types, Date from, Date to) throws SQLException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - Collection events = Context.getDataManager().getEvents(deviceId, from, to); - boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS); - for (Event event : events) { - if (all || types.contains(event.getType())) { - long geofenceId = event.getGeofenceId(); - long maintenanceId = event.getMaintenanceId(); - if ((geofenceId == 0 || Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) - && (maintenanceId == 0 - || Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId))) { - result.add(event); - } - } - } - } - return result; - } - - public static void getExcel(OutputStream outputStream, - long userId, Collection deviceIds, Collection groupIds, - Collection types, Date from, Date to) throws SQLException, IOException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList devicesEvents = new ArrayList<>(); - ArrayList sheetNames = new ArrayList<>(); - HashMap geofenceNames = new HashMap<>(); - HashMap maintenanceNames = new HashMap<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - Collection events = Context.getDataManager().getEvents(deviceId, from, to); - boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS); - for (Iterator iterator = events.iterator(); iterator.hasNext();) { - Event event = iterator.next(); - if (all || types.contains(event.getType())) { - long geofenceId = event.getGeofenceId(); - long maintenanceId = event.getMaintenanceId(); - if (geofenceId != 0) { - if (Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) { - Geofence geofence = Context.getGeofenceManager().getById(geofenceId); - if (geofence != null) { - geofenceNames.put(geofenceId, geofence.getName()); - } - } else { - iterator.remove(); - } - } else if (maintenanceId != 0) { - if (Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId)) { - Maintenance maintenance = Context.getMaintenancesManager().getById(maintenanceId); - if (maintenance != null) { - maintenanceNames.put(maintenanceId, maintenance.getName()); - } - } else { - iterator.remove(); - } - } - } else { - iterator.remove(); - } - } - DeviceReport deviceEvents = new DeviceReport(); - Device device = Context.getIdentityManager().getById(deviceId); - deviceEvents.setDeviceName(device.getName()); - sheetNames.add(WorkbookUtil.createSafeSheetName(deviceEvents.getDeviceName())); - if (device.getGroupId() != 0) { - Group group = Context.getGroupsManager().getById(device.getGroupId()); - if (group != null) { - deviceEvents.setGroupName(group.getName()); - } - } - deviceEvents.setObjects(events); - devicesEvents.add(deviceEvents); - } - String templatePath = Context.getConfig().getString("report.templatesPath", - "templates/export/"); - try (InputStream inputStream = new FileInputStream(templatePath + "/events.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); - jxlsContext.putVar("devices", devicesEvents); - jxlsContext.putVar("sheetNames", sheetNames); - jxlsContext.putVar("geofenceNames", geofenceNames); - jxlsContext.putVar("maintenanceNames", maintenanceNames); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); - } - } -} diff --git a/src/org/traccar/reports/ReportUtils.java b/src/org/traccar/reports/ReportUtils.java deleted file mode 100644 index 3a631e0d9..000000000 --- a/src/org/traccar/reports/ReportUtils.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports; - -import org.apache.velocity.tools.generic.DateTool; -import org.apache.velocity.tools.generic.NumberTool; -import org.jxls.area.Area; -import org.jxls.builder.xls.XlsCommentAreaBuilder; -import org.jxls.common.CellRef; -import org.jxls.formula.StandardFormulaProcessor; -import org.jxls.transform.Transformer; -import org.jxls.transform.poi.PoiTransformer; -import org.jxls.util.TransformerFactory; -import org.traccar.Context; -import org.traccar.database.DeviceManager; -import org.traccar.database.IdentityManager; -import org.traccar.handler.events.MotionEventHandler; -import org.traccar.model.DeviceState; -import org.traccar.model.Driver; -import org.traccar.model.Event; -import org.traccar.model.Position; -import org.traccar.reports.model.BaseReport; -import org.traccar.reports.model.StopReport; -import org.traccar.reports.model.TripReport; -import org.traccar.reports.model.TripsConfig; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; - -public final class ReportUtils { - - private ReportUtils() { - } - - public static void checkPeriodLimit(Date from, Date to) { - long limit = Context.getConfig().getLong("report.periodLimit") * 1000; - if (limit > 0 && to.getTime() - from.getTime() > limit) { - throw new IllegalArgumentException("Time period exceeds the limit"); - } - } - - public static String getDistanceUnit(long userId) { - return (String) Context.getPermissionsManager().lookupAttribute(userId, "distanceUnit", "km"); - } - - public static String getSpeedUnit(long userId) { - return (String) Context.getPermissionsManager().lookupAttribute(userId, "speedUnit", "kn"); - } - - public static String getVolumeUnit(long userId) { - return (String) Context.getPermissionsManager().lookupAttribute(userId, "volumeUnit", "ltr"); - } - - public static TimeZone getTimezone(long userId) { - String timezone = (String) Context.getPermissionsManager().lookupAttribute(userId, "timezone", null); - return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); - } - - public static Collection getDeviceList(Collection deviceIds, Collection groupIds) { - Collection result = new ArrayList<>(); - result.addAll(deviceIds); - for (long groupId : groupIds) { - result.addAll(Context.getPermissionsManager().getGroupDevices(groupId)); - } - return result; - } - - public static double calculateDistance(Position firstPosition, Position lastPosition) { - return calculateDistance(firstPosition, lastPosition, true); - } - - public static double calculateDistance(Position firstPosition, Position lastPosition, boolean useOdometer) { - double distance = 0.0; - double firstOdometer = firstPosition.getDouble(Position.KEY_ODOMETER); - double lastOdometer = lastPosition.getDouble(Position.KEY_ODOMETER); - - if (useOdometer && (firstOdometer != 0.0 || lastOdometer != 0.0)) { - distance = lastOdometer - firstOdometer; - } else if (firstPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE) - && lastPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) { - distance = lastPosition.getDouble(Position.KEY_TOTAL_DISTANCE) - - firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE); - } - return distance; - } - - public static double calculateFuel(Position firstPosition, Position lastPosition) { - - if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null - && lastPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null) { - - BigDecimal value = new BigDecimal(firstPosition.getDouble(Position.KEY_FUEL_LEVEL) - - lastPosition.getDouble(Position.KEY_FUEL_LEVEL)); - return value.setScale(1, RoundingMode.HALF_EVEN).doubleValue(); - } - return 0; - } - - public static String findDriver(Position firstPosition, Position lastPosition) { - if (firstPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { - return firstPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); - } else if (lastPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { - return lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); - } - return null; - } - - public static String findDriverName(String driverUniqueId) { - if (driverUniqueId != null && Context.getDriversManager() != null) { - Driver driver = Context.getDriversManager().getDriverByUniqueId(driverUniqueId); - if (driver != null) { - return driver.getName(); - } - } - return null; - } - - public static org.jxls.common.Context initializeContext(long userId) { - org.jxls.common.Context jxlsContext = PoiTransformer.createInitialContext(); - jxlsContext.putVar("distanceUnit", getDistanceUnit(userId)); - jxlsContext.putVar("speedUnit", getSpeedUnit(userId)); - jxlsContext.putVar("volumeUnit", getVolumeUnit(userId)); - jxlsContext.putVar("webUrl", Context.getVelocityEngine().getProperty("web.url")); - jxlsContext.putVar("dateTool", new DateTool()); - jxlsContext.putVar("numberTool", new NumberTool()); - jxlsContext.putVar("timezone", getTimezone(userId)); - jxlsContext.putVar("locale", Locale.getDefault()); - jxlsContext.putVar("bracketsRegex", "[\\{\\}\"]"); - return jxlsContext; - } - - public static void processTemplateWithSheets( - InputStream templateStream, OutputStream targetStream, - org.jxls.common.Context jxlsContext) throws IOException { - - Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream); - List xlsAreas = new XlsCommentAreaBuilder(transformer).build(); - for (Area xlsArea : xlsAreas) { - xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), jxlsContext); - xlsArea.setFormulaProcessor(new StandardFormulaProcessor()); - xlsArea.processFormulas(); - } - transformer.deleteSheet(xlsAreas.get(0).getStartCellRef().getSheetName()); - transformer.write(); - } - - private static TripReport calculateTrip( - ArrayList positions, int startIndex, int endIndex, boolean ignoreOdometer) { - - Position startTrip = positions.get(startIndex); - Position endTrip = positions.get(endIndex); - - double speedMax = 0.0; - double speedSum = 0.0; - for (int i = startIndex; i <= endIndex; i++) { - double speed = positions.get(i).getSpeed(); - speedSum += speed; - if (speed > speedMax) { - speedMax = speed; - } - } - - TripReport trip = new TripReport(); - - long tripDuration = endTrip.getFixTime().getTime() - startTrip.getFixTime().getTime(); - long deviceId = startTrip.getDeviceId(); - trip.setDeviceId(deviceId); - trip.setDeviceName(Context.getIdentityManager().getById(deviceId).getName()); - - trip.setStartPositionId(startTrip.getId()); - trip.setStartLat(startTrip.getLatitude()); - trip.setStartLon(startTrip.getLongitude()); - trip.setStartTime(startTrip.getFixTime()); - String startAddress = startTrip.getAddress(); - if (startAddress == null && Context.getGeocoder() != null - && Context.getConfig().getBoolean("geocoder.onRequest")) { - startAddress = Context.getGeocoder().getAddress(startTrip.getLatitude(), startTrip.getLongitude(), null); - } - trip.setStartAddress(startAddress); - - trip.setEndPositionId(endTrip.getId()); - trip.setEndLat(endTrip.getLatitude()); - trip.setEndLon(endTrip.getLongitude()); - trip.setEndTime(endTrip.getFixTime()); - String endAddress = endTrip.getAddress(); - if (endAddress == null && Context.getGeocoder() != null - && Context.getConfig().getBoolean("geocoder.onRequest")) { - endAddress = Context.getGeocoder().getAddress(endTrip.getLatitude(), endTrip.getLongitude(), null); - } - trip.setEndAddress(endAddress); - - trip.setDistance(calculateDistance(startTrip, endTrip, !ignoreOdometer)); - trip.setDuration(tripDuration); - trip.setAverageSpeed(speedSum / (endIndex - startIndex)); - trip.setMaxSpeed(speedMax); - trip.setSpentFuel(calculateFuel(startTrip, endTrip)); - - trip.setDriverUniqueId(findDriver(startTrip, endTrip)); - trip.setDriverName(findDriverName(trip.getDriverUniqueId())); - - if (!ignoreOdometer - && startTrip.getDouble(Position.KEY_ODOMETER) != 0 - && endTrip.getDouble(Position.KEY_ODOMETER) != 0) { - trip.setStartOdometer(startTrip.getDouble(Position.KEY_ODOMETER)); - trip.setEndOdometer(endTrip.getDouble(Position.KEY_ODOMETER)); - } else { - trip.setStartOdometer(startTrip.getDouble(Position.KEY_TOTAL_DISTANCE)); - trip.setEndOdometer(endTrip.getDouble(Position.KEY_TOTAL_DISTANCE)); - } - - return trip; - } - - private static StopReport calculateStop( - ArrayList positions, int startIndex, int endIndex, boolean ignoreOdometer) { - - Position startStop = positions.get(startIndex); - Position endStop = positions.get(endIndex); - - StopReport stop = new StopReport(); - - long deviceId = startStop.getDeviceId(); - stop.setDeviceId(deviceId); - stop.setDeviceName(Context.getIdentityManager().getById(deviceId).getName()); - - stop.setPositionId(startStop.getId()); - stop.setLatitude(startStop.getLatitude()); - stop.setLongitude(startStop.getLongitude()); - stop.setStartTime(startStop.getFixTime()); - String address = startStop.getAddress(); - if (address == null && Context.getGeocoder() != null - && Context.getConfig().getBoolean("geocoder.onRequest")) { - address = Context.getGeocoder().getAddress(stop.getLatitude(), stop.getLongitude(), null); - } - stop.setAddress(address); - - stop.setEndTime(endStop.getFixTime()); - - long stopDuration = endStop.getFixTime().getTime() - startStop.getFixTime().getTime(); - stop.setDuration(stopDuration); - stop.setSpentFuel(calculateFuel(startStop, endStop)); - - long engineHours = 0; - if (startStop.getAttributes().containsKey(Position.KEY_HOURS) - && endStop.getAttributes().containsKey(Position.KEY_HOURS)) { - engineHours = endStop.getLong(Position.KEY_HOURS) - startStop.getLong(Position.KEY_HOURS); - } else if (Context.getConfig().getBoolean("processing.engineHours.enable")) { - // Temporary fallback for old data, to be removed in May 2019 - for (int i = startIndex + 1; i <= endIndex; i++) { - if (positions.get(i).getBoolean(Position.KEY_IGNITION) - && positions.get(i - 1).getBoolean(Position.KEY_IGNITION)) { - engineHours += positions.get(i).getFixTime().getTime() - - positions.get(i - 1).getFixTime().getTime(); - } - } - } - stop.setEngineHours(engineHours); - - if (!ignoreOdometer - && startStop.getDouble(Position.KEY_ODOMETER) != 0 - && endStop.getDouble(Position.KEY_ODOMETER) != 0) { - stop.setStartOdometer(startStop.getDouble(Position.KEY_ODOMETER)); - stop.setEndOdometer(endStop.getDouble(Position.KEY_ODOMETER)); - } else { - stop.setStartOdometer(startStop.getDouble(Position.KEY_TOTAL_DISTANCE)); - stop.setEndOdometer(endStop.getDouble(Position.KEY_TOTAL_DISTANCE)); - } - - return stop; - - } - - private static T calculateTripOrStop( - ArrayList positions, int startIndex, int endIndex, boolean ignoreOdometer, Class reportClass) { - - if (reportClass.equals(TripReport.class)) { - return (T) calculateTrip(positions, startIndex, endIndex, ignoreOdometer); - } else { - return (T) calculateStop(positions, startIndex, endIndex, ignoreOdometer); - } - } - - private static boolean isMoving(ArrayList positions, int index, TripsConfig tripsConfig) { - if (tripsConfig.getMinimalNoDataDuration() > 0) { - boolean beforeGap = index < positions.size() - 1 - && positions.get(index + 1).getFixTime().getTime() - positions.get(index).getFixTime().getTime() - >= tripsConfig.getMinimalNoDataDuration(); - boolean afterGap = index > 0 - && positions.get(index).getFixTime().getTime() - positions.get(index - 1).getFixTime().getTime() - >= tripsConfig.getMinimalNoDataDuration(); - if (beforeGap || afterGap) { - return false; - } - } - if (positions.get(index).getAttributes().containsKey(Position.KEY_MOTION) - && positions.get(index).getAttributes().get(Position.KEY_MOTION) instanceof Boolean) { - return positions.get(index).getBoolean(Position.KEY_MOTION); - } else { - return positions.get(index).getSpeed() > tripsConfig.getSpeedThreshold(); - } - } - - public static Collection detectTripsAndStops( - IdentityManager identityManager, DeviceManager deviceManager, - Collection positionCollection, - TripsConfig tripsConfig, boolean ignoreOdometer, Class reportClass) { - - Collection result = new ArrayList<>(); - - ArrayList positions = new ArrayList<>(positionCollection); - if (!positions.isEmpty()) { - boolean trips = reportClass.equals(TripReport.class); - MotionEventHandler motionHandler = new MotionEventHandler(identityManager, deviceManager, tripsConfig); - DeviceState deviceState = new DeviceState(); - deviceState.setMotionState(isMoving(positions, 0, tripsConfig)); - int startEventIndex = trips == deviceState.getMotionState() ? 0 : -1; - int startNoEventIndex = -1; - for (int i = 0; i < positions.size(); i++) { - Map event = motionHandler.updateMotionState(deviceState, positions.get(i), - isMoving(positions, i, tripsConfig)); - if (startEventIndex == -1 - && (trips != deviceState.getMotionState() && deviceState.getMotionPosition() != null - || trips == deviceState.getMotionState() && event != null)) { - startEventIndex = i; - startNoEventIndex = -1; - } else if (trips != deviceState.getMotionState() && startEventIndex != -1 - && deviceState.getMotionPosition() == null && event == null) { - startEventIndex = -1; - } - if (startNoEventIndex == -1 - && (trips == deviceState.getMotionState() && deviceState.getMotionPosition() != null - || trips != deviceState.getMotionState() && event != null)) { - startNoEventIndex = i; - } else if (startNoEventIndex != -1 && deviceState.getMotionPosition() == null && event == null) { - startNoEventIndex = -1; - } - if (startEventIndex != -1 && startNoEventIndex != -1 && event != null - && trips != deviceState.getMotionState()) { - result.add(calculateTripOrStop(positions, startEventIndex, startNoEventIndex, - ignoreOdometer, reportClass)); - startEventIndex = -1; - } - } - if (startEventIndex != -1 && (startNoEventIndex != -1 || !trips)) { - result.add(calculateTripOrStop(positions, startEventIndex, - startNoEventIndex != -1 ? startNoEventIndex : positions.size() - 1, - ignoreOdometer, reportClass)); - } - } - - return result; - } - -} diff --git a/src/org/traccar/reports/Route.java b/src/org/traccar/reports/Route.java deleted file mode 100644 index 6adb00aae..000000000 --- a/src/org/traccar/reports/Route.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; - -import org.apache.poi.ss.util.WorkbookUtil; -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.Group; -import org.traccar.model.Position; -import org.traccar.reports.model.DeviceReport; - -public final class Route { - - private Route() { - } - - public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - result.addAll(Context.getDataManager().getPositions(deviceId, from, to)); - } - return result; - } - - public static void getExcel(OutputStream outputStream, - long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList devicesRoutes = new ArrayList<>(); - ArrayList sheetNames = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - Collection positions = Context.getDataManager() - .getPositions(deviceId, from, to); - DeviceReport deviceRoutes = new DeviceReport(); - Device device = Context.getIdentityManager().getById(deviceId); - deviceRoutes.setDeviceName(device.getName()); - sheetNames.add(WorkbookUtil.createSafeSheetName(deviceRoutes.getDeviceName())); - if (device.getGroupId() != 0) { - Group group = Context.getGroupsManager().getById(device.getGroupId()); - if (group != null) { - deviceRoutes.setGroupName(group.getName()); - } - } - deviceRoutes.setObjects(positions); - devicesRoutes.add(deviceRoutes); - } - String templatePath = Context.getConfig().getString("report.templatesPath", - "templates/export/"); - try (InputStream inputStream = new FileInputStream(templatePath + "/route.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); - jxlsContext.putVar("devices", devicesRoutes); - jxlsContext.putVar("sheetNames", sheetNames); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); - } - } -} diff --git a/src/org/traccar/reports/Stops.java b/src/org/traccar/reports/Stops.java deleted file mode 100644 index 98c9cef00..000000000 --- a/src/org/traccar/reports/Stops.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; - -import org.apache.poi.ss.util.WorkbookUtil; -import org.traccar.Context; -import org.traccar.Main; -import org.traccar.database.DeviceManager; -import org.traccar.database.IdentityManager; -import org.traccar.model.Device; -import org.traccar.model.Group; -import org.traccar.reports.model.DeviceReport; -import org.traccar.reports.model.StopReport; - -public final class Stops { - - private Stops() { - } - - private static Collection detectStops(long deviceId, Date from, Date to) throws SQLException { - boolean ignoreOdometer = Context.getDeviceManager() - .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); - - IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); - DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); - - return ReportUtils.detectTripsAndStops( - identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to), - Context.getTripsConfig(), ignoreOdometer, StopReport.class); - } - - public static Collection getObjects( - long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - result.addAll(detectStops(deviceId, from, to)); - } - return result; - } - - public static void getExcel( - OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList devicesStops = new ArrayList<>(); - ArrayList sheetNames = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - Collection stops = detectStops(deviceId, from, to); - DeviceReport deviceStops = new DeviceReport(); - Device device = Context.getIdentityManager().getById(deviceId); - deviceStops.setDeviceName(device.getName()); - sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName())); - if (device.getGroupId() != 0) { - Group group = Context.getGroupsManager().getById(device.getGroupId()); - if (group != null) { - deviceStops.setGroupName(group.getName()); - } - } - deviceStops.setObjects(stops); - devicesStops.add(deviceStops); - } - String templatePath = Context.getConfig().getString("report.templatesPath", - "templates/export/"); - try (InputStream inputStream = new FileInputStream(templatePath + "/stops.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); - jxlsContext.putVar("devices", devicesStops); - jxlsContext.putVar("sheetNames", sheetNames); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); - } - } - -} diff --git a/src/org/traccar/reports/Summary.java b/src/org/traccar/reports/Summary.java deleted file mode 100644 index 9810424d8..000000000 --- a/src/org/traccar/reports/Summary.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; - -import org.jxls.util.JxlsHelper; -import org.traccar.Context; -import org.traccar.model.Position; -import org.traccar.reports.model.SummaryReport; - -public final class Summary { - - private Summary() { - } - - private static SummaryReport calculateSummaryResult(long deviceId, Date from, Date to) throws SQLException { - SummaryReport result = new SummaryReport(); - result.setDeviceId(deviceId); - result.setDeviceName(Context.getIdentityManager().getById(deviceId).getName()); - Collection positions = Context.getDataManager().getPositions(deviceId, from, to); - if (positions != null && !positions.isEmpty()) { - Position firstPosition = null; - Position previousPosition = null; - double speedSum = 0; - boolean engineHoursEnabled = Context.getConfig().getBoolean("processing.engineHours.enable"); - for (Position position : positions) { - if (firstPosition == null) { - firstPosition = position; - } - if (engineHoursEnabled && previousPosition != null - && position.getBoolean(Position.KEY_IGNITION) - && previousPosition.getBoolean(Position.KEY_IGNITION)) { - // Temporary fallback for old data, to be removed in May 2019 - result.addEngineHours(position.getFixTime().getTime() - - previousPosition.getFixTime().getTime()); - } - previousPosition = position; - speedSum += position.getSpeed(); - result.setMaxSpeed(position.getSpeed()); - } - boolean ignoreOdometer = Context.getDeviceManager() - .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); - result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer)); - result.setAverageSpeed(speedSum / positions.size()); - result.setSpentFuel(ReportUtils.calculateFuel(firstPosition, previousPosition)); - - if (engineHoursEnabled - && firstPosition.getAttributes().containsKey(Position.KEY_HOURS) - && previousPosition.getAttributes().containsKey(Position.KEY_HOURS)) { - result.setEngineHours( - previousPosition.getLong(Position.KEY_HOURS) - firstPosition.getLong(Position.KEY_HOURS)); - } - - if (!ignoreOdometer - && firstPosition.getDouble(Position.KEY_ODOMETER) != 0 - && previousPosition.getDouble(Position.KEY_ODOMETER) != 0) { - result.setStartOdometer(firstPosition.getDouble(Position.KEY_ODOMETER)); - result.setEndOdometer(previousPosition.getDouble(Position.KEY_ODOMETER)); - } else { - result.setStartOdometer(firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE)); - result.setEndOdometer(previousPosition.getDouble(Position.KEY_TOTAL_DISTANCE)); - } - - } - return result; - } - - public static Collection getObjects(long userId, Collection deviceIds, - Collection groupIds, Date from, Date to) throws SQLException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - result.add(calculateSummaryResult(deviceId, from, to)); - } - return result; - } - - public static void getExcel(OutputStream outputStream, - long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { - ReportUtils.checkPeriodLimit(from, to); - Collection summaries = getObjects(userId, deviceIds, groupIds, from, to); - String templatePath = Context.getConfig().getString("report.templatesPath", - "templates/export/"); - try (InputStream inputStream = new FileInputStream(templatePath + "/summary.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); - jxlsContext.putVar("summaries", summaries); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - JxlsHelper.getInstance().setUseFastFormulaProcessor(false) - .processTemplate(inputStream, outputStream, jxlsContext); - } - } -} diff --git a/src/org/traccar/reports/Trips.java b/src/org/traccar/reports/Trips.java deleted file mode 100644 index 3cda65553..000000000 --- a/src/org/traccar/reports/Trips.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; - -import org.apache.poi.ss.util.WorkbookUtil; -import org.traccar.Context; -import org.traccar.Main; -import org.traccar.database.DeviceManager; -import org.traccar.database.IdentityManager; -import org.traccar.model.Device; -import org.traccar.model.Group; -import org.traccar.reports.model.DeviceReport; -import org.traccar.reports.model.TripReport; - -public final class Trips { - - private Trips() { - } - - private static Collection detectTrips(long deviceId, Date from, Date to) throws SQLException { - boolean ignoreOdometer = Context.getDeviceManager() - .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, true); - - IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); - DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); - - return ReportUtils.detectTripsAndStops( - identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to), - Context.getTripsConfig(), ignoreOdometer, TripReport.class); - } - - public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - result.addAll(detectTrips(deviceId, from, to)); - } - return result; - } - - public static void getExcel(OutputStream outputStream, - long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { - ReportUtils.checkPeriodLimit(from, to); - ArrayList devicesTrips = new ArrayList<>(); - ArrayList sheetNames = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { - Context.getPermissionsManager().checkDevice(userId, deviceId); - Collection trips = detectTrips(deviceId, from, to); - DeviceReport deviceTrips = new DeviceReport(); - Device device = Context.getIdentityManager().getById(deviceId); - deviceTrips.setDeviceName(device.getName()); - sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName())); - if (device.getGroupId() != 0) { - Group group = Context.getGroupsManager().getById(device.getGroupId()); - if (group != null) { - deviceTrips.setGroupName(group.getName()); - } - } - deviceTrips.setObjects(trips); - devicesTrips.add(deviceTrips); - } - String templatePath = Context.getConfig().getString("report.templatesPath", - "templates/export/"); - try (InputStream inputStream = new FileInputStream(templatePath + "/trips.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); - jxlsContext.putVar("devices", devicesTrips); - jxlsContext.putVar("sheetNames", sheetNames); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); - } - } - -} diff --git a/src/org/traccar/reports/model/BaseReport.java b/src/org/traccar/reports/model/BaseReport.java deleted file mode 100644 index 9f2d1188c..000000000 --- a/src/org/traccar/reports/model/BaseReport.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports.model; - -public class BaseReport { - - private long deviceId; - - public long getDeviceId() { - return deviceId; - } - - public void setDeviceId(long deviceId) { - this.deviceId = deviceId; - } - - private String deviceName; - - public String getDeviceName() { - return deviceName; - } - - public void setDeviceName(String deviceName) { - this.deviceName = deviceName; - } - - private double distance; - - public double getDistance() { - return distance; - } - - public void setDistance(double distance) { - this.distance = distance; - } - - public void addDistance(double distance) { - this.distance += distance; - } - - private double averageSpeed; - - public double getAverageSpeed() { - return averageSpeed; - } - - public void setAverageSpeed(Double averageSpeed) { - this.averageSpeed = averageSpeed; - } - - private double maxSpeed; - - public double getMaxSpeed() { - return maxSpeed; - } - - public void setMaxSpeed(double maxSpeed) { - if (maxSpeed > this.maxSpeed) { - this.maxSpeed = maxSpeed; - } - } - - private double spentFuel; - - public double getSpentFuel() { - return spentFuel; - } - - public void setSpentFuel(double spentFuel) { - this.spentFuel = spentFuel; - } - - private double startOdometer; - - public double getStartOdometer() { - return startOdometer; - } - - public void setStartOdometer(double startOdometer) { - this.startOdometer = startOdometer; - } - private double endOdometer; - - public double getEndOdometer() { - return endOdometer; - } - - public void setEndOdometer(double endOdometer) { - this.endOdometer = endOdometer; - } - -} diff --git a/src/org/traccar/reports/model/DeviceReport.java b/src/org/traccar/reports/model/DeviceReport.java deleted file mode 100644 index 932753d15..000000000 --- a/src/org/traccar/reports/model/DeviceReport.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports.model; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class DeviceReport { - - private String deviceName; - - public String getDeviceName() { - return deviceName; - } - - public void setDeviceName(String deviceName) { - this.deviceName = deviceName; - } - - private String groupName = ""; - - public String getGroupName() { - return groupName; - } - - public void setGroupName(String groupName) { - this.groupName = groupName; - } - - private List objects; - - public Collection getObjects() { - return objects; - } - - public void setObjects(Collection objects) { - this.objects = new ArrayList<>(objects); - } - -} diff --git a/src/org/traccar/reports/model/StopReport.java b/src/org/traccar/reports/model/StopReport.java deleted file mode 100644 index 245292b63..000000000 --- a/src/org/traccar/reports/model/StopReport.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports.model; - -import java.util.Date; - -public class StopReport extends BaseReport { - - private long positionId; - - public long getPositionId() { - return positionId; - } - - public void setPositionId(long positionId) { - this.positionId = positionId; - } - - private double latitude; - - public double getLatitude() { - return latitude; - } - - public void setLatitude(double latitude) { - this.latitude = latitude; - } - - private double longitude; - - public double getLongitude() { - return longitude; - } - - public void setLongitude(double longitude) { - this.longitude = longitude; - } - - private Date startTime; - - public Date getStartTime() { - return startTime; - } - - public void setStartTime(Date startTime) { - this.startTime = startTime; - } - - private Date endTime; - - public Date getEndTime() { - return endTime; - } - - public void setEndTime(Date endTime) { - this.endTime = endTime; - } - - private String address; - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - private long duration; - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - private long engineHours; // milliseconds - - public long getEngineHours() { - return engineHours; - } - - public void setEngineHours(long engineHours) { - this.engineHours = engineHours; - } - - public void addEngineHours(long engineHours) { - this.engineHours += engineHours; - } -} diff --git a/src/org/traccar/reports/model/SummaryReport.java b/src/org/traccar/reports/model/SummaryReport.java deleted file mode 100644 index 6f9e9459f..000000000 --- a/src/org/traccar/reports/model/SummaryReport.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports.model; - -public class SummaryReport extends BaseReport { - - private long engineHours; // milliseconds - - public long getEngineHours() { - return engineHours; - } - - public void setEngineHours(long engineHours) { - this.engineHours = engineHours; - } - - public void addEngineHours(long engineHours) { - this.engineHours += engineHours; - } -} diff --git a/src/org/traccar/reports/model/TripReport.java b/src/org/traccar/reports/model/TripReport.java deleted file mode 100644 index 3140f3019..000000000 --- a/src/org/traccar/reports/model/TripReport.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports.model; - -import java.util.Date; - -public class TripReport extends BaseReport { - - private long startPositionId; - - public long getStartPositionId() { - return startPositionId; - } - - public void setStartPositionId(long startPositionId) { - this.startPositionId = startPositionId; - } - - private long endPositionId; - - public long getEndPositionId() { - return endPositionId; - } - - public void setEndPositionId(long endPositionId) { - this.endPositionId = endPositionId; - } - - private double startLat; - - public double getStartLat() { - return startLat; - } - - public void setStartLat(double startLat) { - this.startLat = startLat; - } - - private double startLon; - - public double getStartLon() { - return startLon; - } - - public void setStartLon(double startLon) { - this.startLon = startLon; - } - - private double endLat; - - public double getEndLat() { - return endLat; - } - - public void setEndLat(double endLat) { - this.endLat = endLat; - } - - private double endLon; - - public double getEndLon() { - return endLon; - } - - public void setEndLon(double endLon) { - this.endLon = endLon; - } - - private Date startTime; - - public Date getStartTime() { - return startTime; - } - - public void setStartTime(Date startTime) { - this.startTime = startTime; - } - - private String startAddress; - - public String getStartAddress() { - return startAddress; - } - - public void setStartAddress(String address) { - this.startAddress = address; - } - - private Date endTime; - - public Date getEndTime() { - return endTime; - } - - public void setEndTime(Date endTime) { - this.endTime = endTime; - } - - private String endAddress; - - public String getEndAddress() { - return endAddress; - } - - public void setEndAddress(String address) { - this.endAddress = address; - } - - private long duration; - - public long getDuration() { - return duration; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - private String driverUniqueId; - - public String getDriverUniqueId() { - return driverUniqueId; - } - - public void setDriverUniqueId(String driverUniqueId) { - this.driverUniqueId = driverUniqueId; - } - - private String driverName; - - public String getDriverName() { - return driverName; - } - - public void setDriverName(String driverName) { - this.driverName = driverName; - } -} diff --git a/src/org/traccar/reports/model/TripsConfig.java b/src/org/traccar/reports/model/TripsConfig.java deleted file mode 100644 index 0f0c615d3..000000000 --- a/src/org/traccar/reports/model/TripsConfig.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.reports.model; - -public class TripsConfig { - - public TripsConfig() { - } - - public TripsConfig(double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration, - long minimalNoDataDuration, boolean useIgnition, boolean processInvalidPositions, double speedThreshold) { - this.minimalTripDistance = minimalTripDistance; - this.minimalTripDuration = minimalTripDuration; - this.minimalParkingDuration = minimalParkingDuration; - this.minimalNoDataDuration = minimalNoDataDuration; - this.useIgnition = useIgnition; - this.processInvalidPositions = processInvalidPositions; - this.speedThreshold = speedThreshold; - } - - private double minimalTripDistance; - - public double getMinimalTripDistance() { - return minimalTripDistance; - } - - public void setMinimalTripDistance(double minimalTripDistance) { - this.minimalTripDistance = minimalTripDistance; - } - - private long minimalTripDuration; - - public long getMinimalTripDuration() { - return minimalTripDuration; - } - - public void setMinimalTripDuration(long minimalTripDuration) { - this.minimalTripDuration = minimalTripDuration; - } - - private long minimalParkingDuration; - - public long getMinimalParkingDuration() { - return minimalParkingDuration; - } - - public void setMinimalParkingDuration(long minimalParkingDuration) { - this.minimalParkingDuration = minimalParkingDuration; - } - - private long minimalNoDataDuration; - - public long getMinimalNoDataDuration() { - return minimalNoDataDuration; - } - - public void setMinimalNoDataDuration(long minimalNoDataDuration) { - this.minimalNoDataDuration = minimalNoDataDuration; - } - - private boolean useIgnition; - - public boolean getUseIgnition() { - return useIgnition; - } - - public void setUseIgnition(boolean useIgnition) { - this.useIgnition = useIgnition; - } - - private boolean processInvalidPositions; - - public boolean getProcessInvalidPositions() { - return processInvalidPositions; - } - - public void setProcessInvalidPositions(boolean processInvalidPositions) { - this.processInvalidPositions = processInvalidPositions; - } - - private double speedThreshold; - - public double getSpeedThreshold() { - return speedThreshold; - } - - public void setSpeedThreshold(double speedThreshold) { - this.speedThreshold = speedThreshold; - } - -} diff --git a/src/org/traccar/sms/HttpSmsClient.java b/src/org/traccar/sms/HttpSmsClient.java deleted file mode 100644 index 8e2b67bf7..000000000 --- a/src/org/traccar/sms/HttpSmsClient.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.sms; - -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.InvocationCallback; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.api.SecurityRequestFilter; -import org.traccar.helper.DataConverter; -import org.traccar.notification.MessageException; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - -public class HttpSmsClient implements SmsManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(HttpSmsClient.class); - - private String url; - private String authorizationHeader; - private String authorization; - private String template; - private boolean encode; - private MediaType mediaType; - - public HttpSmsClient() { - url = Context.getConfig().getString("sms.http.url"); - authorizationHeader = Context.getConfig().getString("sms.http.authorizationHeader", - SecurityRequestFilter.AUTHORIZATION_HEADER); - authorization = Context.getConfig().getString("sms.http.authorization"); - if (authorization == null) { - String user = Context.getConfig().getString("sms.http.user"); - String password = Context.getConfig().getString("sms.http.password"); - authorization = "Basic " - + DataConverter.printBase64((user + ":" + password).getBytes(StandardCharsets.UTF_8)); - } - template = Context.getConfig().getString("sms.http.template").trim(); - if (template.charAt(0) == '{' || template.charAt(0) == '[') { - encode = false; - mediaType = MediaType.APPLICATION_JSON_TYPE; - } else { - encode = true; - mediaType = MediaType.APPLICATION_FORM_URLENCODED_TYPE; - } - } - - private String prepareValue(String value) throws UnsupportedEncodingException { - return encode ? URLEncoder.encode(value, StandardCharsets.UTF_8.name()) : value; - } - - private String preparePayload(String destAddress, String message) { - try { - return template - .replace("{phone}", prepareValue(destAddress)) - .replace("{message}", prepareValue(message.trim())); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - private Invocation.Builder getRequestBuilder() { - return Context.getClient().target(url).request() - .header(authorizationHeader, authorization); - } - - @Override - public void sendMessageSync(String destAddress, String message, boolean command) throws MessageException { - Response response = getRequestBuilder().post(Entity.entity(preparePayload(destAddress, message), mediaType)); - if (response.getStatus() / 100 != 2) { - throw new MessageException(response.readEntity(String.class)); - } - } - - @Override - public void sendMessageAsync(final String destAddress, final String message, final boolean command) { - getRequestBuilder().async().post( - Entity.entity(preparePayload(destAddress, message), mediaType), new InvocationCallback() { - @Override - public void completed(String s) { - } - - @Override - public void failed(Throwable throwable) { - LOGGER.warn("SMS send failed", throwable); - } - }); - } - -} diff --git a/src/org/traccar/sms/SmsManager.java b/src/org/traccar/sms/SmsManager.java deleted file mode 100644 index 1e3d40f6e..000000000 --- a/src/org/traccar/sms/SmsManager.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.sms; - -import org.traccar.notification.MessageException; - -public interface SmsManager { - - void sendMessageSync( - String destAddress, String message, boolean command) throws InterruptedException, MessageException; - - void sendMessageAsync( - final String destAddress, final String message, final boolean command); - -} diff --git a/src/org/traccar/sms/smpp/ClientSmppSessionHandler.java b/src/org/traccar/sms/smpp/ClientSmppSessionHandler.java deleted file mode 100644 index 6b9de3107..000000000 --- a/src/org/traccar/sms/smpp/ClientSmppSessionHandler.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.sms.smpp; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.cloudhopper.commons.charset.CharsetUtil; -import com.cloudhopper.smpp.SmppConstants; -import com.cloudhopper.smpp.impl.DefaultSmppSessionHandler; -import com.cloudhopper.smpp.pdu.DeliverSm; -import com.cloudhopper.smpp.pdu.PduRequest; -import com.cloudhopper.smpp.pdu.PduResponse; -import com.cloudhopper.smpp.util.SmppUtil; - -public class ClientSmppSessionHandler extends DefaultSmppSessionHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(ClientSmppSessionHandler.class); - - private SmppClient smppClient; - - public ClientSmppSessionHandler(SmppClient smppClient) { - this.smppClient = smppClient; - } - - @Override - public void firePduRequestExpired(PduRequest pduRequest) { - LOGGER.warn("PDU request expired: " + pduRequest); - } - - @Override - public PduResponse firePduRequestReceived(PduRequest request) { - PduResponse response; - try { - if (request instanceof DeliverSm) { - String sourceAddress = ((DeliverSm) request).getSourceAddress().getAddress(); - String message = CharsetUtil.decode(((DeliverSm) request).getShortMessage(), - smppClient.mapDataCodingToCharset(((DeliverSm) request).getDataCoding())); - LOGGER.info("SMS Message Received: " + message.trim() + ", Source Address: " + sourceAddress); - - boolean isDeliveryReceipt; - if (smppClient.getDetectDlrByOpts()) { - isDeliveryReceipt = request.getOptionalParameters() != null; - } else { - isDeliveryReceipt = SmppUtil.isMessageTypeAnyDeliveryReceipt(((DeliverSm) request).getEsmClass()); - } - - if (!isDeliveryReceipt) { - TextMessageEventHandler.handleTextMessage(sourceAddress, message); - } - } - response = request.createResponse(); - } catch (Exception error) { - LOGGER.warn("SMS receiving error", error); - response = request.createResponse(); - response.setResultMessage(error.getMessage()); - response.setCommandStatus(SmppConstants.STATUS_UNKNOWNERR); - } - return response; - } - - @Override - public void fireChannelUnexpectedlyClosed() { - LOGGER.warn("SMPP session channel unexpectedly closed"); - smppClient.scheduleReconnect(); - } - -} diff --git a/src/org/traccar/sms/smpp/EnquireLinkTask.java b/src/org/traccar/sms/smpp/EnquireLinkTask.java deleted file mode 100644 index 7086709d7..000000000 --- a/src/org/traccar/sms/smpp/EnquireLinkTask.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.sms.smpp; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.cloudhopper.smpp.SmppSession; -import com.cloudhopper.smpp.pdu.EnquireLink; -import com.cloudhopper.smpp.type.RecoverablePduException; -import com.cloudhopper.smpp.type.SmppChannelException; -import com.cloudhopper.smpp.type.SmppTimeoutException; -import com.cloudhopper.smpp.type.UnrecoverablePduException; - -public class EnquireLinkTask implements Runnable { - - private static final Logger LOGGER = LoggerFactory.getLogger(EnquireLinkTask.class); - - private SmppClient smppClient; - private Integer enquireLinkTimeout; - - public EnquireLinkTask(SmppClient smppClient, Integer enquireLinkTimeout) { - this.smppClient = smppClient; - this.enquireLinkTimeout = enquireLinkTimeout; - } - - @Override - public void run() { - SmppSession smppSession = smppClient.getSession(); - if (smppSession != null && smppSession.isBound()) { - try { - smppSession.enquireLink(new EnquireLink(), enquireLinkTimeout); - } catch (SmppTimeoutException | SmppChannelException - | RecoverablePduException | UnrecoverablePduException error) { - LOGGER.warn("Enquire link failed, executing reconnect: ", error); - smppClient.scheduleReconnect(); - } catch (InterruptedException error) { - LOGGER.info("Enquire link interrupted, probably killed by reconnecting"); - } - } else { - LOGGER.warn("Enquire link running while session is not connected"); - } - } - -} diff --git a/src/org/traccar/sms/smpp/ReconnectionTask.java b/src/org/traccar/sms/smpp/ReconnectionTask.java deleted file mode 100644 index c009de8e7..000000000 --- a/src/org/traccar/sms/smpp/ReconnectionTask.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.sms.smpp; - -public class ReconnectionTask implements Runnable { - - private final SmppClient smppClient; - - protected ReconnectionTask(SmppClient smppClient) { - this.smppClient = smppClient; - } - - @Override - public void run() { - smppClient.reconnect(); - } - -} diff --git a/src/org/traccar/sms/smpp/SmppClient.java b/src/org/traccar/sms/smpp/SmppClient.java deleted file mode 100644 index 874253d36..000000000 --- a/src/org/traccar/sms/smpp/SmppClient.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org) - * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.sms.smpp; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.notification.MessageException; -import org.traccar.sms.SmsManager; - -import com.cloudhopper.commons.charset.CharsetUtil; -import com.cloudhopper.smpp.SmppBindType; -import com.cloudhopper.smpp.SmppConstants; -import com.cloudhopper.smpp.SmppSession; -import com.cloudhopper.smpp.SmppSessionConfiguration; -import com.cloudhopper.smpp.impl.DefaultSmppClient; -import com.cloudhopper.smpp.impl.DefaultSmppSessionHandler; -import com.cloudhopper.smpp.pdu.SubmitSm; -import com.cloudhopper.smpp.pdu.SubmitSmResp; -import com.cloudhopper.smpp.tlv.Tlv; -import com.cloudhopper.smpp.type.Address; -import com.cloudhopper.smpp.type.RecoverablePduException; -import com.cloudhopper.smpp.type.SmppChannelException; -import com.cloudhopper.smpp.type.SmppTimeoutException; -import com.cloudhopper.smpp.type.UnrecoverablePduException; - -public class SmppClient implements SmsManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(SmppClient.class); - - private SmppSessionConfiguration sessionConfig = new SmppSessionConfiguration(); - private SmppSession smppSession; - private DefaultSmppSessionHandler sessionHandler = new ClientSmppSessionHandler(this); - private ExecutorService executorService = Executors.newCachedThreadPool(); - private DefaultSmppClient clientBootstrap = new DefaultSmppClient(); - - private ScheduledExecutorService enquireLinkExecutor; - private ScheduledFuture enquireLinkTask; - private Integer enquireLinkPeriod; - private Integer enquireLinkTimeout; - - private ScheduledExecutorService reconnectionExecutor; - private ScheduledFuture reconnectionTask; - private Integer reconnectionDelay; - - private String sourceAddress; - private String commandSourceAddress; - private int submitTimeout; - private boolean requestDlr; - private boolean detectDlrByOpts; - private String notificationsCharsetName; - private byte notificationsDataCoding; - private String commandsCharsetName; - private byte commandsDataCoding; - - private byte sourceTon; - private byte sourceNpi; - private byte commandSourceTon; - private byte commandSourceNpi; - - private byte destTon; - private byte destNpi; - - public SmppClient() { - sessionConfig.setName("Traccar.smppSession"); - sessionConfig.setInterfaceVersion( - (byte) Context.getConfig().getInteger("sms.smpp.version", SmppConstants.VERSION_3_4)); - sessionConfig.setType(SmppBindType.TRANSCEIVER); - sessionConfig.setHost(Context.getConfig().getString("sms.smpp.host", "localhost")); - sessionConfig.setPort(Context.getConfig().getInteger("sms.smpp.port", 2775)); - sessionConfig.setSystemId(Context.getConfig().getString("sms.smpp.username", "user")); - sessionConfig.setSystemType(Context.getConfig().getString("sms.smpp.systemType", null)); - sessionConfig.setPassword(Context.getConfig().getString("sms.smpp.password", "password")); - sessionConfig.getLoggingOptions().setLogBytes(false); - sessionConfig.getLoggingOptions().setLogPdu(Context.getConfig().getBoolean("sms.smpp.logPdu")); - - sourceAddress = Context.getConfig().getString("sms.smpp.sourceAddress", ""); - commandSourceAddress = Context.getConfig().getString("sms.smpp.commandSourceAddress", sourceAddress); - submitTimeout = Context.getConfig().getInteger("sms.smpp.submitTimeout", 10000); - - requestDlr = Context.getConfig().getBoolean("sms.smpp.requestDlr"); - detectDlrByOpts = Context.getConfig().getBoolean("sms.smpp.detectDlrByOpts"); - - notificationsCharsetName = Context.getConfig().getString("sms.smpp.notificationsCharset", - CharsetUtil.NAME_UCS_2); - notificationsDataCoding = (byte) Context.getConfig().getInteger("sms.smpp.notificationsDataCoding", - SmppConstants.DATA_CODING_UCS2); - commandsCharsetName = Context.getConfig().getString("sms.smpp.commandsCharset", - CharsetUtil.NAME_GSM); - commandsDataCoding = (byte) Context.getConfig().getInteger("sms.smpp.commandsDataCoding", - SmppConstants.DATA_CODING_DEFAULT); - - - sourceTon = (byte) Context.getConfig().getInteger("sms.smpp.sourceTon", SmppConstants.TON_ALPHANUMERIC); - commandSourceTon = (byte) Context.getConfig().getInteger("sms.smpp.commandSourceTon", sourceTon); - sourceNpi = (byte) Context.getConfig().getInteger("sms.smpp.sourceNpi", SmppConstants.NPI_UNKNOWN); - commandSourceNpi = (byte) Context.getConfig().getInteger("sms.smpp.commandSourceNpi", sourceNpi); - - destTon = (byte) Context.getConfig().getInteger("sms.smpp.destTon", SmppConstants.TON_INTERNATIONAL); - destNpi = (byte) Context.getConfig().getInteger("sms.smpp.destNpi", SmppConstants.NPI_E164); - - enquireLinkPeriod = Context.getConfig().getInteger("sms.smpp.enquireLinkPeriod", 60000); - enquireLinkTimeout = Context.getConfig().getInteger("sms.smpp.enquireLinkTimeout", 10000); - enquireLinkExecutor = Executors.newScheduledThreadPool(1, new ThreadFactory() { - @Override - public Thread newThread(Runnable runnable) { - Thread thread = new Thread(runnable); - String name = sessionConfig.getName(); - thread.setName("EnquireLink-" + name); - return thread; - } - }); - - reconnectionDelay = Context.getConfig().getInteger("sms.smpp.reconnectionDelay", 10000); - reconnectionExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { - @Override - public Thread newThread(Runnable runnable) { - Thread thread = new Thread(runnable); - String name = sessionConfig.getName(); - thread.setName("Reconnection-" + name); - return thread; - } - }); - - scheduleReconnect(); - } - - public synchronized SmppSession getSession() { - return smppSession; - } - - public String mapDataCodingToCharset(byte dataCoding) { - switch (dataCoding) { - case SmppConstants.DATA_CODING_LATIN1: - return CharsetUtil.NAME_ISO_8859_1; - case SmppConstants.DATA_CODING_UCS2: - return CharsetUtil.NAME_UCS_2; - default: - return CharsetUtil.NAME_GSM; - } - } - - public boolean getDetectDlrByOpts() { - return detectDlrByOpts; - } - - protected synchronized void reconnect() { - try { - disconnect(); - smppSession = clientBootstrap.bind(sessionConfig, sessionHandler); - stopReconnectionkTask(); - runEnquireLinkTask(); - LOGGER.info("SMPP session connected"); - } catch (SmppTimeoutException | SmppChannelException - | UnrecoverablePduException | InterruptedException error) { - LOGGER.warn("Unable to connect to SMPP server: ", error); - } - } - - public void scheduleReconnect() { - if (reconnectionTask == null || reconnectionTask.isDone()) { - reconnectionTask = reconnectionExecutor.scheduleWithFixedDelay( - new ReconnectionTask(this), - reconnectionDelay, reconnectionDelay, TimeUnit.MILLISECONDS); - } - } - - private void stopReconnectionkTask() { - if (reconnectionTask != null) { - reconnectionTask.cancel(false); - } - } - - private void disconnect() { - stopEnquireLinkTask(); - destroySession(); - } - - private void runEnquireLinkTask() { - enquireLinkTask = enquireLinkExecutor.scheduleWithFixedDelay( - new EnquireLinkTask(this, enquireLinkTimeout), - enquireLinkPeriod, enquireLinkPeriod, TimeUnit.MILLISECONDS); - } - - private void stopEnquireLinkTask() { - if (enquireLinkTask != null) { - enquireLinkTask.cancel(true); - } - } - - private void destroySession() { - if (smppSession != null) { - LOGGER.info("Cleaning up SMPP session... "); - smppSession.destroy(); - smppSession = null; - } - } - - @Override - public synchronized void sendMessageSync(String destAddress, String message, boolean command) - throws MessageException, InterruptedException, IllegalStateException { - if (getSession() != null && getSession().isBound()) { - try { - SubmitSm submit = new SubmitSm(); - byte[] textBytes; - textBytes = CharsetUtil.encode(message, command ? commandsCharsetName : notificationsCharsetName); - submit.setDataCoding(command ? commandsDataCoding : notificationsDataCoding); - if (requestDlr) { - submit.setRegisteredDelivery(SmppConstants.REGISTERED_DELIVERY_SMSC_RECEIPT_REQUESTED); - } - - if (textBytes != null && textBytes.length > 255) { - submit.addOptionalParameter(new Tlv(SmppConstants.TAG_MESSAGE_PAYLOAD, textBytes, - "message_payload")); - } else { - submit.setShortMessage(textBytes); - } - - submit.setSourceAddress(command ? new Address(commandSourceTon, commandSourceNpi, commandSourceAddress) - : new Address(sourceTon, sourceNpi, sourceAddress)); - submit.setDestAddress(new Address(destTon, destNpi, destAddress)); - SubmitSmResp submitResponce = getSession().submit(submit, submitTimeout); - if (submitResponce.getCommandStatus() == SmppConstants.STATUS_OK) { - LOGGER.info("SMS submitted, message id: " + submitResponce.getMessageId()); - } else { - throw new IllegalStateException(submitResponce.getResultMessage()); - } - } catch (SmppChannelException | RecoverablePduException - | SmppTimeoutException | UnrecoverablePduException error) { - throw new MessageException(error); - } - } else { - throw new MessageException(new SmppChannelException("SMPP session is not connected")); - } - } - - @Override - public void sendMessageAsync(final String destAddress, final String message, final boolean command) { - executorService.execute(new Runnable() { - @Override - public void run() { - try { - sendMessageSync(destAddress, message, command); - } catch (MessageException | InterruptedException | IllegalStateException error) { - LOGGER.warn("SMS sending error", error); - } - } - }); - } - -} diff --git a/src/org/traccar/sms/smpp/TextMessageEventHandler.java b/src/org/traccar/sms/smpp/TextMessageEventHandler.java deleted file mode 100644 index 37c29972d..000000000 --- a/src/org/traccar/sms/smpp/TextMessageEventHandler.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2017 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.sms.smpp; - -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.Event; - -public final class TextMessageEventHandler { - - private TextMessageEventHandler() { - } - - public static void handleTextMessage(String phone, String message) { - Device device = Context.getDeviceManager().getDeviceByPhone(phone); - if (device != null && Context.getNotificationManager() != null) { - Event event = new Event(Event.TYPE_TEXT_MESSAGE, device.getId()); - event.set("message", message); - Context.getNotificationManager().updateEvent(event, null); - } - } - -} diff --git a/src/org/traccar/web/ConsoleServlet.java b/src/org/traccar/web/ConsoleServlet.java deleted file mode 100644 index 2b38a935a..000000000 --- a/src/org/traccar/web/ConsoleServlet.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 - 2016 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. - * 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.web; - -import org.h2.server.web.ConnectionInfo; -import org.h2.server.web.WebServlet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class ConsoleServlet extends WebServlet { - - private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleServlet.class); - - @Override - public void init() { - super.init(); - - try { - Field field = WebServlet.class.getDeclaredField("server"); - field.setAccessible(true); - org.h2.server.web.WebServer server = (org.h2.server.web.WebServer) field.get(this); - - ConnectionInfo connectionInfo = new ConnectionInfo("Traccar|" - + Context.getConfig().getString("database.driver") + "|" - + Context.getConfig().getString("database.url") + "|" - + Context.getConfig().getString("database.user")); - - Method method; - - method = org.h2.server.web.WebServer.class.getDeclaredMethod("updateSetting", ConnectionInfo.class); - method.setAccessible(true); - method.invoke(server, connectionInfo); - - method = org.h2.server.web.WebServer.class.getDeclaredMethod("setAllowOthers", boolean.class); - method.setAccessible(true); - method.invoke(server, true); - - } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { - LOGGER.warn("Console reflection error", e); - } - } - -} diff --git a/src/org/traccar/web/CsvBuilder.java b/src/org/traccar/web/CsvBuilder.java deleted file mode 100644 index 3fe7e408f..000000000 --- a/src/org/traccar/web/CsvBuilder.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.web; - -import java.beans.Introspector; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.Date; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; - -import com.fasterxml.jackson.core.JsonProcessingException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; -import org.traccar.helper.DateUtil; - -public class CsvBuilder { - - private static final Logger LOGGER = LoggerFactory.getLogger(CsvBuilder.class); - - private static final String LINE_ENDING = "\r\n"; - private static final String SEPARATOR = ";"; - - private StringBuilder builder = new StringBuilder(); - - private void addLineEnding() { - builder.append(LINE_ENDING); - } - private void addSeparator() { - builder.append(SEPARATOR); - } - - private SortedSet getSortedMethods(Object object) { - Method[] methodArray = object.getClass().getMethods(); - SortedSet methods = new TreeSet<>(new Comparator() { - @Override - public int compare(Method m1, Method m2) { - if (m1.getName().equals("getAttributes") && !m1.getName().equals(m2.getName())) { - return 1; - } - if (m2.getName().equals("getAttributes") && !m1.getName().equals(m2.getName())) { - return -1; - } - return m1.getName().compareTo(m2.getName()); - } - }); - methods.addAll(Arrays.asList(methodArray)); - return methods; - } - - public void addLine(Object object) { - - SortedSet methods = getSortedMethods(object); - - for (Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { - try { - if (method.getReturnType().equals(boolean.class)) { - builder.append(method.invoke(object)); - addSeparator(); - } else if (method.getReturnType().equals(int.class)) { - builder.append(method.invoke(object)); - addSeparator(); - } else if (method.getReturnType().equals(long.class)) { - builder.append(method.invoke(object)); - addSeparator(); - } else if (method.getReturnType().equals(double.class)) { - builder.append(method.invoke(object)); - addSeparator(); - } else if (method.getReturnType().equals(String.class)) { - builder.append((String) method.invoke(object)); - addSeparator(); - } else if (method.getReturnType().equals(Date.class)) { - Date value = (Date) method.invoke(object); - builder.append(DateUtil.formatDate(value)); - addSeparator(); - } else if (method.getReturnType().equals(Map.class)) { - Map value = (Map) method.invoke(object); - if (value != null) { - try { - String map = Context.getObjectMapper().writeValueAsString(value); - map = map.replaceAll("[\\{\\}\"]", ""); - map = map.replaceAll(",", " "); - builder.append(map); - addSeparator(); - } catch (JsonProcessingException e) { - LOGGER.warn("Map JSON formatting error", e); - } - } - } - } catch (IllegalAccessException | InvocationTargetException error) { - LOGGER.warn("Reflection invocation error", error); - } - } - } - addLineEnding(); - } - - public void addHeaderLine(Object object) { - - SortedSet methods = getSortedMethods(object); - - for (Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { - String name = Introspector.decapitalize(method.getName().substring(3)); - if (!name.equals("class")) { - builder.append(name); - addSeparator(); - } - } - } - addLineEnding(); - } - - public void addArray(Collection array) { - for (Object object : array) { - switch (object.getClass().getSimpleName().toLowerCase()) { - case "string": - builder.append(object.toString()); - addLineEnding(); - break; - case "long": - builder.append((long) object); - addLineEnding(); - break; - case "double": - builder.append((double) object); - addLineEnding(); - break; - case "boolean": - builder.append((boolean) object); - addLineEnding(); - break; - default: - addLine(object); - break; - } - } - } - - public String build() { - return builder.toString(); - } - -} diff --git a/src/org/traccar/web/GpxBuilder.java b/src/org/traccar/web/GpxBuilder.java deleted file mode 100644 index 638d100e5..000000000 --- a/src/org/traccar/web/GpxBuilder.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2016 Anton Tananaev (anton@traccar.org) - * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) - * - * 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.web; - -import java.util.Collection; - -import org.traccar.helper.DateUtil; -import org.traccar.helper.UnitsConverter; -import org.traccar.model.Position; - -public class GpxBuilder { - - private StringBuilder builder = new StringBuilder(); - private static final String HEADER = "" - + "\n"; - private static final String NAME = "%1$s%n"; - private static final String POINT = "" - + "" - + "%4$f" - + "%5$f" - + "%6$f" - + "%n"; - private static final String FOOTER = ""; - - public GpxBuilder() { - builder.append(HEADER); - builder.append("\n"); - } - - public GpxBuilder(String name) { - builder.append(HEADER); - builder.append(String.format(NAME, name)); - } - - public void addPosition(Position position) { - builder.append(String.format(POINT, position.getLatitude(), position.getLongitude(), - DateUtil.formatDate(position.getFixTime()), position.getAltitude(), - position.getCourse(), UnitsConverter.mpsFromKnots(position.getSpeed()))); - } - - public void addPositions(Collection positions) { - for (Position position : positions) { - addPosition(position); - } - } - - public String build() { - builder.append(FOOTER); - return builder.toString(); - } - -} diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java deleted file mode 100644 index 70fef4ed3..000000000 --- a/src/org/traccar/web/WebServer.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2012 - 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. - * 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.web; - -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.proxy.AsyncProxyServlet; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.ErrorHandler; -import org.eclipse.jetty.server.handler.HandlerList; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.glassfish.jersey.jackson.JacksonFeature; -import org.glassfish.jersey.server.ResourceConfig; -import org.glassfish.jersey.servlet.ServletContainer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.api.AsyncSocketServlet; -import org.traccar.api.CorsResponseFilter; -import org.traccar.api.MediaFilter; -import org.traccar.api.ObjectMapperProvider; -import org.traccar.api.ResourceErrorHandler; -import org.traccar.api.SecurityRequestFilter; -import org.traccar.api.resource.ServerResource; - -import javax.servlet.DispatcherType; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; -import java.io.Writer; -import java.net.InetSocketAddress; -import java.util.EnumSet; - -public class WebServer { - - private static final Logger LOGGER = LoggerFactory.getLogger(WebServer.class); - - private Server server; - - private void initServer(Config config) { - - String address = config.getString("web.address"); - int port = config.getInteger("web.port", 8082); - if (address == null) { - server = new Server(port); - } else { - server = new Server(new InetSocketAddress(address, port)); - } - } - - public WebServer(Config config) { - - initServer(config); - - ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); - - int sessionTimeout = config.getInteger("web.sessionTimeout"); - if (sessionTimeout > 0) { - servletHandler.getSessionHandler().setMaxInactiveInterval(sessionTimeout); - } - - initApi(config, servletHandler); - - if (config.getBoolean("web.console")) { - servletHandler.addServlet(new ServletHolder(new ConsoleServlet()), "/console/*"); - } - - initWebApp(config, servletHandler); - - servletHandler.setErrorHandler(new ErrorHandler() { - @Override - protected void handleErrorPage( - HttpServletRequest request, Writer writer, int code, String message) throws IOException { - writer.write("Error" - + code + " - " + HttpStatus.getMessage(code) + ""); - } - }); - - HandlerList handlers = new HandlerList(); - initClientProxy(config, handlers); - handlers.addHandler(servletHandler); - server.setHandler(handlers); - } - - private void initClientProxy(Config config, HandlerList handlers) { - int port = config.getInteger("osmand.port"); - if (port != 0) { - ServletContextHandler servletHandler = new ServletContextHandler() { - @Override - public void doScope( - String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - if (target.equals("/") && request.getMethod().equals(HttpMethod.POST.asString())) { - super.doScope(target, baseRequest, request, response); - } - } - }; - ServletHolder servletHolder = new ServletHolder(new AsyncProxyServlet.Transparent()); - servletHolder.setInitParameter("proxyTo", "http://localhost:" + port); - servletHandler.addServlet(servletHolder, "/"); - handlers.addHandler(servletHandler); - } - } - - private void initWebApp(Config config, ServletContextHandler servletHandler) { - ServletHolder servletHolder = new ServletHolder(DefaultServlet.class); - servletHolder.setInitParameter("resourceBase", new File(config.getString("web.path")).getAbsolutePath()); - if (config.getBoolean("web.debug")) { - servletHandler.setWelcomeFiles(new String[] {"debug.html", "index.html"}); - } else { - String cache = config.getString("web.cacheControl"); - if (cache != null && !cache.isEmpty()) { - servletHolder.setInitParameter("cacheControl", cache); - } - servletHandler.setWelcomeFiles(new String[] {"release.html", "index.html"}); - } - servletHandler.addServlet(servletHolder, "/*"); - } - - private void initApi(Config config, ServletContextHandler servletHandler) { - servletHandler.addServlet(new ServletHolder(new AsyncSocketServlet()), "/api/socket"); - - if (config.hasKey("media.path")) { - ServletHolder servletHolder = new ServletHolder(DefaultServlet.class); - servletHolder.setInitParameter("resourceBase", new File(config.getString("media.path")).getAbsolutePath()); - servletHolder.setInitParameter("dirAllowed", config.getString("media.dirAllowed", "false")); - servletHolder.setInitParameter("pathInfoOnly", "true"); - servletHandler.addServlet(servletHolder, "/api/media/*"); - servletHandler.addFilter(MediaFilter.class, "/api/media/*", EnumSet.allOf(DispatcherType.class)); - } - - ResourceConfig resourceConfig = new ResourceConfig(); - resourceConfig.registerClasses(JacksonFeature.class, ObjectMapperProvider.class, ResourceErrorHandler.class); - resourceConfig.registerClasses(SecurityRequestFilter.class, CorsResponseFilter.class); - resourceConfig.packages(ServerResource.class.getPackage().getName()); - servletHandler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/api/*"); - } - - public void start() { - try { - server.start(); - } catch (Exception error) { - LOGGER.warn("Web server start failed", error); - } - } - - public void stop() { - try { - server.stop(); - } catch (Exception error) { - LOGGER.warn("Web server stop failed", error); - } - } - -} diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java new file mode 100644 index 000000000..0b2c616ce --- /dev/null +++ b/src/test/java/org/traccar/BaseTest.java @@ -0,0 +1,34 @@ +package org.traccar; + +import io.netty.buffer.ByteBuf; +import org.traccar.database.MediaManager; + +import java.util.HashMap; +import java.util.Map; + +public class BaseTest { + + public static class MockMediaManager extends MediaManager { + Map files = new HashMap<>(); + + MockMediaManager() { + super(""); + } + + @Override + public String writeFile(String uniqueId, ByteBuf buf, String extension) { + String fileName = uniqueId + "/mock." + extension; + files.put(fileName, buf); + return fileName; + } + + public ByteBuf readFile(String fileName) { + return files.get(fileName); + } + } + + static { + Context.init(new TestIdentityManager(), new MockMediaManager()); + } + +} diff --git a/src/test/java/org/traccar/ProtocolTest.java b/src/test/java/org/traccar/ProtocolTest.java new file mode 100644 index 000000000..4d48bb763 --- /dev/null +++ b/src/test/java/org/traccar/ProtocolTest.java @@ -0,0 +1,324 @@ +package org.traccar; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpVersion; +import org.traccar.helper.DataConverter; +import org.traccar.model.CellTower; +import org.traccar.model.Command; +import org.traccar.model.Position; + +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class ProtocolTest extends BaseTest { + + protected Position position(String time, boolean valid, double lat, double lon) throws ParseException { + + Position position = new Position(); + + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(time)); + position.setValid(valid); + position.setLatitude(lat); + position.setLongitude(lon); + + return position; + } + + private String concatenateStrings(String... strings) { + StringBuilder builder = new StringBuilder(); + for (String s : strings) { + builder.append(s); + } + return builder.toString(); + } + + protected ByteBuf concatenateBuffers(ByteBuf... buffers) { + ByteBuf result = Unpooled.buffer(); + for (ByteBuf buf : buffers) { + result.writeBytes(buf); + } + return result; + } + + protected ByteBuf binary(String... data) { + return Unpooled.wrappedBuffer(DataConverter.parseHex(concatenateStrings(data))); + } + + protected String text(String... data) { + return concatenateStrings(data); + } + + protected ByteBuf buffer(String... data) { + return Unpooled.copiedBuffer(concatenateStrings(data), StandardCharsets.ISO_8859_1); + } + + protected DefaultFullHttpRequest request(String url) { + return request(HttpMethod.GET, url); + } + + protected DefaultFullHttpRequest request(HttpMethod method, String url) { + return new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method, url); + } + + protected DefaultFullHttpRequest request(HttpMethod method, String url, ByteBuf data) { + return new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method, url, data); + } + + protected DefaultFullHttpRequest request(HttpMethod method, String url, HttpHeaders headers) { + return new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method, url, Unpooled.buffer(), headers, new DefaultHttpHeaders()); + } + + protected void verifyNotNull(BaseProtocolDecoder decoder, Object object) throws Exception { + assertNotNull(decoder.decode(null, null, object)); + } + + protected void verifyNull(Object object) { + assertNull(object); + } + + protected void verifyNull(BaseProtocolDecoder decoder, Object object) throws Exception { + assertNull(decoder.decode(null, null, object)); + } + + protected void verifyAttribute(BaseProtocolDecoder decoder, Object object, String key, Object expected) throws Exception { + Position position = (Position) decoder.decode(null, null, object); + switch (key) { + case "speed": + assertEquals(expected, position.getSpeed()); + break; + case "course": + assertEquals(expected, position.getCourse()); + break; + default: + assertEquals(expected, position.getAttributes().get(key)); + break; + } + } + + protected void verifyAttributes(BaseProtocolDecoder decoder, Object object) throws Exception { + verifyDecodedPosition(decoder.decode(null, null, object), false, true, null); + } + + protected void verifyPosition(BaseProtocolDecoder decoder, Object object) throws Exception { + verifyDecodedPosition(decoder.decode(null, null, object), true, false, null); + } + + protected void verifyPosition(BaseProtocolDecoder decoder, Object object, Position position) throws Exception { + verifyDecodedPosition(decoder.decode(null, null, object), true, false, position); + } + + protected void verifyPositions(BaseProtocolDecoder decoder, Object object) throws Exception { + verifyDecodedList(decoder.decode(null, null, object), true, null); + } + + protected void verifyPositions(BaseProtocolDecoder decoder, boolean checkLocation, Object object) throws Exception { + verifyDecodedList(decoder.decode(null, null, object), checkLocation, null); + } + + protected void verifyPositions(BaseProtocolDecoder decoder, Object object, Position position) throws Exception { + verifyDecodedList(decoder.decode(null, null, object), true, position); + } + + private void verifyDecodedList(Object decodedObject, boolean checkLocation, Position expected) { + + assertNotNull("list is null", decodedObject); + assertTrue("not a list", decodedObject instanceof List); + assertFalse("list is empty", ((List) decodedObject).isEmpty()); + + for (Object item : (List) decodedObject) { + verifyDecodedPosition(item, checkLocation, false, expected); + } + + } + + private void verifyDecodedPosition(Object decodedObject, boolean checkLocation, boolean checkAttributes, Position expected) { + + assertNotNull("position is null", decodedObject); + assertTrue("not a position", decodedObject instanceof Position); + + Position position = (Position) decodedObject; + + if (checkLocation) { + + if (expected != null) { + + if (expected.getFixTime() != null) { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + assertEquals("time", dateFormat.format(expected.getFixTime()), dateFormat.format(position.getFixTime())); + } + assertEquals("valid", expected.getValid(), position.getValid()); + assertEquals("latitude", expected.getLatitude(), position.getLatitude(), 0.00001); + assertEquals("longitude", expected.getLongitude(), position.getLongitude(), 0.00001); + + } else { + + assertNotNull(position.getServerTime()); + assertNotNull(position.getFixTime()); + assertTrue("year > 1999", position.getFixTime().after(new Date(915148800000L))); + assertTrue("time < +25 hours", + position.getFixTime().getTime() < System.currentTimeMillis() + 25 * 3600000); + + assertTrue("latitude >= -90", position.getLatitude() >= -90); + assertTrue("latitude <= 90", position.getLatitude() <= 90); + + assertTrue("longitude >= -180", position.getLongitude() >= -180); + assertTrue("longitude <= 180", position.getLongitude() <= 180); + + } + + assertTrue("altitude >= -12262", position.getAltitude() >= -12262); + assertTrue("altitude <= 18000", position.getAltitude() <= 18000); + + assertTrue("speed >= 0", position.getSpeed() >= 0); + assertTrue("speed <= 869", position.getSpeed() <= 869); + + assertTrue("course >= 0", position.getCourse() >= 0); + assertTrue("course <= 360", position.getCourse() <= 360); + + assertNotNull("protocol is null", position.getProtocol()); + + } + + Map attributes = position.getAttributes(); + + if (checkAttributes) { + assertFalse("no attributes", attributes.isEmpty()); + } + + if (attributes.containsKey(Position.KEY_INDEX)) { + assertTrue(attributes.get(Position.KEY_INDEX) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_HDOP)) { + assertTrue(attributes.get(Position.KEY_HDOP) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_VDOP)) { + assertTrue(attributes.get(Position.KEY_VDOP) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_PDOP)) { + assertTrue(attributes.get(Position.KEY_PDOP) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_SATELLITES)) { + assertTrue(attributes.get(Position.KEY_SATELLITES) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_SATELLITES_VISIBLE)) { + assertTrue(attributes.get(Position.KEY_SATELLITES_VISIBLE) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_RSSI)) { + assertTrue(attributes.get(Position.KEY_RSSI) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_ODOMETER)) { + assertTrue(attributes.get(Position.KEY_ODOMETER) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_RPM)) { + assertTrue(attributes.get(Position.KEY_RPM) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_FUEL_LEVEL)) { + assertTrue(attributes.get(Position.KEY_FUEL_LEVEL) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_POWER)) { + assertTrue(attributes.get(Position.KEY_POWER) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_BATTERY)) { + assertTrue(attributes.get(Position.KEY_BATTERY) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_BATTERY_LEVEL)) { + int batteryLevel = ((Number) attributes.get(Position.KEY_BATTERY_LEVEL)).intValue(); + assertTrue(batteryLevel <= 100 && batteryLevel >= 0); + } + + if (attributes.containsKey(Position.KEY_CHARGE)) { + assertTrue(attributes.get(Position.KEY_CHARGE) instanceof Boolean); + } + + if (attributes.containsKey(Position.KEY_IGNITION)) { + assertTrue(attributes.get(Position.KEY_IGNITION) instanceof Boolean); + } + + if (attributes.containsKey(Position.KEY_MOTION)) { + assertTrue(attributes.get(Position.KEY_MOTION) instanceof Boolean); + } + + if (attributes.containsKey(Position.KEY_ARCHIVE)) { + assertTrue(attributes.get(Position.KEY_ARCHIVE) instanceof Boolean); + } + + if (attributes.containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { + assertTrue(attributes.get(Position.KEY_DRIVER_UNIQUE_ID) instanceof String); + } + + if (attributes.containsKey(Position.KEY_STEPS)) { + assertTrue(attributes.get(Position.KEY_STEPS) instanceof Number); + } + + if (attributes.containsKey(Position.KEY_ROAMING)) { + assertTrue(attributes.get(Position.KEY_ROAMING) instanceof Boolean); + } + + if (attributes.containsKey(Position.KEY_HOURS)) { + assertTrue(attributes.get(Position.KEY_HOURS) instanceof Number); + } + + if (position.getNetwork() != null && position.getNetwork().getCellTowers() != null) { + for (CellTower cellTower : position.getNetwork().getCellTowers()) { + checkInteger(cellTower.getMobileCountryCode(), 0, 999); + checkInteger(cellTower.getMobileNetworkCode(), 0, 999); + checkInteger(cellTower.getLocationAreaCode(), 1, 65535); + checkInteger(cellTower.getCellId(), 0, 268435455); + } + } + + } + + private void checkInteger(Object value, int min, int max) { + assertNotNull("value is null", value); + assertTrue("not int or long", value instanceof Integer || value instanceof Long); + long number = ((Number) value).longValue(); + assertTrue("value too low", number >= min); + assertTrue("value too high", number <= max); + } + + protected void verifyCommand( + BaseProtocolEncoder encoder, Command command, ByteBuf expected) { + verifyFrame(expected, encoder.encodeCommand(command)); + } + + protected void verifyFrame(ByteBuf expected, Object object) { + assertNotNull("buffer is null", object); + assertTrue("not a buffer", object instanceof ByteBuf); + assertEquals(ByteBufUtil.hexDump(expected), ByteBufUtil.hexDump((ByteBuf) object)); + } + +} diff --git a/src/test/java/org/traccar/TestIdentityManager.java b/src/test/java/org/traccar/TestIdentityManager.java new file mode 100644 index 000000000..0f7405dbd --- /dev/null +++ b/src/test/java/org/traccar/TestIdentityManager.java @@ -0,0 +1,72 @@ +package org.traccar; + +import org.traccar.database.IdentityManager; +import org.traccar.model.Device; +import org.traccar.model.Position; + +public final class TestIdentityManager implements IdentityManager { + + private static Device createDevice() { + Device device = new Device(); + device.setId(1); + device.setName("test"); + device.setUniqueId("123456789012345"); + return device; + } + + @Override + public long addUnknownDevice(String uniqueId) { + return 1; + } + + @Override + public Device getById(long id) { + return createDevice(); + } + + @Override + public Device getByUniqueId(String uniqueId) { + return createDevice(); + } + + @Override + public Position getLastPosition(long deviceId) { + return null; + } + + @Override + public boolean isLatestPosition(Position position) { + return true; + } + + @Override + public boolean lookupAttributeBoolean( + long deviceId, String attributeName, boolean defaultValue, boolean lookupConfig) { + return defaultValue; + } + + @Override + public String lookupAttributeString( + long deviceId, String attributeName, String defaultValue, boolean lookupConfig) { + return "alarm,result"; + } + + @Override + public int lookupAttributeInteger( + long deviceId, String attributeName, int defaultValue, boolean lookupConfig) { + return defaultValue; + } + + @Override + public long lookupAttributeLong( + long deviceId, String attributeName, long defaultValue, boolean lookupConfig) { + return defaultValue; + } + + @Override + public double lookupAttributeDouble( + long deviceId, String attributeName, double defaultValue, boolean lookupConfig) { + return defaultValue; + } + +} diff --git a/src/test/java/org/traccar/WebDataHandlerTest.java b/src/test/java/org/traccar/WebDataHandlerTest.java new file mode 100644 index 000000000..cfbd71f23 --- /dev/null +++ b/src/test/java/org/traccar/WebDataHandlerTest.java @@ -0,0 +1,28 @@ +package org.traccar; + +import org.junit.Test; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Position; + +import static org.junit.Assert.assertEquals; + +public class WebDataHandlerTest extends ProtocolTest { + + @Test + public void testFormatRequest() throws Exception { + + Config config = new Config(); + config.setString(Keys.FORWARD_URL, "http://localhost/?fixTime={fixTime}&gprmc={gprmc}&name={name}"); + + Position position = position("2016-01-01 01:02:03.000", true, 20, 30); + + WebDataHandler handler = new WebDataHandler(config, Context.getIdentityManager(), null, null); + + assertEquals( + "http://localhost/?fixTime=1451610123000&gprmc=$GPRMC,010203.000,A,2000.0000,N,03000.0000,E,0.00,0.00,010116,,*05&name=test", + handler.formatRequest(position)); + + } + +} diff --git a/src/test/java/org/traccar/calendar/CalendarTest.java b/src/test/java/org/traccar/calendar/CalendarTest.java new file mode 100644 index 000000000..56406d4b8 --- /dev/null +++ b/src/test/java/org/traccar/calendar/CalendarTest.java @@ -0,0 +1,59 @@ +package org.traccar.calendar; + +import java.io.IOException; +import java.sql.SQLException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.junit.Test; +import org.traccar.model.Calendar; + +import net.fortuna.ical4j.data.ParserException; + +import static org.junit.Assert.assertTrue; + +public class CalendarTest { + + @Test + public void testCalendar() throws IOException, ParserException, ParseException, SQLException { + String calendarString = "BEGIN:VCALENDAR\n" + + "PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN\n" + + "VERSION:2.0\n" + + "BEGIN:VTIMEZONE\n" + + "TZID:Asia/Yekaterinburg\n" + + "BEGIN:STANDARD\n" + + "TZOFFSETFROM:+0500\n" + + "TZOFFSETTO:+0500\n" + + "TZNAME:YEKT\n" + + "DTSTART:19700101T000000\n" + + "END:STANDARD\n" + + "END:VTIMEZONE\n" + + "BEGIN:VEVENT\n" + + "CREATED:20161213T045151Z\n" + + "LAST-MODIFIED:20161213T045242Z\n" + + "DTSTAMP:20161213T045242Z\n" + + "UID:9d000df0-6354-479d-a407-218dac62c7c9\n" + + "SUMMARY:Every night\n" + + "RRULE:FREQ=DAILY\n" + + "DTSTART;TZID=Asia/Yekaterinburg:20161130T230000\n" + + "DTEND;TZID=Asia/Yekaterinburg:20161201T070000\n" + + "TRANSP:OPAQUE\n" + + "END:VEVENT\n" + + "END:VCALENDAR"; + Calendar calendar = new Calendar(); + calendar.setData(calendarString.getBytes()); + DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssX"); + + Date date = format.parse("2016-12-13 22:59:59+05"); + assertTrue(!calendar.checkMoment(date)); + date = format.parse("2016-12-13 23:00:01+05"); + assertTrue(calendar.checkMoment(date)); + + date = format.parse("2016-12-13 06:59:59+05"); + assertTrue(calendar.checkMoment(date)); + date = format.parse("2016-12-13 07:00:01+05"); + assertTrue(!calendar.checkMoment(date)); + } +} diff --git a/src/test/java/org/traccar/config/ConfigTest.java b/src/test/java/org/traccar/config/ConfigTest.java new file mode 100644 index 000000000..13d0ffb04 --- /dev/null +++ b/src/test/java/org/traccar/config/ConfigTest.java @@ -0,0 +1,19 @@ +package org.traccar.config; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import org.traccar.config.Config; + +public class ConfigTest { + + @Test + public void testFormat() { + assertEquals("DATABASE_URL", Config.getEnvironmentVariableName("database.url")); + assertEquals("DATABASE_CHECK_CONNECTION", Config.getEnvironmentVariableName("database.checkConnection")); + assertEquals("DATABASE_MAX_POOL_SIZE", Config.getEnvironmentVariableName("database.maxPoolSize")); + assertEquals("DEVICE_MANAGER_LOOKUP_GROUPS_ATTRIBUTE", Config.getEnvironmentVariableName("deviceManager.lookupGroupsAttribute")); + assertEquals("COMMAND_FALLBACK_TO_SMS", Config.getEnvironmentVariableName("command.fallbackToSms")); + assertEquals("STATUS_TIMEOUT", Config.getEnvironmentVariableName("status.timeout")); + } + +} diff --git a/src/test/java/org/traccar/database/DataManagerTest.java b/src/test/java/org/traccar/database/DataManagerTest.java new file mode 100644 index 000000000..23043e96e --- /dev/null +++ b/src/test/java/org/traccar/database/DataManagerTest.java @@ -0,0 +1,81 @@ +package org.traccar.database; + +import org.junit.Test; +import org.traccar.model.Attribute; +import org.traccar.model.Device; +import org.traccar.model.Driver; +import org.traccar.model.Geofence; +import org.traccar.model.Group; +import org.traccar.model.ManagedUser; +import org.traccar.model.Position; +import org.traccar.model.User; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class DataManagerTest { + + @Test + public void constructObjectQuery() { + assertEquals("SELECT * FROM tc_users", + DataManager.constructObjectQuery(DataManager.ACTION_SELECT_ALL, User.class, false)); + assertEquals("DELETE FROM tc_groups WHERE id = :id", + DataManager.constructObjectQuery(DataManager.ACTION_DELETE, Group.class, false)); + assertEquals("SELECT * FROM tc_positions WHERE id = :id", + DataManager.constructObjectQuery(DataManager.ACTION_SELECT, Position.class, false)); + + String insertDevice = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Device.class, false); + assertFalse(insertDevice.contains("class")); + assertFalse(insertDevice.contains("id")); + assertFalse(insertDevice.contains("status")); + assertFalse(insertDevice.contains("geofenceIds")); + + String updateDeviceStatus = DataManager.constructObjectQuery("update", Device.class, true); + assertTrue(updateDeviceStatus.contains("lastUpdate")); + + String updateUser = DataManager.constructObjectQuery(DataManager.ACTION_UPDATE, User.class, false); + assertFalse(updateUser.contains("class")); + assertFalse(updateUser.contains("password")); + assertFalse(updateUser.contains("salt")); + + String updateUserPassword = DataManager.constructObjectQuery(DataManager.ACTION_UPDATE, User.class, true); + assertFalse(updateUserPassword.contains("name")); + assertTrue(updateUserPassword.contains("hashedPassword")); + assertTrue(updateUserPassword.contains("salt")); + + String insertPosition = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Position.class, false); + assertFalse(insertPosition.contains("type")); + assertFalse(insertPosition.contains("outdated")); + + } + + @Test + public void constructPermissionsQuery() { + assertEquals("SELECT userId, deviceId FROM tc_user_device", + DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, Device.class)); + + assertEquals("SELECT userId, managedUserId FROM tc_user_user", + DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, ManagedUser.class)); + + assertEquals("SELECT deviceId, driverId FROM tc_device_driver", + DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Device.class, Driver.class)); + + assertEquals("SELECT groupId, geofenceId FROM tc_group_geofence", + DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Group.class, Geofence.class)); + + assertEquals("INSERT INTO tc_user_device (userId, deviceId) VALUES (:userId, :deviceId)", + DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, User.class, Device.class)); + + assertEquals("DELETE FROM tc_user_user WHERE userId = :userId AND managedUserId = :managedUserId", + DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, User.class, ManagedUser.class)); + + assertEquals("INSERT INTO tc_device_geofence (deviceId, geofenceId) VALUES (:deviceId, :geofenceId)", + DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, Device.class, Geofence.class)); + + assertEquals("DELETE FROM tc_group_attribute WHERE groupId = :groupId AND attributeId = :attributeId", + DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, Group.class, Attribute.class)); + + } + +} diff --git a/src/test/java/org/traccar/database/GroupTreeTest.java b/src/test/java/org/traccar/database/GroupTreeTest.java new file mode 100644 index 000000000..b547aab60 --- /dev/null +++ b/src/test/java/org/traccar/database/GroupTreeTest.java @@ -0,0 +1,56 @@ +package org.traccar.database; + +import org.junit.Test; +import org.traccar.model.Device; +import org.traccar.model.Group; + +import java.util.ArrayList; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +public class GroupTreeTest { + + private static Group createGroup(long id, String name, long parent) { + Group group = new Group(); + group.setId(id); + group.setName(name); + group.setGroupId(parent); + return group; + } + + private static Device createDevice(long id, String name, long parent) { + Device device = new Device(); + device.setId(id); + device.setName(name); + device.setGroupId(parent); + return device; + } + + @Test + public void testGetDescendants() { + Collection groups = new ArrayList<>(); + groups.add(createGroup(1, "First", 0)); + groups.add(createGroup(2, "Second", 1)); + groups.add(createGroup(3, "Third", 2)); + groups.add(createGroup(4, "Fourth", 2)); + groups.add(createGroup(5, "Fifth", 4)); + + Collection devices = new ArrayList<>(); + devices.add(createDevice(1, "One", 3)); + devices.add(createDevice(2, "Two", 5)); + devices.add(createDevice(3, "One", 5)); + + GroupTree groupTree = new GroupTree(groups, devices); + + assertEquals(4, groupTree.getGroups(1).size()); + assertEquals(3, groupTree.getGroups(2).size()); + assertEquals(0, groupTree.getGroups(3).size()); + assertEquals(1, groupTree.getGroups(4).size()); + + assertEquals(3, groupTree.getDevices(1).size()); + assertEquals(1, groupTree.getDevices(3).size()); + assertEquals(2, groupTree.getDevices(4).size()); + } + +} diff --git a/src/test/java/org/traccar/geocoder/AddressFormatTest.java b/src/test/java/org/traccar/geocoder/AddressFormatTest.java new file mode 100644 index 000000000..0cc5168ef --- /dev/null +++ b/src/test/java/org/traccar/geocoder/AddressFormatTest.java @@ -0,0 +1,33 @@ +package org.traccar.geocoder; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class AddressFormatTest { + + private void test(Address address, String format, String expected) { + assertEquals(expected, new AddressFormat(format).format(address)); + } + + @Test + public void testFormat() { + + Address address = new Address(); + address.setCountry("NZ"); + address.setSettlement("Auckland"); + address.setStreet("Queen St"); + address.setHouse("1A"); + + test(address, "%h %r %t %d %s %c %p", "1A Queen St Auckland NZ"); + test(address, "%h %r %t", "1A Queen St Auckland"); + test(address, "%h %r, %t", "1A Queen St, Auckland"); + test(address, "%h %r, %t %p", "1A Queen St, Auckland"); + test(address, "%t %d %c", "Auckland NZ"); + test(address, "%t, %d, %c", "Auckland, NZ"); + test(address, "%d %c", "NZ"); + test(address, "%d, %c", "NZ"); + test(address, "%p", ""); + } + +} diff --git a/src/test/java/org/traccar/geocoder/GeocoderTest.java b/src/test/java/org/traccar/geocoder/GeocoderTest.java new file mode 100644 index 000000000..85d9bf62f --- /dev/null +++ b/src/test/java/org/traccar/geocoder/GeocoderTest.java @@ -0,0 +1,88 @@ +package org.traccar.geocoder; + +import java.util.Locale; + +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class GeocoderTest { + + static { + Locale.setDefault(Locale.US); + } + + @Ignore + @Test + public void testGoogle() { + Geocoder geocoder = new GoogleGeocoder(null, null, 0, new AddressFormat()); + String address = geocoder.getAddress(31.776797, 35.211489, null); + assertEquals("1 Ibn Shaprut St, Jerusalem, Jerusalem District, IL", address); + } + + @Ignore + @Test + public void testNominatim() { + Geocoder geocoder = new NominatimGeocoder(null, null, null, 0, new AddressFormat()); + String address = geocoder.getAddress(40.7337807, -73.9974401, null); + assertEquals("35 West 9th Street, NYC, New York, US", address); + } + + @Ignore + @Test + public void testGisgraphy() { + Geocoder geocoder = new GisgraphyGeocoder(new AddressFormat()); + String address = geocoder.getAddress(48.8530000, 2.3400000, null); + assertEquals("Rue du Jardinet, Paris, Île-de-France, FR", address); + } + + @Ignore + @Test + public void testOpenCage() { + Geocoder geocoder = new OpenCageGeocoder( + "http://api.opencagedata.com/geocode/v1", "SECRET", 0, new AddressFormat()); + String address = geocoder.getAddress(34.116302, -118.051519, null); + assertEquals("Charleston Road, California, US", address); + } + + @Ignore + @Test + public void testGeocodeFarm() { + Geocoder geocoder = new GeocodeFarmGeocoder(null, null, 0, new AddressFormat()); + String address = geocoder.getAddress(34.116302, -118.051519, null); + assertEquals("Estrella Avenue, Arcadia, California, United States", address); + } + + @Ignore + @Test + public void testGeocodeXyz() { + Geocoder geocoder = new GeocodeXyzGeocoder(null, 0, new AddressFormat()); + String address = geocoder.getAddress(34.116302, -118.051519, null); + assertEquals("605 ESTRELLA AVE, ARCADIA, California United States of America, US", address); + } + + @Ignore + @Test + public void testBan() { + Geocoder geocoder = new BanGeocoder(0, new AddressFormat("%f [%d], %c")); + String address = geocoder.getAddress(48.8575, 2.2944, null); + assertEquals("8 Avenue Gustave Eiffel 75007 Paris [75, Paris, Île-de-France], FR", address); + } + + @Ignore + @Test + public void testHere() { + Geocoder geocoder = new HereGeocoder("", "", null, 0, new AddressFormat()); + String address = geocoder.getAddress(48.8575, 2.2944, null); + assertEquals("6 Avenue Gustave Eiffel, Paris, Île-de-France, FRA", address); + } + + @Ignore + @Test + public void testMapmyIndia() { + Geocoder geocoder = new MapmyIndiaGeocoder("", "", 0, new AddressFormat("%f")); + String address = geocoder.getAddress(28.6129602407977, 77.2294557094574, null); + assertEquals("New Delhi, Delhi. 1 m from India Gate pin-110001 (India)", address); + } +} diff --git a/src/test/java/org/traccar/geofence/GeofenceCircleTest.java b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java new file mode 100644 index 000000000..259a8fb77 --- /dev/null +++ b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java @@ -0,0 +1,28 @@ +package org.traccar.geofence; + +import java.text.ParseException; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class GeofenceCircleTest { + + @Test + public void testCircleWkt() throws ParseException { + String test = "CIRCLE (55.75414 37.6204, 100)"; + GeofenceGeometry geofenceGeometry = new GeofenceCircle(); + geofenceGeometry.fromWkt(test); + assertEquals(geofenceGeometry.toWkt(), test); + } + + @Test + public void testContainsCircle() throws ParseException { + String test = "CIRCLE (55.75414 37.6204, 100)"; + GeofenceGeometry geofenceGeometry = new GeofenceCircle(); + geofenceGeometry.fromWkt(test); + assertTrue(geofenceGeometry.containsPoint(55.75477, 37.62025)); + assertTrue(!geofenceGeometry.containsPoint(55.75545, 37.61921)); + } +} diff --git a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java new file mode 100644 index 000000000..94b73af3a --- /dev/null +++ b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java @@ -0,0 +1,52 @@ +package org.traccar.geofence; + +import java.text.ParseException; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class GeofencePolygonTest { + + @Test + public void testPolygonWkt() throws ParseException { + String test = "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))"; + GeofenceGeometry geofenceGeometry = new GeofencePolygon(); + geofenceGeometry.fromWkt(test); + assertEquals(geofenceGeometry.toWkt(), test); + } + + @Test + public void testContainsPolygon() throws ParseException { + String test = "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))"; + GeofenceGeometry geofenceGeometry = new GeofencePolygon(); + geofenceGeometry.fromWkt(test); + assertTrue(geofenceGeometry.containsPoint(55.75476, 37.61915)); + assertTrue(!geofenceGeometry.containsPoint(55.75545, 37.61921)); + + } + + @Test + public void testContainsPolygon180() throws ParseException { + String test = "POLYGON ((66.9494 179.838, 66.9508 -179.8496, 66.8406 -180.0014))"; + GeofenceGeometry geofenceGeometry = new GeofencePolygon(); + geofenceGeometry.fromWkt(test); + assertTrue(geofenceGeometry.containsPoint(66.9015, -180.0096)); + assertTrue(geofenceGeometry.containsPoint(66.9015, 179.991)); + assertTrue(!geofenceGeometry.containsPoint(66.8368, -179.8792)); + + } + + @Test + public void testContainsPolygon0() throws ParseException { + String test = "POLYGON ((51.1966 -0.6207, 51.1897 0.4147, 50.9377 0.5136, 50.8675 -0.6082))"; + GeofenceGeometry geofenceGeometry = new GeofencePolygon(); + geofenceGeometry.fromWkt(test); + assertTrue(geofenceGeometry.containsPoint(51.0466, -0.0165)); + assertTrue(geofenceGeometry.containsPoint(51.0466, 0.018)); + assertTrue(!geofenceGeometry.containsPoint(50.9477, 0.5836)); + + } + +} diff --git a/src/test/java/org/traccar/geofence/GeofencePolylineTest.java b/src/test/java/org/traccar/geofence/GeofencePolylineTest.java new file mode 100644 index 000000000..1e9dcb7c3 --- /dev/null +++ b/src/test/java/org/traccar/geofence/GeofencePolylineTest.java @@ -0,0 +1,47 @@ +package org.traccar.geofence; + +import java.text.ParseException; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class GeofencePolylineTest { + + @Test + public void testPolylineWkt() throws ParseException { + String test = "LINESTRING (55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165)"; + GeofenceGeometry geofenceGeometry = new GeofencePolyline(); + geofenceGeometry.fromWkt(test); + assertEquals(geofenceGeometry.toWkt(), test); + } + + @Test + public void testContainsPolyline1Interval() throws ParseException { + String test = "LINESTRING (56.83777 60.59833, 56.83766 60.5968)"; + GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 35); + assertTrue(geofenceGeometry.containsPoint(56.83801, 60.59748)); + ((GeofencePolyline) geofenceGeometry).setDistance(15); + assertTrue(!geofenceGeometry.containsPoint(56.83801, 60.59748)); + } + + @Test + public void testContainsPolyline3Intervals() throws ParseException { + String test = "LINESTRING (56.836 60.6126, 56.8393 60.6114, 56.83887 60.60811, 56.83782 60.5988)"; + GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 15); + assertTrue(geofenceGeometry.containsPoint(56.83847, 60.60458)); + assertTrue(!geofenceGeometry.containsPoint(56.83764, 60.59725)); + assertTrue(!geofenceGeometry.containsPoint(56.83861, 60.60822)); + + } + + @Test + public void testContainsPolylineNear180() throws ParseException { + String test = "LINESTRING (66.9494 179.838, 66.9508 -179.8496)"; + GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 25); + assertTrue(geofenceGeometry.containsPoint(66.95, 180.0)); + assertTrue(!geofenceGeometry.containsPoint(66.96, 180.0)); + assertTrue(!geofenceGeometry.containsPoint(66.9509, -179.83)); + } +} diff --git a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java new file mode 100644 index 000000000..2729052d6 --- /dev/null +++ b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java @@ -0,0 +1,41 @@ +package org.traccar.geolocation; + +import org.junit.Ignore; +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.model.CellTower; +import org.traccar.model.Network; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class GeolocationProviderTest extends BaseTest { + + @Ignore + @Test + public void test() throws Exception { + testLocationProvider(); + } + + public void testLocationProvider() throws Exception { + MozillaGeolocationProvider provider = new MozillaGeolocationProvider(null); + + Network network = new Network(CellTower.from(208, 1, 2, 1234567)); + + provider.getLocation(network, new GeolocationProvider.LocationProviderCallback() { + @Override + public void onSuccess(double latitude, double longitude, double accuracy) { + assertEquals(60.07254, latitude, 0.00001); + assertEquals(30.30996, longitude, 0.00001); + } + + @Override + public void onFailure(Throwable e) { + fail(); + } + }); + + Thread.sleep(Long.MAX_VALUE); + } + +} diff --git a/src/test/java/org/traccar/handler/ComputedAttributesTest.java b/src/test/java/org/traccar/handler/ComputedAttributesTest.java new file mode 100644 index 000000000..a76d8169b --- /dev/null +++ b/src/test/java/org/traccar/handler/ComputedAttributesTest.java @@ -0,0 +1,71 @@ +package org.traccar.handler; + +import java.util.Date; + +import org.junit.Test; +import org.traccar.config.Config; +import org.traccar.model.Attribute; +import org.traccar.model.Position; + +import static org.junit.Assert.assertEquals; + +public class ComputedAttributesTest { + + @Test + public void testComputedAttributes() { + + ComputedAttributesHandler handler = new ComputedAttributesHandler(new Config(), null, null); + + Date date = new Date(); + Position position = new Position(); + position.setTime(date); + position.setSpeed(42); + position.setValid(false); + position.set("adc1", 128); + position.set("booleanFlag", true); + position.set("adc2", 100); + position.set("bitFlag", 7); + position.set("event", 42); + position.set("result", "success"); + Attribute attribute = new Attribute(); + + attribute.setExpression("adc1"); + assertEquals(128, handler.computeAttribute(attribute, position)); + + attribute.setExpression("!booleanFlag"); + assertEquals(false, handler.computeAttribute(attribute, position)); + + attribute.setExpression("adc2 * 2 + 50"); + assertEquals(250, handler.computeAttribute(attribute, position)); + + attribute.setExpression("(bitFlag & 4) != 0"); + assertEquals(true, handler.computeAttribute(attribute, position)); + + attribute.setExpression("if (event == 42) \"lowBattery\""); + assertEquals("lowBattery", handler.computeAttribute(attribute, position)); + + attribute.setExpression("speed > 5 && valid"); + assertEquals(false, handler.computeAttribute(attribute, position)); + + attribute.setExpression("fixTime"); + assertEquals(date, handler.computeAttribute(attribute, position)); + + attribute.setExpression("math:pow(adc1, 2)"); + assertEquals(16384.0, handler.computeAttribute(attribute, position)); + + // modification tests + attribute.setExpression("adc1 = 256"); + handler.computeAttribute(attribute, position); + assertEquals(128, position.getInteger("adc1")); + + attribute.setExpression("result = \"fail\""); + handler.computeAttribute(attribute, position); + assertEquals("success", position.getString("result")); + + attribute.setExpression("fixTime = \"2017-10-18 10:00:01\""); + handler.computeAttribute(attribute, position); + assertEquals(date, position.getFixTime()); + + } + +} diff --git a/src/test/java/org/traccar/handler/DistanceHandlerTest.java b/src/test/java/org/traccar/handler/DistanceHandlerTest.java new file mode 100644 index 000000000..f7c6e42cd --- /dev/null +++ b/src/test/java/org/traccar/handler/DistanceHandlerTest.java @@ -0,0 +1,30 @@ +package org.traccar.handler; + +import org.junit.Test; +import org.traccar.config.Config; +import org.traccar.model.Position; + +import static org.junit.Assert.assertEquals; + +public class DistanceHandlerTest { + + @Test + public void testCalculateDistance() { + + DistanceHandler distanceHandler = new DistanceHandler(new Config(), null); + + Position position = distanceHandler.handlePosition(new Position()); + + assertEquals(0.0, position.getAttributes().get(Position.KEY_DISTANCE)); + assertEquals(0.0, position.getAttributes().get(Position.KEY_TOTAL_DISTANCE)); + + position.set(Position.KEY_DISTANCE, 100); + + position = distanceHandler.handlePosition(position); + + assertEquals(100.0, position.getAttributes().get(Position.KEY_DISTANCE)); + assertEquals(100.0, position.getAttributes().get(Position.KEY_TOTAL_DISTANCE)); + + } + +} diff --git a/src/test/java/org/traccar/handler/FilterHandlerTest.java b/src/test/java/org/traccar/handler/FilterHandlerTest.java new file mode 100644 index 000000000..ad8d244a6 --- /dev/null +++ b/src/test/java/org/traccar/handler/FilterHandlerTest.java @@ -0,0 +1,88 @@ +package org.traccar.handler; + +import org.junit.Before; +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Position; + +import java.util.Date; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class FilterHandlerTest extends BaseTest { + + private FilterHandler passingHandler = new FilterHandler(new Config()); + private FilterHandler filteringHandler; + + @Before + public void before() { + Config config = new Config(); + config.setString(Keys.FILTER_INVALID, String.valueOf(true)); + config.setString(Keys.FILTER_ZERO, String.valueOf(true)); + config.setString(Keys.FILTER_DUPLICATE, String.valueOf(true)); + config.setString(Keys.FILTER_FUTURE, String.valueOf(5 * 60)); + config.setString(Keys.FILTER_APPROXIMATE, String.valueOf(true)); + config.setString(Keys.FILTER_STATIC, String.valueOf(true)); + config.setString(Keys.FILTER_DISTANCE, String.valueOf(10)); + config.setString(Keys.FILTER_MAX_SPEED, String.valueOf(500)); + config.setString(Keys.FILTER_SKIP_LIMIT, String.valueOf(10)); + config.setString(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE, String.valueOf(true)); + filteringHandler = new FilterHandler(config); + } + + private Position createPosition( + long deviceId, + Date time, + boolean valid, + double latitude, + double longitude, + double altitude, + double speed, + double course) { + + Position position = new Position(); + position.setDeviceId(deviceId); + position.setTime(time); + position.setValid(valid); + position.setLatitude(latitude); + position.setLongitude(longitude); + position.setAltitude(altitude); + position.setSpeed(speed); + position.setCourse(course); + return position; + } + + @Test + public void testFilter() { + + Position position = createPosition(0, new Date(), true, 10, 10, 10, 10, 10); + + assertNotNull(filteringHandler.handlePosition(position)); + assertNotNull(passingHandler.handlePosition(position)); + + position = createPosition(0, new Date(Long.MAX_VALUE), true, 10, 10, 10, 10, 10); + + assertNull(filteringHandler.handlePosition(position)); + assertNotNull(passingHandler.handlePosition(position)); + + position = createPosition(0, new Date(), false, 10, 10, 10, 10, 10); + + assertNull(filteringHandler.handlePosition(position)); + assertNotNull(passingHandler.handlePosition(position)); + + } + + @Test + public void testSkipAttributes() { + + Position position = createPosition(0, new Date(), true, 10, 10, 10, 0, 10); + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + + assertNotNull(filteringHandler.handlePosition(position)); + + } + +} diff --git a/src/test/java/org/traccar/handler/MotionHandlerTest.java b/src/test/java/org/traccar/handler/MotionHandlerTest.java new file mode 100644 index 000000000..9e0859664 --- /dev/null +++ b/src/test/java/org/traccar/handler/MotionHandlerTest.java @@ -0,0 +1,21 @@ +package org.traccar.handler; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.traccar.model.Position; + +public class MotionHandlerTest { + + @Test + public void testCalculateMotion() { + + MotionHandler motionHandler = new MotionHandler(0.01); + + Position position = motionHandler.handlePosition(new Position()); + + assertEquals(false, position.getAttributes().get(Position.KEY_MOTION)); + + } + +} diff --git a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java new file mode 100644 index 000000000..3f0823245 --- /dev/null +++ b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java @@ -0,0 +1,30 @@ +package org.traccar.handler.events; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Map; + +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.TestIdentityManager; +import org.traccar.config.Config; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public class AlertEventHandlerTest extends BaseTest { + + @Test + public void testAlertEventHandler() { + + AlertEventHandler alertEventHandler = new AlertEventHandler(new Config(), new TestIdentityManager()); + + Position position = new Position(); + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + Map events = alertEventHandler.analyzePosition(position); + assertNotNull(events); + Event event = events.keySet().iterator().next(); + assertEquals(Event.TYPE_ALARM, event.getType()); + } + +} diff --git a/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java b/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java new file mode 100644 index 000000000..0ccf9f6b4 --- /dev/null +++ b/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java @@ -0,0 +1,28 @@ +package org.traccar.handler.events; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Map; + +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public class CommandResultEventHandlerTest extends BaseTest { + + @Test + public void testCommandResultEventHandler() throws Exception { + + CommandResultEventHandler commandResultEventHandler = new CommandResultEventHandler(); + + Position position = new Position(); + position.set(Position.KEY_RESULT, "Test Result"); + Map events = commandResultEventHandler.analyzePosition(position); + assertNotNull(events); + Event event = events.keySet().iterator().next(); + assertEquals(Event.TYPE_COMMAND_RESULT, event.getType()); + } + +} diff --git a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java new file mode 100644 index 000000000..dade20fb8 --- /dev/null +++ b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java @@ -0,0 +1,27 @@ +package org.traccar.handler.events; + +import static org.junit.Assert.assertNull; + +import java.util.Map; + +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.TestIdentityManager; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public class IgnitionEventHandlerTest extends BaseTest { + + @Test + public void testIgnitionEventHandler() { + + IgnitionEventHandler ignitionEventHandler = new IgnitionEventHandler(new TestIdentityManager()); + + Position position = new Position(); + position.set(Position.KEY_IGNITION, true); + position.setValid(true); + Map events = ignitionEventHandler.analyzePosition(position); + assertNull(events); + } + +} diff --git a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java new file mode 100644 index 000000000..f57c16635 --- /dev/null +++ b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java @@ -0,0 +1,119 @@ +package org.traccar.handler.events; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.TimeZone; + +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.model.DeviceState; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.reports.model.TripsConfig; + +public class MotionEventHandlerTest extends BaseTest { + + private Date date(String time) throws ParseException { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat.parse(time); + } + + @Test + public void testMotionWithPosition() throws Exception { + MotionEventHandler motionEventHandler = new MotionEventHandler( + null, null, new TripsConfig(500, 300 * 1000, 300 * 1000, 0, false, false, 0.01)); + + Position position = new Position(); + position.setTime(date("2017-01-01 00:00:00")); + position.set(Position.KEY_MOTION, true); + position.set(Position.KEY_TOTAL_DISTANCE, 0); + DeviceState deviceState = new DeviceState(); + deviceState.setMotionState(false); + deviceState.setMotionPosition(position); + Position nextPosition = new Position(); + + nextPosition.setTime(date("2017-01-01 00:02:00")); + nextPosition.set(Position.KEY_MOTION, true); + nextPosition.set(Position.KEY_TOTAL_DISTANCE, 200); + + Map events = motionEventHandler.updateMotionState(deviceState, nextPosition); + assertNull(events); + + nextPosition.set(Position.KEY_TOTAL_DISTANCE, 600); + events = motionEventHandler.updateMotionState(deviceState, nextPosition); + assertNotNull(events); + Event event = events.keySet().iterator().next(); + assertEquals(Event.TYPE_DEVICE_MOVING, event.getType()); + assertTrue(deviceState.getMotionState()); + assertNull(deviceState.getMotionPosition()); + + deviceState.setMotionState(false); + deviceState.setMotionPosition(position); + nextPosition.setTime(date("2017-01-01 00:06:00")); + nextPosition.set(Position.KEY_TOTAL_DISTANCE, 200); + events = motionEventHandler.updateMotionState(deviceState, nextPosition); + assertNotNull(event); + event = events.keySet().iterator().next(); + assertEquals(Event.TYPE_DEVICE_MOVING, event.getType()); + assertTrue(deviceState.getMotionState()); + assertNull(deviceState.getMotionPosition()); + } + + @Test + public void testMotionWithStatus() throws Exception { + MotionEventHandler motionEventHandler = new MotionEventHandler( + null, null, new TripsConfig(500, 300 * 1000, 300 * 1000, 0, false, false, 0.01)); + + Position position = new Position(); + position.setTime(new Date(System.currentTimeMillis() - 360000)); + position.set(Position.KEY_MOTION, true); + DeviceState deviceState = new DeviceState(); + deviceState.setMotionState(false); + deviceState.setMotionPosition(position); + + Map events = motionEventHandler.updateMotionState(deviceState); + + assertNotNull(events); + Event event = events.keySet().iterator().next(); + assertEquals(Event.TYPE_DEVICE_MOVING, event.getType()); + assertTrue(deviceState.getMotionState()); + assertNull(deviceState.getMotionPosition()); + } + + @Test + public void testStopWithPositionIgnition() throws Exception { + MotionEventHandler motionEventHandler = new MotionEventHandler( + null, null, new TripsConfig(500, 300 * 1000, 300 * 1000, 0, true, false, 0.01)); + + Position position = new Position(); + position.setTime(date("2017-01-01 00:00:00")); + position.set(Position.KEY_MOTION, false); + position.set(Position.KEY_IGNITION, true); + DeviceState deviceState = new DeviceState(); + deviceState.setMotionState(true); + deviceState.setMotionPosition(position); + + Position nextPosition = new Position(); + nextPosition.setTime(date("2017-01-01 00:02:00")); + nextPosition.set(Position.KEY_MOTION, false); + nextPosition.set(Position.KEY_IGNITION, false); + + Map events = motionEventHandler.updateMotionState(deviceState, nextPosition); + assertNotNull(events); + Event event = events.keySet().iterator().next(); + assertEquals(Event.TYPE_DEVICE_STOPPED, event.getType()); + assertFalse(deviceState.getMotionState()); + assertNull(deviceState.getMotionPosition()); + } + +} diff --git a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java new file mode 100644 index 000000000..515f37b5d --- /dev/null +++ b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java @@ -0,0 +1,128 @@ +package org.traccar.handler.events; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.TimeZone; + +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.DeviceState; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public class OverspeedEventHandlerTest extends BaseTest { + + private Date date(String time) throws ParseException { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat.parse(time); + } + + private void testOverspeedWithPosition(boolean notRepeat, long geofenceId) throws ParseException { + Config config = new Config(); + config.setString(Keys.EVENT_OVERSPEED_NOT_REPEAT, String.valueOf(notRepeat)); + config.setString(Keys.EVENT_OVERSPEED_MINIMAL_DURATION, String.valueOf(15)); + config.setString(Keys.EVENT_OVERSPEED_PREFER_LOWEST, String.valueOf(false)); + OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(config, null, null); + + Position position = new Position(); + position.setTime(date("2017-01-01 00:00:00")); + position.setSpeed(50); + DeviceState deviceState = new DeviceState(); + deviceState.setOverspeedState(false); + + Map events = overspeedEventHandler.updateOverspeedState(deviceState, position, 40, geofenceId); + assertNull(events); + assertFalse(deviceState.getOverspeedState()); + assertEquals(position, deviceState.getOverspeedPosition()); + assertEquals(geofenceId, deviceState.getOverspeedGeofenceId()); + + Position nextPosition = new Position(); + nextPosition.setTime(date("2017-01-01 00:00:10")); + nextPosition.setSpeed(55); + + events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId); + assertNull(events); + + nextPosition.setTime(date("2017-01-01 00:00:20")); + + events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId); + assertNotNull(events); + Event event = events.keySet().iterator().next(); + assertEquals(Event.TYPE_DEVICE_OVERSPEED, event.getType()); + assertEquals(50, event.getDouble("speed"), 0.1); + assertEquals(40, event.getDouble(OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT), 0.1); + assertEquals(geofenceId, event.getGeofenceId()); + + assertEquals(notRepeat, deviceState.getOverspeedState()); + assertNull(deviceState.getOverspeedPosition()); + assertEquals(0, deviceState.getOverspeedGeofenceId()); + + nextPosition.setTime(date("2017-01-01 00:00:30")); + events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId); + assertNull(events); + assertEquals(notRepeat, deviceState.getOverspeedState()); + + if (notRepeat) { + assertNull(deviceState.getOverspeedPosition()); + assertEquals(0, deviceState.getOverspeedGeofenceId()); + } else { + assertNotNull(deviceState.getOverspeedPosition()); + assertEquals(geofenceId, deviceState.getOverspeedGeofenceId()); + } + + nextPosition.setTime(date("2017-01-01 00:00:40")); + nextPosition.setSpeed(30); + + events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId); + assertNull(events); + assertFalse(deviceState.getOverspeedState()); + assertNull(deviceState.getOverspeedPosition()); + assertEquals(0, deviceState.getOverspeedGeofenceId()); + } + + private void testOverspeedWithStatus(boolean notRepeat) { + Config config = new Config(); + config.setString(Keys.EVENT_OVERSPEED_NOT_REPEAT, String.valueOf(notRepeat)); + config.setString(Keys.EVENT_OVERSPEED_MINIMAL_DURATION, String.valueOf(15)); + config.setString(Keys.EVENT_OVERSPEED_PREFER_LOWEST, String.valueOf(false)); + OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(config, null, null); + + Position position = new Position(); + position.setTime(new Date(System.currentTimeMillis() - 30000)); + position.setSpeed(50); + DeviceState deviceState = new DeviceState(); + deviceState.setOverspeedState(false); + deviceState.setOverspeedPosition(position); + + Map events = overspeedEventHandler.updateOverspeedState(deviceState, 40); + + assertNotNull(events); + Event event = events.keySet().iterator().next(); + assertEquals(Event.TYPE_DEVICE_OVERSPEED, event.getType()); + assertEquals(notRepeat, deviceState.getOverspeedState()); + } + + @Test + public void testOverspeedEventHandler() throws Exception { + testOverspeedWithPosition(false, 0); + testOverspeedWithPosition(true, 0); + + testOverspeedWithPosition(false, 1); + testOverspeedWithPosition(true, 1); + + testOverspeedWithStatus(false); + testOverspeedWithStatus(true); + } + +} diff --git a/src/test/java/org/traccar/helper/BcdUtilTest.java b/src/test/java/org/traccar/helper/BcdUtilTest.java new file mode 100644 index 000000000..86a32f725 --- /dev/null +++ b/src/test/java/org/traccar/helper/BcdUtilTest.java @@ -0,0 +1,24 @@ +package org.traccar.helper; + +import io.netty.buffer.Unpooled; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class BcdUtilTest { + + @Test + public void testReadInteger() { + byte[] buf = {0x01, (byte) 0x90, 0x34}; + int result = BcdUtil.readInteger(Unpooled.wrappedBuffer(buf), 5); + assertEquals(1903, result); + } + + @Test + public void testReadCoordinate() { + byte[] buf = {0x03, (byte) 0x85, 0x22, 0x59, 0x34}; + double result = BcdUtil.readCoordinate(Unpooled.wrappedBuffer(buf)); + assertEquals(38.870989, result, 0.00001); + } + +} diff --git a/src/test/java/org/traccar/helper/BitBufferTest.java b/src/test/java/org/traccar/helper/BitBufferTest.java new file mode 100644 index 000000000..c2abad36d --- /dev/null +++ b/src/test/java/org/traccar/helper/BitBufferTest.java @@ -0,0 +1,23 @@ +package org.traccar.helper; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class BitBufferTest { + + @Test + public void test() { + BitBuffer buffer = new BitBuffer(); + + buffer.write(0b100100); + buffer.write(0b110110); + buffer.write(0b111111); + buffer.write(0b111111); + + assertEquals(0b100, buffer.readUnsigned(3)); + assertEquals(-7, buffer.readSigned(4)); + assertEquals(0b10110, buffer.readUnsigned(5)); + } + +} diff --git a/src/test/java/org/traccar/helper/BitUtilTest.java b/src/test/java/org/traccar/helper/BitUtilTest.java new file mode 100644 index 000000000..90431bf55 --- /dev/null +++ b/src/test/java/org/traccar/helper/BitUtilTest.java @@ -0,0 +1,38 @@ +package org.traccar.helper; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class BitUtilTest { + + @Test + public void testCheck() { + assertFalse(BitUtil.check(0, 0)); + assertTrue(BitUtil.check(1, 0)); + assertFalse(BitUtil.check(2, 0)); + } + + @Test + public void testBetween() { + assertEquals(0, BitUtil.between(0, 0, 0)); + assertEquals(1, BitUtil.between(1, 0, 1)); + assertEquals(2, BitUtil.between(2, 0, 2)); + assertEquals(2, BitUtil.between(6, 0, 2)); + } + + @Test + public void testFrom() { + assertEquals(1, BitUtil.from(1, 0)); + assertEquals(0, BitUtil.from(1, 1)); + } + + @Test + public void testTo() { + assertEquals(2, BitUtil.to(2, 2)); + assertEquals(0, BitUtil.to(2, 1)); + } + +} diff --git a/src/test/java/org/traccar/helper/ChecksumTest.java b/src/test/java/org/traccar/helper/ChecksumTest.java new file mode 100644 index 000000000..5737b9ff5 --- /dev/null +++ b/src/test/java/org/traccar/helper/ChecksumTest.java @@ -0,0 +1,39 @@ +package org.traccar.helper; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertEquals; + +public class ChecksumTest { + + @Test + public void testCrc8() { + ByteBuf buf = Unpooled.copiedBuffer("123456789", StandardCharsets.US_ASCII); + + assertEquals(0xF7, Checksum.crc8(Checksum.CRC8_EGTS, buf.nioBuffer())); + assertEquals(0xD0, Checksum.crc8(Checksum.CRC8_ROHC, buf.nioBuffer())); + } + + @Test + public void testCrc16() { + ByteBuf buf = Unpooled.copiedBuffer("123456789", StandardCharsets.US_ASCII); + + assertEquals(0xBB3D, Checksum.crc16(Checksum.CRC16_IBM, buf.nioBuffer())); + assertEquals(0x4B37, Checksum.crc16(Checksum.CRC16_MODBUS, buf.nioBuffer())); + assertEquals(0x906e, Checksum.crc16(Checksum.CRC16_X25, buf.nioBuffer())); + assertEquals(0x29b1, Checksum.crc16(Checksum.CRC16_CCITT_FALSE, buf.nioBuffer())); + assertEquals(0x2189, Checksum.crc16(Checksum.CRC16_KERMIT, buf.nioBuffer())); + assertEquals(0x31c3, Checksum.crc16(Checksum.CRC16_XMODEM, buf.nioBuffer())); + } + + @Test + public void testLuhn() { + assertEquals(7, Checksum.luhn(12345678901234L)); + assertEquals(0, Checksum.luhn(63070019470771L)); + } + +} diff --git a/src/test/java/org/traccar/helper/DateBuilderTest.java b/src/test/java/org/traccar/helper/DateBuilderTest.java new file mode 100644 index 000000000..b6323cc1d --- /dev/null +++ b/src/test/java/org/traccar/helper/DateBuilderTest.java @@ -0,0 +1,27 @@ +package org.traccar.helper; + +import org.junit.Test; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +import static org.junit.Assert.assertEquals; + +public class DateBuilderTest { + + @Test + public void testDateBuilder() throws ParseException { + + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(2015, 10, 20).setTime(1, 21, 11); + + assertEquals(dateFormat.parse("2015-10-20 01:21:11"), dateBuilder.getDate()); + + } + +} diff --git a/src/test/java/org/traccar/helper/DateUtilTest.java b/src/test/java/org/traccar/helper/DateUtilTest.java new file mode 100644 index 000000000..ec42e71ae --- /dev/null +++ b/src/test/java/org/traccar/helper/DateUtilTest.java @@ -0,0 +1,30 @@ +package org.traccar.helper; + +import org.junit.Test; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; + +import static org.junit.Assert.assertEquals; + +public class DateUtilTest { + + @Test + public void testCorrectDate() throws ParseException { + + DateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + assertEquals(f.parse("2015-12-31 23:59:59"), + DateUtil.correctDate(f.parse("2016-01-01 00:00:01"), f.parse("2016-01-01 23:59:59"), Calendar.DAY_OF_MONTH)); + + assertEquals(f.parse("2016-01-01 00:00:02"), + DateUtil.correctDate(f.parse("2016-01-01 00:00:01"), f.parse("2016-01-01 00:00:02"), Calendar.DAY_OF_MONTH)); + + assertEquals(f.parse("2016-01-01 00:00:02"), + DateUtil.correctDate(f.parse("2016-01-01 00:00:01"), f.parse("2015-12-31 00:00:02"), Calendar.DAY_OF_MONTH)); + + } + +} diff --git a/src/test/java/org/traccar/helper/DistanceCalculatorTest.java b/src/test/java/org/traccar/helper/DistanceCalculatorTest.java new file mode 100644 index 000000000..a7457b6c4 --- /dev/null +++ b/src/test/java/org/traccar/helper/DistanceCalculatorTest.java @@ -0,0 +1,24 @@ +package org.traccar.helper; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class DistanceCalculatorTest { + + @Test + public void testDistance() { + assertEquals( + DistanceCalculator.distance(0.0, 0.0, 0.05, 0.05), 7863.0, 10.0); + } + + @Test + public void testDistanceToLine() { + assertEquals(DistanceCalculator.distanceToLine( + 56.83801, 60.59748, 56.83777, 60.59833, 56.83766, 60.5968), 33.0, 5.0); + + assertEquals(DistanceCalculator.distanceToLine( + 56.83753, 60.59508, 56.83777, 60.59833, 56.83766, 60.5968), 105.0, 5.0); + } + +} diff --git a/src/test/java/org/traccar/helper/LocationTreeTest.java b/src/test/java/org/traccar/helper/LocationTreeTest.java new file mode 100644 index 000000000..21604144a --- /dev/null +++ b/src/test/java/org/traccar/helper/LocationTreeTest.java @@ -0,0 +1,30 @@ +package org.traccar.helper; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class LocationTreeTest { + + @Test + public void testLocationTree() { + + List items = new ArrayList<>(); + items.add(new LocationTree.Item(1, 1, "a")); + items.add(new LocationTree.Item(3, 2, "b")); + items.add(new LocationTree.Item(1, 3, "c")); + items.add(new LocationTree.Item(4, 3, "d")); + + LocationTree tree = new LocationTree(items); + + assertEquals("a", tree.findNearest(new LocationTree.Item(1f, 1f)).getData()); + assertEquals("d", tree.findNearest(new LocationTree.Item(10f, 10f)).getData()); + assertEquals("c", tree.findNearest(new LocationTree.Item(1f, 2.5f)).getData()); + assertEquals("a", tree.findNearest(new LocationTree.Item(1.5f, 1.5f)).getData()); + + } + +} diff --git a/src/test/java/org/traccar/helper/LogTest.java b/src/test/java/org/traccar/helper/LogTest.java new file mode 100644 index 000000000..853eb05c9 --- /dev/null +++ b/src/test/java/org/traccar/helper/LogTest.java @@ -0,0 +1,14 @@ +package org.traccar.helper; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class LogTest { + + @Test + public void testLog() { + assertEquals("test - Exception (LogTest:11 < ...)", Log.exceptionStack(new Exception("test"))); + } + +} diff --git a/src/test/java/org/traccar/helper/ObdDecoderTest.java b/src/test/java/org/traccar/helper/ObdDecoderTest.java new file mode 100644 index 000000000..1ffe68c8b --- /dev/null +++ b/src/test/java/org/traccar/helper/ObdDecoderTest.java @@ -0,0 +1,26 @@ +package org.traccar.helper; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ObdDecoderTest { + + @Test + public void testDecode() { + + assertEquals(83, ObdDecoder.decode(0x01, "057b").getValue()); + assertEquals(1225, ObdDecoder.decode(0x01, "0C1324").getValue()); + assertEquals(20, ObdDecoder.decode(0x01, "0D14").getValue()); + assertEquals(64050, ObdDecoder.decode(0x01, "31fa32").getValue()); + assertEquals(25, ObdDecoder.decode(0x01, "2F41").getValue()); + + } + + @Test + public void testDecodeCodes() throws Exception { + assertEquals("P0D14", ObdDecoder.decodeCodes("0D14").getValue()); + assertEquals("dtcs", ObdDecoder.decodeCodes("0D14").getKey()); + } + +} diff --git a/src/test/java/org/traccar/helper/PatternBuilderTest.java b/src/test/java/org/traccar/helper/PatternBuilderTest.java new file mode 100644 index 000000000..4c76bc463 --- /dev/null +++ b/src/test/java/org/traccar/helper/PatternBuilderTest.java @@ -0,0 +1,20 @@ +package org.traccar.helper; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class PatternBuilderTest { + + @Test + public void testPatternBuilder() { + assertEquals("\\$GPRMC", new PatternBuilder().text("$GPRMC").toString()); + assertEquals("(\\d{2}\\.[0-9a-fA-F]+)", new PatternBuilder().number("(dd.x+)").toString()); + assertEquals("a(?:bc)?", new PatternBuilder().text("a").text("b").text("c").optional(2).toString()); + assertEquals("a|b", new PatternBuilder().expression("a|b").toString()); + assertEquals("ab\\|", new PatternBuilder().expression("ab|").toString()); + assertEquals("|", new PatternBuilder().or().toString()); + assertEquals("\\|\\d|\\d\\|", new PatternBuilder().number("|d|d|").toString()); + } + +} diff --git a/src/test/java/org/traccar/helper/PatternUtilTest.java b/src/test/java/org/traccar/helper/PatternUtilTest.java new file mode 100644 index 000000000..77660078a --- /dev/null +++ b/src/test/java/org/traccar/helper/PatternUtilTest.java @@ -0,0 +1,18 @@ +package org.traccar.helper; + +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class PatternUtilTest { + + @Ignore + @Test + public void testCheckPattern() { + + assertEquals("ab", PatternUtil.checkPattern("abc", "abd").getPatternMatch()); + + } + +} diff --git a/src/test/java/org/traccar/model/MiscFormatterTest.java b/src/test/java/org/traccar/model/MiscFormatterTest.java new file mode 100644 index 000000000..eb93d5b38 --- /dev/null +++ b/src/test/java/org/traccar/model/MiscFormatterTest.java @@ -0,0 +1,20 @@ +package org.traccar.model; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class MiscFormatterTest { + + @Test + public void testToString() throws Exception { + + Position position = new Position(); + position.set("a", "1"); + position.set("b", "2"); + position.set("a", "3"); + + assertEquals("32", MiscFormatter.toXmlString(position.getAttributes())); + + } + +} diff --git a/src/test/java/org/traccar/notification/NotificiationMailTest.java b/src/test/java/org/traccar/notification/NotificiationMailTest.java new file mode 100644 index 000000000..b82bec02e --- /dev/null +++ b/src/test/java/org/traccar/notification/NotificiationMailTest.java @@ -0,0 +1,59 @@ +package org.traccar.notification; + +import org.junit.Ignore; +import org.junit.Test; + +import javax.mail.Message; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import java.util.Properties; + +public class NotificiationMailTest { + + private static final String FROM = "notification@traccar.org"; + private static final String TO = "anton@traccar.org"; + + private static final String BODY = "Test email body."; + private static final String SUBJECT = "Test"; + + private static final String SMTP_USERNAME = "username"; + private static final String SMTP_PASSWORD = "password"; + + private static final String HOST = "email-smtp.us-west-2.amazonaws.com"; + + private static final int PORT = 25; + + @Ignore + @Test + public void test() throws Exception { + + Properties props = System.getProperties(); + props.put("mail.transport.protocol", "smtps"); + props.put("mail.smtp.port", PORT); + + props.put("mail.smtp.auth", "true"); + props.put("mail.smtp.starttls.enable", "true"); + props.put("mail.smtp.starttls.required", "true"); + + Session session = Session.getInstance(props); + + MimeMessage msg = new MimeMessage(session); + msg.setFrom(new InternetAddress(FROM)); + msg.setRecipient(Message.RecipientType.TO, new InternetAddress(TO)); + msg.setSubject(SUBJECT); + msg.setContent(BODY, "text/plain"); + + Transport transport = session.getTransport(); + + try { + transport.connect(HOST, SMTP_USERNAME, SMTP_PASSWORD); + transport.sendMessage(msg, msg.getAllRecipients()); + } finally { + transport.close(); + } + + } + +} diff --git a/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java new file mode 100644 index 000000000..599dd6190 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java @@ -0,0 +1,38 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AdmProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AdmProtocolDecoder decoder = new AdmProtocolDecoder(null); + + verifyNull(decoder, binary( + "010042033836313331313030323639343838320501000000000000000000000000000000000000000000000000000000000000000000000000000000000000000073")); + + verifyPosition(decoder, binary( + "01002e40041c0744009dfe6742c6c860427402000000f4ff077752c8f55b000000000b4132010213430100041e")); + + verifyPosition(decoder, binary( + "01002680336510002062A34C423DCF8E42A50B1700005801140767E30F568F2534107D220000")); + + verifyPosition(decoder, binary( + "010022003300072020000000000000000044062A330000000000107F10565D4A8310")); + + verifyPosition(decoder, binary( + "0100268033641080207AA34C424CCF8E4239030800005B01140755E30F560000F00F70220000")); + + verifyPosition(decoder, binary( + "01002680336510002062A34C423DCF8E42A50B1700005801140767E30F568F2534107D220000")); + + verifyPosition(decoder, binary( + "01002200333508202000000000000000007F0D9F030000000000E39A1056E24A8210")); + + verifyNotNull(decoder, binary( + "01008449443d3120536f66743d30783531204750533d313036382054696d653d30383a35393a32302031302e30392e31372056616c3d30204c61743d36312e36373738204c6f6e3d35302e3832343520563d3020536174436e743d342b3720537461743d30783030313020496e5f616c61726d3d30783030000000000000000000000000")); + } + +} diff --git a/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java new file mode 100644 index 000000000..cb0a31ceb --- /dev/null +++ b/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2017 Anatoliy Golubev (darth.naihil@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 org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class AdmProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + AdmProtocolEncoder encoder = new AdmProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_GET_DEVICE_STATUS); + assertEquals("STATUS\r\n", encoder.encodeCommand(command)); + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "INPUT 0"); + assertEquals("INPUT 0\r\n", encoder.encodeCommand(command)); + } + +} diff --git a/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java new file mode 100644 index 000000000..9cb9f695a --- /dev/null +++ b/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java @@ -0,0 +1,31 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AisProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AisProtocolDecoder decoder = new AisProtocolDecoder(null); + + verifyPositions(decoder, text( + "!AIVDM,2,1,8,A,53UlSb01l>Ei=H4KF218PTpv222222222222221?8h=766gB00000K6J;5KAIT03wpUkP06,0*5D\\s:MTb827ebc7686b,c:1481688230418*45\\\r\n" + + "!AIVDM,1,1,,B,B52Q8a@00Ul`9N5@ssbmCwr5oP06,0*36\r\n" + + "!AIVDM,1,1,,A,18154?v<2D=j,0*54\r\n\r\n")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java new file mode 100644 index 000000000..47ea8137e --- /dev/null +++ b/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java @@ -0,0 +1,42 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AlematicsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AlematicsProtocolDecoder decoder = new AlematicsProtocolDecoder(null); + + verifyPosition(decoder, text( + "$T,2,64,866050035975497,20180726103446,20180726103514,23.033305,72.558032,0,0,41,5.4,4,0,0,0.000,12.960,0,")); + + verifyPosition(decoder, text( + "$T,2,65,866050035975497,20180726103646,20180726103736,23.033305,72.558032,0,0,41,5.4,4,0,0,0.000,12.976,0,0")); + + verifyPosition(decoder, text( + "$T,2,552,868259020159698,20170515060949,20170515060949,25.035277,121.561986,0,202,78,1.0,8,1,0,0.000,12.768,1629,38,12770,4109,9")); + + verifyPosition(decoder, text( + "$T,2,553,868259020159698,20170515061019,20170515061019,25.035295,121.561981,0,202,79,1.0,8,1,0,0.000,12.768,1629,38,12772,4109,8")); + + verifyPosition(decoder, text( + "$T,4,4,868259020159698,20170515061033,20170515061033,25.035303,121.561975,0,202,81,1.7,6,1,0,0.000,12.770,1629,0,$S,A1,1,,12345.67,88.4,301.5,,2593.25,12.4,89.2,,5999.44,789.572,2345.67,,10763,1024,5,")); + + verifyPosition(decoder, text( + "$T,2,554,868259020159698,20170515061049,20170515061049,25.035309,121.561976,0,202,82,1.1,7,1,0,0.000,12.768,1629,38,12770,4109,9")); + + verifyPosition(decoder, text( + "$T,4,5,868259020159698,20170515061058,20170515061058,25.035308,121.561976,0,202,82,1.2,7,1,0,0.000,12.772,1629,0,$S,A1,1,,12345.67,88.4,301.5,,2593.25,12.4,89.2,,5999.44,789.572,2345.67,,10763,1024,5,")); + + verifyPosition(decoder, text( + "$T,50,592,868259020159698,20170515062915,20170515062915,25.035005,121.561555,0,31,89,3.7,5,1,0,0.000,12.752,1629,38,12752,4203,6")); + + verifyPosition(decoder, text( + "$T,50,594,868259020159698,20170515062928,20170515062928,25.035151,121.561671,0,31,93,1.8,5,0,0,0.000,12.752,1629,38,12756,4205,6")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java new file mode 100644 index 000000000..e3aa0550b --- /dev/null +++ b/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AnytrekProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AnytrekProtocolDecoder decoder = new AnytrekProtocolDecoder(null); + + verifyPosition(decoder, binary( + "78783500300086428703204121160085015111050C0A0D20C6FD24A102FF8EAC0C01001404000000FFFFFFFF131702210000000000000000000D0A")); + + verifyPosition(decoder, binary( + "787835003000867279033457792c009801001209080a3408c81b2a7d0305b88b0c00001ccb0000000f00000002b90174f30b000000000000000d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java new file mode 100644 index 000000000..c32abe6a8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ApelProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ApelProtocolDecoder decoder = new ApelProtocolDecoder(null); + + /*byte[] buf1 = {0x40,0x4E,0x54,0x43,0x01,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x13,0x00,0x44,0x34,0x2A,0x3E,0x53,0x3A,0x38,0x36,0x31,0x37,0x38,0x35,0x30,0x30,0x35,0x32,0x30,0x35,0x30,0x37,0x39}; + verifyNull(decoder, text( ChannelBuffers.wrappedBuffer(ByteOrder.LITTLE_ENDIAN, buf1)));*/ + + //0c002900f12a00000f003235303032363533343135313036340f0033353638393530333632373938313101002000000000 + //5c00380046e6a95136b693277f11b41a00172709f2ff03160002b9bc630007000000000000000000000000000000c31071090000880500000000000000000000 + //5c00380072e7a95136b693277f11b41a00172709f2ff03160002b9bc630007000000000000000000000000000000c31071090000880500000000000000000000 + + //7900040069ea030000000000 + //8300c20003006aea03005c003800223aab5107a393276617b41a0030d506e3000414010250bf630007000000000000000000000000000000c3107209000089050000000000006bea03005c003800403aab5107a393276617b41a0030d506e3000414010250bf630007000000000000000000000000000000c3107209000089050000000000006cea03005c0038005e3aab5107a393276617b41a0030d506e3000414010250bf630007000000000000000000000000000000c31072090000890500000000000000000000 + + } + +} diff --git a/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java new file mode 100644 index 000000000..581f7696f --- /dev/null +++ b/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class AplicomFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AplicomFrameDecoder decoder = new AplicomFrameDecoder(); + + assertEquals( + binary("44C20146B710C158DA009500B09F7700C054CA0EA454CA0EA403BE0BF6015D706B070000142A600000000000000002434946010801000754CA0EA4000000000000008400000000000000000000000000000000300000FE00FE0000000000000000000000000000000000000000000000000000000000000000000040502035000000000000020D0000030D0000040C0000040D0000050C0000050D0000058C0000060C"), + decoder.decode(null, null, binary("33353733303030373030393233333644C20146B710C158DA009500B09F7700C054CA0EA454CA0EA403BE0BF6015D706B070000142A600000000000000002434946010801000754CA0EA4000000000000008400000000000000000000000000000000300000FE00FE0000000000000000000000000000000000000000000000000000000000000000000040502035000000000000020D0000030D0000040C0000040D0000050C0000050D0000058C0000060C"))); + + assertEquals( + binary("44C20146B710C158DA009500B09F7700C054CA0EA454CA0EA403BE0BF6015D706B070000142A600000000000000002434946010801000754CA0EA4000000000000008400000000000000000000000000000000300000FE00FE0000000000000000000000000000000000000000000000000000000000000000000040502035000000000000020D0000030D0000040C0000040D0000050C0000050D0000058C0000060C"), + decoder.decode(null, null, binary("44C20146B710C158DA009500B09F7700C054CA0EA454CA0EA403BE0BF6015D706B070000142A600000000000000002434946010801000754CA0EA4000000000000008400000000000000000000000000000000300000FE00FE0000000000000000000000000000000000000000000000000000000000000000000040502035000000000000020D0000030D0000040C0000040D0000050C0000050D0000058C0000060C"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java new file mode 100644 index 000000000..0b4180bd0 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java @@ -0,0 +1,93 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AplicomProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AplicomProtocolDecoder decoder = new AplicomProtocolDecoder(null); + + verifyNull(decoder, binary( + "434946010A0100075253F85F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FEEA0000FEE90000F0030000F0040000FEF10000FEF20000FEF50000FEFC0000FEC10000FEE500")); + + verifyAttributes(decoder, binary( + "44c30144f667c0e462019800b05f7700005b7d3bdd00000000000000000000000000000000805e420fd60a0d57fffffb002141100000011001000c0932200000000000000a18136fcafefffffb002141100000011001000c0932200000000000000a1812e6dbfefffffb002141100000011001000c746578746167204e000008e3980bfefffffb002141100000011001000ce2009000170400890310f290e873fefffffb002141100000011001000ce2009000170400890290f28e409afefffffb002141100000011001000c0932200000000000000a1812e6dbfefffffb002141100000011001000ce2009000170400890280f28d4e2dfefffffb002141100000011001000c0001460000000000000021427a6cfefffffb002141100000011001000c0001460000000000000021606a6efefffffb002141100000011001000c746578746167204e000008badcc4fefffffb002141100000011001000c00014600000000000000218c0843fefffffb002141100000011001000ce2009000170400890270f6d45e09fefffffb002141100000011001000ce2801160600002053cd57a16549efe")); + + verifyAttributes(decoder, binary( + "44c30144f667ca8e6b003200b45f7700f05b6565e75b6565e6031f845100c6f0e70c00001483387c0fe60001000a263433233031303138373433303746230d0a")); + + verifyAttributes(decoder, binary( + "44c30144f667ca8e6b002d00305f7700d45b307a9a5b307a97031f840a00c6f05b0600000083000000263433233031303138373433303746230d0a")); + + verifyAttributes(decoder, binary( + "44c30144f667c4316500e903ffdfbc00f059aebeb659aebeb302e3f5860065fe32120000ae0000000e47000000000000000000000000000127cd0000014c00000000000000ff010a002900000000000000014542016d0001010090070e140144f667c4316559ae620402e3f7f300660714c0010d15ff0f3332373937313100000000000000000000002a01010737341d331fffcf0103020b8601060c0001a5860001a58600000000010b1001ca01ca7d007d007c7cffffffffffff010a240000ffff0000000100010001ffff0000ffffffffffffffffffffffffffff00000002ffff010c06fec6febffeec")); + + verifyAttributes(decoder, binary( + "45c20144f667c06ff9005d0161ef17000104596da2dc4b10c0c01d99020d6c04004cba7a010d44463030303235333731363238303030000000000000000000000000000000000000000000000000000001010d44463030303235333731363238303030000000000000031c")); + + verifyAttributes(decoder, binary( + "45c20144f667c07287008c01ffff6d01000059368963d0340a0616207d7f4b10c0c019e6000039d7000039d71f40ffff5001574442393036363035533132333435363700014142432d33343520202020202000011231303331373139343039303030303031000000000000000000000000000000000000000000000000000001011231303331373139343039303030303031000000000000005a")); + + verifyAttributes(decoder, binary( + "46c30144f667c1711f00340007ff750058b8f77701037c06b8000000330033000000000b760000425e0100640000b3a90185d5823155000131070204000219641004")); + + verifyAttributes(decoder, binary( + "46c30144f667c1711f00340007ff75005891601401025707b50236003b003b003500000a9300006bd50100640000a5250167d2f9034c01010107020400021a901004")); + + verifyAttributes(decoder, binary( + "48C1014143B4493145004900203F6D014B5557C20003000015060110FF00C800000000000000003D01141E283C500100260404010200000000000000000000000000C8000000000000010200110019001E0064019003E8")); + + verifyAttributes(decoder, binary( + "48c10144b9de54e6b2008700205f710a57d23ec957d23b8d00000000300d0106ff00000000000000000000000000000000000000000000000000000000000000010a141e28323c46505a646e7801000f020104ff000000000000000000010102000f020104ff000000000000000000010103000f020104ff000000000000000000010105000f020104ff0000000000000000000101")); + + verifyAttributes(decoder, binary( + "45c20145931876ffb2007100ffff6d00000057c6dd1970230d087b1f7d7f0000d0c1000000003580000035801f40ffff5001574442393036363035533132333435363700014142432d333435202020202020000000000000000000000000000000000000000000000001123130343632343639373030303030303100000000")); + + verifyAttributes(decoder, binary( + "45c20145931876ffb2007100ffff6d00000057c6dd9170250d087b1f7d7f0000d0c1000000003580000035801f40ffff5001574442393036363035533132333435363700014142432d333435202020202020000000000000000000000000000000000000000000000001123130343632343639373030303030303100000000")); + + verifyAttributes(decoder, binary( + "45c20145931876ffb2007100ffff6d00000057c6de0970270d087b1f7d7f0000d0c1000000003580000035801f40ffff5001574442393036363035533132333435363700014142432d333435202020202020000000000000000000000000000000000000000000000001123130343632343639373030303030303100000000")); + + verifyAttributes(decoder, binary( + "44c3014645e8ecff3c00ea03ffffbc00f457d68a6557d68a6303bb55fa018843da1100009881000000000000000000000000000000000000000000000000000000000000000000000000000000ff0056007600000000000000014542016d0001010095070e14014645e8ecff3c57d68a6403bb55fa018843dac0010d14ff050102030405060708090a0b0c0d0e0f10112a01010730343f3c1ff5cf01020700007d007d23010103022f2e01060c67452301efcdab8967452301010b10000000007d007d007d7dffffffffffff010a2400000000000000010000000000000000ffffffffffffffff00010001ffff00000000ffff010c02fec6")); + + verifyPosition(decoder, binary( + "44c3014645e8e91b66002300a21f0b01f056d3e62856d3e626031f845f00c6ee440800000000000000000017bd1cb30000")); + + verifyPosition(decoder, binary( + "44c3014645e8e91b66002300a21f0b00f056d3e64756d3e646031f845f00c6ee440800000000000000000017bd1cb30001")); + + verifyPosition(decoder, binary( + "44c3014645e8e91b66001f00221f0b01f456ba1e0d56ba1e0b031f842200c6ef550c000000000017bd1cb30004")); + + verifyAttributes(decoder, binary( + "44c3014645e8e9bada003e03fff7070055a4f24200000081000000000000000000000000000000000000000000000000000000000000000000000000000000ff00000001000000000000000044c3014645e8e9bada003e03fff77bff55a4f24300000081000000000000000000000000000000000000000000000000000000000000000000000000000000ff00300002000000000000000044c3014645e8e9bada003e03fff7690655a4f24500000081000000000000000000000000000000000000000000000000000000000000000000000000000000ff003000030000000000000000")); + + verifyPosition(decoder, binary( + "44c3014645e8e9d29a002d0022ff6d00f455893b4d55893b4c027a7e1500189d710800009e0000000000000000000000023300000000000000009d")); + + verifyPosition(decoder, binary( + "44C20146B710C158DA002100B09F0700C054CA0EA254CA0E9C03BE0BF6015D7069070000142A600000000000000001")); + + verifyPosition(decoder, binary( + "44C20143720729D6840043031fff7191C0450ef906450ef90603b20b8003b20b80066465b3870ce30f010ce30ce3003200001520000000030aa200003b13000000320300000bcb17acff0099000186a002")); + + verifyPosition(decoder, binary( + "440129D684002b0700C0450ef906450ef90603b20b8003b20b80066465b3870ce30f010ce30ce300003b130300000bcb170a")); + + verifyPosition(decoder, binary( + "44c3014645e8e9152e008900b09f7700f4558c07e8558c07e703be0bd8015d6faf0e0000003240000000000000000f4349460107010007558c07e70000000000000002d209df028f05fffe00000000000000002eff13fe11fe1a00011000000000000010ff11ff3cff11008c00080060f41b0043502015000000000000020d0000030d0000040c0000040d0000050c0000050d0000058c")); + + verifyPosition(decoder, binary( + "44c20144563508385a009500b09f7700c0555ea99e555ea9b103bb569f01883ff50b00002a30f000000000000013074349460108010007555ea99e000000000000003f0000ae017605b3ff00000000010000006700d900d500000003000000000000006700d900d500000087002500c4ff0000435020150000000040512001000000000000020d0000030d0000040c0000040d0000050c0000050d0000058c0000060c")); + + verifyPosition(decoder, binary( + "44C20146B710C158DA009500B09F7700C054CA0EA454CA0EA403BE0BF6015D706B070000142A600000000000000002434946010801000754CA0EA4000000000000008400000000000000000000000000000000300000FE00FE0000000000000000000000000000000000000000000000000000000000000000000040502035000000000000020D0000030D0000040C0000040D0000050C0000050D0000058C0000060C")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java new file mode 100644 index 000000000..ac0858e82 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AppelloProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AppelloProtocolDecoder decoder = new AppelloProtocolDecoder(null); + + verifyAttributes(decoder, text( + "FOLLOWIT,867273024233699,UTCTIME,0.000000,0.000000,0,0,0,0,L,262:3:c703:4bf8:64:255|262:3:c703:9a18:45|262:3:c703:e838:33|262:3:c703:7190:20|262:3:c704:d896:17|,02,44,,31,,4.20,0,0,86/44/24,,,,26,02264DFF6E16:69|4C09D408554E:79|4C09D408554F:79|E0885DE705E5:81|E2885DE705E7:81|246511122CCC:83|,34925")); + + verifyAttributes(decoder, text( + "FOLLOWIT,867273024233699,UTCTIME,0.000000,0.000000,0,0,0,0,L,262:3:c703:4bf8:64:1|262:3:c703:9a18:44|262:3:c703:e838:33|262:3:c703:7190:21|262:3:c704:d896:18|262:3:c703:71a6:13|262:3:c703:253d:13|,02,44,,22,,4.20,0,0,86/44/24,,,,30,02264DFF6E16:67|E0885DE705E5:87|B4A5EF284B94:88|E2885DE705E7:85|4C09D408554E:78|3481C4D71B13:43|,24033")); + + verifyAttributes(decoder, text( + "FOLLOWIT,860719028336968,UTCTIME,-12.112660,-77.045189,0,0,3,-0,L,716,10,049C,2A47,23,,4.22,,53,999/00/00,,,,,,59826,")); + + verifyPosition(decoder, text( + "FOLLOWIT,860719028336968,160211221959,-12.112660,-77.045258,1,0,6,116,F,716,17,4E85,050C,29,,4.22,,39,999/00/00,,,,,,46206,")); + + verifyPosition(decoder, text( + "FOLLOWIT,359586019278139,130809160321,22.340218,114.030737,60,120,05,152,F,460,01,2533,720B,31,out,3.90,1,192,20/00/00,12.5,100%,80,45,1CFA68BB754E:60|2CFA68BB754E:100|3CFA68BB754E:100|4CFA68BB754E:100|5CFA68BB754E:100|,46672")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AppletProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AppletProtocolDecoderTest.java new file mode 100644 index 000000000..ad13c60f6 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AppletProtocolDecoderTest.java @@ -0,0 +1,27 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AppletProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AppletProtocolDecoder decoder = new AppletProtocolDecoder(null); + + DefaultHttpHeaders headers = new DefaultHttpHeaders(); + + headers.add("HOST", "192.168.0.1:8080"); + headers.add("X-Admin-Protocol", "globalplatform-remote-admin/1.0"); + headers.add("X-Admin-From", "8943170080001406197F"); + headers.add("User-Agent", "oma-scws-admin-agent/1.1"); + headers.add("From", "8943170080001406197F"); + + verifyNull(decoder, request(HttpMethod.POST, "/pli?=", headers)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java new file mode 100644 index 000000000..793b2c646 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java @@ -0,0 +1,79 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AquilaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecodeA() throws Exception { + + AquilaProtocolDecoder decoder = new AquilaProtocolDecoder(null); + + verifyPosition(decoder, text( + "$$CLIENT_1ZF,170215089,20,18.462809,73.824188,170613182744,A,01,123456,*37")); + + verifyPosition(decoder, text( + "$$CLIENT_1ZF,170215089,1,18.462809,73.824188,170613182744,A,19,0,0,256,4,4.860000,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,259,3731,*37")); + + verifyPosition(decoder, text( + "$$CLIENT_1ZF,170222318,101,22.846016,75.949104,170321103506,A,0,0,244991,0,10,0.860000,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,12483,294,*3D")); + + verifyNull(decoder, text( + "$$CLIENT_1ZF,170222318,15,2_00AP,70.35.195.185,5089,internet,T1:10 S,T2:1 M,Ad1:9164061023,Ad2:9164061023,TOF:0 S,,OSC:75 KM,OST:0 S,GPS:YES,Ignition:ON,*75")); + + verifyPosition(decoder, text( + "$$CLIENT_1ZF,170222318,1,22.836912,75.942215,170321110736,A,11,12,247196,103,10,0.810000,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,13325,306,*36")); + + verifyPosition(decoder, text( + "$$CLIENT_1ZF,130329214,1,12.962985,77.576484,140127165433,A,22,0,0,140,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1253,420,1,0,1,0,0,1,P(01:410104000102|05:410521|0C:410C0000|0D:410D65|21:4121161C),D(P0121|B2105),-895,745,-145,300,*26")); + + verifyPosition(decoder, text( + "$$CLIENT_1NS,101010119,1,22.845943,75.949059,170202184000,A,27,0,0,120,31141,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,399,3709,0,0,0,0,0,0,P(01:|04:|05:|0B:|0C:|0D:|10:|1C:|21:|23:|30:|31:|1F:|11:|00:|00:|),D(),-89,44,-1062,0,*49")); + + verifyPosition(decoder, text( + "$$CLIENT_1DT,151028368,1,19.108438,72.925308,160628154920,A,22,0,0,131,3503,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,*1D")); + + verifyNull(decoder, text( + "$$CLIENT_1DT,160319372,1,28.549541,77.249802,160628140743,A,23,0,-65025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,*0D")); + + verifyPosition(decoder, text( + "$$SRINI_1MS,141214807,1,12.963515,77.533844,150925161628,A,27,0,8,0,68,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,*43")); + + verifyPosition(decoder, text( + "$$CLIENT_1ZF,130329214,1,12.962985,77.576484,140127165433,A,22,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,*26")); + + verifyPosition(decoder, text( + "$$CLIENT_1WP,141216511,3,12.963123,77.534012,150908163534,A,31,0,0,0,7,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,*28")); + + verifyPosition(decoder, text( + "$$CLIENT_1WP,141216511,3,12.963212,77.533989,150908164041,V,31,0,0,0,8,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,*2A")); + + } + + @Test + public void testDecodeB() throws Exception { + + AquilaProtocolDecoder decoder = new AquilaProtocolDecoder(null); + + verifyPosition(decoder, text( + "$Header,nliven,EMR,861693034634154,NM,09112017155133,A,12.976495,N,77.549713,E,906.0,0.0,23,G,KA01I2000,+919844098440*4B")); + + verifyPosition(decoder, text( + "$EPB,iTriangle1,EMR,864495034445822,SP,03082018110730,A,22.829292,N,75.935806,E,543.0,0.0,0,G,KA01G1234,+9164061023*13")); + + verifyPosition(decoder, text( + "$Header,iTriangle,1_37T02B0164MAIS_2,NR,1,L,864495034490141,KA01I2000,1,19042018,102926,22.846401,N,75.948952,E,0.0,311,5,578.0,3.80,3.67,AirTel,0,1,12.5,4.3,1,C,14,404,93,0456,16db,29,ebd8,0458,28,3843,18ab,25,072e,18ab,22,35da,0458,0000,00,031181,0.0,0.0,0,()*34")); + + verifyPosition(decoder, text( + "$Header,nliven,1_37T02B0164MAIS,BR,6,L,861693034634154,KA01I2000,1,09112017,160702,12.976593,N,77.549782,E,25.1,344,15,911.0,1.04,0.68,Airtel,1,1,11.8,3.8,1,C,24,404,45,61b4,9ad9,31,9adb,61b4,35,ffff,0000,33,ffff,0000,31,ffff,0000,0001,00,000014,0.0,0.1,4,()*1E")); + + verifyPosition(decoder, text( + "$Header,iTriangle,1_37T02B0164MAIS_2,NR,1,L,864495034490141,KA01I2000,1,31032018,122247,22.845999,N,75.949005,E,0.0,44,16,545.0,1.19,0.65,AirTel,1,1,12.0,4.3,0,C,13,404,93,0456,16db,27,16dd,0456,22,3843,18ab,19,ebd8,0458,14,072c,18ab,0101,00,003735,0.0,0.0,0,()*48")); + + verifyNull(decoder, text( + "$Header,nliven,KA01I2000,861693034634154,1_37T02B0164MAIS,AIS140,12.976545,N,77.549759,E*50")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java new file mode 100644 index 000000000..8498bb7f9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Ardi01ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Ardi01ProtocolDecoder decoder = new Ardi01ProtocolDecoder(null); + + verifyPosition(decoder, text( + "013227003054776,20141010052719,24.4736042,56.8445807,110,289,40,7,5,78,-1"), + position("2014-10-10 05:27:19.000", true, 56.84458, 24.47360)); + + verifyPosition(decoder, text( + "013227003054776,20141010052719,24.4736042,56.8445807,110,289,40,7,5,78,-1")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java new file mode 100644 index 000000000..18901d9a6 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ArknavProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ArknavProtocolDecoder decoder = new ArknavProtocolDecoder(null); + + verifyPosition(decoder, text( + "358266016278447,05*827,000,L001,V,4821.6584,N,01053.8650,E,000.0,000.0,00.0,08:46:04 17-03-16,9.5A,D7,0,79,0,,,,"), + position("2016-03-17 08:46:04.000", false, 48.36097, 10.89775)); + + verifyPosition(decoder, text( + "123456789012345,05*850,000,L001,A,2459.3640,N,12125.2958,E,000.0,224.8,00.8,07:47:26 09-09-05,9.00,D3,0,C4,1,,,,")); + + verifyPosition(decoder, text( + "123456789012345,05*850,000,L001,A,2459.3640,N,12125.2958,E,000.0,224.8,00.8,07:47:26 09-09-05,9.00,D3,0,C4,1,,,00000000,")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java new file mode 100644 index 000000000..dfe1435d1 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java @@ -0,0 +1,45 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ArknavX8ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ArknavX8ProtocolDecoder decoder = new ArknavX8ProtocolDecoder(null); + + verifyNull(decoder, text( + "351856045213782,241111")); + + verifyPosition(decoder, text( + "1G,181213092101,A,0347.0756N,09842.7435E,0.0,183,1.1,11008000")); + + verifyAttributes(decoder, text( + "2G,181213092101,08,4084.0,00.04,04.01,000396255.0")); + + verifyNull(decoder, text( + "2R,090214235955,00,,00.04,03.76,001892024.9")); + + verifyNull(decoder, text( + "351856040005407,240101")); + + verifyPosition(decoder, text( + "1R,110509053244,A,2457.9141N,12126.3321E,220.0,315,10.0,00000000")); + + verifyNull(decoder, text( + "2R,110509053244,837493,,998372,,,")); + + verifyPosition(decoder, text( + "1G,110509053245,A,2457.9141N,12126.3192E,3.1,35,2.0,00000001")); + + verifyPosition(decoder, text( + "1G,110509053246,A,2457.9121N,12126.3415E,2.0,288,1.7,00000000")); + + verifyPosition(decoder, text( + "1M,110509053247,A,2457.9118N,12126.3522E,1.0,55,2.2,00000000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ArnaviProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviProtocolDecoderTest.java new file mode 100644 index 000000000..6b075facc --- /dev/null +++ b/src/test/java/org/traccar/protocol/ArnaviProtocolDecoderTest.java @@ -0,0 +1,42 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ArnaviProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ArnaviProtocolDecoder decoder = new ArnaviProtocolDecoder(null); + + verifyPosition(decoder, text( + "$AV,V4,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,80.0,56.1,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); + + verifyNull(decoder, text( + "$AV,V3DI,85164,20707,-1,19,0008C56A,000879AC,0C000002,863071013041618,89997077111301204297,*0B")); + + verifyNull(decoder, text( + "$AV,V6SD,85164,20708,-1,3,6,37,33,*52")); + + verifyAttributes(decoder, text( + "$AV,V4,85164,20709,1148,418,-1,0,1,192,0,0,0,0,0,0,,,000023,0000.0000N,00000.0000E,0.0,0.0,060180,0,0,32767,*4F")); + + verifyNull(decoder, text( + "$AV,V3GSMINFO,85164,-1,20450,KMOBILE,1,2,1,23,0,40101,cc3,1,ce19,401,16,65304,5613,72,,SF*7F")); + + verifyAttributes(decoder, text( + "$AV,V4,85164,20451,1146,418,-1,1,1,192,0,0,0,0,0,0,,,104340,0000.0000N,00000.0000E,0.0,0.0,060219,11,0,32767,,SF*47")); + + verifyNull(decoder, text( + "$AV,V6SD,85164,20452,-1,3,3,5,6769,,SF*5D")); + + verifyPosition(decoder, text( + "$AV,V2,32768,12487,2277,203,-1,0,0,193,0,0,1,13,200741,5950.6773N,03029.1043E,0.0,0.0,121012,*6E")); + + verifyPosition(decoder, text( + "$AV,V3,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java new file mode 100644 index 000000000..453ec9da5 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AstraProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AstraProtocolDecoder decoder = new AstraProtocolDecoder(null); + + verifyPositions(decoder, binary( + "4b00700529c0c265976b8202cba9ff00676d864554a9c30000000020073401006436000300030008000000000000a0000100001920c43d00009600428302cba9ff00676d864554aa3e000000002007240100643b000300020008000000000000b0000100001920c43d00009600420f0e")); + + verifyPositions(decoder, binary( + "4b00320524c1da58769e6d0322617effe874024453065600a800000100080000643e0000000000000000000000069500e7bb")); + + verifyPositions(decoder, binary( + "4b013c02213aec35c501ad031368b8ffcd1ad043e5c4500c79000100003101005c490c001c0009020200020015069600ae03136801ffcd1af143e5c452125e000100003101005c491200090011010000020015068500af0313629effcd1f4b43e5c45d1e46000100003101005c491e00080409040500040015068700b0031359d5ffcd35ad43e5c47b2a3b000001003101005c492a1b1a0d0b0f0b00080015068700b103134984ffcd4b1e43e5c4913354000100003101005c49340b0103090606000f0015067700b203132e1affcd5a5a43e5c4af3348000001003101005c4935070a08000a070017001505f700b30313192cffcd7af143e5c4cd3733000001003101005c4937091206050a0800200015058600b403130debffcda88743e5c4eb2c3e000001003101005c493707030601080600290015058600b377")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java b/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java new file mode 100644 index 000000000..c5829d588 --- /dev/null +++ b/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class At2000FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + At2000FrameDecoder decoder = new At2000FrameDecoder(); + + verifyFrame( + binary("01012f00000000000000000000000000003335363137333036343430373439320fad981997ae8e031fe10c0ea7641903ca32c0331df467233d2a9cd886fbeef8"), + decoder.decode(null, null, binary("01012f00000000000000000000000000003335363137333036343430373439320fad981997ae8e031fe10c0ea7641903ca32c0331df467233d2a9cd886fbeef8"))); + + verifyFrame( + binary("893f0000000000000000000000000000e048b1a31deba3f5dbe8877f574877e6ed4d022b6611a10d80dfc4c0c11fa8aacf4a9de61528327e2b66843dd9c5d3a7cc9ee1d9c71a34bb482145d88b4fda3e"), + decoder.decode(null, null, binary("893f0000000000000000000000000000e048b1a31deba3f5dbe8877f574877e6ed4d022b6611a10d80dfc4c0c11fa8aacf4a9de61528327e2b66843dd9c5d3a7cc9ee1d9c71a34bb482145d88b4fda3e"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java new file mode 100644 index 000000000..9e2f180d2 --- /dev/null +++ b/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java @@ -0,0 +1,59 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assume.assumeTrue; + +public class At2000ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + assumeTrue(Boolean.parseBoolean(System.getenv("CI"))); + + At2000ProtocolDecoder decoder; + + decoder = new At2000ProtocolDecoder(null); + + verifyNull(decoder, binary( + "01012f00000000000000000000000000003335373435343037313632373539388b57ec3a6ec7e3310a1ceb0a70fd751b8f2e7be6df1d6dcd80129f66fff0ea1c")); + + verifyNull(decoder, binary( + "89000000000000000000000000000000")); + + decoder = new At2000ProtocolDecoder(null); + + verifyNull(decoder, binary( + "01012f0000000000000000000000000000333537343534303731363036313936ddf189075add9a32d97b54073025963e65849a3a59940d05fd8db655fc84bc6d")); + + verifyPositions(decoder, binary( + "893b01000000000000000000000000003b40bcdab6387d829146701d8cb53daaa87b84d24b40cb24fd86da5d3f5f02b0f6f603c43c5a513418a0b2bdcaba603dbe737687cfe9082c57668eb6789d2b029a35aeac6a609558b96de5d7ad37917c902efc878ca9aff474f9d5d2417191285b8d5749bd3ffa86cc99096ce24c1f6ac350ae9adf3d5c788f80b4e3d3dc2dbb8abc1414ea1b52fdb55b2bb8af223ec528245f99d451b715e5774c5397db645d9ae441e645f8dae70230b728e81f51240868712d6f426fd694dbad8026fcf487c268939f04593ad86391cc829b1a1bdac8804ff7507544a69dc0b1b3927d7344e8a5b26fa56825283b3e476330b36d15011e1647ebd9f2ef71844ed32c0dc050457bfbd79160e6d1d8cda00a0927c8957631770e98eb20735aa46b0b18502baf4c45d2623ee51a4320cf3018010e7bbf8bc0dd79eb28e88b727ea67e980b8a91")); + + decoder = new At2000ProtocolDecoder(null); + + verifyNull(decoder, binary( + "01012f000000000000000000000000000033353734353430373136303631393637f5441a9862260117858237fe3160388490f0df7d46c09112ee087235a92101")); + + verifyPositions(decoder, binary( + "89043203000000000000000000000000d01ff1df1b56ba9185bb741ddc253f3cee093b1f8193100cd95777b5288a6f29d1b343a952f882ce8825679f7e27ad88ed7898bff92f716acadfc3c17fa8c1a6b9d0934e8f042433a183776c06c1acd73efb4b9f19030debb4dceb161fb3e6630757d25c3e995b7cf5f446318dcc1677eb215d1af49f11cd7300598bcdc40cc25466ed2391d836c782e44bc04a332e902b2b34f5597a542af4ca670cdfc18d87ce2a225c3e6f2f32359d4914c6df09aa5ee306c229260d4a56da53f93398bc8a6e77095305ee214cf605de20d3876a993fb810486f75bcd514c12442bf4dc3fbe7963b20d5100b5ecff1c1aef4c4b3736a04e245d50f538327db21d55270b279db5ac5a9658876bae3d9b5026b8975bb2bf4d100b8492760d66ae31f27bf9c525c2d794860eabca9c788b91152dbce79f336daaf6a7a9547bf1dd8e3334c891f4548fd6d112ebf45125c2a8abd3a786ebbcfdd03101b524bbf465f14a9a424305ce7de56ffca85b4657fc8c03e4349c0ca6be64d1cf595ee91f8173678ef2267dae54dd00028450c48d9b74c925af0f245d409d8773238dce5832747587f53a12155869c1d464eb0630f94cf8dceb76aa39995411d4ce7743b1501692425afec498535526067e79f568b7f71ee47d8b4929118d57b13d56cdbfd26582d579dee")); + + decoder = new At2000ProtocolDecoder(null); + + verifyNull(decoder, binary( + "01012f0000000000000000000000000000333537343534303731363035353033dd529a1eb5df9f3b6d320b38250e03306692957e8c2127d8e381a717f639b4c9")); + + verifyPositions(decoder, binary( + "89898701000000000000000000000000ae99e38f13d44f536769eb4930a6826dfebe5b98a6048941e89b17c9cdcb276be4af7c0d188d07c90d6e94aa9efcb465fe7aeaff4d85caf837483b4e9b32fbbacfbc4e175eebf57a27f552a64fc3419565d2dfbea668511a08d5a526342fad0e93b20c4449ad8defab4a9ac68cf7dad86971eb2cd96810d9d6a9c56e07fd90e4c28cfc53a069b63efe37a0523a69b607a2dc011ba17b177c5332c04be1faeeabed24539b3b790fa8a8610ab3633e0140ed79690fcae9dea43c7daad780d95a511d8f4875e621bcfe7516a03b80eb3c473ffd4bc1eda298dfa7d994a2cfeaa5d24c190d52d72fd90975a2e6f9ed3b95017133952262f91787c46839738a80c333dc53ee4d8afe75315d801efe17bc7309f30cfce64906bf70e6844c835781cbb64b49e9315ca3c2cd39d00a03cc7178a4ebc5df230dcdfd44ec588791d488f96bb6ff4007a753f552bda4d1766632aa3ec5eb38feb23ed6efb8f382a7f22b70adc9cb533c09bf749190c36d63b572c1acfc3a59138d51273835ab13c4689df01e3d2c2dd1829e00aac5c56b5d51e60d6731833f82c7464d88df663ca28a20eedeecb60f3704ae78281838caa116184e414db459768321bbfa1e83ad59fe168eb81f3b41cfe0e39c8aa78cbbe5825620bf053a1cb62e04d4cdf17ca2dc9305d47c")); + + decoder = new At2000ProtocolDecoder(null); + + verifyNull(decoder, binary( + "01012f00000000000000000000000000003335363137333036343430373439320fad981997ae8e031fe10c0ea7641903ca32c0331df467233d2a9cd886fbeef8")); + + verifyPositions(decoder, binary( + "893f0000000000000000000000000000e048b1a31deba3f5dbe8877f574877e6ed4d022b6611a10d80dfc4c0c11fa8aacf4a9de61528327e2b66843dd9c5d3a7cc9ee1d9c71a34bb482145d88b4fda3e")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java new file mode 100644 index 000000000..3a26bb7a7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java @@ -0,0 +1,39 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AtrackFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AtrackFrameDecoder decoder = new AtrackFrameDecoder(); + + verifyFrame( + binary("40502c414246342c3532362c3939312c3335363936313037353933313136352c313533343338313635362c313533343338313635392c313533343338313635392c2d38383432393138382c34343237313232352c37302c322c3230303536332c392c312c302c302c302c2c323030302c323030302c1a2c25434925434525434e25475125475325464c254d4c25564e25504425464325454c254554254344254154254d46254d5625425625434d25445425474c25474e254756254c43254d4525524c25525025534125534d255452254941254d502c302c3331303236302c31382c392c302c302c3254314b523332453238433730363138352c302c302c302c35342c383930313236303838313231353234373735392c3235322c36302c3132322c34312c3331303236303838313532343737352c302c687474703a2f2f6d6170732e676f6f676c652e636f6d2f6d6170733f713d34342e3237313232352c2d38382e343239313834201a2c3030393830303442303346343030393830303442303346343030393830303442303346333030393830303442303346343030393830303442303346343030393930303442303346343030393830303442303346343030393830303442303346343030393830303442303346343030393830303442303346331a2c3030343846463130303345381a2c302c3335363936313037353933313136352c302c3938302c31322c302c31382c35302c300d0a"), + decoder.decode(null, null, binary("40502c414246342c3532362c3939312c3335363936313037353933313136352c313533343338313635362c313533343338313635392c313533343338313635392c2d38383432393138382c34343237313232352c37302c322c3230303536332c392c312c302c302c302c2c323030302c323030302c1a2c25434925434525434e25475125475325464c254d4c25564e25504425464325454c254554254344254154254d46254d5625425625434d25445425474c25474e254756254c43254d4525524c25525025534125534d255452254941254d502c302c3331303236302c31382c392c302c302c3254314b523332453238433730363138352c302c302c302c35342c383930313236303838313231353234373735392c3235322c36302c3132322c34312c3331303236303838313532343737352c302c687474703a2f2f6d6170732e676f6f676c652e636f6d2f6d6170733f713d34342e3237313232352c2d38382e343239313834201a2c3030393830303442303346343030393830303442303346343030393830303442303346333030393830303442303346343030393830303442303346343030393930303442303346343030393830303442303346343030393830303442303346343030393830303442303346343030393830303442303346331a2c3030343846463130303345381a2c302c3335363936313037353933313136352c302c3938302c31322c302c31382c35302c300d0a"))); + + verifyFrame( + binary("40502c383732442c3731322c36353232312c3335373239383037303432363439382c313533343731353836322c313533343731353836322c313533343732363437342c2d38383531303939352c34343236303637362c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32392c31302c3331303236302c373838383637342c3134342c31360d0a313533343731353932312c313533343731353932322c313533343732363437342c2d38383531313032332c34343236303636382c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32382c31302c3331303236302c373838383637342c3134342c31360d0a313533343731353938322c313533343731353938322c313533343732363437342c2d38383531313034362c34343236303636382c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32392c392c3331303236302c373838383637342c3134342c31360d0a313533343731363034312c313533343731363034322c313533343732363437342c2d38383531313031312c34343236303636332c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32392c31302c3331303236302c373838383637342c3134342c31360d0a313533343731363130322c313533343731363130322c313533343732363437342c2d38383531303938382c34343236303637362c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32392c31302c3331303236302c373838383637342c3134352c31360d0a"), + decoder.decode(null, null, binary("40502c383732442c3731322c36353232312c3335373239383037303432363439382c313533343731353836322c313533343731353836322c313533343732363437342c2d38383531303939352c34343236303637362c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32392c31302c3331303236302c373838383637342c3134342c31360d0a313533343731353932312c313533343731353932322c313533343732363437342c2d38383531313032332c34343236303636382c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32382c31302c3331303236302c373838383637342c3134342c31360d0a313533343731353938322c313533343731353938322c313533343732363437342c2d38383531313034362c34343236303636382c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32392c392c3331303236302c373838383637342c3134342c31360d0a313533343731363034312c313533343731363034322c313533343732363437342c2d38383531313031312c34343236303636332c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32392c31302c3331303236302c373838383637342c3134342c31360d0a313533343731363130322c313533343731363130322c313533343732363437342c2d38383531303938382c34343236303637362c3137362c322c35363832372c362c312c302c302c302c2c323030302c323030302c1a2c25434925475125475325434e254345254d562553412c32392c31302c3331303236302c373838383637342c3134352c31360d0a"))); + + verifyFrame( + binary("40502c373542332c3132302c37393737392c3335383930313034383039313535342c32303138303431323134323531342c32303138303431323134323531342c32303138303431333030303635352c31363432333338392c34383137383730302c3130382c322c362e352c392c302c302c302c302c302c323030302c323030302c1a0d0a"), + decoder.decode(null, null, binary("40502c373542332c3132302c37393737392c3335383930313034383039313535342c32303138303431323134323531342c32303138303431323134323531342c32303138303431333030303635352c31363432333338392c34383137383730302c3130382c322c362e352c392c302c302c302c302c302c323030302c323030302c1a0d0a"))); + + verifyFrame( + binary("244F4B0D0A"), + decoder.decode(null, null, binary("244F4B0D0A"))); + + verifyFrame( + binary("fe0200014104d8f196820001"), + decoder.decode(null, null, binary("fe0200014104d8f196820001"))); + + verifyFrame( + binary("40501e58003301e000014104d8f19682525ecd5d525ee344525ee35effc88815026ab4d70000020000104403de01000b0000000007d007d000"), + decoder.decode(null, null, binary("40501e58003301e000014104d8f19682525ecd5d525ee344525ee35effc88815026ab4d70000020000104403de01000b0000000007d007d000"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java new file mode 100644 index 000000000..3a9382086 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java @@ -0,0 +1,99 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AtrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AtrackProtocolDecoder decoder = new AtrackProtocolDecoder(null); + + verifyPositions(decoder, buffer( + "@P,3A34,146,41431,353816057242284,20180622015809,20180622015809,20180622015809,9720689,4014230,61,2,0,20,1,0,0,0,0,2000,2000,12160,42,624,002,20009,20014,\r\n")); + + verifyPositions(decoder, buffer( + "@P,1126,121,104547,358901048091554,20180412143513,20180412143514,20180413060000,16423389,48178700,108,2,6.5,9,0,0,0,0,0,2000,2000,\r\n")); + + verifyPositions(decoder, buffer( + "@P,434E,124,104655,358901048091554,20180412143706,20180412143706,20180413060107,16423389,48178700,108,121,6.5,10,0,0,0,0,0,2000,2000,\r\n")); + + verifyPositions(decoder, binary( + "4050b5ed004a2523000310c83713f8c05a88b43e5a88b43f5a88b43f021e0ad5fffdc0a800f3020003059100080000000000000007d007d046554c533a463d3230393120743d3137204e3d3039303100")); + + verifyAttributes(decoder, buffer( + "$INFO=358683066267395,AX7,Rev.0.61 Build.1624,358683066267395,466924131626767,89886920041316267670,144,0,9,1,12,1,0\r\n")); + + decoder.setLongDate(true); + + verifyPositions(decoder, binary( + "0203b494003c00eb00014104d8dd3a3e07de011b0b1f0307de011b0b1f0307de011b0b1f0300307f28030574d30000020000000600160100020000000007d007d000")); + + decoder.setLongDate(false); + + decoder.setCustom(true); + + verifyPositions(decoder, buffer( + "@P,9493,402,143,356961075931165,1546830150,1546830151,1546830151,-88429209,44271154,54,10,0,10,1,0,0,0,1858AE010000,2000,2000,\u001A,%CI%FL%ML%VN%PD%FC%EL%ET%AT%MF%MV%BV%DT%GN%GV%ME%RL%RP%SA%SM%TR%IA%MP,0,0,2T1KR32E28C706185,0,1,0,7,251,89,118,41,0,00A5001A040800A5001A040B00A5001A040C00A5001A040900A4001C040D00A50019040900A60019040900A4001B040B00A5001A040900A7001A040E\u001A,008CFE7C03C4\u001A,356961075931165,0,0,12,0,18,5,0\n")); + + verifyPositions(decoder, buffer( + "@P,FD34,720,12256,357520076794151,1535445349,1535445354,1535500603,106784149,-6283086,105,2,138,0,3,0,0,0,,2000,2000,,%CI%TR%MV%BV%AT%SA%ET%GQ%GS%PC%RP%OD%AV1%XS%VS,0,0,0,0,0,0,0,0,1011677,0,138,0,0,0\r\n", + "1535445376,1535445374,1535500603,106783763,-6282981,105,101,138,6,2,0,0,0,,2000,2000,,%CI%TR%MV%BV%AT%SA%ET%GQ%GS%PC%RP%OD%AV1%XS%VS,0,141,41,60,12,0,0,7,1011677,0,138,0,0,0\r\n", + "1535445380,1535445378,1535500603,106783763,-6282981,105,103,138,6,2,0,0,0,,2000,2000,,%CI%TR%MV%BV%AT%SA%ET%GQ%GS%PC%RP%OD%AV1%XS%VS,0,135,41,61,12,0,0,9,1011677,0,138,0,0,0\r\n", + "1535445415,1535445415,1535500603,106783763,-6282981,105,2,138,7,2,0,0,0,,2000,2000,,%CI%TR%MV%BV%AT%SA%ET%GQ%GS%PC%RP%OD%AV1%XS%VS,0,135,41,61,12,0,21,10,1011677,0,138,0,0,0\r\n")); + + verifyPositions(decoder, buffer( + "@P,0EBB,687,1917,357298070426498,1534718280,1534718279,1534739774,-88643875,44210148,270,2,57128,6,1,130,0,0,,2000,2000,,%CI%GQ%GS%CN%CE%MV%SA,5,10,310260,7888593,137,16\r\n", + "1534718283,1534718283,1534739774,-88645243,44210145,269,2,57129,6,1,129,0,0,,2000,2000,,%CI%GQ%GS%CN%CE%MV%SA,5,10,310260,7888593,137,16\r\n", + "1534718286,1534718285,1534739774,-88646581,44210136,269,2,57130,6,1,127,0,0,,2000,2000,,%CI%GQ%GS%CN%CE%MV%SA,99,10,0,0,137,16\r\n", + "1534718289,1534718288,1534739774,-88647911,44210123,269,2,57131,6,1,127,0,0,,2000,2000,,%CI%GQ%GS%CN%CE%MV%SA,99,10,0,0,137,16\r\n", + "1534718292,1534718291,1534739774,-88649229,44210111,269,2,57132,6,1,124,0,0,,2000,2000,,%CI%GQ%GS%CN%CE%MV%SA,99,10,0,0,136,16\r\n")); + + verifyPositions(decoder, binary( + "4050b63b02c401af000144a77a21281d5b79d8ef5b79d8ef5b79d8f0fab84831029f35580056020003144d00080100130000000007d007d00025434925434525434e25475125475325464c254d4c25564e25504425464325454c254554254344254154254d46254d5625425625434d25445425474c25474e254756254c43254d4525524c25525025534125534d255452254941254d5000000000000004bbf41f0900003254314b5233324532384337303631383500000000000053005f3839303132363038383132313532343737353900000000fd078e0085002900011a2e3da1882700687474703a2f2f6d6170732e676f6f676c652e636f6d2f6d6170733f713d34332e3938383331322c2d38382e35383631383920000013ff4e04190023ff13041100a3ffdc0402009affde03fc00a4ffe3040c0093ffab03ee004dffbb04130012ff7a04180010ff6e04100037ff4d0402ffd8000c04140000000144a77a21281d0009470c00131b2b005b79d8f05b79d8f05b79d8f0fab8488e029f356f0043020003144d00080100170000000007d007d00025434925434525434e25475125475325464c254d4c25564e25504425464325454c254554254344254154254d46254d5625425625434d25445425474c25474e254756254c43254d4525524c25525025534125534d255452254941254d5000000000000004bbf41f0900003254314b5233324532384337303631383500000000000052005f3839303132363038383132313532343737353900000000fd09190085002900011a2e3da1882700687474703a2f2f6d6170732e676f6f676c652e636f6d2f6d6170733f713d34332e3938383333352c2d38382e35383630393820000013ff4e04190023ff1304110017ff0c0424000cff30041a00a4ffe3040c0093ffab03ee004dffbb04130012ff7a04180010ff6e04100037ff4d0402ffd8000c04140000000144a77a21281d0009470c00171c2b00")); + + verifyPositions(decoder, binary( + "405ad77c01670410000144a77a21281d5b74d2335b74d2335b74d233fabaf3bc02a38d3d010c0200030f8e000701001a0000000007d007d00025434925434525434e25475125475325464c254d4c25564e25504425464325454c254554254344254154254d46254d5625425625434d25445425474c25474e254756254c43254d4525524c25525025534125534d255452254941254d5000000000000004bbf41c0900003254314b523332453238433730363138350000000000004800543839303132363038383132313532343737353900000000ec06a50089002900011a2e3da1882700687474703a2f2f6d6170732e676f6f676c652e636f6d2f6d6170733f713d34342e3237323935372c2d38382e34313132303120000075ff4903fb006fff63040a004dff5d04080030ffa10407003b001304060026000503f9001e002504020078ff6204000073ff7d03f9007aff6903f3ffc0001804040000000144a77a21281d00073f0c001a182400")); + + verifyPositions(decoder, buffer( + "@P,6254,235,989,356961075931165,1534381563,1534381564,1534381564,-88429188,44271225,70,2,200563,8,1,0,0,0,,2000,2000,,%CI%CE%CN%GQ%GS%FL%ML%VN%PD%FC%EL%ET%CD%AT%MF%MV,0,310260,18,9,0,0,2T1KR32E28C706185,0,0,0,54,8901260881215247759,252,489,123")); + + verifyPositions(decoder, buffer( + "@P,27A6,663,707,356961075931165,1534211298,1534211297,1534211437,-88429190,44271135,288,2,200235,8,1,0,0,0,,2000,2000,,%CI%CE%CN%GQ%GS%FL%ML%VN%PD%FC%EL%ET%CD%AT%MF%MV,0,310260,17,9,0,0,2T1KR32E28C706185,0,0,0,80,8901260881215247759,251,59,124\r\n", + "1534211353,1534211357,1534211437,-88429190,44271135,288,2,200235,7,1,0,0,0,,2000,2000,,%CI%CE%CN%GQ%GS%FL%ML%VN%PD%FC%EL%ET%CD%AT%MF%MV,0,310260,17,2,0,0,2T1KR32E28C706185,0,0,0,79,8901260881215247759,251,60,124\r\n", + "1534211417,1534211417,1534211437,-88429190,44271135,288,2,200235,7,1,0,0,0,,2000,2000,,%CI%CE%CN%GQ%GS%FL%ML%VN%PD%FC%EL%ET%CD%AT%MF%MV,0,310260,17,2,0,0,2T1KR32E28C706185,0,0,0,78,8901260881215247759,251,56,124\r\n")); + + verifyPositions(decoder, buffer( + "@P,CA4B,122,1,358683064932578,1533633976,1533633975,1533633975,121562641,25082649,72,0,1638,15,0,0,1,0,,2000,2000,,%CI%MV%BV,143,0\r\n")); + + verifyPositions(decoder, binary( + "405025e30096eb730001452efaf6a7d6562fe4f8562fe4f7562fe52c02a006d902273f810064650000e0f5000a0100000000000007d007d000254349255341254d5625425625475125415400090083002a1a000001a8562fe4f8562fe4f7562fe52c02a006d902273f810064020000e0f5000a0100000000000007d007d000254349255341254d5625425625475125415400090083002a1a000001a8")); + + decoder.setCustom(false); + + verifyNull(decoder, binary( + "fe0200014104d8f196820001")); + + verifyPositions(decoder, binary( + "40503835003300070001441c3d8ed1c400000000000000c9000000c900000000000000000000020000000003de0100000000000007d007d000"), + position("1970-01-01 00:00:00.000", true, 0.00000, 0.00000)); + + verifyPositions(decoder, binary( + "4050993f005c000200014104d8f19682525666c252568c3c52568c63ffc8338402698885000002000009cf03de0100000000000007d007d000525666c252568c5a52568c63ffc8338402698885000002000009cf03de0100000000000007d007d000")); + + verifyPositions(decoder, binary( + "40501e58003301e000014104d8f19682525ecd5d525ee344525ee35effc88815026ab4d70000020000104403de01000b0000000007d007d000")); + + verifyPositions(decoder, binary( + "40501e58003301e000014104d8f19682525ecd5d525ee344525ee35effc88815026ab4d70000020000104403de01000b0000000007d007d000000000000000")); + + verifyAttributes(decoder, buffer( + "$OK\r\n")); + + verifyAttributes(decoder, buffer( + "$ERROR=101\r\n")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java new file mode 100644 index 000000000..aeea48967 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AuroProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AuroProtocolDecoder decoder = new AuroProtocolDecoder(null); + + verifyPosition(decoder, text( + "M0028T0000816398975I357325031465123E00001W*****110620150437000068DA#RD01DA240000000001+100408425+013756121100620152137231112240330004400")); + + verifyPosition(decoder, text( + "M0029T0000816398975I357325031465123E00001W*****110620150439000068DA#RD01DA240000000001+100407886+013755936100620152138221952123100003400")); + + verifyPosition(decoder, text( + "M0030T0000816398975I357325031465123E00001W*****110620150441000068DA#RD01DA240000000000+100408391+013756125100620152140102362238320034400")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java new file mode 100644 index 000000000..fa8f3a071 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java @@ -0,0 +1,33 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AustinNbProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AustinNbProtocolDecoder decoder = new AustinNbProtocolDecoder(null); + + verifyPosition(decoder, text( + "48666666666;2017-01-01 16:31:01;52,1133308410645;21,1000003814697;310;120;2292;1;ORANGE")); + + verifyPosition(decoder, text( + "48666666666;2017-01-01 16:55:00;52,1636123657227;21,0827789306641;0;90;4000;0;ORANGE")); + + verifyPosition(decoder, text( + "48666666666;2017-01-01 17:32:01;52,1711120605469;21,0866680145264;70;90;1199;0;ORANGE")); + + verifyPosition(decoder, text( + "48601601601;2017-01-01 16:31:01;52,1133308410645;21,1000003814697;310;360;2292;1;ORANGE")); + + verifyPosition(decoder, text( + "48601601601;2017-01-01 16:55:00;52,1636123657227;21,0827789306641;0;360;4000;0;ORANGE")); + + verifyPosition(decoder, text( + "48601601601;2017-01-01 17:32:01;52,1711120605469;21,0866680145264;70;360;1199;0;ORANGE")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java new file mode 100644 index 000000000..9e17b437f --- /dev/null +++ b/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java @@ -0,0 +1,41 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + + +public class AutoFonProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AutoFonProtocolDecoder decoder = new AutoFonProtocolDecoder(null); + + verifyNull(decoder, binary( + "10556103592310314825728F")); + + verifyPosition(decoder, binary( + "02080000251848470afa010262daa690013aa4046da83745f8812560df010001126a")); + + verifyPosition(decoder, binary( + "111E00000000000000000100007101010B0C020302010B0C0005A053FFFFFFFF02010B0C00276047FFFFFFFF1F5600FA000176F218C7850C0B0B0C203A033DBD46035783EF009E00320014FFFF45")); + + //verifyPosition(decoder, binary( + // "12060000007501010B0C00089CFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000003E7FFFF02007601010B0C00269CFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000003E7FFFF4A007601010B0C01089CFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000003E7FFFF04007501010B0C01269CFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000003E7FFFF80007601010B0C02089CFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000003E7FFFFA6007501010B0C02231F5600FA000176F218C70000000000000000000000000000000000000003E7FFFF9629")); + + verifyNull(decoder, binary( + "41035151305289931441139602662095148807")); + + verifyNull(decoder, binary( + "41032125656985547543619173484002123481")); + + verifyPosition(decoder, binary( + "023E00001E004D411EFA01772F185285009C48041F1E366C2961380F26B10B00911C"), + position("2010-01-27 04:00:08.000", true, 54.73838, 56.10343)); + + verifyPosition(decoder, binary( + "023E00001E004D411EFA01772F185285009C48041F1E366C2961380F26B10B00911C")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java new file mode 100644 index 000000000..f71fcd8eb --- /dev/null +++ b/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AutoGradeProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AutoGradeProtocolDecoder decoder = new AutoGradeProtocolDecoder(null); + + verifyPosition(decoder, text( + "(000000001637868324027912356171116A2250.7611N07556.9425E000.9024427197.36\u008eA0000B0000C0000D0000E0000K0000L0000M0000N0000O0000)")); + + verifyPosition(decoder, text( + "(000000007322865733022629240170415A1001.1971N07618.1375E0.000145312128.59?A0024B0024C0000D0000E0000K0000L0000M0000N0000O0000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java new file mode 100644 index 000000000..5daafcc40 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AutoTrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AutoTrackProtocolDecoder decoder = new AutoTrackProtocolDecoder(null); + + verifyNull(decoder, binary( + "f1f1f1f1330c00201007090006de7200000000daa3")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java new file mode 100644 index 000000000..d3be0b6d6 --- /dev/null +++ b/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class AvemaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + AvemaProtocolDecoder decoder = new AvemaProtocolDecoder(null); + + verifyNull(decoder, text( + "8,20180927150956,19.154864,49.124862,7,56,0,12,3,0.0,0,0.02,14.01,0,0,26,0,219-2,65534,10255884,0.01")); + + verifyPosition(decoder, text( + "1130048939,20120224000129,121.447487,25.168025,0,0,0,0,3,0.0,1,0.02V,14.88V,0,1,24,4,46608,F8BC,F9AD,CID0000028")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java new file mode 100644 index 000000000..0972e3fd4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + + +public class Avl301ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Avl301ProtocolDecoder decoder = new Avl301ProtocolDecoder(null); + + verifyNull(decoder, binary( + "244c0f086058500087335500010d0a")); + + verifyNull(decoder, binary( + "24480d1001c3065c0d00010d0a")); + + verifyPosition(decoder, binary( + "24242c0f041710001d0e060146944904ff4ac40000148f0651044b001a081001be06590daa00000108a30d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java new file mode 100644 index 000000000..400ba7e12 --- /dev/null +++ b/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java @@ -0,0 +1,39 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class BceProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + BceProtocolDecoder decoder = new BceProtocolDecoder(null); + + verifyNull(decoder, binary( + "3ab90b71bc1503000300c10bff11")); + + verifyPositions(decoder, binary( + "789622d1cb1303003401a53365b70f4a9babc0ffd700c04400f0b6c741e63933428f1c431c015468de43f18221341b007e0ae20001430a698f003f008d000000000031f85900000000f0831c018400000000000000000000000000000000000209000000000000000000000000000000030065f70f4a9babc0ffd700c0440069bcc741e73733427f1c431a01a9378343f1829c391b00a80be2000170056da7003e007c000000000031c04e00000000f0831c01810000000000000000000000000000000000060100000000000000000000000000000003006537104a9babc0ffd700c0440051c1c74129363342721c421801e4809543f18210341b00710ae2000170056da7003e0072000000000031c04800000000b8841c017e00000000000000000000000000000000000306000000000000000000000000000000030069")); + + verifyPositions(decoder, binary( + "be76619c834601004200a0003fd769c568ffc3db0079161d420683a9414918b1150000000000d102660167040000000000009f06357f0000a401042ea415e10232000000000000000000000051")); + + verifyPositions(decoder, binary( + "be76619c834601004200a0003ff76cc568ffc3db00bd151d423c8ca9410a18af150000000000d1023a0160040000000000009f06427f0000a401042ea416e1003e00000000000000000000009a")); + + verifyPositions(decoder, binary( + "be76619c834601004202a5863f57f8b868ffc3db0001712642b70b9d41221946200246d23342d1023e016404000000000000a0065a7f0000a4010496f277e3064300000000000000000000003f97f8b868ffc3db0074712642ae0a9d412919452102fff19042d102a4026304000000000000a006487f0000a4010496f277e3064300000000000000000000003fb7f8b868ffc3db00c6712642000a9d413019442002a6074542d102300165040000000000009f064f7f0000a4010496f277e3064300000000000000000000003fd7f8b868ffc3db002872264245099d413518421f02bea35e42d1021e0164040000000000009f06377f0000a4010496f277e3064300000000000000000000003fe7f8b868ffc3db0061722642e3089d413a28421f02a05ff641d102580163040000000000009f06577f0000a4010496f277e3064300000000000000000000003f17f9b868ffc3db0021732642a3079d414119411d02d69fcc42d102440165040000000000009f06437f0000a4010496f277e3064300000000000000000000003f37f9b868ffc3db00ae732642b4069d414628421b02e0629742d1024c0167040000000000009f06557f0000a4010496f277e3064300000000000000000000003f57f9b868ffc3db0044742642ae059d414c28421a027540a342d102860163040000000000009f065b7f0000a4010496f277e3064300000000000000000000003f97f9b868ffc3db007275264256039d4153284417029e1f2f43d1024a016704000000000000a0064e7f0000a4010496f277e306430000000000000000000000db")); + + verifyPositions(decoder, binary( + "2d41abfa2e4501004e02a5a0068609f96a009106260af96a00a006260af96a009106960af96a00a306a60af96a008f06b60af96a009106960cf96a00a03e0715f96affc300804000e6a23a4230ccc441001f47850200000000a0000000bd6542651a110d004b1000000000a401045a56bf4d02480000000000000000061623f96a00a0062623f96a00913ea728f96affc300804000e6a23a4230ccc441001f7f850200000000a0000000bd6542651a110d004a1000000000a401045a56bf4d02480000000000000000069639f96a00a006a639f96a00913e373cf96affc300804000e6a23a4230ccc441001f7f850200000000a0000000ad6534651a110d004a1000000000a401045a56bf4d024800000000000000003ed74ff96affc300804000e6a23a4230ccc441001f7f850200000000a0000000ad6534651a111b004a1000000000a401045a56bf4d01480000000000000000061650f96a00a0062650f96a00913e6763f96affc300804000e6a23a4230ccc441001f7f850200000000a0000000ad6534651a110d004a1000000000a401045a56bf4d01480000000000000000069666f96a00a006a666f96a00913e0777f96affc300804000e6a23a4230ccc441001f7f850200000000a0000000ad6534651a110d004a1000000000a401045a56bf4d0148000000000000000006067df96a00a006167df96a0091063687f96a00a3064687f96a008f065687f96a0091063689f96a00a03e978af96affc300804000e6a23a4230ccc441001f87850200000000a0000000ad6527651a110d004a1000000000a401045a56bf4d024800000000000000000e")); + + verifyPositions(decoder, binary( + "be76619c834601003302a5e8327764726bff432fc52a420e2c93410028afd2070000000080024a0005040000000000008e06547f0000a401043cf21f390e54328764726bff432fc52a420e2c93410028afd2070000000080024c0005040000000000008e064f7f0000a401043cf21f390e54329764726bff432fc52a420e2c93410028afd2070000000080024e0002040000000000008d064f7f0000a401043cf21f390e5432a764726bff432fc52a420e2c93410028afd2070000000080024e0004040000000000008e06587f0000a401043cf21f390e5432b764726bff432fc52a420e2c93410028afd207000000008002460005040000000000008e06557f0000a401043cf21f390e5432c764726bff432fc52a420e2c93410028afd2070000000080024e0004040000000000008e06347f0000a401043cf21f390e5432d764726bff432fc52a420e2c93410028afd2070000000080024e0002040000000000008e06547f0000a401043cf21f390e5432e764726bff432fc52a420e2c93410028afd207000000008002540002040000000000008e06477f0000a401043cf21f390e5432f764726bff432fc52a420e2c93410028afd207000000008002540004040000000000008d064f7f0000a401043cf21f390e54320765726bff432fc52a420e2c93410028afd207000000008002540004040000000000008e064d7f0000a401043cf21f390e54321765726bff432fc52a420e2c93410028afd207000000008002540004040000000000008e06467f0000a401043cf21f390e544200a0003f3743c96bffc3db0060c81c42d885ab41002aaf060000000000d102380167040000000000008a064f7f0000a4010412a46b330033000000000000000000000025")); + + verifyPositions(decoder, binary( + "ca07629c834601002702a58f3c278ff96a0bc000a0c00140bc3a42508bc541002a70a905000000009000c101a40103d904440e003000000000000000000000000000000000000001013c878ff96a0bc000a0c00140bc3a42508bc541002970a905000000009000c301a40103d904440e003000000000000000000000000000000000000001013cb7d2f96a0bc000a0c00124bc3a426b8fc5410428000404000000009000c401a40103d904440e003500000000000000000000000000000000000001013cc7d2f96a0bc000a0c00124bc3a426b8fc5410428000404000000009000c301a40103d904440e003500000000000000000000000000000000000001013cd7f2f96a0bc000a0c00114bc3a42a48fc5410029027e03000000009000c301a40103d904440e003000000000000000000000000000000000000001013c670dfa6a0bc000a0c001f1bb3a42418dc541002a484904000000009000c001a40103d904440e003a00000000000000000000000000000000000001013c770dfa6a0bc000a0c001f1bb3a42418dc5410028484904000000009000bf01a40103d904440e003a00000000000000000000000000000000000001013c470efa6a0bc000a0c001f1bb3a42418dc5410029484904000000009000bf01a40103d904440e003a00000000000000000000000000000000000001013c5711fa6a0bc000a0c001f1bb3a42418dc5410029484904000000009000c101a40103d904440e003000000000000000000000000000000000000001013f00a0003cc795866b0bc000a0c00144bc3a423a90c541003697cb03000000008000cf01a40103d9040d0f0030000000000000000000000000000000000000010100")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java new file mode 100644 index 000000000..bdcc1f9e8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class BceProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + BceProtocolEncoder encoder = new BceProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_OUTPUT_CONTROL); + command.set(Command.KEY_INDEX, 1); + command.set(Command.KEY_DATA, "1"); + + verifyCommand(encoder, command, binary("79df0d86487000000600410aff00550048")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java new file mode 100644 index 000000000..9a24ece1f --- /dev/null +++ b/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class BlackKiteProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + BlackKiteProtocolDecoder decoder = new BlackKiteProtocolDecoder(null); + + verifyNull(decoder, binary( + "01150003313131313131313131313131313131209836055605BA")); + + verifyPositions(decoder, binary( + "0136000331313131313131313131313131313120523905563000010000000100000033000000003400004000004500004600005000005100009F76")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java new file mode 100644 index 000000000..d661a10f2 --- /dev/null +++ b/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java @@ -0,0 +1,67 @@ +package org.traccar.protocol; + + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class BoxProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + BoxProtocolDecoder decoder = new BoxProtocolDecoder(null); + + verifyNull(decoder, text( + "H,BT,358281002435893,081028142432,F5813D19,6D6E6DC2")); + + verifyNull(decoder, text( + "H,BT,N878123,080415081234,D63E6DD9,6D6E6DC2,8944100300825505377")); + + verifyPosition(decoder, text( + "L,190227043304,G,25.68773,48.59788,71,53,261.42,1,23;A,0.03;D,0.06;I,0")); + + verifyPosition(decoder, text( + "L,081028142429,G,52.51084,-1.70849,0,170,0,1,0")); + + verifyPosition(decoder, text( + "L,081028142432,G,52.51081,-1.70849,0,203,0,16,0")); + + verifyNull(decoder, text( + "L,080528112501,AI1,145.56")); + + verifyNull(decoder, text( + "E,1")); + + verifyPosition(decoder, text( + "L,150728150130,G,24.68312,46.67526,0,140,0,3,20;A,0;D,0;I,0")); + + verifyPosition(decoder, text( + "L,150728155815,G,24.68311,46.67528,0,140,0,6,21;A,0;D,0;I,0")); + + verifyPosition(decoder, text( + "L,150728155833,G,24.68311,46.67528,11,140,0,52,23;A,0.79;D,0;I,0")); + + verifyPosition(decoder, text( + "L,150728155934,G,24.68396,46.67489,0,282,0.12,1,21;A,1.27;D,1.23;I,0")); + + verifyPosition(decoder, text( + "L,150728160033,G,24.68414,46.67485,0,282,0.12,1,21;A,0;D,0;I,0")); + + verifyPosition(decoder, text( + "L,150728160133,G,24.68388,46.675,0,282,0.12,1,21;A,0;D,0;I,0")); + + verifyPosition(decoder, text( + "L,150728160233,G,24.68377,46.67501,0,282,0.12,1,21;A,0;D,0;I,0")); + + verifyPosition(decoder, text( + "L,150728160333,G,24.684,46.67488,0,282,0.12,1,21;A,0;D,0;I,0")); + + verifyPosition(decoder, text( + "L,150728155855,G,24.68413,46.67482,0,282,0.14,53,21;A,0;D,0;I,0")); + + verifyPosition(decoder, text( + "L,150728160400,G,24.68413,46.67482,0,282,0.14,7,20;A,0;D,0;I,0;END,25,326,150728155814")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java new file mode 100644 index 000000000..9f841fb8c --- /dev/null +++ b/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class C2stekProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + C2stekProtocolDecoder decoder = new C2stekProtocolDecoder(null); + + verifyNull(decoder, text( + "PA$863083038046613$D#181123#162850#1#+37.92684#+23.75933#0.62#200.1#0.0#3768#000#9#00#sz-w1001#B0907839$AP")); + + verifyPosition(decoder, text( + "PA$353990030327618$D#091117#020928#1#22.537222#114.020948#0.00#0.0#42.1#4183#011#1#101#Wsz-wl001#B0101940#C+3.0,-5.0,+2.0$AP")); + + verifyNull(decoder, text( + "PA$863083030602124$20$AP")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java new file mode 100644 index 000000000..5ed3f5dc8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java @@ -0,0 +1,54 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CalAmpProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CalAmpProtocolDecoder decoder = new CalAmpProtocolDecoder(null); + + verifyPosition(decoder, binary( + "83051633033459010101028afd59ae7c1459ae7c140b06bbce2c01520e0000d916000001b900450900005affa50f091f00260d040000000f24000001b90000000000003714")); + + verifyPosition(decoder, binary( + "83092701131797081078220107010200dc583d4d3f583d4d3f19c70502cd1d512d00005f180000008500ec0800101eff980f090100313102000000000000000000")); + + verifyPosition(decoder, binary( + "8305133303910501010102004557E5AB2457E3B3E01FD828DBFE9E3465000028C90000004201310704001EFFA12F0B22081BCA05000000000000000F87000E8E2F00EA029E0000082D")); + + verifyPosition(decoder, binary( + "8305313301481601010102045557ea2eba57ea2eba1ebf06db005f2e5e0000220c00000000000006200000ff8f000a00000bca06000000000000000f1b000f35ef00ea02900000087000000060")); + + verifyPosition(decoder, binary( + "8305454205067001010102008157a9bddc57a96aaa17cdb98fccc1a457000056ac00000000000007250000ff8f000e00082711570000000000ffff101b00003148000010680000000000000000000000050000000000000000000005b0000000000000289600000000000000000000069b00000000000008e400000000000000000000000000000003000000010000070f")); + + verifyPosition(decoder, binary( + "83052132052924010101020001575c590300000000000000000000000000000000000000000000002c0000ff8f0000030801010000")); + + verifyPosition(decoder, binary( + "830543321494860101010a0080560b5a5e0eadd0291becf3c500f005090f1f3305000003010040c0a600000000000000008b12a102")); + + verifyPosition(decoder, binary( + "830543321494860101010a0c215608b6680ead5ada1bed88d300000049801f000500000300003cf33200000000000000008b0ce101")); + + verifyNull(decoder, binary( + "830545321041830101010300010000333862000023c301000000004532104183ffffff353816051610691f420040163953294fffffffffffffffff8996604211639032949f4f54413a317c303b302c317c343b302c34004f5441535441543a302c302c302c302c302c222200564255533a342c322e302e302c343533323130343138332c5630312e30332e30312e34302c5630312e30332e30312e33312c2c0056494e2d494e464f3a56494e3d31464d5a5537324539355a4137303032362c4445562d5245474e3d55532c535256522d5245474e3d555300")); + + verifyPosition(decoder, binary( + "8308353301059723580f01020102088952d994c352d994c4134fa767c4c482e20000c12700000d29006e1002019affc90f061d00060c0000")); + + verifyPosition(decoder, binary( + "8308355233050116134f01020102445652d993e152d993e1124c728cc68f0647000023c00000000000000e02019affc90f071c0015020000")); + + verifyPosition(decoder, binary( + "830545420185450101010200075517fb335516c5c40fb1aea4cf4cbf250000000000000000008900260015ffb10f001108110a0000")); + + verifyPosition(decoder, binary( + "830543321494750101010A00085492798A0EC4F9E71BDA3B81005600040F1F33050000030000000076000000000000000000000000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java new file mode 100644 index 000000000..c8db07ee3 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java @@ -0,0 +1,32 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CarTrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CarTrackProtocolDecoder decoder = new CarTrackProtocolDecoder(null); + + verifyNull(decoder, text( + "$$020040????????&A0000")); + + verifyPosition(decoder, text( + "$$020040????????&A9955&B011939.000,A,4436.3804,N,02606.9434,E,0.00,0.00,190317,,,A*64|0.9|&C0100000000&D01830=?6&E00000001&Y00000000")); + + verifyPosition(decoder, text( + "$$2222234???????&A9955&B102904.000,A,2233.0655,N,11404.9440,E,0.00,,030109,,*17|6.3|&C0100000100&D000024?>&E10000000"), + position("2009-01-03 10:29:04.000", true, 22.55109, 114.08240)); + + verifyPosition(decoder, text( + "$$2222234???????&A9955&B102904.000,A,2233.0655,N,11404.9440,E,0.00,,030109,,*17|6.3|&C0100000100&D000024?>&E10000000&Y00100020")); + + verifyPosition(decoder, text( + "$$2222234???????&A9955&B102904.000,A,2233.0655,N,11404.9440,E,0.00,,030109,,*17|6.3|&C0100000100&D000024?>&E10000000")); + + + } + +} diff --git a/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java new file mode 100644 index 000000000..412901d90 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java @@ -0,0 +1,46 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CarscopProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CarscopProtocolDecoder decoder = new CarscopProtocolDecoder(null); + + verifyNull(decoder, text( + "*170821223045UB00HSO")); + + verifyPosition(decoder, text( + "*170821223121UB05ORANGE000731512061825V0000.0000N00000.0000E000.0040331309.62")); + + verifyPosition(decoder, text( + "*170724163029UB05ORANGE000000010061825V0000.0000N00000.0000E000.0040331309.62")); + + verifyNull(decoder, text( + "*160618233129UB00HSO")); + + verifyNull(decoder, text( + "*160618232614UD00232614A5009.1747N01910.3829E0.000160618298.2811000000L000000")); + + verifyNull(decoder, text( + "*160618232529UB05CW9999C00000538232529A5009.1747N01910.3829E0.000160618298.2811000000L000000")); + + verifyPosition(decoder, text( + "*040331141830UB05123456789012345061825A2934.0133N10627.2544E000.0040331309.6200000000L000000"), + position("2004-03-31 06:18:25.000", true, 29.56689, 106.45424)); + + verifyPosition(decoder, text( + "*040331141830UB04999999984061825A2934.0133N10627.2544E000.0040331309.6200000000L000000")); + + verifyPosition(decoder, text( + "*040331141830UA012Hi-jack061825A2934.0133N10627.2544E000.0040331309.6200000000L000000")); + + verifyPosition(decoder, text( + "*150817160254UB05CC8011400042499160254A2106.8799S14910.2583E000.0150817158.3511111111L000000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java new file mode 100644 index 000000000..27f503b34 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java @@ -0,0 +1,144 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CastelProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CastelProtocolDecoder decoder = new CastelProtocolDecoder(null); + + verifyAttributes(decoder, binary( + "40403a00043231335750323031373030363135360000000000a00200000100000101201100344a474446364545374a4230373632363056ff0d0a")); + + verifyAttributes(decoder, binary( + "4040560004323133474c3230313630303033363400000000004002a122a05a5423a05abe0f2a000000000007f1f90014000000040001640011170003001e000505210b210c210d210f2101062b58ef02001a25950d0a")); + + verifyAttributes(decoder, binary( + "404057000431303031313132353239393837000000000000004002C1F06952F0F169529C9111000000000069830000470000000400036401014C01030078000505210C210D210F21102101073BE8030064280AEB930D0A")); + + verifyPosition(decoder, binary( + "40405f000536303331353030303335313200000000000000004001040212102a2f72b29302a0af8512b40787018e000000000043e4ae000000007ca0f7224d5049503632305f56312e312e30004d5049502d3632302056322e300072140d0a")); + + verifyPosition(decoder, binary( + "24245000363137313135313243333133360000000000000040011b011207133ac49a390464514a15000000008e480c00000917000000000000ffafffaf00010000ffff7800ffffffffffffff003c0d0a")); + + verifyPositions(decoder, binary( + "40408200033231334c32303137303031313039000000000000100136477b5964477b590400000000000000dc410f000000000204000709207910008304011c07110e110dd41a160714a95a0f00001e058c4944442d3231334c2056312e312e3120323031372d30352d3038004944442d3231334c2056312e312e300000006da10d0a")); + + verifyPositions(decoder, binary( + "40408200033231334c323031373030303131370000000000001001000c6759a10d67590a9e1200000000000e3e0000000000020000000e4e791c000004010d0711060515083017086cd1181f000040067d4944442d3231334c2056312e312e3120323031372d30352d3038004944442d3231334c2056312e312e3000000066e30d0a")); + + verifyAttributes(decoder, binary( + "404043000432313345503230313630303035383500000000004006a2021d5810031d58ae940400da050000f6040000070000000400076401680000000001001bd20d0a")); + + verifyNull(decoder, binary( + "4040d0000432313345503230313630303035383500000000001001831c1c58b1fc1c58ae94040012220000f60400005800000000000763016800008484004944445f3231335730315f532056312e302e37004944445f3231335730315f482056312e302e370032000110021003100410051006100710081009100a100b100c100d100e1011100111021103110411051106110711011202120312041201130213031301160216011701180218011b011c011d011e011f021f031f041f051f061f071f0121022101260127012861780d0a")); + + verifyNull(decoder, binary( + "404029000432313345503230313630303035383500000000009001ffffffff0000b4fc1c582b6e0d0a")); + + verifyPositions(decoder, binary( + "40406000043231334550323031363030303538350000000000400708000000831c1c58f4fb1c58ae94040012220000f604000058000000200007630168000084c401040b10090c3532db3f07f07f7520090100000101010e00000000c7920d0a")); + + verifyNull(decoder, binary( + "404042000432313345503230313630303035383500000000001002831c1c58b7fc1c58ae94040012220000f604000058000000000007630168000084840072a20d0a")); + + verifyNull(decoder, binary( + "4040d0000432313345503230313630303035383500000000001001831c1c5805fe1c58ae94040012220000f60400005800000000000763016800008484004944445f3231335730315f532056312e302e37004944445f3231335730315f482056312e302e370032000110021003100410051006100710081009100a100b100c100d100e1011100111021103110411051106110711011202120312041201130213031301160216011701180218011b011c011d011e011f021f031f041f051f061f071f012102210126012701284eb10d0a")); + + verifyAttributes(decoder, binary( + "40405700043231334e583230313630303131373700000000004002c458ce572159ce57a9e2020082030000500c00000f0000000400036401240e0403023c000505210c210d210f21102101075b14030121330269430d0a")); + + verifyNull(decoder, binary( + "40407800043231334e583230313630303131373700000000004004fa52ce574b53ce57cad1020041020000050c00000d0000000400036401240b0503001b042105210c210d210f211021112113211c211f212121232124212c212d213021312133213e2141214221452149214a214c214f215021384e0d0a")); + + verifyAttributes(decoder, binary( + "4040a600043231334e583230313630303131373700000000004005fa52ce575053ce57cad102006b020000050c00000d0000000400036401240b050300001b042105210c210d210f211021112113211c211f212121232124212c212d213021312133213e2141214221452149214a214c214f215021015bd604301f500600000653000000bc0bffff78250000ff2d98642401000f8080e038000f0f0000000000000077b10d0a")); + + verifyAttributes(decoder, binary( + "40404300043231334e583230313630303131373700000000004006fa52ce574e53ce57cad1020053020000050c00000d0000000400036401240b0503000000feec0d0a")); + + verifyPosition(decoder, binary( + "40403600043231334e583230313630303033343600000000004009ad31a457050810061a35b29bf80ae6da83180300320bbe32580d0a40403600043231334e583230313630303033343600000000004009ad31a457050810061a35b29bf80ae6da83180300320bbe32580d0a")); + + verifyNull(decoder, binary( + "4040d400043535333133350000000000000000000000000000100196d499574bd899570000000000000000010000000000000000000000002410000000004944445f3231334730325f532056322e332e345f4e004944445f3231334730325f482056322e332e345f4e0032000110021003100410051006100710081009100a100b100c100d100e1011100111021103110411051106110711011202120312041201130213031301160216011701180218011b011c011d011e011f021f031f041f051f061f071f012102210126012701285b410d0a")); + + verifyPosition(decoder, binary( + "24243f00676e6768656636313031313132393030313734002001840d0000d2deb556020602100b35360456cf09e6ebac0200000000030000000001abc10d0a")); + + verifyPosition(decoder, binary( + "24243f00676e6768656636313031313132393030313734002001840d000000dfb556020602100b36298256cf0956ebac020000990c7f0000000001b4830d0a")); + + verifyPositions(decoder, binary( + "4040590004313030303030303030303800000000000000000040010072f53f56c25240560000000078b00900000000009c3100000000030100011900030001090b0f080106c04fe40b4037310c0060e001ff018d01e05e0d0a")); + + verifyPositions(decoder, binary( + "40405900043231334e5832303135303030303336000000000040010073dd735600df7356b9220000270b000000000000000000000400000000240e03000201120c0f0a19050c1e5808ca35530dd902540d9c010000e5300d0a")); + + verifyPositions(decoder, binary( + "404055000431303031313132353239393837000000000000001002C1F0695230086A529C911100000000000F890000A60500000000036301014CFF000001190A0D0539191480D60488C5721800000000BF8A640D0A")); + + verifyPositions(decoder, binary( + "40406000043130303131313235323939383700000000000000400705000000C1F0695249F469529C9111000000000069830000D80040000400036401014C04030001190A0D04201E1480D60488C5721800000000AF0101060F000F00EA1E0D0A")); + + verifyAttributes(decoder, binary( + "404057000431303031313132353239393837000000000000004002C1F06952F0F169529C9111000000000069830000470000000400036401014C01030078000505210C210D210F21102101073BE8030064280AEB930D0A")); + + verifyPositions(decoder, binary( + "40405900043130303131313235323939383700000000000000400101C1F06952E7F069529C9111000000000069830000070000000400036401014C00030001190A0D0412041480D60488C57218000000009F01E803ED9A0D0A")); + + verifyAttributes(decoder, binary( + "4040B9000431303031313132353239393837000000000000004005C1F069521BF169529C9111000000000069830000130000000400036401014C0003000022032104210521062107210C210D210E210F2110211121132115211C211F21212124212E212F2130213121322133213C214221432144214521472149214A214C214D214E210100643B6232E803003E64280A3C24FE00010E010F00D5805A483C640000000000010000E02E000000066400000500000000A7710D0A")); + + verifyAttributes(decoder, binary( + "404043000431303031313132353239393837000000000000004006C1F0695209F169529C91110000000000698300000D0000000400036401014C00030000009AF40D0A")); + + verifyNull(decoder, binary( + "404086000431303031313132353239393837000000000000004004C1F0695200F169529C91110000000000698300000D0000000400036401014C00030022032104210521062107210C210D210E210F2110211121132115211C211F21212124212E212F2130213121322133213C214221432144214521472149214A214C214D214E219AE90D0A")); + + verifyPositions(decoder, binary( + "40407F000431303031313132353239393837000000000000001001C1F06952FDF069529C91110000000000698300000C0000000000036401014C00030001190A0D04121A1480D60488C5721800000000AF4944445F3231364730325F532056312E322E31004944445F3231364730325F482056312E322E31000000DF640D0A")); + + verifyPositions(decoder, binary( + "404044000c3631313135303030303935360000000000000000420600011e0a0f0b1312864fcd08c07a13030100640acf000004000a000000000000007ba083a66ad80d0a")); + + verifyPosition(decoder, binary( + "40405c000c363131313530303030393536000000000000000040011c0a0f0e362dca53cd0860831303000000000300000000ff000000000000007ba083a650542d3639305f56312e312e320050542d3639302056312e32008a020d0a")); + + verifyAttributes(decoder, binary( + "4040450004323132474c31313433303035303033000000000040082ca89b55a6a99b555c57000000000000c40200000b0000001400036401111f000302f5533bd653f10d0a")); + + verifyNull(decoder, binary( + "40404d0004323132474c3131343330303530303300000000004007120000002ca89b55cba99b555c57000000000000c40200000b0000000000036401111f000102000101170000000068850d0a")); + + verifyNull(decoder, binary( + "4040420004323132474c31313433303035303033000000000010022ca89b55cca99b555c57000000000000cf0200000b0000000000036401111f0000020013be0d0a")); + + verifyAttributes(decoder, binary( + "4040870004323132474c31313433303035303033000000000040052ca89b55e3a89b555c57000000000000c4020000040000001400036401111f0003000012042105210b210c210d210f211021112113211c2121212321242133213421422146214f212b50663603003ce9030dff060000600dffffc25865ffff9e02b43624000000003cbc0d0a")); + + verifyNull(decoder, binary( + "4040d00004323132474c31313433303035303033000000000010013ec09b5596c29b555c57000000000000de0200000f0000000000036401111f000000004944445f3231334730325f532056322e322e36004944445f3231334730325f482056322e322e360032000110021003100410051006100710081009100a100b100c100d100e1011100111021103110411051106110711011202120312041201130213031301160216011701180218011b011c011d011e011f021f031f041f051f061f071f012102210126012701288a690d0a")); + + verifyNull(decoder, binary( + "40404d0004323132474c3131343330303530303300000000004007050000003ec09b5564c29b555c57000000000000de0200000f0000002000036401111f0000020001010e00000000237e0d0a")); + + verifyNull(decoder, binary( + "40401F00043130303131313235323939383700000000000000100303320D0A")); + + verifyPositions(decoder, binary( + "40407F000431303031313132353239393837000000000000001001C1F06952FDF069529C91110000000000698300000C0000000000036401014C00030001190A0D04121A1480D60488C5721800000000AF4944445F3231364730325F532056312E322E31004944445F3231364730325F482056312E322E31000000DF640D0A")); + + verifyPositions(decoder, binary( + "40405900043130303131313235323939383700000000000000400101C1F06952E7F069529C9111000000000069830000070000000400036401014C00030001190A0D0412041480D60488C57218000000009F01E803ED9A0D0A")); + + verifyPositions(decoder, binary( + "40405900043335343034333035303834343134330000000000400100f61a7355c11b7355710000000b00000000000000000000000400000000240e0200020106060f100b2d5a78a7076ec0fb1d00008c065f010000ac220d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java new file mode 100644 index 000000000..bcb93a010 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class CastelProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + CastelProtocolEncoder encoder = new CastelProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + verifyCommand(encoder, command, binary("40402000013132333435363738393031323334350000000000458301a94a0d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java new file mode 100644 index 000000000..28236c87f --- /dev/null +++ b/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CautelaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CautelaProtocolDecoder decoder = new CautelaProtocolDecoder(null); + + verifyPosition(decoder, text( + "20,010907000000,14,02,18,16.816667,96.166667,1325,S,*2E")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java new file mode 100644 index 000000000..769760fa5 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java @@ -0,0 +1,33 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CellocatorProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CellocatorProtocolDecoder decoder = new CellocatorProtocolDecoder(null); + + verifyPosition(decoder, binary( + "4d4350470041420f000402021226d8a70221d801010000000001000000000000000000000000c4d90000000ca7a741ff0096dd15a40700000000000000001619130c01e307e4")); + + verifyPosition(decoder, binary( + "4D434750008AD01500080103011804000000460020000000005E750000000000000000000000C34300040204DA4DA30367195703E803000000000000000001030F0802E10778")); + + verifyPosition(decoder, binary( + "4D434750008AD01500080102011804000000360060000000005E750000000000000000000000C24300040204DA4DA30367195703E80300000000000000003B020F0802E107DF")); + + verifyPosition(decoder, binary( + "4D4347500006000000081A02021204000000210062300000006B00E100000000000000000000E5A100040206614EA303181A57034E1200000000000000001525071403D60749")); + + verifyPosition(decoder, binary( + "4d434750000101000008011f041804000000200100000000005e750000000000000000000000548500040204da4da30367195703e80300000000000000002014151007dd07f7")); + + verifyPosition(decoder, binary( + "4d434750005e930100080102041804000000200f20000000005e7500000000000000000000005af400040204da4da30367195703e8030000000000000000021a111e08dd0760")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java new file mode 100644 index 000000000..89850fb5f --- /dev/null +++ b/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java @@ -0,0 +1,26 @@ +package org.traccar.protocol; + +import org.junit.Ignore; +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class CellocatorProtocolEncoderTest extends ProtocolTest { + + @Ignore + @Test + public void testEncode() throws Exception { + + CellocatorProtocolEncoder encoder = new CellocatorProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_OUTPUT_CONTROL); + command.set(Command.KEY_INDEX, 0); + command.set(Command.KEY_DATA, "1"); + + verifyCommand(encoder, command, binary("4D434750000000000000000000000303101000000000000026")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java new file mode 100644 index 000000000..a386b6b47 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java @@ -0,0 +1,78 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CguardProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CguardProtocolDecoder decoder = new CguardProtocolDecoder(null); + + verifyNull(decoder, text( + "IDRO:354868050655283")); + + verifyPosition(decoder, text( + "NV:190225 144543:55.776505:37.729000:0:10:0:0")); + + verifyAttributes(decoder, text( + "BC:190225 144543:CSQ1:64:NSQ1:0:NSQ2:1:BAT1:100")); + + verifyAttributes(decoder, text( + "BC:190225 142653:CSQ1:80:NSQ1:0:NSQ2:1:BAT1:3.53")); + + verifyPosition(decoder, text( + "NV:170409 031456:56.808553:60.595476:0:NAN:0")); + + verifyAttributes(decoder, text( + "BC:170409 031456:CSQ1:64:NSQ1:17:PWR1:0")); + + verifyPosition(decoder, text( + "NV:161007 122043:55.812730:37.733689:3.62:NAN:244.05:143.4")); + + verifyPosition(decoder, text( + "NV:161007 122044:55.812732:37.733670:3.97:NAN:260.95:143.9")); + + verifyAttributes(decoder, text( + "BC:161007 122044:CSQ1:77:NSQ1:18:BAT1:100")); + + verifyPosition(decoder, text( + "NV:160711 044023:54.342907:48.582590:0:NAN:0:110.1")); + + verifyPosition(decoder, text( + "NV:160711 044023:54.342907:-148.582590:0:NAN:0:110.1")); + + verifyAttributes(decoder, text( + "BC:160711 044023:CSQ1:48:NSQ1:7:NSQ2:1:BAT1:98:PWR1:11.7:CLG1:NAN")); + + verifyAttributes(decoder, text( + "BC:160711 044524:CSQ1:61:NSQ1:18:BAT1:98:PWR1:11.7:CLG1:NAN")); + + verifyNull(decoder, text( + "VERSION:3.3")); + + verifyPosition(decoder, text( + "NV:160420 101902:55.799425:37.674033:0.94:NAN:213.59:156.6")); + + verifyAttributes(decoder, text( + "BC:160628 081024:CSQ1:32:NSQ1:10:BAT1:100")); + + verifyAttributes(decoder, text( + "BC:160628 081033:NSQ2:0")); + + verifyPosition(decoder, text( + "NV:160630 151537:55.799913:37.674267:0.7:NAN:10.21:174.9")); + + verifyAttributes(decoder, text( + "BC:160630 153316:BAT1:76")); + + verifyAttributes(decoder, text( + "BC:160630 153543:NSQ2:0")); + + verifyNull(decoder, text( + "PING")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java new file mode 100644 index 000000000..146e13ae8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java @@ -0,0 +1,41 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + + +public class CityeasyProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CityeasyProtocolDecoder decoder = new CityeasyProtocolDecoder(null); + + verifyNotNull(decoder, binary( + "545400853575570249020100033b3430342c34352c31303638312c31313632312c33352c31303638312c31313632322c32332c31303638312c32383938332c32332c31303638312c31313632332c32312c31303638312c32333338312c31372c31303638312c32323538332c31372c31303638312c32363434312c31330000000d352e0d0a")); + + verifyNull(decoder, binary( + "54540019357557024902010002520704100000000bbe700d0a")); + + verifyNull(decoder, binary( + "5454001735755702490201434a01000000000c24280d0a")); + + verifyNull(decoder, binary( + "545400153520000000000100010000000111000D0A")); + + verifyNull(decoder, binary( + "54540019357557024902000002520704300000000376390d0a")); + + verifyPosition(decoder, binary( + "5454006135200000000001000332303134313131303039353430392C412C342C4E2C32322E3533373232382C452C3131342E3032323737342C302E312C312E392C35302E363B3436302C302C31303137332C343635322C34310000000B63130D0A"), + position("2014-11-10 09:54:09.000", true, 22.53723, 114.02277)); + + verifyPosition(decoder, binary( + "5454006135200000000001000432303134313131303039353330362C412C352C4E2C32322E3533373233352C452C3131342E3032323838312C302E322C312E362C35342E313B3436302C302C31303137332C343635322C343100000045EC620D0A")); + + verifyPosition(decoder, binary( + "5454009035755702490200000332303135303732393033303834352c412c362c4e2c31322e3833353735362c452c37372e3638373039362c302e332c312e322c3931302e303b3430342c34352c31303638312c31313632312c34332c31303638312c31313632332c32312c31303638312c32323538332c32302c31303638312c32333338312c31380000000267370d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java new file mode 100644 index 000000000..7c03b7d5b --- /dev/null +++ b/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class CityeasyProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + CityeasyProtocolEncoder encoder = new CityeasyProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SET_TIMEZONE); + command.set(Command.KEY_TIMEZONE, "GMT+6"); + + verifyCommand(encoder, command, binary("5353001100080001680000000B60820D0A")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java new file mode 100644 index 000000000..83722ef97 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java @@ -0,0 +1,29 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ContinentalProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ContinentalProtocolDecoder decoder = new ContinentalProtocolDecoder(null); + + verifyPosition(decoder, binary( + "5356003216001eb48505025b4001e90f7f18ce0f00522200400001015b4001e9000e820100000c24000100014e0400736a7a"), + position("2018-07-06 23:57:29.000", true, -23.46609, -46.54497)); + + verifyPosition(decoder, binary( + "5356002A1100003039030243A68B5700FEB5AB00FD715F012700000143A68B57000E000000000C2F00000130"), + position("2005-12-19 10:28:39.000", true, -23.49027, -46.55138)); + + verifyPosition(decoder, binary( + "5356002a0d0010a12403025a9ea47f00feb48400fd6e63000c0000015a9ea480000e000100000c000000")); + + verifyPosition(decoder, binary( + "5356002a0d0010a1240302581b944100febed800fd9fa30139001300581c73fa000e000000000d000001")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java new file mode 100644 index 000000000..7ffad8015 --- /dev/null +++ b/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class CradlepointProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + CradlepointProtocolDecoder decoder = new CradlepointProtocolDecoder(null); + + verifyPosition(decoder, text( + "356526070063940,0,4337.19009,N,11612.34705,W,0.0,277.2,AT&T,,,-79,,-14.0,")); + + verifyPosition(decoder, text( + "356526070063940,1,4337.19008,N,11612.34705,W,0.0,277.2,AT&T,,,-79,,-14.0,")); + + verifyPosition(decoder, text( + "+14063964266,162658,4333.62404,N,11636.23469,W,0.0,,Verizon Wireless,LTE,-107,-74,-16,,100.68.169.178")); + + verifyPosition(decoder, text( + "+12084014675,162658,4337.174385,N,11612.338373,W,0.0,,Verizon,,-71,-44,-11,,")); + + verifyPosition(decoder, text( + "353547063544681,170515,3613.25,N,11559.14,W,0.0,,,,,,,,")); + + verifyPosition(decoder, text( + "353547060558130,170519,4337.17,N,11612.34,W,0.0,294.7,,,,,,,")); + + verifyPosition(decoder, text( + "+12084014675,162658,4337.174385,N,11612.338373,W,0.0,,Verizon,,-71,-44,-11,,")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java new file mode 100644 index 000000000..ddb5aca18 --- /dev/null +++ b/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class DishaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + DishaProtocolDecoder decoder = new DishaProtocolDecoder(null); + + verifyPosition(decoder, text( + "$A#A#864161028848856#A#053523#010216#2232.7733#N#08821.1940#E#002.75#038.1#09#00.8#1800#0#000#0000#9999#11.7#285.7#0001*")); + + verifyPosition(decoder, text( + "$A#A#864161028848856#A#182134#090116#2232.0191#N#08821.3278#E#001.74#231.4#04#01.5#1300#0#000#0000#9999#54.4#6407.7#0000*"), + position("2016-01-09 18:21:34.000", true, 22.53365, 88.35546)); + + verifyPosition(decoder, text( + "$A#A#353943046615971#A#064219#281113#1836.7267#N#07347.4177#E#000.00#280.4#09#00.8#3000#2#100#0000#8888#86.5#3919.1#0000*")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java new file mode 100644 index 000000000..e9d98d6d3 --- /dev/null +++ b/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class DmtHttpProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + DmtHttpProtocolDecoder decoder = new DmtHttpProtocolDecoder(null); + + verifyPositions(decoder, request(HttpMethod.POST, "/", + buffer("{\"SerNo\":131693,\"IMEI\":\"356692063643328\",\"ICCID\":\"8944538523010771676\",\"ProdId\":33,\"FW\":\"33.4.1.27\",\"Records\":[{\"SeqNo\":125,\"Reason\":11,\"DateUTC\":\"2017-05-11 05:58:44\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":7,\"FType\":0},{\"DIn\":2,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14641,\"3\":2484,\"4\":26,\"5\":10868},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":0,\"13\":309,\"14\":9921,\"15\":3},\"FType\":7}]},{\"SeqNo\":128,\"Reason\":11,\"DateUTC\":\"2017-05-11 17:59:45\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":7,\"FType\":0},{\"DIn\":2,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14607,\"3\":2752,\"4\":26,\"5\":11062},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":1,\"13\":325,\"14\":10881,\"15\":3},\"FType\":7}]},{\"SeqNo\":130,\"Reason\":9,\"DateUTC\":\"2017-05-11 19:30:03\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":3,\"FType\":0},{\"DIn\":6,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14599,\"3\":2731,\"4\":27,\"5\":10965},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":2,\"13\":329,\"14\":11121,\"15\":3},\"FType\":7}]},{\"SeqNo\":131,\"Reason\":11,\"DateUTC\":\"2017-05-11 19:32:03\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":7,\"FType\":0},{\"DIn\":6,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14403,\"3\":2783,\"4\":27,\"5\":10965},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":2,\"13\":330,\"14\":11181,\"15\":3},\"FType\":7}]},{\"SeqNo\":133,\"Reason\":11,\"DateUTC\":\"2017-05-11 19:36:15\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":7,\"FType\":0},{\"DIn\":6,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14319,\"3\":2898,\"4\":23,\"5\":10965},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":3,\"13\":331,\"14\":11241,\"15\":3},\"FType\":7}]}]}"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java new file mode 100644 index 000000000..ae5e9353c --- /dev/null +++ b/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java @@ -0,0 +1,42 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class DmtProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + DmtProtocolDecoder decoder = new DmtProtocolDecoder(null); + + verifyNull(decoder, binary( + "0255003300001b00003335333232393032373533393235310038393931353030303030303030313330343539340000000403041910780603")); + + verifyPositions(decoder, false, binary( + "02551040000eaca40d00d2b8e562c51f9912f39a6bee00007e420091090903070100000000008b1065360000000000007fd401c4fcf2feffffffffffffffffee0000003f1b")); + + verifyPositions(decoder, false, binary( + "02551080000eada40d00d2b8e58ac51f9912f39a6bee00007e42007e090709070000000000009010fc330000000000007fc201a0fc04ffffffffffffffffffe5000000c5d00eaea40d00d2b8e58ac51f9912f39a6bee00007e42007e09070207000000000000851008340000000000007fc201a0fc04ff0000000000000000e5000000c96d")); + + verifyNull(decoder, binary( + "025500310038f90100333533333233303831363639373330003839363130313835303031383234383434363330002202010900000000")); + + verifyNull(decoder, binary( + "0255220000")); + + verifyPositions(decoder, false, binary( + "025504d80352000602000052185c0803001552185c0842ee19eaba2524682d000d060973112b0302080100000000000300060901421003e40604140007190b300000000c030000000de80100000ec90e00000f0700000052000702000069185c0803001569185c089ac019ea0ad223682300fb02047d152f03020801000000000003000609013f1003fc0604140007190b300000000c030000000de90100000ecb0e00000f0700000052000802000092185c0803001592185c0800a619eaa5e7226821009c0506880e250302080100000000000300060901411003f30604140007190b300000000c030000000dea0100000ef10e00000f07000000520009020000a9185c08030015a9185c0818ae19ea1e62226826001e05038e0e2203020801000000000003000609013f1003030704140007190b300000000c030000000deb0100000ef60e00000f0700000052000a020000c0185c08030015c0185c0893b619ea7fd321681a00640403860f1d0302080100000000000300060901401003ff0604140007190b300000000c030000000dec0100000ef80e00000f0700000052000b020000d7185c08030015d7185c08e08519eab7c921682300fd04035510270302080100000000000300060901401003ea0604140007190b300000000c030000000ded0100000efa0e00000f0700000052000c020000ee185c08030015ee185c08f61719ea61e221682c004c0503540f190302080100000000000300060901421003dd0604140007190b300000000c030000000dee0100000efc0e00000f0700000052000d02000005195c0803001505195c0836b518eac9f221683000fa0107740e2d03020801000000000003000609013f1003fe0604140007190b300000000c030000000def0100000efe0e00000f0700000052000e0200001d195c080300151d195c08d1b518ea2d6721682300980502870e1d0302080100000000000300060901411003ed0604140007190b300000000c030000000df00100000e000f00000f0700000052000f02000034195c0803001534195c086acd18ea742b2168400006020500132903020801000000000003000609013d10030d0704140007190b300000000c030000000df10100000e030f00000f070000005200100200004d195c080300154d195c08dfba18eab81721684e003000093b0e1e03020801000000000003000609013e1003130704140007190b300000000c030000000df20100000e050f00000f0700000052001102000065195c0803001565195c081db318ea871f216822000400080416250302080100000000000300060901401003060704140007190b300000000c030000000df30100000e090f00000f07000000")); + + verifyPositions(decoder, false, binary( + "025504e9032f000d000000000000001501222700524553455420446172742033342e322e312e3920666c6167733d312057443d303f000e0000000000000015013214004e6f2041646d696e20706172616d7320666f756e64202d207573696e672064656661756c7473202b204175746f41504e37000f00000000000000090015000000000000000000000000000000000000000000020805000000000007000609012b1002400003700e37001000000000000000090015000000000000000000000000000000000000000000020801000000000007000609012b1002400003700e37001100000000000000090015000000000000000000000000000000000000000000020800000000000007000609012b1002400003700e37001200000000000000020015000000000000000000000000000000000000000000020800000000000006000609012b1002400003700e370013000000000000000f001500000000000000000000000000000000000000000002080000000000000200060901271002370003670e2e0014000000000000001501211300526f6c6c20646574656374656420636f735e32203c203338333535333838343700150000000000000017001500000000000000000000000000000000000000000002080000000000000200060901071002300003d60e2a00160000000000000015011d130054756d626c65722074726967676572656420636f735e32203c20302e0017000000000000001501211300526f6c6c20646574656374656420636f735e32203c203338333535333838343700180000000000000017001500000000000000000000000000000000000000000002080000000000000200060901071002300003f70e2a00190000000000000015011d130054756d626c65722074726967676572656420636f735e32203c203026001a000000000000001501190b0047534d3a20544350206261642053594e432063686172732e001b000000000000001501211300526f6c6c20646574656374656420636f735e32203c203338333535333838343a001c0000000000000017001500000000000000000000000000000000000000000002080000000000000200060c01c90f02300003e20f041f002a001d0000000000000015011d130054756d626c65722074726967676572656420636f735e32203c20302e001e000000000000001501211300526f6c6c20646574656374656420636f735e32203c203338333535333838343a001f0000000000000017001500000000000000000000000000000000000000000002080000000000000200060c01d80f02300003ff0f0418002a00200000000000000015011d130054756d626c65722074726967676572656420636f735e32203c2030")); + + verifyNull(decoder, binary( + "025500310038f90100333533333233303831363639373330003839363130313435363839393333303030303835002202010900000000")); + + verifyPositions(decoder, binary( + "0255043D003D004746000096D684020B001502D48402F043F4EC2A6909452B001F00050011230302080000000000000A00060F041D0001FE0F021E0005000003BF08")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java new file mode 100644 index 000000000..107a2a435 --- /dev/null +++ b/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class DwayProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + DwayProtocolDecoder decoder = new DwayProtocolDecoder(null); + + verifyPosition(decoder, text( + "AA55,36,10024,1,171025,161055,36.0294,-79.7881,201, 2.5,111,1000,0000,00000,3578,0,0,0,D")); + + verifyPosition(decoder, text( + "AA55,115,318,1,171024,195059,28.0153,-82.4761,3, 1.0,319,1000,0000,00000,4244,0,0,0,D")); + + verifyPosition(decoder, text( + "AA55,117,318,1,171025,153758,28.0152,-82.4759,19, 0.6,319,1000,0000,10000,4242,0,0,0,D")); + + verifyPosition(decoder, text( + "AA55,1,123456,1,140101,101132,22.5500,113.6770,75,70.5,320,1100,0011,1110,3950,33000,24000,12345678")); + + verifyNull(decoder, text( + "AA55,HB")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java new file mode 100644 index 000000000..b26991ae7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java @@ -0,0 +1,55 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class EasyTrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + EasyTrackProtocolDecoder decoder = new EasyTrackProtocolDecoder(null); + + verifyPosition(decoder, text( + "*ET,358155100054249,HB,A,100b06,053318,803a0b51,03d507c9,0017,0000,00400000,07,100,0000,1435,63")); + + verifyNull(decoder, text( + "*ET,358155100054249,MQ")); + + verifyNull(decoder, text( + "*ET,358155100054249,TX,A,100b06,053230")); + + verifyPosition(decoder, text( + "*ET,358155100054249,HB,A,100b06,053212,803a0b20,03d507a2,0054,0000,40400000,06,100,0000,1435,44")); + + verifyNull(decoder, text( + "*ET,135790246811221,GZ,0001,0005")); + + verifyPosition(decoder, text( + "*ET,135790246811221,DW,A,0A090D,101C0D,00CF27C6,0413FA4E,0000,0000,00000000,20,4,0000,00F123"), + position("2010-09-13 16:28:13.000", true, 22.62689, 114.03021)); + + verifyNull(decoder, text( + "*ET,358155100048430,CC,0.0,V,100603,141817,80d77ae8,81ab1ffd,0000,6b08,40000000,19,99,0000,fa9,918")); + + verifyPosition(decoder, text( + "*ET,135790246811221,DW,A,050915,0C2A27,00CE5954,04132263,0000,0000,01000000,20,4,0000,001254")); + + verifyPosition(decoder, text( + "*ET,135790246811221,DW,A,0A090D,101C0D,00CF27C6,0413FA4E,0000,0000,00000000,20,4,0000,00F123,100")); + + verifyPosition(decoder, text( + "*ET,135790246811221,DW,A,0A090D,101C0D,00CF27C6,8413FA4E,0000,0000,00000000,20,4,0000,00F123,100")); + + verifyPosition(decoder, text( + "*ET,358155100003016,HB,A,0d081e,07381e,8038ee09,03d2e9be,004f,0000,40c00000,0f,100,0000,00037c,29")); + + verifyPosition(decoder, text( + "*ET,358155100003016,HB,A,0d081e,073900,8038ee2f,03d2e9fd,0114,0000,40c00000,12,100,0000,00037c,32")); + + verifyPosition(decoder, text( + "*ET,135790246811221,HB,A,050915,0C2A27,00CE5954,04132263,0000,0000,01000000,20,4,0000,00F123,100,200")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java new file mode 100644 index 000000000..e3cff9525 --- /dev/null +++ b/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java @@ -0,0 +1,114 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class EelinkProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + EelinkProtocolDecoder decoder = new EelinkProtocolDecoder(null); + + verifyNull(decoder, binary( + "454C0027E753035254407167747167670100180002035254407167747100200205020500010432000086BD")); + + verifyAttributes(decoder, binary( + "676707006502df5c89fde800bc3fa8030302005555045b555555057a5555550b225555550c105c55550d115555550e7e5555550f4555555510017b5555112b5555551f01ed5555208005b0012100005555407ad000004237f5555589000000498a0000aef78b00000000")); + + verifyAttribute(decoder, binary( + "676712003400e45c5b0ade02012e03702d87064546aa24066a1086018a0000002dc1a0ffffffff0afd074d000000000000000000000000fce0"), + Position.PREFIX_TEMP + 2, -50.0); + + verifyAttribute(decoder, binary( + "6767120043000e5c37387c0304e4e1b4f8194fa800160013009408012e03702d8706453c6e5b066f115f05710000001b067f8d248d240313020500000000000000000000000001cc"), + Position.PREFIX_TEMP + 2, 28.75); + + verifyPosition(decoder, binary( + "676714002414B05AD43A7D03026B92B10C395499FFD7000000000701CC00002495000014203604067B")); + + verifyNotNull(decoder, binary( + "676714004F14B0E68CAFE58AA8E68AA5E8ADA621E5B9BFE4B89CE79C81E6B7B1E59CB3E5B882E58D97E5B1B1E58CBAE696B0E8A5BFE8B7AF3138EFBC88E8B79DE5AE87E998B3E5A4A7E58EA63230E7B1B3EFBC89")); + + verifyPosition(decoder, binary( + "676780005a000001000000004c61743a4e33312e38333935352c4c6f6e3a5738322e36313334362c436f757273653a302e30302c53706565643a302e30306b6d2f682c4461746554696d653a323031372d31322d30322031313a32393a3433")); + + verifyPosition(decoder, binary( + "676780005E5788014C754C754C61743A4E32332E3131313734330A4C6F6E3A453131342E3430393233380A436F757273653A302E30300A53706565643A302E31374B4D2F480A446174652054696D653A323031352D30392D31332032303A32313A3230")); + + verifyPosition(decoder, binary( + "454C0050EAE2035254407167747167671200410021590BD93803026B940D0C3952AD0021000000000501CC0001A53F0170F0AB1305890F11000000000000C2D0001C001600000000000000000000000000000000")); + + verifyNull(decoder, binary( + "676701000c007b03525440717505180104")); + + verifyPosition(decoder, binary( + "6767120048000559c1829213059a7400008e277d000c000000000800cc00080d2a000034df3cf0b429dd82cad3048910320000000000007b7320d005ba0000000019a000000000000000000000")); + + verifyPosition(decoder, binary( + "6767050020213b59c6aecdff41dce70b8b977d00000001fe000a36e30078fe010159c6aecd")); + + verifyPosition(decoder, binary( + "676705002102b459ae7388fcd360d7034332b1000000028f000a4f64002eb101010159ae7388")); + + verifyPosition(decoder, binary( + "676702001c02b259ae7387fcd360d6034332b2000000028f000a4f64002eb10101")); + + verifyPosition(decoder, binary( + "6767050022001F59643640000000000000000000000001CC0000249500142000015964A6C0006E")); + + verifyAttributes(decoder, binary( + "67670300040021006E")); + + verifyPosition(decoder, binary( + "676705002200255964369D000000000000000000000001CC0000249500142000025964A71D006A")); + + verifyAttributes(decoder, binary( + "67670300040028006A")); + + verifyPosition(decoder, binary( + "676712002d066c592cca6803002631a60b22127700240046005c08020d000301af000da0fd12007f11ce05820000001899c0")); + + verifyPosition(decoder, binary( + "676702002509f65868507603a1e92e03cf90fe000000019f000117ee00111e0120631145003101510000")); + + verifyAttributes(decoder, binary( + "676712001e0092579714d60201f90001785003a301cd1a006a118504f2000000000000")); + + verifyPosition(decoder, binary( + "676712003400505784cc0b130246479b07d05a06001800000000070195039f046100002cc52e6466b391604a4900890e7c00000000000006ca")); + + verifyPosition(decoder, binary( + "676714002b00515784cc24130246479b07d05a06001800010000060195039f046100002cc52f6466b391604a49020089")); + + verifyNull(decoder, binary( + "676701000c002603541880486128290120")); + + verifyPosition(decoder, binary( + "676704001c01a4569ff2dd0517a0f7020b0d9a06011000d8001e005b0004450183")); + + verifyPosition(decoder, binary( + "676705002200ba569fc3520517a0d8020b0f740f007100d8001e005b0004460101569fd162001f")); + + verifyPosition(decoder, binary( + "676702002500bb569fc3610517a091020b116000001900d8001e005b00044601001f1170003200000000")); + + verifyPosition(decoder, binary( + "676704001c00b7569fc3020517a2d7020b08e100000000d8001e005b0004460004")); + + verifyNull(decoder, binary( + "676701000b001b035418804661834901")); + + verifyAttributes(decoder, binary( + "6767030004001A0001")); + + verifyAttributes(decoder, binary( + "6767070088001050E2281400FFFFFFFF02334455660333445566043344556605AA00000007334455660A334455660B334455660C4E2000000DAA0000000E334455660F3344556610AAAA000011334455661C334455661F334455662133445566423344556646334455664D334455665C334455665E33445566880000000089000000008A000000008B00000000")); + + verifyPosition(decoder, binary( + "676702001b03c5538086df0190c1790b3482df0f0157020800013beb00342401")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java new file mode 100644 index 000000000..e4502f919 --- /dev/null +++ b/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class EelinkProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + verifyCommand(new EelinkProtocolEncoder(false), command, binary("676780000f0000010000000052454c41592c3123")); + + verifyCommand(new EelinkProtocolEncoder(true), command, binary("454c001eb41a0123456789012345676780000f0000010000000052454c41592c3123")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java new file mode 100644 index 000000000..237c849c5 --- /dev/null +++ b/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class EgtsFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + EgtsFrameDecoder decoder = new EgtsFrameDecoder(); + + verifyFrame( + binary("0100020B0025003A5701C91A003A5701CD6E68490202101700CBB4740F7617FD924364104F116A0000000000010300001EC2"), + decoder.decode(null, null, binary("0100020B0025003A5701C91A003A5701CD6E68490202101700CBB4740F7617FD924364104F116A0000000000010300001EC2"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java new file mode 100644 index 000000000..2210893e7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java @@ -0,0 +1,37 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class EgtsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + EgtsProtocolDecoder decoder = new EgtsProtocolDecoder(null); + + verifyNull(decoder, binary( + "0100010b002200c06401f21700c1640171360d00010101140071360d000238363539303500000000000000000047fc")); + + verifyNull(decoder, binary( + "0100000b002400a0d601f01900030081030000000101011600030000004238363434393530333436343333373600014cdc")); + + verifyPositions(decoder, binary( + "0100000b002700030e01211800030e8573890100845e980f0202101500f85d980fb37f50aae9653c2b193708317b00000001c51b")); + + verifyPositions(decoder, binary( + "0100010b00a308c26401029808c3640171360d000202101800e19a7b0fcfb4c49a0bfdb87a911801b70000000010d90000180400021c0000120300000000101800f39a7b0f2fc9c39a9bf2b87a914001b50000000010da0000180400021c0000120300000000101800fa9a7b0fc663c39a21eeb87a914001b60000000010da0000180400021c0000120300000000101800069b7b0f56d8c29a26ebb87a919600ab0000000010da0000180400021c00001203000000001018000a9b7b0fb2c5c29a19f4b87a915a007d0000000010da0000180400021c0000120300000000101800089b7b0f68ccc29a21eeb87a9164008f0000000010da0000180400021c0000120300000000101800079b7b0fa0d1c29aa4ecb87a918200980000000010da0000180400021c00001203000000001018000b9b7b0f34c4c29ad3f7b87a915a00670000000010da0000180400021c00001203000000001018000f9b7b0f3dbec29aaf0fb97a91c8005e0000000010dc0000180400021c0000120300000000101800199b7b0f42bbc29a0855b97a9178006b0000000010db0000180400021c00001203000000001018001b9b7b0fc8b6c29a3c5db97a916e007e0000000010db0000180400021c00001203000000001018001a9b7b0fc4b9c29a8159b97a916e00750000000010db0000180400021c00001203000000001018001d9b7b0f94aec29a3363b97a916400930000000010db0000180400021c00001203000000001018001c9b7b0fcdb3c29a3760b97a916e008a0000000010db0000180400021c0000120300000000101800209b7b0f28a1c29af263b97a918200ba0000000010db0000180400021c00001203000000001018001f9b7b0f61a6c29af263b97a917800b30000000010db0000180400021c00001203000000001018001e9b7b0f58acc29af263b97a916400a50000000010db0000180400021c0000120300000000101800299b7b0ff26fc29ab561b97a916e00b20000000010d90000180400021c00001203000000001018002d9b7b0fd05bc29a3760b97a916e00bd0000000010d80000180400021c0000120300000000101800359b7b0f4f31c29abe5bb97a916400b50000000010d70000180400021c0000120300000000101800379b7b0f5d28c29abe5bb97a916e00b40000000010d60000180400021c0000120300000000101800369b7b0fd62cc29abe5bb97a916400bd0000000010d60000180400021c00001203000000001018003c9b7b0fca09c29a0358b97a918c00bc0000000010d50000180400021c0000120300000000101800419b7b0f38ebc19a0855b97a916e00b40000000010d60000180400021c0000120300000000101800449b7b0f4edcc19a8a53b97a916400c30000000010d60000180400021c0000120300000000101800469b7b0fded1c19acb52b97a916e00b70000000010d60000180400021c0000120300000000101800649b7b0f7a69c19a154cb97a810000bc0000000010d60000180400021c0000120300000000101800709b7b0fcc5cc19a114fb97a915000970000000010d70000180400021c0000120300000000101800729b7b0fda53c19a8a53b97a91a0007d0000000010d70000180400021c0000120300000000101800749b7b0fa24ec19a3c5db97a91a000650000000010d70000180400021c0000120300000000101800789b7b0fe74ac19aca7eb97a910e015c0000000010d80000180400021c00001203000000001018007f9b7b0f6e46c19a78e0b97a9190015c0000000010d80000180400021c0000120300000000101800869b7b0f3641c19a144eba7a9190015c0000000010d60000180400021c00001203000000001018008d9b7b0ffd3bc19a74b9ba7a9190015c0000000010d40000180400021c0000120300000000101800949b7b0fc536c19a1524bb7a9186015b0000000010d20000180400021c00001203000000001018009b9b7b0fce30c19af78dbb7a919a015c0000000010d00000180400021c0000120300000000101800a29b7b0f552cc19a93fbbb7a9172015d0000000010cd0000180400021c0000120300000000101800b09b7b0f2521c19a6ec0bc7a9186015b0000000010c90000180400021c0000120300000000101800a99b7b0f5e26c19a8759bc7a915e015b0000000010cb0000180400021c0000120300000000101800b79b7b0fa81fc19a1328bd7a9172015b0000000010c70000180400021c0000120300000000101800be9b7b0f6b1dc19ac686bd7a914a015c0000000010c60000180400021c0000120300000000101800c19b7b0fed1bc19ad2a9bd7a912201530000000010c60000180400021c0000120300000000101800c39b7b0f6223c19af4bdbd7a910401420000000010c60000180400021c0000120300000000101800c29b7b0fe91ec19a42b4bd7a910e014c0000000010c60000180400021c0000120300000000101800c59b7b0f502fc19a1acfbd7a91fa00300000000010c60000180400021c0000120300000000101800c49b7b0fdb27c19ae6c6bd7a91fa00390000000010c60000180400021c0000120300000000101800c79b7b0fb83fc19a8ad9bd7a91f000180000000010c60000180400021b0000120300000000101800c69b7b0fc536c19a52d4bd7a91f000250000000010c60000180400021b0000120300000000101800ca9b7b0fc85fc19a81dfbd7a910401030000000010c50000180400021b0000120300000000101800c89b7b0fe74ac19a86dcbd7a91fa000e0000000010c50000180400021b0000120300000000101800d29b7b0f06b7c19afbe3bd7a91a000100000000010c50000180400021c0000120300000000101800d59b7b0ff0c5c19a6beebd7a91b400410000000010c40000180400021c0000120300000000101800d49b7b0ff4c2c19af2e9bd7a91a000310000000010c40000180400021c0000120300000000101800d39b7b0f3ebcc19a79e5bd7a9196001e0000000010c40000180400021c0000120300000000101800d69b7b0f6dc7c19ae0f5bd7a91c800570000000010c40000180400021c000012030000000016b7")); + + verifyPositions(decoder, binary( + "0100020B0025003A5701C91A003A5701CD6E68490202101700CBB4740F7617FD924364104F116A0000000000010300001EC2"), + position("2018-03-21 05:38:19.000", true, 51.67569, 55.59189)); + + verifyPositions(decoder, binary( + "0100020B0079000000011F6A001424951CA5CB0F23B5740F020210180023B5740F0A301994DA9C524C9128000A000000100082000011040018110300120900000003150100E803001B0700010000340900001B0700420000000000001B0700430000000000001B0700440000000000001B0700450000000000001B0700460000000000008020")); + + verifyPositions(decoder, binary( + "0100020B00F200000001D66A001224951CA5CB0FFCB4740F0202101800FCB4740F502119943D9F524C9119805C000000100084000011040018110300120900000003150100E803001B0700410000000000001B0700420000000000001B0700430000000000001B0700440000000000001B0700450000000000001B0700460000000000006A001324951CA5CB0F05B5740F020210180005B5740F222519942D9E524C9100008B000000100083000011040018110300120900000003160100E803001B0700010000310900001B0700420000000000001B0700430000000000001B0700440000000000001B0700450000000000001B070046000000000000134E")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java new file mode 100644 index 000000000..1c2f9492a --- /dev/null +++ b/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java @@ -0,0 +1,31 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class EnforaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + EnforaProtocolDecoder decoder = new EnforaProtocolDecoder(null); + + verifyNull(decoder, binary( + "000A08002020202020303131303730303030353730323637")); + + verifyNull(decoder, binary( + "003B000502000000000820202020202030313130373030303035373032363720383A000000000D00508401358E640032B37700000367B00000A804")); + + verifyPosition(decoder, binary( + "007100040200202020202020202020382020202020202031323334353637383930313233343520313320244750524D432C3232333135322E30302C412C333530392E3836303539342C4E2C30333332322E3734333838372C452C302E302C302E302C3032303631322C2C2C412A35320D0A"), + position("2012-06-02 22:31:52.000", true, 35.16434, 33.37906)); + + verifyPosition(decoder, binary( + "007600040200202020202020202020382020202020202030313138393230303036303831383920313320244750524D432C3137313834312E30302C412C333530392E3835323431302C4E2C30333332322E3735393131332C452C302E302C302E302C3137303731322C332E342C572C412A32350D0A00")); + + verifyPosition(decoder, binary( + "006a000a081000202020202020202020333320202020202038363130373430323137313936353620204750524d432c3136313234382e30302c412c333433322e36393231312c532c30353833312e30323231372c572c302e3034382c2c3232303831342c2c2c412a3734")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java new file mode 100644 index 000000000..b615e5062 --- /dev/null +++ b/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java @@ -0,0 +1,33 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class EsealProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + EsealProtocolDecoder decoder = new EsealProtocolDecoder(null); + + verifyPosition(decoder, text( + "##S,eSeal,1000821,256,3.0.6,Normal,34,2017-08-31,08:14:40,15,A,25.708828N 100.372870W,10,0,Close,0.71,0:0:3:0,3.8,-73,E##")); + + verifyPosition(decoder, text( + "##S,eSeal,1000821,256,3.0.6,Startup,1,2017-08-31,02:01:19,3,V,0.000000N 0.000000E,0,0,Close,3.25,0:0:5:0,3.8,-93,E##")); + + verifyNull(decoder, text( + "##S,eSeal,1000821,256,3.0.6,Startup OK,1,180,30,30,16,1,E##")); + + verifyNull(decoder, text( + "##S,eSeal,1000821,256,3.0.6,Startup OK,1,180,30,30,16,1,E##")); + + verifyPosition(decoder, text( + "##S,eSeal,1000898,256,3.0.6,Normal,6,2017-09-06,23:48:39,3,V,0.000000N 0.000000E,0,0,Close,1.0,0:0:3:0,4.0,-81,E##")); + + verifyNull(decoder, text( + "##S,eSeal,1000898,256,3.0.6,RC-NFC DEL ACK,,E##")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java new file mode 100644 index 000000000..16f00d69b --- /dev/null +++ b/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class EsealProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + EsealProtocolEncoder encoder = new EsealProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ALARM_DISARM); + + assertEquals("##S,eSeal,123456789012345,256,3.0.8,RC-Unlock,E##", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java b/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java new file mode 100644 index 000000000..ed587e4f3 --- /dev/null +++ b/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java @@ -0,0 +1,31 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class EskyFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + EskyFrameDecoder decoder = new EskyFrameDecoder(); + + verifyFrame( + binary("454f3b303b3836313331313030363436313930383b523b363b3138303432303130343735313b322e39373839363b3130312e36353039313b302e37353b3332303b333339383b313b7c"), + decoder.decode(null, null, binary("454f3b303b3836313331313030363436313930383b523b363b3138303432303130343735313b322e39373839363b3130312e36353039313b302e37353b3332303b333339383b313b7c"))); + + verifyFrame( + binary("454c3b313b3836343930363032393139363632363b3137303832323134333432363b"), + decoder.decode(null, null, binary("454c3b313b3836343930363032393139363632363b3137303832323134333432363b"))); + + verifyFrame( + binary("454f3b303b3836343930363032393139363632363b523b302b3137303830383135353335322b302e30303030302b302e30303030302b302e30302b302b3078312b302b302b302b31323333"), + decoder.decode(null, null, binary("454f3b303b3836343930363032393139363632363b523b302b3137303830383135353335322b302e30303030302b302e30303030302b302e30302b302b3078312b302b302b302b31323333"))); + + verifyFrame( + binary("454f3b303b3836343930363032393139363632363b523b302b3137303830383135353335322b302e30303030302b302e30303030302b302e30302b302b3078312b302b302b302b31323333"), + decoder.decode(null, null, binary("454f3b303b3836343930363032393139363632363b523b302b3137303830383135353335322b302e30303030302b302e30303030302b302e30302b302b3078312b302b302b302b31323333454f3b303b3836343930363032393139363632363b523b302b3137303830383135353335322b302e30303030302b302e30303030302b302e30302b302b3078312b302b302b302b31323333"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java new file mode 100644 index 000000000..da7df0ab2 --- /dev/null +++ b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class EskyProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + EskyProtocolDecoder decoder = new EskyProtocolDecoder(null); + + verifyPosition(decoder, text( + "EO;0;861311006461908;R;6;180420104751;2.97896;101.65091;0.75;320;3398;1;|")); + + verifyNull(decoder, text( + "EL;1;864906029196626;170822143426;")); + + verifyPosition(decoder, text( + "EO;0;864906029196626;R;7+170822143646+-26.10806+27.94600+0.40+0+0x1+0+102540+0+1242")); + + verifyPosition(decoder, text( + "EO;0;864906029196626;R;0+170808155352+0.00000+0.00000+0.00+0+0x1+0+0+0+1233")); + + verifyPosition(decoder, text( + "ET;1;014682000989425;R;0+171216001250+33.34405+-111.96682+0.00+0+0x1+0+25598+0+1257+0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java new file mode 100644 index 000000000..c5b3364cf --- /dev/null +++ b/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java @@ -0,0 +1,33 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ExtremTracProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ExtremTracProtocolDecoder decoder = new ExtremTracProtocolDecoder(null); + + verifyPosition(decoder, text( + "$GPRMC,862106020628733,050859.000,A,1404.8573,N,08710.9967,W,0.00,0,080117,0,,00C8,00218,99,,,,,,0.00")); + + verifyPosition(decoder, text( + "$GPRMC,10000000001,092313.299,A,2238.8947,N,11355.2253,E,0.00,311.19,010307,0,,")); + + verifyPosition(decoder, text( + "$GPRMC,00000000000,092244.000,A,0000.0000,S,00000.0000,E,0.00,0.00,101016,0,,8000,0")); + + verifyNull(decoder, text( + "$GPRMC,092313.299,A,2238.8947,N,11355.2253,E,0.00,311.19,010307,0,,1111,1111")); + + verifyNull(decoder, text( + "$GPRMC,092313.299,A,2238.8947,N,11355.2253,E,0.00,311.19,010307,0,,")); + + verifyNull(decoder, text( + "$GPRMC,100936.000,A,0000.0000,S,00000.0000,E,0.00,0.00,101016,0,,8000,0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java new file mode 100644 index 000000000..1dcfc89c4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class FifotrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + FifotrackProtocolDecoder decoder = new FifotrackProtocolDecoder(null); + + verifyNull(decoder, text( + "$$79,868345037864709,382,D05,190220085833,22.643210,114.018176,1,1,1,13152,23FFD339*25")); + + verifyPosition(decoder, text( + "$$105,866104023179743,AB,A00,,161007085534,A,54.738791,25.271918,0,350,151,0,17929,0000,0,,246|1|65|96DB,936|0*0B")); + + verifyPosition(decoder, text( + "$$103,866104023179743,5,A00,,161006192841,A,54.738791,25.271918,0,342,200,0,4265,0000,0,,246|1|65|96DB,9C4|0*75")); + + verifyPosition(decoder, text( + "$$103,866104023179743,4,A00,,161006192810,V,54.738791,25.271918,0,158,122,0,4235,0000,0,,246|1|65|96DB,9C5|0*69")); + + verifyPosition(decoder, text( + "$$135,866104023192332,29,A01,,160606093046,A,22.546430,114.079730,0,186,181,0,415322,0000,02,2,460|0|27B3|EA7,A2F|3B9|3|0,940C7E,31.76|30.98*46")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java new file mode 100644 index 000000000..9e5a45a83 --- /dev/null +++ b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class FlespiProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + FlespiProtocolDecoder decoder = new FlespiProtocolDecoder(null); + + verifyPositions(decoder, request(HttpMethod.POST, "/", + buffer("[{\"position.speed\":0,\"position.latitude\":53.90573,\"time.valid.status\":true,\"timestamp\":1506956075,\"position.satellites\":10,\"message.buffered.status\":false,\"business.mode.status\":true,\"gps.status\":true,\"position.longitude\":27.455848,\"position.direction\":0,\"ident\":\"605630\"},{\"siren.status\":false,\"business.mode.status\":true,\"position.satellites\":8,\"timestamp\":1506695785,\"led.status\":false,\"position.latitude\":53.905569,\"position.longitude\":27.455986,\"position.speed\":0,\"gradual.stop.status\":false,\"position.direction\":262.643854,\"hardware.version.enum\":223,\"vehicle.mileage\":160,\"message.buffered.status\":false,\"blinkers.status\":false,\"ident\":\"605630\",\"position.altitude\":233.48,\"immobilizer.status\":false}]"))); + + verifyPositions(decoder, request(HttpMethod.POST, "/", + buffer("[{\"geofence.inside.status\":false,\"position.valid\":false,\"ain#4\":0,\"rs232.sensor.value#1\":0,\"position.direction\":0,\"rs232.sensor.value#0\":0,\"position.speed\":0,\"position.latitude\":10.11223,\"refrigerator.sensor.temperature#1\":62.5,\"gnss.antenna.cut.status\":true,\"din\":3,\"ain#3\":0,\"refrigerator.sensor.temperature#3\":71.4,\"position.altitude\":0,\"shock.event.trigger\":false,\"alarm.mode.status\":false,\"ibutton.event.connect\":false,\"refrigerator.sensor.temperature#4\":66.7,\"internal.battery.voltage.limit.lower.status\":false,\"ain#2\":0,\"gsm.signal.level\":0,\"refrigerator.connection.status\":0,\"position.satellites\":0,\"external.powersource.voltage.range.outside.status\":false,\"refrigerator.sensor.temperature#2\":68.2,\"incline.event.trigger\":false,\"alarm.event.trigger\":false,\"movement.status\":true,\"refrigerator.sensor.temperature#6\":68.9,\"ident\":\"605630\",\"timestamp\":946684840,\"engine.ignition.status\":true,\"gsm.sim.status\":true,\"record.seqnum\":8165,\"external.powersource.voltage\":15.298,\"gnss.enum\":\"glonass\",\"position.longitude\":20.88774,\"battery.voltage\":4.088,\"refrigerator.sensor.temperature#5\":71.3,\"ain#1\":0,\"internal.bus.supply.voltage.range.outside.status\":false},{\"geofence.inside.status\":false,\"position.valid\":true,\"ain#4\":0,\"rs232.sensor.value#1\":0,\"position.direction\":0,\"rs232.sensor.value#0\":0,\"position.speed\":0,\"position.latitude\":57.986744,\"refrigerator.sensor.temperature#1\":74.1,\"gnss.antenna.cut.status\":false,\"ain#3\":0,\"position.hdop\":21.1,\"refrigerator.sensor.temperature#3\":71.4,\"position.altitude\":219,\"shock.event.trigger\":false,\"alarm.mode.status\":false,\"ibutton.event.connect\":false,\"refrigerator.sensor.temperature#4\":70.5,\"internal.battery.voltage.limit.lower.status\":false,\"ain#2\":0,\"gsm.signal.level\":0,\"refrigerator.connection.status\":0,\"position.satellites\":5,\"external.powersource.voltage.range.outside.status\":false,\"refrigerator.sensor.temperature#2\":71.3,\"incline.event.trigger\":false,\"alarm.event.trigger\":false,\"movement.status\":true,\"refrigerator.sensor.temperature#6\":69.3,\"ident\":\"605630\",\"timestamp\":1392272112,\"engine.ignition.status\":true,\"gsm.sim.status\":true,\"record.seqnum\":8174,\"external.powersource.voltage\":15.303,\"gnss.enum\":\"glonass\",\"position.longitude\":56.207576,\"battery.voltage\":3.934,\"refrigerator.sensor.temperature#5\":68.1,\"ain#1\":0,\"internal.bus.supply.voltage.range.outside.status\":false}]"))); + + verifyPositions(decoder, request(HttpMethod.POST, "/", + buffer("[{\"ain#1\":1,\"ain#2\":0,\"ain#3\":0,\"ain#4\":0,\"alarm.event.trigger\":true,\"custom.SOS\":1,\"custom.dparam\":3.141593,\"custom.ign\":1,\"custom.iparam\":-55,\"custom.tparam\":\"lorem\",\"din\":722,\"dout\":1048576,\"ident\":\"namo:namo\",\"position.altitude\":300,\"position.direction\":0,\"position.hdop\":1.1,\"position.latitude\":53.90821,\"position.longitude\":27.524165,\"position.satellites\":7,\"position.speed\":0,\"timestamp\":1508508510.013227}]"))); + } + +} \ No newline at end of file diff --git a/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java new file mode 100644 index 000000000..28ecaf646 --- /dev/null +++ b/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class FlexCommProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + FlexCommProtocolDecoder decoder = new FlexCommProtocolDecoder(null); + + verifyPosition(decoder, text( + "7E00865067022408382201705302358271024932258006712785200700022601010224100040002C5002A2210001000000010012342107")); + + verifyPosition(decoder, text( + "7E27865067022408382201705241211301024932197006712794000910022481008234100040002C5002A2200011000000006306941827")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java new file mode 100644 index 000000000..3f268fde9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java @@ -0,0 +1,32 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + + +public class FlextrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + FlextrackProtocolDecoder decoder = new FlextrackProtocolDecoder(null); + + verifyNull(decoder, text( + "-1,LOGON,7000000123,8945000000")); + + verifyNull(decoder, text( + "-1,LOGON,1080424008,8945020110126633198")); + + verifyPosition(decoder, text( + "-2,UNITSTAT,20060101,123442,1080424008,N0.00.0000,E0.00.0000,0,0,0,4129,-61,2,23866,0,999,A214,63,2EE2,3471676")); + + verifyPosition(decoder, text( + "-2,UNITSTAT,20050205,181923,7000004634,N55.46.0812,E009.21.1665,122,198,6,3934,-81,01A8,23802,213,55,37FD,45,0055,12878"), + position("2005-02-05 18:19:23.000", true, 55.76802, 9.35278)); + + verifyPosition(decoder, text( + "-2,UNITSTAT,20050205,181923,7000004634,N55.46.0812,E009.21.1665,122,198,6,3934,-81,01A8,23802,213,55,37FD,45,0055,12878")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java new file mode 100644 index 000000000..837b36b64 --- /dev/null +++ b/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class FoxProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + FoxProtocolDecoder decoder = new FoxProtocolDecoder(null); + + verifyPosition(decoder, text( + "")); + + verifyPosition(decoder, text( + "")); + + verifyPosition(decoder, text( + "")); + + verifyPosition(decoder, text( + "")); + + verifyPosition(decoder, text( + "")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java new file mode 100644 index 000000000..b2fc1fd8d --- /dev/null +++ b/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class FreedomProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + FreedomProtocolDecoder decoder = new FreedomProtocolDecoder(null); + + verifyPosition(decoder, text( + "IMEI,353358011714362,2014/05/22, 20:49:32, N, Lat:4725.9624, E, Lon:01912.5483, Spd:5.05"), + position("2014-05-22 20:49:32.000", true, 47.43271, 19.20914)); + + verifyPosition(decoder, text( + "IMEI,353358011714362,2014/05/22, 20:49:32, N, Lat:4725.9624, E, Lon:01912.5483, Spd:5.05")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java new file mode 100644 index 000000000..a84c4e357 --- /dev/null +++ b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class FreematicsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + FreematicsProtocolDecoder decoder = new FreematicsProtocolDecoder(null); + + verifyNull(decoder, text( + "1#EV=2,TS=1871902,ID=ESP32305C06C40A24*AC")); + + verifyNull(decoder, text( + "0#EV=1,TS=23930,ID=ID1C6606C40A24,SK=TEST_SERVER_KEY*49")); + + verifyPositions(decoder, text( + "1#0:102560,20:0;0;0,24:425,10:4285580,A:-35.803696,B:175.748413,C:0.22,D:0.41,F:5,0:103174,20:0;0;0,24:423,10:4285660,A:-35.803696,B:175.748413,C:0.22,D:0.41,F:5,30:88193792*21")); + + verifyPositions(decoder, text( + "1#0:49244,20:0;0;0,24:423,0:50779,20:0;0;0,24:425,30:32924444*38")); + + verifyNotNull(decoder, text( + "1#0:47607,20:0;0;0,24:423,0:48732,20:0;0;0,24:428,10:4280140,A:0.000000,B:0.000000,C:0.00,D:18520000.00,F:2,30:32924444*BA")); + + verifyPositions(decoder, text( + "1#0:68338,10D:79,30:1010,105:199,10C:4375,104:56,111:62,20:0;-1;95,10:6454200,A:-32.727482,B:150.150301,C:159,D:0,F:5,24:1250*7A")); + + verifyPositions(decoder, text( + "1#0=68338,10D=79,30=1010,105=199,10C=4375,104=56,111=62,20=0;-1;95,10=6454200,A=-32.727482,B=150.150301,C=159,D=0,F=5,24=1250*7A")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java new file mode 100644 index 000000000..4f4972895 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class GalileoFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GalileoFrameDecoder decoder = new GalileoFrameDecoder(); + + assertEquals( + binary("011780011102e603383633353931303238393630323437043200801c"), + decoder.decode(null, null, binary("011780011102e603383633353931303238393630323437043200801c"))); + + assertEquals( + binary("01d48304320010020520a5829f58300f50dc8a024c0965013300000000344102350740003a41e14b426610431b4459fa672a4500004601a050364c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e293000000043200100105202d829f58300f50dc8a024c0965013300000000344102350740003a41d04b426110431b445702882a4500004601a050374c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29400000004320010000520b5819f58300f50dc8a024c0965013300000000344102350740003a419e4b426a10431c4456fab72a4500004601a050434c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010ff04203d819f58300f50dc8a024c0965013300000000344102350740003a41874b426310431c4454fe572a4500004601a050334c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29600000004320010fe0420c5809f58300f50dc8a024c0965013300000000344102350840003a41a24b426710431c4457fea72a4500004601a050214c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fd04204d809f58300f50dc8a024c0965013300000000344102350840003a41a34b426310431c4455f6772a4500004601a0502e4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29900000004320010fc0420d57f9f58300f50dc8a024c0965013300000000344102350840003a41bd4b426510431d4458fe672a4500004601a0501f4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fb04205d7f9f58300f50dc8a024c0965013300000000344102350840003a41b54b426310431d4456fa772a4500004601a0502d4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010fa0420e57e9f58300f50dc8a024c0965013300000000344102350840003a41b24b426210431e4454fa872a4500004601a050fe4b510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29000000004320010f904206d7e9f58300f50dc8a024c0965013300000000344102350a40003a41af4b426710431f4458fea72a4500004601a0500a4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e28900000067c5"), + decoder.decode(null, null, binary("01d48304320010020520a5829f58300f50dc8a024c0965013300000000344102350740003a41e14b426610431b4459fa672a4500004601a050364c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e293000000043200100105202d829f58300f50dc8a024c0965013300000000344102350740003a41d04b426110431b445702882a4500004601a050374c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29400000004320010000520b5819f58300f50dc8a024c0965013300000000344102350740003a419e4b426a10431c4456fab72a4500004601a050434c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010ff04203d819f58300f50dc8a024c0965013300000000344102350740003a41874b426310431c4454fe572a4500004601a050334c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29600000004320010fe0420c5809f58300f50dc8a024c0965013300000000344102350840003a41a24b426710431c4457fea72a4500004601a050214c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fd04204d809f58300f50dc8a024c0965013300000000344102350840003a41a34b426310431c4455f6772a4500004601a0502e4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29900000004320010fc0420d57f9f58300f50dc8a024c0965013300000000344102350840003a41bd4b426510431d4458fe672a4500004601a0501f4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fb04205d7f9f58300f50dc8a024c0965013300000000344102350840003a41b54b426310431d4456fa772a4500004601a0502d4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010fa0420e57e9f58300f50dc8a024c0965013300000000344102350840003a41b24b426210431e4454fa872a4500004601a050fe4b510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29000000004320010f904206d7e9f58300f50dc8a024c0965013300000000344102350a40003a41af4b426710431f4458fea72a4500004601a0500a4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e28900000067c5"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java new file mode 100644 index 000000000..74612caab --- /dev/null +++ b/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java @@ -0,0 +1,45 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GalileoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GalileoProtocolDecoder decoder = new GalileoProtocolDecoder(null); + + verifyPositions(decoder, binary( + "011801018202130338363833343530333230343234323604640010a406207caa9f5b300c830a7901ca0ec802330000000034b802350540003e41703f422b1043234504004600e09000000000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d4d3140000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000f400000000f500000000f600000000f700000000f800000000f9000000008960")); + + verifyPositions(decoder, binary( + "017583018202120338363833343530333230363635373304520010384520c850975b300cc03a910107cbf9023365000607341300350640012a41236a4215104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4993b0500d64100d70000d8be02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000018202120338363833343530333230363635373304520010394520c950975b300cab3a91010ecbf902336000be06341300350640012a41266a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d49b3b0500d64100d70000d8bc02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103a4520ca50975b300c953a910113cbf9023358008f06341300350640012a41206a4215104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d49e3b0500d64100d70000d8ba02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103b45204251975b300c6d3a91011dcbf9023300008a06341300350640013a41726a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4a33b0500d64800d70000d80003d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103c4520bb51975b300c6d3a91011dcbf9023300008a06341300350640013a41816a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4a33b0500d64800d70000d80003d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000e007")); + + verifyNull(decoder, binary( + "07e10300ffd8ffe000114a464946000101010000000000000affe1011445786966000049492a000800000005000e010200140000004a0000000f0102000a0000005e000000100102000a0000006800000032010200130000007200000025880400010000008600000000000000494d45492033353336313230383730353035393247616c696c656f536b7971717a6d202020202020323031383a30383a30392030363a35393a303100060001000200020000004e0000000200050003000000d40000000300020002000000450000000400050003000000ec000000050001000100000000000000060005000100000004010000000000008e7f930240420f0000000000010000000000000001000000a11aaa0140420f00000000000100000000000000010000003300000001000000ffdb0084000d09090b09080d0b0a0b0e0d0d0f131f1413111113261b1d171f2d28302f2d282c2b3238483d323544362b2c3f553f444a4d505150303c585f584e5e484f504d010d0e0e131013251414254d342c344d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4dffc000110801e0028003012100021101031101ffdd0004000affc401a20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa0100030101010101010101010000000000000102030405060708090a0b1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00f41237526768c119a0811803c8e29a7eb40075151ba9e2801436060d0df779ef408685c50092db6801e63c9c83834c772a3140c818163522924fa5310367b9a8f3ce2806382734e2bc7340c68031c52ab1e86811ffd0edcf0335170fd7b5333023151c83d4ba")); + + verifyPositions(decoder, false, binary( + "01560003383636303530303338343337353836044701e000000000e13c494e414c4c3a696e303d31313230362c696e313d302c696e323d302c696e333d302c696e343d302c696e353d302c4163633d3536363932343732353bfdef")); + + verifyPositions(decoder, false, binary( + "012a0003383633353931303233353137333732046600e000000000e1104f555428332e2e3029203d2031313130bb29")); + + verifyPositions(decoder, binary( + "0144030338363832303430303132363939333404320010ee0f20f5a86c57300570172f03bc7dfd023363002604343e00351c40092a414a6842af0e432445000046030050246b51666a524c055300000338363832303430303132363939333404320010ed0f20f4a86c57300570172f03b47dfd023363000d05343e00351140090a41c56742a60e432445000046030050b56a514f6a521b045300000338363832303430303132363939333404320010ec0f20e6a86c57300b34172f03287efd023300000000344900350d40290a41562742030b43234500004603205023455190445295005300000338363832303430303132363939333404320010eb0f20e4a86c57300b34172f03287efd023300000000344900350d40290b41000042bd0b432345000046032050dc31518c315200005300000338363832303430303132363939333404320010ea0f20c7a86c57300b34172f03287efd023300000000344900350d40a90b41000042050d43234500004600205000005100005200005300000338363832303430303132363939333404320010e90f204fa86c57300b34172f03287efd023300000000344900350d40a90b41000042ff0c43244500004600205000005100005200005300000338363832303430303132363939333404320010e80f20d7a76c57300b34172f03287efd023300000000344900350d40a90b41000042fd0c43244500004600205000005100005200005300000338363832303430303132363939333404320010e70f205fa76c57300b34172f03287efd023300000000344900350d40a90b41000042fd0c43254500004600205000005100005200005300000338363832303430303132363939333404320010e60f20e7a66c57300b34172f03287efd023300000000344900350d40a90b41000042fd0c43264500004600205000005100005200005300000338363832303430303132363939333404320010e50f206fa66c57300468172f03907cfd023300007a0a343600352b40a90b41000042030d43274500004600205000005100005200005300000338363832303430303132363939333404320010e40f2051a66c5730048c172f03ac7cfd02335300980a341600352b40a12b41000042040d43274500004600e0500000510000520000530000abde")); + + verifyNull(decoder, binary( + "011380033836383230343030313534393038370432008590")); + + verifyPositions(decoder, binary( + "01cf030446ba10630320a7054c533008f86c8e0310062c043347049e02344000350940013241506b428f10432244aeea572045f9004604a0500000510000529a6b5300000446ba10712420ce1c4b533009b4f06703043df4033381037b0a343800350a40093241db6b428f10432544c05ef81f45f9004604a050000051000052886b5300000446ba10702420c11c4b53300a54f16703c450f403336e034e0a343900350840093241dd6b428f1043254491eaf71f45f9004604a050000051000052c26b5300000446ba106f2420b31c4b53300cecf267033865f403336a03300a343800350740093241e66b429010432544b446582045f9004604a050000051000052f76b5300000446ba106e2420a61c4b53300c9cf467038878f403337b03370a343800350740093241b56b428f10432544ba46f81f45f9004604a050000051000052c66b5300000446ba106d2420991c4b53300bc8f56703508cf403338d036e0a343700350840093241d66b428f10432544b4ea572045f9004604a050000051000052846b5300000446ba106c24208c1c4b533008c8f5670370a0f403338703920a343a00350e40093241c76b428f10432544c0fef71f45f9004604a0500000510000528d6b5300000446ba106b24207f1c4b533009a4f5670338b4f403337603920a343c00350a40093241d06b428f104325449146a81f45f9004604a0500000510000528a6b5300000446ba106a2420721c4b53300b9cf56703ecc7f403337103810a343a00350840093241ca6b428f10432544d12e582045f9004604a050000051000052996b5300000446ba10692420651c4b53300a64f6670358dbf403337a03490a343900350840093241e56b429010432544aed2f71f45f9004604a050000051000052b26b5300000446ba10682420581c4b5330094cf86703e0eef4033381030c0a343a00350940093241f96b428f10432544cb2e182145f9004604a050000051000052926b5300000446ba106724204b1c4b533009f8fa67032802f503337b03fc09343b00350a40093241d86b428f10432544c0ea772145f9004604a0500000510000529e6b5300000446ba106624203e1c4b533009a0fd67036815f503338403fd09343c00350a40093241a86b428f10432544ae2e582045f9004604a050000051000052a86b5300000446ba10652420311c4b53300944006803b028f503338003ff09343d00350940093241dc6b428e10432544a8fea71f45f9004604a050000051000052e26b5300000446ba10642420241c4b533008f0026803083cf503338b03f909343c00350d40093241d36b428f10432544c0eaa71f45f9004604a050000051000052ab6b530000ff3f")); + + verifyPositions(decoder, binary( + "011e8304320010270220dbd2f051300a90cf740328ac59033300000000347600351240012a41e92e42500f431f440006c814450f00460020500000510000520000530000540000550000560000570000580000600000610000620000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d471020000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f30000000004320010260220bdd2f051300590cf740328ac59033300000000347600351440090a41f02e427b0f431f44ff0db814450f00460000500000510000520000530000540000550000560000570000580000600000610000620000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d471020000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000043200102502208ed2f051300ed8d0740304ac5903330000000034a500350a40012a41ec2e422d0f431f440016b814450f00460020500000510000520000530000540000550000560000570000580000600000610000620000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d44d020000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000622e")); + + verifyPositions(decoder, binary( + "01d48304320010020520a5829f58300f50dc8a024c0965013300000000344102350740003a41e14b426610431b4459fa672a4500004601a050364c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e293000000043200100105202d829f58300f50dc8a024c0965013300000000344102350740003a41d04b426110431b445702882a4500004601a050374c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29400000004320010000520b5819f58300f50dc8a024c0965013300000000344102350740003a419e4b426a10431c4456fab72a4500004601a050434c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010ff04203d819f58300f50dc8a024c0965013300000000344102350740003a41874b426310431c4454fe572a4500004601a050334c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29600000004320010fe0420c5809f58300f50dc8a024c0965013300000000344102350840003a41a24b426710431c4457fea72a4500004601a050214c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fd04204d809f58300f50dc8a024c0965013300000000344102350840003a41a34b426310431c4455f6772a4500004601a0502e4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29900000004320010fc0420d57f9f58300f50dc8a024c0965013300000000344102350840003a41bd4b426510431d4458fe672a4500004601a0501f4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29700000004320010fb04205d7f9f58300f50dc8a024c0965013300000000344102350840003a41b54b426310431d4456fa772a4500004601a0502d4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29500000004320010fa0420e57e9f58300f50dc8a024c0965013300000000344102350840003a41b24b426210431e4454fa872a4500004601a050fe4b510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e29000000004320010f904206d7e9f58300f50dc8a024c0965013300000000344102350a40003a41af4b426710431f4458fea72a4500004601a0500a4c510000520000530000c000000000c100000000c200000000c300000000d80000dd00000000e28900000067c5")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java new file mode 100644 index 000000000..34423578d --- /dev/null +++ b/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class GalileoProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + GalileoProtocolEncoder encoder = new GalileoProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "status"); + + verifyCommand(encoder, command, binary("01200003313233343536373839303132333435040000e000000000e1067374617475731f64")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java new file mode 100644 index 000000000..e2be99cb9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java @@ -0,0 +1,50 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class GatorProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecodeId() { + + assertEquals("3512345006", GatorProtocolDecoder.decodeId(12, 162, 50, 134)); + + } + + @Test + public void testDecode() throws Exception { + + GatorProtocolDecoder decoder = new GatorProtocolDecoder(null); + + verifyAttributes(decoder, binary( + "2424800026364101b31608041108380273453415301532000000008000010000122800000124000000c40d")); + + verifyNull(decoder, binary( + "242421000658e3d851150d")); + + verifyAttributes(decoder, binary( + "242480002658e3d851a60101c662bc00000000000000000000000000470007a30b0c00b10fc900ff00460d")); + + verifyNull(decoder, binary( + "242421000643e30282070d")); + + verifyPosition(decoder, binary( + "24248000260009632d141121072702059226180104367500000000c04700079c0c34000ad80b00ff000a0d"), + position("2014-11-21 07:27:02.000", true, 59.37697, 10.72792)); + + verifyPosition(decoder, binary( + "24248100230CA23285100306145907022346901135294700000000C04001012C0E1100000021CB0D")); + + verifyPosition(decoder, binary( + "2424800023c2631e00111220104909833268648703804100000000c0470000000b4e00000000550d"), + position("2011-12-20 10:49:09.000", true, -33.44773, -70.63402)); + + verifyPosition(decoder, binary( + "24248000260009632d141121072702059226180104367500000000c04700079c0c34000ad80b00ff000a0d")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java new file mode 100644 index 000000000..373c8c49e --- /dev/null +++ b/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GenxProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GenxProtocolDecoder decoder = new GenxProtocolDecoder(null); + + decoder.setReportColumns("28,2,3,4,13,17,10,23,27,11,7,8,46,56,59,70,74,75,77,89,90,93,99,107,112,113,114,176,175,178,181,182"); + + verifyPosition(decoder, text( + "000036004133,11/05/2017 00:03:45,45.54767,-73.75547,0,0,63,569.35,118,ON,10687,0,12,O,9,3669.000,95.0,0.0,1,107.9464,0.0065,583.752,43,0.00,28.26,7.60,NA,U,UUU,0,-95.0,U")); + + decoder.setReportColumns("1,2,3,4"); + + verifyPosition(decoder, text( + "000036004130,08/31/2017 17:24:13,45.47275,-73.65491,5,19,117,1.14,147,ON,1462,0,6,N,0,0.000,-95.0,-1.0,0,0.0000,0.0000,0.000,0,0.00,0.00,0.00,NA,U,UUU,0,-95.0,U")); + + verifyPosition(decoder, text( + "000036004130,08/31/2017 17:24:37,45.47257,-73.65506,3,0,117,1.14,124,ON,1489,0,5,N,0,0.000,-95.0,-1.0,0,0.0000,0.0000,0.000,0,0.00,0.00,0.00,NA,U,UUU,0,-95.0,U")); + + decoder.setReportColumns("1,2,3,4,13,17,10,23,27,11,7,8,46,56,59,70,74,75,77,89,90,93,99,107,112,113,114,176,175,178,181,182"); + + verifyPosition(decoder, text( + "000036035855,04/16/2017 21:19:07,45.46485,-73.65424,24,32,61:213,342.51,157,ON,20984,0,12,O,18,0.000,95.0,24.0,1990,64.0894,0.0219,316.009,71,0.00,16.78,5.10,NA,U,UUU,0,-95.0,U")); + + verifyPosition(decoder, text( + "000036004129,10/20/2017 00:54:27,43.44638,-79.68616,36,310,6,4954.40,321,ON,35377,0,12,O,13,0.000,85.6,36.0,1573,451.2514,0.0012,5260.953,0,0.00,122.48,33.17,NA,U,UUU,0,-95.0,U")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java new file mode 100644 index 000000000..ffafcd7b1 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java @@ -0,0 +1,56 @@ +package org.traccar.protocol; + + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Gl100ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gl100ProtocolDecoder decoder = new Gl100ProtocolDecoder(null); + + verifyPosition(decoder, text( + "+RESP:GTLGL,359464030492644,1,2,1,0,0.4,0,299.7,1,5.455551,51.449776,20160311083229,0204,0016,03EC,BD94,00,0036,0102090501")); + + verifyPosition(decoder, text( + "+RESP:GTTRI,359464030439249,1,0,61,1,0.0,346,-2.7,2,-80.392825,26.122424,20151214000354,0310,0260,72BC,35F5,00,04B6,0102070407")); + + verifyPosition(decoder, text( + "+RESP:GTTRI,135790246811220,1,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102070202")); + + verifyPosition(decoder, text( + "+RESP:GTTRI,135790246811220,2,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,1,-3.6,145,30.0,2,121.354442,31.221940,20090101000100,0460,0000,18d8,6141,00,11F0,0102070202")); + + verifyNull(decoder, text( + "AT+GTHBD=HeartBeat,359231030000010,20090101000000,11F0,0102120204")); + + verifyPosition(decoder, text( + "+RESP:GTSOS,359231030000010,0,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204"), + position("2009-01-01 00:00:00.000", false, 31.22207, 121.35434)); + + verifyPosition(decoder, text( + "+RESP:GTRTL,359231030000010,0,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204")); + + verifyPosition(decoder, text( + "+RESP:GTEST,359231030000010,0,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204")); + + verifyPosition(decoder, text( + "+RESP:GTSZI,359231030000010,0,3,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204")); + + verifyPosition(decoder, text( + "+RESP:GTLBC,359231030000010,02132523415,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204")); + + verifyPosition(decoder, text( + "+RESP:GTTRI,359231030000010,1,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,11F0,0102120204")); + + verifyPosition(decoder, text( + "+RESP:GTTRI,359231030000010,2,0,0,1,4.3,92,70.0,1,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,0,0,1,-3.6,145,30.0,2,121.354442,31.221940,20090101000100,0460,0000,18d8,6141,00,11F0,0102120204")); + + verifyPosition(decoder, text( + "+RESP:GTTRI,359464030073766,1,0,0,0,1.7,254,-27.8,3,30.474475,50.488383,20131107155511,0255,0003,6995,4761,00,0071,0103090402")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java new file mode 100644 index 000000000..e6fb98340 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Gl200BinaryProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gl200BinaryProtocolDecoder decoder = new Gl200BinaryProtocolDecoder(null); + + verifyPosition(decoder, binary( + "2b4556542d00fc1fbf0063450102020956325403000343056437f8220700000200000000010000160100f2007eff75a1f0025c6b1a07e1080108241a02680003189c1ac500000000000002100800000000000000000007e1080108241a19e24e4e0d0a")); + + verifyPositions(decoder, binary( + "2b5253506400fc1fbf058e450102020956325403000343056438ed2205010e61c6f0ff75a1b4025c6af959803d8ba07ffe17dea03f7e1fdda0007df7dfa03e7e3fd0a0befdf7cea001fddfd8a000fdefdca042fd9fe1a0427d6fe9a0017db7dca0407d47e7a0027d67e5bfc0fd77eca03ffd8fe4bfff7dcfddbffd7dbfdebffdfddfe2bfbe7e0fe1bf7f7e67e2bf7bfed7e2bf7c7f5fe2bffbffc7e3a12880a7daa0b9013fe3a0f801b7dfa0bd81efe1a03f8207e0a03e8217e4a07e023fe9a0bd824feca03a02affda07b02d004a07f02e007a00002d808a041830001a003834fefa00402b7eebf8382a7ebbfc28267e9bf81821fe3bf0181d7e3bf01016fe9bf010117edbf4080c7f6bf7f8087fabfbf805ff9a0fa8097fca23401300aa0b4016019a13a817026a13b81883ea0be81a83fa0bd81b03ba00101d83abfc0039874bfc081b835bfbf819834bfc081982fa01004702ea00502500da002827802bfc0825fffbf41821fffbf4081d801bf3f816802bec180fffebec20077fdbf80002801bfc0000800a000000800e0e0a202804ffba14a8127eea0460107e4a0cc809fd9a0c4004fcda0c2004fcaa080007fbfa0410067bebfc100c7b6a03f8037c1bfbf004fc6a03f0057c6a0410027c5a081001fbaa0418017baa001001fb8a0007fe7bca000ffdfb7a0817fc7b7a040ffbfb3a0407fb7b4a0407fb7b1bf807fbfb3a0007fb7b5a0007fb7b1a0007fb7b2a0007fbfb3a0407fafaba000ffb7ada0017f97aba040ff7faca001ff77b6bf3fff67b3bf007f87bea082ff47b4bfc27f17c1bfffff3fc2bebdff9fcabe3effbfe0bf3cff47e9a03c002ff0a1740097e9a1f8813fe1a12f01f7fca0fa028ff8a07f02a7fea041829007a00302bff8bf810287f2a0080257e1a0050207dbbfc481cfd3a044819fcda043015fc3a043810fc2a0c680a7b2a0448027b0a0857fa7aea0c37f67a2a0017ee7a7a0407f0f9fa000ff079fa03ffeffa1a03ffeffa2a07fff17a0a03fff1fa0a03fff2fa2a03fff3fa0a07fff47a2a0007f579fa03fff4f9da03fff679ca0007f679ea000ff4f9ca07fff5f9ca0007f579cbfc07f5f9fbf407f6fa6bf807f6fabbfc07f7fadbf807f87b2a0407f87b0a0407f77aba000ff77afbfc07f77aea03fff7fada07fff7faca000ff7fada0007f77abbfc0ff77b0a000ff7faea042ff2faba0037ee7ada0437e57a1a0037e27abbfc1fdf7bcbf827defc5bf01fe0fcebf017e3fd5bfc17e2fdca0ff7e27d7a13cfe27cba0bd7e0fa7a07d7e6fb9a07d7eb7b3a07efedfaea03ffef7afa0c07eefa7a07f7f07a3a03fff0fa3a03f7f27a2a03f7f37a4bfff7f6fa3bfff7f5fa3a07eff979fa03f7fbfa2a03f7fdfa1bfbf8017a5bfbf0037adbeff004fb8bfbf004fc1beff804fcbbf7f8047d5bf408027debf408007e8a03e804fdebf7e8027f2bf00ffefffa0400017efa0418017f1a041002feca0410017edbf007fbffea0007fdff6a1018027e4bf81ffc7f6a1008017dca0c10087bea0018097baa083ffc7cda0837fafc7a102ff0fc8a0c27effb9a0c2fe87c1a143fbf78ea07f7dcfc0a0bd7dffb3a03d7e47b1a03ffe77afa07ffe77ada0007e77aebfc07e77afbfc07e8faea03ffea7afbfbf7ecfb4bfbcfeffbbbf7bff8fb8bf7d0027bebffb809fc7bffa00ffc9bf78813fd9a03d8197e1a03b81d7e6a07e01efdda00081bfdda00101bfdba03f81a7dfbfc001afdbbfbd81a7f1bfbe0187eebf80814feea0028127e7a081813fe2a0010147e6a03e8147f4a0408167eca040817fe7a0018157e4bfc8011fdaa08b002fd1a009ffa7d5a009fe57f6a04b7df7f4a0097e07eca0027df7edbf807e2feca000fe3feca07ffe37f0a0407e0ff7a040fde7f0a0007de7eea000fdcff4a001fddffaa000fdcff8a0027dcffda07f7dbff3a03f7dc7f402680003189c355300000109000002120700000000000000000007e1080108290019e63b5c0d0a")); + + verifyNotNull(decoder, binary( + "2B5253500300FC1FFF0064450102020867623130302D446F642F442105007018217345005F010100000001100045073C4D4101DB86BD07E106130B2B0F0460000018770013000000030000000106020F2300002714301107E106130B2B1003424EFB0D0A")); + + verifyPositions(decoder, binary( + "2b5253500700fc1fbf005d4501020209563254030003430564377e42071001000000000000007eff75a151025c6a8107e10801081a2a02680003189c1ac500000000000002100700000000000000000007e1080108241019e17ebe0d0a")); + + verifyAttributes(decoder, binary( + "2b494e4601fd7f0076676231303000000045010202090104020500004100054007e107150b061d0000003f010e02580000000000d0312a1013648935103226313921591f1200000000000302680003189c1ac3001b02680003189c1ac4000d02680003189c1ac5001207e107150b0d3704f658060d0a")); + + verifyPosition(decoder, binary( + "2b4556540c00fc1fbf005c4501010108563254030003430564312a41090100000000003f007dff75a11a025c6a7807e1070a14041202680003189c1ac500000000000000000000000000000000000007e1070b041134054e5c6e0d0a")); + + verifyNull(decoder, binary( + "2b41434b017f244501010108676231303000000000ffff07e1070b03112d054dfe030d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java new file mode 100644 index 000000000..e90c6495a --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java @@ -0,0 +1,29 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class Gl200FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gl200FrameDecoder decoder = new Gl200FrameDecoder(); + + assertEquals( + binary("2b41434b017f244501010108676231303000000000ffff07e1070b03112d054dfe030d0a"), + decoder.decode(null, null, binary("2b41434b017f244501010108676231303000000000ffff07e1070b03112d054dfe030d0a"))); + + assertEquals( + binary("2b4556540c00fc1fbf005c4501010108563254030003430564312a41090100000000003f007dff75a11a025c6a7807e1070a14041202680003189c1ac500000000000000000000000000000000000007e1070b041134054e5c6e0d0a"), + decoder.decode(null, null, binary("2b4556540c00fc1fbf005c4501010108563254030003430564312a41090100000000003f007dff75a11a025c6a7807e1070a14041202680003189c1ac500000000000000000000000000000000000007e1070b041134054e5c6e0d0a"))); + + assertEquals( + binary("2b524553503a47545354522c3430303330302c3836323336353033303134323238392c474c3530302c302c302c302c33392e342c39332c312c302e332c31372c3130352e382c32352e3934343234302c34342e3430333733362c32303137303532393134303533302c303232362c303030312c353643322c373038342c2c2c2c32303137303532393136303533302c30324441"), + decoder.decode(null, null, binary("2b524553503a47545354522c3430303330302c3836323336353033303134323238392c474c3530302c302c302c302c33392e342c39332c312c302e332c31372c3130352e382c32352e3934343234302c34342e3430333733362c32303137303532393134303533302c303232362c303030312c353643322c373038342c2c2c2c32303137303532393136303533302c3032444124"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java new file mode 100644 index 000000000..2fe860573 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -0,0 +1,390 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class Gl200TextProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gl200TextProtocolDecoder decoder = new Gl200TextProtocolDecoder(null); + + verifyAttribute(decoder, buffer( + "+RESP:GTPFA,F50201,866425030235982,GL300M,20190208124849,0BD4$"), + Position.KEY_ALARM, Position.ALARM_POWER_OFF); + + verifyAttribute(decoder, buffer( + "+RESP:GTPNA,F50201,866425030235982,GL300M,20190208124909,0BD5$"), + Position.KEY_ALARM, Position.ALARM_POWER_ON); + + verifyAttributes(decoder, buffer( + "+BUFF:GTSTC,410301,864802030022424,,,0,,,,,,,0228,0002,4EE8,1BFF489,00,20181207134332,EC90$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,1A0900,860599000306845,G3-313,0,0,4,1,2.1,0,426.7,8.611466,47.681639,20181214134603,0228,0001,077F,4812,25.2,1,5.7,34,437.3,8.611600,47.681846,20181214134619,0228,0001,077F,4812,25.2,1,4.4,62,438.2,8.611893,47.681983,20181214134633,0228,0001,077F,4812,25.2,1,4.8,78,436.6,8.612236,47.682040,20181214134648,0228,0001,077F,4812,25.2,83,20181214134702,0654$")); + + verifyPosition(decoder, buffer( + "+RESP:GTCAN,270703,867162025056839,gv300w,0,1,E07FFFFF,,2,H9307659,368713.50,1291,90,91,,P82.40,,61,10.10,6.76,3.34,524.08,,,0000,,00,,,007FFFFF,,,,,,,,,,,,,,,,,,,,,0000,2,0,,,0,88.6,104,117.6,-116.886007,32.543697,20181031202959,0334,0020,5234,7FCC3D0,00,20181031203002,9F50$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,310701,863286023712855,,00000004,28378,10,1,1,0.0,294,358.4,14.271475,50.110771,20181111185001,0230,0003,94D4,3B30,00,14.5,,,,110000,2,0,C03FFFFF,,0,H46400,12310.70,0,0,83,,,,0,,0.53,3.43,,,,40,,0,,,20181111185252,2DFF")); + + verifyAttributes(decoder, buffer( + "+RESP:GTCAN,310701,863286023712855,,10,0,003FFFFF,,2,H46358,12305.50,601,0,83,,P53.00,,0,2749.15,0.19,2.80,,,,40,,0,,,20181110103016,2945$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTCAN,310701,863286023712855,,10,0,203FFFFF,,2,H46358,12305.50,601,0,83,,P53.00,,0,2749.15,0.19,2.80,,,,40,,0,,,007FFFFF,,,,,,0,,,134,37,6,0.19,,0.00,0,,,,,,0,0,0,20181110112126,299F$")); + + verifyPosition(decoder, buffer( + "+RESP:GTCAN,310701,863286023712855,,10,0,E03FFFFF,,2,H46358,12305.50,601,0,83,,P53.00,,0,2749.15,0.19,2.80,,,,40,,0,,,007FFFFF,,,,,,0,,,134,37,6,0.19,,0.00,0,,,,,,0,0,0,0,0.0,312,358.4,14.271460,50.110796,20181110103130,0230,0003,94D4,3B30,00,20181110105348,2969$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,1F0301,862193022001432,WF0GXXGBBGBM26503,,14900,41,1,1,11.6,74,356.0,14.120023,50.167894,20181104080703,0230,0003,9B14,5891,00,74.1,,,,83,220000,799,7.3,,20181104080703,099B$")); + + verifyPosition(decoder, buffer( + "+RESP:GTCAN,4B0201,867995030001575,,10,0,C03FFFFF,,0,H0,,,,,,,,,,0.00,0.03,,,,0,,0,,,0,10.0,310,404.3,14.096743,50.143363,20181102110535,0230,0003,9B14,5066,00,20181102112101,03E0$")); + + verifyPositions(decoder, buffer( + "+RESP:GTSTR,440502,866427030112088,GL530,0,0,2,,100,3,0.6,0,127.5,2.413963,48.877096,20180704180102,0208,0001,0310,E625,,,0000,20180704180100,004C$")); + + verifyPosition(decoder, buffer( + "+RESP:GTLSW,300500,860599002636595,,0,0,0,0.0,0,2886.5,-78.467145,-0.165335,20180518221815,,,,,,20180518221817,B6FD$")); + + verifyPosition(decoder, buffer( + "+RESP:GTLSW,300500,860599002636595,,0,1,0,0.0,0,2886.5,-78.467145,-0.165335,20180518221818,,,,,,20180518221819,B6FF$")); + + verifyPosition(decoder, buffer( + "+RESP:GTTSW,1A0100,135790246811220,,1,0,0,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,20100214093254,11F0$")); + + verifyPosition(decoder, buffer( + "+RESP:GTLSW,1A0100,135790246811220,,0,1,0,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,20100214093254,11F0$")); + + verifyPosition(decoder, buffer( + "+RESP:GTIGF,270302,867162025085234,,3519,0,0.0,92,111.2,-116.867638,32.450321,20180327070835,0334,0020,2B24,52CC3DE,00,,243.1,20180327070837,2A98$")); + + verifyPosition(decoder, buffer( + "+RESP:GTDIS,270302,867162025086950,,,21,1,1,0.0,81,117.8,-116.862025,32.453497,20180309084516,0334,0020,2B24,52CA916,00,1286.2,20180309084517,357E$")); + + verifyPosition(decoder, buffer( + "+RESP:GTIGL,270302,867162025085234,,,01,1,1,0.0,92,111.2,-116.867638,32.450321,20180327070838,0334,0020,2B24,52CC3DE,00,243.1,20180327070839,2A9A$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,310603,863286023345490,,00000002,,10,1,2,0.3,0,155.7,8.000000,52.000000,20171215213040,0262,0002,1450,9F13,00,1130.3,00539:27:19,,,110000,2,1,28FFD5239115034E,1,,20171215213041,27C7$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,250C02,868789023691057,,00000019,,10,1,1,0.0,196,2258.0,-99.201807,19.559242,20180214002957,0334,0003,235B,7F8D,00,6786.7,,,,100,110000,1,0394,1,4,100.0,100.0,20180214003006,C72B$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTCAN,310603,863286023335723,gv65,00,1,C03FFFFF,,0,,719601.00,,,,,,,,274.99,179.02,95.98,84761.00,,,0,,0,,,0,0.0,216,29.8,-2.155296,51.899400,20180209172714,0234,0010,53F3,8D38,00,20180211002128,E94E$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTCAN,310201,153759012347650,gv65,0,1,C03FFFFF,,2,H89394,63.14,200,0,87,,P43.60,0,0,17.53,11.61,5.92,0.00,0,0,4002,0,1,0.76,35.00,0,,,,0,0,,0000,0000,0000,0000,00,20040101000052,05A6$")); + + verifyPosition(decoder, buffer( + "+RESP:GTCAN,310603,863286023346480,gv65,00,1,C03FFFFF,,2,H2843820,373.76,1440,44,77,M23,P35.00,1810,,59.48,42.68,16.80,15.42,,,610,,0,,,0,42.7,263,27.2,-2.156478,51.899989,20171021151805,0234,0010,15D6,9AD2,00,20171021151807,0B28$")); + + verifyPosition(decoder, buffer( + "+RESP:GTCAN,310603,863286023346480,gv65,02,1,C03FFFFF,,0,H2843820,373.80,0,4,75,M12,,1800,,59.49,42.69,16.80,15.42,,,0,,0,,,0,0.7,75,24.3,-2.155148,51.899400,20171021151837,0234,0010,15D6,9AD2,00,20171021152355,0B2E$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,380603,869606020025833,gv65,00000002,12003,10,1,1,0.0,172,24.6,-81.931875,26.577439,20171002045352,0310,0260,72BD,8E5B,00,1052.1,01383:52:12,0,100,210700,2,1,28FF4560A3150483,1,05B0,20171002045402,9548$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,04040E,861074023747143,gv200,41,8959301000648637556f,24,0,1,0,1,4.4,0,1,0,0,20170912221854,0,00,01,-0500,1,20170912193448,1D5B$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,210102,354524044950583,,42,89011702272048900184,11,99,0,,,4.08,0,1,1,0,0,20170831170831,87,0.00,,,,20170831171010,0064$")); + + verifyPosition(decoder, buffer( + "+RESP:GTOBD,360701,864251020253807,LSGTC58UX7Y067312,GV500,0,70FFFF,LSGTC58UX7Y067312,1,12309,983A8140,0,0,33,nan,,0,0,0,,10,0,,0,4.4,0,83.7,36.235142,49.967324,20170829112348,0255,0001,2760,9017,00,690.1,20170829112400,3456$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,060502,861074023620928,,00000002,27822,10,1,1,0.0,84,2870.9,-78.531796,-0.277329,20170825045344,,,,,,0.0,01138:30:24,,,83,220104,2,1,28FF2776A2150308,1,FFAD,0,20170825045348,A88C$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,280500,A1000043D20139,GL300VC,41,,31,0,0,,,3.87,0,1,1,,,20170802150751,70,,48.0,,,20170802112145,03AC$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,2D0300,A1000043D20139,1G1JC5444R7252367,,11,,31,0,1,12986,,4.16,0,2,,,20170802145640,,,,,,+0000,0,20170802145643,CD5A$")); + + verifyPosition(decoder, buffer( + "+RESP:GTMPN,450102,865084030001323,gb100,0,1.6,0,-93.1,121.393023,31.164105,20170619103113,0460,0000,1806,2142,00,20170619103143,0512$")); + + verifyPosition(decoder, buffer( + "+RESP:GTTRI,862370030005908,1,0,99,1,0.0,354,18.5,18.821100,-34.084002,20170607152024,0655,0001,00DD,1CAE,00,0103010100,20170607172115,3E7D$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,060800,861074023677175,,00000002,12351,10,1,1,0.0,0,2862.4,-78.467273,-0.164998,20170529181717,,,,,,0.0,00259:11:50,,,0,210104,2,1,28E17436060000E2,1,015F,0,20170529181723,2824$")); + + verifyPosition(decoder, buffer( + "+RESP:GTSWG,110100,358688000000158,,1,0,2.1,0,27.1,121.390717,31.164424,20110901073917,0460,0000,1878,0873,,20110901154653,0015$")); + + verifyPosition(decoder, buffer( + "+RESP:GTTMP,110100,358688000000158,,2,60,1,1,4.3,92,70.0,121.354335,31.222073,20110214013254,0460,0000,18d8,6141,00,80,20110214093254,000F$")); + + verifyPosition(decoder, buffer( + "+RESP:GTSTT,110100,358688000000158,,41,0,4.3,92,70.0,121.354335,31.222073,20110214013254,0460,0000,18d8,6141,,20110214093254,0022$")); + + verifyPosition(decoder, buffer( + "+RESP:GTBPL,110100,358688000000158,,3.53,0,4.3,92,70.0,121.354335,31.222073,20110214013254,0460,0000,18d8,6141,,20110214093254,001F$")); + + verifyNotNull(decoder, buffer( + "+BUFF:GTIGL,060228,862894020180553,,,00,1,1,3.4,199,409.6,-63.174466,-17.739317,20170407121823,0000,0000,0000,0000,00,15989.5,20170407081824,9606$")); + + verifyNotNull(decoder, buffer( + "+RESP:GTFRI,060228,862894020180553,,14827,10,1,1,3.4,199,409.6,-63.174466,-17.739317,20170407121823,0000,0000,0000,0000,00,15989.5,01070:43:13,13,180,0,220101,,,,20170407081824,9607$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,060502,861074023376992,,00000002,27239,10,1,1,0.2,312,183.3,-79.320820,-2.499110,20170401212005,0740,0000,EE4E,C98F,00,0.0,02114:36:35,,,90,220504,2,0,0,20170401212007,9E3D$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,060502,861074023689626,,25202,10,1,1,0.0,0,2744.1,-78.261047,0.023452,20170401211940,,,,,,0.0,00079:19:15,,,51,110000,,,,20170401212003,4DA7$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,060100,135790246811220,,,00,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,2000.0,12345:12:34,,,80,210100,,,,20090214093254,11F0$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,06020B,862170010196747,,00000000,,10,1,2,1.8,0,-2.5,117.198440,31.845219,20120802061037,0460,0000,5663,0358,00,0.0,,,,0,410000,20120802061040,0012$")); + + verifyPositions(decoder, buffer( + "+RESP:GTERI,060502,861074023692562,,00000002,14197,10,1,1,0.2,220,491.8,-79.064212,-2.159754,20170401212007,0740,0000,EE49,CE25,00,0.0,01509:10:58,,,87,220104,2,0,0,20170401212010,D14D$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,210102,354524044925825,,1,1,1,29,2.8,0,133.7,-90.203063,32.265473,20170318005208,,,,,10800,4,20170318005208,0002$")); + + verifyPositions(decoder, false, buffer( + "+RESP:GTFRI,210102,354524044925825,,1,1,1,,,,,,,,310,410,51bc,ca1dae6,10800,1,20170318214333,0002$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTGSM,400201,862365030025161,STR,0234,0015,003a,62a2,16,,0234,0015,003a,56a2,14,,0234,0015,003a,062a,13,,0234,0015,003a,32d9,11,,0234,0015,003a,56a0,11,,,,,,,,0234,0015,003a,7489,17,,20170219200048,0033$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTGSM,400201,862365030025161,STR,0234,0015,003a,56a2,18,,0234,0015,003a,77bc,14,,0234,0015,003a,32d9,12,,0234,0015,003a,062a,12,,0234,0015,003a,62a2,11,,0234,0015,003a,56a0,10,,0234,0015,003a,7489,15,,20170219080049,0030$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTGSM,400201,862365030034940,STR,0234,0030,0870,2469,19,,0234,0030,0870,35ee,18,,0234,0030,0870,16ac,12,,0234,0030,0870,16b2,11,,0234,0030,0870,360f,6,,0234,0030,0870,165d,6,,0234,0030,0870,35ef,17,,20170215220049,008D$")); + + verifyPosition(decoder, buffer( + "+RESP:GTSTR,400201,862365030034940,GL500,0,0,2,21.1,86,0,1.6,0,5.8,0.622831,51.582688,20170215090422,0234,0030,0870,35EF,,,,20170215220049,008C$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,2C0402,867162020000816,,0,0,1,2,0.3,337,245.7,-82.373387,34.634011,20170215003054,,,,,,63,20170215003241,3EAB$")); + + verifyNotNull(decoder, buffer( + "+RESP:GTWIF,210102,354524044608058,,4,c413e200ff14,-39,,,,c413e2010e55,-39,,,,c8d3ff04a837,-43,,,,42490f997c6d,-57,,,,,,,,100,20170201020055,0001$")); + + verifyNotNull(decoder, buffer( + "+RESP:GTWIF,210102,354524044484948,,1,08626693fb98,-36,,,,,,,,97,20170119071300,05E3$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,210102,A100004D9EF2AE,,41,,8,99,0,17.7,21,3.58,0,1,1,0,0,20161216135038,4,,,,,20161216135038,00AB$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTSTR,400201,862365030034957,GL500,0,0,2,23.1,5,2,0.2,0,36.0,0.623089,51.582744,20161129174625,0234,0015,03C3,3550,,,,20161129174625,0026$")); + + verifyNotNull(decoder, buffer( + "+RESP:GTSTR,400201,862365030034957,GL500,0,1,2,21.8,100,0,,,,,,,0234,0015,03C3,3550,,,,20161129174009,0023$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,210102,A10000499AEF9B,,41,,0,0,0,15.0,9,3.87,0,1,1,0,0,20161101140211,72,,,,,20161101140211,00A3$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTNMR,210102,A10000499AEF9B,,0,0,1,9,0.0,0,288.0,-76.902364,39.578828,20161101134145,,,,,00,73,20161101134145,009F$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,210102,A10000499AEF9B,,0,1,1,9,0.5,0,288.0,-76.902364,39.578828,20161101134124,,,,,00,73,20161101134123,009D$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTRTL,210102,A10000499AEF9B,,0,0,1,10,0.2,0,305.4,-76.902274,39.578517,20161101155001,,,,,00,73,20161101155001,00A6$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,110100,358688000000158,,41,898600810906F8048812,18,99,0,33.23,1,4.19,1,1,1,0,0,20110714104934,100,,,,,20110714104934,0014$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,080100,135790246811220,,16,898600810906F8048812,16,0,1,11870,,4.1,0,0,0,,20090214013254,,12340,,00,00,+0800,0,20090214093254,11F0$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,040100,135790246811220,,16,898600810906F8048812,16,0,1,,0,4.4,0,0,0,0,20090214013254,13000,00,00,+0800,0,20090214093254,11F0$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,060100,135790246811220,,16,898600810906F8048812,16,0,1,12000,,4.4,0,0,0,0,20090214013254,0,1300,2000,00,00,+0800,0,20090214093254,11F0$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,1A0800,860599000773978,GL300,41,89701016426133851978,17,0,1,26.6,,3.90,1,1,0,0,0,20161003184043,69,1,44,,,20161004040811,022C$")); + + verifyAttributes(decoder, buffer( + "+BUFF:GTINF,1A0800,860599000773978,GL300,41,89701016426133851978,23,0,1,204.7,,3.84,1,1,0,0,0,20161006072548,62,1,38,,,20161006082343,0C98$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,360100,864251020141408,3VWGW6AJ0FM237324,gv500,,10,1,1,0.0,0,2258.4,-99.256948,19.555800,20160929214743,0334,0020,0084,65AC,00,0.0,,,,100,410000,0,nan,,20160929214743,13BA$")); + + verifyPosition(decoder, buffer( + "+RESP:GTOBD,360201,864251020186064,4T1BE46KX7U018210,,0,19FFFF,4T1BE46KX7U018210,1,14283,983901C0,799,36,18,,33792,0,0,0,,,38,,6,53557,0,0.0,0,219.5,-76.661456,39.832588,20160507132153,20160507132154,0230$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,360201,864251020186064,1G1JC5444R7252367,,12802,10,1,0,0.0,0,219.5,-76.661456,39.832588,20160507132235,,,,,,20460.9,00080:03:37,,,100,210000,791,,56,20160507132239,0233$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,1F0101,135790246811220,1G1JC5444R7252367,,,00,2,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,0,4.3,92,70.0,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,2000.0,12345:12:34,,,80,210100,,,50,20090214093254,11F0$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,1F0101,135790246811220,1G1JC5444R7252367,,,00,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,2000.0,12345:12:34,,92,80,210100,,,50,20090214093254,11F0$")); + + verifyPosition(decoder, buffer( + "+RESP:GTSTT,060228,862894020178276,,21,0,0.0,0,411.3,-63.169745,-17.776330,20160319132220,0736,0003,6AD4,5BAA,00,20160319092223,1FBD$")); + + verifyPosition(decoder, buffer( + "+RESP:GTNMR,210102,A10000458356CE,,0,1,1,9,0.0,8,190.7,-85.765865,42.894837,20160316123202,,,,,60,30,20160316123202,0137$")); + + verifyPosition(decoder, buffer( + "+RESP:GTIDA,060228,862894020178276,,,01C68011010000C7,1,1,0,0.0,0,413.0,-63.169675,-17.776349,20160317222129,0736,0003,6AD4,32CF,00,34.9,,,,,20160317182130,1626$")); + + verifyPosition(decoder, buffer( + "+RESP:GTIGN,060228,862894020180553,,9860,0,0.2,189,420.0,-63.158195,-17.800608,20160309022951,0736,0003,6AD4,3471,00,,881.2,20160308222956,129A$")); + + verifyPosition(decoder, buffer( + "+BUFF:GTIGF,060228,862894020180553,,1958,0,0.0,240,390.3,-63.089213,-17.764712,20160309122854,0736,0003,6AB8,5A23,00,,936.8,20160309082858,1368$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,060228,862894020180553,,,10,1,1,20.0,147,329.7,-62.899703,-17.720434,20160309113548,0736,0003,6AAE,3381,00,913.3,,,,0,220101,,,,20160309073554,132B$")); + + verifyPositions(decoder, buffer( + "+BUFF:GTFRI,060402,862894021808798,,,10,1,1,0.0,349,394.3,-63.287717,-17.662410,20160116234031,0736,0003,6ABA,8305,00,3326.8,,,,94,220100,,,,20160116194035,4D83")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,2C0204,867162020003125,GL300W,0,0,2,1,1.7,205,2867.0,-78.481127,-0.206828,20160215210433,0740,0000,7596,5891C,0.0,1,1.7,205,2867.0,-78.481127,-0.206828,20160215210503,0740,0000,7596,5891C,0.0,88,20160215210506,1E78$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,060228,862894020178276,,15153,10,1,1,0.0,0,431.7,-63.169571,-17.776235,20160210153458,0736,0003,6AD4,80EF,00,34.9,00117:31:26,13442,15163,0,210101,,,,20160210113503,38EE$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,110100,A5868800000015,,0,0,1,1,4.3,92,70.0,121.354335,31.222073,20110214013254,0460,0000,18d8,6141,00,80,20110214013254,000C")); + + verifyNotNull(decoder, buffer( + "+RESP:GTFRI,210102,A10000458356CE,,0,1,1,15,1.4,0,190.6,-85.765763,42.894896,20160208164505,4126,210,0,18673,00,92,20160208164507,00A6")); + + verifyPositions(decoder, buffer( + "+BUFF:GTFRI,060402,862894021808798,,,10,1,1,0.0,349,394.3,-63.287717,-17.662410,20160116234031,0736,0003,6ABA,8305,00,3326.8,,,,94,220100,,,,20160116194035,4D83")); + + verifyPosition(decoder, buffer( + "+RESP:GTIDA,06020A,862170013895931,,,D2C4FBC5,1,1,1,0.8,0,22.2,117.198630,31.845229,20120802121626,0460,0000,5663,2BB9,00,0.0,,,,,20120802121627,008E$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTINF,1F0101,135790246811220,1G1JC5444R7252367,,16,898600810906F8048812,16,0,1,12000,,4.2,0,0,,,20090214013254,,,,,,+0800,0,20090214093254,11F0$")); + + verifyPositions(decoder, false, buffer( + "+RESP:GTFRI,120113,555564055560555,,1,1,1,,,,,,,,0282,0380,f080,cabf,6900,79,20140824165629,0001$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,0F0106,862193020451183,,,10,1,1,0.0,163,,-57.513617,-25.368191,20150918182145,,,,,,21235.0,,,,0,210100,,,,20150918182149,00B8$")); + + verifyPosition(decoder, buffer( + "+RESP:GTOBD,1F0109,864251020135483,,gv500,0,78FFFF,,1,12613,,,,,,,,,,,,,,1286,0,0.0,0,17.1,3.379630,6.529701,20150813074639,0621,0030,51C0,A2B3,00,0.0,20150813074641,A7E6$")); + + verifyPosition(decoder, buffer( + "+RESP:GTOBD,1F0109,864251020135483,4T1BE46KX7U018210,gv500,0,78FFFF,4T1BE46KX7U018210,1,13411,981B81C0,787,3,43,,921,463,1,10,0300030103030304001200310351035203530354,20,55,,1286,0,6.5,74,21.6,3.379710,6.529714,20150813074824,0621,0030,51C0,A2B3,00,0.0,20150813074828,A7E9$")); + + verifyPosition(decoder, buffer( + "+RESP:GTSTT,1A0401,860599000508846,,41,0,0.0,84,107.5,-76.657998,39.497203,20150623160622,0310,0260,B435,3B81,,20150623160622,0F54$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,1A0401,860599000508846,,0,0,1,1,134.8,154,278.7,-76.671089,39.778885,20150623154301,0310,0260,043F,7761,,99,20150623154314,0F24$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,1A0200,860599000165464,CRI001,0,0,1,2,,41,,-71.153137,42.301634,20150328020301,,,,,280.3,55,20150327220351,320C")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,02010D,867844001675407,,0,0,1,2,0.0,0,28.9,8.591011,56.476397,20140915213209,0238,0001,03CB,2871,,97,20140915213459,009A")); + + verifyNull(decoder, buffer( + "+RESP:GTINF,359464030073766,8938003990320469804f,18,99,100,1,0,+2.00,0,20131018084015,00EE,0103090402")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,04040C,359231038939904,,,10,1,2,0.0,117,346.0,8.924243,50.798077,20130618122040,0262,0002,0299,109C,00,0.0,,,,,,,,,20130618122045,00F6")); + + verifyPosition(decoder, buffer( + "+RESP:GTSTT,04040C,359231038939904,,42,0,0.0,117,346.0,8.924243,50.798077,20130618125152,0262,0002,0299,109C,00,20130618125154,017A")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,020102,000035988863964,,0,0,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,,20090214093254,11F0")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,020102,135790246811220,,0,0,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,,20090214093254,11F0")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,020102,135790246811220,,0,0,2,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,0,4.3,92,70.0,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,,20090214093254,11F0")); + + verifyPosition(decoder, buffer( + "+RESP:GTDOG,020102,135790246811220,,0,0,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,2000.0,20090214093254,11F0")); + + verifyPosition(decoder, buffer( + "+RESP:GTLBC,020102,135790246811220,,+8613800000000,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,,20090214093254,11F0")); + + verifyPosition(decoder, buffer( + "+RESP:GTGCR,020102,135790246811220,,3,50,180,2,0.4,296,-5.4,121.391055,31.164473,20100714104934,0460,0000,1878,0873,00,,20100714104934,000C")); + + verifyPosition(decoder, buffer( + "+RESP:GTFRI,07000D,868487001005941,,0,0,1,1,0.0,0,46.3,-77.039627,38.907573,20120731175232,0310,0260,B44B,EBC9,0015e96913a7,-58,,100,20120731175244,0114")); + + verifyPosition(decoder, buffer( + "+RESP:GTHBM,0F0100,135790246811220,,,10,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,2000.0,20090214093254,11F0$")); + + verifyPosition(decoder, buffer( + "+RESP:GTHBM,0F0100,135790246811220,,,11,1,1,24.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,2000.0,20090214093254,11F0$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,02010C,867844001274144,,0,0,1,1,18.0,233,118.1,7.615551,51.515600,20140106130516,0262,0007,79E6,B956,,72,20140106140524,09CE$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,02010C,867844001274649,,0,0,1,1,0.0,0,122.5,7.684216,51.524512,20140106233722,0262,0007,79EE,1D22,,93,20140107003805,03C4$")); + + verifyPositions(decoder, buffer( + "+BUFF:GTFRI,210101,863286020016706,,,10,1,1,,,,49.903915,40.391669,20140818105815,,,,,,,,,,,210100,,,,,000C$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,240100,135790246811220,,,10,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,2000.0,12345:12:34,,80,,,,,,20090214093254,11F0$")); + + verifyPositions(decoder, buffer( + "+RESP:GTFRI,240100,135790246811220,,,10,2,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,0,4.3,92,70.0,121.354335,31.222073,20090101000000,0460,0000,18d8,6141,00,2000.0,12345:12:34,,,80,,,,,20090214093254,11F0$")); + + verifyNotNull(decoder, buffer( + "+RESP:GTSTT,280100,A1000043D20139,,42,0,0.1,321,228.6,-76.660884,39.832552,20150615120628,0310,0484,00600019,0A52,,20150615085741,0320$")); + + verifyNotNull(decoder, buffer( + "+RESP:GTRTL,280100,A1000043D20139,,0,0,1,1,0.1,321,239.1,-76.661047,39.832501,20150615114455,0310,0484,00600019,0A52,,87,20150615074456,031E$")); + + verifyAttributes(decoder, buffer( + "+BUFF:GTBPL,1A0800,860599000773978,GL300,3.55,0,0.0,0,257.1,60.565437,56.818277,20161006070553,,,,,204.7,20161006071028,0C75$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTTEM,1A0102,860599000000448,,3,33,0,5.8,0,33.4,117.201191,31.832502,20130109061410,0460,0000,5678,2079,,20130109061517,0091$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTJDR,0A0102,135790246811220,,0,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,20090214093254,11F0$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTJDS,0A0102,135790246811220,,2,0,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,20090214093254,11F0$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTSOS,020102,135790246811220,,0,0,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,00,,20090214093254,11F0$")); + + verifyAttributes(decoder, buffer( + "+RESP:GTVER,1A0800,860599000773978,GL300,GL300,0A03,0103,20161007041531,10F8$")); + + verifyNull(decoder, buffer( + "+ACK:GTHBD,1A0401,135790246811220,,20100214093254,11F0")); + + verifyAttributes(decoder, buffer( + "+ACK:GTRTO,1A0800,860599000773978,GL300,VER,FFFF,20161006053520,0C19")); + + verifyAttributes(decoder, buffer( + "+ACK:GTJDC,0A0102,135790246811220,,0016,20090214093254,11F0")); + + verifyAttributes(decoder, buffer( + "+ACK:GTGEO,1A0102,135790246811220,,0,0008,20100310172830,11F0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java new file mode 100644 index 000000000..9746845a0 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java @@ -0,0 +1,56 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GlobalSatProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GlobalSatProtocolDecoder decoder = new GlobalSatProtocolDecoder(null); + + verifyNull(decoder, text( + "GSh,131826789036289,3,M,ea04*3d")); + + decoder.setFormat0("SORPZAB27GHKLMN*U!"); + + verifyPosition(decoder, text( + "GSr,011412001878820,4,5,00,,1,250114,105316,E00610.2925,N4612.1824,0,0.02,0,1,0.0,64*51!")); + + verifyPosition(decoder, text( + "GSr,357938020310710,,4,04,,1,170315,060657,E00000.0000,N0000.0000,148,0.00,0,0,0.0,11991mV*6c!")); + + decoder.setFormat0("TSPRXAB27GHKLMnaicz*U!"); + + verifyPosition(decoder, text( + "GSr,1,135785412249986,01,I,EA02,3,230410,153318,E12129.2839,N2459.8570,0,1.17,212,8,1.0,12.3V*55")); + + verifyPosition(decoder, text( + "GSr,GTR-128,012896009148443,0040,5,0080,3,190813,185812,W11203.3661,N3330.2104,344,0.24,78,9,0.8,60%,0,0,12,\"310,410,0bdd,050d,02,21\",\"310,410,0bdd,0639,24,7\"*79")); + + verifyPosition(decoder, text( + "$355632004245866,1,1,040202,093633,E12129.2252,N2459.8891,00161,0.0100,147,07,2.4")); + + verifyPosition(decoder, text( + "$355632000959420,9,3,160413,230536,E03738.4906,N5546.3148,00000,0.3870,147,07,2.4")); + + verifyPosition(decoder, text( + "$353681041893264,9,3,240913,100833,E08513.0122,N5232.9395,181.3,22.02,251.30,9,1.00")); + + decoder.setFormat0("SPRXYAB27GHKLMmnaefghiotuvwb*U!"); + + verifyPosition(decoder, text( + "GSr,GTR-128,013227006963064,0080,1,a080,3,190615,163816,W07407.7134,N0440.8601,2579,0.01,130,12,0.7,11540mV,0,77,14,\"732,123,0744,2fc1,41,23\",\"732,123,0744,2dfe,05,28\",\"732,123,0744,272a,15,21\",\"732,123,0744,2f02,27,23\"*3b!")); + + verifyPosition(decoder, text( + "$80050377796567,0,13,281015,173437,E08513.28616,N5232.85432,222.3,0.526,,07*37"), + position("2015-10-28 17:34:37.000", true, 52.54757, 85.22144)); + + verifyPosition(decoder, text( + "$80050377796567,0,18,281015,191919,E08513.93290,N5232.42141,193.4,37.647,305.40,07*37"), + position("2015-10-28 19:19:19.000", true, 52.54036, 85.23222)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java new file mode 100644 index 000000000..91aca50c8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GnxProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GnxProtocolDecoder decoder = new GnxProtocolDecoder(null); + + verifyPosition(decoder, text( + "$GNX_MIF,865733022354161,143,0,172642,180316,172642,180316,1,13.034581,N,080.234521,E,0,05396274,ROUTE_2#########,Deo ############,GNX04008,B0*")); + + verifyPosition(decoder, text( + "$GNX_LOC,865733022352132,095,0,102134,280914,102134,280914,1,18.765432,N,073.752811,W,032,165.32,12,25,0,A,E,2,000099.9,000099.5,GNX01001,12*")); + + verifyNull(decoder, text( + "$GNX_LOC,865733022354161,139,0,142838,160316,142825,160316,0,000000000,N,0000000000,E,000,0.00,00,48,0,e,C,2,000000.0,000000.0,GNX04008,BB*")); + + verifyPosition(decoder, text( + "$GNX_DIO,863071015071563,110,1,155627,121214,151244,121214,1,08.878321,N,076.643154,E,0,0,0,0,0,0,GNX01001,B1*")); + + verifyNull(decoder, text( + "$GNX_DIO,865733022354161,112,1,142849,160316,142714,160316,0,000000000,N,0000000000,E,0,0,0,0,0,0,0,GNX04008,1A*")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java new file mode 100644 index 000000000..70c86bb23 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java @@ -0,0 +1,87 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GoSafeProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GoSafeProtocolDecoder decoder = new GoSafeProtocolDecoder(null); + + verifyPositions(decoder, text( + "*GS06,860078024226974,101437211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;7;N3.052302;E101.787216;16;137;48;1.58,COT:4261733103,ADC:22.86;0.58;0.01,DTT:4004;E1;0;0;0;3$101439211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;8;N3.052265;E101.787200;12;152;46;1.31,COT:4261733103,ADC:22.98;0.58;0.01,DTT:4004;E1;0;0;0;3$101441211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;8;N3.052247;E101.787232;8;131;46;1.34,COT:4261733103,ADC:23.13;0.58;0.01,DTT:4004;E1;0;0;0;3$101510211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;8;N3.052150;E101.787152;0;131;40;0.97,COT:4261733160,ADC:22.88;0.58;0.01,DTT:4000;E1;0;0;0;1$101540211218,,SYS:G3SC;V3.36;V1.1.8,GPS:A;7;N3.052150;E101.787152;0;131;40;0.97,COT:4261733160,ADC:22.91;0.58;0.00,DTT:4000;E1;0;0;0;1#")); + + verifyPositions(decoder, text( + "*GS06,359568052570135,090349191018,,SYS:G3C;V1.40;V1.0.4,GPS:A;10;S26.112722;E28.078766;0;23;1581;0.80,COT:,ADC:10.86;3.79,DTT:4000;E7;0;0;0;1$090419191018,,SYS:G3C;V1.40;V1.0.4,GPS:A;10;S26.112722;E28.078766;0;23;1581;0.80,COT:,ADC:10.85;3.79,DTT:4000;E7;0;0;0;1#")); + + verifyPositions(decoder, text( + "*GS06,359913060650380,152248050718,,SYS:G3C;V1.38;V05,GPS:A;10;N31.914370;E35.914640;0;0,COT:689,ADC:0.18;3.55,DTT:4025;E6;0;0;0;1#")); + + verifyPositions(decoder, text( + "*GS06,359913060650380,101019050718,,SYS:G3C;V1.38;V05,GPS:L;6;N31.916576;E35.908480;0;0,GSM:1;4;416;3;627A;A84B;-66,COT:188,ADC:4.31;3.88,DTT:4005;E6;0;0;0;1#")); + + verifyPositions(decoder, text( + "*GS06,860078024287174,070120310318,,SYS:G3SC;V3.32;V1.1.8,GPS:A;9;N23.169946;E113.450568;0;0;23;0.86,COT:65;20,ADC:4.27;3.73;0.01;0.02,DTT:4004;E0;0;0;0;1,IWD:0;0;000000000000#")); + + verifyPositions(decoder, text( + "*GS06,860078024213915,032544190318,,SYS:G3SC;V3.32;V1.1.8,GPS:A;7;N3.052417;E101.787112;0;0;94;1.38,COT:686;0-0-0,ADC:16.25;4.09,DTT:4000;E0;0;0;0;1#")); + + verifyPositions(decoder, text( + "*GS06,351535058659335,062728190318,,SYS:G6S;V3.32;V1.0.5,GPS:A;10;N23.169806;E113.450760;0;0;81;0.77,COT:0,ADC:0.00;0.16,DTT:80;E0;0;0;0;1#")); + + verifyPositions(decoder, text( + "*GS26,356449061046586,082522030117,,SYS:G737IC;V1.13;V1.0.5,GPS:V;5;N42.594136;W70.723832;0;0;8;2.06,GSM:;;310;260;C76D;9F1D;-85,ADC:3.86,DTT:3918C;;0;0;0;1,#")); + + verifyPositions(decoder, text( + "*GS56,357330051092344,123918301116,10,GPS:L;9;N47.582920;W122.238720;0;0;102;0.99,GSM:0;0;310;410;A7DB;385C;-86,COT:76506,ADC:0.82;3.77,DTT:2184;;0;0;10000;0$000000000000,86,GPS:A;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:0.00;3.75,DTT:0;;0;0;40;0$000000000000,86,GPS:A;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:0.00;3.74,DTT:0;;0;0;40;0$000000000000,93,GPS:A;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:0.00;3.73,DTT:8000;;0;0;80000;0$000000000000,13,GPS:L;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:11.09;3.79,DTT:2004;;0;0;80000;0$000000000000,90,GPS:L;6;N47.582912;W122.238840;0;0;88;2.20,COT:76506,ADC:11.13;3.79,DTT:23004;;0;0;10000;0$000000000000,,GPS:L;6;N47.582912;W122.238840;0;0;88;2.20,GSM:5;2;310;410;A7DB;385C;-89,COT:76506,ADC:14.12;3.81,DTT:23184;;0;0;0;6#")); + + verifyPositions(decoder, text( + "*GS26,356449061139936,022918011216,,SYS:G737IC;V1.13;V1.0.5,GPS:A;9;N42.651728;W70.623520;0;0;48;1.50,ADC:4.08,DTT:3900C;;0;0;0;1,#")); + + verifyNotNull(decoder, text( + "*GS56,356449063230915,052339180916,,SYS:G7S;V1.08;V1.2,GPS:V;4;N24.730006;E46.637816;14;0;630,GSM:;;420;4;5655;507A;-70,COT:75242;2-8-17,ADC:13.22;0.08,DTT:23004;;0;0;0;1#")); + + verifyNotNull(decoder, text( + "*GS56,356449063230915,052349180916,,SYS:G7S;V1.08;V1.2,GPS:V;6;N24.730384;E46.637620;47;56;607,GSM:;;420;4;5655;507A;-70,COT:75290;2-8-27,ADC:13.24;0.08,DTT:23004;;0;0;0;1#")); + + verifyNotNull(decoder, text( + "*GS56,356449063230915,052444180916,,SYS:G7S;V1.08;V1.2,GPS:V;6;N24.730384;E46.637620;47;56;607,GSM:;;420;4;5655;F319;-102,COT:75290;2-9-27,ADC:13.00;0.08,DTT:23004;;0;0;0;1$052449180916,,SYS:G7S;V1.08;V1.2,GPS:V;6;N24.730384;E46.637620;47;56;607,GSM:;;420;4;5655;F319;-102,COT:75290;2-9-27,ADC:13.13;0.08,DTT:23004;;0;0;0;1#")); + + verifyPositions(decoder, text( + "*GS16,356449062643845,141224290316,,SYS:G79;V1.13;V1.0.2,GPS:V;5;N24.694972;E46.680736;46;334;606;1.43,GSM:;;420;4;5655;4EB8;-57,COT:330034,ADC:13.31;3.83,DTT:27004;;0;0;0;1,OBD:064101000400000341057E04410304000341510104411001C203410F4B0341112904411F01AB0641010004000014490201FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03410D21,FUL:28260")); + + verifyPositions(decoder, text( + "*GS16,351535059439208,145425130316,,GPS:V;0;N0.000000;E0.000000;0;0;0;0.00;0.00,GSM:1;3;416;3;A8C;2820;-81;416;3;A8C;281F;-83;416;3;A8C;368A;-87;416;3;A8C;368B;-89;416;3;A8C;2C26;-103;416;3;A8C;3689;-107;416;3;A8C;2D83;-107")); + + verifyPosition(decoder, text( + "*GS02,358696043774648,GPS:230040;A;S1.166829;E36.934287;0;0;170116,STT:20;0,MGR:32755204,ADC:0;11.2;1;28.3;2;4.1,GFS:0;0")); + + verifyNull(decoder, text( + "*GS02,358696043774648")); + + verifyPositions(decoder, text( + "*GS16,351535058709775,100356130215,,SYS:G79W;V1.06;V1.0.2,GPS:A;6;N24.802700;E46.616828;0;0;684;1.35,COT:60,ADC:4.31;0.10,DTT:20000;;0;0;0;1")); + + verifyPositions(decoder, text( + "*GS16,351535059439208,074558291015,,GPS:A;9;N31.935942;E35.867092;;345;921;1.03;1.59,GSM:1;3;416;3;A8C;368B;-78;416;3;A8C;2820;-73;416;3;BB8;2CBE;-76;416;3;A8C;368A;-76;416;3;A8C;2C26;-79,OBD:04410C122003410D0F03411C0103410547037F011203411100")); + + verifyPositions(decoder, text( + "*GS16,351535059439208,083515281015,,GPS:A;9;N31.959502;E35.908316;;108;890;1.05;1.79,GSM:1;4;416;3;AF0;A3A6;-59;416;3;AF0;A3A3;-50;416;3;AF0;A3A4;-56;416;3;AF0;A3A5;-62;416;3;AF0;B195;-76,OBD:04410C194603410D2303411C0103410583037F011203411115")); + + verifyNull(decoder, text( + "*GS16,351535058709775")); + + verifyPositions(decoder, text( + "*GS16,351535059439208,103441131015,,GPS:A;8;N31.960122;E35.921652;27;99;847;1.33;2.41,GSM:1;4;416;3;AF0;9C73;-61;416;3;AF0;9C89;-68,OBD:04410C0DA403410D0B03411C010341057A037F011203411100$103453131015,,GPS:A;8;N31.959976;E35.922144;6;0;835;1.33;2.41,GSM:1;4;416;3;AF0;9C73;-67;416;3;AF0;9C89;-64;416;3;AF0;B389;-83,OBD:04410C0D8E03410D0B03411C010341057D037F011203411100$103503131015,,GPS:A;9;N31.959870;E35.922284;11;127;830;1.33;2.41,GSM:1;4;416;3;AF0;9C73;-67;416;3;AF0;9C89;-64;416;3;AF0;B389;-83,OBD:04410C0D8E03410D0B03411C010341057D037F011203411100$103513131015,,GPS:A;9;N31.959742;E35.922516;10;106;830;1.37;2.91,GSM:1;4;416;3;AF0;9C73;-67;416;3;AF0;9C89;-64;416;3;AF0;B389;-83,OBD:04410C0D1003410D0603411C010341057E037F011203411100$103553131015,,GPS:A;8;N31.959564;E35.923308;6;0;836;1.41;2.43,GSM:1;4;416;3;AF0;9C73;-65;416;3;AF0;B389;-71;416;3;AF0;9C89;-74,OBD:04410C0DAE03410D0403411C010341057C037F011203411100#")); + + verifyPositions(decoder, text( + "*GS16,351535059439208,155750220815,,SYS:G79;V1.10;V1.0.2,GPS:A;4;N31.944198;E35.846644;0;0;923;9.47;1.00,COT:155133,ADC:12.21;0.10,DTT:20002;;0;0;0;1#")); + + verifyPositions(decoder, text( + "*GS16,351535059439208,070034220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945970;E35.859848;29;65;922;1.14;1.68,COT:147528,ADC:14.07;0.11,DTT:27006;;0;0;0;3,OBD:04410C1ECD03410D2D03411C010341057A037F011203411107$070035220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945934;E35.859908;29;86;922;1.14;1.68,COT:147528,ADC:13.94;0.15,DTT:27006;;0;0;0;3,OBD:04410C1ECD03410D2D03411C010341057A037F011203411107$070037220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945844;E35.859952;29;123;922;1.14;1.68,COT:147625,ADC:13.75;0.11,DTT:27006;;0;0;0;3,OBD:04410C0FE803410D1803411C010341057C037F011203411100$070038220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945808;E35.859940;29;145;923;1.14;1.68,COT:147625,ADC:14.00;0.11,DTT:27006;;0;0;0;3,OBD:04410C0FE803410D1803411C010341057C037F011203411100#")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java new file mode 100644 index 000000000..ca3ddfda8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java @@ -0,0 +1,37 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GotopProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GotopProtocolDecoder decoder = new GotopProtocolDecoder(null); + + verifyNull(decoder, text( + "")); + + verifyNull(decoder, text( + "353327020412763,CMD-X")); + + verifyPosition(decoder, text( + "013226009991924,CMD-T,A,DATE:130802,TIME:153721,LAT:25.9757433S,LOT:028.1087816E,Speed:000.0,X-X-X-X-81-26,000,65501-00A0-4B8E")); + + verifyPosition(decoder, text( + "353327020115804,CMD-T,A,DATE:090329,TIME:223252,LAT:22.7634066N,LOT:114.3964783E,Speed:000.0,84-20,000"), + position("2009-03-29 22:32:52.000", true, 22.76341, 114.39648)); + + verifyPosition(decoder, text( + "353327020115804,CMD-T,A,DATE:090329,TIME:223252,LAT:22.7634066N,LOT:114.3964783E,Speed:000.0,1-1-0-84-20,000")); + + verifyPosition(decoder, text( + "353327020412763,CMD-F,V,DATE:140125,TIME:183636,LAT:51.6384466N,LOT:000.2863866E,Speed:000.0,61-19,")); + + verifyPosition(decoder, text( + "013949008891817,CMD-F,A,DATE:150225,TIME:175441,LAT:50.000000N,LOT:008.000000E,Speed:085.9,0-0-0-0-52-31,000,26201-1073-1DF5")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java new file mode 100644 index 000000000..ce21f733f --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class Gps056FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gps056FrameDecoder decoder = new Gps056FrameDecoder(); + + assertEquals( + binary("242435314750534c5f30323836323436323033333738323934361905110f160b0b7710584e1cbd1b9b4500005b100300fb0a071700ffff23"), + decoder.decode(null, null, binary("242435314750534c5f30323836323436323033333738323934361905110f160b0b7710584e1cbd1b9b4500005b100300fb0a071700ffff230030"))); + + assertEquals( + binary("242432354c4f474e5f3131383632343632303333373832393436322e3123"), + decoder.decode(null, null, binary("242432354c4f474e5f3131383632343632303333373832393436322e3123"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java new file mode 100644 index 000000000..a6d0c024a --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Gps056ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gps056ProtocolDecoder decoder = new Gps056ProtocolDecoder(null); + + verifyNull(decoder, buffer( + "$$25LOGN_118624620337829462.1#")); + + verifyPosition(decoder, binary( + "242435314750534C5F30323836333037313031353034353834391D0A0E091A0A0B1112C34E1E23230A45FF00000000000000000000000023")); + + verifyAttributes(decoder, binary( + "2424323853594E435F313138363330373130313530343538343900000000000023")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java new file mode 100644 index 000000000..da8d8ff5a --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java @@ -0,0 +1,261 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class Gps103ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gps103ProtocolDecoder decoder = new Gps103ProtocolDecoder(null); + + verifyAttribute(decoder, text( + "imei:868683023212255,tracker,190205084503,,F,064459.000,A,4915.1221,N,01634.5655,E,3.91,83.95;"), + "course", 83.95); + + verifyPosition(decoder, text( + "imei:864180034124375,vt14,190116192753,,F,172750.000,A,3649.2186,N,00235.8411,W,0.00,0,,0,0,51.93%,,+22;")); + + verifyNull(decoder, text( + "imei:864180034124375,vr,0c00fa011ea05a03d726977103ad0034c98ef49e6d303fffd1c8361303f2dbb0fa530d8ca3930be3e94f4110145c7029a507a0a00028f4a70514c05c500503170334b400531971cad002ab7634f001a4027949c8e541ea47f853bca2f961ba427ab1e290089197711c485e4f6e82ad0d1ee8f25573eed4af60284f6935bb7ef2307f1dc3f4355bbf3f90a607ffd2e5fcc6c60310be80f152dbca54ed53147fed3ae7fa1fe54809e45330fdedc993d073b7f2a6340a00d8cabeb9a4980c68900e5cb1f6e29aab9e00fc334012a5a5c32e5227c7b21a9a2d35dc02cdb49edb189fe545ec058fec7565e667cfa08b1fccd34686e4f12003dd7ffaf4b980957440bd595beb53269bb082a517dd570693604cb6299cb1663f5a9d608e3e42807d71cd002d206028011e50aa49381513494011349cd2092803ffd3d031f154ef11bc86d870781f8679a90302540adc545c55a00e28c8a602e47ad2e46680133cd19e6800cd1cf4a0063293ce695188e0d20265e58559305c3ffcb2948eca10d20278adb50518890c40f5ed9a5fece941ccb29cfd19ff00c2a6e860d6471c7da1cffb3b507eb9aaafa3dc4a4909b7fdf6c9fd28b88fffd4ca5d06e7b94152af87a53f7a7403d949a8e60265f0eaff0014ee7e8807f5a99340857abcadf881fd2973013a6936f1f48d4ffbc01fe95652dd63fba00fa521926d1de8e07a51600dc3d01d00;")); + + verifyPosition(decoder, text( + "imei:868683026321020,T:+11,181217080050,,F,080047.000,A,3227.3057,N,11649.4754,W,0.00,0,,0,0,0.00%,,+11;")); + + verifyAttribute(decoder, text( + "imei:868683026321020,tracker,181217080106,,F,080102.000,A,3227.3057,N,11649.4754,W,0.00,0,,0,0,0.00%,0,+11;"), + Position.PREFIX_TEMP + 1, 11); + + verifyPosition(decoder, text( + "imei:861359038609986,Equipo 1,---,------,----,214734,241018,26,1,-33.42317,-70.61930,067,229,0674,1.00,08,0,1,---,*")); + + verifyPosition(decoder, text( + "imei:861359038609986,Equipo 1,---,------,----,214812,241018,14,0,-33.42317,-70.61930,000,000,0000,99.9,00,0,1,---,*")); + + verifyNull(decoder, text( + "imei:123451234512345,L,*")); + + verifyAttributes(decoder, text( + "imei:868683027758113,OBD,180905200218,,,,0,0,0.39%,70,9.41%,494,0.00,P0137,P0430,,;")); + + verifyAttribute(decoder, text( + "imei:353451044508750,001,0809231929,13554900601,F,055403.000,A,2233.1870,N,11354.3067,E,0.00,30.1,65.43,1,0,10.5%,0.0%,28;"), + "fuel1", 10.5); + + verifyPosition(decoder, text( + "imei:864180036029895,acc on,180508145653,,F,065645.000,A,4729.1497,N,01904.2342,E,0.00,0,,1,,0.00%,,;")); + + verifyNotNull(decoder, text( + "imei:864895030279986,ac alarm,180404174252,,L,,,296a,,51f7,,,")); + + verifyAttributes(decoder, text( + "imei:359710048977327,OBD,180301094003,5000000,0.00,0.00,98,18,68.63%,55,25.10%,1368,14.24,,,,;")); + + verifyAttributes(decoder, text( + "imei:862106025092216,OBD,170605095949,195874,,370.8,808,066,30.0%,+87,13.0%,02444,14.3,,,,;")); + + verifyAttributes(decoder, text( + "imei:868683027825532,OBD,170613203014,,,,0,0,0.00%,0,0.00%,0,0.00,,,,;")); + + verifyAttributes(decoder, text( + "imei:862106025092216,OBD,170612165656,196043,,145803.9,,000,0.0%,+,0.0%,00000,12.6,,,,;")); + + verifyAttributes(decoder, text( + "imei:862106025092216,OBD,170605095949,195874,,370.8,808,066,30.0%,+87,13.0%,02444,14.3,,,,;")); + + verifyPosition(decoder, text( + "imei:353451044508750,DTC,0809231929,,F,055403.000,A,2233.1870,N,11354.3067,E,0.00,30.1,,1,0,10.5%,P0021,;")); + + verifyPosition(decoder, text( + "imei:353451044508750,oil1,0809231929,,F,055403.000,A,2233.1870,N,11354.3067,E,0.00,,,,51.6,41.7,;")); + + verifyPosition(decoder, text( + "imei:353451044508750,oil2,0809231929,,F,055403.000,A,2233.1870,N,11354.3067,E,0.00,,,,51.6,41.7,;")); + + verifyPosition(decoder, text( + "imei:353451044508750,oil 51.67,0809231929,,F,055403.000,A,2233.1870,N,11354.3067,E,0.00,,;")); + + verifyPosition(decoder, text( + "imei:353451044508750,T:+28.0,0809231929,,F,055403.000,A,2233.1870,N,11354.3067,E,0.00,,;")); + + verifyPosition(decoder, text( + "imei:353451044508750,bonnet alarm,0809231929,,F,055403.000,A,2233.1870,N,11354.3067,E,0.00,,;")); + + verifyPosition(decoder, text( + "imei:353451044508750,footbrake alarm,0809231929,,F,055403.000,A,2233.1870,N,11354.3067,E,0.00,,;")); + + verifyPosition(decoder, text( + "imei:862106021237716,ac alarm,1611291645,,F,204457.000,A,1010.2783,N,06441.0274,W,0.00,,;")); + + verifyAttributes(decoder, text( + "imei:359710049057798,OBD,161003192752,1785,,,0,54,96.47%,75,20.00%,1892,0.00,P0134,P0571,,;")); + + verifyAttributes(decoder, text( + "imei:359710049090138,OBD,160629022949,51442,0.00,15.88,5632,122,40.39%,95,0.00%,2101,13.80,,,,;")); + + verifyPosition(decoder, text( + "imei:359710049090138,tracker,160629022948,,F,182949.000,A,4043.8839,N,11328.8029,W,65.26,271.82,,1,0,31.37%,51442,;")); + + verifyAttributes(decoder, text( + "imei:359710049042014,001,160615040011,,F,040011.000,A,2833.0957,N,07711.9465,E,0.01,215.33,,0,,,,;")); + + verifyAttributes(decoder, text( + "imei:359710049028435,OBD,160316053657,70430,,,0,49,60.00%,46,19.22%,859,0.00,U1108,,,;")); + + verifyPosition(decoder, text( + "359769031878322imei:359769031878322,tracker,1602160718,2,F,221811.000,A,1655.2193,S,14546.6722,E,0.00,,")); + + verifyNull(decoder, text( + "imei:865328021049167,OBD,141118115036,,,0.0,,000,0.0%,+,0.0%,00000,,,,,")); + + verifyAttributes(decoder, text( + "imei:359710049032874,OBD,160208152900,13555,,,45,0,24.71%,35,13.73%,1230,14.13,U1108,,,")); + + verifyAttributes(decoder, text( + "imei:359710049064398,OBD,160101035156,17887,0.00,17.06,0,0,0.00%,0,0.00%,16383,10.82,,,,")); + + verifyPosition(decoder, text( + "imei:868683020235846,rfid,160202091347,49121185,F,011344.000,A,0447.7273,N,07538.9934,W,0.00,0,,0,0,0.00%,,")); + + verifyNotNull(decoder, text( + "imei:359710049075097,help me,,,L,,,113b,,558f,,,,,0,0,,,")); + + verifyNotNull(decoder, text( + "imei:359710041100000,tracker,000000000,,L,,,fa8,,c9af,,,,,0,0,0.00%,,")); + + verifyNotNull(decoder, text( + "imei:863070016871385,tracker,0000000119,,L,,,0FB6,,CB5D,,,")); + + verifyPosition(decoder, text( + "imei:359710045559474,tracker,151030080103,,F,000101.000,A,5443.3834,N,02512.9071,E,0.00,0;"), + position("2015-10-30 00:01:01.000", true, 54.72306, 25.21512)); + + verifyPosition(decoder, text( + "imei:359710049092324,tracker,151027025958,,F,235957.000,A,2429.5156,N,04424.5828,E,0.01,27.91,,0,0,,,;"), + position("2015-10-26 23:59:57.000", true, 24.49193, 44.40971)); + + verifyPosition(decoder, text( + "imei:865328021058861,tracker,151027041419,,F,011531.000,A,6020.2979,N,02506.1940,E,0.49,113.30,,0,0,0.0%,,;"), + position("2015-10-27 01:15:31.000", true, 60.33830, 25.10323)); + + // Log on request + verifyNull(decoder, text( + "##,imei:359586015829802,A")); + + // Heartbeat package + verifyNull(decoder, text( + "359586015829802")); + + // No GPS signal + verifyNull(decoder, text( + "imei:359586015829802,tracker,000000000,13554900601,L,;")); + + verifyPosition(decoder, text( + "imei:869039001186913,tracker,1308282156,0,F,215630.000,A,5602.11015,N,9246.30767,E,1.4,,175.9,")); + + verifyPosition(decoder, text( + "imei:359710040656622,tracker,13/02/27 23:40,,F,125952.000,A,3450.9430,S,13828.6753,E,0.00,0")); + + verifyPosition(decoder, text( + "imei:359710040565419,tracker,13/05/25 14:23,,F,062209.000,A,0626.0411,N,10149.3904,E,0.00,0")); + + verifyPosition(decoder, text( + "imei:353451047570260,tracker,1302110948,,F,144807.000,A,0805.6615,S,07859.9763,W,0.00,,")); + + verifyPosition(decoder, text( + "imei:359587016817564,tracker,1301251602,,F,080251.000,A,3223.5832,N,11058.9449,W,0.03,")); + + verifyPosition(decoder, text( + "imei:359587016817564,tracker,1301251602,,F,080251.000,A,3223.5832,N,11058.9449,W,,")); + + verifyPosition(decoder, text( + "imei:012497000208821,tracker,1301080525,,F,212511.000,A,2228.5279,S,06855.6328,W,18.62,268.98,")); + + verifyPosition(decoder, text( + "imei:012497000208821,tracker,1301072224,,F,142411.077,A,2227.0739,S,06855.2912,,0,0,")); + + verifyPosition(decoder, text( + "imei:012497000431811,tracker,1210260609,,F,220925.000,A,0845.5500,N,07024.7673,W,0.00,,")); + + verifyPosition(decoder, text( + "imei:100000000000000,help me,1004171910,,F,010203.000,A,0102.0003,N,00102.0003,E,1.02,")); + + verifyPosition(decoder, text( + "imei:353451040164707,tracker,1105182344,+36304665439,F,214418.000,A,4804.2222,N,01916.7593,E,0.37,")); + + verifyPosition(decoder, text( + "imei:353451042861763,tracker,1106132241,,F,144114.000,A,2301.9052,S,04909.3676,W,0.13,")); + + verifyPosition(decoder, text( + "imei:359587010124900,tracker,0809231929,13554900601,F,112909.397,A,2234.4669,N,11354.3287,E,0.11,321.53,")); + + verifyPosition(decoder, text( + "imei:353451049926460,tracker,1208042043,123456 99008026,F,124336.000,A,3509.8668,N,03322.7636,E,0.00,,")); + + // SOS alarm + verifyPosition(decoder, text( + "imei:359586015829802,help me,0809231429,13554900601,F,062947.294,A,2234.4026,N,11354.3277,E,0.00,")); + + // Low battery alarm + verifyPosition(decoder, text( + "imei:359586015829802,low battery,0809231429,13554900601,F,062947.294,A,2234.4026,N,11354.3277,E,0.00,")); + + // Geo-fence alarm + verifyPosition(decoder, text( + "imei:359586015829802,stockade,0809231429,13554900601,F,062947.294,A,2234.4026,N,11354.3277,E,0.00,")); + + // Move alarm + verifyPosition(decoder, text( + "imei:359586015829802,move,0809231429,13554900601,F,062947.294,A,2234.4026,N,11354.3277,E,0.00,")); + + // Over speed alarm + verifyPosition(decoder, text( + "imei:359586015829802,speed,0809231429,13554900601,F,062947.294,A,2234.4026,N,11354.3277,E,0.00,")); + + verifyPosition(decoder, text( + "imei:863070010423167,tracker,1211051840,,F,104000.000,A,2220.6483,N,11407.6377,,0,0,")); + + verifyPosition(decoder, text( + "imei:863070010423167,tracker,1211051951,63360926,F,115123.000,A,2220.6322,N,11407.5313,E,0.00,,")); + + verifyPosition(decoder, text( + "imei:863070010423167,tracker,1211060621,,F,062152.000,A,2220.6914,N,11407.5506,E,15.85,347.84,")); + + verifyPosition(decoder, text( + "imei:863070012698733,tracker,1303092334,,F,193427.000,A,5139.0369,N,03907.2791,E,0.00,,")); + + verifyPosition(decoder, text( + "imei:869039001186913,tracker,130925065533,0,F,065533.000,A,5604.11015,N,9232.12238,E,0.0,,329.0,")); + + verifyPosition(decoder, text( + "imei:359710041641581,acc alarm,1402231159,,F,065907.000,A,2456.2591,N,06708.8335,E,7.53,76.10,,1,0,0.03%,,")); + + verifyPosition(decoder, text( + "imei:359710041641581,acc alarm,1402231159,,F,065907.000,A,2456.2591,N,06708.8335,E,7.53,76.10,,1,0,0.03%,,")); + + verifyPosition(decoder, text( + "imei:313009071131684,tracker,1403211928,,F,112817.000,A,0610.1133,N,00116.5840,E,0.00,,,0,0,0.0,0.0,")); + + verifyPosition(decoder, text( + "imei:866989771979791,tracker,140527055653,,F,215653.00,A,5050.33113,N,00336.98783,E,0.066,0")); + + verifyPosition(decoder, text( + "imei:353552045375005,tracker,150401165832,61.0,F,31.0,A,1050.73696,N,10636.49489,E,8.0,,22.0,")); + + verifyPosition(decoder, text( + "imei:353552045403597,tracker,150420050648,53.0,F,0.0,A,N,5306.64155,E,00700.77848,0.0,,1.0,;")); + + verifyPosition(decoder, text( + "imei:353552045403597,tracker,150420051153,53.0,F,0.0,A,5306.64155,N,00700.77848,E,0.0,,1.0,;")); + + verifyPosition(decoder, text( + "imei:359710047424644,tracker,150506224036,,F,154037.000,A,0335.2785,N,09841.1543,E,3.03,337.54,,0,0,45.16%,,;")); + + verifyPosition(decoder, text( + "imei:865328023776874,acc off,150619152221,,F,072218.000,A,5439.8489,N,02518.5945,E,0.00,,,1,1,0.0,0.0,23.0,;")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java new file mode 100644 index 000000000..f888ee252 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java @@ -0,0 +1,39 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class Gps103ProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncodePositionPeriodic() throws Exception { + + Gps103ProtocolEncoder encoder = new Gps103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_PERIODIC); + command.set(Command.KEY_FREQUENCY, 300); + + assertEquals("**,imei:123456789012345,C,05m", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeCustom() throws Exception { + + Gps103ProtocolEncoder encoder = new Gps103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "H,080"); + + assertEquals("**,imei:123456789012345,H,080", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java new file mode 100644 index 000000000..d35666b56 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java @@ -0,0 +1,52 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GpsGateProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GpsGateProtocolDecoder decoder = new GpsGateProtocolDecoder(null); + + verifyPosition(decoder, text( + "$FRCMD,0097,_SendMessage,,7618.51990,S,4002.26182,E,350.0,1.08,0.0,250816,183522.000,0*7F")); + + verifyPosition(decoder, text( + "$FRCMD,356406061385182,_SendMessage,,5223.88542,N,11440.45866,W,951.2,0.027,,220716,153507.00,1*5F")); + + verifyPosition(decoder, text( + "$FRCMD,353067011068246,_SendMessage,,1918.1942,N,09906.3696,W,2246.5,000.0,295.9,150416,213147.00,1,Odometer=*70")); + + verifyNull(decoder, text( + "$FRCMD,862950025974620,_Ping,voltage=4*4F")); + + verifyPosition(decoder, text( + "$FRCMD,862950025974620,_SendMessage, ,2721.5781,S,15259.145,E,61,0.00,61,080316,092612,1,SosButton=0,voltage=4*60")); + + verifyNull(decoder, text( + "$FRLIN,,user1,8IVHF*7A")); + + verifyNull(decoder, text( + "$FRLIN,,354503026292842,VGZTHKT*0C")); + + verifyNull(decoder, text( + "$FRLIN,IMEI,1234123412341234,*7B")); + + verifyNull(decoder, text( + "$FRLIN,,saab93_device,KLRFBGIVDJ*28")); + + verifyPosition(decoder, text( + "$GPRMC,154403.000,A,6311.64120,N,01438.02740,E,0.000,0.0,270707,,*0A"), + position("2007-07-27 15:44:03.000", true, 63.19402, 14.63379)); + + verifyPosition(decoder, text( + "$GPRMC,074524,A,5553.73701,N,03728.90491,E,10.39,226.5,160614,0.0,E*75")); + + verifyPosition(decoder, text( + "$GPRMC,154403.000,A,6311.64120,N,01438.02740,E,0.000,0.0,270707,,*0A")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java new file mode 100644 index 000000000..d6ba11cb7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java @@ -0,0 +1,32 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + + +public class GpsMarkerProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GpsMarkerProtocolDecoder decoder = new GpsMarkerProtocolDecoder(null); + + verifyPosition(decoder, text( + "$GM23D863071014445404T260816142611N55441051E037325071033063C0530304#")); + + verifyNull(decoder, text( + "$GM300350123456789012T100511123300G25000001772F185200000000000000005230298#")); + + verifyPosition(decoder, text( + "$GM200350123456789012T100511123300N55516789E03756123400000035230298#"), + position("2011-05-10 12:33:00.000", true, 55.86132, 37.93539)); + + verifyPosition(decoder, text( + "$GM1350123456789012T1005111233N55516789E03756123400000035200298#")); + + verifyPosition(decoder, text( + "$GM203863071014445404T150715202258N55481576E03729275300000040530301#")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java new file mode 100644 index 000000000..438d0fb3a --- /dev/null +++ b/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GpsmtaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GpsmtaProtocolDecoder decoder = new GpsmtaProtocolDecoder(null); + + verifyPosition(decoder, text( + "3085a94ef459 1446536867 49.81621 24.054207 1 0 22 0 10 12 24 0 0")); + + verifyPosition(decoder, text( + "864528021249771 1446116686 49.85073 24.004438 0 217 6 338 00 59 27 0 0")); + + verifyNotNull(decoder, text( + "359144048138856 1442932957 -49.85064 -24.003979 1 0 40 0 10 110 26 0 0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java b/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java new file mode 100644 index 000000000..7c4bb06c2 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java @@ -0,0 +1,45 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class GranitFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GranitFrameDecoder decoder = new GranitFrameDecoder(); + + assertEquals( + binary("2b525243427e1a003e2934757c57b8b03c38d279b4e61e9bd7006b000000001c00002a4533"), + decoder.decode(null, null, binary("2b525243427e1a003e2934757c57b8b03c38d279b4e61e9bd7006b000000001c00002a45330d0a"))); + + assertEquals( + binary("2b525243427e1a000d0a34757c57b8b03c38d279b4e61e9bd7006b000000001c00002a4533"), + decoder.decode(null, null, binary("2b525243427e1a000d0a34757c57b8b03c38d279b4e61e9bd7006b000000001c00002a45330d0a"))); + + assertEquals( + binary("4f4b"), + decoder.decode(null, null, binary("4f4b0d0a2b525243427e1a000d0a34757c57b8b03c38d279b4e61e9bd7006b000000001c00002a45330d0a"))); + + assertEquals( + binary("2b444441547e84003e290401d01690737c57b8903c383c7fa0e5081b64006b000000001c0000b8803c388e7fe7e5102197006c000000001c0000b8813c38ad7f02e6042035006c000000001d0000b8813c38bf7f13e6001d1e006c000000001d0000b8813c38bf7f13e6001d00006c000000001d0000b8903c38977f34e6091065006c000000001e000014002a3932"), + decoder.decode(null, null, binary("2b444441547e84003e290401d01690737c57b8903c383c7fa0e5081b64006b000000001c0000b8803c388e7fe7e5102197006c000000001c0000b8813c38ad7f02e6042035006c000000001d0000b8813c38bf7f13e6001d1e006c000000001d0000b8813c38bf7f13e6001d00006c000000001d0000b8903c38977f34e6091065006c000000001e000014002a39320d0a"))); + + assertEquals( + binary("2b444441547e84003e290401d41680747c57f8a03c38987f50e6005300006c000000001c0000f8b03c38987f50e6005300006c000000001c0000fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe14002a4346"), + decoder.decode(null, null, binary("2b444441547e84003e290401d41680747c57f8a03c38987f50e6005300006c000000001c0000f8b03c38987f50e6005300006c000000001c0000fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe14002a43460d0a"))); + + assertEquals( + binary("2b49444e543a204e6176696761746f722e30347820204669726d776172652076657273696f6e202030373132474c4e202a3231"), + decoder.decode(null, null, binary("2b49444e543a204e6176696761746f722e30347820204669726d776172652076657273696f6e202030373132474c4e202a32310d0a"))); + + assertEquals( + binary("4552524f522057524f4e4720434845434b53554d5f31"), + decoder.decode(null, null, binary("4552524f522057524f4e4720434845434b53554d5f310d0a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java new file mode 100644 index 000000000..fc75b2a53 --- /dev/null +++ b/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java @@ -0,0 +1,49 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class GranitProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + GranitProtocolDecoder decoder = new GranitProtocolDecoder(null); + + verifyPositions(decoder, binary( + "2b444441547e8400c500040130050c43495808002839aee3150200000000640000000000000008002839aee3150200000000640000000000000008002839aee3150200000000640000000000000008002839aee3150200000000640000000000000008002839aee3150200000000640000000000000008002839aee3150200000000640000000000000014002a37420d0a")); + + verifyPosition(decoder, binary( + "2b525243427e1a00c5008443495808002839aee315020000000064000000000000002a37410d0a"), + position("2016-12-08 11:27:00.000", false, 57.00888, 40.97143)); + + verifyPosition(decoder, binary( + "2b525243427e1a00c500ec904858b842283997e30002000000005e000000000d00002a32390d0a"), + position("2016-12-07 22:45:00.000", true, 57.00853, 40.97105)); + + verifyPosition(decoder, binary( + "2b525243427e1a00c500009148580800283997e30002000000005f000000000000002a33410d0a")); + + verifyPositions(decoder, binary( + "2b444441547e84003b6d0401b10e9217445800b051398f35d34a313b000072000000010b000080b051398f35d34a313b000072000000010b0000f0b051390f33314c303b900371000000010b0000f0b05139cd31e54c2f3cd0016f000000010b0000f0b051396831204d303d950071000000010b0000f0b051397530aa4d323c610171000000010b00000a002a30420d0a")); + + verifyPosition(decoder, binary( + "2b525243427e1a003e2934757c57b8b03c38d279b4e61e9bd7006b000000001c00002a4533")); + + verifyPositions(decoder, binary( + "2b444441547e84003e290401d01690737c57b8903c383c7fa0e5081b64006b000000001c0000b8803c388e7fe7e5102197006c000000001c0000b8813c38ad7f02e6042035006c000000001d0000b8813c38bf7f13e6001d1e006c000000001d0000b8813c38bf7f13e6001d00006c000000001d0000b8903c38977f34e6091065006c000000001e000014002a3932")); + + verifyPositions(decoder, binary( + "2b444441547e84003e290401d41680747c57f8a03c38987f50e6005300006c000000001c0000f8b03c38987f50e6005300006c000000001c0000fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe14002a4346")); + + // +IDNT: Navigator.04x Firmware version 0712GLN *21 + verifyAttributes(decoder, binary( + "2b49444e543a204e6176696761746f722e30347820204669726d776172652076657273696f6e202030373132474c4e202a3231")); + + // ERROR WRONG CHECKSUM_1 + verifyAttributes(decoder, binary( + "4552524f522057524f4e4720434845434b53554d5f31")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java new file mode 100644 index 000000000..f9b8f6509 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java @@ -0,0 +1,43 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Gt02ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gt02ProtocolDecoder decoder = new Gt02ProtocolDecoder(null); + + verifyAttributes(decoder, binary( + "6868150000035889905895258400831c07415045584f4b210d0a")); + + verifyAttributes(decoder, binary( + "68682d0000035889905895258400951c1f415045584572726f723a20506172616d65746572203120284f4e2f4f4646290d0a")); + + verifyAttributes(decoder, binary( + "68680f0504035889905831401700df1a00000d0a")); + + verifyAttributes(decoder, binary( + "6868130504035889905831401700001a040423261e290d0a")); + + verifyAttributes(decoder, binary( + "68681905040358899058314017000e1a010a2623211b2722252329000d0a")); + + verifyAttributes(decoder, binary( + "68681a060303588990500037252de91a010a171a191b171915191e10000d0a")); + + verifyPosition(decoder, binary( + "68682500000123456789012345000110010101010101026B3F3E026B3F3E000000000000000000010D0A"), + position("2001-01-01 01:01:01.000", true, -22.54610, -22.54610)); + + verifyAttributes(decoder, binary( + "6868110603035889905101276600001a0402292d0d0a")); + + verifyPosition(decoder, binary( + "68682500a403588990510127660001100e09060a1d1b00ade1c90b79ea3000011b000000000000050d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java new file mode 100644 index 000000000..cf6d1cfd7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java @@ -0,0 +1,51 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Gt06FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gt06FrameDecoder decoder = new Gt06FrameDecoder(); + + verifyFrame( + binary("787803691604130318491475905BD30E25001E10BBF7635D14759006E626560501CC0028660F213228660F1F2828660EA81E286610731428660F20140D0A"), + decoder.decode(null, null, binary("787803691604130318491475905BD30E25001E10BBF7635D14759006E626560501CC0028660F213228660F1F2828660EA81E286610731428660F20140D0A"))); + + verifyFrame( + binary("78780d0103563140414198583c0d0a"), + decoder.decode(null, null, binary("78780d0103563140414198583c0d0a"))); + + verifyFrame( + binary("787800691709261259400700cc0400d376714600d37a3d5000d37a3c5000d393505a00d3765d5a00d376735a00d32e6b640d0a"), + decoder.decode(null, null, binary("787800691709261259400700cc0400d376714600d37a3d5000d37a3c5000d393505a00d3765d5a00d376735a00d32e6b640d0a"))); + + verifyFrame( + binary("7878121011091c0b1e2e98058507f80097a6ac03344a0d0a"), + decoder.decode(null, null, binary("7878121011091c0b1e2e98058507f80097a6ac03344a0d0a"))); + + verifyFrame( + binary("787808171709281135331491827b75594dc8d719a9708452cad719a9708550cad719a97086521491827b75574cac9e17b308085dc8d71939633947cad71939633a480700cc0400d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a0d0a"), + decoder.decode(null, null, binary("787808171709281135331491827b75594dc8d719a9708452cad719a9708550cad719a97086521491827b75574cac9e17b308085dc8d71939633947cad71939633a480700cc0400d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a0d0a"))); + + verifyFrame( + binary("787808134606020002044dc5050d0a"), + decoder.decode(null, null, binary("787808134606020002044dc5050d0a"))); + + verifyFrame( + binary("78781f1210020e14061dcc0476fcd0003e3faf3e14b20000000000000000044ef6740d0a"), + decoder.decode(null, null, binary("78781f1210020e14061dcc0476fcd0003e3faf3e14b20000000000000000044ef6740d0a"))); + + verifyFrame( + binary("78780d010352887071911998000479d00d0a"), + decoder.decode(null, null, binary("78780d010352887071911998000479d00d0a"))); + + verifyFrame( + binary("78782516000000000000c000000000000000000020000900fa0210ef00fb620006640301000468030d0a"), + decoder.decode(null, null, binary("78782516000000000000c000000000000000000020000900fa0210ef00fb620006640301000468030d0a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java new file mode 100644 index 000000000..a6008e682 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -0,0 +1,294 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class Gt06ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gt06ProtocolDecoder decoder = new Gt06ProtocolDecoder(null); + + verifyNull(decoder, binary( + "787805120099abec0d0a")); + + verifyNull(decoder, binary( + "78780D01086471700328358100093F040D0A")); + + verifyPosition(decoder, binary( + "787821121303120b2524c70138e363085b549003d43301940057d200cd52c000006aa1ca0d0a")); + + verifyAttribute(decoder, binary( + "7878251613020C12141AC5027951430C2A16F60014000900000000001A00007C550300020002F1E70D0A"), + Position.KEY_ALARM, Position.ALARM_REMOVING); + + verifyNotNull(decoder, binary( + "7878006919012105090303028f01007549e05a00bc9c5c5a007a8d1a5a0d0a")); + + verifyNotNull(decoder, binary( + "7878001719011910543607028f0100bc2e695a00bcb3635a00bc27c56400bc447b6400bc46c96400bc33ce6400bc64ca640d0a")); + + verifyAttributes(decoder, binary( + "797900de8c120b1502121b013137333d302c3232333d312c3238333d30303030303030302c3436333d30303030303035362c3437333d30303030303030662c3438333d30303030303031312c3242333d30303030303030302c3244333d30303030313839632c3335333d30303030313661382c3336333d30303032386163382c3339333d30303030303230612c3330333d30303030303561612c3439333d30303030303030302c3441333d4b4e4146323431434d4b353031343235352c3341333d30303030303338352c3530333d30303030c0041df0940f89c06700000000c800910d0a")); + + verifyAttributes(decoder, binary( + "79790020940A035985708053908307060104900402788950301217070401538F0003E8210D0A")); + + verifyPosition(decoder, binary( + "78783c3439000000120a0902093a07031f9e690529be2e00155500000016214901a30308b70000b3fb004aa82b059401a3422100000001000000007d9370b90d0a")); + + verifyAttributes(decoder, binary( + "7878079404eb001c705d0d0a")); + + verifyNotNull(decoder, binary( + "78781219028f0a29e10036f12003040102000875dc0d0a")); + + verifyAttributes(decoder, binary( + "79790008940000ed0289d6860d0a")); + + verifyNull(decoder, binary( + "797900a59404414c4d313d34353b414c4d323d44353b414c4d333d35353b535441313d34303b4459443d30313b534f533d303538353036313536372c2c3b43454e5445523d3b46454e43453d46656e63652c4f46462c302c302e3030303030302c302e3030303030302c3330302c494e206f72204f55542c303b49434349443d38393937313033313031303038393539303432463b4d4f44453d4d4f44452c312c3138303b0008f65e0d0a")); + + verifyPosition(decoder, binary( + "78782222120616083817c5050cc8c801a819d600152400e8011dbf003332000000004862500d0a")); + + verifyAttributes(decoder, binary( + "78780B23C00122040001000818720D0A")); + + verifyNotNull(decoder, binary( + "78782EA4110C0C02281BF6026C18720C38D22800149C1181CC00010000260E000000000615F8012C05041102FF001058FD0D0A")); + + verifyNotNull(decoder, binary( + "78787aa2110c0e06372c813601040000591200000000009d7c01040000591200000000009d7c01040000591200000000009d7c01040000591200000000009d7c01040000591200000000009d7c01040000591200000000009d7c01040000591200000000009d7c0104ff02001801eb4039d10000000000000004fabeb50d0a")); + + verifyNotNull(decoder, binary( + "78782727110c0b0e170f850450059107f461ae001c7e0a81360104cb8a00bef32806030c02ff000316b10d0a")); + + verifyNotNull(decoder, binary( + "78782322110c070f1b0270000000000000000000040081360104cb8a00bef3000000000523030d0a")); + + verifyNotNull(decoder, binary( + "787880a2110b161010140136040000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c01020000591200000000009d7c0102ff033c1e04ddc28aa6001801eb4039c90000000000000014db84730d0a")); + + verifyNotNull(decoder, binary( + "78782ba701cc000000919100000000090617032b3836313832323038343735363200000000000000000100049fb60d0a")); + + verifyNotNull(decoder, binary( + "787819a501cc0000009191000000000906170304050400010005f44d0d0a")); + + verifyNotNull(decoder, binary( + "78782ca3110b10081336f000000000000000000004003901cc0000009191000000000906170304050400010003e0940d0a")); + + verifyNotNull(decoder, binary( + "7878A3A2110B0603201501CC010000254E000000000615F804000000254E000000000615F804000000254E000000000615F804000000254E000000000615F804000000254E000000000615F804000000254E000000000615F804000000254E000000000615F80400FF08F483CD4DF4C0D750BD5F8BC5CECFB0D59DAFB459CDA8574E8424C6CC50BD5F6C7E1CC9B0D59D8AA718C90087363040E0C83496727B4DE4C7002919670D0A")); + + verifyNotNull(decoder, binary( + "78786CA1110B0413093801CC01000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201000025FC000000000618C10201FF0002000541D70D0A")); + + verifyPosition(decoder, binary( + "787822220F0C1D023305C9027AC8180C46586000140001CC00287D001F71000001000820860D0A")); + + verifyAttributes(decoder, binary( + "797900262100000000020043006f006d006d0061006e00640020006500720072006f0072002100236e850d0a")); + + verifyNotNull(decoder, binary( + "787803691604130318491475905BD30E25001E10BBF7635D14759006E626560501CC0028660F213228660F1F2828660EA81E286610731428660F20140D0A")); + + verifyNotNull(decoder, binary( + "787800691710231108500200cc080c4e2fa5640c4e2fa66e0d0a")); + + verifyNotNull(decoder, binary( + "787800171710231108290200cc080c4e2fa5640c4e2fa5640d0a")); + + verifyNotNull(decoder, binary( + "787800691710231109200400cc080c4e2fa55a0c4ec0025a0c4e2fa6640c583918640d0a")); + + verifyNotNull(decoder, binary( + "787800691710231111210700cc080c4e2fa55a0c4ec0025a0c4e39295a0c583918640c4e2fa6640c4e2fa4640c4ec854640d0a")); + + verifyNotNull(decoder, binary( + "787800171710231112510600cc080c4e2fa55a0c4e2fa55a0c4e2fa55a0c4e2fa55a0c4e2fa55a0c4e2fa55a0d0a")); + + verifyPosition(decoder, binary( + "7878121011091c0b1b2999058508040097a89e0034520d0a")); + + verifyNotNull(decoder, binary( + "78780869170928113413ac9e17b30808514494fcf6e148596cb0ce2c67bd4a6eb0ce2c67bd4b0018e7d4333e55ec086be7f2df5fe48d8c94fc6657e48d8cb8f378510600cc0400d37a3d4600d37a3c5000d37a3b6400d376716400d305ac6400d393506e0d0a")); + + verifyNotNull(decoder, binary( + "787808171709281135331491827b75594dc8d719a9708452cad719a9708550cad719a97086521491827b75574cac9e17b308085dc8d71939633947cad71939633a480700cc0400d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a00d37a3d5a0d0a")); + + verifyNotNull(decoder, binary( + "78783b281108111002050136041bcf0000bf09000000000000000000000000000000000000000000000000000000000000000000000000ff00020007d3280d0a")); + + verifyNotNull(decoder, binary( + "7878412c11030b011c1f013604cb8a00b17754cb8a00bef357cb8a00b73f5fcb8900b0e25fcb8900b6655fcb8a00b74960cb8a00b178620701001801eb40393800bbbde10d0a")); + + verifyNotNull(decoder, binary( + "7878412c11030b012629013604cb8a00b17757cb8a00b73f5bcb8a00b7495ecb8900b0e25fcb8a00b1b9620000000000ff0000000000ffff01001801eb40393e00c0e6340d0a")); + + verifyPosition(decoder, binary( + "787822221106160a1016c60278019407c7783800040001940504700046fc01030100065f570d0a")); + + verifyAttributes(decoder, binary( + "797900143311070609020b00000000a0030046000109e4610d0a")); + + verifyAttributes(decoder, binary( + "7979003e32110707083819000901fe0a060f006a1e3f24000000000000000000000000000000000000000000000000000000000000000000000000000000012116ba0d0a")); + + verifyAttributes(decoder, binary( + "7979007632110706090217000901fe0a060f006a1c2024060f0053a429060f006a1d21060f0053a720060f006f151d0000000000000000000000003844d9e7f7e1773d60e327a9e442405cf28628b9c640a42bb0fc0d0244d855a38c220a4c802aa8da7dab50b0e235ef32dd5348ee0ce77a52540000010a205a0d0a")); + + verifyAttributes(decoder, binary( + "7979006f210000000001426174746572793a352e3536562c4e4f524d414c3b20475052532a4c696e6b2055702047534d205369676e616c204c6576656c3a5374726f6e673b204750533a4f46463b2020204c4f434b3a4f46463b204254204d41433a4234413832383034343436323b007260880d0a")); + + verifyPosition(decoder, binary( + "7979004a321106170c1b180cc900a875580b7ab4f00010350901fe0a007c0009112424007c000912240081004efe2100c500100f1200000000000000000000000000000000000000000000bc7c900d0a")); + + verifyNotNull(decoder, binary( + "79790045321106170c1b13000901fe0a007c0009112424007c000912230081004efe1e00c500100f120000000000000000000000000000000000000710bef565574e37000000b26f140d0a")); + + verifyNull(decoder, binary( + "787811010863586038760942a0010000010aa4000d0a")); + + verifyNull(decoder, binary( + "78781f3511061a0b24330503107d06084889cb01000100000cfa20e3acd301333fcb0d0a")); + + verifyPosition(decoder, binary( + "78783c340000000011061809130c0903107d2408488a5800144c00000000000001940b00b1000047ff000000000500018f42210000000100050003010b69450d0a")); + + verifyPosition(decoder, binary( + "78783c34000000001106190336070903107d51084889b900152e0000000043b101940b00b10000480100000000050001a3422100000001000300011bdc7b5f0d0a")); + + verifyAttributes(decoder, binary( + "78780a13c40604000201298f5b0d0a")); + + verifyNotNull(decoder, binary( + "78781f12110616091835d0024bb93007d3fb783dd4c501940500f2006c8504a6e0370d0a")); + + verifyPosition(decoder, binary( + "787822221106160a1016c60278019407c7783800040001940504700046fc01030100065f570d0a")); + + verifyNotNull(decoder, binary( + "7878661500000000004459443d537563636573732100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010009e82b0d0a")); + + verifyAttributes(decoder, binary( + "7979000894000000000338ba0d0a")); + + verifyAttributes(decoder, binary( + "79790020940a03516080825457290502194200448892980691312079088572f50004d4350d0a")); + + verifyPosition(decoder, binary( + "7979007121000000000143757272656e7420706f736974696f6e214c61743a4e35342e3733393333322c4c6f6e3a4532352e3237333237302c436f757273653a3132362e35332c53706565643a302e303030302c4461746554696d653a323031372d30352d3236202031303a32373a3437000bbee30d0a")); + + verifyAttributes(decoder, binary( + "7979003F940D110315102A202141494F494C2C30322C3030382E3239302C3032392E3630302C3531394A2C303430302C3030382E3433302C302C30302C4142001678EA0D0A")); + + verifyAttributes(decoder, binary( + "79790039940d2141494f494c2c30322c3030322e3732302c3032392e3530302c3532344a2c303130302c3030332e3430302c302c30302c393309ad72000d0a")); + + verifyNull(decoder, binary( + "79790005840016BB1A0D0A")); + + verifyAttributes(decoder, binary( + "797900089400000002e852d70d0a")); + + verifyAttributes(decoder, binary( + "7979000794050000c9b63e0d0a")); + + verifyNotNull(decoder, binary( + "78783b18100c0f1201010195271784005ab63617840002fa47178400ff8f4817840019f3491784005ab54b178400ff8e4c17840019f24cff0002012287c80d0a")); + + verifyPosition(decoder, binary( + "7878251610051b0f1c34c5022515d504b5dcd20738080902d4022bdf009cba5006640201006759680d0a")); + + verifyNotNull(decoder, binary( + "787866150000000000416c726561647920696e20746865207374617465206f66206675656c20737570706c7920746f20726573756d652c74686520636f6d6d616e64206973206e6f742072756e6e696e672100000000000000000000000000000000000001001981e50d0a")); + + verifyAttributes(decoder, binary( + "78782d152500000000437574206f666620746865206675656c20737570706c793a2053756363657373210002013b898a0d0a")); + + verifyAttributes(decoder, binary( + "787829152100000000526573746f7265206675656c20737570706c793a2053756363657373210002014077ce0d0a")); + + verifyNull(decoder, binary( + "78780D01012345678901234500018CDD0D0A")); + + verifyNull(decoder, binary( + "78780d0103534190360660610003c3df0d0a")); + + verifyAttributes(decoder, binary( + "78780a13440604000201baaf540d0a")); + + verifyAttributes(decoder, binary( + "787825160F0C1D0A2B21C8027AC8040C46581000146F0901CC00287D001F714804040301001C84CF0D0A")); + + verifyPosition(decoder, binary( + "78781f120f0a140e150bc505e51e780293a9e800540000f601006e0055da00035f240d0a"), + position("2015-10-20 14:21:11.000", true, 54.94535, 24.01762)); + + verifyPosition(decoder, binary( + "787823120f081b121d37cb01c8e2cc08afd3c020d50201940701d600a1190041ee100576d1470d0a")); + + verifyPosition(decoder, binary( + "78781F120B081D112E10CC027AC7EB0C46584900148F01CC00287D001FB8000380810D0A")); + + verifyPosition(decoder, binary( + "787819100B031A0B1B31CC027AC7FD0C4657BF0115210001001CC6070D0A")); + + verifyPosition(decoder, binary( + "787821120C010C0F151FCF027AC8840C4657EC00140001CC00287D001F720001000F53A00D0A")); + + verifyPosition(decoder, binary( + "787825160B051B093523CF027AC8360C4657B30014000901CC00266A001E1740050400020008D7B10D0A")); + + verifyPosition(decoder, binary( + "787819100e010903230ec803ae32a60653cded00180000020072feb70d0a")); + + verifyPosition(decoder, binary( + "7878471e0e03110b0511c501c664fd074db73f0218a602e003433a002fed40433a0056e14e433a0056104e433a0056fd53433a002eed55433a007e4b57433a002ee25aff00020120f6720d0a")); + + verifyNull(decoder, binary( + "7979005bfd0358899050927725004c0020bf984358df603b2ea3a339e54335013a5b56455253494f4e5d47543036445f32305f3630444d325f423235455f5631355f574d5b4255494c445d323031332f31322f32382031353a3234002a3b240d0a7979005bfd0358899050927725004c0020bf984358df603b2ea3a339e54335013a5b56455253494f4e5d47543036445f32305f3630444d325f423235455f5631355f574d5b4255494c445d323031332f31322f32382031353a3234002d4f9b0d0a7979005bfd0358899050927725004c0020bf984358df603b2ea3a339e54335013a5b56455253494f4e5d47543036445f32305f3630444d325f423235455f5631355f574d5b4255494c445d323031332f31322f32382031353a3234003084ff0d0a")); + + verifyNull(decoder, binary( + "78788b818300000000534545464e2626004f04220045042626262b37393035343031353534362626262626260410041b0415041a04210415041926262b373930363433333031313526260410043d044f26262b373936303437383430363426260412043e0432043026262b373932383834373738383126262626262626262626262626262626232300020022155d0d0a")); + + verifyPosition(decoder, binary( + "787822220e0914160f07c9021a362805090a7800d8b802d402c30e00a98a0105010213f4bb0d0a")); + + verifyNull(decoder, binary( + "787811010864717003664467100f190a0002c6d20d0a")); + + verifyNull(decoder, binary( + "787811010123456789012345100B3201000171930D0A")); + + verifyNull(decoder, binary( + "78780d1f000000000000000200b196a20d0a")); + + verifyPosition(decoder, binary( + "78781f12110819110216d402f250340828924055d4c801944600d300c09501429c830d0a")); + + verifyPosition(decoder, binary( + "78782516110819110208d402f264dc08289a4058d4c70901944600d300c0954606040600014057e90d0a")); + + verifyNull(decoder, binary( + "78780d010359339075005244340d0a")); + + verifyNotNull(decoder, binary( + "787800691709261259400700cc0400d376714600d37a3d5000d37a3c5000d393505a00d3765d5a00d376735a00d32e6b640d0a")); + + verifyNull(decoder, binary( + "787801080d0a")); + + verifyNull(decoder, binary( + "78782E2A0F0C1D071139CA027AC8000C4658000014D83132353230313335333231373730373900000000000001002A6ECE0D0A")); + + verifyNull(decoder, binary( + "7878058A000688290D0A")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java new file mode 100644 index 000000000..aceaef434 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class Gt06ProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + Gt06ProtocolEncoder encoder = new Gt06ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + verifyCommand(encoder, command, binary("787812800c0000000052656c61792c312300009dee0d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java new file mode 100644 index 000000000..cb792ba09 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Gt30ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Gt30ProtocolDecoder decoder = new Gt30ProtocolDecoder(null); + + verifyPosition(decoder, text( + "$$005D3037811014 9955102834.000,A,3802.8629,N,02349.7163,E,0.00,,060117,,*13|1.3|26225BD")); + + verifyPosition(decoder, text( + "$$005E3037811014 9999\u0003121909.000,A,3802.9133,N,02349.9354,E,0.00,,060117,,*18|1.8|264518B")); + + verifyPosition(decoder, text( + "$$00633037811014 9999\u0002121901.000,A,3802.9137,N,02349.9334,E,2.86,18.16,060117,,*3E|1.8|262D752")); + + verifyPosition(decoder, text( + "$$005E3037811014 9999\u0001121849.000,A,3802.9094,N,02349.9384,E,0.00,,060117,,*1C|1.2|2683812")); + + verifyPosition(decoder, text( + "$$005B3037811124 9955161049.000,A,3802.9474,N,02241.1897,E,0.00,,021115,,*15|2.9|5A639")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java b/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java new file mode 100644 index 000000000..bdb2ff37b --- /dev/null +++ b/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java @@ -0,0 +1,71 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class H02FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecodeShort() throws Exception { + + H02FrameDecoder decoder = new H02FrameDecoder(0); + + assertEquals( + binary("2a48512c3335353438383032303131333931312c56312c3031323934352c412c353233312e37393238332c4e2c30313332342e31303731382c452c302e30352c302c3137303231372c464646464646464623"), + decoder.decode(null, null, binary("2a48512c3335353438383032303131333931312c56312c3031323934352c412c353233312e37393238332c4e2c30313332342e31303731382c452c302e30352c302c3137303231372c4646464646464646230d0a"))); + + assertEquals( + binary("2441060116601245431311165035313006004318210e000000fffffbffff0024"), + decoder.decode(null, null, binary("2441060116601245431311165035313006004318210e000000fffffbffff0024"))); + + assertEquals( + binary("2441060116601245431311165035313006004318210e000000fffffbffff0024"), + decoder.decode(null, null, binary("2441060116601245431311165035313006004318210e000000fffffbffff00242a48512c343130363031313636302c56312c3132343535322c412c353033352e333132392c4e2c30303433312e383231312c452c3030302e32302c3030302c3133313131362c464646464642464623"))); + + assertEquals( + binary("2a48512c3335333538383036303031353536382c56312c3139333530352c412c3830392e303031302c532c333435342e383939372c572c302e30302c302e30302c3239313031332c65666666666266662c3030303264342c3030303030622c3030353338352c3030353261612c323523"), + decoder.decode(null, null, binary("2a48512c3335333538383036303031353536382c56312c3139333530352c412c3830392e303031302c532c333435342e383939372c572c302e30302c302e30302c3239313031332c65666666666266662c3030303264342c3030303030622c3030353338352c3030353261612c323523"))); + + assertEquals( + binary("24430025645511183817091319355128000465632432000100ffe7fbffff0000"), + decoder.decode(null, null, binary("24430025645511183817091319355128000465632432000100ffe7fbffff0000"))); + + } + + @Test + public void testDecodeLong() throws Exception { + + H02FrameDecoder decoder = new H02FrameDecoder(0); + + assertEquals( + binary("24410600082621532131081504419390060740418306000000fffffbfdff0015060000002c02dc0c000000001f"), + decoder.decode(null, null, binary("24410600082621532131081504419390060740418306000000fffffbfdff0015060000002c02dc0c000000001f"))); + + } + + @Test + public void testDecodeAlternative() throws Exception { + + H02FrameDecoder decoder = new H02FrameDecoder(0); + + assertEquals( + binary("2a48512c343230363131393133302c4e42522c3130323430332c3233382c312c302c372c313131312c323236342c36332c313131312c323236352c35382c313131312c323236362c35302c313131312c333133352c33372c313131312c3630352c33332c313131312c343932302c33302c313131312c3630372c32382c3131303131372c46464646444646462c3623"), + decoder.decode(null, null, binary("2a48512c343230363131393133302c4e42522c3130323430332c3233382c312c302c372c313131312c323236342c36332c313131312c323236352c35382c313131312c323236362c35302c313131312c333133352c33372c313131312c3630352c33332c313131312c343932302c33302c313131312c3630372c32382c3131303131372c46464646444646462c3623"))); + + assertEquals( + binary("2442061191301024031101175540227006012321670c000095fffffbffff001f00000001f800ee010000000032"), + decoder.decode(null, null, binary("2442061191301024031101175540227006012321670c000095fffffbffff001f00000001f800ee010000000032"))); + + assertEquals( + binary("5800009814991024031101175540227006012321670c000095fffffbffff0033"), + decoder.decode(null, null, binary("5800009814991024031101175540227006012321670c000095fffffbffff0033"))); + + assertEquals( + binary("2a48512c343230363131393133302c4e42522c3130323431362c3233382c312c302c372c313131312c323236342c35332c313131312c323236352c36302c313131312c323236362c34342c313131312c333133352c34332c313131312c3630352c33392c313131312c343932302c32392c313131312c3630372c32342c3131303131372c46464646464246462c3623"), + decoder.decode(null, null, binary("2a48512c343230363131393133302c4e42522c3130323431362c3233382c312c302c372c313131312c323236342c35332c313131312c323236352c36302c313131312c323236362c34342c313131312c333133352c34332c313131312c3630352c33392c313131312c343932302c32392c313131312c3630372c32342c3131303131372c46464646464246462c3623"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java new file mode 100644 index 000000000..4a5eadf52 --- /dev/null +++ b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java @@ -0,0 +1,261 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class H02ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + H02ProtocolDecoder decoder = new H02ProtocolDecoder(null); + + verifyNotNull(decoder, buffer( + "*hq,356327081001239,VP1,V,470,002,92,3565,0Y92,19433,30Y92,1340,29#")); + + verifyPosition(decoder, binary( + "2435248308419329301047591808172627335900074412294E024138FEFFFFFFFF01120064BA73005ECC")); + + verifyPosition(decoder, buffer( + "*HQ,4210209006,V1,054048,A,2828.2297,N,07733.4332,E,000.5,047,4,080918,EEE7FBDF,4261193,0#")); + + verifyPosition(decoder, buffer( + "*HQ,353505221264507,V2,100220,0,5238.26259,N,00507.33983,E,0.25,0,280917,FFFFFFFF,cc,28, db,d75b#")); + + verifyPosition(decoder, buffer( + "*HQ,,V1,173212,A,2225.78879,S,02829.19021,E,0.00,0,290418,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,353505221264507,VI1,075146,0,5238.25900,N,00507.33429,E,0.54,0,250917,FFFFFFFF,cc,28, db,d75b#")); + + verifyNull(decoder, buffer( + "*HQ,353505510948929,V1,,V,,N,,E,0.00,0,,FFFFF7FF,f0,a,11a0,c0c6#")); + + verifyPosition(decoder, buffer( + "*hq,356327080425330,VP1,A,2702.7245,S,15251.9311,E,0.48,0.0000,080917#")); + + verifyPosition(decoder, buffer( + "*HQ,4209951296,V19,214452,A,5201.0178,N,01830.5029,E,000.00,000,200417,,195.63.13.195,89480610500392633029,BFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*hq,356327080425330,VP1,A,2702.7215,S,15251.9309,E,0.62,0.0000,050917#")); + + verifyNull(decoder, buffer( + "*HQ,356327080425330,XT,1,100#")); + + verifyAttributes(decoder, buffer( + "*HQ,353111080001055,V3,044855,28403,01,001450,011473,158,-62,0292,0,X,030817,FFFFFBFF#")); + + verifyPosition(decoder, binary( + "2442091341332059572807175137358006000183640e000000fffffbfdff001f080000000000ea1e0000000021")); + + verifyNull(decoder, buffer( + "*HQ,4109198974,#")); + + verifyAttributes(decoder, buffer( + "*HQ,1700086468,LINK,180902,15,0,84,0,0,240517,FFFFFBFF#")); + + verifyAttributes(decoder, buffer( + "*HQ,355488020882405,V3,095426,74001,01,010278,045142,128,-92,02DE,0,X,090517,FFFFFBFF#")); + + verifyAttributes(decoder, buffer( + "*HQ,355488020882405,V3,095426,74001,04,010278,045142,128,-92,010278,026311,125,,010278,026582,125,,010278,028322,119,,02DD,0,X,090517,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,4109179024,V19,181519,V,3853.2587,S,06205.9175,W,000.00,000,090217,,5492932630888,8954315265044716555?,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,8161289587,V1,181933,A,5444.3994,N,02516.3844,E,000.05,000,090317,FFFFBBFF,246,03,00002,41565#")); + + verifyPosition(decoder, binary( + "2421305109380127171003170520046500100286297e003085ffffdfffff03440069129344006400001151415a20")); + + verifyPosition(decoder, buffer( + "*HQ,2130510938,V1,012632,A,0520.0663,N,10028.6324,E,0.286,023,100317,FFFFDFFF,69129336,0,100.0,18,5141,5A20#")); + + verifyPosition(decoder, buffer( + "*HQ,4210209006,V1,201812,A,2608.9437,N,08016.2521,W,000.80,000,150317,EFE7F9FF,310,260,0,0,6#")); + + verifyPosition(decoder, buffer( + "*HQ,4210209006,V1,201844,A,2608.9437,N,08016.2521,W,000.80,000,150317,FFFFF9FF,310,260,0,0,6#")); + + verifyPosition(decoder, buffer( + "*HQ,4109179024,V19,103732,V,3853.2770,S,06205.8678,W,000.00,000,100217,,5492932630888,8954314165044716555?,FFFFFBFF#")); + + verifyAttributes(decoder, buffer( + "*HQ,4109179024,NBR,103732,722,310,0,6,8106,32010,23,8101,22007,25,8106,12010,23,8106,22105,22,8101,22012,16,8106,42010,5,100217,FFFFFBFF,5#")); + + verifyAttributes(decoder, buffer( + "*HQ,355488020930796,V3,002339,62160,06,024852,035421,148,0,024852,035425,143,,022251,036482,137,,024852,000335,133,,024852,031751,133,,024852,035423,133,,02A1,0,X,010104,EFE7FBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,4106012736,V1,224434,A,1827.3855,N,06705.7577,W,000.00,000,100117,FFFFFBFF,310,260,49101,1753,5#")); + + verifyAttributes(decoder, buffer( + "*HQ,4208150188,NBR,210249,260,6,0,7,1014,50675,37,1014,50633,27,1014,17933,18,1014,17231,15,1014,50632,12,1014,13211,11,1014,17031,10,281216,FFFFFBFF,2#")); + + verifyAttributes(decoder, buffer( + "*HQ,1600068812,NBR,141335,262,02,255,6,431,17003,26,431,11101,13,431,6353,13,431,22172,13,431,11093,13,431,60861,10,151216,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,353588020068342,V1,084436,A,3257.01525,N,00655.03865,W,57.78,40,011216,FFFBFFFF,25c,a, 154,b04c#")); + + verifyNull(decoder, buffer( + "*HQ,356803210091319,BS,,2d4,a,1b63,1969,26,1b63,10b2,31,0,0,25,,ffffffff,60#")); + + verifyAttributes(decoder, buffer( + "*HQ,1400046168,NBR,160169,460,0,1,4,9338,3692,150,9338,3691,145,9338,3690,140,9338,3692,139,180813,FFFFFBFF#")); + + verifyAttributes(decoder, buffer( + "*HQ,1600068860,NBR,120156,262,03,255,6,802,54702,46,802,5032,37,802,54782,30,802,5052,28,802,54712,12,802,5042,12,081116,FFFFFBFF#")); + + verifyAttributes(decoder, buffer( + "*HQ,1600068860,NBR,110326,262,03,255,6,802,23152,23,812,49449,14,802,35382,13,802,35402,11,812,56622,09,802,23132,04,081116,FFFFFBFF#")); + + verifyAttributes(decoder, buffer( + "*HQ,1600068860,LINK,112137,20,8,67,0,0,081116,FFFFFBFF#")); + + verifyAttributes(decoder, buffer( + "*HQ,355488020533263,V3,121536,65501,04,000152,014001,156,-64,000161,010642,138,,000152,014003,129,,000152,013973,126,,02E4,0,X,071116,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,4209917484,V19,093043,V,5052.9749,N,00426.4322,E,000.00,000,130916,,0032475874141,8944538530000543700F,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,353505220873067,V1,,V,4605.75732,N,01430.73863,E,0.00,0,,FFFFFFEF,125,194, 64,d3#")); + + verifyPosition(decoder, buffer( + "*HQ,4210051415,V1,164549,A,0956.3869,N,08406.7068,W,000.00,000,221215,FFFFFBFF,712,01,0,0,6#"), + position("2015-12-22 16:45:49.000", true, 9.93978, -84.11178)); + + verifyAttributes(decoder, buffer( + "*HQ,1451316451,NBR,112315,724,10,2,2,215,2135,123,215,2131,121,011215,FFFFFFFF#")); + + verifyPosition(decoder, buffer( + "*HQ,1451316485,V1,121557,A,-23-3.3408,S,-48-2.8926,W,0.1,158,241115,FFFFFFFF#")); + + verifyPosition(decoder, buffer( + "*HQ,1451316485,V1,121557,A,-23-35.3408,S,-48-2.8926,W,0.1,158,241115,FFFFFFFF#")); + + verifyPosition(decoder, buffer( + "*HQ,355488020119695,V1,050418,,2827.61232,N,07703.84822,E,0.00,0,031015,FFFEFBFF#"), + position("2015-10-03 05:04:18.000", false, 28.46021, 77.06414)); + + verifyPosition(decoder, buffer( + "*HQ,1451316409,V1,030149,A,-23-29.0095,S,-46-51.5852,W,2.4,065,070315,FFFFFFFF#"), + position("2015-03-07 03:01:49.000", true, -23.48349, -46.85975)); + + verifyNull(decoder, buffer( + "*HQ,353588020068342,V1,000000,V,0.0000,0,0.0000,0,0.00,0.00,000000,ffffffff,000106,000002,000203,004c87,16#")); + + verifyPosition(decoder, buffer( + "*HQ,3800008786,V1,062507,V,3048.2437,N,03058.5617,E,000.00,000,250413,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,4300256455,V1,111817,A,1935.5128,N,04656.3243,E,0.00,100,170913,FFE7FBFF#")); + + verifyPosition(decoder, buffer( + "*HQ,123456789012345,V1,155850,A,5214.5346,N,2117.4683,E,0.00,270.90,131012,ffffffff,000000,000000,000000,000000#")); + + verifyPosition(decoder, buffer( + "*HQ,353588010001689,V1,221116,A,1548.8220,S,4753.1679,W,0.00,0.00,300413,ffffffff,0002d4,000004,0001cd,000047#")); + + verifyPosition(decoder, buffer( + "*HQ,354188045498669,V1,195200,A,701.8915,S,3450.3399,W,0.00,205.70,050213,ffffffff,000243,000000,000000#")); + + verifyPosition(decoder, buffer( + "*HQ,2705171109,V1,213324,A,5002.5849,N,01433.7822,E,0.00,000,140613,FFFFFFFF#")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V1,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,FFFFFBFF#\r\n")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V4,S17,130305,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V4,S14,100,10,1,3,130305,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V4,S20,ERROR,130305,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V4,S20,DONE,130305,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,F7FFFBFF#")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V4,R8,ERROR,130305,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V4,S23,165.165.33.250:8800,130305,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V4,S24,thit.gd,130305,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,FFFFFBFF#")); + + verifyPosition(decoder, buffer( + "*TH,2020916012,V4,S1,OK,pass_word,130305,050316,A,2212.8745,N,11346.6574,E,14.28,028,220902,FFFFFBFD#")); + + verifyPosition(decoder, buffer( + "*HQ,353588020068342,V1,062840,A,5241.1249,N,954.9490,E,0.00,0.00,231013,ffffffff,000106,000002,000203,004c87,24#")); + + verifyPosition(decoder, buffer( + "*HQ,353505220903211,V1,075228,A,5227.5039,N,01032.8443,E,0.00,0,231013,FFFBFFFF,106,14, 201,2173#")); + + verifyPosition(decoder, buffer( + "*HQ,353505220903211,V1,140817,A,5239.3538,N,01003.5292,E,21.03,312,221013,FFFBFFFF,106,14, 203,1cd#")); + + verifyPosition(decoder, buffer( + "*HQ,356823035368767,V1,083618,A,0955.6392,N,07809.0796,E,0.00,0,070414,FFFBFFFF,194,3b5, 71,c9a9#")); + + verifyNull(decoder, buffer( + "*HQ,8401016597,BASE,152609,0,0,0,0,211014,FFFFFFFF#")); + + verifyPosition(decoder, binary( + "2441060116601245431311165035313006004318210e000000fffffbffff0024")); + + verifyPosition(decoder, binary( + "24410600082621532131081504419390060740418306000000fffffbfdff0015060000002c02dc0c000000001f"), + position("2015-08-31 21:53:21.000", true, 4.69898, -74.06971)); + + verifyPosition(decoder, binary( + "2427051711092133391406135002584900014337822e000000ffffffffff0000")); + + verifyPosition(decoder, binary( + "2427051711092134091406135002584900014337822e000000ffffffffff0000")); + + verifyPosition(decoder, binary( + "2410307310010503162209022212874500113466574C014028fffffbffff0000")); + + verifyPosition(decoder, binary( + "2441090013450831250401145047888000008554650e000000fffff9ffff001006000000000106020299109c01")); + + verifyPosition(decoder, binary( + "24270517030820321418041423307879000463213792000056fffff9ffff0000")); + + verifyPosition(decoder, binary( + "2441091144271222470112142233983006114026520E000000FFFFFBFFFF0014060000000001CC00262B0F170A")); + + verifyPosition(decoder, binary( + "24971305007205201916101533335008000073206976000000effffbffff000252776566060000000000000000000049")); + + } + + @Test + public void testDecodeStatus() throws Exception { + + H02ProtocolDecoder decoder = new H02ProtocolDecoder(null); + + verifyAttribute(decoder, buffer( + "*HQ,2705171109,V1,213324,A,5002.5849,N,01433.7822,E,0.00,000,140613,FFFFFFFF#"), + Position.KEY_STATUS, 0xFFFFFFFFL); + + verifyAttribute(decoder, binary( + "2441091144271222470112142233983006114026520E000000FFFFFBFFFF0014060000000001CC00262B0F170A"), + Position.KEY_STATUS, 0xFFFFFBFFL); + + verifyAttribute(decoder, buffer( + "*HQ,4210051415,V1,164549,A,0956.3869,N,08406.7068,W,000.00,000,221215,FFFFFBFF,712,01,0,0,6#"), + Position.KEY_STATUS, 0xFFFFFBFFL); + + } + +} diff --git a/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java new file mode 100644 index 000000000..a7ce3fc7e --- /dev/null +++ b/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java @@ -0,0 +1,72 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.util.Date; + +import static org.junit.Assert.assertEquals; + +public class H02ProtocolEncoderTest extends ProtocolTest { + + private H02ProtocolEncoder encoder = new H02ProtocolEncoder(); + private Date time = Date.from( + LocalDateTime.of(LocalDate.now(), LocalTime.of(1, 2, 3)).atZone(ZoneOffset.systemDefault()).toInstant()); + + @Test + public void testAlarmArmEncode() throws Exception { + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ALARM_ARM); + + assertEquals("*HQ,123456789012345,SCF,010203,0,0#", encoder.encodeCommand(command, time)); + } + + @Test + public void testAlarmDisarmEncode() throws Exception { + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ALARM_DISARM); + + assertEquals("*HQ,123456789012345,SCF,010203,1,1#", encoder.encodeCommand(command, time)); + } + + @Test + public void testEngineStopEncode() throws Exception { + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + assertEquals("*HQ,123456789012345,S20,010203,1,1#", encoder.encodeCommand(command, time)); + } + + @Test + public void testEngineResumeEncode() throws Exception { + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_RESUME); + + assertEquals("*HQ,123456789012345,S20,010203,1,0#", encoder.encodeCommand(command, time)); + } + + @Test + public void testPositionPeriodicEncode() throws Exception { + + Command command = new Command(); + command.setDeviceId(1); + command.set(Command.KEY_FREQUENCY, 10); + command.setType(Command.TYPE_POSITION_PERIODIC); + + assertEquals("*HQ,123456789012345,S71,010203,22,10#", encoder.encodeCommand(command, time)); + } + +} diff --git a/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java new file mode 100644 index 000000000..6d879daf2 --- /dev/null +++ b/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java @@ -0,0 +1,28 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class HaicomProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + HaicomProtocolDecoder decoder = new HaicomProtocolDecoder(null); + + verifyPosition(decoder, text( + "$GPRS012497007097169,T100001,150618,230031,5402267400332464,0004,2014,000001,,,1,00#V040*"), + position("2015-06-18 23:00:31.000", true, 40.37790, -3.54107)); + + verifyPosition(decoder, text( + "$GPRS123456789012345,602S19A,100915,063515,7240649312041079,0019,3156,111000,10004,0000,11111,00LH#V037")); + + verifyPosition(decoder, text( + "$GPRS123456789012345,T100001,141112,090751,7240649312041079,0002,1530,000001,,,1,00#V039*")); + + verifyPosition(decoder, text( + "$GPRS012497007101250,T100001,141231,152235,7503733600305643,0000,2285,000001,,,1,00#V041*")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java new file mode 100644 index 000000000..9acf2ce87 --- /dev/null +++ b/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class HomtecsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + HomtecsProtocolDecoder decoder = new HomtecsProtocolDecoder(null); + + verifyNull(decoder, text( + "MDS0001_R6d1821f7,170323,143601.00,04,,,,,,,,,")); + + verifyPosition(decoder, text( + "MDS0001_R6d1821f7,170323,143621.00,06,5105.29914,N,11400.52675,W,0.223,198.41,1,2.12,1042.3")); + + verifyPosition(decoder, text( + "strommabus939_R01272028,160217,191003.00,06,5540.12292,N,01237.49814,E,0.391,,1,1.27,1.2")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java new file mode 100644 index 000000000..0f24d4b5c --- /dev/null +++ b/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java @@ -0,0 +1,33 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class HuaShengFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + HuaShengFrameDecoder decoder = new HuaShengFrameDecoder(); + + assertEquals( + binary("c0010c00120060000000000004000600010100c0"), + decoder.decode(null, null, binary("c0010c00120060000000000004000600010100c0"))); + + assertEquals( + binary("c0010c003e0002000000000010020012a0014f42445f3347315f56312e302e330013a0043335353835353035303434303635380006a08701000006a0a1035fc0"), + decoder.decode(null, null, binary("c0010c003e0002000000000010020012a0014f42445f3347315f56312e302e330013a0043335353835353035303434303635380006a08701000006a0a1035fc0"))); + + assertEquals( + binary("c00000003faa0000000000003ea5a5005a3f00c000000031363037303530373132353700e6d186ffcc7a25002201160010000000010015000000000000000000c0"), + decoder.decode(null, null, binary("c00000003faa0000000000003ea5a5005a3f00dbdc00000031363037303530373132353700e6d186ffcc7a25002201160010000000010015000000000000000000c0"))); + + assertEquals( + binary("C000000041AA00000000000030C000000031353035323630373538323800ADDCC100226AEF0000000000120005000100151206EF0504E99975002903EB80556492CEC0"), + decoder.decode(null, null, binary("C000000041AA00000000000030DBDC00000031353035323630373538323800ADDCC100226AEF0000000000120005000100151206EF0504E99975002903EB80556492CEC0"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java new file mode 100644 index 000000000..319d34e4c --- /dev/null +++ b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java @@ -0,0 +1,45 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class HuaShengProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + HuaShengProtocolDecoder decoder = new HuaShengProtocolDecoder(null); + + verifyNull(decoder, binary( + "c0010c003c0002000000000044020010a0014f42445f3347315f56322e320013a0043335353835353035313032303536360006a08700000006a0a105c9c0")); + + verifyNull(decoder, binary( + "c000000077aa0200000000000e000100143347315f48312e315f56312e30372e54000300133335353835353035303434303635380004000b3531323030303000050005010006000400070004000800050000090018383936313032353431343533333239313833360d000a000f796573696e7465726e6574c0")); + + verifyPosition(decoder, binary( + "c00000004baa0000000000000f8000000031363130323030373236333600e6d4f9ffcc78c700000022003600000001001500000000000000000000059bffffffffff0005000a040300000253c0")); + + verifyPosition(decoder, binary( + "c00000004baa000000000000098000000031363130303732323236343700e6d4efffcc789f000000000026000000010015000000000000000000000488ffffffffff0005000a10060000008dc0")); + + verifyPosition(decoder, binary( + "c00000004baa000000000000098000000031363130303732323236343700e6d4efffcc789f000000000026000000010015000000000000000000000488ffffffffff0005000a10060000008dc0")); + + verifyPosition(decoder, binary( + "c00000004baa00000000000005c400000131363037303630323537303800e6c82effcc7cb0003900a30089000000010015000000000000000000f20559ff577ce3980005000a060500000087c0")); + + verifyNull(decoder, binary( + "c0010c003e0002000000000010020012a0014f42445f3347315f56312e302e330013a0043335353835353035303434303635380006a08701000006a0a1035fc0")); + + verifyNull(decoder, binary( + "c0010c00120060000000000004000600010100c0")); + + verifyNull(decoder, binary( + "C00000007EAA020000000000010001001047315F48312E305F56312E3000030013383632393530303238353334333036000400144C342D56374C673979497A7A2D724A6D0005000501000600084341524400070008434152440008000500000900183839383630303530313931343436313130393134000A0009434D4E4554C0")); + + verifyPosition(decoder, binary( + "C000000041AA00000000000030C000000031353035323630373538323800ADDCC100226AEF0000000000120005000100151206EF0504E99975002903EB80556492CEC0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java new file mode 100644 index 000000000..2d3937903 --- /dev/null +++ b/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class HuabaoFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + HuabaoFrameDecoder decoder = new HuabaoFrameDecoder(); + + assertEquals( + binary("7e307e087d557e"), + decoder.decode(null, null, binary("7e307d02087d01557e"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java new file mode 100644 index 000000000..d4ae3b50c --- /dev/null +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -0,0 +1,69 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class HuabaoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + HuabaoProtocolDecoder decoder = new HuabaoProtocolDecoder(null); + + verifyNull(decoder, binary( + "7E01000021013345678906000F002C012F373031313142534A2D4D3742203030303030303001D4C1423838383838B47E")); + + verifyPosition(decoder, binary( + "7e020000400303000002280042000000000000000301618ab406c31ec800000000000518092116145701040000047830011031010aeb16000c00b28986011780108622216500060089ffffffffc37e")); + + verifyPosition(decoder, binary( + "7E0200002A013833501744001900000000000000C201597FA806CC01580080000000081508180721210104000002F502020000030200009F7E")); + + verifyPositions(decoder, binary( + "7E0704014301356777777707F5000801002600000000000000030159741206CBFD5001720000000116052709062401040000001D03020000002600000000000000030159746606CBFD50016B0000000116052709065301040000001D0302000000260000000000000003015975E406CBFE58013F0000000116052709072701040000001D0302000000260000000000000003015976DE06CBFF10012E0000000116052709075601040000001D0302000000260000000000000003015976BC06CBFED0012D0000000116052709083001040000001D0302000000260000000000000003015976FE06CBFEC001080000000116052709090001040000001D0302000000260000000000000003015976FE06CBFE7800FC0000000116052709093301040000001D0302000000260000000000000003015977A606CBFF3001080000000116052709100201040000001D030200001F7E")); + + verifyAttributes(decoder, binary( + "7E0200002F01357888888800B60000000000000003015972B406CBF6B802230000000116061317571301040000000003020000EB0700050001016708B37E")); + + verifyPositions(decoder, binary( + "7E070400F30303000002450064000401003A000000000000000301618AC606C31F20000000000029180514202847010400000000EB16000C00B28986061708003732585700060089FFFFFFFE003A000000000000000301618AE806C31EB800000000009F180514202917010400000000EB16000C00B28986061708003732585700060089FFFFFFFE003A000000000000000301618AE806C31EB800000000009F180514202947010400000000EB16000C00B28986061708003732585700060089FFFFFFFE003A000001000000080301618AE806C31EB800000000009F180514203006010400000000EB16000C00B28986061708003732585700060089FFFFFFFED77E")); + + verifyPosition(decoder, binary( + "7e02000054093037612710000700000000000000010223aca000dc9dd800000000000017121417122133362a4d30302c34352c31313336393042383030313233303026303030303030303030303030263132333435363738393031323334353623897e")); + + verifyPosition(decoder, binary( + "7e0200002c00160128561400020000000000040001005de1f7065c6cef00000000000017011710044201040000a9002a02000030011b3101030c7e")); + + verifyPosition(decoder, binary( + "7e0200002c00160128561400030000000000040007005de13c065c6cdb00160000000017011710054201040000a9002a02000030011b310104e47e")); + + verifyNull(decoder, binary( + "7e0100002d0141305678720024002c012f373031313142534a2d41362d424400000000000000000000003035363738373201d4c14238383838386d7e")); + + verifyNull(decoder, binary( + "7E0100002D013511221122000500000000373031303748422D52303347424400000000000000000000003233363631303402CBD5424136383630387E")); + + verifyNull(decoder, binary( + "7e0100002d007089994489002800000000000000000048422d523033474244000000000000000000000031393036373531024142433030303030d17e")); + + verifyNull(decoder, binary( + "7E0102000E013511221122000661757468656E7469636174696F6E3F7E")); + + verifyPosition(decoder, binary( + "7E02000032013511221122000700000000000C000301578CC006CA3A5C00470000000014072317201501040000000030011631010BD07E")); + + verifyNull(decoder, binary( + "7E010200100940278494700084323031313131303831313333323139369F7E")); + + verifyNull(decoder, binary( + "7e010000190940278494700012000000000000000000000000000000000000094027849470000a7e")); + + verifyPosition(decoder, binary( + "7e0200002e094027587492000a000000010000000a03083db7001329f3000000140000130412164952010400000012360a0002341502cb0c20085c107e")); + + verifyPosition(decoder, binary( + "7e020000220014012499170007000000000000400e012af16f02cbd2ba000000000000150101194257010400000077a97e")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java new file mode 100644 index 000000000..771e6d28c --- /dev/null +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Ignore; +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class HuabaoProtocolEncoderTest extends ProtocolTest { + + @Ignore + @Test + public void testEncode() throws Exception { + + HuabaoProtocolEncoder encoder = new HuabaoProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + verifyCommand(encoder, command, binary("7e81050001080201000027001ff0467e")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java new file mode 100644 index 000000000..f0697f423 --- /dev/null +++ b/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class HunterProProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + HunterProProtocolDecoder decoder = new HunterProProtocolDecoder(null); + + verifyPosition(decoder, text( + ">0002<$GPRMC,170559.000,A,0328.3045,N,07630.0735,W,0.73,266.16,200816,,,A77, s000078015180\",0MD")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java new file mode 100644 index 000000000..d211d80ce --- /dev/null +++ b/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class IdplProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + IdplProtocolDecoder decoder = new IdplProtocolDecoder(null); + + verifyPosition(decoder, text( + "*ID1,863071011086474,210314,153218,A,1831.4577,N,07351.1433,E,0.79,240.64,9,20,A,1,4.20,0,1,01,1,0,0,A01,R,935D#"), + position("2014-03-21 15:32:18.000", true, 18.524295, 73.852388333333)); + + verifyPosition(decoder, text( + "*ID1,863071011086474,210314,162752,A,1831.4412,N,07351.0983,E,0.04,213.84,9,25,A,1,4.20,0,1,01,1,0,0,A01,L,EA01#")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java new file mode 100644 index 000000000..00b7de094 --- /dev/null +++ b/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java @@ -0,0 +1,64 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class IntellitracProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + IntellitracProtocolDecoder decoder = new IntellitracProtocolDecoder(null); + + verifyNull(decoder, text( + "$OK:TRACKING")); + + verifyPosition(decoder, text( + "101000001,20100304075545,121.64547,25.06200,0,0,61,7,2,1,0,0.046,0.000,20100304075546,0"), + position("2010-03-04 07:55:45.000", true, 25.06200, 121.64547)); + + verifyPosition(decoder, text( + "1010000002,20030217132813,121.646060,25.061725,20,157,133,7,0,11,15,0.096,0.000")); + + verifyPosition(decoder, text( + "1010000002,20030217132813,121.646060,25.061725,20,157,-133,7,0,11,15,0.096,0.000")); + + verifyPosition(decoder, text( + "1001070919,20130405084206,37.903730,48.011377,0,0,235,10,2,2,0,20.211,0.153")); + + verifyPosition(decoder, text( + "1010000002,20030217144230,121.646102,25.061398,0,0,139,0,0,0,0,0.093,0.000")); + + verifyPosition(decoder, text( + "1010000004,20050513153524,121.646075,25.063675,0,166,50,6,1,0,0,0.118,0.000")); + + verifyPosition(decoder, text( + "1010000004,20050513154001,121.646075,25.063675,0,166,55,7,1,0,0,0.096,0.000")); + + verifyPosition(decoder, text( + "1010000002,20030217132813,121.646060,25.061725,20,157,0,7,0,11,15")); + + verifyPosition(decoder, text( + "12345,1010000002,20030217132813,121.646060,25.061725,20,157,0,7,0,11,15")); + + verifyPosition(decoder, text( + "1010000002,20030217144230,121.646102,25.061398,0,0,0,7,2,0,0")); + + verifyPosition(decoder, text( + "$RP:12345,1010000002,20030217144230,121.646102,25.061398,0,0,0,7,2,0,0")); + + verifyPosition(decoder, text( + "1010000001,20030105092129,121.651598,25.052325,0,0,33,0,1,0,0")); + + verifyPosition(decoder, text( + "1010000001,20030105092129,-121.651598,-25.052325,0,0,33,0,1,0,0")); + + verifyPosition(decoder, text( + "1015210962,20131010144712,-77.070037,-12.097935,0,0,77,7,2,2,0,0,139446.8,2095,20131010144712,,0.103,0.000")); + + verifyPosition(decoder, text( + "1003269480,20131126100258,10.32989,49.93836,0,304,217,6,2,0,0,0.000,0.000,20131126100258,0,0,0,-40,0,0,-273,0,0,0,0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java new file mode 100644 index 000000000..7523e29a0 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java @@ -0,0 +1,54 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ItsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ItsProtocolDecoder decoder = new ItsProtocolDecoder(null); + + verifyPosition(decoder, text( + "$NRM,ROADRPA,1.8AIS,EA,01,L,869867036341099,,1,11032019,231048,19.25166667,N,73.04615167,E,0.0,230.21,17,12.8,0.80,0.80,airtel,0,1,13.5,4.2,0,O,22,404,90,0CC9,EBC8,19,0CC9,8992,16,0CC9,AB49,15,0CC9,AB44,14,0CC9,F03C,0000,00,002080,C9FBBF99")); + + verifyPosition(decoder, text( + "$NRM,ROADRPA,1.7AIS,NR,01,L,869867036345389,,1,25022019,051716,25.12891000,N,75.85587833,E,7.6,350.00,14,284.8,1.00,1.00,AIRTEL,1,1,28.0,4.2,0,C,13,404,70,4E3B,3C84,11,4E3B,39B8,08,4E3B,3965,07,4E3B,48B5,07,4E3B,3C85,0000,00,000551,71978C6B")); + + verifyPosition(decoder, text( + "$,03,XYZ123,0.0.1,TA,16,L,869867035297185,MH12AB1234,1,20,02,2019,10,59,13,023.482630,N,086.399673,E,000.1,015.19,21,212.3,01.12,00.58,NOSERV,0,1,00.0,4.6,1,C,11,404,75,082a,db3a,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,01,000013,01dbd51f,")); + + verifyPosition(decoder, text( + "$NRM,ROADRPA,1.7AIS,NR,01,L,869867036345389,,1,25022019,051716,25.12891000,N,75.85587833,E,7.6,350.00,14,284.8,1.00,1.00,AIRTEL,1,1,28.0,4.2,0,C,13,404,70,4E3B,3C84,11,4E3B,39B8,08,4E3B,3965,07,4E3B,48B5,07,4E3B,3C85,0000,00,000551,71978C6B")); + + verifyPosition(decoder, text( + "$,1,CHVTS,CHVTS1.0,DT,16,L,861359039868243,861359039868243,1,05022019,071225,19.965062,N,73.736088,E,0,050,03,0632,6.67,6.75,Idea Cel,1,1,23.96,4.0,0,W,28,404,004,4e2b,49e,4e2bea86727ab3d6704e2bea7714e2be9d72,0000,00,001133,232")); + + verifyPosition(decoder, text( + "$,04,XYZ123,0.0.1,TA,16,L,861359034100626,MH12AB1234,1,12,11,2018,08,53,08,018.489645,N,073.855972,E,000.0,220.04,12,593.0,01.13,00.75,AIRTEL,1,1,00.0,4.1,1,C,18,404,90,0c23,781a,5169,0c23,-093,0000,0000,0000,0000,0000,0000,0000,0000,0000,1000,01,000006,f906c65c,")); + + verifyPosition(decoder, text( + "$,A,MFR,7.0,NR,01,L,869026034780985,PJ09BU1234,1,12112018,121953,12.756974,N,077.800025,E,000.0,318.03,15,794.0,001.3,000.7,TAMIL NAD,0,1,13.08,04.13,0,O,22,404,80,0919,71C1,0919,7168,19,0919,71c3,17,0919,71c2,11,0919,7167,09,0011,00,000173,D8,000000.00,,,")); + + verifyPosition(decoder, text( + "$,04,XYZ123,0.0.1,TA,16,L,861359034100626,MH12AB1234,1,14,10,2018,04,50,52,018.489624,N,073.855980,E,000.0,039.86,13,584.1,01.11,00.75,AIRTEL,1,1,00.0,4.1,1,C,15,404,90,0c23,781a,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,1000,01,000005,13b75499,")); + + verifyNull(decoder, text( + "$,01,XYZ123,0.0.1,861359034137271,MH12AB1234,")); + + verifyNull(decoder, text( + "$,02,XYZ123,0.0.1,861359034137271,100,30,00.0,00005,00600,1000,01,00.1,00.0,")); + + verifyPosition(decoder, text( + "$,EPB,EMR,861359034100626,SP,00,00,0000,00,00,00,V,000.000000,N,000.000000,E,000.0,000.0,000.00,N,MH12AB1234,0000000000000,d34679e1,")); + + verifyPosition(decoder, text( + "$,03,XYZ123,0.0.1,TA,16,L,861359034137271,MH12AB1234,0,00,00,0000,00,00,00,000.000000,N,000.000000,E,000.0,000.00,00,000.0,00.00,00.00,IDEAIN,1,1,00.0,4.0,1,O,16,404,22,2797,11b7,11b9,2797,-087,11b8,2797,-093,11b4,2797,-106,0000,0000,0000,1000,01,000032,8173e058,")); + + verifyPosition(decoder, text( + "$,04,XYZ123,0.0.1,BR,06,L,861359034137271,MH12AB1234,0,00,00,0000,00,00,00,000.000000,N,000.000000,E,000.0,000.00,00,000.0,00.00,00.00,IDEAIN,1,1,00.0,3.8,1,O,17,404,22,2797,11b7,11b9,2797,-093,11b8,2797,-098,0000,0000,0000,0000,0000,0000,1000,00,000006,abd26284,")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java new file mode 100644 index 000000000..b0b416891 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java @@ -0,0 +1,60 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Ivt401ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Ivt401ProtocolDecoder decoder = new Ivt401ProtocolDecoder(null); + + verifyPosition(decoder, text( + "(TLA,356917051007891,190118,090211,+16.986606,+82.242416,0,66,4,13,1,5,000,00,0.0,11.59,8.30,37.77,0.0,1,1.02,0,0,208,0,0,0,0,000000000,0,0,0,0,0,0,0,1,8654604,5,9,114)")); + + verifyPosition(decoder, text( + "(TLN,862107032006249,230218,180500,+18.479728,+73.896339,30,0,944,13,1,5,111,11,0.00,10.88,6.31,29.55,0.00,0,0.99,66,0,0,88,95)")); + + verifyPosition(decoder, text( + "(TLN,865933030026336,250118,063827,+18.598098,+73.806518,0,79,0,1,1,5,1200,0,0.0,11.50,4.00,36,0,0,1.00,0,0,12702,202,0)")); + + verifyPosition(decoder, text( + "(TLA,865933030026336,250118,063838,+18.598110,+73.806518,0,334,0,1,1,5,1200,0,0.0,12.20,4.10,36,0,0,1.00,0,0,12704,0,0,0,0,0,0,0,0,0,0,0,0,1,0,3,203,0)")); + + verifyNull(decoder, text( + "(TLB,356917050440515,0,0,+0.0,+0.0,0,0,0,0,0,0,000,00,0.00,12.21,7.95,26.57,0.0,1,1.12,0,0,0,1,90)")); + + verifyPosition(decoder, text( + "(TLN,356917050440515,250118,094723,+0.0,+0.0,0,0,0,0,3,5,000,00,0.00,12.25,7.95,27.11,0.0,0,1.13,0,0,0,4,86)")); + + verifyPosition(decoder, text( + "(TLA,356917050440515,250118,094733,+0.0,+0.0,0,0,0,0,3,5,000,00,0.00,12.25,7.95,27.20,0.0,0,1.12,0,0,0,0,0,0,0,000000000,0,1,0,0,0,0,0,1,0,0,5,70)")); + + verifyPosition(decoder, text( + "(TLN,356917050440515,250118,094733,+0.0,+0.0,0,0,0,0,3,5,000,00,0.00,12.25,7.95,27.20,0.0,0,1.13,0,0,0,6,87)")); + + verifyPosition(decoder, text( + "(TLN,356917050440515,250118,103541,+17.015546,+54.080841,0,0,31,12,1,5,000,00,0.0,0.00,8.04,28.59,M+0+0+0+0+0,0,1.12,0,0,2,48,30)")); + + verifyPosition(decoder, text( + "(TLN,356917050291991,090315,133525,+12.990582,+77.589080,0,0,944,13,1,5,000,00,0.00,10.88,6.31,29.55,0.00,0,0.99,66,0,0,88,95)")); + + verifyPosition(decoder, text( + "(TLN,356917050269732,061117,220046,+21.134126,+74.798561,51,28,204,14,1,5,100,00,0.0,13.92,7.82,23.74,0.0,1,1.33,-9,0,429,4848,67)")); + + verifyPosition(decoder, text( + "(TLN,356917050269732,061117,220116,+21.137619,+74.800659,52,28,202,14,1,3,100,00,0.0,13.92,7.82,23.74,0.0,1,1.26,-23,0,445,4849,125)")); + + verifyPosition(decoder, text( + "(TLA,356917050217335,190115,011336,+12.932403,+79.898887,0,0,71.7,08,3,10,000,00,0.00,10.41,7.07,26.84,0.00,0,0.99,63,0,0,0,0,0,0,000000000,0,0,0,0,0,0,0,2,0,0,14,86)")); + + verifyPosition(decoder, text( + "(TLB,356917050291991,090315,133525,+12.990582,+77.589080,0,0,944,13,1,5,000,00,0.00,10.88,6.31,29.55,0.00,0,0.99,66,0,0,88,95)")); + + verifyPosition(decoder, text( + "(TLL,356917050217335,190115,011336,+12.932403,+79.898887,0,0,71.7,08,3,10,000,00,0.00,10.41,7.07,26.84,0.00,0,0.99,63,0,0,0,0,0,0,000000000,0,0,0,0,0,0,0,2,0,0,14,86)")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java new file mode 100644 index 000000000..8179a2bae --- /dev/null +++ b/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class JpKorjarProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + JpKorjarProtocolDecoder decoder = new JpKorjarProtocolDecoder(null); + + verifyPosition(decoder, text( + "KORJAR.PL,329587014519383,160910144240,52.247254N,021.013375E,0.00,1,F:4.18V,1 260 01 794B 3517,")); + + verifyPosition(decoder, text( + "KORJAR.PL,329587014519383,160910144240,52.895515N,021.949151E,6.30,212,F:3.94V,0 260 01 794B 3519,")); + + verifyPosition(decoder, text( + "KORJAR.PL,329587014519383,160910144240,52.895596N,021.949343E,12.46,087,L:2.18V,1 260 01 794B 3517,")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java new file mode 100644 index 000000000..ae0948987 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java @@ -0,0 +1,39 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Jt600FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Jt600FrameDecoder decoder = new Jt600FrameDecoder(); + + verifyFrame( + binary("24315011626912001b21111718095900000000000000000e0000005c000000000000000000"), + decoder.decode(null, null, binary("24315011626912001b21111718095900000000000000000e0000005c00000000000000000024315011626912001b22111708130400000000000000000e0000005a00000000000000000024315011626912001b22111708140400000000000000000e0000005a000000723e18a61b01"))); + + verifyFrame( + binary("2475604055531611002311111600311326144436028210791d016c0000001f070000000020c03c4f6d07d80ccf"), + decoder.decode(null, null, binary("2475604055531611002311111600311326144436028210791d016c0000001f070000000020c03c4f6d07d80ccf"))); + + verifyFrame( + binary("2475605035891613002328091601152806086750106533350c00000000000a000000000000e1ff4f97007f1607"), + decoder.decode(null, null, binary("2475605035891613002328091601152806086750106533350c00000000000a000000000000e1ff4f97007f1607"))); + + verifyFrame( + binary("28333132303832303032392C5730312C30323535332E333535352C452C323433382E303939372C532C412C3137313031322C3035333333392C302C382C32302C362C33312C352C32302C323029"), + decoder.decode(null, null, binary("28333132303832303032392C5730312C30323535332E333535352C452C323433382E303939372C532C412C3137313031322C3035333333392C302C382C32302C362C33312C352C32302C323029"))); + + verifyFrame( + binary("24312082002911001B171012053405243809970255335555000406140003EE2B91044D1F02"), + decoder.decode(null, null, binary("24312082002911001B171012053405243809970255335555000406140003EE2B91044D1F02"))); + + verifyFrame( + binary("28373536303430353535332c404a5429"), + decoder.decode(null, null, binary("28373536303430353535332c404a5429"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java new file mode 100644 index 000000000..2bb4b0fa3 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java @@ -0,0 +1,108 @@ +package org.traccar.protocol; + +import org.traccar.ProtocolTest; + +import org.junit.Test; + +public class Jt600ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Jt600ProtocolDecoder decoder = new Jt600ProtocolDecoder(null); + + verifyPositions(decoder, binary( + "2475801263981711002713061813333723501622090221558f012f0000002a070000000020c055b88552191f000f0f0f07")); + + verifyPositions(decoder, binary( + "24408111888821001B09060908045322564025113242329F0598000001003F0000002D00AB")); + + verifyPositions(decoder, binary( + "2475609213701711002701010000020200000000000000000e00000000000f000000000020c164cd7b00d516000f0f0f02")); + + verifyPositions(decoder, binary( + "24657060730131001b13111710361906538525079524797f000000000000000003f300036c")); + + verifyPositions(decoder, binary( + "24624090196121001b19071703493631277203074235752f295800005308010000768b0822")); + + verifyPositions(decoder, binary( + "24624090196123019519071703412131285623074214252f10560000130801000076850819071703420631282832074215165f172c0000030801000076850919071703422131282792074216635f222e0000130801000076850919071703423631282808074218261f212a0000130801000076860819071703435131283678074222928f08350000930801000076860919071703440631283003074223174f19500000930801000076870819071703445131279872074224584f07380000930801000076870819071703453631280643074227091f1b220000530801000076880919071703455131281043074228216f0a260000530801000076880819071703460631281229074228988f0c260000530801000076880819071703462131281551074229954f1f220000530801000076880919071703463631281289074230503f114e0000530801000076880819071703465131281186074230884f094f0000530801000076880819071703470631280308074231240f17500000530801000076880619071703472131280358074231636f0b1d0000530801000076890821")); + + verifyPositions(decoder, binary( + "2475604055531611002311111600311326144436028210791d016c0000001f070000000020c03c4f6d07d80ccf")); + + verifyPositions(decoder, binary( + "2475201509260111002313101503464722331560113555309F00000000002D0500CB206800F064109326381A03")); + + verifyPositions(decoder, binary( + "2475605035891613002328091601152806086750106533350c00000000000a000000000000e1ff4f97007f1607")); + + verifyPosition(decoder, buffer( + "(3301210003,U01,040812,185302,T,22.564025,N,113.242329,E,5.21,152,9,32%,00000000000011,10133,5173,22,100,1)")); + + verifyPosition(decoder, buffer( + "(3301210003,U02,040812,185302,T,22.564025,N,113.242329,E,5,152,9,32%,00000000000011,10133,5173,22,100,1)")); + + verifyPosition(decoder, buffer( + "(3301210003,U03,040812,185302,T,22.564025,N,113.242329,E,5,152,9,32%,00000000000011,10133,5173,22,100,1)")); + + verifyNull(decoder, buffer( + "(3301210003,U04)")); + + verifyPosition(decoder, buffer( + "(3301210003,U06,1,040812,185302,T,22.564025,N,113.242329,E,5,152,9,32%,0000000000011,10133,5173,22,100,1,300,100,10)")); + + verifyPosition(decoder, buffer( + "(3460311327,U01,220916,135251,T,9.552607,N,13.658292,W,0.31,0,9,0%,00001001000000,11012,10,27,0,0,33)")); + + verifyPosition(decoder, buffer( + "(3460311327,U01,010100,000024,F,0.000000,N,0.000000,E,0.00,0,0,100%,00000001000000,263,1,18,0,0,33)")); + + verifyNull(decoder, buffer( + "(3460311327,@JT)")); + + verifyPosition(decoder, buffer( + "(3460311327,U06,11,220916,135643,T,9.552553,N,13.658265,W,0.61,0,9,100%,00000001000000,11012,10,30,0,0,126,0,30)")); + + verifyPosition(decoder, buffer( + "(3460311327,U06,10,220916,140619,T,9.552495,N,13.658227,W,0.43,0,7,0%,00101001000000,11012,10,0,0,0,126,0,30)")); + + verifyPositions(decoder, binary( + "24311021600111001B16021105591022329862114046227B0598095080012327951435161F"), + position("2011-02-16 05:59:10.000", true, 22.54977, -114.07705)); + + verifyPositions(decoder, binary( + "24312082002911001B171012052831243810120255336425001907190003FD2B91044D1FA0")); + + verifyPositions(decoder, binary( + "24312082002911001B1710120533052438099702553358450004061E0003EE000000000C00")); + + verifyPositions(decoder, binary( + "24608111888821001B09060908045322564025113242329F0598000001003F0000002D00AB")); + + verifyPosition(decoder, buffer( + "(3110312099,W01,11404.6204,E,2232.9961,N,A,040511,063736,4,7,100,4,17,1,1,company)"), + position("2011-05-04 06:37:36.000", true, 22.54994, 114.07701)); + + verifyPosition(decoder, buffer( + "(3120820029,W01,02553.3555,E,2438.0997,S,A,171012,053339,0,8,20,6,31,5,20,20)")); + + verifyPosition(decoder, buffer( + "(3330104377,U01,010100,010228,F,00.000000,N,000.000000,E,0,0,0,0%,00001000000000,741,14,22,0,206)")); + + verifyNull(decoder, buffer( + "(6221107674,2,U09,129,2,A,280513113036,E,02711.0500,S,1721.0876,A,030613171243,E,02756.7618,S,2300.0325,3491,538200,14400,1)")); + + verifyPosition(decoder, buffer( + "(3301210003,U02,040812,185302,T,00.000000,N,000.000000,E,0,0,0,0%,00000000000011,741,51,22,0,1,05)")); + + verifyPosition(decoder, buffer( + "(3301210003,U06,4,250916,133207,T,7.011013,N,25.060708,W,27.61,102,10,0%,00101011000000,0,1,0,448,0,126,1,30)")); + + verifyPosition(decoder, buffer( + "(3551001012,U01,010100,000032,F,0.000000,N,0.000000,E,0.00,0,0,10%,00000000010000,15748,7923,23,0,0,3E)")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java new file mode 100644 index 000000000..100d7492a --- /dev/null +++ b/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java @@ -0,0 +1,37 @@ +package org.traccar.protocol; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class Jt600ProtocolEncoderTest extends ProtocolTest { + Jt600ProtocolEncoder encoder = new Jt600ProtocolEncoder(); + Command command = new Command(); + + @Test + public void testEngineStop() throws Exception { + command.setType(Command.TYPE_ENGINE_STOP); + assertEquals("(S07,0)", encoder.encodeCommand(command)); + } + + @Test + public void testEngineResume() throws Exception { + command.setType(Command.TYPE_ENGINE_RESUME); + assertEquals("(S07,1)", encoder.encodeCommand(command)); + } + + @Test + public void testSetTimezone() throws Exception { + command.setType(Command.TYPE_SET_TIMEZONE); + command.set(Command.KEY_TIMEZONE, "GMT+4"); + assertEquals("(S09,1,240)", encoder.encodeCommand(command)); + } + + @Test + public void testReboot() throws Exception { + command.setType(Command.TYPE_REBOOT_DEVICE); + assertEquals("(S17)", encoder.encodeCommand(command)); + } +} diff --git a/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java new file mode 100755 index 000000000..5596913c9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class KenjiProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + KenjiProtocolDecoder decoder = new KenjiProtocolDecoder(null); + + verifyPosition(decoder, text( + ">C800000,M005004,O0000,I0002,D124057,A,S3137.2783,W05830.2978,T000.0,H254.3,Y240116,G06*17"), + position("2016-01-24 12:40:57.000", true, -31.62131, -58.50496)); + } + +} diff --git a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java new file mode 100644 index 000000000..62b6070b6 --- /dev/null +++ b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java @@ -0,0 +1,48 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class KhdProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + KhdProtocolDecoder decoder = new KhdProtocolDecoder(null); + + verifyNull(decoder, binary( + "2929b1000605162935b80d")); + + verifyPosition(decoder, binary( + "29298e006d1f29402d181117083846801193910365274500000000f80000227ffc3f00001e00500000000000060088000000220019ffc100000000000000000000000000000000007080002000000016ff893839323534303231303734313134323334333639000800233030302e30306e0d")); + + verifyPosition(decoder, binary( + "2929a3002e1780c663170216203353003060811013839500000114f8000000ffff5000000a00000000000000060102003db70d")); + + verifyPosition(decoder, binary( + "292980002805162935140108074727801129670365336900000103ffff000082fc0000001e78091b000000360d")); + + verifyPosition(decoder, binary( + "29298100280A9F9538081228160131022394301140372500000330FF0000007FFC0F00001E000000000034290D")); + + verifyPosition(decoder, binary( + "29298000280A81850A120310095750005281370061190800000232F848FFBBFFFF0000001E000000000000ED0D")); + + verifyPosition(decoder, binary( + "29298E00280F80815A121218203116022318461140227000720262FB00077C7FBF5600001E3C3200000000850D")); + + verifyPosition(decoder, binary( + "29298200230AA2CC391205030505220285947903109550008002078400000002000000000000750D")); + + verifyPosition(decoder, binary( + "29298500081DD08C22120312174026026545710312541700000000F819C839FFFF1D00001E00500000003AF90D")); + + verifyPosition(decoder, binary( + "292980002822836665140825142037045343770193879200000050ffff000082fc000004b0780b170000002a0d")); + + verifyPosition(decoder, binary( + "292980002802425349120811032137022373011140211100000334FFFF000082FC0000001E780913000034DF0D")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java new file mode 100644 index 000000000..ab858041a --- /dev/null +++ b/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class KhdProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + KhdProtocolEncoder encoder = new KhdProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + verifyCommand(encoder, command, binary("29293900065981972d5d0d")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java b/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java new file mode 100644 index 000000000..5ffa3d8d1 --- /dev/null +++ b/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java @@ -0,0 +1,31 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class L100FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + L100FrameDecoder decoder = new L100FrameDecoder(); + + verifyFrame( + binary("41544c2c4c2c3836383334353033383137313936332c4e2c3230313231382c3039333031362c412c3032352e3036373134342c4e2c3035352e3134343833332c452c3030302e302c4750532c333933392c3432342c30332c30303430352c303038383334"), + decoder.decode(null, null, binary("41544c2c4c2c3836383334353033383137313936332c4e2c3230313231382c3039333031362c412c3032352e3036373134342c4e2c3035352e3134343833332c452c3030302e302c4750532c333933392c3432342c30332c30303430352c30303838333440"))); + + verifyFrame( + binary("4c2c41544c2c3836363739353033303437373935322c30312c303033352c"), + decoder.decode(null, null, binary("4c2c41544c2c3836363739353033303437373935322c30312c303033352c2a28"))); + + verifyFrame( + binary("41544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c"), + decoder.decode(null, null, binary("200141544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735242c2330313130303131313030313031302c4e2e432c4e2e432c4e2e432c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c027a"))); + + verifyFrame( + binary("41544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735244c4f432c436f6e6e61756768742043697263757320c2a0436f6e6e617567687420506c61636520c2a04e65772044656c686920c2a044656c6869c2a0496e6469612c2330313130303130313130313031302c322e332c33352e36372c38302c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c"), + decoder.decode(null, null, binary("200341544c3335363839353033373533333734352c244750524d432c3131313731392e3030302c412c323833382e303034352c4e2c30373731332e333730372c452c302e30302c2c3132303831302c2c2c412a3735244c4f432c436f6e6e61756768742043697263757320c2a0436f6e6e617567687420506c61636520c2a04e65772044656c686920c2a044656c6869c2a0496e6469612c2330313130303130313130313031302c322e332c33352e36372c38302c31323334352e36372c33312e342c342e322c32312c4d43432c4d4e432c4c41432c43656c6c494441544c047a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java new file mode 100644 index 000000000..04f586f7a --- /dev/null +++ b/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java @@ -0,0 +1,51 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class L100ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + L100ProtocolDecoder decoder = new L100ProtocolDecoder(null); + + verifyPosition(decoder, text( + "ATL,NP,868004029750174,$GPRMC,062943,A,2533.6719,N,09154.3203,E,0,179,311218,,,*39,#01111011000000,0,0,0,934.82,27.13,4.0,25,405,755,15af,974b,0,0,0,ATL")); + + verifyPosition(decoder, text( + "ATL,L,868345038171963,N,201218,093016,A,025.067144,N,055.144833,E,000.0,GPS,3939,424,03,00405,008834")); + + verifyPosition(decoder, text( + "N,111116,090031,A,028.123456,N,077.123456,E,000.0,GPS,4180,404,11,00159,064753")); + + verifyAttributes(decoder, text( + "L,ATLOBD,866795030475584,03,7429,143344,130918,CAN,0101:00076100,0103:0200,0104:3C,0105:84,010A:XX,010B:19,010C:0F98,010D:22,010E:68,010F:5A,0110:XXXX,0111:28,011C:20,011F:XXXX,0121:0000,0122:XXXX,012F:XX,0162:XX,0132:XXXX,0133:61,0143:00A8,0145:0F,0146:XX,0147:30,0148:XX,0149:31,014A:18,014B:XX,014C:92,0151:XX,0131:00BB,0144:8000,015E:XXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0902:XXXXXXXXXXXXXXX")); + + verifyPosition(decoder, text( + "H,ATL,866795030478513,02,0981,054448,230318,A,28.633486;N,77.222595;E,0,154,1.14,4.2,18,404,4,88,ad7b,#1031,0,ATL,")); + + verifyNull(decoder, text( + "L,ATL,866795030477952,01,0035,")); + + verifyPosition(decoder, text( + "ATL861693039769518,$GPRMC,074930.000,A,2838.0112,N,07713.3602,E,0000,223.36,290518,,,A*7E,#01111011000100,0.012689,0,0,2.572415,0,4.015,22,404,4,88,3ad5,0,0.01,1.4_800F_VTS3D3_gen_peri_myn,,internet,00000000,ATL")); + + verifyPosition(decoder, text( + "ATL867857039216564,$GPRMC,131101,A,2838.010010,N,7713.354980,E,0,0,240418,,,*09,#00011011000000,0,0,0,10.70,24.31,3.8,0,0,0,0,0ATL")); + + verifyPosition(decoder, text( + "ATL867857039216564,$GPRMC,131033,A,2838.010010,N,7713.354980,E,0,51,240418,,,*3D,#00011011000000,0,0,0,10.70,24.31,3.8,20,404,4,88,cfaaATL")); + + verifyPosition(decoder, text( + "ATL868004026997257,$GPRMC,095542,A,2838.0107,N,07713.3579,E,0,98,010617,,,*03,#01111011000000,0,0,0,0.01,45.94,4.0,25,404,4,88,3ad5ATL")); + + verifyPosition(decoder, text( + "ATL861693035285253,$GPRMC,022040,A,2954.0481,N,07353.1694,E,0,150,280417,,,*36,#01111011000000,0,0,0,82.92,37.92,4.0,23,404,70,163,b178ATL")); + + verifyPosition(decoder, text( + "ATL356895037533745,$GPRMC,111719.000,A,2838.0045,N,07713.3707,E,0.00,,120810,,,A*75,#01100111001010,N.C,N.C,N.C,12345.67,31.4,4.2,21,100,000,000001,00000ATL")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java new file mode 100644 index 000000000..31a0434bc --- /dev/null +++ b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java @@ -0,0 +1,125 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class LaipacProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + LaipacProtocolDecoder decoder = new LaipacProtocolDecoder(null); + + verifyPosition(decoder, text( + "$AVRMC,80006405,212645,r,3013.9938,N,08133.3998,W,0.00,0.00,010317,a,4076,0,1,0,0,53170583,310260*78")); + + verifyNull(decoder, text( + "$AVSYS,99999999,V1.50,SN0000103,32768*15")); + + verifyNull(decoder, text( + "$ECHK,99999999,0*35")); + + verifyNull(decoder, text( + "$AVSYS,MSG00002,14406,7046811160,64*1A")); + + verifyNull(decoder, text( + "$EAVSYS,MSG00002,8931086013104404999,,Owner,0x52014406*76")); + + verifyNull(decoder, text( + "$ECHK,MSG00002,0*5E")); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,A,4351.0542,N,07923.5445,W,0.29,78.66,180703,0,3.727,17,1,0,0*37"), + position("2003-07-18 16:43:39.000", true, 43.85090, -79.39241)); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,a,4351.0542,N,07923.5445,W,0.29,78.66,180703,0,3.727,17,1,0,0*17")); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,v,4351.0542,N,07923.5445,W,0.29,78.66,180703,0,3.727,17,1,0,0*00")); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,r,4351.0542,N,07923.5445,W,0.29,78.66,180703,0,3.727,17,1,0,0*04")); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,A,4351.0542,N,07923.5445,W,0.29,78.66,180703,S,3.727,17,1,0,0*54")); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,A,4351.0542,N,07923.5445,W,0.29,78.66,180703,T,3.727,17,1,0,0*53")); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,A,4351.0542,N,07923.5445,W,0.29,78.66,180703,3,3.727,17,1,0,0*34")); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,A,4351.0542,N,07923.5445,W,0.29,78.66,180703,X,3.727,17,1,0,0*5F")); + + verifyPosition(decoder, text( + "$AVRMC,99999999,164339,A,4351.0542,N,07923.5445,W,0.29,78.66,180703,4,3.727,17,1,0,0*33")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,003016,v,0000.0000,N,00000.0000,E,0.00,0.00,200614,0,3804,167,1,0,0,0D7AB913,020408*23")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,003049,V,0000.0000,N,00000.0000,E,0.00,0.00,200614,H,3804,167,1,0,0,0D7AB913,020408*71")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,041942,V,0000.0000,N,00000.0000,E,0.00,0.00,200614,H,4115,167,1,0,0*0E")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,043703,V,0000.0000,N,00000.0000,E,0.00,0.00,200614,H,4115,167,1,0,0*07")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,043750,V,0000.0000,N,00000.0000,E,0.00,0.00,200614,H,4115,167,1,0,0*01")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,124022,V,0000.0000,N,00000.0000,E,0.00,0.00,240614,3,4076,167,1,0,0,0D7AB913,020408*0D")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,124058,A,5053.0447,N,00557.8549,E,0.45,65.06,240614,0,4037,167,1,0,0,0D7AB913,020408*26")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,124144,A,5053.0450,N,00557.8544,E,0.00,65.06,240614,3,4076,167,1,0,0,0D7AB913,020408*26")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,125142,R,5053.0442,N,00557.8694,E,1.21,40.90,240614,0,4037,167,1,0,0,0D7AB913,020408*33")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,125517,R,5053.0442,N,00557.8694,E,0.00,0.00,240614,H,4076,167,1,0,0,0D7AB913,020408*75")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,043104,p,5114.4664,N,00534.3308,E,0.00,0.00,280614,0,4115,495,1,0,0,0D48C3DC,020408*52")); + + verifyPosition(decoder, text( + "$AVRMC,MSG00002,050601,P,5114.4751,N,00534.3175,E,0.00,0.00,280614,0,4115,495,1,0,0,0D48C3DC,020408*7D")); + + verifyPosition(decoder, text( + "$AVRMC,96414215,170046,p,4310.7965,N,07652.0816,E,0.00,0.00,071016,0,4069,98,1,0,0*04")); + + verifyPosition(decoder, text( + "$AVRMC,999999999999999,111602,r,5050.1262,N,00419.9660,E,0.00,0.00,120318,0,3843,95,1,0,0,3EE4A617,020610*47")); + + verifyPosition(decoder, text( + "$AVRMC,358174067149865,143456,R,5050.1285,N,00420.0620,E,0.00,309.27,190318,0,3455,119,1,0,0,3EE4A617,020610*54")); + + verifyPosition(decoder, text( + "$AVRMC,999999999999999,084514,r,5050.1314,N,00419.9719,E,0.68,306.39,120318,0,3882,84,1,0,0,3EE4A617,020610*4D")); + + //Alarm button + verifyPosition(decoder, text( + "$AVRMC,358174067149865,142945,R,5050.1254,N,00420.0490,E,0.00,0.00,190318,3,3455,119,1,0,0,3EE4A617,020610*53")); + + //G-Sensor + verifyPosition(decoder, text( + "$AVRMC,358174067149865,143407,R,5050.1254,N,00420.0490,E,0.00,0.00,190318,8,3455,119,1,0,0,3EE4A617,020610*52")); + + //Powered off + verifyPosition(decoder, text( + "$AVRMC,358174067149865,143648,A,5050.1141,N,00420.0525,E,1.24,174.38,190318,H,3455,119,1,0,0,3EE4A617,020610*3E")); + + //No network + verifyPosition(decoder, text( + "$AVRMC,358174067149865,143747,R,5050.1124,N,00420.0542,E,1.34,161.96,190318,a,3416,119,1,0,0*7D")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java new file mode 100644 index 000000000..65c9cc43b --- /dev/null +++ b/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java @@ -0,0 +1,27 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class M2cProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + M2cProtocolDecoder decoder = new M2cProtocolDecoder(null); + + verifyPositions(decoder, text( + "[#M2C,2020,P1.B1.H3.F9.R1,102,864547034433966,1,L,0,20,171221,062016,28.647552,77.192841,0,0,0.0,0,0,64,255,11983,0,0,0,0.0,0,0,0,404,4,1F6,4D77,31,0*7524\r\n", + "#M2C,2020,P1.B1.H3.F9.R1,102,864547034433966,2,L,0,20,171221,062019,28.647552,77.192841,0,0,0.0,0,0,64,255,11983,0,0,0,0.0,0,0,0,404,4,1F6,4D77,31,0*7528\r\n", + "#M2C,2020,P1.B1.H3.F9.R1,102,864547034433966,3,L,0,20,171221,062024,28.647552,77.192841,0,0,0.0,0,0,64,255,16292,0,0,0,0.0,0,0,0,404,4,1F6,4D77,31,0*7523\r\n")); + + verifyPositions(decoder, text( + "[#M2C,2020,P1.B1.H1.F1.R1,101,862462038980016,2,L,1,100,170704,074933,28.647556,77.192940,900,194,0.0,0,0,0,255,11942,0,0,0,0,0,0,0,0,30068,5051,0,0,1*8159\r\n")); + + verifyPositions(decoder, text( + "[#M2C,2020,P1.B1.H1.F1.R1,101,862462038980016,7,L,0,31,170704,075905,28.647615,77.192970,300,260,0.0,6,7,3,255,11967,0,12,0,0,0,0,0,0,19500,5051,0,27,1*8234\r\n", + "#M2C,2020,P1.B1.H1.F1.R1,101,862462038980016,8,L,0,33,170704,075905,28.647615,77.192970,300,260,0.0,6,7,0,255,11942,0,12,0,0,0,0,0,0,20300,5051,0,27,1*8217\r\n")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java new file mode 100644 index 000000000..1c45c976b --- /dev/null +++ b/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class M2mProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + M2mProtocolDecoder decoder = new M2mProtocolDecoder(null); + + verifyNull(decoder, binary( + "235A3C2A2624215C287D70212A21254C7C6421220B0B0B")); + + verifyPosition(decoder, binary( + "A6E12C2AAADA4628326B2059576E30202A2FE85D20200B")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java new file mode 100644 index 000000000..c7a7624c0 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MaestroProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MaestroProtocolDecoder decoder = new MaestroProtocolDecoder(null); + + verifyPosition(decoder, text( + "@353893040202807,705,UPV-02,1,13.2,17,0,0,16/09/11,11:42:49,0.352705,32.647918,1210.5,0.000000,35.33,11,0.8,0.000,0!\0")); + + verifyPosition(decoder, text( + "@353893040202807,705,UPV-02,1,13.4,18,0,0,16/09/11,11:43:30,0.352808,32.647990,1211.0,0.000000,80.96,11,0.8,0.000,0!\0")); + + verifyPosition(decoder, text( + "@353893040202807,601,UPV-02,0,13.4,10,0,0,16/11/04,17:21:14,0.352793,32.647927,0,0,0,0,99,0.000,0!\0")); + + verifyPosition(decoder, text( + "@123451234512345,531,M2MGTW,1,12.5,30,0,0,11/10/10,09:09:09,22.222222,114.141414,45.6,0.0,160.0,8,1,20!")); + + verifyPosition(decoder, text( + "@123451234512345,702,M2MGTW,1,14.7,30,0,1,11/10/10,09:09:09,22.222222,114.141414,45.6,25.12,160.0,8,1,25!")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java new file mode 100644 index 000000000..1d6f80ae3 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ManPowerProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ManPowerProtocolDecoder decoder = new ManPowerProtocolDecoder(null); + + verifyPosition(decoder, text( + "simei:352581250259539,,,tracker,51,24,1.73,130426023608,A,3201.5462,N,03452.2975,E,0.01,28B9,1DED,425,01,1x0x0*0x1*60x+2,en-us,"), + position("2013-04-26 02:36:08.000", true, 32.02577, 34.87163)); + + verifyPosition(decoder, text( + "simei:352581250259539,,,weather,99,20,0.00,130426032310,V,3201.5517,N,03452.3064,E,1.24,28B9,25A1,425,01,1x0x0*0x1*60x+2,en-us,")); + + verifyPosition(decoder, text( + "simei:352581250259539,,,SMS,54,19,90.41,130426172308,V,3201.5523,N,03452.2705,E,0.14,28B9,01A5,425,01,1x0x0*0x1*60x+2,en-us,")); + } + +} diff --git a/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java new file mode 100644 index 000000000..68606a98a --- /dev/null +++ b/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java @@ -0,0 +1,27 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MegastekFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MegastekFrameDecoder decoder = new MegastekFrameDecoder(); + + verifyFrame( + binary("30313337244d47563030322c3335343535303035303239323636392c4756543930302c522c3134313231352c3033313830342c412c2c532c2c452c30302c30332c30302c332e36372c302e3030302c302e30302c3131372e312c302e302c3531302c31302c2c2c2c303030302c303030302c32322c31322c302c202c202c2c312d312c39382c5057204f4e3b21"), + decoder.decode(null, null, binary("30313337244d47563030322c3335343535303035303239323636392c4756543930302c522c3134313231352c3033313830342c412c2c532c2c452c30302c30332c30302c332e36372c302e3030302c302e30302c3131372e312c302e302c3531302c31302c2c2c2c303030302c303030302c32322c31322c302c202c202c2c312d312c39382c5057204f4e3b21"))); + + verifyFrame( + binary("244d47563030322c3031333737373030373533363433342c2c522c3031303131342c3030303035372c562c303030302e303030302c4e2c30303030302e303030302c452c30302c30302c30302c39392e392c302e3030302c302e30302c302e302c38302e3236332c3531302c38392c323334322c303330422c2c303030302c303030302c3230302c39362c302c202c202c2c2c2c54696d65723b21"), + decoder.decode(null, null, binary("244d47563030322c3031333737373030373533363433342c2c522c3031303131342c3030303035372c562c303030302e303030302c4e2c30303030302e303030302c452c30302c30302c30302c39392e392c302e3030302c302e30302c302e302c38302e3236332c3531302c38392c323334322c303330422c2c303030302c303030302c3230302c39362c302c202c202c2c2c2c54696d65723b210d0a"))); + + verifyFrame( + binary("53545832363034373520202020202020202020024f244750524d432c3133313131302e30302c562c2c2c2c2c2c2c3036303931332c2c2c4e2a37362c3232322c30312c383135412c443435352c31312c39372c303030302c303030312c302c54696d65723b3735"), + decoder.decode(null, null, binary("53545832363034373520202020202020202020024f244750524d432c3133313131302e30302c562c2c2c2c2c2c2c3036303931332c2c2c4e2a37362c3232322c30312c383135412c443435352c31312c39372c303030302c303030312c302c54696d65723b37350d0a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java new file mode 100644 index 000000000..1bf3dbd25 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java @@ -0,0 +1,100 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MegastekProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MegastekProtocolDecoder decoder = new MegastekProtocolDecoder(null); + + verifyPosition(decoder, text( + "0132$MGV002,869152024261561,,S,310818,133945,V,3814.35442,N,02144.50662,E,00,00,00,99.9,,,44.2,,202,10,,,13,0,0,0,0,90,,,,11,100,Timer;!")); + + verifyPosition(decoder, text( + "0151$MGV002,869152024261561,ID,S,070918,155544,V,3814.35419,N,02144.52113,E,00,00,00,99.9,0.062,,12.3,,202,01,0898,D1BE,8,34,1055,0,0,600,,,,11,010,Timer;!")); + + verifyPosition(decoder, text( + "0174$MGV002,014682001957744,014682001957744,R,260318,042537,A,3853.77301,N,07728.66673,W,00,09,00,1.06,0.147,329.51,123.3,,310,26,B46C,5E69375,5,0000,0000,0,,,,,,10,019,Timer,,;!")); + + verifyNull(decoder, text( + "0112$MGV002,,GVT900-3,S,010114,000003,,,,,,00,00,00,,0.000,0.00,,0.0,,,,,,0000,0000,14,10,0, , ,,1-0,0,Low Ext Vol;!")); + + verifyPosition(decoder, text( + "0170$MGV002,354550056642321,GVT900-3,S,011017,090208,A,1635.8484,N,10446.6095,E,00,09,00,0.91,16.980,257.73,177.6,0.0,457,01,0741,00C0,21,0000,0000,20,10,0, , ,,1-1,54,Dist;!")); + + verifyNull(decoder, text( + "0140$MGV002,354550056642321,GVT900-3,S,300917,071731,V,,,,,00,00,00,99.9,0.000,0.00,,0.0,457,01,0741,00CD,,0000,0000,20,10,0, , ,,1-1,94,PW ON;!")); + + verifyPosition(decoder, text( + "$MGV002,869152024446923,,S,290816,200627,V,5056.21059,N,00439.25034,E,00,00,00,99.9,,,-25.1,,206,01,0BBB,4418,28,,,,,,,,,01,093,Timer;")); + + verifyPosition(decoder, text( + "$MGV002,869152024446923,869152024446923,S,240816,151631,A,5053.83335,N,00424.05702,E,00,10,00,0.88,2.645,76.09,22.7,,206,01,07D1,6600,28,,,,,,,,,01,100,Timer;!")); + + verifyPosition(decoder, text( + "STX,013950007137061,$GPRMC,191959.000,A,5203.09602,N,00830.77057,E,5.73,255.27,240716,,,A*62,L,Belt Up,imei:013950007137061,0/5,,Battery=52%,,1,262,03,0084,B20E;FD")); + + verifyPosition(decoder, text( + "STX,865067021328417,$GPRMC,064721.000,A,4241.2793,N,02321.9762,E,6.74,346.90,300316,,,1*CA,F,Nil-Alarms,imei:865067021328417,9,559.8,Battery=82%,0,284,03,047E,2B5F;99")); + + verifyNull(decoder, text( + "0147$MGV002,354550050292669,GVT900,S,141215,031804,A,,S,,E,00,04,00,5.17,0.000,193.05,117.1,0.0,510,10,041B,0A5E,,0000,0000,22,12,0, , ,,1-1,98,Timer;!")); + + verifyNull(decoder, text( + "0137$MGV002,354550050292669,GVT900,R,141215,031804,A,,S,,E,00,03,00,3.67,0.000,0.00,117.1,0.0,510,10,,,,0000,0000,22,12,0, , ,,1-1,98,PW ON;!")); + + verifyPosition(decoder, text( + "0125$MGV002,860719020193193,DeviceName,R,240214,104742,A,2238.20471,N,11401.97967,E,00,03,00,1.20,0.462,356.23,137.9,1.5,460,07,262C,0F54,25,0000,0000,0,0,0,28.5,28.3,,,100,Timer;")); + + verifyPosition(decoder, text( + "$MGV002,860719020193193,DeviceName,R,240214,104742,A,2238.20471,N,11401.97967,E,00,03,00,1.20,0.462,356.23,137.9,1.5,460,07,262C,0F54,25,0000,0000,0,0,0,28.5,28.3,,,100,Timer;!"), + position("2014-02-24 10:47:42.000", true, 22.63675, 114.03299)); + + verifyPosition(decoder, text( + "STX2010101801 j$GPRMC,101053.000,A,2232.7607,N,11404.7669,E,0.00,,231110,,,A*7F,460,00,2795,0E6A,14,94,1000,0000,91,Timer;1D")); + + verifyPosition(decoder, text( + "STX,861001005215757,$GPRMC,180118.000,A,4241.330116,N,2321.931251,E,0.00,182.19,130915,,E,A,F,Nil-Alarms,imei:861001005215757,8,577.0,Battery=38%,0,284,03,03E8,3139;7A")); + + verifyPosition(decoder, text( + "STX,865067020439090,$GPRMC,171013.000,A,5919.1411,N,01804.1681,E,0.000,294.41,140815,,,A")); + + verifyPosition(decoder, text( + "$MGV002,013777007536434,,R,010114,000057,V,0000.0000,N,00000.0000,E,00,00,00,99.9,0.000,0.00,0.0,80.263,510,89,2342,030B,,0000,0000,200,96,0, , ,,,,Timer;!")); + + verifyPosition(decoder, text( + "STX,GerAL22,$GPRMC,174752.000,A,3637.060059,S,6416.2354,W,0.00,0.00,030812,,,A*55,F,,imei:861785000249353,05,180.6,Battery=100%,,1,722,310,0FA6,39D0;8F")); + + verifyPosition(decoder, text( + "STX,GerAL22,$GPRMC,000051.000,A,3637.079590,S,6416.2148,W,1.72,332.98,010109,,,A*52,L,,imei:861785000249353,03,275.3,Battery=68%,,1,722,07,0515,1413;41")); + + verifyPosition(decoder, text( + "STX,,$GPRMC,001339.000,A,4710.85395,N,02733.58209,E,1.65,238.00,010109,,,A*67,L,Help,imei:013227009737796,0/8,137.1,Battery=100%,,0,226,01,2B9B,BBBF;8D")); + + verifyPosition(decoder, text( + "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")); + + verifyPosition(decoder, text( + "STX863070014949464 $GPRMC,215942.290,A,4200.1831,N,02128.5904,E,003.1,079.8,090813,,,A*6E,294,02,0064,0F3D,18,17,0000,000000,0000,0.00,0.02,0.00,Store;D8")); + + verifyPosition(decoder, text( + "STX123456 $GPRMC,063709.000,A,2238.1998,N,11401.9670,E,0.00,,250313,,,A*7F,460,01,2531,647E,11,87,1000,001001,0000,0.00,0.02,0.00,Timer;4A")); + + verifyPosition(decoder, text( + "STX260475 $GPRMC,104032.001,A,4022.1119,N,01811.4081,E,000.0,000.0,060913,,,A*67,222,01,815A,D455,11,99,0000,0001,0,Timer;")); + + verifyPosition(decoder, text( + "LOGSTX,123456789012345,$GPRMC,225419.000,A,3841.82201,N,09494.73357,W,12.46,135.33,270914,,,A*47,F,,imei:123456789012345,0/6,,Battery=100%,,0,,,5856,78A3;24")); + + verifyPosition(decoder, text( + "LOGSTX,123456789012345,$GPRMC,230551.000,A,3841.81956,N,09494.45403,W,0.00,0.00,270914,,,A*7C,L,,imei:123456789012345,0/7,269.7,Battery=100%,,0,,,5856,78A3;83")); + + verifyPosition(decoder, text( + "LOGSTX,123456789012345,$GPRMC,230739.000,A,3841.81895,N,09494.12409,W,0.00,0.00,270914,,,A*70,L,,imei:123456789012345,0/7,269.7,Battery=100%,,0,,,5856,78A3;78")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java new file mode 100644 index 000000000..2d09c626b --- /dev/null +++ b/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java @@ -0,0 +1,29 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class MeiligaoFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MeiligaoFrameDecoder decoder = new MeiligaoFrameDecoder(); + + assertNull( + decoder.decode(null, null, binary("00"))); + + assertEquals( + binary("2424007b8621700151517899553233323835372e3030302c562c333632372e313835342c4e2c30313034352e323130392c452c302e30302c372c3239303131332c2c2a31347c302e307c347c303030307c303030382c303030357c303235443030303230303541374432327c30367c303030314530353527f40d0a"), + decoder.decode(null, null, binary("2424007B8621700151517899553233323835372E3030302C562C333632372E313835342C4E2C30313034352E323130392C452C302E30302C372C3239303131332C2C2A31347C302E307C347C303030307C303030382C303030357C303235443030303230303541374432327C30367C303030314530353527F40D0A"))); + + assertEquals( + binary("2424007b8621700151517899553233323835372e3030302c562c333632372e313835342c4e2c30313034352e323130392c452c302e30302c372c3239303131332c2c2a31347c302e307c347c303030307c303030382c303030357c303235443030303230303541374432327c30367c303030314530353527f40d0a"), + decoder.decode(null, null, binary("002424007B8621700151517899553233323835372E3030302C562C333632372E313835342C4E2C30313034352E323130392C452C302E30302C372C3239303131332C2C2A31347C302E307C347C303030307C303030382C303030357C303235443030303230303541374432327C30367C303030314530353527F40D0A"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java new file mode 100644 index 000000000..da5a81144 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java @@ -0,0 +1,137 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MeiligaoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MeiligaoProtocolDecoder decoder = new MeiligaoProtocolDecoder(null); + + verifyNull(decoder, binary( + "24240012254748594772ff080002ffff0d0a")); + + verifyNull(decoder, binary( + "242403fe254748594772ff99880242681100ffd8ffe000104a46494600010101000000000000ffdb004300080606070605080707070909080a0c140d0c0b0b0c1912130f141d1a1f1e1d1a1c1c20242e2720222c231c1c2837292c30313434341f27393d38323c2e333432ffdb0043010909090c0b0c180d0d1832211c213232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffc000110801e0028003012100021101031101ffda000c03010002110311003f00f0cc679a5a977d84b517d69474a98f615930e3a52edabea50b8a5c54c9e84c9f4178a5c7b50ad617bbd45a5c00287b16d681f852f5eb44aefde32e5bbb0ec0a38eb4d36d9a48753f150f4d5916f74318a70ad5dd8dc75168ed53ccadee8e239452f434afd10921719a7639aad56854ac3c0a5a98cfc8971d6c85a7f6a65ad07e29f8a1b10fc52ff153f405a6e48053f145f4b31abc5928e9cd4cabd3152f4d01ab6a4ca2a50a33509d9d809d56a50b56a7a87c24cbd6a655a2510ea4aa2a555a953b30255a92a80945498a435b8f1520a3d043b14e02974d40752d37a20490b4b40076a2a760129298094949e8030d368527b8c6530d4ddc84861a6353b8119a69e94b402334ca6e5a0861eb4c22b3d876184530d56e85623c506b27cd719e494bdabadab6a2d43e945227588a7d29739e69d92dc7d4703476cd569612d472b6452d4fbb61d828c734d6eac263fb52d539caf7634c55f6a2a1b8885a78e949db94528bd90539714dbea69bea2e7d29d9c51b19db4b053c75abffff0d0a")); + + verifyPosition(decoder, binary( + "242400716578902405843299553136323533332e3937382c412c343632332e313137392c4e2c30373932342e323437312c572c303030302c3030302c3139313231372c2c2a31437c31312e357c3139347c303030307c313139322c303030307c3835383030307c30303331343809540d0a")); + + verifyPosition(decoder, binary( + "242400716578902405843299553136323533332e3937382c412c343632332e313137392c4e2c30373932342e323437312c572c303030302c3030302c3139313231372c2c2a31437c31312e357c3139347c303030307c313139322c303030307c3835383030307c30303331343809540d0a")); + + verifyPosition(decoder, binary( + "2424010a142170525979ff9999753137353830322e3030302c412c313330362e303639342c4e2c31303035342e323439302c452c302e30302c3331332c3234313031372c2c2a30457c302e397c377c323530307c303030302c303030302c303130312c303241447c30323038303030353043313330313638353333427c30427c30303032313034357c30417c2520205e59454e53414241494348414924534f4e474b52414e244d522e5e5e3f3b363030373634333130303530303337333835333d3135303531393637303631343d3f2b202020202020202020202020203234202020202020202020202020312020202020202020202020203030303431313120203030313030545c0d0a")); + + verifyPositions(decoder, binary( + "2424006661172036237118668801003039333630342e3030302c562c303330332e333231352c4e2c31303134372e313530302c452c302e30302c2c3235313031377c302e307c302e307c303030307c303030302c303030307c30303030303230343259ca0d0a")); + + verifyPositions(decoder, binary( + "242401d961172036237118668805003039353830332e3030302c412c303330332e333431392c4e2c31303134372e343130342c452c372e30342c3230362e36312c3235313031377c302e307c302e307c303230307c303030302c303030307c3030303031313532325c003039353833332e3030302c412c303330332e323630302c4e2c31303134372e333734342c452c31302e33382c3236332e31342c3235313031377c302e307c302e307c303230307c303030302c303030307c3030303031313734355c003039353930332e3030302c412c303330332e313833382c4e2c31303134372e333735362c452c382e34392c3232332e37372c3235313031377c302e307c302e307c303230307c303030302c303030307c3030303031313839375c003039353933332e3030302c412c303330332e313033312c4e2c31303134372e333435332c452c382e37312c3139312e35302c3235313031377c302e307c302e307c303230307c303030302c303030307c3030303031323130325c003130303030302e3030302c412c303330332e313032332c4e2c31303134372e333338372c452c302e30302c3231332e36392c3235313031377c302e307c302e307c303030307c303030312c303030307c3030303031323131380d110d0a")); + + verifyPosition(decoder, binary( + "2424007f1092ffffffffff9999523232303534392e3030302c412c333533372e313231372c4e2c30313130302e303633332c452c362e34382c3139332c3238303631372c2c2a30357c302e387c32347c323030307c303030432c303030417c303235443030303230303833354437427c31357c3037303636424142f7310d0a")); + + verifyAttributes(decoder, binary( + "242400561001ffffffffff99553030303030302e3030302c562c303030302e303030302c532c30303030302e303030302c572c302e30302c302e30302c3232303839392c2c2c412a37457c7c307c3030303059ae0d0a0000")); + + verifyPosition(decoder, binary( + "242400706573402852404799553130313932372e3030302c412c313732362e38323739332c4e2c30373832382e31393637312c452c312e382c362e342c3137313131362c2c2a32427c312e36387c3534342e327c313030307c303030302c303030307c3030303032383638373a1a0d0a")); + + verifyPosition(decoder, binary( + "2424007d0000000000000099553231303333302e3030302c562c343533342e333832342c532c30373230332e303630302c572c302e30302c302c3231313031362c2c2a31327c302e307c3332397c323030307c303030452c303030437c303244413030303145413634393541417c31307c30303030303030306e540d0a")); + + verifyAttributes(decoder, binary( + "4040005066104020094432990131302E312C302C3135362C302E30302C31392E36312C2D33342C33342E32362C32312E38332C372E39312C313033332C322E36392C362E35352C302C302C309DBF0D0A")); + + verifyAttributes(decoder, binary( + "242400736610402421174399553130353033342e3937382c412c333933352e333638392c4e2c30303233382e313638342c452c303034382c3034322c3038313231362c2c2a31437c31312e357c3139347c313030317c303341362c303030307c30303130343030307c3030303030303cd00d0a2424004e66104024211743990131342e312c323638372c39302c32312e35372c342e37312c38352c372e31302c382e31362c342e32372c3130342c302e33342c392e33342c302c312c30b7160d0a2424003266104024211743990232352c322e34302c302e37392c32322c34332c3131392c333735362c37352c3132e4c90d0a")); + + verifyPosition(decoder, binary( + "242400746251103044ffff99553033353033392e3939392c412c323832332e373632312c4e2c31303635322e303730342c572c3030302e302c3030302e302c3136303631362c2c2c412a37357c302e397c323038332e327c303030307c303030302c303030307c31303034333736333265780d0a")); + + verifyPosition(decoder, binary( + "24240072190820157fffff99553039343335342e3030302c412c313930372e303631392c4e2c30373235312e333235312c452c3031302e312c3138382e352c3234303231362c2c2c412a36427c302e387c36352e327c303830307c303030302c303030307c303336343838373532c73f0d0a")); + + verifyPosition(decoder, binary( + "242400680790209818ffff99553038333235382e3030302c412c303131352e393338302c532c30333634382e313430392c452c302e30302c3331352e35352c3132303131367c302e37347c313930322e337c303430307c303030302c303030307c302e30f41b0d0a")); + + verifyNull(decoder, binary( + "24240011671440258855405000b24d0d0a")); + + verifyPosition(decoder, binary( + "242400706796502079108999553131333131382e3030302c412c313033372e393637382c4e2c30363132312e353637392c572c302e35342c322e34322c3330303931352c2c2c412a37307c302e37377c392e397c303030307c303030302c303161327c3030313138373132374cae0d0a"), + position("2015-09-30 11:31:18.000", true, 10.63280, -61.35947)); + + verifyPosition(decoder, binary( + "24240074630700194707719966009E1F7F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007C3132303334302C3238303630362C323430302E303030302C4E2C31323130302E303030302C458F7E0D0A"), + position("2006-06-28 12:03:40.000", true, 24.00000, 121.00000)); + + verifyPosition(decoder, binary( + "24240076220720151fffff99660012b3ab00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c3135303634382c3233303731352c313931352e37323835362c4e2c30373235322e35333034342c456dd00d0a")); + + verifyNull(decoder, binary( + "24240000123456FFFFFFFF50008B9B0D0A")); + + verifyPosition(decoder, binary( + "242400722015032700004299553134313131352e3030302c412c353031312e343335342c4e2c30303834332e373039322c452c3030302e302c3034342e362c3134303431352c2c2c412a36437c322e317c39392e347c303030307c303030302c303030307c3030303032343730350e480d0a")); + + verifyPosition(decoder, binary( + "2424006e241120141fffff99553039333931302e30302c412c313931342e37373736352c4e2c30373235302e36383037322c452c302e3035312c2c3230313231342c2c2c442a37357c302e38327c322e387c303030307c303030302c303030307c3031303833373433311d170d0a")); + + verifyPosition(decoder, binary( + "24240000123456FFFFFFFF99553033353634342E3030302C412C323233322E363038332C4E2C31313430342E383133372C452C302E30302C2C3031303830392C2C2A31437C31312E357C3139347C303030307C303030302C3030303069620D0A")); + + verifyPosition(decoder, binary( + "242400003358019703581F99553133343335312E3030302C412C303932352E353032352C4E2C30363931342E383130372C572C302E30302C32332C3330313031322C2C2A32437C302E387C3138367C323030307C303132362C303046467C303244453030303244384344423431357C30367C303046443642373995820D0A")); + + verifyPosition(decoder, binary( + "242400001691000484124F99553134303630332E3030302C412C303933342E323535342C4E2C30363931332E303936362C572C302E30302C2C3330313031322C2C2A30327C302E387C3230377C30303030FA420D0A")); + + verifyPosition(decoder, binary( + "2424000045124220306FFF9999143135353432322E3030302C562C323233302E373632332C4E2C31313430332E343231382C452C302E30302C302C3036303231312C2C2A31417C302E307C32367C303030307C303030302C303030307C303030303030303030303030303030307C36337C3030303030303030BAC10D0A")); + + verifyPosition(decoder, binary( + "242400008621700142458F9999503139323935382E3030302C412C333632372E313639392C4E2C30313034332E353632372C452C302E30302C3233392C3039313231322C2C2A30467C312E307C377C303030307C303141392C303139377C303235443030303230303541383639467C31327C3030303333424233E2480D0A")); + + verifyPosition(decoder, binary( + "24240000123456789FFFFF99553032303630302E3933302C412C323330392E323035312C4E2C31313331382E383434392C452C302E30302C302E30302C3039303731302C2C2C412A36417C322E367C39362E377C303030307C303030302C334646467C303030303030303030C4520D0A")); + + verifyPosition(decoder, binary( + "242400005977203744058499553032303131372E3030302C412C343131372E393231322C4E2C30383133302E323039362C572C302E30302C3330332E38352C3236303231337C312E367C30307C303030307C303030302C3030303071CD0D0A")); + + verifyPosition(decoder, binary( + "242400003511111111111199553133343734332e3030332c412c303634382e393836362c532c31303730372e353739352c452c3030302e302c3030302e302c323630333133f3150d0a")); + + verifyPosition(decoder, binary( + "242400000091800369764199553038353133302e3030302c412c333035332e313634352c4e2c30373535352e373437362c452c302e30302c32372c3136303431332c2c2a33467c302e387c3234357c323030307c303346372c303030302c303030302c303031422c303030302c303030302c303030302c303030307c303139343030303230314343363237437c31417c3031313630383439e6a70d0a")); + + verifyPosition(decoder, binary( + "2424000026016100901fff99553136353835332c412c343130392e36303231322c4e2c3833382e35393131392c572c332e3838332c31322e30302c3034303731332c2c2a34467c322e357c3131307c000600007c0000010f7c303242302c3042333697740d0a")); + + verifyNull(decoder, binary( + "2424000067622010053562aa0000010001ae4f00000007800000003039353135362e3030302c412c323632332e383936362c4e2c30353030352e303638302c452c32342e352c3234312e302c323231303133599c0d0a")); + + verifyPosition(decoder, binary( + "242400001007ffffffffff99553136323330392e3035342c562c303933312e393136332c4e2c30363931312e383233332c572c2c2c3235313131332c2c2c4e2a36437c7c3135387c303030309cc60d0a")); + + verifyAttributes(decoder, binary( + "242400003563070435652099553035323034322e3030302c412c343435382e333536352c4e2c30343130342e343831332c452c302e30302c302e30302c3139303131342c2c2a39437c302e3730303030307c2d3835393131373337367c303130307c307c7c7c4f2a0d0a")); + + verifyPosition(decoder, binary( + "2424005035784251ffffff99553030303033362e3938312c562c303933312e333437312c4e2c30363931312e383431322c572c2c2c3238303131342c2c2c4e2a36357c7c3136387c323030305e420d0a")); + + verifyPosition(decoder, binary( + "2424007811223344ffffff99553031303735372e3030302c412c323935392e313337342c4e2c30393534302e333238342c572c3030302e302c3038382e372c3234303631342c2c2c412a37397c312e347c33352e317c303030307c303030312c303030307c3030303030333732337c3030303030e39f0d0a")); + + verifyPosition(decoder, binary( + "2424007f3568960306760199553131303932342e3030302c412c343533342e323538352c4e2c30313933382e363531342c452c302e30302c2c3237303731342c2c2c412a37317c312e377c3130307c383030307c303737422c303030302c303030302c303030302c303030302c303030302c303030302c303030305dfc0d0a")); + + verifyPosition(decoder, binary( + "2424007f2015603256ffff99553230303230392e30302c412c313734342e36393434382c4e2c30383331392e30353537302c452c31302e3236322c3234382e35352c3236303631352c2c2c442a35437c302e39397c33312e397c303830317c303030302c303030637c3030303933303131367c3030376165313035d5550d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java new file mode 100644 index 000000000..ee4a869f9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java @@ -0,0 +1,41 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class MeiligaoProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + MeiligaoProtocolEncoder encoder = new MeiligaoProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_SINGLE); + + verifyCommand(encoder, command, binary("404000111234567890123441016cf70d0a")); + + command.setType(Command.TYPE_POSITION_PERIODIC); + command.set(Command.KEY_FREQUENCY, 100); + + verifyCommand(encoder, command, binary("40400013123456789012344102000a2f4f0d0a")); + + command.setType(Command.TYPE_SET_TIMEZONE); + command.set(Command.KEY_TIMEZONE, "GMT+8"); + + verifyCommand(encoder, command, binary("4040001412345678901234413234383030ad0d0a")); + + command.setType(Command.TYPE_REBOOT_DEVICE); + + verifyCommand(encoder, command, binary("40400011123456789012344902d53d0d0a")); + + command.setType(Command.TYPE_ALARM_GEOFENCE); + command.set(Command.KEY_RADIUS, 1000); + + verifyCommand(encoder, command, binary("4040001312345678901234410603e87bb00d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java new file mode 100644 index 000000000..53749816e --- /dev/null +++ b/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class MeitrackFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MeitrackFrameDecoder decoder = new MeitrackFrameDecoder(); + + assertEquals( + binary("24244e3132372c3836333037313031333830333036362c4141412c33352c2d312e3330323638302c33362e3835323133352c3135303430393231313032362c412c392c302c302e312c302c352c313635332c343039362c33323634382c3633397c30327c313030347c3930432c303030302c307c307c307c3346467c3330302c2a37430d0a"), + decoder.decode(null, null, binary("24244e3132372c3836333037313031333830333036362c4141412c33352c2d312e3330323638302c33362e3835323133352c3135303430393231313032362c412c392c302c302e312c302c352c313635332c343039362c33323634382c3633397c30327c313030347c3930432c303030302c307c307c307c3346467c3330302c2a37430d0a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java new file mode 100644 index 000000000..3e05d5243 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java @@ -0,0 +1,110 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MeitrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MeitrackProtocolDecoder decoder = new MeitrackProtocolDecoder(null); + + verifyNull(decoder, binary( + "242441313038362c3836343530373033313231393937342c4430302c3138303232343037323631345f4331453130395f4e31553144312e6a70672c31342c302cffd8ffdb008400140e0f120f0d14121012171514181e32211e1c1c1e3d2c2e243249404c4b47404645505a736250556d5645466488656d777b8182814e608d978c7d96737e817c011517171e1a1e3b21213b7c5346537c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7cffc000110801e0028003012100021101031101ffdd0004000affc401a20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa0100030101010101010101010000000000000102030405060708090a0b1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00cca69ac8d06e3348569884db4845021b498a60371494008692980119a8ca7a5342101a5cd5221a0ab312ed1ee68b943e80dce2a467ffd0c806a48e592270f13b230e841a0096eeea7bb09e6c85b667033552800069c2980e14f15422418a916ad099228a95455089505584140993a2d5fb598a7cae72bd8fa536ae892e8e69e2b9d971168a459fffd1ece8a0028a006b534f4a68ce5b9130a89ab444919a61a6c634d34d21894952310d25002514084a4a00ffd2d2349564086929082929805250025140094940c4a4a04251400949408292819fffd3cca31591a098a5c62801a45464531098a69a6210d371400629a6980628eb400c64cd3791c1aa16c491479393563343105424fcc4d007ffd4c3463c0a94500381a5e3b8cd000c99e57f2a8f3835402834e0d4d08914d4aa6ac4c954d4aad4c4c955aa647a6496236ab51b552132e412e383d3f955b0722b09ab32a0c5a2a0d0ffd5ece8a0028a0061a6d5193dc8daa36ab422334c34c634")); + + verifyPositions(decoder, binary( + "24246b3131342c3836353738393032343134303439352c4343452c0000000001005000130006011f05010607071415001b00060800000949010a0c000b9b0119a1011afe010602e934ce0203fc9aeb0004309f13220cafc503000d97741e001c01000000010e0ce8000300092f2e060000b7ff2a33330d0a")); + + verifyPosition(decoder, buffer( + "$$^182,864507031245110,AAA,109,13.844553,100.644360,171227173141,A,11,19,0,359,0.8,8,15075,934591,520|4|0643|07D20555,8400,0000|0000|0000|018D|04CB,,,108,0000,,6,0,,,,,10|171227173100*7C")); + + verifyPosition(decoder, buffer( + "$$S214,864507031219974,AAA,109,13.844643,100.644395,171207021520,A,10,28,0,31,0.8,6,390,421327,520|0|0016|000F2DB0,8400,0000|0000|0000|018D|04C6,,,108,0000,,6,0,,,,,11|171207091500|171207091500|78|3500|000000|000003*12")); + + verifyPositions(decoder, binary( + "24245f3237382c3836353738393032313434373233322c4343452c5b00000003005000130006012305010608070d15001b0006080000091e010a09000b2e0019a1011af90106025c033300039be60c06044f6678210c6f1806000d48db06001c41000000010e0cf60113002005912b830001ff5000130006012305010608070d15001b0006080000091e010a09000b2e0019a0011af90106025c033300039be60c0604506678210c6f1806000d49db06001c41000000010e0cf60113002005912b830001ff5000130006012305010608070d15001b0006080000091e010a09000b2e0019a1011af90106025c033300039be60c0604516678210c6f1806000d4adb06001c41000000010e0cf60113002005912b830001ff2a37460d0a")); + + verifyPosition(decoder, buffer( + "$$V177,863835026871173,AAA,35,34.516428,10.470160,170915154043,A,9,12,68,74,0.9,9,1988259,525882,605|2|008C|0007B5A6,0200,0003|0000|0000|01A6|0571,00000001,,3,0000,06FB2E,360,511*74")); + + verifyPosition(decoder, buffer( + "$$V177,863835026871173,AAA,35,34.516428,10.470160,170915154043,A,9,12,68,74,0.9,9,1988259,525882,605|2|008C|0007B5A6,0200,0003|0000|0000|01A6|0571,00000001,,3,0000,010A92,360,511*74")); + + verifyPosition(decoder, buffer( + "$$B136,011691002364761,AAA,29,47.055220,28.893193,170914144240,V,0,7,0,0,0,132,129754946,129793197,259|2|02F8|413F,0000,000D|000C||028C|,*9E")); + + verifyNotNull(decoder, buffer( + "$$F153,863835026880190,AAA,29,25.313160,55.422473,170628150902,V,0,0,0,0,0.0,0,6553,6697,0|0|0000|00000000,0000,0002|0000|0000|018B|0000,,,3,0000,,110,386*22")); + + verifyPosition(decoder, buffer( + "$$T143,869013024733944,AAA,1,18.459575,-69.947161,170220142912,A,5,15,10,300,1.6,115,3989,187884,370|2|5337|2B2C,0100,0000|0000|0000|0964|0B04,,*C2")); + + verifyPosition(decoder, buffer( + "$$K157,866771027160687,AAA,3,37.040231,10.042391,160412151656,A,10,11,0,48,0.8,21,1035518,774980,605|2|0010|307B,0400,0000|0000|0000|0A47|03E3,,,1,0000,001206*2C")); + + verifyNull(decoder, buffer( + "$$D28,353358017784062,D03,OK*F3")); + + verifyPosition(decoder, buffer( + "$$A158,79007001520234,AAA,35,40.996370,-8.575065,150730184834,A,8,24,0,1,1.3,173,32573389,31405012,268|3|2BC0|250B,2000,|||0A2D|0000,00000001,,50,,,,,,,,,,,,,*4A"), + position("2015-07-30 18:48:34.000", true, 40.99637, -8.57507)); + + verifyPosition(decoder, buffer( + "$$G145,862106024274815,AAA,35,-1.287125,36.906061,150530054639,A,10,13,12,67,0.8,1621,38359791,42330881,639|2|FB2|2F3,0000,3|0|0|A58|432,,,1,0009,*26")); + + verifyPosition(decoder, buffer( + "$$I152,013949004569813,AAA,37,54.739468,25.273648,150208173414,A,5,24,0,73,1.5,165,74,3381,246|1|0065|118A,0000,0003|0003|0000|08D4|0002,006380DF,,1,0008*7C")); + + verifyPosition(decoder, buffer( + "$$E141,863071013799553,AAA,35,-1.264521,36.801128,150307132846,A,11,20,0.2,0,5,1767,84045888,36496633,639|02|100E|844,1234,0018|||025D|00CB,*17")); + + verifyPosition(decoder, buffer( + "$$m140,013777008931857,AAA,1,54.739580,25.273263,141120144603,V,0,25,0,6,50.0,159,19825,13940,246|1|0065|118A,0100,0000|0000|0000|092A|0001,,*1C")); + + verifyPosition(decoder, buffer( + "$$X138,862170010187175,AAA,35,-29.960365,-51.655455,130507201625,A,8,9,0,107,0.9,7,169322,126582,724|6|0547|132B,0000,0009|000A||0278|0000,*BE")); + + verifyPosition(decoder, buffer( + "$$X138,862170010187175,AAA,35,-29.960365,-51.655455,130507201625,A,8,9,0,107,0.9,-7,169322,126582,724|6|0547|132B,0000,0009|000A||0278|0000,*BE")); + + verifyPosition(decoder, buffer( + "$$]138,012896000475498,AAA,35,-6.138255,106.910545,121205074600,A,5,18,0,0,0,49,3800,24826,510|10|0081|4F4F,0000,0011|0012|0010|0963|0000,,*94")); + + verifyPosition(decoder, buffer( + "$$d138,012896000475498,AAA,35,-6.138255,106.910545,121205074819,A,7,18,0,0,0,49,3800,24965,510|10|0081|4F4F,0000,000D|0010|0012|0963|0000,,*BF")); + + verifyPosition(decoder, buffer( + "$$j138,012896000475498,AAA,35,-6.138306,106.910655,121205103708,A,3,11,0,0,1,36,4182,35025,510|10|0081|4F4F,0000,000A|000C|000A|0915|0000,,*BF")); + + verifyPosition(decoder, buffer( + "$$m139,012896005334567,AAA,35,-33.866423,151.190060,121208020649,A,7,27,0,32,4,13,6150,49517,505|2|0B67|5A6C,0000,0000|0000|0000|0977|0000,,*F1")); + + verifyPosition(decoder, buffer( + "$$A141,012896005334567,AAA,35,-33.866543,151.190148,121209081758,A,6,27,0,16,1,48,65551,152784,505|2|0B5F|D9D3,0000,0000|0000|0000|0A39|0000,,*5B")); + + verifyPosition(decoder, buffer( + "$$_128,861074020109479,AAA,34,22.512618,114.057065,090215000318,V,0,31,0,0,0,0,0,733,302|720|3EE4|BBB5,0000,0006|0006||028C|0000,*E3")); + + verifyPosition(decoder, buffer( + "$$K146,013227004985762,AAA,35,28.618005,-81.246783,131101213828,A,9,22,0,209,1.1,23,80974,1187923,310|260|2A13|634E,0000,0000|0000|0000|09DA|0B34,,*51")); + + verifyPosition(decoder, buffer( + "$$E150,013777001165479,AAA,35,10.296601,123.872115,140501161505,A,4,22,1,170,1.4,77,39097,393563,515|3|A0CC|ED96,0000,0008|0003|0000|09D5|0000,,,1,0009*1E")); + + verifyPosition(decoder, buffer( + "$$B140,013777001293701,AAA,35,-7.266760,112.743550,140521095314,A,3,22,0,275,2.7,45,1984,8059,510|1|3504|EBFE,0000,0000|0000|0000|0914|0002,,*F9\r\n")); + + verifyPosition(decoder, buffer( + "$$J163,123123123123123,AFF,0004,35,58.588926,16.180473,140928192856,A,10,27,0,161,1.2,19,1648894,435695,240|24|88B9|E435,0000,|||0A22|0000,00000001,,50,,,,,,,,,,,,,*70\r\n")); + + verifyPositions(decoder, binary( + "24245838362c3336393830303031343039303032312c4343432c020134000100000023381f91ffe354b806c5e3121b0009130000000000000000d33801007cbf0200fe0101000435feeb02000500a3010000000000002a62650d0a"), + position("2014-05-24 04:59:49.000", false, -7.26650, 112.74365)); + + verifyPositions(decoder, binary( + "2424473937302c3336393830303031333436303637342c4343432c020134005b000000010ce304035db9e000ec6f591a000013000000000c001801edb70200c96d0100e60001004838576501000300a101c20400000000010ce304035db9e000ee6f591a000013000000000c001801edb70200ca6d0100e60001004838576501000300a101c20400000000010ce304035db9e000ef6f591a000013000000000c001801edb70200cc6d0100e60001004838576501000300a101c20400000000020ce304035db9e000f76f591a000016000000000c001801edb70200d36d0100e60001004838576502000300a101bf04000000000a0ce304035db9e000f76f591a000016000000000c001801edb70200d46d0100e60001004838576500000300a101bf0400000000020ce304035db9e000fb6f591a000016000000000c001801edb70200d86d0100e60001004838576502000300a101760400000000180ce304035db9e000fc6f591a0000120000000000008c00edb70200d96d0100e60001004838576502000300a10176040000000019b1e2040323b9e0000b70591a0105150600bb0012002901edb70200e76d0100e60001004838576502000300a2017005000000002023e304031fb9e0001070591a010615070027010d001601fcb70200ec6d0100e60001004838576502000300a201800500000000201fe3040302b9e0001170591a010615090019010d001501feb70200ed6d0100e60001004838576502000300a2018005000000002018e30403dcb8e0001270591a0106150b0011010d00150100b80200ee6d0100e60001004838576502000300a2018005000000002036e3040345b8e0001570591a0107150b002d010b0013010ab80200f16d0100e60001004838576502000300a2018005000000002053e3040326b8e0001670591a0107150d0041010b0013010eb80200f26d0100e60001004838576502000300a2018005000000002070e3040310b8e0001770591a0107150e004f010b00130111b80200f36d0100e60001004838576502000300a2018005000000002095e3040306b8e0001870591a0107150d005a010b00140115b80200f46d0100e60001004838576502000300a20180050000000020b3e3040305b8e0001970591a0107150b0060010b00140118b80200f56d0100e60001004838576502000300a20183050000000020cfe3040308b8e0001a70591a0107150b0066010b0014011bb80200f66d0100e60001004838576502000300a20183050000000020eee304030cb8e0001b70591a0106170b0004000d0014011eb80200f76d0100e60001004838576502000300a2018305000000002a62350d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java new file mode 100644 index 000000000..b63ce5051 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class MeitrackProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + MeitrackProtocolEncoder encoder = new MeitrackProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_SINGLE); + + assertEquals("@@Q25,123456789012345,A10*68\r\n", encoder.encodeCommand(command)); + + command.setDeviceId(1); + command.setType(Command.TYPE_REQUEST_PHOTO); + + assertEquals("@@D46,123456789012345,D03,1,camera_picture.jpg*1F\r\n", encoder.encodeCommand(command)); + + command.setDeviceId(1); + command.setType(Command.TYPE_SEND_SMS); + command.set(Command.KEY_PHONE, "15360853789"); + command.set(Command.KEY_MESSAGE, "Meitrack"); + + assertEquals("@@f48,123456789012345,C02,0,15360853789,Meitrack*B0\r\n", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java new file mode 100644 index 000000000..be0209975 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MilesmateProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MilesmateProtocolDecoder decoder = new MilesmateProtocolDecoder(null); + + verifyPosition(decoder, text( + "ApiString={A:861359037373030,B:09.8,C:00.0,D:083506,E:2838.5529N,F:07717.8049E,G:000.00,H:170918,I:G,J:00004100,K:0000000A,L:1234,M:126.86}")); + + verifyPosition(decoder, text( + "ApiString={A:861359037496211,B:12.7,C:06.0,D:060218,E:2837.1003N,F:07723.3162E,G:016.80,H:310818,I:G,J:10010100,K:0000000A,L:1234,M:358.33}"), + position("2018-08-31 06:02:18.000", true, 28.61834, 77.38860)); + + verifyPosition(decoder, text( + "ApiString={A:862631032208018,B:12.1,C:24.4,D:055852,E:2838.5310N,F:07717.8126E,G:000.0,H:200117,I:G,J:10100100,K:1000000A,L:1234,M:324.45}")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java new file mode 100644 index 000000000..afa930e5b --- /dev/null +++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java @@ -0,0 +1,73 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MiniFinderProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MiniFinderProtocolDecoder decoder = new MiniFinderProtocolDecoder(null); + + verifyNull(decoder, text( + "!1,867273023933661,V07S.5701.1621,100")); + + verifyAttributes(decoder, text( + "!3,ok")); + + verifyNull(decoder, text( + "!1,123456789012345")); + + verifyNull(decoder, text( + "!5,17,V")); + + verifyNull(decoder, text( + "!1,860719027585011")); + + verifyPosition(decoder, text( + "!D,02/05/17,19:56:17,47.083542,15.482373,0,0,100001,479.3,100,4,9,0")); + + verifyPosition(decoder, text( + "!D,15/04/17,13:58:53,51.483067,-0.452548,60,180,140001,28.7,47,4,13,0")); + + verifyPosition(decoder, text( + "!D,07/04/17,05:42:26,-37.588970,145.121231,0,0,0c0001,185.2,92,7,14,1.2")); + + verifyPosition(decoder, text( + "!D,28/11/16,00:04:09,42.926067,-85.747589,124,236,140001,179.8,60,11,16,0")); + + verifyPosition(decoder, text( + "!C,30/1/16,1:1:6,31.259157,30.020910,0,0,100001,25.32,100,0.03,0.01,0")); + + verifyPosition(decoder, text( + "!A,26/10/12,00:28:41,7.770385,-72.215706,0.0,25101,0")); + + verifyPosition(decoder, text( + "!A,01/12/10,13:25:35,22.641724,114.023666,000.1,281.6,0")); + + verifyPosition(decoder, text( + "!D,08/07/15,04:01:32,40.428257,-3.704808,0,0,170001,701.7,22,5,14,0")); + + verifyPosition(decoder, text( + "!D,08/07/15,04:55:13,40.428257,-3.704932,0,0,180001,680.0,8,8,13,0")); + + verifyPosition(decoder, text( + "!D,08/07/15,02:01:32,40.428230,-3.704950,4,170,170001,682.7,43,6,13,0")); + + verifyNull(decoder, text( + "!1,860719020212696")); + + verifyPosition(decoder, text( + "!D,22/2/14,13:40:58,56.899601,14.811541,0,0,1,176.0,98,5,16,0"), + position("2014-02-22 13:40:58.000", true, 56.89960, 14.81154)); + + verifyPosition(decoder, text( + "!D,22/2/14,13:47:51,56.899517,14.811665,0,0,b0001,179.3,97,5,16,0")); + + verifyPosition(decoder, text( + "!D,3/7/13,6:35:30,22.645952,114.040436,0.0,225.8,1f0001,12.11,98,0,0,0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java new file mode 100644 index 000000000..e9422da9f --- /dev/null +++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java @@ -0,0 +1,33 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class MiniFinderProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + MiniFinderProtocolEncoder encoder = new MiniFinderProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SET_TIMEZONE); + command.set(Command.KEY_TIMEZONE, "GMT+1"); + + assertEquals("123456L+01", encoder.encodeCommand(command)); + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SOS_NUMBER); + command.set(Command.KEY_INDEX, 2); + command.set(Command.KEY_PHONE, "1111111111"); + + assertEquals("123456C1,1111111111", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java new file mode 100644 index 000000000..c4f15d907 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MtxProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MtxProtocolDecoder decoder = new MtxProtocolDecoder(null); + + verifyPosition(decoder, text( + "#MTX,353815011138124,20101226,195550,41.6296399,002.3611174,000,035,000000.00,X,X,1111,000,0,0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java new file mode 100644 index 000000000..834a35011 --- /dev/null +++ b/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java @@ -0,0 +1,45 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MxtProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MxtProtocolDecoder decoder = new MxtProtocolDecoder(null); + + verifyPosition(decoder, binary( + "01a631144c7e0008643ad2f456fb2d49747cfe4cbe0ffd002008800000001021000fd43d3f1403000000ff300000f42760001031102445a81fda04")); + + verifyPosition(decoder, binary( + "01a631361e7a00082471418b052a2c46b587ffc01ae3fd000008800000000000003345422203000000f000f00000000000ea1e04")); + + verifyPosition(decoder, binary( + "01a63118787d00086440628d226e2bc26a97feac8a3afd10210010308000000000000018003d2b10240000005e2f0000f427f21031feff0000593804")); + + verifyPosition(decoder, binary( + "01a631bd777d0008646e319e17292ce86798fed4cd3afd102110211030800000102403001f15003e2b102400000034300000f4271021007b175535a7be04")); + + verifyPosition(decoder, binary( + "01a631e3f97e00087cf40a98151c2cc46898fee0ce3afd1021001030c0000006102116072e003829bb00000036102100001024000000062b0000f42730004b06a6384b4304")); + + verifyPosition(decoder, binary( + "01a63118787d00086468457a466a2bc26a97feac8a3afd10212010308000000000001fe1053d291024000000922f0000f4271021007b17553599bb04")); + + verifyPosition(decoder, binary( + "01a63118787d0008648645ec486a2bc26a97feac8a3afd1021001030c0000000001419eb05372b1024000000982a0000f4271021007b17000010308c04")); + + verifyPosition(decoder, binary( + "01a631e3f97e00087cfa0af3151c2c126798febace3afd1021801030c0000006102122082f003e29bb00000037102100001024000000ab2f0000f42730004b060000488c04")); + + verifyPosition(decoder, binary( + "01a631e3f97e00087cfe0a4b161c2c126798febace3afd1021801030800000071021240731003e2abb00000038102100001024000000c12f0000f42730004b06a638633104")); + + verifyPosition(decoder, binary( + "01a63118787d0008648645ec486a2bc26a97feac8a3afd1021001030c0000000001419eb05372b1024000000982a0000f4271021007b17000010308c04")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java new file mode 100644 index 000000000..2db4afbf2 --- /dev/null +++ b/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class NavigilProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + NavigilProtocolDecoder decoder = new NavigilProtocolDecoder(null); + + verifyNull(decoder, binary( + "01004300040020000000f60203080200e7cd0f510c0000003b00000000000000")); + + verifyPosition(decoder, binary( + "0100b3000f0024000000f4a803080200ca0c1151ef8885f0b82e6d130400c00403000000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java new file mode 100644 index 000000000..0ebfeacd2 --- /dev/null +++ b/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.traccar.ProtocolTest; + +import org.junit.Test; + +public class NavisFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecodeNtcb() throws Exception { + + NavisFrameDecoder frameDecoder = new NavisFrameDecoder(); + + verifyFrame(binary( + "404e5443010000000000000059009adb2a3e54250000000000ff1500040b0a1008291838001200760ee600000000000000000000000f1500040b0a10ac20703fb1aec23f00000000320149668f430000000000000000000000000000000000000000000000f3808080"), + frameDecoder.decode(null, null, binary("404e5443010000000000000059009adb2a3e54250000000000ff1500040b0a1008291838001200760ee600000000000000000000000f1500040b0a10ac20703fb1aec23f00000000320149668f430000000000000000000000000000000000000000000000f3808080"))); + + } + + @Test + public void testDecodeFlex10() throws Exception { + + NavisFrameDecoder frameDecoder = new NavisFrameDecoder(); + + frameDecoder.setFlexDataSize(73); + + verifyFrame(binary( + "7e54040000000400000030129957405c000b00632f9857405ccace03021e129101a103000000000000c4005ba3fe3b00000000120046100000000000001aff7f000080bfffff80000080bfffffffff9f"), + frameDecoder.decode(null, null, binary("7e54040000000400000030129957405c000b00632f9857405ccace03021e129101a103000000000000c4005ba3fe3b00000000120046100000000000001aff7f000080bfffff80000080bfffffffff9f"))); + + verifyFrame(binary( + "7e4101080000000917c057405c002b001833c057405cbbce030225129101a00300007c6102408900400c1b3cfce3b23a12004710e000000000001bff7f000080bfffff80000080bfffffffffb2"), + frameDecoder.decode(null, null, binary("7e4101080000000917c057405c002b001833c057405cbbce030225129101a00300007c6102408900400c1b3cfce3b23a12004710e000000000001bff7f000080bfffff80000080bfffffffffb2"))); + } + +} diff --git a/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java new file mode 100644 index 000000000..33a6bab24 --- /dev/null +++ b/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java @@ -0,0 +1,79 @@ +package org.traccar.protocol; + +import org.traccar.ProtocolTest; + +import org.junit.Test; + +public class NavisProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecodeNtcb() throws Exception { + + NavisProtocolDecoder decoder = new NavisProtocolDecoder(null); + + verifyNull(decoder, binary( + "404E5443010000007B000000130044342A3E533A383631373835303035323035303739")); + + verifyNull(decoder, binary( + "404E5443010000007B000000130047372A3E533A383631373835303035313236303639")); + + verifyPosition(decoder, binary( + "404e5443010000000000000059009adb2a3e54250000000000ff1500040b0a1008291838001200760ee600000000000000000000000f1500040b0a10ac20703fb1aec23f00000000320149668f430000000000000000000000000000000000000000000000f3808080"), + position("2016-11-11 21:00:04.000", true, 53.74336, 87.14437)); + + verifyPositions(decoder, binary( + "404e544300000000040000005a00c6812a3e410125e3a60700011705071503011030210c0000fa200910e6000000000000000000000001082106150010ae97643f88a39f3f0000000090001fcc6c450000000000000000000000000000000000000000000000f6808080")); + + verifyPositions(decoder, binary( + "404e544301000000000000005a002e6c2a3e410125d7540100001512233a0b0a0f08026300000a000b000b00020000000000000000000c12233b0b0a0f03fd6d3f0fde603f00000000ba0051e0c845000000000000000000000000000000000000000000000080808080")); + + verifyPositions(decoder, binary( + "404E5443010000007B0000005A0050692A3E410125DB0E00000015110707110A0C0880630000AA39A2381600020000000000000000000C110708110A0CB389793F1AEF263F00000000120034F516440000000000000000000000FAFF000000FAFF000000FAFF80808080")); + + verifyPosition(decoder, binary( + "404e544301000000cdfbf5027200852e2a3e5406aa170000c11116162410001310a9110e80996b281003000a0008000000000000000000d207d207ffffff00fbff00fbff00fbff00fbff00fbff00fbff00fbff2d808080ffffffffffff2b161624100013509b0302b0f89201830500000000000037002fb8cf43eed5843a35003500"), + position("2019-01-16 22:22:36.000", true, 56.31800, 44.01523)); + + verifyPositions(decoder, binary( + "404e54430100000045635902730081972a3e4101060b7e0e000b171328050d00133029110e00bc6141100200000000000000000000000000d207d307ffffff00fbff00fbff00fbff00fbff00fbff00fbff00fbff02808080ffffffffffff4f1328050d001371cd0302c5109101a60300000000000000003d1b37470000000096009600")); + } + + @Test + public void testDecodeFlex10() throws Exception { + + NavisProtocolDecoder decoder = new NavisProtocolDecoder(null); + + verifyNull(decoder, binary( + "404e544301000000c9b5f602130046c52a3e533a383639363936303439373232383235")); + + verifyNull(decoder, binary( + "404e544301000000aaecf6021300c8712a3e464c4558b00a0a45ffff300a08080f8388")); + + verifyPosition(decoder, binary( + "7e54040000000400000030129957405c000b00632f9857405ccace03021e129101a103000000000000c4005ba3fe3b00000000120046100000000000001aff7f000080bfffff80000080bfffffffff9f"), + position("2019-01-17 10:23:20.000", true, 56.33996, 43.80762)); + + verifyPositions(decoder, binary( + "7e4101080000000917c057405c002b001833c057405cbbce030225129101a00300007c6102408900400c1b3cfce3b23a12004710e000000000001bff7f000080bfffff80000080bfffffffffb2")); + } + + @Test + public void testDecodeFlex20() throws Exception { + + NavisProtocolDecoder decoder = new NavisProtocolDecoder(null); + + verifyNull(decoder, binary( + "404e544301000000a9eef602130043fb2a3e533a383639363936303439373337333835")); + + verifyNull(decoder, binary( + "404e544301000000a9eef6021a003f8e2a3e464c4558b014147afffff008080800000e00000000000000")); + + verifyPosition(decoder, binary( + "7e5428000000280000002111d16b435c00a900154bd16b435ce19e030259f6920133050000b7623e429300c9e7f03f2ba45a3e1f001f007b6c5910850f0100001629080a000000000000060947"), + position("2019-01-19 18:26:25.000", true, 56.31952, 44.01423)); + + verifyPositions(decoder, binary( + "7e4101270000000b17b16b435c00a9000d4bb26b435caaa2030229f29201620500000000000093004493d53fee892d3e1f001f00ac6c591081f00000001700080a0000000000000609f2")); + } + +} diff --git a/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java new file mode 100644 index 000000000..a8db30476 --- /dev/null +++ b/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class NeosProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + NeosProtocolDecoder decoder = new NeosProtocolDecoder(null); + + verifyPosition(decoder, text( + ">12345678,1,1,070201,144111,W05829.2613,S3435.2313,,00,034,25,00,126-000,0,3,11111111*2d!\r\n")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java new file mode 100644 index 000000000..7c02402b1 --- /dev/null +++ b/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java @@ -0,0 +1,45 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class NoranProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + NoranProtocolDecoder decoder = new NoranProtocolDecoder(null); + + verifyNull(decoder, binary( + "0d0a2a4b57000d000080010d0a")); + + verifyPosition(decoder, binary( + "34000800010b0000000000003f43bb8da6c2ebe229424e523039423233343439000031362d30392d31352030373a30303a303700")); + + verifyPosition(decoder, binary( + "28003200c380000000469458408c4ad340ad381e3f4e52303947313336303900000001ff00002041")); + + verifyPosition(decoder, binary( + "28003200c38000d900fcc97a416b1a7a42b43eef3d4e523039473034383737000000000092fcda4a")); + + verifyPosition(decoder, binary( + "3400080001090000000000001D43A29BE842E62520424E523039423036363932000031322D30332D30352031313A34373A343300")); + + verifyPosition(decoder, binary( + "34000800010c000000000080a3438e20944149bd07c24e523039423139323832000031352d30342d32362030383a34333a353300")); + + verifyNull(decoder, binary( + "0f0000004e52303946303431353500")); + + verifyPosition(decoder, binary( + "22000800010c008a007e9daa42317bdd41a7f3e2384e523039463034313535000000")); + + verifyPosition(decoder, binary( + "34000800010c0000000000001c4291251143388d17c24e523039423131303930000031342d31322d32352030303a33333a303700")); + + verifyPosition(decoder, binary( + "34000800010c00000000000000006520944141bd07c24e523039423139323832000031352d30342d32352030303a30333a323200")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java new file mode 100644 index 000000000..38599e0ba --- /dev/null +++ b/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class NoranProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + NoranProtocolEncoder encoder = new NoranProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + verifyCommand(encoder, command, binary( + "0d0a2a4b5700440002000000000000002a4b572c3030302c3030372c3030303030302c302300000000000000000000000000000000000000000000000000000000000d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java new file mode 100644 index 000000000..8a00207eb --- /dev/null +++ b/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class NvsFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + NvsFrameDecoder decoder = new NvsFrameDecoder(); + + assertEquals( + binary("0012333537303430303630303137383234312e38"), + decoder.decode(null, null, binary("0012333537303430303630303137383234312e38"))); + + assertEquals( + binary("cccccccc0073000144b9ddf2aca002015694823d1f165d80902139a44f00aa001e1400000103000a080115001a001d001e0141004001f00065001301061600001700001800004231da430000440000085000000000480000000049000000004a0000000047ffffffff6900000004c700000000e10000000100954a"), + decoder.decode(null, null, binary("cccccccc0073000144b9ddf2aca002015694823d1f165d80902139a44f00aa001e1400000103000a080115001a001d001e0141004001f00065001301061600001700001800004231da430000440000085000000000480000000049000000004a0000000047ffffffff6900000004c700000000e10000000100954a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java new file mode 100644 index 000000000..9a516e733 --- /dev/null +++ b/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class NvsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + NvsProtocolDecoder decoder = new NvsProtocolDecoder(null); + + verifyNull(decoder, binary( + "0012333537303430303630303137383234312e38")); + + verifyNull(decoder, binary( + "0012313233343536373839303132333435312E31")); + + verifyPositions(decoder, binary( + "cccccccc0073000144b9ddf2aca002015694823d1f165d80902139a44f00aa001e1400000103000a080115001a001d001e0141004001f00065001301061600001700001800004231da430000440000085000000000480000000049000000004a0000000047ffffffff6900000004c700000000e10000000100954a")); + + verifyPositions(decoder, binary( + "CCCCCCCC00FE00007048860DDF79020446a6f1ce010f14f650209cca80006f00d6040004010300030101150316030001460000015d0046a6f1dc0d0f14ffe0209cc580006e00c7050001010300030101150316010001460000015e0046a6f1ea0e0f150f00209cd20000950108040000010300030101150016030001460000015d0046a6f1ff0b0f150a50209cccc000930068040000010300030101150016030001460000015b006123")); + + verifyPositions(decoder, binary( + "cccccccc0217000144b9ddf2aca002055683f72b01165d80632139a3c800ab00ce0a00000403000a080115bf1a001d001e0141004001f00065011301061600001700001800004231a9430000440000085000000000480000000049000000004a0000000047ffffffff69000000b7c700000000e100000001005683f74901165d80632139a3c800ab012a0a00000403000a080115bf1a001d001e0141004001f00065011301061600001700001800004231a9430000440000085000000000480000000049000000004a0000000047ffffffff69000000b8c700000000e100000001005683f76801165d80632139a3c800ab00590a00000403000a080115bf1a001d001e0141004001f00065011301061600001700001800004231a9430000440000085000000000480000000049000000004a0000000047ffffffff69000000b9c700000000e100000001005683f78601165d80632139a3c800ab00c80a00000403000a080115bf1a001d001e0141004001f00065011301061600001700001800004231a9430000440000085000000000480000000049000000004a0000000047ffffffff69000000bac700000000e100000001005683f7a401165d80632139a3c800ab01310a00000403000a080115bf1a001d001e0141004001f00065011301061600001700001800004231a9430000440000085000000000480000000049000000004a0000000047ffffffff69000000bbc700000000e100000001001d72")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java new file mode 100644 index 000000000..4cafd7612 --- /dev/null +++ b/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class NyitechProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + NyitechProtocolDecoder decoder = new NyitechProtocolDecoder(null); + + verifyPosition(decoder, binary( + "4040690030313436383230303238373201201c0c12031a308080801c0c12031a3007d67e7e08aceb841002000000ae08000000000000000000000000001e002900f0ffdd002700f2ffe0002700f2ffe1002400f0ffdf002400f3ffe3008a00ffff01010000a9c70d0a")); + + verifyPosition(decoder, binary( + "4040390030313436383230303238373203200100010c000000001c0c1203192a1b0c12171d3104fed87d089288801000000000000011ec0d0a")); + + verifyPosition(decoder, binary( + "4040480030313436383230303238373201101c0c12031a2907fa7e7e08b8eb841002000000bc080101040904040300010100000a818283848586878862611c0c12031a293f9c0d0a")); + + verifyPosition(decoder, binary( + "40404b003247512d313630313030313901101e0b100604190c02c83707f887ac0f000000002d130101030304020000010100000d426162636465666768696a6ba51e0b1006041965c30d0a")); + + verifyPosition(decoder, binary( + "4040490030313436383230303238373202201c0c120319348080001b0c12171d3104fed87d0892888010000000000000000000000000000000000000008b00ffff010100008a480d0a")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java new file mode 100644 index 000000000..4c33d1766 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ObdDongleProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ObdDongleProtocolDecoder decoder = new ObdDongleProtocolDecoder(null); + + verifyNull(decoder, binary( + "55550003383634383637303232353131303135010009010011023402010201ABAAAA")); + + verifyPosition(decoder, binary( + "5555000338363438363730323235313130313503000100010355AABBCC184F1ABC614E21C1FA08712A84ABAAAA"), + position("2015-07-18 20:49:16.000", true, 22.12346, -123.45678)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java new file mode 100644 index 000000000..c79978f88 --- /dev/null +++ b/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java @@ -0,0 +1,42 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class OigoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + OigoProtocolDecoder decoder = new OigoProtocolDecoder(null); + + verifyPosition(decoder, binary( + "7e002e000000146310002523830400001bfb000369150f310c0591594d062ac0c0141508011303cd63101604fd00000000")); + + verifyPosition(decoder, binary( + "0103537820628365110310410790660962521813380026EE4EFF8593AA0065003E00794C020600100500000000")); + + verifyPosition(decoder, binary( + "0E03537820628344660204043255862749531B100E0026EE3AFF8593A3FFFE00BF00044C20090710C300000000")); + + verifyPosition(decoder, binary( + "00035378206638500203340201271426226b190203001ac000ff72eedd00370097238b4c34116a130b000094d9")); + + verifyPosition(decoder, binary( + "1d035378206638500203340201271426226b19020c001ab144ff72f74d005f0097298a4c1d066d130b000094de")); + + verifyPosition(decoder, binary( + "00035378206638500203340201271426226b191016001c04e5ff760081013d002900814c1a0f5e130b00009576")); + + verifyPosition(decoder, binary( + "7e004200000014631000258257000000ffff02d0690e000220690e0002200696dbd204bdfde31a070000b307101135de106e05f500000000010908010402200104ffff8001")); + + verifyPosition(decoder, binary( + "7e004200000014631000258257000000ffff02d1690e00051f690e00051f0696dbd204bdfde31a070000b307100f35c0106305f500000000010908010402200104ffff8001")); + + verifyPosition(decoder, binary( + "7e004200000014631000258257000000ffff0d82691300001669130000160696dbd804bdfdbb1a0800000007101035a2106905f500000000010908010402200104ffff8001")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java new file mode 100644 index 000000000..e2f72c161 --- /dev/null +++ b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java @@ -0,0 +1,33 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class OkoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + OkoProtocolDecoder decoder = new OkoProtocolDecoder(null); + + verifyPosition(decoder, text( + "{861694033681089,045403.00,A,4924.14181,N,03207.43787,E,0.080,,151117,07,0.00,01,24.8,1,02,5n4}")); + + verifyPosition(decoder, text( + "{045411.00,A,4924.14243,N,03207.43754,E,0.172,,151117,07,0.00,F9,28.1,2,C2,5n4}")); + + verifyPosition(decoder, text( + "{861001001016415,115031.000,A,4804.101180,N,02255.227002,E,4.121,111.0,211215,6,0.00,F7,13.6,1,00")); + + verifyPosition(decoder, text( + "{132810.000,A,4926.4243,N,03203.6831,E,25.0,183,131011,07,5.69,05,14.1,1,82,3N5")); + + verifyPosition(decoder, text( + "{115034.000,A,4804.098944,N,02255.233436,E,7.858,120.9,211215,7,0.00,F7,13.7,1,00")); + + verifyPosition(decoder, text( + "{115038.000,A,4804.091227,N,02255.250213,E,17.621,128.1,211215,8,0.00,00,13.7,2,00")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java new file mode 100644 index 000000000..a04cf4e72 --- /dev/null +++ b/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class OpenGtsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + OpenGtsProtocolDecoder decoder = new OpenGtsProtocolDecoder(null); + + verifyPosition(decoder, request( + "/?id=999000000000003&gprmc=$GPRMC,082202.0,A,5006.747329,N,01416.512315,E,0.0,,131018,1.2,E,A*2E")); + + verifyPosition(decoder, request( + "/?id=gprmc_999000000000003&gprmc=$GPRMC,143013.0,A,5006.728217,N,01416.437869,E,0.0,329.6,281017,1.2,E,A*0E")); + + verifyPosition(decoder, request( + "/?id=123456789012345&dev=dev_name&acct=account&batt=0&code=0xF020&alt=160.5&gprmc=$GPRMC,191555,A,5025.46624,N,3030.39937,E,0.000000,0.000000,200218,,*2F")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java new file mode 100644 index 000000000..bb5f1f135 --- /dev/null +++ b/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class OrionProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + OrionProtocolDecoder decoder = new OrionProtocolDecoder(null); + + verifyPositions(decoder, binary( + "5057000137bf6236235a0331b5c6e402a3b5ecff5102980003000e0c1d172936080e0c1d172936b03b01000882050000008e080000000000008c0300940500000084030085030003067600900113150000000000000000000000000000000000000004a4c8")); + + verifyPositions(decoder, binary( + "5057004107367C242B440901ADE97D0163143B07B003000000000D041917382D000B0101000511000000000682050000008E080000000000008C0300840300850300090A0000000048010000008AFC")); + + verifyPositions(decoder, binary( + "5057004107367C242C440901ADE97D0163143B07B003000000000D041917382D000B0101000513000000000682050000008E080000000000008C0300840300850300090A000000003BFEFFFF01FAE5")); + + verifyPositions(decoder, binary( + "5057004107367C242D440901ADE97D0163143B07B003000000000D041917382D000B0101000514000000000682050000008E080000000000008C0300840300850300090A00000000FDFDFFFF023721")); + + verifyPositions(decoder, binary( + "505700412ac86236354009114d20e402210f1f00d204000000000e06110d3414000b0101001228000000000682050000008e080000000000008c030084030085030003067b006801000930")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java new file mode 100644 index 000000000..3c38bd831 --- /dev/null +++ b/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java @@ -0,0 +1,48 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class OsmAndProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + OsmAndProtocolDecoder decoder = new OsmAndProtocolDecoder(null); + + verifyNotNull(decoder, request( + "/?id=123456×tamp=1377177267&cell=257,02,16,2224&cell=257,02,16,2223,-90&wifi=00-14-22-01-23-45,-80&wifi=00-1C-B3-09-85-15,-70")); + + verifyNull(decoder, request( + "/?timestamp=1377177267&lat=60.0&lon=30.0")); + + verifyPosition(decoder, request( + "/?id=902064&lat=42.06288&lon=-88.23412×tamp=2016-01-27T18%3A55%3A47Z&hdop=6.0&altitude=224.0&speed=0.0")); + + verifyPosition(decoder, request( + "/?id=902064&lat=42.06288&lon=-88.23412×tamp=1442068686579&hdop=6.0&altitude=224.0&speed=0.0")); + + verifyPosition(decoder, request( + "/?lat=49.60688&lon=6.15788×tamp=2014-06-04+09%3A10%3A11&altitude=384.7&speed=0.0&id=353861053849681")); + + verifyPosition(decoder, request( + "/?id=123456×tamp=1377177267&lat=60.0&lon=30.0&speed=0.0&bearing=0.0&altitude=0&hdop=0.0")); + + verifyPosition(decoder, request( + "/?id=123456×tamp=1377177267&lat=60.0&lon=30.0")); + + verifyPosition(decoder, request( + "/?lat=60.0&lon=30.0&speed=0.0&heading=0.0&vacc=0&hacc=0&altitude=0&deviceid=123456")); + + verifyPosition(decoder, request( + "/?id=861001000719969&lat=41.666667&lon=-0.883333&altitude=350.059479&speed=0.000000&batt=87")); + + verifyPosition(decoder, request( + "/?id=123456×tamp=1377177267&location=60.0,30.0")); + + verifyPosition(decoder, request( + "/?id=123456789012345×tamp=1504763810&lat=40.7232948571&lon=-74.0061408571&bearing=7.19889788244&speed=40&ignition=true&rpm=933&fuel=24")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java new file mode 100644 index 000000000..248920e21 --- /dev/null +++ b/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java @@ -0,0 +1,27 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class OwnTracksProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + OwnTracksProtocolDecoder decoder = new OwnTracksProtocolDecoder(null); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"_type\":\"location\",\"acc\":15,\"alt\":440,\"batt\":46,\"conn\":\"w\",\"lat\":46.0681247,\"lon\":11.1512805,\"t\":\"u\",\"tid\":\"5t\",\"tst\":1551874878,\"vac\":2,\"vel\":0}"))); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"lon\":2.29513,\"lat\":48.85833,\"tst\":1497349316,\"_type\":\"location\",\"tid\":\"JJ\"}"))); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"cog\":271,\"lon\":2.29513,\"acc\":5,\"vel\":61,\"vac\":21,\"lat\":48.85833,\"tst\":1497349316,\"alt\":167,\"_type\":\"location\",\"tid\":\"JJ\",\"t\":\"u\",\"batt\":67}"))); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("{\"lat\":48.85,\"lon\":2.295,\"_type\":\"location\",\"tid\":\"JJ\",\"tst\":1497476456}"))); + } + +} diff --git a/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java new file mode 100644 index 000000000..4b9739242 --- /dev/null +++ b/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class PathAwayProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + PathAwayProtocolDecoder decoder = new PathAwayProtocolDecoder(null); + + verifyPosition(decoder, request( + "?UserName=name&Password=pass&LOC=$PWS,1,\"Roger\",,,100107,122846,45.317270,-79.642219,45.00,42,1,\"Comment\",0*58")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java new file mode 100644 index 000000000..03d0dd7b9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java @@ -0,0 +1,20 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class PiligrimProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + PiligrimProtocolDecoder decoder = new PiligrimProtocolDecoder(null); + + verifyPositions(decoder, request(HttpMethod.POST, + "/bingps?imei=868204005544720&csq=18&vout=00&vin=4050&dataid=00000000", + binary("fff2200d4110061a32354f3422310062000a0005173b0000a101000300005e00fff2200d4110100932354f2b22310042000b000e173b00009f01000700006000"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java new file mode 100644 index 000000000..61a057dd7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class PretraceProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + PretraceProtocolDecoder decoder = new PretraceProtocolDecoder(null); + + verifyPosition(decoder, text( + "(867967021915915U1110A1701201500102238.1700N11401.9324E000264000000000009001790000000,&P11A4,F1050^47")); + + verifyPosition(decoder, text( + "(864244029498838U1110A1509250653072238.1641N11401.9213E000196000000000406002990000000,&P195%,T1050,F14A5,R104C51E47B^30")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java new file mode 100644 index 000000000..1b2780325 --- /dev/null +++ b/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java @@ -0,0 +1,39 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class PretraceProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncodePositionPeriodic() throws Exception { + + PretraceProtocolEncoder encoder = new PretraceProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_PERIODIC); + command.set(Command.KEY_FREQUENCY, 300); + + assertEquals("(123456789012345D221300,300,,^69)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeCustom() throws Exception { + + PretraceProtocolEncoder encoder = new PretraceProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "D21012"); + + assertEquals("(123456789012345D21012^44)", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java new file mode 100644 index 000000000..dbc1665fb --- /dev/null +++ b/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class PricolProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + PricolProtocolDecoder decoder = new PricolProtocolDecoder(null); + + verifyPosition(decoder, binary( + "3c5052493030303350020000011402110b222b0455152e4e001de819ca450000000000000003820249000000000000000000000000000000000000000040003e")); + + verifyNotNull(decoder, binary( + "3c544553303030324b02000000000000000000000000000000000000000000000000000000037c01f4000000000000000000000000000000000000000000003e")); + + verifyPosition(decoder, binary( + "3c4944303030303150FFFFFFFF1C050C121D38045D09FA4e001DE815F4452FFFFFFFFFFF03FF03FF03FF03FF03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF113e")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java new file mode 100644 index 000000000..5f6f564b1 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ProgressProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ProgressProtocolDecoder decoder = new ProgressProtocolDecoder(null); + + verifyNull(decoder, binary( + "020037000100000003003131310f003335343836383035313339303036320f00323530303136333832383531353535010000000100000000000000e6bb97b6")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java new file mode 100644 index 000000000..e7d87d583 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java @@ -0,0 +1,22 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Pt3000ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Pt3000ProtocolDecoder decoder = new Pt3000ProtocolDecoder(null); + + verifyPosition(decoder, text( + "%356939010012099,$GPRMC,124945.752,A,4436.6245,N,01054.4634,E,0.11,358.52,060408,,,A,+393334347445,N028d"), + position("2008-04-06 12:49:45.000", true, 44.61041, 10.90772)); + + verifyPosition(decoder, text( + "%356939010014433,$GPRMC,172821.000,A,4019.5147,N,00919.1160,E,0.00,,010613,,,A,+393998525043,N098d")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java new file mode 100644 index 000000000..487a8500c --- /dev/null +++ b/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java @@ -0,0 +1,39 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Pt502FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Pt502FrameDecoder decoder = new Pt502FrameDecoder(); + + verifyFrame( + binary("24504844302c3936302cffd8ffdb008400140e0f120f0d14121012171514181e32211e1c1c1e3d2c2e243249404c4b47404645505a736250556d5645466488656d777b8182814e608d978c7d96737e817c011517171e1a1e3b21213b7c5346537c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7cffc000110800f0014003012100021101031101ffdd0004000affc401a20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa0100030101010101010101010000000000000102030405060708090a0b1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00e5292800ef450020a2800a2801d49400b450014b40052e2800a69340094a05007fffd0e5d14b10055b51b00c76a00527273494005250014500251400525001450015347c25003a928010d25007ffd1e52909a00290d0014b40052d0014500145002e297b50018a280109a6d002d2e2803fffd2e7a04da3777a94fbd0025140052500145002514005250014940054e381400b494008690d007fffd3e4f345001486800a5a005a2800a2801680280168a002909e280100cd028016a48937bfb5007fffd4c5038a42280128a004a280128a003ad2500251400945002a8cb0a9a80133450026692803ffd5e4e8a004a2801694500145002d18a005c5140052e280109a69a0029680140abb147b139eb401ffd6c62290d00251400949400114940052500252d002525003e31c93525002521a004a4a00ffd7e4a8a00281400a29d40094b40053ba500252d0018a31400d3cd250018cd2d005ab58777ccdd074ab645007ffd0c72290d00348a2801280"), + decoder.decode(null, null, binary("bffbf6d10324504844302c3936302cffd8ffdb008400140e0f120f0d14121012171514181e32211e1c1c1e3d2c2e243249404c4b47404645505a736250556d5645466488656d777b8182814e608d978c7d96737e817c011517171e1a1e3b21213b7c5346537c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7cffc000110800f0014003012100021101031101ffdd0004000affc401a20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa0100030101010101010101010000000000000102030405060708090a0b1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00e5292800ef450020a2800a2801d49400b450014b40052e2800a69340094a05007fffd0e5d14b10055b51b00c76a00527273494005250014500251400525001450015347c25003a928010d25007ffd1e52909a00290d0014b40052d0014500145002e297b50018a280109a6d002d2e2803fffd2e7a04da3777a94fbd0025140052500145002514005250014940054e381400b494008690d007fffd3e4f345001486800a5a005a2800a2801680280168a002909e280100cd028016a48937bfb5007fffd4c5038a42280128a004a280128a003ad2500251400945002a8cb0a9a80133450026692803ffd5e4e8a004a2801694500145002d18a005c5140052e280109a69a0029680140abb147b139eb401ffd6c62290d00251400949400114940052500252d002525003e31c93525002521a004a4a00ffd7e4a8a00281400a29d40094b40053ba500252d0018a31400d3cd250018cd2d005ab58777ccdd074ab645007ffd0c72290d00348a28012800d0a"))); + + verifyFrame( + binary("244655533836353332383032363234333836342c3531302d56312e31322c4131312d56332e30"), + decoder.decode(null, null, binary("bffb192d00244655533836353332383032363234333836342c3531302d56312e31322c4131312d56332e300d0d"))); + + verifyFrame( + binary("24504f532c313336303030303237372c3138323234312e3030302c412c303834362e303839362c4e2c30373535322e313733382c572c31332e35382c32362e38382c3239313031372c2c2c412f30303030302c30303030302f3134322c302c302c302f36323739323930302f2f6636352f2f23"), + decoder.decode(null, null, binary("bffb57d50124504f532c313336303030303237372c3138323234312e3030302c412c303834362e303839362c4e2c30373535322e313733382c572c31332e35382c32362e38382c3239313031372c2c2c412f30303030302c30303030302f3134322c302c302c302f36323739323930302f2f6636352f2f230a24504f532c313336303030303237372c3138323235312e3030302c412c303834362e313234382c4e2c30373535322e313534352c572c31352e35322c33362e39332c3239313031372c2c2c412f30303030302c30303030302f3134312c302c302c302f36323739333030302f2f6636382f2f230a24504f532c313336303030303237372c3138323332342e3030302c412c303834362e323633362c4e2c30373535322e303630352c572c31382e39342c32392e39302c3239313031372c2c2c412f30303030302c30303030302f3133652c302c302c302f36323739333330302f2f6639372f2f230a24504f532c313336303030303237372c3138323332362e3030302c412c303834362e323733302c4e2c30373535322e303535342c572c31392e31322c33302e34322c3239313031372c2c2c412f30303030302c30303030302f3134302c302c302c302f36323739333330302f2f6639382f2f230a"))); + + verifyFrame( + binary("24504f532c3836353332383032363234333836342c3134343733352e3030302c412c313333322e373038332c4e2c3230342e363833312c452c302e302c3233302e30302c3032303531372c2c2c412f30303030302c31302f312c302f3233342f2f4646392f"), + decoder.decode(null, null, binary("24504f532c3836353332383032363234333836342c3134343733352e3030302c412c313333322e373038332c4e2c3230342e363833312c452c302e302c3233302e30302c3032303531372c2c2c412f30303030302c31302f312c302f3233342f2f4646392f0d0a"))); + + verifyFrame( + binary("24504f532c3335333435313030303136342c3038323430352e3030302c412c313235342e383530312c4e2c31303035312e363735322c452c302e30302c3233372e39392c3136303531332c2c2c412f303030302c302f302f35353030302f2f6137312f"), + decoder.decode(null, null, binary("24504f532c3335333435313030303136342c3038323430352e3030302c412c313235342e383530312c4e2c31303035312e363735322c452c302e30302c3233372e39392c3136303531332c2c2c412f303030302c302f302f35353030302f2f6137312f0d0a"))); + + verifyFrame( + binary("24504f532c3335333435313030303136342c3038323430352e3030302c412c313235342e383530312c4e2c31303035312e363735322c452c302e30302c3233372e39392c3136303531332c2c2c412f303030302c302f302f35353030302f2f6137312f"), + decoder.decode(null, null, binary("bffb1b6a0024504f532c3335333435313030303136342c3038323430352e3030302c412c313235342e383530312c4e2c31303035312e363735322c452c302e30302c3233372e39392c3136303531332c2c2c412f303030302c302f302f35353030302f2f6137312f0d0a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java new file mode 100644 index 000000000..cb1c1eb0e --- /dev/null +++ b/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java @@ -0,0 +1,86 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class Pt502ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Pt502ProtocolDecoder decoder = new Pt502ProtocolDecoder(null); + + verifyNull(decoder, binary( + "24504844302c3936302cffd8ffdb008400140e0f120f0d14121012171514181e32211e1c1c1e3d2c2e243249404c4b47404645505a736250556d5645466488656d777b8182814e608d978c7d96737e817c011517171e1a1e3b21213b7c5346537c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7cffc000110800f0014003012100021101031101ffdd0004000affc401a20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa0100030101010101010101010000000000000102030405060708090a0b1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00e5292800ef450020a2800a2801d49400b450014b40052e2800a69340094a05007fffd0e5d14b10055b51b00c76a00527273494005250014500251400525001450015347c25003a928010d25007ffd1e52909a00290d0014b40052d0014500145002e297b50018a280109a6d002d2e2803fffd2e7a04da3777a94fbd0025140052500145002514005250014940054e381400b494008690d007fffd3e4f345001486800a5a005a2800a2801680280168a002909e280100cd028016a48937bfb5007fffd4c5038a42280128a004a280128a003ad2500251400945002a8cb0a9a80133450026692803ffd5e4e8a004a2801694500145002d18a005c5140052e280109a69a0029680140abb147b139eb401ffd6c62290d00251400949400114940052500252d002525003e31c93525002521a004a4a00ffd7e4a8a00281400a29d40094b40053ba500252d0018a31400d3cd250018cd2d005ab58777ccdd074ab645007ffd0c72290d00348a2801280")); + + verifyPosition(decoder, buffer( + "$PHO3821-1,1156802639,022125.000,A,0707.0014,N,07307.3725,W,0.0,0.1,110418,,,A/00000,00000/0,0,0,0/500//fd4//")); + + verifyPosition(decoder, buffer( + "$POS,1360000277,182241.000,A,0846.0896,N,07552.1738,W,13.58,26.88,291017,,,A/00000,00000/142,0,0,0/62792900//f65//#")); + + verifyPosition(decoder, buffer( + "$PHO0-1,1360000260,123012.000,A,0913.9644,N,07548.8345,W,0.0,309.8,111017,,,A/00000,10000/0,0,0,0/64551600//f98//")); + + verifyPosition(decoder, buffer( + "$POS,865328026243864,151105.000,A,1332.7096,N,204.6787,E,0.0,10.00,050517,,,A/00000,10/1,0/234//FD9/")); + + verifyNull(decoder, buffer( + "$FUS865328026243864,510-V1.12,A11-V3.0")); + + verifyPosition(decoder, buffer( + "$HDA,20007,134657.000,A,0626.1607,N,00330.2245,E,33.38,81.79,041016,,,A/00010,00000/270,0,0,0/19948900//fa4//")); + + verifyPosition(decoder, buffer( + "$HDB,20007,134708.000,A,0626.1759,N,00330.3192,E,26.55,80.37,041016,,,A/00010,00000/23b,0,0,0/19949100//fa4//")); + + verifyPosition(decoder, buffer( + "$POS,20007,134704.000,A,0626.1698,N,00330.2870,E,31.23,79.58,041016,,,A/00010,00000/26c,0,0,0/19949100//fa4//#")); + + verifyPosition(decoder, buffer( + "$PHO6608,115099,133140.000,A,1307.1238,N,05936.4194,W,0.00,21.50,290816,,,A/00010,00000/0,0,0,0/185100//f59/")); + + verifyPosition(decoder, buffer( + "$DFR,40456789,083125.000,A,2232.0971,N,11400.9504,E,0.0,5.00,090714,,,A/00000,00/0,0/200076//FE7/")); + + verifyPosition(decoder, buffer( + "$FDA,40456789,083125.000,A,2232.0971,N,11400.9504,E,0.0,5.00,090714,,,A/00000,00/0,0/200076//FE7/")); + + verifyAttribute(decoder, buffer( + "$CPA,40456789,083125.000,A,2232.0971,N,11400.9504,E,7.62,265.24,291117,,,A/00000,00000/0/1200//#"), Position.KEY_ALARM, Position.ALARM_POWER_CUT); + + verifyPosition(decoder, buffer( + "$POS,216769295715,163237.000,A,3258.1738,S,02755.4350,E,0.00,215.88,100915,,,A/0000,0//232300//5b3/"), + position("2015-09-10 16:32:37.000", true, -32.96956, 27.92392)); + + verifyPosition(decoder, buffer( + "$POS,11023456,033731.000,A,0335.2617,N,09841.1587,E,0.00,88.12,210615,,,A/0000,0/1f8/388900//f33//")); + + verifyPosition(decoder, buffer( + "$POS,6094,205523.000,A,1013.6223,N,06728.4248,W,0.0,99.3,011112,,,A/00000,00000/0/23895000//")); + + verifyPosition(decoder, buffer( + "$POS,6120,233326.000,V,0935.1201,N,06914.6933,W,0.00,,151112,,,A/00000,00000/0/0/")); + + verifyPosition(decoder, buffer( + "$POS,6002,233257.000,A,0931.0430,N,06912.8707,W,0.05,146.98,141112,,,A/00010,00000/0/5360872")); + + verifyPosition(decoder, buffer( + "$POS,6095,233344.000,V,0933.0451,N,06912.3360,W,,,151112,,,N/00000,00000/0/1677600/")); + + verifyPosition(decoder, buffer( + "$PHO0,6091,233606.000,A,0902.9855,N,06944.3654,W,0.0,43.8,141112,,,A/00010,00000/0/224000//")); + + verifyPosition(decoder, buffer( + "$POS,353451000164,082405.000,A,1254.8501,N,10051.6752,E,0.00,237.99,160513,,,A/0000,0/0/55000//a71/")); + + verifyPosition(decoder, buffer( + "$POS,012896008586486,154215.000,A,0118.0143,S,03646.9144,E,0.00,83.29,180714,,,A/0000,0/0/29200//644/")); + + verifyPosition(decoder, buffer( + "$POS,1151000,205326.000,A,0901.3037,N,07928.2751,W,48.79,30.55,170814,,,A/00010,10000/0,0,0,0/15986500//fb8/")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java new file mode 100644 index 000000000..a6c8bb50f --- /dev/null +++ b/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java @@ -0,0 +1,69 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class Pt502ProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncodeCustom() throws Exception { + + Pt502ProtocolEncoder encoder = new Pt502ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "#PTI300"); + + assertEquals("#PTI300\r\n", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeOutputControl() throws Exception { + + Pt502ProtocolEncoder encoder = new Pt502ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_OUTPUT_CONTROL); + command.set(Command.KEY_INDEX, 2); + command.set(Command.KEY_DATA, "1"); + + assertEquals("#OPC2,1\r\n", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeTimezone() throws Exception { + + Pt502ProtocolEncoder encoder = new Pt502ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SET_TIMEZONE); + command.set(Command.KEY_TIMEZONE, "GMT+8"); + + assertEquals("#TMZ8\r\n", encoder.encodeCommand(command)); + + } + + + @Test + public void testEncodeAlarmSpeed() throws Exception { + + Pt502ProtocolEncoder encoder = new Pt502ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ALARM_SPEED); + command.set(Command.KEY_DATA, 120); + + assertEquals("#SPD120\r\n", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java new file mode 100644 index 000000000..1ba8d25c7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java @@ -0,0 +1,54 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Pt60ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Pt60ProtocolDecoder decoder = new Pt60ProtocolDecoder(null); + + verifyNull(decoder, text( + "@B#@|01|006|864891030184954|9425010450971470|20181213093127|2|1|")); + + verifyNull(decoder, text( + "@B#@|01|006|864891030184954|9425010450971470|20181213093235|40412,10461,1,425,4|2|1|")); + + verifyNotNull(decoder, text( + "@B#@|01|001|864891030184852|9425010450971470|1|84|20181205161005|40412,10461,1,425,10|2|")); + + verifyPosition(decoder, text( + "@B#@|01|001|864891030184852|9425010450971470|1|45|20181127122717|32.701093|35.570938|1|")); + + verifyNull(decoder, text( + "@B#@|01|003|864891030184954|9425010450971470|S6_EN_A_V1.3.7|0|66|20181122113251|40412,10461,1,425,18|49382,10461,1,425,9|40411,10461,1,425,7|2|")); + + verifyNull(decoder, text( + "@B#@|01|033|864891030184954|9425010450971470|0|4|20181120151744|")); + + verifyPosition(decoder, text( + "@B#@|01|001|111112222233333|8888888888888888|1|55|20160715150323|37.615124|125.48276|111.059279|49.346383|1|")); + + verifyPosition(decoder, text( + "@B#@|01|001|111112222233333|8888888888888888|1|55|20160715150323|37.615124|125.48276|1|")); + + verifyAttributes(decoder, text( + "@G#@,V01,14,357653051059785,9404223001501310,20180419165604,101,26,")); + + verifyAttributes(decoder, text( + "@G#@,V01,13,357653051059785,9404223001501310,20180419112656,1180,")); + + verifyPosition(decoder, text( + "@G#@,V01,6,111112222233333,8888888888888888,20150312010203,23.2014050;104.235212,")); + + verifyNull(decoder, text( + "@G#@,V01,1,353882080015633,9460025014649193,")); + + verifyNull(decoder, text( + "@G#@,V01,43,105681639001701,9460000412618231,20180410092923,5,460;0;9763;3852;-63|460;0;9763;3851;-26|460;0;9763;4080;-22|460;0;9763;3593;-18|460;0;9763;3591;-10,5,14:b8:37:26:64:88;004300680069006e0061004e00650074002d006e0047006e0058;-76|08:9b:4b:93:b5:b1;005400480049004e004b0052004100430045;-77|ec:3d:fd:c9:38:4a;004b00460052006f0075007400650072;-78|b0:d5:9d:c6:f8:82;003300360030514d8d390057006900460069002d00380032;-81|02:fa:84:3b:fa:6a;00470075006500730074005f0032002e003400470048007a;-82,")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java new file mode 100644 index 000000000..165027351 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class RaveonProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + RaveonProtocolDecoder decoder = new RaveonProtocolDecoder(null); + + verifyPosition(decoder, text( + "$PRAVE,0001,0001,3308.9051,-11713.1164,195348,1,10,168,31,13.3,3,-83,0,0,,1003.4*66")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java new file mode 100644 index 000000000..668879787 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class RecodaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + RecodaProtocolDecoder decoder = new RecodaProtocolDecoder(null); + + verifyNull(decoder, binary( + "01100020480000000300000030393535360000000000000001000000303030303000000000000000000000000000000000000000006100004531313037353500ffffffffffff0000")); + + verifyNull(decoder, binary( + "01200020100000000300000002000000")); + + verifyNull(decoder, binary( + "0110000008000000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java new file mode 100644 index 000000000..779e21823 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class RetranslatorProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + RetranslatorProtocolDecoder decoder = new RetranslatorProtocolDecoder(null); + + verifyPosition(decoder, binary( + "74000000333533393736303133343435343835004B0BFB70000000030BBB000000270102706F73696E666F00A027AFDF5D9848403AC7253383DD4B400000000000805A40003601460B0BBB0000001200047077725F657874002B8716D9CE973B400BBB00000011010361766C5F696E707574730000000001")); + + verifyPosition(decoder, binary( + "1f010000333533353439303930303934373330005b129b5f000000010bbb000000270102706f73696e666f004e3be14e5ec356c0e0e92f6201282c400000000000000000000000130d0bbb0000000a00036d636300000002c00bbb0000000a00036d6e6300000000010bbb0000000a00036c616300000001490bbb0000000e000363656c6c5f696400000056590bbb0000000a000361636300000000000bbb000000100003646174615f6d6f6465000000000e0bbb0000001200036770735f7265616c5f757000000000000bbb0000000d000373657269616c000000089b0bbb0000001000016d73675f747970650030783232000bbb000000110004637573746f6d0000000000000033400bbb0000001200046d696c65616765000000000000000000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java new file mode 100644 index 000000000..73d07efd6 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class RitiProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + RitiProtocolDecoder decoder = new RitiProtocolDecoder(null); + + verifyPosition(decoder, binary( + "3b28a2a2056315316d4000008100000000000000005f710000244750524d432c3138303535332e3030302c412c353532342e383437312c4e2c30313133342e313837382c452c302e30302c2c3032313231332c2c2c412a37340d0a00000000000000000000000000000000040404")); + + verifyPosition(decoder, binary( + "3b2864a3056300006d40000003000000000000000000000000244750524d432c3231313734332e3030302c412c313335372e333637352c4e2c31303033362e363939322c452c302e30302c2c3031303931342c2c2c412a37380d0a00000000000000000000000000000000040404")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java new file mode 100644 index 000000000..2e3853f86 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class RoboTrackFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + RoboTrackFrameDecoder decoder = new RoboTrackFrameDecoder(); + + verifyFrame( + binary("00524f424f545241434b00000000000000383638323034303032323533343136313233343536373839303132312e313261000000312e353761000000312e3030000000003e"), + decoder.decode(null, null, binary("00524f424f545241434b00000000000000383638323034303032323533343136313233343536373839303132312e313261000000312e353761000000312e3030000000003e"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java new file mode 100644 index 000000000..0c969ab68 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class RoboTrackProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + RoboTrackProtocolDecoder decoder = new RoboTrackProtocolDecoder(null); + + verifyNull(decoder, binary( + "00524f424f545241434b00000000000000383638323034303032323533343136313233343536373839303132312e313261000000312e353761000000312e3030000000003e")); + + verifyPosition(decoder, binary( + "03e020bb5a034409034862120210a9e105000000000000b9")); + + verifyPosition(decoder, binary( + "03f120bb5a30460903426312021798e105000000000000cd")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java new file mode 100644 index 000000000..12f63ef7d --- /dev/null +++ b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java @@ -0,0 +1,48 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class RuptelaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + RuptelaProtocolDecoder decoder = new RuptelaProtocolDecoder(null); + + verifyNull(decoder, binary( + "002e000315bc70d3e2ff0f4f42443130302e30312e30382e30300000c2b30ea77e430000601b000001f40000003c00144aa0")); + + verifyAttributes(decoder, binary( + "0011000315A07F440B1D07534554494f20636f6e66696775726174696f6e2064617461206f6b341C")); + + verifyAttributes(decoder, binary( + "0044000313612d76c5cb0744494e313d312c44494e323d302c44494e333d302c44494e343d302c444f5554313d312c444f5554323d312c41494e313d31372c41494e323d3236ac80")); + + verifyPositions(decoder, binary( + "000B00000B1A29F64B1A0902FF4E9CAF2C07D608F11A1480BA015030303130FF4E9CAF2C07D608F11A1480BA0250303031318C91")); + + verifyPositions(decoder, binary( + "01a4000315bc70f9b69244000458068f4a0030000d11398a1c0c19fd056524040b000c0a00090c0005010031f40032fd0033f200ce47002400002500001c010199000195010196010086000900aa0000001e0ff000d3ffff0043ffff01930000019200000194000002220000022300000200300000000200af000e872401008e000000000000000058068f4a0031000d11398a1c0c19fd056524040b000c0a00090400870000880000a90000820010008b0002021e0000021f0000021d0000021c0000022400000225000000890000008505f00220000002210000008300000084000002260000022700000228000003008a00000000008d00000000008c000000000058068f4a0032000d11398a1c0c19fd056524040b000c0a000905019f01005800001b1f00ad0000cfb10b02290000022a0000022b0000022c0000022d00000012000000130000001d367400c52f8000740055023e0502060097000000000096000058520041007746cb00d0000003f1005c0007c21b0072001864880058068f4a0033000d11398a1c0c19fd056524040b000c0a000900000001008e0000000000000000e815")); + + verifyPositions(decoder, binary( + "033d000315bc70f9b69244000858068f3b0030010d11354e1c0c17a5055d54560c00000900050c0005010031f30032fb0033f300ce00002400002500001c010199000195010196010086000900aa0000001e0ff300d3ffff0043ffff01930000019200000194000002220000022300000200300000000000af000e872401008e000000000000000058068f3b0031010d11354e1c0c17a5055d54560c00000900050400870000880000a90000820010008b0000021e0000021f0000021d0000021c0000022400000225000000890000008500000220000002210000008300000084000002260000022700000228000003008a00000000008d00000000008c000000000058068f3b0032010d11354e1c0c17a5055d54560c000009000505019f01005800001b1f00ad0000cfac0b02290000022a0000022b0000022c0000022d00000012000000130000001d31b100c5000000740000023e0502060097000000000096000058520041007746be00d0000003f1005c0007c2150072001864880058068f3b0033010d11354e1c0c17a5055d54560c000009000500000001008e000000000000000058068f3b0130000d11354e1c0c17a5055d54560d00000900070c0005010031f30032fb0033f300ce00002400002500001c010199000195010196010086000900aa0000001e0ff300d3ffff0043ffff01930000019200000194000002220000022300000200300000000000af000e872401008e000000000000000058068f3b0131000d11354e1c0c17a5055d54560d00000900070400870000880000a90000820010008b0000021e0000021f0000021d0000021c0000022400000225000000890000008500000220000002210000008300000084000002260000022700000228000003008a00000000008d00000000008c000000000058068f3b0132000d11354e1c0c17a5055d54560d000009000705019f01005800001b1f00ad0000cfac0b02290000022a0000022b0000022c0000022d00000012000000130000001d31ae00c5000000740000023e0502060097000000000096000058520041007746be00d0000003f1005c0007c2150072001864880058068f3b0133000d11354e1c0c17a5055d54560d000009000700000001008e0000000000000000084d")); + + verifyPositions(decoder, binary( + "0050000310f5615f419c0100015613d8ed0000fff5b37a035af37801e700000900000d07071b0c020003001c01202cad000500064302a81d33e61e100116317cd3ffff174ad60241000077fa960000f232003c2e")); + + verifyPositions(decoder, binary( + "00560003116e7438a7a50100015565cbb9000020fd21300f113f4600005f000600090d090805011b13cf00020003001c012029ad00041d31dd1e0ebd160000c50000047200000000d0000000004100016a2a960000a5a300c9ee")); + + verifyPositions(decoder, binary( + "00a10003116e7438a7a5010002553dddbe000020fddaff0f12289b007200000600000c070805011b18cf00020003001c01201dad01041d32d81e0d7d160000c50000047200000000d000000000410000b1ae960000a5a300553dddd4000020fdd96f0f122bfe005c16f80700050b090805011b18cf00020003001c01201ead01041d338a1e0d8d160000c50000047200000000d000000000410000b1bd960000a5a3001681")); + + verifyPositions(decoder, binary( + "007900000b1a2a5585c30100024e9c036900000f101733208ff45e07b31b570a001009090605011b1a020003001c01ad01021d338e16000002960000601a41014bc16d004e9c038400000f104fdf20900d20075103b00a001308090605011b1a020003001c01ad01021d33b116000002960000601a41014bc1ea0028f9")); + + verifyPositions(decoder, binary( + "009200000c07a6bacd4701000552db5cc20000187b8b251ace478e087c044c0a000009070000000052db5cfe0000187b8ab01ace47190879044c0900000b070000000052db5d3a0000187b8b251ace474b089d044c09000009070000000052db5d760000187b8b9a1ace475c08cd044c08000009070000000052db5db20000187b8b141ace46e708b3044c08000009070000000041cb")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java new file mode 100644 index 000000000..8a00caa09 --- /dev/null +++ b/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class RuptelaProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + RuptelaProtocolEncoder encoder = new RuptelaProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, " Setio 2,1"); + + verifyCommand(encoder, command, binary("000b6c20536574696F20322C31eb3e")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java new file mode 100644 index 000000000..7a42a71a0 --- /dev/null +++ b/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class SabertekFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SabertekFrameDecoder decoder = new SabertekFrameDecoder(); + + assertEquals( + binary("2c3939393939393939392c332c34302c36352c372c302c312c2d32352e3738313636362c32382e3235343730322c34302c3236382c313431342c382c35353632332c"), + decoder.decode(null, null, binary("022c3939393939393939392c332c34302c36352c372c302c312c2d32352e3738313636362c32382e3235343730322c34302c3236382c313431342c382c35353632332c030d0a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java new file mode 100644 index 000000000..20b02841e --- /dev/null +++ b/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SabertekProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SabertekProtocolDecoder decoder = new SabertekProtocolDecoder(null); + + verifyPosition(decoder, text( + ",999999999,3,40,65,7,0,1,-25.781666,28.254702,40,268,1414,8,55623,")); + + verifyPosition(decoder, text( + ",999999999,4,356495040613400,89270200120171498287,+27821234123,20180525145412,60,75,15,1,1,-25.781666,28.254702,40,268,1414,8,24844,")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java new file mode 100644 index 000000000..36fd7ecba --- /dev/null +++ b/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java @@ -0,0 +1,37 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SanavProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SanavProtocolDecoder decoder = new SanavProtocolDecoder(null); + + verifyPosition(decoder, text( + "imei=353197040023431&rmc=$GPRMC,015258.000,A,2457.8101,N,12125.5393,E,0.00,0.00,210111,,*18,AUTO,0300,2.1,10,466,97,34E7,3391,74,466,9 7,3F2D,3391,65,466,97,39C9,3391,79,466,97,3F2C,3391,81,466,97,0000,00 00,83,466,97,0000,0000,85,466,97,0000,0000,85,1,24")); + + verifyPosition(decoder, text( + "imei=1234567890&rmc=$GPRMC,091950.00,V,5300.10000,N,00900.14000,E,0.160,,200513,,,A*68,STOP,V3.872;67%,S4,H8.3,D2.38")); + + verifyPosition(decoder, text( + "imei=352024028982787&rmc=$GPRMC,103048.000,A,4735.0399,N,01905.2895,E,0.00,0.00,171013,,*05,AUTO-4095mv"), + position("2013-10-17 10:30:48.000", true, 47.58400, 19.08816)); + + verifyPosition(decoder, text( + "imei:352024028980000rmc:$GPRMC,093604.354,A,4735.0862,N,01905.2146,E,0.00,0.00,171013,,*09,AUTO-4103mv")); + + verifyPosition(decoder, text( + "imei:352024027800000rmc:$GPRMC,000025.000,A,4735.0349,N,01905.2899,E,0.00,202.97,171013,,*03,3950mV,AUTO")); + + verifyPosition(decoder, text( + "imei:352024020976845rmc:$GPRMC,000201.000,A,4655.7043,N,01941.3796,E,0.54,159.14,171013,,,A*65,AUTO")); + + verifyPosition(decoder, text( + "imei:352024020976845rmc:$GPRMC,000201.000,A,4655.7043,N,01941.3796,E,0.54,159.14,171013,,,A*65,AUTO")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java new file mode 100644 index 000000000..45e919bbb --- /dev/null +++ b/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SatsolProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SatsolProtocolDecoder decoder = new SatsolProtocolDecoder(null); + + verifyPositions(decoder, binary( + "f0e1bf4cb2ec1600e1005f8791e901000000c959515c2cc24a03aeadcd010e01a800250001090201878e92e901000000cb59515c2dc24a03b8adcd018801a8001d0001080201325993e901000000cc59515c2fc24a03bfadcd01ab01a800220001080201dd8194e901000000cd59515c32c24a03ceadcd015801a8002500010802015f3795e905000900ce59515c32c24a03d8adcd01f600a700250001091401000000000000000000863496e901000000cf59515c34c24a03ddadcd019b00a700280001090201714197e904000600cf59515c34c24a03ddadcd019b00a7002800010a1401becd07001901")); + + verifyPositions(decoder, binary( + "22b5bf4cb2ec1600500122b37ba020001500cb5d2f5c68c24a0310aecd016200b1003d000004000177042700a501000000000000000101020100011e00a1657ca020001500cf5d2f5c68c24a03dbadcd013501b10097000004030177042700a501000000000000000101020101011e00816e7da003004800b95e2f5c89c24a03fbadcd010000aa00000000040601011038363133353930333632333039323600383933373530323730313030323335343836363000323537303237303132333534383636004d5453000000000066640101005700e515cf047ea001000000295f2f5c89c24a03fbadcd0100009a0000000106020106dc30a8030048006bc13e5c19c24a03bfadcd010000ad00000000050600011338363133353930333632333039323600383933373530323730313030323335343836363000323537303237303132333534383636004d5453000000000066640101005700e515")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java new file mode 100644 index 000000000..48adb0ccb --- /dev/null +++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SigfoxProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SigfoxProtocolDecoder decoder = new SigfoxProtocolDecoder(null); + + verifyPosition(decoder, request(HttpMethod.POST, "/", + buffer("%7B++%22device%22%3A%222BF839%22%2C++%22time%22%3A1510605882%2C++%22duplicate%22%3Afalse%2C++%22snr%22%3A45.61%2C++%22station%22%3A%2235A9%22%2C++%22data%22%3A%2200bd6475e907398e562d01b9%22%2C++%22avgSnr%22%3A45.16%2C++%22lat%22%3A-38.0%2C++%22lng%22%3A145.0%2C++%22rssi%22%3A-98.00%2C++%22seqNumber%22%3A228+%7D="))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java new file mode 100644 index 000000000..3a91d8482 --- /dev/null +++ b/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SiwiProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SiwiProtocolDecoder decoder = new SiwiProtocolDecoder(null); + + verifyPosition(decoder, text( + "$SIWI,9803932,23992,E,0,,0,1,1,0,5055,0,5,A,22.289887,70.807192,152,168,102922,090317,28,1,12,5,4098,1,0,13,0,0,0,1.0,3.1CHKS_4.82,0!")); + + verifyPosition(decoder, text( + "$SIWI,2845,1320,Q,10,airtelgprs.com,1,1,0,0,876578,43,9,A,19.0123456,72.65347,45,0,055929,071107,22,5,1,0,3700,1210,0,2500,1230,321,0,1.1,4.0,1!")); + + verifyPosition(decoder, text( + "$SIWI,9803849,953,R,9,,0,1,1,0,0,0,8,A,19.066145,73.002278,213,178,122738,210217,28,5,12,6,4066,1,0,2,0,0,0,1.0,3.1CHKS_4.82,0")); + + verifyPosition(decoder, text( + "$EIT,9803849,953,R,9,,0,1,1,0,0,0,8,A,19.066145,73.002278,213,178,122738,210217,28,5,12,6,4066,1,0,2,0,0,0,1.0,3.1CHKS_4.82,0")); + + verifyPosition(decoder, text( + "$SIWI,9803849,954,E,0,,0,1,1,0,0,0,0,V,0.000000,0.000000,0,0,122855,210217,29,5,12,5,4104,1,0,2,0,0,0,1.0,3.1CHKS_4.82,0")); + + verifyPosition(decoder, text( + "$SIWI,2845,1320,A,0,,1,1,0,0,876578,43,10,A,19.0123456,72.65347,45,0,055929,071107,22,5,1,0,3700,1210,0,2500,1230,321,0,1.1,4.0,1!")); + + verifyPosition(decoder, text( + "$SIWI,9803849,956,E,0,,0,1,1,0,0,0,3,V,19.066935,73.003383,0,111,123037,210217,28,5,12,5,4071,1,0,2,0,0,0,1.0,3.1CHKS_4.82,0")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java new file mode 100644 index 000000000..bc2dac7e9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java @@ -0,0 +1,34 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SkypatrolProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SkypatrolProtocolDecoder decoder = new SkypatrolProtocolDecoder(null); + + verifyNull(decoder, binary( + "000a02171101303131373232303031333537393833060200000006202020202020202020312020202020202030313137323230303133353739383320")); + + verifyNull(decoder, binary( + "000402171101303131373232303031333537393833060200081046202020202020202020392020202020202030313137323230303133353739383320244750524d432c3134303931372e30302c412c333330322e3230313132352c532c30373133352e3837383338332c572c302e302c302e302c3036303731372c322e382c572c412a32370d0a00")); + + verifyPosition(decoder, binary( + "0005021004FFFFFFFF0000000D313134373735383300CB000000000E11070C010184D032FB3841370000000016072B000017050032000000000000024E0C071116072C105900050000000000050000000000050000000003100260B7363B6306C11A00B73637F206BF19B73637F106B50EB73638B106BB0BB7363B6106B80AB73637F306B709000000000000000000")); + + verifyNull(decoder, binary( + "000500030101383637383434303031373832333336420102000c0000fa07b5e101876c5b0e0a111606131c1b5e")); + + // Enfora TT8750 + verifyNull(decoder, binary( + "000502000000f1143035303031393031d1df002f00000d0187120115e556ff762aa90000000000aae40005d2000ee1bc0e010a042530000000000000070004000002233c096c00ee2a00233c008500f022233c0b0500f21d233c000000fb23000000000000000000000000000000000000000000000000000000")); + + verifyNull(decoder, binary( + "00040200202020202020202020382020202020202030313137323230303131383531373820313220244750524d432c3232343833392e30302c412c303332382e3433383830362c4e2c30373633312e3630373731372c572c302e302c302e302c3139303731342c332e382c452c412a32420d0a00")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java new file mode 100644 index 000000000..183af899b --- /dev/null +++ b/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SmartSoleProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SmartSoleProtocolDecoder decoder = new SmartSoleProtocolDecoder(null); + + verifyPosition(decoder, text( + "#GTXRP=359366080000385,8,180514200051,34.041981,-118.255806,60,1,1,7,1.80,180514200051,4.16,11")); + + verifyPosition(decoder, text( + "#GTXRP=359372090000290,11,180919105751,46.477173,6.445475,389,0,0,0,1.08,180919105751,4.10,10")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java new file mode 100644 index 000000000..c2d74b433 --- /dev/null +++ b/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SmokeyProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SmokeyProtocolDecoder decoder = new SmokeyProtocolDecoder(null); + + verifyAttributes(decoder, binary( + "534d0300865101019383025f0403000000000b86250200000c0000028f000102f8cc0900127f08")); + + verifyAttributes(decoder, binary( + "534d0300865101019383025f0403000000000bcf260200000c0000028f000102f8cc090012360b")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java new file mode 100644 index 000000000..7191f31ef --- /dev/null +++ b/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpMethod; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SpotProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SpotProtocolDecoder decoder = new SpotProtocolDecoder(null); + + verifyPositions(decoder, request(HttpMethod.POST, "/", + buffer("\n\n
\n 1\n LIVE\n
\n \n 891801957\n 0-3112123\n 0-3112123a\n NEWMOVEMENT\n SPOT Trace has detected that the asset has moved.\n 2017-12-27T13:19:38.000Z\n 1514380778\n -1.28781\n -47.93042\n GOOD\n \n
"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java new file mode 100644 index 000000000..70e173284 --- /dev/null +++ b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java @@ -0,0 +1,54 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class StarLinkProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + StarLinkProtocolDecoder decoder = new StarLinkProtocolDecoder(null); + + verifyAttributes(decoder, text( + "$SLU068328,06,55,170518122023,16,,,,,,000000,1,1,0,0,0,0,0,0,10443,32722,12.664,03.910,,0,0,,01000001FDB3A9*BF")); + + verifyAttributes(decoder, text( + "$SLU068328,06,56,170518122023,20,,,,,,000000,1,1,0,0,0,0,0,0,10443,32722,12.664,03.910,,0,0,2,01000001FDB3A9,00000000000000000000*D9")); + + verifyAttributes(decoder, text( + "$SLU068328,06,57,170518122038,01,,,,,,000000,1,1,0,0,1,0,0,0,10443,32722,12.669,03.910,,0,0,0,99*6E")); + + verifyAttributes(decoder, text( + "$SLU068328,06,58,170518122045,19,,,,,,000000,1,1,0,0,1,0,0,0,10443,32722,12.678,03.910,,0,0*7C")); + + verifyAttributes(decoder, text( + "$SLU068328,06,59,170518122054,16,,,,,,000000,1,1,0,0,0,0,0,0,10443,32723,12.678,03.910,,0,0,01000001FDB3A9,01000001ACE0A6*BF")); + + verifyPosition(decoder, text( + "$SLU031B2B,06,622,170329035057,01,170329035057,+3158.0018,+03446.6968,004.9,007,000099,1,1,0,0,0,0,0,0,,,14.176,03.826,,1,1,1,4*B0")); + + verifyPosition(decoder, text( + "$SLU031B2B,06,624,170329035143,01,170329035143,+3158.0171,+03446.6742,006.8,326,000099,1,1,0,0,0,0,0,0,10452,8723,14.212,03.827,,1,1,1,4*6D")); + + verifyPosition(decoder, text( + "$SLU0330D5,06,3556,170314063523,19,170314061634,+3211.7187,+03452.8106,000.0,332,015074,1,1,0,0,0,0,0,0,10443,32722,12.870,03.790,,0,0*FC")); + + verifyPosition(decoder, text( + "$SLU0330D5,06,3555,170314063453,20,170314061634,+3211.7187,+03452.8106,000.0,332,015074,1,1,0,0,0,0,0,0,10443,32722,12.838,03.790,,0,0,1,,1122*74")); + + verifyPosition(decoder, text( + "$SLU006968,06,375153,170117051824,01,170117051823,+3203.2073,+03448.1360,000.0,300,085725,1,1,0,0,0,0,0,0,10422,36201,12.655,04.085,,0,0,0,99*45")); + + verifyPosition(decoder, text( + "$SLU006968,06,375155,170117052615,24,170117052613,+3203.2079,+03448.1369,000.0,300,085725,1,1,0,0,0,0,0,0,10422,36201,14.290,04.083,,1,1*5B")); + + verifyPosition(decoder, text( + "$SLU006968,06,375156,170117052616,34,170117052614,+3203.2079,+03448.1369,000.0,300,085725,1,1,0,0,0,0,0,0,10422,36201,14.277,04.084,1,1,1,1*F3")); + + verifyPosition(decoder, text( + "$SLU006968,06,375154,170117052613,04,170117052612,+3203.2079,+03448.1369,000.0,300,085725,1,1,0,0,0,0,0,0,10422,36201,14.287,04.084,,1,0*5B")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java new file mode 100644 index 000000000..e2be2028e --- /dev/null +++ b/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java @@ -0,0 +1,28 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Stl060ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Stl060ProtocolDecoder decoder = new Stl060ProtocolDecoder(null); + + verifyPosition(decoder, text( + "$1,357804048043099,D001,AP29AW0963,23/02/14,14:06:54,17248488N,078342226E,0.08,193.12,1,1,1,1,1,A"), + position("2014-02-23 14:06:54.000", true, 17.41415, 78.57038)); + + verifyPosition(decoder, text( + "$1,357804048043099,D001,AP29AW0963,12/05/14,07:39:57,1724.8564N,07834.2199E,0.00,302.84,1,1,1,1,1,A")); + + verifyPosition(decoder, text( + "$1,357804047969310,D001,AP29AW0963,01/01/13,13:24:47,1723.9582N,07834.0945E,00100,010,0,0,0,0,0,A,")); + + verifyPosition(decoder, text( + "$1,357804047969310,D001,AP29AW0963,01/01/13,13:24:47,1723.9582N,07834.0945E,00100,010,0,0,0,0,0,0008478660,1450,40,34,0,0,0,A")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java new file mode 100644 index 000000000..355cda783 --- /dev/null +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -0,0 +1,167 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class SuntechProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecodeTemperature() throws Exception { + + SuntechProtocolDecoder decoder = new SuntechProtocolDecoder(null); + + decoder.setHbm(true); + decoder.setIncludeAdc(true); + decoder.setIncludeTemp(true); + + verifyPosition(decoder, text( + "ST300STT;205173382;07;564;20160322;23:23:18;232e19;+19.288278;-099.128750;000.122;000.00;9;1;478391;11.53;000100;1;9498;079324;4.3;1;0.00;0.00;0.00;00000000000000;0;2898E16006000058:-20.8;2861626006000039:+2.5;:")); + + verifyPosition(decoder, text( + "ST300EVT;205173382;07;564;20160322;23:23:18;232e19;+19.288278;-099.128750;000.122;000.00;9;1;478391;11.53;000100;2;1;9498;079324;4.3;1;0.00;0.00;0.00;00000000000000;0;2898E16006000058:-20.8;2861626006000039:+2.5;:")); + + verifyPosition(decoder, text( + "ST600STT;008349958;35;523;20181112;00:49:30;0bf10d4e;334;20;2f19;22;+20.552718;-100.824478;050.021;095.41;12;1;1303603;14.30;10000000;4;8911;001987;4.1;0;0.00;;;;00000000000000;0;2826C8A70800000C:+26.6;:;:")); + + } + + @Test + public void testDecodeHours() throws Exception { + + SuntechProtocolDecoder decoder = new SuntechProtocolDecoder(null); + + decoder.setHbm(true); + + verifyPosition(decoder, text( + "ST300STT;007238270;40;313;20190220;12:05:04;c99e48;+04.644623;-074.076922;010.390;202.77;20;1;997100;14.10;100000;2;8384;003634;4.1;1")); + + verifyPosition(decoder, text( + "ST300STT;109002029;08;1080;20190220;13:00:55;85405;+04.645710;-074.078525;007.760;005.19;10;1;6520802;13.86;100100;4;1716;0000039863;4.1;1;0.00;0000;0000;0;0")); + + verifyAttribute(decoder, text( + "ST300ALT;007239104;40;313;20190112;01:07:16;c99139;+04.703287;-074.148897;000.000;189.72;21;1;425512;12.61;100000;33;003188;4.1;1"), + Position.KEY_HOURS, 3188 * 60000L); + + } + + @Test + public void testDecode() throws Exception { + + SuntechProtocolDecoder decoder = new SuntechProtocolDecoder(null); + + verifyPosition(decoder, text( + "SA200STT;608945;129;20190215;15:04:53;3dce071558;+22.006721;-098.771016;001.198;000.00;11;1;2632589;12.21;010000;1;3211")); + + verifyPosition(decoder, text( + "ST410STT;007272376;408;01;10217;732;103;-87;51511;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;3.8;1;2503;6;20181031;20:12:58;+04.741277;-074.048238;052.375;189.87;20;1")); + + verifyPosition(decoder, text( + "ST410STT;007272376;408;01;21651;732;123;-65;1824;1;21654;732;123;1824;0;0;22542;732;123;1824;0;0;21656;732;123;1824;0;0;21655;732;123;1824;0;0;22541;732;123;1824;0;0;0;0;0;0;0;0;3.7;1;0156;1;20180816;05:18:52;+04.722322;-074.052776;000.074;000.00;10;1")); + + verifyPosition(decoder, text( + "ST600STT;008084783;20;419;20180308;18:00:36;0032cc3e;736;3;445c;41;-16.530023;-068.084267;018.640;267.99;10;1;11655;13.33;100000;2;0336;000061;4.5;0;0.00")); + + verifyPosition(decoder, text( + "ST600STT;107850496;20;419;20180227;14:30:45;00462b08;736;3;4524;50;-16.479091;-068.119119;000.346;000.00;4;1;0;13.89;000000;1;0223;000003;0.0;0;0.00")); + + verifyPosition(decoder, text( + "ST600STT;100850000;01;010;20081017;07:41:56;0000004f;450;20;0023;24;+37.478519;+126.886819;000.012;000.00;9;1;0;15.30;00110000;1;0072;0;4.5;1;12.35")); + + verifyPosition(decoder, text( + "STT;100850000;3FFFFF;26;010;1;20161117;08:37:39;0000004F;450;0;0014;20;+37.479323;+126.887827;62.03;65.43;10;1;00000101;00001000;1;2;0492")); + + verifyPosition(decoder, text( + "STT;6009999006;3FFFFF;26;398;0;20170827;20:04:37;087d4760;310;410;0ba0;23;+40.123420;-074.995971;000.031;000.00;8;1;00000001;00000000;1;1;0006")); + + verifyPosition(decoder, text( + "ST500STT;205450135;07;843;20170816;23:24:45;+19.338432;-099.179817;000.283;000.00;6;1;141121;12.89;0;0;1;4659;002.795;0;001.891;611;4.0")); + + verifyPosition(decoder, text( + "ST300STT;205170303;12;561;20170816;09:10:34;173f53;+19.082370;-098.214287;006.776;000.00;0;0;52982186;12.75;100000;2;6328;155747;4.2;1;0.00;0;0.00;0.00;00000000000000;0;28F2B7600600005D:+5.2;:;:")); + + verifyPosition(decoder, text( + "ST910;Location;205576803;500;20170319;12:18:17;-22.846014;-046.322176;000.000;000.00;0;3.8;0;1;9159")); + + verifyPosition(decoder, text( + "ST910;Emergency;205576803;500;20170319;12:15:22;-22.846014;-046.322176;000.000;000.00;0;2")); + + verifyPosition(decoder, text( + "ST910;Location;205576803;500;20170312;12:56:52;-22.846014;-046.322176;000.000;000.00;0;3.8;0;0;0019")); + + verifyPosition(decoder, text( + "ST300STT;100850000;01;010;20081017;07:41:56;00100;+37.478519;+126.886819;000.012;000.00;9;1;0;15.30;001100;1;0072;0;4.5;1;1750;012497F1160000;1;004f001454;450;00;-320;20;255;1")); + + verifyPosition(decoder, text( + "ST300STT;205589913;05;527;20170304;02:21:33;be139;-25.398868;-049.325636;000.476;000.00;6;1;427;12.57;100000010;1;0172;017.159;0;002.327;12;4.0")); + + verifyPosition(decoder, text( + "SA200STT;638947;803;20170117;07:40:44;5d309;-01.287213;-047.917462;000.035;000.00;10;1;2036194;12.57;000000;1;0376;010360;4.2;1")); + + verifyPosition(decoder, text( + "ST300ALT;205174410;14;712;20110101;00:00:07;00000;+20.593923;-100.336716;000.000;000.00;0;0;0;16.57;000000;81;000000;4.0;0;0.00;0000;0000;0;0")); + + verifyNull(decoder, text( + "SA200ALV;317652")); + + verifyPosition(decoder, text( + "ST910;Alert;123456;410;20141018;18:30:12;+37.478774;+126.889690;000.000;000.00;0;4.0;1;6002"), + position("2014-10-18 18:30:12.000", false, 37.47877, 126.88969)); + + verifyPosition(decoder, text( + "ST910;Alert;123456;410;20141018;18:30:12;+37.478774;+126.889690;000.000;000.00;0;4.0;1;6002;02;0;0310000100;450;01;-282;70;255;3;0")); + + verifyPosition(decoder, text( + "SA200STT;317652;042;20120718;15:37:12;16d41;-15.618755;-056.083241;000.024;000.00;8;1;41548;12.17;100000;2;1979"), + position("2012-07-18 15:37:12.000", true, -15.61876, -56.08324)); + + verifyPosition(decoder, text( + "SA200STT;317652;042;20120721;19:04:30;16d41;-15.618743;-056.083221;000.001;000.00;12;1;41557;12.21;000000;1;3125")); + + verifyPosition(decoder, text( + "SA200STT;317652;042;20120722;00:24:23;4f310;-15.618767;-056.083214;000.011;000.00;11;1;41557;12.21;000000;1;3205")); + + verifyPosition(decoder, text( + "SA200STT;315198;042;20120808;20:37:34;3fac25;-15.618731;-056.083216;000.007;000.00;12;1;48;0.00;000000;1;0127")); + + verifyPosition(decoder, text( + "SA200STT;315198;042;20120809;13:43:34;4f310;-15.618709;-056.083223;000.025;000.00;8;1;49;12.10;100000;2;0231")); + + verifyPosition(decoder, text( + "SA200EMG;317652;042;20120718;15:35:41;16d41;-15.618740;-056.083252;000.034;000.00;8;1;41548;12.17;110000;1")); + + verifyPosition(decoder, text( + "SA200ALT;317652;042;20120829;14:25:58;16d41;-15.618770;-056.083242;000.029;000.00;0;0;2404240;0.00;000000;10")); + + verifyPosition(decoder, text( + "SA200STT;430070;133;20130615;22:22:32;151347;+02.860514;-060.653351;000.003;000.00;12;1;0;12.39;000000;1;0208")); + + verifyPosition(decoder, text( + "ST910;Location;344506;017;20130727;14:10:00;-25.398714;-049.296818;000.187;000.00;1;4.32;1;1;0001")); + + verifyPosition(decoder, text( + "ST300STT;205027329;03;374;20150108;17:54:42;177b38;-23.566052;-046.477588;000.000;000.00;0;0;0;12.11;000000;1;0312")); + + verifyPosition(decoder, text( + "ST910;Emergency;205283272;500;20150716;19:12:01;-23.659019;-046.695403;000.602;000.00;0;4.2;1;1;02;10820;2fdb090736;724;05;0;2311;255;0;100")); + + decoder.setProtocolType(1); + + verifyPosition(decoder, text( + "ST910;Location;907510186;552;20180504;23:15:45;3af54e5331;+19.301833;-099.190657;000.246;000.00;1;28462;80;1;0;0423;02;334;05;-215;20051;1;4;100")); + + verifyPosition(decoder, text( + "ST910;Alert;485195;20170409;22:37:41;3be0133057;+24.882410;-107.509152;000.070;000.00;1;286734;72;02;295;05;-415;4912;255;10;10")); + + verifyPosition(decoder, text( + "ST910;Location;485195;528;20170410;01:18:57;f1dd134840;+24.787139;-107.434679;000.020;000.00;1;286734;100;1;0;0188;02;295;05;-339;4936;255;4;74")); + + verifyPosition(decoder, text( + "ST910;Location;560266;500;20161207;21:33:11;af910be101;-25.504234;-049.278003;000.080;000.00;1;10054889;70;1;1;1311;02;724;06;-317;3041;2;10;92")); + + verifyPosition(decoder, text( + "ST910;Emergency;238569;528;20170403;00:02:09;7574160020;+19.661292;-099.144473;000.176;000.00;1;228638;1")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java new file mode 100755 index 000000000..2a7ab2dee --- /dev/null +++ b/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SupermateProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SupermateProtocolDecoder decoder = new SupermateProtocolDecoder(null); + + verifyPosition(decoder, text( + "2:359672050130411:1:*,00000000,XT,A,10031b,140b28,80ad4c72,81ba2d2c,06ab,238c,020204010000,12,0,0000,0003e6")); + + verifyPosition(decoder, text( + "2:359672050130411:2:*,00000000,UP,A,10031b,140a1c,80ad4bf6,81ba2dc3,0000,0000,020204000000,14,0,0000,0003e6")); + + verifyPosition(decoder, text( + "2:359672050130411:1:*,00000000,BJ,A,10031b,140c2f,80ad5012,81ba1f27,0f4c,2e18,020204014000,14,0,0000,0003ed")); + + } + +} \ No newline at end of file diff --git a/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java new file mode 100644 index 000000000..f7b15ca2e --- /dev/null +++ b/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class SviasProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + SviasProtocolDecoder decoder = new SviasProtocolDecoder(null); + + verifyPosition(decoder, text( + "[7061,3041,57,20324277,710,40618,141342,-93155840,-371754060,0,20469,0,16,1,0,0,11323,100,9,,32,4695")); + + verifyPosition(decoder, text( + "[7041,3041,8629,20856286,710,60618,201027,-92268040,-371346250,7994,31844,38271,16,1,0,0,13416,100,0,0,5089")); + + verifyPosition(decoder, text( + "[7051,3041,15270,30179873,710,70618,40335,-94679080,-360604930,0,35454,23148,0,1,0,0,12542,100,13,32,4971")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java new file mode 100644 index 000000000..f21acdee7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java @@ -0,0 +1,126 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class T55ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + T55ProtocolDecoder decoder = new T55ProtocolDecoder(null); + + verifyNull(decoder, text( + "$DEVID,0x0103846677F21422*41")); + + verifyPosition(decoder, text( + "660420156A0066AA$GPRMC,122806.0,A,0119.212178,N,10355.000942,E,0.0,,230119,0.0,E,A*27")); + + verifyNull(decoder, text( + "$IMEI=355797031609284")); + + verifyNull(decoder, text( + "086415031C20")); + + verifyNull(decoder, text( + "358244017671308")); + + verifyPosition(decoder, text( + "$GPGGA,082350.000,5355.0314,N,01044.1271,E,1,10,0.7,-46.0,M,0.0,M,0.0,0000")); + + verifyPosition(decoder, text( + "$GPRMC,082350.000,A,5355.0314,N,01044.1271,E,26.20,184.27,080518,,")); + + verifyPosition(decoder, text( + "$GPRMC,192350.000,V,0000.0000,N,00000.0000,E,,,110318,,*12")); + + verifyPosition(decoder, text( + "$GPRMC,073446.000,A,1255.5125,N,07738.2948,E,0.00,0.53,080316,D*71,11,865733027593268,1,090,086,123,456,789,987,12345")); + + verifyNotNull(decoder, text( + "$GPRMC,161223.000,A,2517.0545,S,05739.1788,W,0.0,0.0,011196,,,A*61")); + + verifyPosition(decoder, text( + "4711/022789000688081/$GPRMC,133343,A,5308.56325,N,1029.12850,E,0.000000,0.000000,290316,,*2A")); + + verifyPosition(decoder, text( + "$GPRMC,073446.000,A,1255.5125,N,07738.2948,E,0.00,0.53,080316,D*71,11,865733027593268,1,090,086")); + + verifyNull(decoder, text( + "$GPFID,ID123456ABC")); + + verifyNull(decoder, text( + "$PGID,359853000144328*0F")); + + verifyNull(decoder, text( + "$PCPTI,CradlePoint Test,184453,184453.0,6F*57")); + + verifyNull(decoder, text( + "IMEI 351467108700000")); + + verifyPosition(decoder, text( + "$GPRMC,012006,A,4828.10,N,1353.52,E,0.00,0.00,180915,020.3,E*42")); + + verifyPosition(decoder, text( + "$GPRMC,094907.000,A,6000.5332,N,03020.5192,E,1.17,60.26,091111,,*33")); + + verifyPosition(decoder, text( + "$GPRMC,115528.000,A,6000.5432,N,03020.4948,E,,,091111,,*06")); + + verifyPosition(decoder, text( + "$GPRMC,064411.000,A,3717.240078,N,00603.046984,W,0.000,1,010313,,,A*6C")); + + verifyPosition(decoder, text( + "$GPGGA,000000.0,4337.200755,N,11611.955704,W,1,05,3.5,825.5,M,-11.0,M,,*6F")); + + verifyPosition(decoder, text( + "$GPGGA,000000,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47")); + + verifyPosition(decoder, text( + "$GPRMA,V,0000.00,S,00000.00,E,,,00.0,000.,11.,E*7")); + + verifyPosition(decoder, text( + "$TRCCR,20140101001122.333,V,60.0,-100.0,1.1,2.2,3.3,4.4,*00")); + + verifyPosition(decoder, text( + "$TRCCR,20140111000000.000,A,60.000000,60.000000,0.00,0.00,0.00,50,*3a")); + + verifyPosition(decoder, text( + "$GPRMC,125735.000,A,6010.34349,N,02445.72838,E,1.0,101.7,050509,6.9,W,A*1F")); + + verifyPosition(decoder, text( + "$GPGGA,000000.000,6010.34349,N,02445.72838,E,1,05,1.7,0.9,M,35.1,M,,*59")); + + verifyPosition(decoder, text( + "123456789$GPGGA,000000.000,4610.1676,N,00606.4586,E,0,00,4.3,0.0,M,50.7,M,,0000*59")); + + verifyPosition(decoder, text( + "123456789$GPRMC,155708.252,V,4610.1676,N,00606.4586,E,000.0,000.0,060214,,,N*76")); + + verifyPosition(decoder, text( + "990000561287964,$GPRMC,213516.0,A,4337.216791,N,11611.995877,W,0.0,335.4,181214,,,A * 72")); + + verifyPosition(decoder, text( + "355096030432529$GPGGA,000000.00,3136.599,S,5213.981,W,1,7,2.13,250.00,M,-16.384,M,3550960304325290.0,1")); + + verifyPosition(decoder, text( + "355096030432529$GPGGA,000000.00,3136.628,S,5213.990,W,1,7,2.13,250.00,M,-16.384,M,0.0,1")); + + } + + @Test + public void testMaxonDecode() throws Exception { + + // Maxon devices can send NMEA before identification + + T55ProtocolDecoder decoder = new T55ProtocolDecoder(null); + + verifyNull(decoder, text( + "$GPRMC,012006,A,4828.10,N,1353.52,E,0.00,0.00,180915,020.3,E*42")); + + verifyPosition(decoder, text( + "$GPFID,ID123456ABC")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java b/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java new file mode 100644 index 000000000..f74d3c350 --- /dev/null +++ b/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java @@ -0,0 +1,19 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class T57FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + T57FrameDecoder decoder = new T57FrameDecoder(); + + verifyFrame( + binary("2a5435372346312354353731313137303031233330313131372330303038343323323233342e31333033234e2330383832362e313731342345232b302e3234322c2b302e3130392c2d302e37383923302e30303023362e323030303023413223342e3223"), + decoder.decode(null, null, binary("2a5435372346312354353731313137303031233330313131372330303038343323323233342e31333033234e2330383832362e313731342345232b302e3234322c2b302e3130392c2d302e37383923302e30303023362e323030303023413223342e32232a5435372346312354353731313137303031233330313131372330303038353323323233342e31333033234e2330383832362e313731342345232b302e3234322c2b302e3130392c2d302e37383923302e30303023362e323030303023413223342e32232a5435372346312354353731313137303031233330313131372330303039303423323233342e31333033234e2330383832362e313731342345232b302e3234322c2b302e3130392c2d302e37383923302e30303023362e323030303023413223342e32232a5435372346312354353731313137303031233330313131372330303039313423323233342e31333033234e2330383832362e313731342345232b302e3234322c2b302e3130392c2d302e37383923302e30303023362e323030303023413223342e32232a5435372346312354353731313137303031233330313131372330303039323423323233342e31333033234e2330383832362e313731342345232b302e3234322c2b302e3130392c2d302e37383923302e30303023362e323030303023413223342e32232a5435372346312354353731313137303031233330313131372330303038333323323233342e31333033234e2330383832362e313731342345232b302e3234322c2b302e3130392c2d302e37383923302e30303023362e323030303023413223342e3223"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java new file mode 100644 index 000000000..c457b4602 --- /dev/null +++ b/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java @@ -0,0 +1,27 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class T57ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + T57ProtocolDecoder decoder = new T57ProtocolDecoder(null); + + verifyPosition(decoder, text( + "*T57#F1#T571117001#301117#000843#2234.1303#N#08826.1714#E#+0.242,+0.109,-0.789#0.000#6.20000#A2#4.2#")); + + verifyPosition(decoder, text( + "*T57#F1#0123456789#041117#152900#1258.9653#N#07738.4169#E#00000000000000000000#0.000#926.300#A2#4.0#")); + + verifyPosition(decoder, text( + "*T57#F2#0123456789#041117#152900#1258.9653#N#07738.4169#E#00000000000000000000#0.000#926.300#A2#4.0#")); + + verifyNull(decoder, text( + "*T57#F3#0123456789#041117#152900#1258.9653#N#07738.4169#E#I#9674432345#340#")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java new file mode 100644 index 000000000..fe77d91b7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java @@ -0,0 +1,48 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class T800xProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + T800xProtocolDecoder decoder = new T800xProtocolDecoder(null); + + verifyNull(decoder, binary( + "252501001504050880061689888888111111250350")); + + verifyPosition(decoder, binary( + "2525020044a66d0862522030401350001403841409c40064edc000051100960000071701370000003ea7ee0019032010581300000000aad3e1bda6f24d42000000001281")); + + verifyPosition(decoder, binary( + "252502004400010880616898888888000A00FF2001000020409600989910101010055501550000101005050005051010050558866B4276D6E342912AB441111500051010")); + + verifyNull(decoder, binary( + "232301001500000880316890202968140197625020")); + + verifyNull(decoder, binary( + "232303000f00000880316890202968")); + + verifyAttributes(decoder, binary( + "232302004200000880316890202968001e02582d00000000000000050000320000018901920000001dc1e2001601081154255d0202005a0053875a00a57e5a00af80")); + + verifyNull(decoder, binary( + "232301001500020357367031063979150208625010")); + + verifyNull(decoder, binary( + "232303000f00000357367031063979")); + + verifyPosition(decoder, binary( + "232304004200030357367031063979003c03842307d00000c80000050100008000008900890100000017b100151022121648b8ef0c4422969342cec5944100000110")); + + verifyPosition(decoder, binary( + "232302004200150357367031063979003c03842307d000004a0000050100004001009500940000000285ab001510281350477f710d4452819342d1ba944101160038")); + + verifyAttributes(decoder, binary( + "232302004200000357367031063979003c03842307d000008000000501000000010094009400000002a0b90015102814590694015a00620cf698620cf49e620cf498")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java new file mode 100644 index 000000000..af3700225 --- /dev/null +++ b/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class T800xProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + T800xProtocolEncoder encoder = new T800xProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "RELAY,0000,On#"); + + verifyCommand(encoder, command, binary("232381001e000101234567890123450152454c41592c303030302c4f6e23")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java new file mode 100644 index 000000000..bdbaec8aa --- /dev/null +++ b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java @@ -0,0 +1,86 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TaipProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TaipProtocolDecoder decoder = new TaipProtocolDecoder(null); + + verifyPosition(decoder, text( + ">RGP211217112154-2748332-058946350000000FF7F2100;ID=AA01;#0002;*2D<")); + + verifyPosition(decoder, text( + ">RCV12270218010247-3471349-058400030002057F001200020A1D013010600001509+0000FF+0000FF;#1DE2;ID=7196;*03<")); + + verifyPosition(decoder, text( + ">RPV03874+3477708-0923453100029212;ID=0017;*71<")); + + verifyNull(decoder, text( + ">RAL03874+00185+00012;ID=0017;*4A<")); + + verifyNull(decoder, text( + ">RCP03874+347771-092345312;ID=0017;*65<")); + + verifyNull(decoder, text( + ">RLN03874000+347770828-0923453071+000608270000+0000292309000000000000000000000000000000000000000000000012;ID=0017;*49<")); + + verifyPosition(decoder, text( + ">RPV46640+4197412-0752857900015802;ID=5102;*71<")); + + verifyNull(decoder, text( + ">RCP46640+419741-075285802;ID=5102;*6C<")); + + verifyPosition(decoder, text( + ">REV001958003965+0307178+1016144900031532;IO=300;SV=8;BL=4159;CF=8161,C,13;AD=14145;IX=10233040;FF=0,0,0,0;VO=338578;ID=357042063052352<")); + + verifyPosition(decoder, text( + ">REV011958000369+0307185+1016144400000032;IO=200;SV=9;BL=4158;CF=0,0,0;AD=12347;IX=10213040;FF=0,0,0,0;VO=338572;ID=357042063052352<")); + + verifyPosition(decoder, text( + ">REV421942237017+1170957-0701880200000032;ID=356612022463055<")); + + verifyPosition(decoder, text( + ">RGP200317010815-3852.9306-06204.88560000003000101;&01;ID=5555;#7AD7*51<")); + + verifyPosition(decoder, text( + ">RCQ09000000000000-3460365-058381460000007F0000000000000115000FFFF1099;#0000;ID=555224;*05<")); + + verifyPosition(decoder, text( + ">RBR00130217040848-3462200-05846708000175FF0022900003B3C13010800001118410+24061A;ID=555224;*07<")); + + verifyPosition(decoder, text( + ">REV451891352379+0307152+1016143700000012;SV=8;BL=4416;VO=8055;ID=356612026322000<")); + + verifyPosition(decoder, text( + ">RGP230615010248-2682523-065236820000003007F4101;ID=0005;#0002;*2A<"), + position("2015-06-23 01:02:48.000", true, -26.82523, -65.23682)); + + verifyPosition(decoder, text( + ">RGP190805211932-3457215-058493640000000FFBF0300;ID=8251;#2122;*54<")); + + verifyPosition(decoder, text( + ">RPV00000+3739438-1220384601512612;ID=1234;*7F")); + + verifyPosition(decoder, text( + "\r\n>REV691615354941+3570173+1397742703203212;ID=Test")); + + verifyPosition(decoder, text( + ">REV481599462982+2578391-0802945201228512;ID=Test"), + position("2010-09-02 17:29:42.000", true, 25.78391, -80.29452)); + + verifyPosition(decoder, text( + ">REV131756153215+3359479-0075299001031332;VO=10568798;IO=310;SV=10;BL=4190;CV09=0;AD=0;AL=+47;ID=356612021059680")); + + verifyPosition(decoder, text( + ">RPV02138+4555512-0735478000000032;ID=1005;*76<")); + + verifyPosition(decoder, text( + ">RPV19105+4538405-0739518900000012;ID=9999;*7A<\r\n")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java new file mode 100644 index 000000000..0446670d8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TekFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TekFrameDecoder decoder = new TekFrameDecoder(); + + verifyFrame( + binary("020315048715E70861074028023219026200400A0340002C007F0009000000000000000000402842064028420641284206402844064128440640284406402844064028440641284406402844060010010C04052B000253000000000001060A0000000000000228330000FF0000FF360014B394"), + decoder.decode(null, null, binary("020315048715E70861074028023219026200400A0340002C007F0009000000000000000000402842064028420641284206402844064128440640284406402844064028440641284406402844060010010C04052B000253000000000001060A0000000000000228330000FF0000FF360014B394"))); + + verifyFrame( + binary("0501C2828E14750861075021004551047B00019700000082010F0A5B28770A5B28770A5B28760A5B28770A5B28770A5B28770A5B28770A5B28760A5B28760A5B28760A5B28770A5B28760A5B28760A5B28760A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5F2877000000000000000000000000EEBA"), + decoder.decode(null, null, binary("0501C2828E14750861075021004551047B00019700000082010F0A5B28770A5B28770A5B28760A5B28770A5B28770A5B28770A5B28770A5B28760A5B28760A5B28760A5B28770A5B28760A5B28760A5B28760A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5F2877000000000000000000000000EEBA"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java new file mode 100644 index 000000000..f67ae9c3f --- /dev/null +++ b/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TekProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TekProtocolDecoder decoder = new TekProtocolDecoder(null); + + verifyPosition(decoder, binary( + "0501E304E00E76086107502100455111492C33332C3137303935342E302C353235352E393933344E2C30303833322E34333935572C322E312C3133342E382C322C302E30302C302E302C302E302C3234303931352C30362C3C45")); + + verifyAttributes(decoder, binary( + "0501C2828E14750861075021004551047B00019700000082010F0A5B28770A5B28770A5B28760A5B28770A5B28770A5B28770A5B28770A5B28760A5B28760A5B28760A5B28770A5B28760A5B28760A5B28760A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5D28770A5F2877000000000000000000000000EEBA")); + + verifyAttributes(decoder, binary( + "0509220886157E0863835020373564087B00018C0000018003160A6E28790A6E28790A6E287A0A6E287A0A6E287A0A6E287A0A6E287A0A6E287A0A6E287A0A6E287A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BD35")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java new file mode 100644 index 000000000..e330600e5 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TelemaxProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TelemaxProtocolDecoder decoder = new TelemaxProtocolDecoder(null); + + verifyNull(decoder, text( + "%067374070128")); + + verifyPositions(decoder, text( + "Y000007C6999999067374074649003C00A7018074666F60D66818051304321900000000C5")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java new file mode 100644 index 000000000..5fcbcbb57 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java @@ -0,0 +1,42 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TelicFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TelicFrameDecoder decoder = new TelicFrameDecoder(); + + verifyFrame( + binary("303032363230333339337c3232367c31307c303032303034303130"), + decoder.decode(null, null, binary("303032363230333339337c3232367c31307c30303230303430313000"))); + + verifyFrame( + binary("3030333032303333393332352c3139303331373038333035322c302c3138303331373130333132372c3235393932342c3434353133332c332c302c302c392c2c2c39332c31323231303134312c2c303031302c30302c34302c3234302c302c30343036"), + decoder.decode(null, null, binary("630000003030333032303333393332352c3139303331373038333035322c302c3138303331373130333132372c3235393932342c3434353133332c332c302c302c392c2c2c39332c31323231303134312c2c303031302c30302c34302c3234302c302c3034303600"))); + + verifyFrame( + binary("303032363239363231385343434530315f534343457c3232367c31307c30323637"), + decoder.decode(null, null, binary("303032363239363231385343434530315f534343457c3232367c31307c3032363700"))); + + verifyFrame( + binary("30303434323936323138544c4f43303236372c30302c3031313030393030303239363231382c3139303331373038333033362c3235353137382c3434353037322c332c302c38322c2c2c2c3136382c31343734313239362c2c30302c30302c302c323137"), + decoder.decode(null, null, binary("6400000030303434323936323138544c4f43303236372c30302c3031313030393030303239363231382c3139303331373038333033362c3235353137382c3434353037322c332c302c38322c2c2c2c3136382c31343734313239362c2c30302c30302c302c32313700"))); + + verifyNull( + decoder.decode(null, null, binary("00303032363937393238317c3233327c30337c30303230303430313000"))); + + verifyFrame( + binary("303032363937393238317c3233327c30337c303032303034303130"), + decoder.decode(null, null, binary("303032363937393238317c3233327c30337c30303230303430313000"))); + + verifyFrame( + binary("3030323039373932383139392c3231303231363038313930302c302c3231303231363038313835392c3031333839333338352c34363635383639352c332c302c302c382c2c2c3534312c36313239382c2c303030302c30302c302c3139362c302c30343037"), + decoder.decode(null, null, binary("650000003030323039373932383139392c3231303231363038313930302c302c3231303231363038313835392c3031333839333338352c34363635383639352c332c302c302c382c2c2c3534312c36313239382c2c303030302c30302c302c3139362c302c3034303700"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java new file mode 100644 index 000000000..b743cef96 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java @@ -0,0 +1,94 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TelicProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TelicProtocolDecoder decoder = new TelicProtocolDecoder(null); + + verifyNull(decoder, text( + "0026355565071347499|206|01|001002008")); + + verifyPosition(decoder, text( + "052028495198,160917073641,0,160917073642,43879,511958,3,24,223,17,,,-3,142379,,0010,00,64,205,0,0499")); + + verifyPosition(decoder, text( + "01302849516,160917073503,0,160917073504,43907,512006,3,11,160,14,,,-7,141811,,0010,00,64,206,0,0499")); + + verifyPosition(decoder, text( + "002135556507134749999,010817171138,0,010817171138,004560973,50667173,3,0,0,11,1,1,100,958071,20601,000000,00,4142,0000,0000,0208,10395,0")); + + verifyPosition(decoder, text( + "442045993198,290317131935,0,290317131935,269158,465748,3,26,183,,,,184,85316567,226,01,00,68,218")); + + verifyPosition(decoder, text( + "673091036017,290317131801,0,290317131801,262214,450536,3,40,199,8,,,154,19969553,,0011,00,59,240,0,0406")); + + verifyPosition(decoder, text( + "092020621198,280317084155,0,280317084156,259762,444356,3,42,278,9,,,89,56793311,,0110,00,67,0,,0400")); + + verifyPosition(decoder, text( + "502091227598,280317084149,0,280317084149,261756,444358,3,33,286,9,,,77,3143031,,0010,00,171,240,0,0406")); + + verifyPosition(decoder, text( + "232027997498,230317083900,0,230317083900,260105,444112,3,22,259,,,,111,61110817,226,01,00,255,218,00000000000000")); + + verifyPosition(decoder, text( + "072027997498,230317082635,0,230317082635,260332,444265,3,28,165,,,,124,61107582,226,01,00,255,219,00000000000000")); + + verifyNull(decoder, text( + "0026203393|226|10|002004010")); + + verifyPosition(decoder, text( + "003020339325,190317083052,0,180317103127,259924,445133,3,0,0,9,,,93,12210141,,0010,00,40,240,0,0406")); + + verifyNull(decoder, text( + "0026296218SCCE01_SCCE|226|10|0267")); + + verifyNull(decoder, text( + "1242022592TTUV0100,0201,351266000022592,170403114305,0115859,480323,3,30,5,9,3,4,650,250000000,26202,1001,0001,211,233,111,0")); + + verifyPosition(decoder, text( + "123002259213,170403114305,1234,170403114305,0115859,480323,3,30,5,9,3,4,650,250000000,26202,1001,0001,211,233,111,0,600")); + + verifyNull(decoder, text( + "0044296218TLOC0267,00,011009000296218,190317083036,255178,445072,3,0,82,,,,168,14741296,,00,00,0,217")); + + verifyPosition(decoder, text( + "003097061325,220616044200,0,220616044200,247169,593911,3,48,248,8,,,50,1024846,,1111,00,48,0,51,0406")); + + verifyPosition(decoder, text( + "003097061325,210216112630,0,210216001405,246985,594078,3,0,283,12,,,23,4418669,,0010,00,117,0,0,0108")); + + verifyPosition(decoder, text( + "592078222222,010100030200,0,240516133500,222222,222222,3,0,0,5,,,37,324,,1010,00,48,0,0,0406")); + + verifyPosition(decoder, text( + "002017297899,220216111100,0,220216111059,014306446,46626713,3,7,137,7,,,448,266643,,0000,00,0,206,0,0407")); + + verifyPosition(decoder, text( + "003097061325,210216112630,0,210216001405,246985,594078,3,0,283,12,,,23,4418669,,0010,00,117,0,0,0108")); + + verifyNull(decoder, text( + "0026970613|248|01|004006011")); + + verifyPosition(decoder, text( + "032097061399,210216112800,0,210216112759,246912,594076,3,47,291,10,,,46,4419290,,0010,00,100,0,0,0108")); + + verifyPosition(decoder, text( + "002017297899,190216202500,0,190216202459,014221890,46492170,3,0,0,6,,,1034,43841,,0000,00,0,209,0,0407")); + + verifyPosition(decoder, text( + "182043672999,010100001301,0,270613041652,166653,475341,3,0,355,6,2,1,231,8112432,23201,01,00,217,0,0,0,0,7"), + position("2013-06-27 04:16:52.000", true, 47.53410, 16.66530)); + + verifyPosition(decoder, text( + "182043672999,010100001301,0,270613041652,166653,475341,3,0,355,6,2,1,231,8112432,23201,01,00,217,0,0,0,0,7")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java new file mode 100644 index 000000000..f94cd9460 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java @@ -0,0 +1,134 @@ +package org.traccar.protocol; + +import org.junit.Ignore; +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class TeltonikaProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TeltonikaProtocolDecoder decoder = new TeltonikaProtocolDecoder(null, false); + + verifyNull(decoder, binary( + "000F313233343536373839303132333435")); + + verifyPositions(decoder, binary( + "000000000000004c08010000016818d500580009c28d9f1cb3757a00be00c60f0053000f06f0011503c80001011d00fc0007423799180053cdf80dce426f430f88190bb8560bb802f100005aa110002887e000010000ee8d")); + + verifyPositions(decoder, binary( + "00000000000000818e0100000166e368a510000f0d8b5b20961c35008d010308000000000014000900ef0000f00100500100150400c800004501001e00002500002900000a00b5000800b60007004230dc0018000000430fcb0044005f001103de001200e50013001200240000000000000001010000113141314a433534343452373235323336370100005e99")); + + verifyPositions(decoder, binary( + "000000000000009D10020000013feb55ff74000f0ea850209a690000AE00B90B00000000070A050001000002000003000004000120000200180000004601290200C700000000004C0000000001003E00000000000000000000015B198C7498000F0DBC502095872F00AE00B90B00000000070A050001000002000003000004000120000200180000004601290200C700000000004C0000000001003E000000000000000002000009A5")); + + verifyPositions(decoder, binary( + "000000000000009F100100000164D855401800D5E3B744EC11C762023B011A060000000007200A010000010500010600010D00010E00010F00011600011700011800011F001301010000010700000108000001090000010A0000010B0000010C000001100000011100000112000001130000011400000115000001190000011A0000011B0000011C0000011D0000011E000003010200000000010300000000010400000000000100000D3B")); + + verifyPositions(decoder, binary( + "000000000000008c08010000013feb55ff74000f0ea850209a690000940000120000001e09FD01FE210300040016014703f0001504c8000c0900730a00460b00501300464306d7440000b5000bb60007422e9f180000cd0386ce000107c700000000f10000601a46000001344800000bb84900000bb84a00000bb84c00000000024e0000000000000000cf00000000000000000100003fca")); + + verifyPositions(decoder, binary( + "00000000000000A708010000016269E7D9A8000A5A0F0A1CBF8F3300880046120000001C0801014F005100550F740073007801790103430000440000426F980B540000000056000045275700000047580000022659000000005D0000000068000003D07100007355870000000288000000008A000045270669584C5241534834336A30304731363538326B3600FFFFFF0000008155412055414430308230303039383236368330303000000000000100008396")); + + verifyPositions(decoder, binary( + "0000000000000035080100000161f37c50500020de5ba60ef11450000000000000000006040100b300b400ef000109002000014e0000000000000000010000be52")); + + verifyPositions(decoder, binary( + "000000000000008c08010000013feb55ff74000f0ea850209a690000940000120000001e09010002000300040016014703f0001504c8000c0900730a00460b00501300464306d7440000b5000bb60007422e9f180000cd0386ce000107c700000000f10000601a46000001344800000bb84900000bb84a00000bb84c00000000024e0000000000000000cf00000000000000000100003fca")); + + verifyPositions(decoder, binary( + "0000000000000401080e0000015d12cc211000fadaf627186742f5000d0048080006000a040100f001500515000342318a430fe344000003c700000000f1000068b61000001b05000000015d12c6683800fadaf72118673f82000000000000000007030100f00050040342318a430fe344000001f1000068b6000000015d12bd407800fadaf72118673f82000000000000000007030100f000500403423179430fe144000001f1000068b6000000015d12b414d000fadaf72118673f82000400900c0000fa120a0100f00050051502080007010552090e6f4bfa000542316a430fe14400000600006202b203c700002328f1000068b61000001b05000000015d12b3074800fadaf2821867436a000400890d00170011090100f00150011502081007010553090e6f4d054231fb430fe14400000603ae6202a003c700002328f1000068b61000001b05000000015d12b2ff7800fadaee89186747c60005009a0d001d0011090100f00150011502081b07010553090e6f4d05423125430fe144000006050862029e03c700002328f1000068b61000001b05000000015d12b2e42000fadae8cf18675e0a000300a60d00210011090101f00150011502082407030554090e6f4d0542310a430fe14400000606cf62029703c700002328f1000068b61000001b05000000015d12b2d48000fadae05818676a16000400930c00240011090100f00150011502082207010554090e6f4e05423738430fe144000006066a62029303c700002328f1000068b61000001b05000000015d12b2a1b800fadac33e18678e48000600940d00150011090101f00150051500081907030553090e6f4e054239cc430fe14400000607c662028603c700002328f1000000001000001b05000000015d12b29dd000fadac19d18678fc8000700820d00110011090100f00150051500081607030553090e6f4e054238c8430fe14400000606d962028503c700002328f1000000001000001b05000000015d12b299e800fadabfa9186790e3000700670d00110011090101f00150051500081407030553090e6f4e054231e5430fe144000006060a62028403c700002328f1000000001000001b05000000015d12b2960000fadabd4018679104000600510d00120011090101f00150051500081207030553090e6f4e054231ce430fe144000006057062028303c700002328f1000000001000001b05000000015d12b27aa800fadaa96518678b7c000600470d00120011090101f00150051500081807030551090e6f4e05423a70430fe144000006074462027c03c700002328f1000000001000001b05000000015d12b276c000fadaa73f18678ae60006003b0d000e0011090101f00150051500081607030551090e6f4e05423a5a430fe14400000606b762027b03c700002328f1000000001000001b05000e000007a4")); + + verifyPositions(decoder, binary( + "00000000000002cb08080000015a71ccbec00002fc9bfc1e53a1e00016004cf80005001914150216056500ee00ef00f0009d029e029f02a002a102a202a302a402a502a602020003000164d20003480100c6000ac500ce02c80000654ec700004ee8000000015a725aaac80002fc933c1e539d4000150049f80000001914150116056500ee00ef00f0009d029e029f02a002a102a202a302a402a502a602020003000164d200034800f4c6000ac500ce02c80000654ec700004ee8000000015a75a42c900002fc97d01e539640001d0008020000001914150016056500ee00ef00f0009d029e029f02a002a102a202a302a402a502a602020003000164d200034800f8c6000ac500ce02c80006ba5ac700004ee8000000015a75a440180002fc931c1e539b60001d00b9020001001914150016056500ee00ef00f0009d029e029f02a002a102a202a302a402a502a602020003000164d200034800fac6000ac500ce02c80006ba5ac700004ee8000000015a75a453a00002fc93601e539cc0001d015d0c0000001914150016056500ee00ef00f0009d029e029f02a002a102a202a302a402a502a602020003000164d200034800f9c6000ac500ce02c80006ba5ac700004ee8000000015a75a467280002fc93801e539cc0001d013c0c0000001914150016056500ee00ef00f0009d029e029f02a002a102a202a302a402a502a602020003000164d200034800f9c6000ac500ce02c80006ba5ac700004ee8000000015a75a47ab00002fc92cc1e539c80001d00b00c0000001914150016056500ee00ef00f0009d029e029f02a002a102a202a302a402a502a602020003000164d200034800f8c60004c5000a02c800003085c70006ba5a000000015a75a48e380002fc92ec1e539c40001d00410c0000001914150116056500ee00ef00f0009d029e029f02a002a102a202a302a402a502a602020003000164d200034800f8c6000ac500ce02c80000c83dc700004ee800080000e0b2")); + + verifyPositions(decoder, binary( + "0000000000000000080100000113fc208dff00209cca800f14f650006f00d60400040004030101150316030001460000015d000100000000")); // invalid length and checksum + + verifyPositions(decoder, binary( + "000000000000009f080400000159738f76b8012e13b796110ab27600d700000b00004e01000000014e000000000000000000000159738f6ee8012e13b796110ab27600d700000a00004e01000000014e01000b00791c179300000159738f6b00012e13b796110ab27600d700000a00004e01000000014e000000000000000000000159738f5f48012e13b796110ab27600d700000b00004e01000000014e01000b00791c17930400009671")); + + verifyPositions(decoder, false, binary( + "00000000000000710c0106000000694154244d5347534e443d342c225354474234302c50522c3335363630313036303236353035302c313630343232313531372c313630343232313531382c432c2b3032332e332c302c2b3032332e312c302c4445414354492c302c4445414354492c302c312c30220d0a010000d8db")); + + verifyPositions(decoder, false, binary( + "0000000000000055070450aa14320201f00150aa17f3031f42332a4c4193d68c008d00020901f00150aa1b6a031f423383f54193624f009d00000a01f00150aa1c230fc01a0000552b040164f400dd00f0010143100c0105000000050400006846")); + + verifyPositions(decoder, binary( + "000000000000003508010000014f8e016420002141bbaf0f4e96a7fffa0000120000000602010047030242669c92000002c7000000009100000000000100002df3")); + + verifyPositions(decoder, binary( + "00000000000000A7080400000113fc208dff000f14f650209cca80006f00d60400040004030101150316030001460000015d0000000113fc17610b000f14ffe0209cc580006e00c00500010004030101150316010001460000015e0000000113fc284945000f150f00209cd200009501080400000004030101150016030001460000015d0000000113fc267c5b000f150a50209cccc0009300680400000004030101150016030001460000015b00040000")); + + verifyPositions(decoder, binary( + "000000000000014708060000013e5a60a4cb003fa7b780fc424518004200000a000000090501010200b300b400f000034268a746011818000001c700000000000000013e5dc8ba28003fa7c080fc4246040001000005000000090501010200b300b400f001034268b44600ef18000001c700000000000000013e5dc90455003fa7b640fc424388003a0000070000f0090501010200b300b400f000034268dc4600f718000001c70000001d000000013e5dc9d368003fa7b800fc4244300049000004000000090501010200b300b400f001034267de46010718000001c700000000000000013e5dca311d003fa7b680fc4243cc00420000070000f0090501010200b300b400f0000342685346010b18000001c700000000000000013e5dcfafe9003fa7b600fc4242f0003d000008000000090501010200b300b400f0000342685246011918000001c700000000000600000275")); + + verifyPositions(decoder, binary( + "000000000000002c08010000013eff8d6f9800173295002111f400008100ae0b0000000401010003090016432980422f7200000100007a5d")); + + verifyPositions(decoder, binary( + "00000000000000c7070441bf9db00fff425adbd741ca6e1e009e1205070001030b160000601a02015e02000314006615000a160067010500000ce441bf9d920fff425adbb141ca6fc900a2b218070001030b160000601a02015e02000314006615000a160067010500000cc641bf9d740fff425adbee41ca739200b6c91e070001030b1f0000601a02015f02000314006615000a160066010500000ca841bf9cfc0fff425adba041ca70c100b93813070001030b1f0000601a02015f02000314002315000a160025010500000c3004000000")); + + verifyPositions(decoder, binary( + "000000000000003107024c61410b013f4231c2c141d0beb9003d000005006483ff4c6140eb013f4231c2c141d0beb9003d000005006483ff02000041df")); + + verifyPositions(decoder, binary( + "000000000000002b080100000140d4e3ec6e000cc661d01674a5e0fffc00000900000004020100f0000242322318000000000100007a04")); + + verifyPositions(decoder, false, binary( + "000000000000002d0c01060000002523464d323d3236323033323736313732313339362c32363230332c30372e30322e30350d0a0100009a2e")); + + verifyPositions(decoder, binary( + "00000000000000a608010000013f14a1d1ce000f0eb790209a778000ab010c0500000000000000000100003390")); + + verifyPositions(decoder, binary( + "000000000000004508010000015eb70a86d00024089d4d21dee3860137005f12005f000e06ef01f00150011503c800450108b5000bb6000642382718005fcd057ace19d3430f57440000000001000002bf")); + + verifyPositions(decoder, binary( + "000000000000004a08010000015ebc1da508002411926621f15246010b00b913005e000f06ef01f00150011505c800450108b5000bb6000642381b18005ecd0318ce19cd430f5844000001f1000061a900010000c8e1")); + + decoder.setExtended(true); + + verifyPositions(decoder, false, binary( + "0000000000000158080b0000015d4b4dc07a00d5dbd13eec04324e020e0000120000000000000000000000015d4b4cd5e800d5dbd13eec04324e020e0000120000000000000000000000015d4b4beb8800d5dbd13eec04324e020e0000130000000000000000000000015d4b4b012800d5dbd13eec04324e020e0000120000000000000000000000015d4b4a16c800d5dbd13eec04324e020f0000110000000000000000000000015d4b492c6800d5dbd13eec04324e020f0000110000000000000000000000015d4b48420800d5dbd13eec04324e020f0000120000000000000000000000015d4b4757a800d5dbd13eec04324e020f00000f0000000000000000000000015d4b466d4800d5dbd13eec04324e020f0000100000000000000000000000015d4b4582e800d5dbd13eec04324e020f0000110000000000000000000000015d4b44988800d5dbd13eec04324e020f0000110000000000000000000b0000ec10")); + + verifyPositions(decoder, false, binary( + "00000000000003b5080b0000015ab5642a8800d5db1769ec01d70a020a00e3040004000e0501010200030004006000060900100a00010b0000130000422f1318000302c700000000f7000000000001cb000000000000000000000000000000000000015ab5642e7000d5db178aec01d6d6020a0070040003000e0501010200030004006000060900100a00000b0000130000422f1318000302c700000000f7000000000001cb000000000000000000000000000000000000015ab567050000d5db1805ec01da3c02060101040006000e05010102000300040060000609000f0a00010b0000130000422f0c18000302c700000046f7000000000001cb000000000000000000000000000000000000015ab56708e800d5db1723ec01d9ec020600e5040006000e05010102000300040060000609000f0a00010b0000130000422f1018000502c700000003f7000000000001cb000000000000000000000000000000000000015ab5685cc000d5db20f7ec01d8fa02080033050007000e05010102000300040060000609000f0a00010b0000130000422f0a18000502c700000030f7000000000001cb000000000000000000000000000000000000015ab5693b6800d5db2367ec01d9430211011b040006000e05010102000300040060000609000f0a00010b0000130000422f0c18000302c700000027f7000000000001cb000000000000000000000000000000000000015ab569433800d5db1fb2ec01d9310211008b040006000e0501010200030004006000060900110a00000b0000130000422f1318000402c700000009f7000000000001cb000000000000000000000000000000000000015ab56a0e5800d5db22a2ec01da5502100041050007000e05010102000300040060000609000f0a00000b0000130000422f1118000602c70000000ef7000000000001cb000000000000000000000000000000000000015ab56a700000d5db2afcec01ddb2020a0012050008000e05010102000300040060000609000e0a00000b0000130000422f0918000502c700000026f7000000000001cb000000000000000000000000000000000000015ab56a73e800d5db2ad8ec01de65020a014e050008000e05010102000300040060000609000f0a00010b0000130000422f0818000702c700000002f7000000000001cb000000000000000000000000000000000000015ab56a7bb800d5db2971ec01e00e020a013f040008000e0501010200030004006000060900100a00020b0000130000422f0b18000802c700000004f7000000000001cb000000000000000000000000000000000b00007c5f")); + + } + + + @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 { + + TeltonikaProtocolDecoder decoder = new TeltonikaProtocolDecoder(null, true); + + verifyPositions(decoder, false, binary( + "0049cafe0122000f33353734353430373237313339373508010000015d3766f6a800003eef961ec6215e0063006d09003100070401000200f001c8000242381c18003201c7000000e10001")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java new file mode 100644 index 000000000..83ea961b4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class TeltonikaProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + TeltonikaProtocolEncoder encoder = new TeltonikaProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "setdigout 11"); + + verifyCommand(encoder, command, binary("00000000000000160C01050000000E7365746469676F75742031310D0A010000E258")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java new file mode 100644 index 000000000..a30d17502 --- /dev/null +++ b/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class ThinkRaceProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + ThinkRaceProtocolDecoder decoder = new ThinkRaceProtocolDecoder(null); + + verifyNull(decoder, binary( + "48415349483031343730303134382C8000100134363030303134363139363239343806FF")); + + verifyPosition(decoder, binary( + "48415349483031343730303134382C90001755701674D70155466406CBB813003D24A410F5000000770B4C")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java new file mode 100644 index 000000000..f1ba7c593 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java @@ -0,0 +1,51 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Tk102ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Tk102ProtocolDecoder decoder = new Tk102ProtocolDecoder(null); + + verifyNull(decoder, buffer( + "[\u00800000000000\u000821315452]")); + + verifyNull(decoder, buffer( + "[\u00f00000000000\u000821315452]")); + + verifyPosition(decoder, buffer( + "[\u00900100100001\u0036(ONE025857A2232.0729N11356.0030E000.02109110100000000)]")); + + verifyPosition(decoder, buffer( + "[\u00900100100001\u0036(ITV025857A2232.0729N11356.0030E000.02109110100000000)]")); + + verifyNull(decoder, buffer( + "[\u00210000000081\u0072(353327023367238,TK102-W998_01_V1.1.001_130219,255,001,255,001,0,100,100,0,internet,0000,0000,0,0,255,0,4,1,11,00)]")); + + verifyNull(decoder, buffer( + "[\u004c0000001323\u004e(GSM,0,0,07410001,20120101162600,404,010,9261,130,0,2353,130,35,9263,130,33,1)]")); + + verifyNull(decoder, buffer( + "[\u00250000000082\u001d(100100000000000600-30-65535)]")); + + verifyNull(decoder, buffer( + "[\u00230000000004\u0018(062100000000000600-0-0)]")); + + verifyPosition(decoder, buffer( + "[\u003d0000000083\u0036(ITV013939A4913.8317N02824.9241E000.90018031310010000)]")); + + verifyPosition(decoder, buffer( + "[\u003d0000000036\u0036(ITV012209A4913.8281N02824.9258E000.32018031310010000)]")); + + verifyPosition(decoder, buffer( + "[\u003b0000000010\u0036(ONE200834A5952.8114N01046.0832E003.93212071305010000)]")); + + verifyPosition(decoder, buffer( + "[\u00930000000000\u0046(ITV153047A1534.0805N03233.0888E000.00029041500000400&Wsz-wl001&B0000)]")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java new file mode 100644 index 000000000..1f42e588f --- /dev/null +++ b/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java @@ -0,0 +1,44 @@ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Tk103FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Tk103FrameDecoder decoder = new Tk103FrameDecoder(); + + verifyFrame( + binary("283836343735353535353535353535352C445733422C3133313131372C412C353536322E30323837304E2C30313334382E3038313934452C312E3539372C3232333730372C3239312E36352C2D302E31302C3429"), + decoder.decode(null, null, binary("283836343735353535353535353535352C445733422C3133313131372C412C353536322E30323837304E2C30313334382E3038313934452C312E3539372C3232333730372C3239312E36352C2D302E31302C3429283836343735353535353535353535352C5A4332302C3133313131372C3232333730362C362C3339342C36353533352C32353529"))); + + ByteBuf buf = binary("283836343535353535353535353535352C445735422C3231302C362C353939352C34373730312C352C33303A45453A43433A45373A38363A44442A2D35392A31312C34433A36303A43433A45413A42423A45452A2D36382A312C34323A41413A44453A45413A42423A30302A2D36392A312C33323A43443A42423A43333A34463A43432A2D38362A332C31303A30303A34333A42413A32323A31352A2D38382A312C3135313131372C31363337323229283836343735353535353535353535352C5A4332302C3133313131372C3232333730362C362C3339342C36353533352C32353529"); + + verifyFrame( + binary("283836343535353535353535353535352C445735422C3231302C362C353939352C34373730312C352C33303A45453A43433A45373A38363A44442A2D35392A31312C34433A36303A43433A45413A42423A45452A2D36382A312C34323A41413A44453A45413A42423A30302A2D36392A312C33323A43443A42423A43333A34463A43432A2D38362A332C31303A30303A34333A42413A32323A31352A2D38382A312C3135313131372C31363337323229"), + decoder.decode(null, null, buf)); + + verifyFrame( + binary("283836343735353535353535353535352C5A4332302C3133313131372C3232333730362C362C3339342C36353533352C32353529"), + decoder.decode(null, null, buf)); + + verifyFrame( + binary("283836343735353535353535353535352C445733422C3133313131372C412C353536322E30323837304E2C30313334382E3038313934452C312E3539372C3232333730372C3239312E36352C2D302E31302C3429"), + decoder.decode(null, null, binary("676172626167652540232A5E242D2B3C3E3F2429292924242D2D283836343735353535353535353535352C445733422C3133313131372C412C353536322E30323837304E2C30313334382E3038313934452C312E3539372C3232333730372C3239312E36352C2D302E31302C3429283836343735353535353535353535352C5A4332302C3133313131372C3232333730362C362C3339342C36353533352C32353529"))); + + verifyNull(decoder.decode(null, null, binary("67"))); + + verifyNull(decoder.decode(null, null, binary("676172626167652540232a5e242d2b3c3e3f24"))); + + verifyFrame( + binary("2838363437353535353535352C5A4330332C3139313131372C3233343432312C24294E6F746963653A0D0A446576696365732073657269616C206E756D6265723A200D0A3538303535353535353535292E0D0A536F6674776172652076657273696F6E3A0D0A56322E3030302C323031362F30382F32332031313A3137292429"), + decoder.decode(null, null, binary("610D0A676172626167652540232A5E242D2B3C3E3F2429292924242D2D2838363437353535353535352C5A4330332C3139313131372C3233343432312C24294E6F746963653A0D0A446576696365732073657269616C206E756D6265723A200D0A3538303535353535353535292E0D0A536F6674776172652076657273696F6E3A0D0A56322E3030302C323031362F30382F32332031313A3137292429283836343735353535353535353535352C5A4332302C3133313131372C3232333730362C362C3339342C36353533352C32353529"))); + + verifyNull(decoder.decode(null, null, binary("610D0A676172626167652540232A5E242D2B3C3E3F2429292924242D2D2838363437353535353535352C5A4330332C3139313131372C3233343432312C24294E6F746963653A0D0A446576696365732073657269616C206E756D6265723A200D0A3538303535353535353535292E0D0A536F6674776172652076657273696F6E3A0D0A56322E3030302C323031362F30382F32332031313A31372929283836343735353535353535353535352C5A4332302C3133313131372C3232333730362C362C3339342C36353533352C32353529"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java new file mode 100644 index 000000000..db636893b --- /dev/null +++ b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java @@ -0,0 +1,202 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +public class Tk103ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Tk103ProtocolDecoder decoder = new Tk103ProtocolDecoder(null); + + verifyPosition(decoder, text( + "(094625928000BR00190213A1156.0431S07705.6145W000.000023521.40000000007L00000314T113)")); + + verifyPosition(decoder, text( + "(019358704260BR00180725A2300.0957N07235.2748E032.412092187.58001100166L000D9779)")); + + verifyPosition(decoder, text( + "(358511020000026,DW5B,310,6,29876,30393,0,041217,102211)")); + + verifyPosition(decoder, text( + "(007611121184BR00170816A2401.5217N07447.0788E000.0221352232.340000004FL0030F14F)")); + + verifyNull(decoder, text( + "(027044702512BP00027044702512HSO01A4)")); + + verifyPosition(decoder, text( + "(864768011069660,ZC11,250517,V,0000.0000N,00000.0000E,000.0,114725,000.0,0.00,11)")); + + verifyPosition(decoder, text( + "(864768011069660,ZC17,250517,A,3211.7118N,03452.8086E,0.68,115525,208.19,64.50,9)")); + + verifyNull(decoder, text( + "(357593060760397BP02,G,2,170304A6015.7466N01101.8460E001.609445591.048,7)")); + + verifyPosition(decoder, text( + "(325031693849BR00170228A5750.8012N02700.7476E000.2154529000.0000000200L00000000,170228,194530)")); + + verifyAttribute(decoder, text( + "(087073803649BR00170221A6142.0334N02712.2197E000.3203149000.00,00000000L00000000)"), + Position.KEY_FUEL_LEVEL, 0); + + verifyPosition(decoder, text( + "(864768010869060,DW30,050117,A,5135.82713N,00001.17918E,0.089,154745,000.0,43.40,12)")); + + verifyNotNull(decoder, text( + "(087073104337BZ00,740,000,3bf7,0425,3bf7,0bf5,3bf7,09e7,3bf7,cbad,3bf7,0dcf,3bf7,c7b2,01000000)")); + + verifyNull(decoder, text( + "(087073005534BP00HSO)")); + + verifyNull(decoder, text( + "(027028258309BQ86,0,05550c21b10d1d0f431008bd114c0ea5078400010007a100423932,161117005322,01000001)")); + + verifyNull(decoder, text( + "(027028258309BQ86,0,05470c0eb20d040f4410022911360e92077e00010007a1004237c7,161117005232,01000001)")); + + verifyPosition(decoder, text( + "(01602009983BR00160830V1855.7022S4817.8731W000.0002729000.0010000000L00000000)")); + + verifyPosition(decoder, text( + "(088046338039BR00160727A3354.7768N03540.7258E000.0140832068.4700000000L00BEB0D4+017.7)")); + + verifyPosition(decoder, text( + "(088046338039BP05000088046338039160727A3354.7768N03540.7258E000.0140309065.1000000000L00BEB0D4+017.3)")); + + verifyAttributes(decoder, text( + "(013632651491,ZC20,180716,144222,6,392,65535,255)")); + + verifyAttributes(decoder, text( + "(087072009461BR00000007V0000.0000N00000.0000E000.00014039900000000L00000000)")); + + verifyPosition(decoder, text( + "(013612345678BO012061830A2934.0133N10627.2544E040.0080331309.6200000000L000770AD)")); + + verifyNotNull(decoder, text( + "(088047194605BZ00,510,010,36e6,932c,43,36e6,766b,36,36e6,7668,32)")); + + verifyAttributes(decoder, text( + "(013632651491,ZC20,040613,040137,6,421,112,0)")); + + verifyAttributes(decoder, text( + "(864768010159785,ZC20,291015,030413,3,362,65535,255)")); + + verifyPosition(decoder, text( + "(088047365460BR00151024A2555.3531S02855.3329E004.7055148276.1701000000L00009AA3)"), + position("2015-10-24 05:51:48.000", true, -25.92255, 28.92222)); + + verifyPosition(decoder, text( + "(088047365460BP05354188047365460150929A3258.1754S02755.4323E009.4193927301.9000000000L00000000)")); + + verifyPosition(decoder, text( + "(088048003342BP05354188048003342150917A1352.9801N10030.9050E000.0103115265.5600010000L000003F9)")); + + verifyPosition(decoder, text( + "(088048003342BR00150917A1352.9801N10030.9050E000.0103224000.0000010000L000003F9)")); + + verifyPosition(decoder, text( + "(088048003342BR00150807A1352.9871N10030.9084E000.0110718000.0001010000L00000000)")); + + verifyNull(decoder, text( + "(090411121854BP0000001234567890HSO)")); + + verifyPosition(decoder, text( + "(01029131573BR00150428A3801.6382N02351.0159E000.0080729278.7800000000LEF9ECB9C)")); + + verifyPosition(decoder, text( + "(035988863964BP05000035988863964110524A4241.7977N02318.7561E000.0123536356.5100000000L000946BB)")); + + verifyPosition(decoder, text( + "(013632782450BP05000013632782450120803V0000.0000N00000.0000E000.0174654000.0000000000L00000000)")); + + verifyPosition(decoder, text( + "(013666666666BP05000013666666666110925A1234.5678N01234.5678W000.002033490.00000000000L000024DE)")); + + verifyPosition(decoder, text( + "(013666666666BO012110925A1234.5678N01234.5678W000.0025948118.7200000000L000024DE)")); + + verifyPosition(decoder, text( + "(088045133878BR00130228A5124.5526N00117.7152W000.0233614352.2200000000L01B0CF1C)")); + + verifyPosition(decoder, text( + "(008600410203BP05000008600410203130721A4152.5790N01239.2770E000.0145238173.870100000AL0000000)")); + + verifyPosition(decoder, text( + "(013012345678BR00130515A4843.9703N01907.6211E000.019232800000000000000L00009239)")); + + verifyPosition(decoder, text( + "(012345678901BP05000012345678901130520A3439.9629S05826.3504W000.1175622323.8700000000L000450AC)")); + + verifyPosition(decoder, text( + "(012345678901BR00130520A3439.9629S05826.3504W000.1175622323.8700000000L000450AC)")); + + verifyPosition(decoder, text( + "(352606090042050,BP05,240414,V,0000.0000N,00000.0000E,000.0,193133,000.0)")); + + verifyPosition(decoder, text( + "(352606090042050,BP05,240414,A,4527.3513N,00909.9758E,4.80,112825,155.49)"), + position("2014-04-24 11:28:25.000", true, 45.45586, 9.16626)); + + verifyPosition(decoder, text( + "(013632782450,BP05,101201,A,2234.0297N,11405.9101E,000.0,040137,178.48,00000000,L00000000)")); + + verifyPosition(decoder, text( + "(864768010009188,BP05,271114,V,4012.19376N,00824.05638E,000.0,154436,000.0)")); + + verifyPosition(decoder, text( + "(013632651491,BP05,040613,A,2234.0297N,11405.9101E,000.0,040137,178.48)")); + + verifyPosition(decoder, text( + "(013632651491,ZC07,040613,A,2234.0297N,11405.9101E,000.0,040137,178.48)")); + + verifyPosition(decoder, text( + "(013632651491,ZC11,040613,A,2234.0297N,11405.9101E,000.0,040137,178.48)")); + + verifyPosition(decoder, text( + "(013632651491,ZC12,040613,A,2234.0297N,11405.9101E,000.0,040137,178.48)")); + + verifyPosition(decoder, text( + "(013632651491,ZC13,040613,A,2234.0297N,11405.9101E,000.0,040137,178.48)")); + + verifyPosition(decoder, text( + "(013632651491,ZC17,040613,A,2234.0297N,11405.9101E,000.0,040137,178.48)")); + + verifyPosition(decoder, text( + "(094050000111BP05000094050000111150808A3804.2418N04616.7468E000.0201447133.3501000011L0028019DT000)")); + + verifyPosition(decoder, text( + "(864555555555555,DW3B,131117,A,5544.02870N,01315.08194E,1.597,223707,291.65,-0.10,4)")); + + verifyPosition(decoder, text( + "(864555555555555,DW3B,131117,A,5544.02870N,01315.08194E,1.597,223707,291.65,0.10,8)")); + + verifyPosition(decoder, text( + "(013632651491,ZC07,040613,A,2234.0297N,11405.9101E,000.0,040137,178.48)")); + + verifyAttributes(decoder, text( + "(013632651491,ZC20,040613,040137,6,42,112,0)")); + + verifyNotNull(decoder, text( + "(864555555555555,DW51,200,1,3215,43370,2,58:F3:BB:3B:AA:82*-65*1,1C:6A:BB:AA:81:95*-78*1,151117,154419)")); + + verifyNotNull(decoder, text( + "(864555555555555,DW5B,210,6,5995,47701,5,30:EE:CC:E7:86:DD*-59*11,4C:60:CC:EA:BB:EE*-68*1,42:AA:DE:EA:BB:00*-69*1,32:CD:BB:C3:4F:CC*-86*3,10:00:43:BA:22:15*-88*1,151117,163722)")); + + verifyNotNull(decoder, text( + "(013632651491,DW50,460,0,0,6,2,aa:bb:cc:dd:ee:ff*-8*0,aa:bb:cc:dd:ee:ff*-8*0,040613,040137)")); + + verifyNotNull(decoder, text( + "(013632651491,DW50,460,0,0,6,0,040613,040137)")); + + verifyNotNull(decoder, text( + "(864555555555555,ZC03,191117,234207,$Notice: Device version: 1.0$)")); + + verifyNotNull(decoder, text( + "(864555555555555,ZC03,191117,234207,$1 .Sensor sensitivity: 1\r\n2 .Alert status: Off\r\n3 .Check interval is set to 240 minute(s).\r\n4 .Checkgsm interval is set to 60 minute(s).\r\n5 .SOS SMS Alert: On\r\n6 .SOS Call Alert: On\r\n7 . Power: 95%$)")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java new file mode 100644 index 000000000..34b2acf86 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java @@ -0,0 +1,282 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class Tk103ProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncodeOutputControl() { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_OUTPUT_CONTROL); + command.set(Command.KEY_DATA, "1"); + + assertEquals("(123456789012345AV001)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeEngineStop() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ENGINE_STOP); + + assertEquals("(123456789012345AV010)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodePositionSingle() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_SINGLE); + + assertEquals("(123456789012345AP00)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodePositionPeriodic() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_PERIODIC); + command.set(Command.KEY_FREQUENCY, 60); + + assertEquals("(123456789012345AR00003C0000)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodePositionStop() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_STOP); + + assertEquals("(123456789012345AR0000000000)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeGetVersion() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_GET_VERSION); + + assertEquals("(123456789012345AP07)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeRebootDevice() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_REBOOT_DEVICE); + + assertEquals("(123456789012345AT00)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeSetOdometer() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SET_ODOMETER); + + assertEquals("(123456789012345AX01)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodePositionSingleAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_SINGLE); + + assertEquals("[begin]sms2,*getposl*,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodePositionPeriodicAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_PERIODIC); + + assertEquals("[begin]sms2,*routetrack*99*,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodePositionStopAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_STOP); + + assertEquals("[begin]sms2,*routetrackoff*,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeGetVersionAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_GET_VERSION); + + assertEquals("[begin]sms2,*about*,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeRebootDeviceAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_REBOOT_DEVICE); + + assertEquals("[begin]sms2,88888888,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeIdentificationAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_IDENTIFICATION); + + assertEquals("[begin]sms2,999999,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeSosOnAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ALARM_SOS); + command.set(Command.KEY_ENABLE, true); + + assertEquals("[begin]sms2,*soson*,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeSosOffAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_ALARM_SOS); + command.set(Command.KEY_ENABLE, false); + + assertEquals("[begin]sms2,*sosoff*,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeCustom() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "AA00"); + + assertEquals("(123456789012345AA00)", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeCustomAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "any text is ok"); + + assertEquals("[begin]sms2,any text is ok,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeSetConnectionAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SET_CONNECTION); + command.set(Command.KEY_SERVER, "1.2.3.4"); + command.set(Command.KEY_PORT, "5555"); + + assertEquals("[begin]sms2,*setip*1*2*3*4*5555*,[end]", encoder.encodeCommand(command)); + + } + + @Test + public void testEncodeSosNumberAlternative() throws Exception { + + Tk103ProtocolEncoder encoder = new Tk103ProtocolEncoder(true); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SOS_NUMBER); + command.set(Command.KEY_INDEX, "0"); + command.set(Command.KEY_PHONE, "+55555555555"); + command.set(Command.KEY_DEVICE_PASSWORD, "232323"); + + assertEquals("[begin]sms2,*master*232323*+55555555555*,[end]", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java new file mode 100644 index 000000000..83caae208 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java @@ -0,0 +1,64 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Tlt2hProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Tlt2hProtocolDecoder decoder = new Tlt2hProtocolDecoder(null); + + verifyPositions(decoder, text( + "#867962040161955#MT600#0000#0#0#137#41#0#AUTO#1\r\n" + + "#00019023402$GPRMC,084702.00,A,3228.6772,S,11545.9684,E,,159.80,251018,,,A*56\r\n")); + + verifyPositions(decoder, text( + "#868323028789359#MT600#0000#AUTOLOW#1\r\n", + "#07d8cd5198$GPRMC,164934.00,A,1814.4854,N,09926.0566,E,0.03,,240417,,,A*4A\r\n")); + + verifyNull(decoder, text( + "#861075026000000#\r\n", + "#0000#AUTO#1\r\n", + "#002c4968045$GPRMC,001556.00,A,3542.1569,N,13938.9814,E,7.38,185.71,160417,,,A*55\r\n")); + + verifyPositions(decoder, text( + "#863835026938048#MT500#0000#AUTO#1\r\n", + "#67904917c0e$GPRMC,173926.00,A,4247.8476,N,08342.6996,W,0.03,,160417,,,A*59\r\n")); + + verifyPositions(decoder, text( + "#357671030108689##0000#AUTO#1\r\n", + "#13AE2F8F$GPRMC,211452.000,A,0017.378794,S,03603.441981,E,0.000,0,060216,,,A*68\r\n")); + + verifyPositions(decoder, text( + "#357671030946351#V500#0000#AUTO#1\r\n", + "#$GPRMC,223835.000,A,0615.3545,S,10708.5779,E,14.62,97.41,070313,,,D*70\r\n"), + position("2013-03-07 22:38:35.000", true, -6.25591, 107.14297)); + + verifyPositions(decoder, text( + "\r\n#357671030946351#V500#0000#AUTO#1\r\n", + "#$GPRMC,223835.000,A,0615.3545,S,10708.5779,E,14.62,97.41,070313,,,D*70\r\n")); + + verifyPositions(decoder, text( + "#357671030938911#V500#0000#AUTOSTOP#1\r\n", + "#00b34d3c$GPRMC,140026.000,A,2623.6452,S,02828.8990,E,0.00,65.44,130213,,,A*4B\r\n")); + + verifyPositions(decoder, text( + "#123456789000001#V3338#0000#SMS#3\r\n", + "#25ee0dff$GPRMC,083945.180,A,2233.4249,N,11406.0046,E,0.00,315.00,251207,,,A*6E\r\n", + "#25ee0dff$GPRMC,083950.180,A,2233.4249,N,11406.0046,E,0.00,315.00,251207,,,A*6E\r\n", + "#25ee0dff$GPRMC,083955.180,A,2233.4249,N,11406.0046,E,0.00,315.00,251207,,,A*6E")); + + verifyPositions(decoder, text( + "#353686009063310#353686009063310#0000#AUTO#2\r\n", + "#239757a9$GPRMC,150252.001,A,2326.6856,S,4631.8154,W,,,260513,,,A*52\r\n", + "#239757a9$GPRMC,150322.001,A,2326.6854,S,4631.8157,W,,,260513,,,A*55")); + + verifyPositions(decoder, text( + "#357671031289215#V600#0000#AUTOLOW#1\r\n", + "#00735e1c$GPRMC,115647.000,A,5553.6524,N,02632.3128,E,0.00,0.0,130614,0.0,W,A*28")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java new file mode 100644 index 000000000..0aaf567e8 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TlvProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TlvProtocolDecoder decoder = new TlvProtocolDecoder(null); + + verifyNull(decoder, binary( + "30430f383630323437303330303934333931ff10393233323132323030303834353433340f533636385f415f56312e30315f454eff1130303a30433a45373a30303a30303a30300132")); + + verifyNull(decoder, binary( + "30410f383630323437303330303934333931")); + + verifyNull(decoder, binary( + "30420f3836303234373033303039343339310131")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java new file mode 100644 index 000000000..4f7be1b28 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TmgFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TmgFrameDecoder decoder = new TmgFrameDecoder(); + + verifyFrame( + binary("24696f662c3836343530323033373939393630342c323238323133323031372c383132343238302c302c3239393133363231362e2d3438323235383537362ca52c313337393234353339382e3831383733343637362c142c2d36393936393937332e302c313135333435343433372e2d313938363833343039322c3439323039373739392c32302c302c2d3332302c302c4c4c4c4c2c4e4e544e2c48482c302e31372c332e30312c3330313131363030312c302c56455230302e3161"), + decoder.decode(null, null, binary("111538360b383634353032303337393939363034eb0b1c8d00ffff23000000000000000000000000000000001c9401008c320c00188901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000001d940100c8950100bd0024696f662c3836343530323033373939393630342c323238323133323031372c383132343238302c302c3239393133363231362e2d3438323235383537362ca52c313337393234353339382e3831383733343637362c142c2d36393936393937332e302c313135333435343433372e2d313938363833343039322c3439323039373739392c32302c302c2d3332302c302c4c4c4c4c2c4e4e544e2c48482c302e31372c332e30312c3330313131363030312c302c56455230302e31610a000195010090960100bd0024746d702c3836343530323033373939393630342c323238323133323031372c383132343238302c302c3239393133363231362e2d3438323235383537362ca52c313337393234353339382e3831383733343637362c142c2d36393936393937332e302c313135333435343433372e2d313938363833343039322c3439323039373739392c32302c302c2d3237372c302c4c4c4c4c2c4e4e544e2c48482c302e31372c332e30312c3330313131363030312c302c56455230302e31610a00c9950100289701008b002462616b2c3836343530323033373939393630342c32313131323031372c3132303230312c312c323832362e353938312c4e2c30373731382e363436352c452c3030302e302c3239382e35322c35323834372c32322c332c2d3233392c302c4c4c4c4c2c4e4e544e2c48482c302e32342c332e30332c3330313131363030312c302c56455230302e31610a00000091960100c09701008b002462616b2c3836343530323033373939393630342c32313131323031372c3132303231322c312c323832362e353938312c4e2c30373731382e363437322c452c3030302e302c3037392e34322c35323834372c32332c332c2d3230352c302c4c4c4c4c2c4e4e544e2c48482c302e31352c332e30332c3330313131363030312c302c56455230302e31610a00000029970100589801008a002462616b2c3836343530323033373939393630342c32313131323031372c3132303232322c312c323832362e353938302c4e2c30373731382e363438352c452c3030302e302c3037372e332c35323834372c32332c332c2d3137342c302c4c4c4c4c2c4e4e544e2c48482c302e31382c332e30332c3330313131363030312c302c56455230302e31610a00000000c1970100f09801008a002462616b2c3836343530323033373939393630342c32313131323031372c3132303233312c312c323832362e353936342c4e2c30373731382e363437312c452c3030302e302c3133312e352c35323834372c32322c342c2d3134362c302c4c4c4c4c2c4e4e544e2c48482c302e31392c332e30332c3330313131363030312c302c56455230302e31610a0000000059980100889901008b002462616b2c3836343530323033373939393630342c32313131323031372c3132303234332c312c323832362e353935382c4e2c30373731382e363436382c452c3030302e302c3133392e36362c35323834372c32322c342c2d3132312c302c4c4c4c4c2c4e4e544e2c48482c302e31322c332e30332c3330313131363030312c302c56455230302e31610a000000f1980100209a01008a002462616b2c3836343530323033373939393630342c32313131323031372c3132303235332c312c323832362e353934392c4e2c30373731382e363436"))); + + verifyFrame( + binary("246c6f632c3836343530323033303335323734342c32393131323031372c3038333034392c312c323533342e363733312c4e2c30383733342e363735352c452c3033382e302c3037372e31392c35343234312c362c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31342c332e31312c3330313131363030312c332c56455230302e3161"), + decoder.decode(null, null, binary("246c6f632c3836343530323033303335323734342c32393131323031372c3038333034392c312c323533342e363733312c4e2c30383733342e363735352c452c3033382e302c3037372e31392c35343234312c362c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31342c332e31312c3330313131363030312c332c56455230302e31610a246c6f632c3836343530323033303335323734342c32393131323031372c3038333035392c312c323533342e363634322c4e2c30383733342e373333352c452c3032392e302c3132322e37302c35343234312c362c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31342c332e31312c3330313131363030312c342c56455230302e31610a246c6f632c3836343530323033303335323734342c32393131323031372c3038333130392c312c323533342e363531362c4e2c30383733342e373938312c452c3034342e302c3039342e39382c36303631322c31312c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31372c332e31302c3330313131363030312c342c56455230302e31610a246c6f632c3836343530323033303335323734342c32393131323031372c3038333131392c312c323533342e363432312c4e2c30383733342e383639312c452c3033352e302c3130312e37332c36303631322c31322c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31342c332e31312c3330313131363030312c342c56455230302e31610a246c6f632c3836343530323033303335323734342c32393131323031372c3038333132392c312c323533342e363335352c4e2c30383733342e393135322c452c3032302e302c3131312e31322c36303631322c31322c31312c3130302c302c48484c4c2c4e4e4e4e2c48482c302e31362c332e31312c3330313131363030312c342c56455230302e31610a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java new file mode 100644 index 000000000..5df2378d9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java @@ -0,0 +1,54 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TmgProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TmgProtocolDecoder decoder = new TmgProtocolDecoder(null); + + verifyPosition(decoder, text( + "$loc,869309013800417,08032014,094459,1,2826.1956,N,07659.7690,E,0.0,2.5,4441,31,6,95,1,LLLL,NNTN,HH,0.15,0.26,HR38AU1389,0,SW0.1a")); + + verifyPosition(decoder, text( + "$bak,864502037999604,21112017,120243,1,2826.5958,N,07718.6468,E,000.0,139.66,52847,22,4,-174,0,LLLL,NNTN,HH,0.12,3.03,301116001,0,VER00.1a")); + + verifyNull(decoder, text( + "$iof,864502037999604,2282132017,8124280,0,299136216.-482258576,¥,1379245398.818734676,,-69969973.0,1153454437.-1986834092,492097799,20,0,-320,0,LLLL,NNTN,HH,0.17,3.01,301116001,0,VER00.1a")); + + verifyPosition(decoder, text( + "$nor,L,868325023006341,14022017,103947,1,2836.6542,N,07706.2504,E,0.0,0.0,0.0,0.0,0,22,VODAFONE - DELH,15,49B7,1,2.57,13.2,00000010,00000000,0111,00.0,00.0,0.0,SW10.12,NA,#")); + + verifyPosition(decoder, text( + "$rid,L,868325023006341,14022017,103706,1,2836.6542,N,07706.2504,E,0.0,0.0,0.0,0.0,0,22,VODAFONE - DELH,15,49B7,1,2.57,13.2,00000011,00000000,0111,00.0,00.0,0.0,SW10.12,0004909463,#")); + + verifyPosition(decoder, text( + "$ion,H,868324023777431,27012017,101057,4,2830.2952,N,07705.2532,E,0.0,202.38,225.9,1.22,8,20,N.A,0,N.A,1,4.09,00.0,00000111,00000000,1101,00.0-00.0,00.0-0.0,4.42,01.02,#")); + + verifyPosition(decoder, text( + "$iof,H,868324023777431,27012017,101111,4,2830.2952,N,07705.2532,E,0.0,202.38,225.9,0.87,11,21,N.A,25,N.A,0,4.09,00.0,00000111,00000000,1110,00.0-00.0,00.0-0.0,4.42,01.02,#")); + + verifyPosition(decoder, text( + "$rmv,L,868324023777431,27012017,101141,4,2830.2952,N,07705.2532,E,0.0,202.38,225.9,0.86,12,21,VODAFONE - DELH,24,3220,0,4.11,00.0,00000111,00000000,1110,00.0-00.0,00.0-0.0,4.42,01.02,#")); + + verifyPosition(decoder, text( + "$rnc,H,868324023777431,27012017,101013,4,2830.2923,N,07705.2551,E,0.0,9.65,226.0,0.88,12,21,VODAFONE - DELH,28,3220,0,4.14,07.4,00000111,00000000,1111,00.0-00.0,00.0-0.0,4.42,01.02,#")); + + verifyPosition(decoder, text( + "$ebl,H,868324023777431,27012017,101046,4,2830.2923,N,07705.2551,E,0.0,9.65,226.0,0.97,11,21,VODAFONE - DELH,25,3220,0,4.11,00.0,00000111,00000000,1110,00.0-00.0,00.0-0.0,4.42,01.02,#")); + + verifyPosition(decoder, text( + "$nor,L,868324023777431,17012017,001023,4,2830.2977,N,07705.2478,E,0.0,207.07,229.2,0.97,11,22,IDEA CELLULAR L,18,DCDE,0,4.09,12.9,00000111,00000000,1111,00.0-00.0,00.0-0.0,3.59,01.02,#")); + + verifyPosition(decoder, text( + "$nor,L,868324023777431,17012017,001523,4,2830.2939,N,07705.2527,E,0.0,50.96,236.5,1.05,11,21,IDEA CELLULAR L,18,DCDE,0,4.09,12.8,00000111,00000000,1111,00.0-00.0,00.0-0.0,3.59,01.02,#")); + + verifyPosition(decoder, text( + "$nor,L,869309999985699,24062015,094459,4,2826.1956,N,07659.7690,E,67.5,2.5,167,0.82,15,22,airtel,31,4441,1,4.1,12.7,00000011,00000011,1111,0.0,0.0,21.3,SW00.01,#")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java new file mode 100644 index 000000000..666a48bfa --- /dev/null +++ b/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TopflytechProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TopflytechProtocolDecoder decoder = new TopflytechProtocolDecoder(null); + + verifyPosition(decoder, text( + "(880316890094910BP00XG00b600000000L00074b54S00000000R0C0F0014000100f0130531152205A0706.1395S11024.0965E000.0251.25")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java new file mode 100644 index 000000000..8fb5f8d54 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java @@ -0,0 +1,35 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TotemFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TotemFrameDecoder decoder = new TotemFrameDecoder(); + + verifyFrame( + binary("24243030323542423836323031303033373239343836313345"), + decoder.decode(null, null, binary("24243030323542423836323031303033373239343836313345"))); + + verifyFrame( + binary("24243030363545363836313137323033353932363639357c3137303931323135333235372c2d37392e3337333835332c34332e3736353631392c302c302c7c3441"), + decoder.decode(null, null, binary("24243030363545363836313137323033353932363639357c3137303931323135333235372c2d37392e3337333835332c34332e3736353631392c302c302c7c3441"))); + + verifyFrame( + binary("24243031303841413836343234343032363036333433377c3141303030303030313430313031303130313031343131313030303032374241304535373030333130303030303030302e3030303030303030303030302e303030304e30303030302e3030303045303438313536"), + decoder.decode(null, null, binary("24243031303841413836343234343032363036333433377c3141303030303030313430313031303130313031343131313030303032374241304535373030333130303030303030302e3030303030303030303030302e303030304e30303030302e3030303045303438313536"))); + + verifyFrame( + binary("242442393335363839353033373537383531387c4141244750524d432c3036313730382e3030302c412c333734302e323033332c4e2c30323132382e383132312c452c33382e38352c3237322e33362c3132313131332c2c2c412a35327c30322e337c30312e337c30312e397c3030303030303030303030307c32303133313131323036313730387c31343034313430327c30303030303030307c30303245323137317c303030307c302e323137327c383930327c34463945"), + decoder.decode(null, null, binary("242442393335363839353033373537383531387c4141244750524d432c3036313730382e3030302c412c333734302e323033332c4e2c30323132382e383132312c452c33382e38352c3237322e33362c3132313131332c2c2c412a35327c30322e337c30312e337c30312e397c3030303030303030303030307c32303133313131323036313730387c31343034313430327c30303030303030307c30303245323137317c303030307c302e323137327c383930327c344639450d0a"))); + + verifyFrame( + binary("242442393335363839353033373537383531387c4141244750524d432c3036313730382e3030302c412c333734302e323033332c4e2c30323132382e383132312c452c33382e38352c3237322e33362c3132313131332c2c2c412a35327c30322e337c30312e337c30312e397c3030303030303030303030307c32303133313131323036313730387c31343034313430327c30303030303030307c30303245323137317c303030307c302e323137327c383930327c34463945"), + decoder.decode(null, null, binary("0d0a242442393335363839353033373537383531387c4141244750524d432c3036313730382e3030302c412c333734302e323033332c4e2c30323132382e383132312c452c33382e38352c3237322e33362c3132313131332c2c2c412a35327c30322e337c30312e337c30312e397c3030303030303030303030307c32303133313131323036313730387c31343034313430327c30303030303030307c30303245323137317c303030307c302e323137327c383930327c344639450d0a"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java new file mode 100644 index 000000000..287c54968 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java @@ -0,0 +1,116 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TotemProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TotemProtocolDecoder decoder = new TotemProtocolDecoder(null); + + verifyPosition(decoder, text( + "$$0113AA862010037348253|588040001901220851494212000000753AE901655121700100000.800000002632.6084S02803.3289E29497E"), + position("2019-01-22 08:51:49.000", true, -26.54347, 28.05548)); + + verifyPosition(decoder, text( + "$$011602867119025755430|50099800180420045019401400000000000000B8797D110816811201.500002132615.7037S02801.8099E056149")); + + verifyPosition(decoder, text( + "$$0108AB863835028447675|5004C0001710250234064214059828A058AE121010604000.600000320304.7772N10134.8238E11625B")); + + verifyPosition(decoder, text( + "$$0108AA863835028447675|5004C0001710250234134114057728A058AE112108305100.600000660304.7787N10134.8719E116458")); + + verifyPosition(decoder, text( + "$$0112AA864244026065291|180018001409160205244011000027BA0E57063100000001.200000002237.8119N11403.5075E05202D")); + + verifyPosition(decoder, text( + "$$0116AA864244026065291|18001800140916020524401100000000000027BA0E57063100000001.200000002237.8119N11403.5075E052020")); + + verifyPosition(decoder, text( + "$$0116AA867119025683137|108000001611020925324112000000000000616027F7001300000099.900000000000.0000N00000.0000E531824")); + + verifyPosition(decoder, text( + "$$0128AA864244026065291|18001800140916020524401100000000000000000000000027BA0E57063100000001.200000002237.8119N11403.5075E05202D")); + + verifyPosition(decoder, text( + "$$0128AA867965024919124|10010800160223032415401203270321032103270189000027BA0E4E001800200001.000000002237.7581N11403.5088E000957"), + position("2016-02-23 03:24:15.000", false, 22.62930, 114.05848)); + + verifyPosition(decoder, text( + "$$0108AA863835024426319|18004000160216160756411100007DCD0000111000000000.800000000316.3519N10228.5086E126522")); + + verifyPosition(decoder, text( + "$$0128AA867521029231005|1880100015101802314842140000000000000000000000001AB48366093127600000.900000000806.1947N09818.4795E080355")); + + verifyPosition(decoder, text( + "$$0108AA864244026063437|1A0000001401010101014111000027BA0E57003100000000.000000000000.0000N00000.0000E048156")); + + verifyPosition(decoder, text( + "$$BE863771024392112|AA$GPRMC,044704.000,A,1439.3334,N,12059.1417,E,0.00,0.00,200815,,,A*67|01.7|00.8|01.4|000000000000|20150820044704|14291265|00000000|4EECBF8B31|0000|0.0000|0002|00000|56E7"), + position("2015-08-20 04:47:04.000", true, 14.65556, 120.98570)); + + verifyPosition(decoder, text( + "$$AE860990002922822|AA$GPRMC,051002.00,A,0439.26245,N,10108.94448,E,0.023,,140315,,,A*71|02.98|01.95|02.26|000000000000|20150314051003|13841157|105A3B1C|0000|0.0000|0005|5324"), + position("2015-03-14 05:10:02.000", true, 4.65437, 101.14907)); + + verifyPosition(decoder, text( + "$$AE860990002922822|AA$GPRMC,051002.00,A,0439.26245,N,10108.94448,E,0.023,,140315,,,A*71|02.98|01.95|02.26|000000000000|20150314051003|13841157|105A3B1C|0000|0.0000|0005|5324\r")); + + verifyNull(decoder, text( + "$$BB862170017856731|AA$GPRMC,000000.00,V,0000.0000,N,00000.0000,E,000.0,000.0,000000,,,A*73|00.0|00.0|00.0|000000001000|20000000000000|13790000|00000000|00000000|00000000|0.0000|0007|8C23")); + + verifyPosition(decoder, text( + "$$B8862170017856731|AA$GPRMC,171849.00,A,3644.9893,N,01012.9927,E,0.049,51,200813,,,A*73|1.59|0.97|1.25|100000001000|20130820171849|13690000|00000000|019BD508|00000000|0.0000|0026|1B2C")); + + verifyPosition(decoder, text( + "$$B2359772032984289|AA$GPRMC,104446.000,A,5011.3944,N,01439.6637,E,0.00,,290212,,,A*7D|01.8|00.9|01.5|000000100000|20120229104446|14151221|00050000|046D085E|0000|0.0000|1170|29A7")); + + verifyPosition(decoder, text( + "$$8B862170017861566|AA180613080657|A|2237.1901|N|11402.1369|E|1.579|178|8.70|100000001000|13811|00000000|253162F5|00000000|0.0000|0014|2B16"), + position("2013-06-18 08:06:57.000", true, 22.61984, 114.03562)); + + verifyPosition(decoder, text( + "$$72862170017856731|3913090911165280000370000000000000000019BD508A0400000003.400000093644.9817N01012.9944E00506F2E")); + + verifyPosition(decoder, text( + "$$B0456123|61$GPRMC,114725.00,A,1258.68276,N,07730.60237,E,0.410,,080113,,,A*79|1.44|0.66|1.27|000000000000|20130108114425|03600000|00000000|053C2BFE|0000|0.3325|0063|2005")); + + verifyNull(decoder, text( + "$$AE359772033395899|AA000000000000000000000000000000000000000000000000000000000000|00.0|00.0|00.0|000000000000|20090215000153|13601435|00000000|00000000|0000|0.0000|0007|2DAA")); + + verifyNull(decoder, text( + "$$AE359772033395899|AA000000000000000000000000000000000000000000000000000000000000|00.0|00.0|00.0|00000000|20090215001204|14182037|00000000|0012D888|0000|0.0000|0016|5B51")); + + verifyNull(decoder, text( + "$$AE359772033395899|AA00000000000000000000000000000000000000000000000000000000000|00.0|00.0|00.0|00000000000|20090215001337|14182013|00000000|0012D888|0000|0.0000|0017|346E")); + + verifyPosition(decoder, text( + "$$B3359772032399074|60$GPRMC,094859.000,A,3648.2229,N,01008.0976,E,0.00,,221211,,,A*79|02.3|01.3|02.0|000000000000|20111222094858|13360808|00000000|00000000|0000|0.0000|0001||A977")); + + verifyPosition(decoder, text( + "$$B3359772032399074|09$GPRMC,094905.000,A,3648.2229,N,01008.0976,E,0.00,,221211,,,A*71|02.1|01.3|01.7|000000000000|20111222094905|03210533|00000000|00000000|0000|0.0000|0002||FA58")); + + verifyPosition(decoder, text( + "$$B3359772032399074|AA$GPRMC,093911.000,A,3648.2146,N,01008.0977,E,0.00,,140312,,,A*7E|02.1|01.1|01.8|000000000000|20120314093910|04100057|00000000|0012D887|0000|0.0000|1128||C50E")); + + verifyPosition(decoder, text( + "$$B3359772032399074|AA$GPRMC,094258.000,A,3648.2146,N,01008.0977,E,0.00,,140312,,,A*7F|02.1|01.1|01.8|000000000000|20120314094257|04120057|00000000|0012D887|0000|0.0000|1136||CA32")); + + verifyPosition(decoder, text( + "$$B3359772032399074|AA$GPRMC,234603.000,A,3648.2179,N,01008.0962,E,0.00,,030412,,,A*74|01.8|01.0|01.5|000000000000|20120403234603|14251914|00000000|0012D888|0000|0.0000|3674||940B")); + + verifyPosition(decoder, text( + "$$B3359772032399074|AA$GPRMC,234603.000,A,3648.2179,N,01008.0962,E,0.00,,030412,,,A*74|01.8|01.0|01.5|000000000000|20120403234603|14251914|00000000|0012D888|0000|0.0000|3674|940B")); + + verifyPosition(decoder, text( + "$$B2356895037578518|AA$GPRMC,173829.000,A,3740.4107,N,02129.9815,E,0.00,,111113,,,A*7B|02.6|01.6|02.1|000000000000|20131111173829|14041251|00000000|002E0DD7|0000|0.0240|6010|8128")); + + verifyPosition(decoder, text( + "$$B2356895037578518|AA$GPRMC,203823.000,A,3740.3285,N,02129.9295,E,0.00,,111113,,,A*79|01.5|01.0|01.1|000000000000|20131111203823|14041251|00000000|002E0DD7|0000|0.0000|6371|3824")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java new file mode 100644 index 000000000..5a47f74cc --- /dev/null +++ b/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class TotemProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + TotemProtocolEncoder encoder = new TotemProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(2); + command.setType(Command.TYPE_ENGINE_STOP); + command.set(Command.KEY_DEVICE_PASSWORD, "000000"); + + assertEquals("*000000,025,C,1#", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java new file mode 100644 index 000000000..76355066b --- /dev/null +++ b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java @@ -0,0 +1,31 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Tr20ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Tr20ProtocolDecoder decoder = new Tr20ProtocolDecoder(null); + + verifyPosition(decoder, text( + "%%123456789012345,A,120101121800,N6000.0000E13000.0000,0,000,0,01034802,150,[Message]")); + + verifyNull(decoder, text( + "%%TRACKPRO01,1")); + + verifyPosition(decoder, text( + "%%868873457748532,A,181109121248,N2237.4181E11403.2857,000,282,NA,47010000,108")); + + verifyPosition(decoder, text( + "%%TR-10,A,050916070549,N2240.8887E11359.2994,0,000,NA,D3800000,150,CFG:resend|"), + position("2005-09-16 07:05:49.000", true, 22.68148, 113.98832)); + + verifyPosition(decoder, text( + "%%TR-10,A,050916070549,N2240.8887E11359.2994,0,000,NA,D3800000,150,CFG:resend|")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java new file mode 100644 index 000000000..92fe0da29 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Tr900ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Tr900ProtocolDecoder decoder = new Tr900ProtocolDecoder(null); + + verifyPosition(decoder, text( + ">00001001,4,1,150626,131252,W05830.2978,S3137.2783,,00,348,18,00,003-000,0,3,11111011*3b!"), + position("2015-06-26 13:12:52.000", true, -31.62131, -58.50496)); + + verifyPosition(decoder, text( + ">12345678,1,1,070201,144111,W05829.2613,S3435.2313,,00,034,25,00,126-000,0,3,11111111*2d!")); + + verifyPosition(decoder, text( + ">00001001,4,1,150626,131252,W05830.2978,S3137.2783,,00,348,18,00,003-000,0,3,11111011*3b!\r\n")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java new file mode 100644 index 000000000..e83824fb4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TrackboxProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TrackboxProtocolDecoder decoder = new TrackboxProtocolDecoder(null); + + verifyNull(decoder, text( + "a=connect&v=11&i=111111111111111")); + + verifyPosition(decoder, text( + "183457.999,5126.0247N,00002.8686E,5.2,70.4,3,57.63,32.11,17.32,150507,05"), + position("2007-05-15 18:34:57.999", true, 51.43375, 0.04781)); + + verifyPosition(decoder, text( + "183558.999,5126.3979N,00003.0745E,5.2,70.4,3,57.63,32.11,17.32,150507,05")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java new file mode 100644 index 000000000..4352fc935 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java @@ -0,0 +1,27 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TrakMateProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TrakMateProtocolDecoder decoder = new TrakMateProtocolDecoder(null); + + verifyPosition(decoder, text( + "^TMSTP|352984083995323|116|13.07809|77.55979|131508|131118|0.0|146.51|7|0|71 -2 248|0|13.1|0.0|10.5|1|0|0|0|#")); + + verifyPosition(decoder, text( + "^TMPER|354678456723764|1|12.59675|77.56789|123456|030414|2.3|34.0|1|0|0|0.015|3.9|12.0|23.4|23.4|1|1|0|#")); + + verifyPosition(decoder, text( + "^TMALT|354678456723764|3|2|1|12.59675|77.56789|123456|030414|1.2|34.0|#")); + + verifyPosition(decoder, text( + "^TMSRT|354678456723764|12.59675|77.56789|123456|030414|1.03|1.01|#")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java new file mode 100644 index 000000000..f482a00bb --- /dev/null +++ b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TramigoFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TramigoFrameDecoder decoder = new TramigoFrameDecoder(); + + verifyFrame( + binary("8000ed2bb0009c000101bee000050b09633d925b5472616d69676f3a205472697020737461727465642c2053686f636b2053656e736f722c206174204b696e6720437265656b20526f61642d46726565746f776e205374726565742c20506f727420486172636f7572742c205269766572732c204e472c20342e37363336312c20372e30313836382c2030373a31383a333620536570203320454f46"), + decoder.decode(null, null, binary("8000ed2bb0009c000101bee000050b09633d925b5472616d69676f3a205472697020737461727465642c2053686f636b2053656e736f722c206174204b696e6720437265656b20526f61642d46726565746f776e205374726565742c20506f727420486172636f7572742c205269766572732c204e472c20342e37363336312c20372e30313836382c2030373a31383a333620536570203320454f46"))); + + verifyFrame( + binary("80003d1ac0001c00010100000367152b13bc1d5970696e6720454f46"), + decoder.decode(null, null, binary("80003d1ac0001c00010100000367152b13bc1d5970696e6720454f46"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java new file mode 100644 index 000000000..d35c5c54e --- /dev/null +++ b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java @@ -0,0 +1,63 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TramigoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TramigoProtocolDecoder decoder = new TramigoProtocolDecoder(null); + + verifyAttributes(decoder, binary( + "8000c426b000a6000101c557037598050d5c8a595472616d69676f3a204d6f76696e672c20302e3132206b6d2045206f66204c617275742054696e2049736c616d6963205072696d617279205363686f6f6c2c2054616970696e672c20506572616b2c204d592c20342e38333134392c203130302e37333038352c204e572077697468207370656564203130206b6d2f682c2030303a34393a30382041756720392020454f46")); + + verifyAttributes(decoder, binary( + "8000c526b000a6000101f17d03759805115c8a595472616d69676f3a204d6f76696e672c20302e3133206b6d205345206f66204c617275742054696e2049736c616d6963205072696d617279205363686f6f6c2c2054616970696e672c20506572616b2c204d592c20342e38333132322c203130302e37333037382c204e4520776974682073706565642039206b6d2f682c2030303a34383a35332041756720392020454f46")); + + verifyAttributes(decoder, binary( + "8000d426b0009f00010184f20375980593638a595472616d69676f3a204d6f76696e672c20302e3039206b6d204e57206f66204a616c616e2053696d70616e672042617475204d61726b65742c2054616970696e672c20506572616b2c204d592c20342e38333034332c203130302e37323230342c20532077697468207370656564203130206b6d2f682c2030313a32313a31322041756720392020454f46")); + + verifyAttributes(decoder, binary( + "8000d626b0007f0001013c0b037598051d648a595472616d69676f3a2053746f707065642c206174204a616c616e2053696d70616e672042617475204d61726b65742c2054616970696e672c20506572616b2c204d592c20342e38323937322c203130302e37323233322c2030313a32323a34342041756720392020454f46")); + + verifyNull(decoder, binary( + "80003d1ac0001c00010100000367152b13bc1d5970696e6720454f46")); + + verifyAttributes(decoder, binary( + "8000d316b000860001018f8703771bee11fdf2585472616d69676f3a205061726b65642c20302e3131206b6d2053206f6620492e452e532e2050756572746120426f6e6974612c204361726162616e6368656c2c204d61647269642c2045532c2034302e33373736362c202d332e37333833352c2030353a3131204170722031362020454f46")); + + verifyAttributes(decoder, binary( + "80009e08b00086000101bc1803778a59c58dea57546573742054323320547261636b65723a204d6f76696e672c20312e3639206b6d204e57206f66205574656b6f6e2c2045646f2c204e472c20362e34363137302c20352e36313938322c20452077697468207370656564203333206b6d2f682c2031363a3138205365702032372020454f46")); + + verifyAttributes(decoder, binary( + "8000853eb000b8000101fcff032f14665a89e2564176656e7369732053797353657276653a2049676e6974696f6e206f6e2064657465637465642c206d6f76696e672c20302e3135206b6d205357206f66204261626120416e696d61736861756e205374726565742d426f64652054686f6d61732053742e2c20537572756c6572652c204c61676f7320436974792c204e472c20362e34383736352c20332e33343735352c2031303a3031204d6172203131202020454f46")); + + verifyAttributes(decoder, binary( + "8000973eb000b90001012128032f14667794e2564176656e7369732053797353657276653a2049676e6974696f6e206f6e2064657465637465642c2073746f707065642c20302e3134206b6d205357206f66204261626120416e696d61736861756e205374726565742d426f64652054686f6d61732053742e2c20537572756c6572652c204c61676f7320436974792c204e472c20362e34383736372c20332e33343737332c2031303a3438204d6172203131202020454f46")); + + verifyAttributes(decoder, binary( + "8000b73eb000ad000101fdd2032f1466c9cbe2564176656e7369732053797353657276653a2049676e6974696f6e206f6e2064657465637465642c206d6f76696e672c20302e3131206b6d2045206f6620416c68616a69204d6173686120526f616420466f6f746272696467652c20537572756c6572652c204c61676f7320436974792c204e472c20362e35303031342c20332e33353434332c2031343a3434204d6172203131202020454f46")); + + verifyAttributes(decoder, binary( + "8000883eb000d3000101b223032f1466fc89e2564176656e7369732053797353657276653a2049676e6974696f6e206f66662064657465637465642c2049676e4f6e506572696f643a2030303a30323a34312c2073746f707065642c20302e3039206b6d205345206f66204a696e616475205072696d617279205363686f6f6c20416465204f6e6974696d6572696e2053742e2c20537572756c6572652c204c61676f7320436974792c204e472c20362e34383639332c20332e33343636302c2031303a3033204d6172203131202020454f46")); + + verifyAttributes(decoder, binary( + "80009a3eb000d300010109ff032f1466b195e2564176656e7369732053797353657276653a2049676e6974696f6e206f66662064657465637465642c2049676e4f6e506572696f643a2030303a30353a31342c2073746f707065642c20302e3039206b6d205345206f66204a696e616475205072696d617279205363686f6f6c20416465204f6e6974696d6572696e2053742e2c20537572756c6572652c204c61676f7320436974792c204e472c20362e34383639312c20332e33343636322c2031303a3533204d6172203131202020454f46")); + + verifyAttributes(decoder, binary( + "8000bc3eb000ba000101622c032f1466bacce2564176656e7369732053797353657276653a2049676e6974696f6e206f66662064657465637465642c2049676e4f6e506572696f643a2030303a30343a30302c206d6f76696e672c20617420416b6572656c6520526f61642d4f67756e6c616e612044726976652c20537572756c6572652c204c61676f7320436974792c204e472c20362e35303630332c20332e33353232382c2031343a3438204d6172203131202020454f46")); + + verifyAttributes(decoder, binary( + "80001d3cb000b3000101160f032f1466b475e0564176656e7369732053797353657276653a205374617475732c204750533a203931252c2047534d3a203737252c20475052533a20436f6e6e65637465642c20626174746572793a20313030252c207265706f7274733a2049676e6974696f6e20286f6666292c205374617475732028352c322e302c3732302c3330292c20362e34393239382c20332e33343836352c2031393a3038204d6172203920454f46")); + + verifyAttributes(decoder, binary( + "80005408b000af000101b23903677f00c8436d3842616c697365204f6e653a20416c6c756d616765206d61726368652064e974656374e92c20676172e92c20302e3735206b6d20452064652045636f6c65204175746f726f757465206465204b696e73686173612c2056696c6c65206465204b696e73686173612c204b696e73686173612c2043442c202d342e33343130362c2031352e33343931352c2030313a3030204a616e2031202020454f46")); + + verifyAttributes(decoder, binary( + "8000011bb0009e0001015b93032ef6f35994a9545472616d69676f3a204d6f76696e672c20302e3930206b6d205345206f66204372616e6562726f6f6b20466972652053746174696f6e2c2050656e726974682c205379646e65792c2041552c202d33332e37303732322c203135302e37313735392c2053452077697468207370656564203337206b6d2f682c2031393a3438204a616e20342020454f46")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java new file mode 100644 index 000000000..2fdb86218 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java @@ -0,0 +1,67 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TrvProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TrvProtocolDecoder decoder = new TrvProtocolDecoder(null); + + verifyNull(decoder, text( + "TRVAP00352121088015548")); + + verifyNotNull(decoder, text( + "IWAP02,zh_cn,0,6,260,1,11002|39252|9,11002|35112|23,11002|11043|24,11002|39253|24,11002|13751|24,11018|8102|26,3,a|c0-4a-00-b6-9c-f5|64&a|c0-4a-00-b6-9c-f5|64&a|18-a6-f7-92-35-da|84")); + + verifyPosition(decoder, text( + "TRVAP01170905A5227.1382N00541.4256E001.7095844000.0008100610020100,204,8,3230,13007")); + + verifyAttributes(decoder, text( + "TRVCP01,07800010010000602001206001120124")); + + verifyNull(decoder, text( + "IWAP00353456789012345")); + + verifyPosition(decoder, text( + "IWAP01080524A2232.9806N11404.9355E000.1061830323.8706000908000102,460,0,9520,3671,Home|74-DE-2B-44-88-8C|97& Home1|74-DE-2B-44-88-8C|97&Home2|74-DE-2B-44-88-8C|97& Home3|74-DE-2B-44-88-8C|97")); + + verifyNotNull(decoder, text( + "IWAP02,zh_cn,0,7,460,0,9520|3671|13,9520|3672|12,9520|3673|11,9520|3674|10,9520|3675|9,9520|3676|8,9520|3677|7,4,1|D8-24-BD-79-FA-1F|59&2|3C-46-D8-6D-CE-01|81&3|0C-4C-39-1A-7C-65|69&4|70-A8-E3-5D-D7-C0|65")); + + verifyPosition(decoder, text( + "IWAP10080524A2232.9806N11404.9355E000.1061830323.8706000908000502,460,0,9520,3671,00,zh-cn,00,HOME|74-DE-2B-44-88-8C|97&HOME1|74-DE-2B-44-88-8C|97&HOME2|74-DE-2B-44-88-8C|97&HOME3|74-DE-2B-44-88-8C|97")); + + verifyNull(decoder, text( + "IWAP03,06000908000102,5555,30")); + + verifyNull(decoder, text( + "TRVAP00353456789012345")); + + verifyAttributes(decoder, text( + "TRVCP01,06000908000102")); + + verifyAttributes(decoder, text( + "TRVCP01,100007100000001020151060011")); + + verifyPosition(decoder, text( + "TRVAP01160211A2544.5118N05553.7586E105.711185941.52010001010010000,424,030,3011,27003")); + + verifyPosition(decoder, text( + "TRVAP01160209A2540.8863N05546.6125E005.6075734123.7910000810010000,424,030,3012,27323")); + + verifyPosition(decoder, text( + "TRVAP01080524A2232.9806N11404.9355E000.1061830323.8706000908000102,460,0,9520,3671")); + + verifyPosition(decoder, text( + "TRVAP01080524A2232.9806N11404.9355E000.1061830323.8706000908000102,460,0,9520,3671"), + position("2008-05-24 06:18:30.000", true, 22.54968, 114.08226)); + + verifyPosition(decoder, text( + "TRVAP10080524A2232.9806N11404.9355E000.1061830323.8706000908000502,460,0,9520,3671,00,zh-cn,00")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java new file mode 100644 index 000000000..e3833bcc7 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Tt8850ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Tt8850ProtocolDecoder decoder = new Tt8850ProtocolDecoder(null); + + verifyPosition(decoder, text( + "\u0000\u0004,007F,0,GTFRI,020102,867844000667538,4142726856,0,0,1,3,1.6,0,997.3,-66.830786,10.483394,20171212171418,0734,0004,041A,4220,69,20171212171657,FF61")); + + verifyPosition(decoder, text( + "\u0000\u0004,005F,0,GTFRI,020100,135790246811220,,0,0,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,90,20090214093254,11F0")); + + verifyPosition(decoder, text( + "\u0000\u0004,005F,0,GTGEO,020100,135790246811220,,0,0,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,90,20090214093254,11F0")); + + verifyPosition(decoder, text( + "\u0000\u0004,005F,0,GTNMR,020100,135790246811220,,0,0,1,1,4.3,92,70.0,121.354335,31.222073,20090214013254,0460,0000,18d8,6141,90,20090214093254,11F0")); + + verifyPosition(decoder, text( + "\u0000\u0004,0017,0,GTNMR,,867844000400914,,0,41,1,2,0.0,0,1504.2,-75.569202,6.242850,20150404162835,,,,,97,20150404162836,05EF")); + + verifyNull(decoder, text( + "\u0000\u0004,0017,0,GTPNA,,867844000400914,,0,0,1,0,,,,0,0,,,,,,99,20150404190153,0601")); + + verifyPosition(decoder, text( + "\u0000\u0004,0017,0,GTEPN,,867844000400914,,0,0,1,0,0.0,0,1717.4,-75.598445,6.278578,20150405003116,,,,,95,20150405003358,0607")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java new file mode 100644 index 000000000..ed75cee38 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TytanProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TytanProtocolDecoder decoder = new TytanProtocolDecoder(null); + + verifyPositions(decoder, binary( + "B500192000001405125652CA9B1A325FC98D11A9990018020118FC0D")); + + verifyPositions(decoder, binary( + "B500197800007422125652D7AC32325FD08D11A69900180200188280")); + + verifyPositions(decoder, binary( + "B500181000001405115652DEEB2A325FC68D11A7D00005012A2AE1")); + + verifyPositions(decoder, binary( + "B5005690000068494F561CEAE932325FD28D11A299000702000063045532030066013567018768014B6901286B0240396C04030785986D013E7F040000A7CE81040000A76C82027EAB83080FA01068FFFF0F3C880202583156")); + + verifyPositions(decoder, binary( + "b50069a00000689d315604512b32378f1a8e9fe094005a04d7c84b41020300ab250402140c0702c0006501006601006b0280646c0402883db0315604525732378f1d8e9fdd94005a04d7c84b41020300ab250402140c0702c0006501006601006b0280646c0402883db08887")); + + verifyPositions(decoder, binary( + "b50028080000689d215602772f00378f1b8e9fdd98005a042efb3e4102030000000402140c070200000901")); + + verifyPositions(decoder, binary( + "b500280a0000689d215602772f00378f1b8e9fdd98005a042efb3e4102030000000402140c07020000da20")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java new file mode 100644 index 000000000..bd1fc71f4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java @@ -0,0 +1,53 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class TzoneProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + TzoneProtocolDecoder decoder = new TzoneProtocolDecoder(null); + + verifyAttributes(decoder, binary( + "545a005b24240406010800000866050033819630120911071824000472bd8e5b0008aac01b07019b04bb002f00040b06161154000e100132ff2006161152000e080096ff4606161151000e1e0101ff1406161156000db6405bff490024469e0d0a")); + + verifyAttributes(decoder, binary( + "545a006624240406010800000866050033819630120911070e1d000472bd8e5b0008aac01b17019b04bc003a00050b06161151000e1e00ffff1406161152000e08008aff4706161154000e100134ff1f06161156000db0406cff4906161155000df44011ff4e0023811a0d0a")); + + verifyPosition(decoder, binary( + "545a005624240111010e0000086169303626931411091b151d2600160801de26ec002f633411091b151d2500000000160c0000040d2a34df000eaa4000001b37016000000000319c0000000000000000000000000000003a84240d0a")); + + verifyPosition(decoder, binary( + "545a005024240153011000000863835025559464110103080a22001609011bed79245964a9110103080a22000a0000550c00000604396f04222c000daac000151701a204870000000000000003000959000546190d0a")); + + verifyPosition(decoder, binary( + "545A005224240153010E000008638350256668551008130616090016050079F63D2527FAF710081306160900A000002F0D33000803015B07013D7976000DAAE0400537016C049E000000000000000300800002B65EEA0D0A")); + + verifyPosition(decoder, binary( + "545a00582424010b022000000860041028904798100803030c2700160a007da96203356669100803030c2700000000000e000004002813730010aa4000000617017100000000000080000000000000000000000000000000007701fe0d0a")); + + verifyPosition(decoder, binary( + "545a00582424010b022000000860041028904798100803030d1a001609007da9620335666a100803030d1900000000000e000004002813730010aa400000063701720000000000008000000000000000000000000000000000787f0c0d0a")); + + verifyPosition(decoder, binary( + "545a00582424010b021e000008637710239476270f080b0a3228001600000000000000000000000000000000000000000000000401a00822001088c00020183701a6053800000000800000000000000000000000000000000077c9860d0a"), + position("1999-11-30 00:00:00.000", false, 0.0, 0.0)); + + verifyPosition(decoder, binary( + "545A00912424010B021E000008661040203754350F061807083800160400CE5ADC041447620F0618070838000A0000060C7C0004253378370010AAC000000C37018504E500000000800000000000000000390B0A0014061113000000051200140610600014061220001000133800140610070010001473001000151100101500640010000920001000148400000000000000F2EF570D0A"), + position("2015-06-24 07:08:56.000", true, 22.53946, 114.06310)); + + verifyAttributes(decoder, binary( + "545A009E2424010A0205000008637710225481290F010F081E33000000000010A0C000310E35000005840000000000000000000000000066140A00140612200010001511001406101000140612490014061308001015006400051400170014061012000000050200140612470000000504001406100700140612510014061260001015012000000005080014061252001406130900101501410000000506000853A40D0A")); + + verifyAttributes(decoder, binary( + "545A00992424010A0205000008637710225481290F010F082634000000000010A0C000311035000005870000000000000000000000000061130A000000050800101500640014061251001406130800051400170010150141001406101000140612200014061309000000050200140610070014061260001406124900140612470014061012001406125200100015110010150120000000050400183E8A0D0A")); + + verifyAttributes(decoder, binary( + "545A00942424010A0205000008637710225481290F010F091C1F000000000010A1C000310F3500000586000000000000000000000000005C120A001406101000140612490014061012001406125200000005040000000502001015012000000005080010001511001406122000140612600014061247001406130900140610070010150141000514001700140612510010150064007A907C0D0A")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java b/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java new file mode 100644 index 000000000..d3d0429d6 --- /dev/null +++ b/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java @@ -0,0 +1,29 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class UlbotechFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + UlbotechFrameDecoder decoder = new UlbotechFrameDecoder(); + + assertEquals( + binary("f8010103515810532780699f7e2e3f010e015ee4c906bde45c00000000008b0304004000000404002c776005060373193622110b00240b00fee8ffff807dffff606d0b00fee9af000000af0000000b00feee7d78807dffffffff100101cc2af8"), + decoder.decode(null, null, binary("f8010103515810532780699f7e2e3f010e015ee4c906bde45c00000000008b0304004000000404002c776005060373193622110b00240b00fee8ffff807dffff606d0b00fee9af000000af0000000b00feee7d78807dffffffff100101cc2af8"))); + + assertEquals( + binary("2a545330312c33353430343330353133383934363023"), + decoder.decode(null, null, binary("2a545330312c33353430343330353133383934363023"))); + + assertEquals( + binary("f8010108679650230646339de69054010e015ee17506bde2c60000000000ac0304024000000404000009f705060390181422170711310583410c0000310d00312f834131018608040003130a100101136cf8"), + decoder.decode(null, null, binary("f8010108679650230646339de69054010e015ee17506bde2c60000000000ac0304024000000404000009f70005060390181422170711310583410c0000310d00312f834131018608040003130a100101136cf8"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java new file mode 100644 index 000000000..1c29ccd4a --- /dev/null +++ b/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java @@ -0,0 +1,90 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class UlbotechProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + UlbotechProtocolDecoder decoder = new UlbotechProtocolDecoder(null); + + verifyNull(decoder, buffer( + "*TS01,353323081464660#")); + + verifyAttributes(decoder, buffer( + "*TS01,868323025245751,134955140317,WFE:0#")); + + verifyPosition(decoder, binary( + "f8010103515810532780699f7e2e3f010e015ee4c906bde45c00000000008b0304004000000404002c776005060373193622110b00240b00fee8ffff807dffff606d0b00fee9af000000af0000000b00feee7d78807dffffffff100101cc2af8")); + + verifyPosition(decoder, binary( + "F8010103596580420045259CFB3329010E015ED91506BDE5A800000000009E030402420000040400492AA405060344197E220D071131058F410C1591310D48312F8F413107C60804027666B00C138254D182607A826EE083BE554385F50019423CAD1DF8")); + + verifyNotNull(decoder, binary( + "F8010108683230231070781EA3676E020BFFFFFFFFFFFFFFFFFFFF780304000000030404000002C20506032A1790220E100101AC72F8")); + + verifyNotNull(decoder, binary( + "f8010108683230220996561ea6ce1c020bffffffffffffffffffff78030400000000040400087b710506035519ad2214060800000000000000006220f8")); + + verifyAttributes(decoder, binary( + "f8010108683230220996561ea6ce3f020b02cc00114e86000002f153030400000000040400087b710506035619a4221406080000000000000000fbcff8")); + + verifyAttributes(decoder, binary( + "f8010108683230211861161e9d8c48020b00de0063eb730128b56161030400010001040400127d0705060174179422021005e000000001db06f8")); + + verifyPosition(decoder, binary( + "f8010108683230220996561ea6cdf9010eff47465cfb68d7a000000000270f030400000000040400087b710506035119ba22140608000000000000000022cef8")); + + verifyPosition(decoder, binary( + "f8010108683230220996561ea74274010eff47477bfb68d89000000000270f030400000000040400087b710506035419472214060800000000000000006661f8")); + + verifyPosition(decoder, binary( + "f8010103515790566431569e5fbb9d010e015ee2b906bde4a000000000009f03040a4000000404000115fe05060340173f22030711310583410c0000310d00312f834131000008040000b78c09077320290082c021100101120af8")); + + verifyNull(decoder, buffer( + "*TS01,354043051389460#")); + + verifyPosition(decoder, binary( + "f8010108679650230646339de69054010e015ee17506bde2c60000000000ac0304024000000404000009f705060390181422170711310583410c0000310d00312f834131018608040003130a100101136cf8")); + + verifyPosition(decoder, binary( + "f8010108679650230651689dc8e45b010e01194a26fbd47fa6001f003c0054030402420000040400024d7b0506037c18692212071131057f410c0ee0310d1b312f41413112ef0804000dd59fcc32f8")); + + verifyPosition(decoder, binary( + "f8010103596580419465449da89d16010efe5580fe0923d82100140129005903040242000004040001a7f10506037818be220e070e31057b410c1324310d144131fa3208040020b1418297f8")); + + verifyPosition(decoder, binary( + "f8010103596580419465449da8564e010efe55a1800923d04b0000000000710304000000000404000178d2050603571876220ec3caf8")); + + verifyPosition(decoder, binary( + "f8010103545500500179009ccb4b62010e00144db906310d3f0000000000cb0304000000000404000a8123050603211860221006080000000100000000ef97f8")); + + verifyPosition(decoder, binary( + "F80101035785203457289495D60235010E016175A506C2C838000000000064")); + + verifyPosition(decoder, binary( + "F8010108621060211481299C4247FA010E015EE1D606BDE797000301370081030402420000040400523CAF050603921743220706080000000000000000071131058E410C0E30310D48312F8E4131046A080402C8F2545445F8")); + + verifyPosition(decoder, binary( + "F8010108621060211481299C4249FA010E015EE27506BDE80900020000008F030402420000040400523CAF05060392173F220706080000000000000000071131058E410C0E40310D48312F8E41310884080402CA60E43872F8")); + + verifyNotNull(decoder, binary( + "f8010108653280262660481cdacf830209ffffffffffffffff780304000300000404000000030506017418a021f99697f8")); + + verifyNotNull(decoder, binary( + "f801010865328026266048fffeae800209ffffffffffffffff7803040200000004040000000005060375175421f3060800000000000000009c28f8")); + + verifyPosition(decoder, binary( + "f8010108653280262660489ce260b4010e01e757bd022340d7002b010d01570304020200000404000000260506036a17d42200060800000000000000000a0101ab9ff8")); + + verifyPosition(decoder, binary( + "f8010108653280262660489ce260df010e01e756f30223384a0003010a02a80304020200000404000001280506036217fe22010608000000000000000005aaf8")); + + verifyPosition(decoder, binary( + "f8010108653280262660489ce26128010e01e769ac022336290014010300730304020200000404000003c905060371181c2201060800000000000000000a0140e471f8")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java new file mode 100644 index 000000000..dbbe4591f --- /dev/null +++ b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java @@ -0,0 +1,65 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class UproProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + UproProtocolDecoder decoder = new UproProtocolDecoder(null); + + verifyPosition(decoder, buffer( + "*HQ200861810538000002,BA&A0206033302618209658563620115180119&B0100000040&C6328680=&F0039&R2710&V0036&T09&K50000&N04&P0200#")); + + verifyPosition(decoder, buffer( + "*HQ200999999,AB1&A1656512233362911356523660000230618&B0100060010&C00000<6<&F0000&R2405&V0109&W0000003E&K00100&T65&X(k89860045191536000374)#")); + + verifyPosition(decoder, buffer( + "*HQ20113800138000,YAA&A0732142233550011405829060520190314&B0100000000&C00001234&R3109&T80#")); + + verifyPosition(decoder, binary( + "2a4d473230313836383530303032303030343836372c414226413035303032343138313438373536303636303131373732323030303031313132313626583331302c3236302c34383837322c353639312c37333b34383837322c3732322c38363b34383837322c353639332c38383b34383837322c323336332c39303b34383837322c323336322c393726423030303030303030303026573030264e3230265a31342659313430303323")); + + verifyPosition(decoder, binary( + "2a4d473230303639333530323030303033353537332c42412641303834313237333332363334353230373033383933373630303030303235313131362642303130303030303030302647303036323030264d393930264e3235264f3035303026433030313a363b363926510411058c0c125c0d0a2fff4237ee614d66454c140826555f50000000000300000000000000000026543139333723")); + + verifyPosition(decoder, buffer( + "*MG201693502000035441,BA&A1213073325458307036690710000151116&P0730000032ce4fb3&D1&B0000000000&C005799?7&S3,20161115120025,07035.54659E,3324.87721N,3000,0,0,0,0,847,599,8,40,0,19,20&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0&T0107")); + + verifyPosition(decoder, buffer( + "*MG201693502000034964,AB&A0800253335360507036975710000091116&P0730000032d2a94d&B0000000000&N13&Z12&U_P\0\0\0\u0004\0\0\0\0\0\0\0\0\0\0"), + position("2016-11-09 08:00:25.000", true, -33.58934, -70.61626)); + + verifyNull(decoder, buffer( + "*MG20113800138000,AH")); + + verifyPosition(decoder, buffer( + "*MG201693502000034964,AB&A0200183324418107033792800009051116&B0000000000&N15&Z94&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0")); + + verifyPosition(decoder, buffer( + "*MG201693502000034964,AB&A0200543324412007033805910000051116&P0730000032d66785&B0000000000&N15&Z92&U_P\0\0\0\0\0\0\0\0\0\0\0\0\0\0")); + + verifyPosition(decoder, buffer( + "*AI2000905447674,BA&A2003064913201201845107561627121016&B0100000000&C05>8=961&F0333&K023101002154A7")); + + verifyPosition(decoder, buffer( + "*AI200905300036,AH&A0317264913209801844913060000251115&B0500000000&C0;4?72:9&F0000"), + position("2015-11-25 03:17:26.000", false, 49.22016, 18.74855)); + + verifyPosition(decoder, buffer( + "*AI2000905300036,AS&A1647304913209801844913060000251115&B0400000000&C0;4?72:9&F0000")); + + verifyPosition(decoder, buffer( + "*AI2000905300036,AC1&A1648014913209801844913060000251115&B0400000000&C0;4?72:9&F0000")); + + verifyPosition(decoder, buffer( + "*AI2000905300036,AB1&A1702464913231101844949860000251115&B0500000000&C0;4?72:9&F0000")); + + verifyPosition(decoder, buffer( + "*AI2000905300036,AD1&A1703054913231101844949860000251115&B0500000000&C0;4?72:9&F0000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java new file mode 100644 index 000000000..e3761c3ef --- /dev/null +++ b/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java @@ -0,0 +1,77 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class V680ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + V680ProtocolDecoder decoder = new V680ProtocolDecoder(null); + + verifyPosition(decoder, text( + "#867967020910610#01234567890#1#0000#AUT#1#0500000000120000#114.036291,E,22.665795,N,111.00,000.00#111116#193333##"), + position("2016-11-11 19:33:33.000", true, 22.66579, 114.03629)); + + verifyPosition(decoder, text( + "#355488020168617##1#0000#AUT#01#260001a412966f#1834.790700,E,5302.748800,N,0.00,0.00#310316#174538.000##")); + + verifyPosition(decoder, text( + "#355488020168617##1#0000#AUT#01##1834.770100,E,5302.742800,N,0.62,0.00#310316#211537.000##")); + + verifyNull(decoder, text( + "#353588102019155")); + + verifyPosition(decoder, text( + "#135790246811222#13486119277#1#0000#SOS#1#27bc10af#11407.4182,E,2232.7632,N,0.00,79.50#070709#134147.000##")); + + verifyPosition(decoder, text( + "#356823031193431##0#0000#SF#1#72403#V#04702.3025,W,2252.18380,S,008.18,0#090413#134938"), + position("2013-04-09 13:49:38.000", false, -22.86973, -47.038375)); + + verifyPosition(decoder, text( + "#356823033219838#1000#0#1478#AUT#1#66830FFB#03855.6628,E,4716.6821,N,001.41,259#130812#143905")); + + verifyPosition(decoder, text( + "#353588102019155##1#0000#AUT#01#7240060be7873f#4849.079800,W,2614.458200,S,0.00,0.00#130413#182110.000")); + + verifyPosition(decoder, text( + "#353588302045917##1#0000#AUT#01#7243141c2b14c3#4738.442300,W,2334.874000,S,0.00,0.30#170413#004831.000")); + + verifyPosition(decoder, text( + "#352897045085282##0#0000#AUT#1#72400510730208,00d36307,10734fc4#4647.8922,W,2339.1956,S,2.60,63.74#200413#094310.000")); + + verifyPosition(decoder, text( + "#356823033537791##0#0000#AUT#1#V#03610.2179,E,5004.5796,N,000.01,349#180513#073758")); + + verifyPosition(decoder, text( + "#356823031236214##0#0000#AUT#1#V#01904.5491,E,6941.0085,N,000.09,248#170513#160140")); + + verifyNull(decoder, text( + "#353588550032869##1#0000#AUT#01#72400401cd01a5#00000.0000,E,0000.0000,N,0.00,#000000#000000.000")); + + verifyPosition(decoder, text( + "#352897045085282##0#0000#AUT#1#72400510730208,00d36307,10734fc4#4647.8922,W,2339.1956,S,2.60,63.74#200413#094310.000##")); + + verifyPosition(decoder, text( + "#352165050199210##13#0000#AUT#1#72400605471305,054712fd,054712ff#05144.0008,W,3005.5011,S,0.11,201.46#260713#172647.000##")); + + verifyPosition(decoder, text( + "#356823031166908#13001190527#0#0000#AUT#4#V#07136.4070,W,1040.0575,N,000.35,257#280813#142836#V#07136.4088,W,1040.0580,N,000.49,288#280813#142846#V#07136.4098,W,1040.0590,N,000.59,264#280813#142856#V#07136.4093,W,1040.0605,N,000.30,264#280813#142906##")); + + verifyPosition(decoder, text( + "#355488020132015##1#0000#AUT#01#510089246a34c0#10641.338800,E,619.427100,S,0.00,0.00#011113#161942.000##")); + + verifyPosition(decoder, text( + "#359094025419110#bigfriend#0#1234#AUTO#1##04632.8846,W,2327.2264,S,0.00,0.00#220913#234808##")); + + verifyPosition(decoder, text( + "#353588102031599##1#0000#AUT#01#41300304843fc1#7955.124400,E,642.095500,N,5.28,95.21#041213#074431.000##")); + + verifyPosition(decoder, text( + "1#0000#AUT#01#23403007fa650e#16.747700,W,5136.356500,N,0.00,0.00#040415#002051.000")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java new file mode 100644 index 000000000..11596945e --- /dev/null +++ b/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java @@ -0,0 +1,40 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class VisiontekProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + VisiontekProtocolDecoder decoder = new VisiontekProtocolDecoder(null); + + verifyPosition(decoder, text( + "$1,117,28,01,16,15,05,48,1725.0518N,07824.5298E,0620,11,0,185,2062,0,0,0,1,1,1,1,24,00.0000,00.3740,00.0000,VAJRA V1.00,A")); + + verifyPosition(decoder, text( + "$1,VMC,358072044271838,26,10,15,10,43,20,17.066418N,080.395667E,000.0,285,00.8,0074,6390,0,0,0,0,0,0,0,0,00.00,00.00,00,00,0000,12.7,4.0,24,10,0000000000000,A,0")); + + verifyNull(decoder, text( + "$1,VMC,358072044271838,25,10,15,09,19,40,00.0000000,000.0000000,000.0,000,00.0,0000,6070,0,0,0,0,0,0,0,0,00.00,00.00,00,00,0000,12.5,4.0,99,00,0000000000000,V,0")); + + verifyPosition(decoder, text( + "$1,AP116,05,06,15,11,48,32,1725.0460N,07824.5289E,0617,07,0,030,2091,0,0,0,1,1,1,1,20,00.0000,00.3820,00.0000,VAJRA V1.00,A")); + + verifyPosition(decoder, text( + "$1,AP09BU9397,861785006462448,20,06,14,15,03,28,17267339N,078279407E,060.0,073,0550,11,0,1,0,0,1,1,26,A,0000000000"), + position("2014-06-20 15:03:28.000", true, 17.44556, 78.46567)); + + verifyNull(decoder, text( + "$1,AP09BU9397,861785006462448,20,06,14,15,03,28,000000000,0000000000,000.0,000,0000,00,0,1,0,0,1,1,24,V,0000000000")); + + verifyNull(decoder, text( + "$1,1234567890,02,06,11,17,07,45,00000000,000000000,00.0,0,0,V")); + + verifyPosition(decoder, text( + "$1,1234567890,02,06,11,17,07,45,17267690N,078279340E,060.0,113,0,A")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java new file mode 100644 index 000000000..9422f6d74 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Vt200FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Vt200FrameDecoder decoder = new Vt200FrameDecoder(); + + verifyFrame( + binary("28631037309456208400340102dc0906171616454415760201144494473f920a0c0000030500200100417c1f383a9d1090510000006a00007000000e00180ee129"), + decoder.decode(null, null, binary("28631037309456208400340102dc0906171616454415760201144494473f920a0c0000030500200100417c1f383a9d1090510000006a00007000000e00180ee129"))); + + verifyFrame( + binary("28631037309456208400340102f51306171327294418267501208948170231071f0000044300200100005f02180000667500000000000000000000080000624629"), + decoder.decode(null, null, binary("28631037309456208400340102f513061713273d144418267501208948170231071f0000044300200100005f02180000667500000000000000000000080000624629"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java new file mode 100644 index 000000000..9c224bc8e --- /dev/null +++ b/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java @@ -0,0 +1,60 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Vt200ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Vt200ProtocolDecoder decoder = new Vt200ProtocolDecoder(null); + + verifyPosition(decoder, binary( + "28192030961807208200210101b919011818375801245774036424612500160917000003aa008800007b00aa3429")); + + verifyNull(decoder, binary( + "286310373094563082002701033d010817143327c68a14841e00c27f550e9a000000000c000000084700200120007d01af260b29")); + + verifyAttributes(decoder, binary( + "2863103730945630880062033d862631037309456f222014604362936f010817140954010817144135076b00002a3800003b7d6127cc91040000000000000000000000005a0000088e000001ce02630000263b000009b401ff00000cb40000069c02af000018190200000102019729")); + + verifyPosition(decoder, binary( + "286310373094562086002101033d010817143328441790420114817637207d090a00000847002001207f00d6f229")); + + verifyPosition(decoder, binary( + "286310373094562086002101033d0108171433354417932101148139772c9d080a00000847002001207f00dc6729")); + + verifyNull(decoder, binary( + "2863103730945600880012180108171433004418103801148375470000dd29")); + + verifyNull(decoder, binary( + "28631037309456108800002e29")); + + verifyAttributes(decoder, binary( + "2863103730945630880062033c862631037309456f222014604362936f01081713365601081713571904c800001b2c000034f66827f0840000000000000000000000000047000006e7000001b9022a000023ff000007f2018a00000a10000003f300cd00000d8d0300000302002729")); + + verifyNull(decoder, binary( + "28631037309456008e000801042307171804584229")); + + verifyNull(decoder, binary( + "28631037309456108800002e29")); + + verifyPosition(decoder, binary( + "28631037309456208200210103302307171805444417097301147188170198090f0000073a002000007e00074429")); + + verifyNull(decoder, binary( + "286310373094563089001200032f2107171740144417075001147188872c29")); + + verifyAttributes(decoder, binary( + "2863103730945630880062032f862631037309456f222014604362936f21071717373221071717401400a100000cd700000004020d3c8e0000000000000000000000000000000000000000000000000000000000000000000a000000040000000e009700000cc9000000000000e929")); + + verifyPosition(decoder, binary( + "28631037309456208400340102dc0906171616454415760201144494473f920a0c0000030500200100417c1f383a9d1090510000006a00007000000e00180ee129")); + + verifyPosition(decoder, binary( + "28631037309456208400340102dc090617161654441577230114439597368c0a0c0000030500200100417c1baa349d3290510000006a00007000003d15004c11c629")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java new file mode 100644 index 000000000..a5eb0b49b --- /dev/null +++ b/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class VtfmsFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + VtfmsFrameDecoder decoder = new VtfmsFrameDecoder(); + + assertEquals( + buffer("(863071010087648,0HK44,00,000,14,2,9,,A,114946,180313,11.0244,076.9768,282,000,00000,00000,K,0000128,1,12.8,,200,2.501,,4.001,0,0,0,0,0,0,0,,)105"), + decoder.decode(null, null, buffer("(863071010087648,0HK44,00,000,14,2,9,,A,114946,180313,11.0244,076.9768,282,000,00000,00000,K,0000128,1,12.8,,200,2.501,,4.001,0,0,0,0,0,0,0,,)105"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java new file mode 100644 index 000000000..ede5dc7ac --- /dev/null +++ b/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class VtfmsProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + VtfmsProtocolDecoder decoder = new VtfmsProtocolDecoder(null); + + verifyPosition(decoder, text( + "(861359037432331,0EF87,00,0,21,2,01,,A,154559,230119,1101.4046,07656.3859,241,000,00078,00000,K,0000812,1,12.7,,,,,,1,0,0,0,1,1,1,+919566531111*+919994462226,)054"), + position("2019-01-23 15:45:59.000", true, 11.02341, 76.93977)); + + verifyPosition(decoder, text( + "(865733028143493,00I76,00,000,,,,,A,133755,210617,10.57354,077.24912,SW,000,00598,00000,K,0017368,1,12.7,,,0.000,,,0,0,0,0,1,1,0,,)074")); + + verifyPosition(decoder, text( + "(863071010087648,0HK44,00,000,14,2,9,,A,114946,180313,11.0244,076.9768,282,000,00000,00000,K,0000128,1,12.8,,200,2.501,,4.001,0,0,0,0,0,0,0,,)105")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java new file mode 100644 index 000000000..4e40eea86 --- /dev/null +++ b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java @@ -0,0 +1,35 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class WatchFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + WatchFrameDecoder decoder = new WatchFrameDecoder(); + + verifyFrame( + binary("5b33472a3335323636313039303134333135302a303030412a4c4b2c302c302c3130305d"), + decoder.decode(null, null, binary("5b33472a3335323636313039303134333135302a303030412a4c4b2c302c302c3130305d"))); + + verifyFrame( + binary("5b33472a383330383430363237392a303030382a72636170747572655d"), + decoder.decode(null, null, binary("5b33472a383330383430363237392a303030382a72636170747572655d"))); + + verifyFrame( + binary("5b33472a383330383430363237392a303030392a4c4b2c302c302c38345d"), + decoder.decode(null, null, binary("5b33472a383330383430363237392a303030392a4c4b2c302c302c38345d"))); + + verifyFrame( + binary("5b5a4a2a3031343131313030313335303330342a303033342a303030392a4c4b2c302c302c31395d"), + decoder.decode(null, null, binary("5b5a4a2a3031343131313030313335303330342a303033342a303030392a4c4b2c302c302c31395d"))); + + verifyFrame( + concatenateBuffers(buffer("[CS*1234567890*000e*TK,#!AMR"), binary("7d5b5d2c2aff"), buffer("]")), + decoder.decode(null, null, concatenateBuffers(buffer("[CS*1234567890*000e*TK,#!AMR"), binary("7d017d027d037d047d05ff"), buffer("]")))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java new file mode 100644 index 000000000..539e63253 --- /dev/null +++ b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java @@ -0,0 +1,128 @@ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import org.junit.Test; +import org.traccar.Context; +import org.traccar.ProtocolTest; +import org.traccar.model.Position; + +import static org.junit.Assert.assertEquals; + +public class WatchProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + WatchProtocolDecoder decoder = new WatchProtocolDecoder(null); + + verifyPosition(decoder, buffer( + "[ZJ*014111001332708*0075*0064*AL,040418,052156,A,22.536207,N,113.938673,E,0,0,0,5,100,82,1000,50,00100000,1,255,460,0,9340,3663,35]")); + + verifyPosition(decoder, buffer( + "[SG*352661090143150*006C*UD,150817,132115,V,28.435142,N,81.354333,W,2.2038,000,99,00,70,100,0,50,00000000,1,1,310,260,1091,30082,139,,00]")); + + verifyAttributes(decoder, buffer( + "[3G*4700609403*0013*bphrt,120,79,73,,,,]")); + + verifyPosition(decoder, buffer( + "[3G*8308373902*0080*AL,230817,095346,A,47.083950,N,15.4821850,E,7.60,273.8,0.0,4,15,44,0,0,00200010,2,255,232,1,7605,42530,118,7605,58036,119,0,65.8]")); + + verifyPosition(decoder, buffer( + "[SG*9051007430*006C*UD,150817,132115,V,28.435142,N,81.354333,W,2.2038,000,99,00,70,100,0,50,00000000,1,1,310,260,1091,30082,139,,00]")); + + verifyPosition(decoder, buffer( + "[3G*6005412902*011F*WT,170517,133811,V,18.512200,N,73.7750283,E,0.00,0.0,0.0,0,92,82,4262,0,00000010,2,1,404,22,10125,8301,141,10125,13921,122,5,Skynet,28:c6:8e:be:87:c0,-60,Intel Wi-Fi,4c:60:de:32:3d:38,-70,Nirvanic-2,40:e3:d6:4a:d9:c2,-73,A4-Guest,40:e3:d6:4a:d9:c4,-73,A4Idatix,40:e3:d6:4a:d9:c3,-73,13.8]")); + + verifyPosition(decoder, buffer( + "[3G*8308406279*00CC*UD3,170417,190930,V,54.739618,N,25.273213,E,0.0,323.53,175.1,6,51,83,0,0,00000000,1,1,246,01,200,13242758,51,3,TEO-189835,00:8c:54:58:1d:64,-84,Cgates_7137,78:54:2e:e3:71:37,-85,ASUS,9c:5c:8e:b8:d4:78,-93]")); + + verifyPosition(decoder, buffer( + "[SG*9051004074*0058*AL,120117,145602,V,40.058413,N,76.336618,W,11.519,188,99,00,01,80,0,50,00000000,0,1,0,0,,10]")); + + verifyPosition(decoder, buffer( + "[SG*9051000884*009B*UD,030117,161129,V,52.745450,N,0.369512,,0.1481,000,99,00,70,5,0,50,00000000,5,1,234,15,893,3611,135,893,3612,132,893,3993,131,893,30986,129,893,40088,126,,00]")); + + verifyPosition(decoder, buffer( + "[3G*6430073509*00E7*UD2,241016,081622,V,09.951861,N,-84.1422119,W,0.00,0.0,0.0,0,39,94,0,0,00000000,1,0,712,3,2007,18961,123,4,Luz,00:23:6a:34:ee:76,-70,familia,b0:c5:54:b9:90:ef,-78,fam salas delgado,fc:b4:e6:5d:50:ea,-81,QWERTY,c8:3a:35:43:0f:e8,-93]")); + + verifyPosition(decoder, buffer( + "[3G*6105117105*008D*UD2,210716,231601,V,-33.480366,N,-70.7630692,E,0.00,0.0,0.0,0,100,34,0,0,00000000,3,255,730,2,29731,54315,167,29731,54316,162,29731,54317,145]"), + position("2016-07-21 23:16:01.000", false, -33.48037, -70.76307)); + + verifyPosition(decoder, buffer( + "[3G*4700222306*0077*UD,120316,140610,V,48.779045,N, 9.1574736,E,0.00,0.0,0.0,0,25,83,0,0,00000000,2,255,262,1,21041,9067,121,21041,5981,116]")); + + verifyPosition(decoder, buffer( + "[3G*4700222306*011F*UD2,120316,140444,A,48.779045,N, 9.1574736,E,0.57,12.8,0.0,7,28,77,0,0,00000000,2,2,262,1,21041,9067,121,21041,5981,116,5,WG-Superlativ,34:31:c4:c8:a9:22,-67,EasyBox-28E858,18:83:bf:28:e8:f4,-70,MoMaXXg,be:05:43:b7:19:15,-72,MoMaXX2,bc:05:43:b7:19:15,-72,Gastzugang,18:83:bf:28:e8:f5,-72]")); + + verifyNull(decoder, buffer( + "[SG*9081000548*0009*LK,0,100]")); + + verifyPosition(decoder, buffer( + "[SG*9081000548*00A9*UD,110116,113639,V,16.479064,S,68.119072,,0.7593,000,99,00,80,80,0,50,00000000,5,1,736,2,10103,10732,153,10103,11061,152,10103,11012,152,10103,10151,150,10103,10731,143,,00]")); + + verifyPosition(decoder, buffer( + "[3G*2256002206*0079*UD2,100116,153723,A,38.000000,N,-9.000000,W,0.44,299.3,0.0,7,100,86,0,0,00000008,2,0,268,3,3010,51042,146,3010,51043,132]")); + + verifyNull(decoder, buffer( + "[3G*8800000015*0003*TKQ]")); + + verifyPosition(decoder, buffer( + "[3G*4700186508*00B1*UD,301015,084840,V,45.853100,N,14.6224899,E,0.00,0.0,0.0,0,84,61,0,11,00000008,7,255,293,70,60,6453,139,60,6432,139,60,6431,132,60,6457,127,60,16353,126,60,6451,121,60,16352,118]")); + + verifyNull(decoder, buffer( + "[SG*8800000015*0002*LK]")); + + verifyAttributes(decoder, buffer( + "[3G*4700186508*000B*LK,0,10,100]")); + + verifyPosition(decoder, buffer( + "[SG*8800000015*0087*UD,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141]"), + position("2014-04-22 13:46:52.000", true, 22.57171, 113.86140)); + + verifyPosition(decoder, buffer( + "[SG*8800000015*0087*UD,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141]")); + + verifyPosition(decoder, buffer( + "[SG*8800000015*0088*UD2,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0000,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141]")); + + verifyPosition(decoder, buffer( + "[SG*8800000015*0087*AL,220414,134652,A,22.571707,N,113.8613968,E,0.1,0.0,100,7,60,90,1000,50,0001,4,1,460,0,9360,4082,131,9360,4092,148,9360,4091,143,9360,4153,141]")); + + verifyAttributes(decoder, buffer( + "[CS*8800000015*0008*PULSE,72]")); + + verifyAttributes(decoder, buffer( + "[3G*6005412902*0007*heart,0]")); + + verifyAttributes(decoder, buffer( + "[3G*6005412902*0008*heart,71]")); + + verifyPosition(decoder, buffer( + "[ZJ*014111001350304*0033*0064*UD,070318,020827,V,00.000000,N,000.000000,E,0,0,0,0,100,19,1000,50,00000000,1,255,460,0,9346,5223,42]")); + + verifyPosition(decoder, buffer( + "[ZJ*014111001350304*0035*0097*UD,070318,020857,V,00.000000,N,000.000000,E,0,0,0,0,100,19,1000,50,00000000,5,255,460,0,9346,5223,42,9346,5214,21,9784,4083,13,9346,5222,11,9346,5221,8]")); + + verifyPosition(decoder, buffer( + "[ZJ*014111001350304*0038*008a*UD,070318,021027,V,00.000000,N,000.000000,E,0,0,0,0,100,18,1000,50,00000000,4,255,460,0,9346,5223,42,9346,5214,20,9784,4083,11,9346,5221,5]")); + + } + + @Test + public void testDecodeVoiceMessage() throws Exception { + + WatchProtocolDecoder decoder = new WatchProtocolDecoder(null); + + verifyNull(decoder.decode(null, null, buffer("[CS*1234567890*0004*TK,1]"))); + + ByteBuf data = binary("7d5b5d2c2aff"); + + Object decodedObject = decoder.decode(null, null, concatenateBuffers(buffer("[CS*1234567890*000e*TK,#!AMR"), data.resetReaderIndex(), buffer("]"))); + assertEquals("1234567890/mock.amr", ((Position) decodedObject).getAttributes().get("audio")); + + verifyFrame(concatenateBuffers(buffer("#!AMR"), data.resetReaderIndex()), ((MockMediaManager) Context.getMediaManager()).readFile("1234567890/mock.amr")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java new file mode 100644 index 000000000..a0631be3b --- /dev/null +++ b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java @@ -0,0 +1,83 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +public class WatchProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + WatchProtocolEncoder encoder = new WatchProtocolEncoder(); + + Command command; + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_REBOOT_DEVICE); + verifyFrame(buffer("[CS*123456789012345*0005*RESET]"), encoder.encodeCommand(null, command)); + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SOS_NUMBER); + command.set(Command.KEY_INDEX, 1); + command.set(Command.KEY_PHONE, "123456789"); + verifyFrame(buffer("[CS*123456789012345*000e*SOS1,123456789]"), encoder.encodeCommand(null, command)); + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_VOICE_MESSAGE); + command.set(Command.KEY_DATA, "2321414d520a2573"); + verifyFrame(buffer("[CS*123456789012345*000b*TK,#!AMR\n%s]"), encoder.encodeCommand(null, command)); + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_VOICE_MESSAGE); + command.set(Command.KEY_DATA, "7d5b5d2c2a"); + verifyFrame(concatenateBuffers(buffer("[CS*123456789012345*000d*TK,"), binary("7d017d027d037d047d05"), buffer("]")), encoder.encodeCommand(null, command)); + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_VOICE_MESSAGE); + command.set(Command.KEY_DATA, "ff"); + verifyFrame(concatenateBuffers(buffer("[CS*123456789012345*0004*TK,"), binary("ff"), buffer("]")), encoder.encodeCommand(null, command)); + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_MESSAGE); + command.set(Command.KEY_MESSAGE, "text"); + verifyFrame(buffer("[CS*123456789012345*0018*MESSAGE,0074006500780074]"), encoder.encodeCommand(null, command)); + + command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "WORK,6-9,11-13,13-15,17-19"); + verifyFrame(buffer("[CS*123456789012345*001a*WORK,6-9,11-13,13-15,17-19]"), encoder.encodeCommand(null, command)); + + } + + @Test + public void testEncodeTimezone() { + + WatchProtocolEncoder encoder = new WatchProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_SET_TIMEZONE); + + command.set(Command.KEY_TIMEZONE, "Europe/Amsterdam"); + verifyFrame(buffer("[CS*123456789012345*0006*LZ,,+1]"), encoder.encodeCommand(null, command)); + + command.set(Command.KEY_TIMEZONE, "GMT+01:30"); + verifyFrame(buffer("[CS*123456789012345*0008*LZ,,+1.5]"), encoder.encodeCommand(null, command)); + + command.set(Command.KEY_TIMEZONE, "Atlantic/Azores"); + verifyFrame(buffer("[CS*123456789012345*0006*LZ,,-1]"), encoder.encodeCommand(null, command)); + + command.set(Command.KEY_TIMEZONE, "GMT-11:30"); + verifyFrame(buffer("[CS*123456789012345*0009*LZ,,-11.5]"), encoder.encodeCommand(null, command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java new file mode 100644 index 000000000..40b0469ea --- /dev/null +++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java @@ -0,0 +1,67 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class WialonProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + WialonProtocolDecoder decoder = new WialonProtocolDecoder(null); + + verifyNull(decoder, text( + "#L#2.0;42001300083;;CE45")); + + verifyNull(decoder, text( + "#L#123456789012345;test")); + + verifyNull(decoder, text( + "#L#2002;NA")); + + verifyNull(decoder, text( + "#P#")); + + verifyPosition(decoder, text( + "#D#101118;061143;0756.0930;N;12338.6403;E;18.223;99.766;-4.000;10;0.800;NA;NA;NA;NA;101_521347:1:521249,101_521126:1:6593598,101_521127:1:774780,101_521072_21.1:1:0,101_521072_21.2:1:71353;F24A")); + + verifyPosition(decoder, text( + "#D#151216;135910;5321.1466;N;04441.7929;E;87;156;265.000000;12;1.000000;241;NA;NA;NA;odo:2:0.000000,total_fuel:1:430087,can_fls:1:201,can_taho:1:11623,can_mileage:1:140367515")); + + verifyPosition(decoder, text( + "#D#151216;140203;5312.59514;N;04830.37834;E;53;273;NA;10;NA;NA;NA;NA;NA;EvId:1:1,Board:2:12.81,Accum:2:4.28")); + + verifyPosition(decoder, text( + "#SD#270413;205601;5544.6025;N;03739.6834;E;1;2;3;4"), + position("2013-04-27 20:56:01.000", true, 55.74338, 37.66139)); + + verifyPosition(decoder, text( + "#SD#021214;065947;2237.7552;N;11404.8851;E;0.000;;170.9;5")); + + verifyPosition(decoder, text( + "#D#270413;205601;5544.6025;N;03739.6834;E;1;2;3;4;0.0;0;0;14.77,0.02,3.6;NA;count1:1:564,fuel:2:45.8,hw:3:V4.5")); + + verifyPosition(decoder, text( + "#D#190114;051312;4459.6956;N;04105.9930;E;35;306;204.000000;12;NA;452986639;NA;106.000000;NA;sats_gps:1:9,sats_glonass:1:3,balance:2:12123.000000,stay_balance:1:0")); + + verifyPosition(decoder, text( + "#D#021214;065947;2237.7552;N;11404.8851;E;0.000;;170.9;5;1.74;NA;NA;NA;NA;NA")); + + verifyPosition(decoder, text( + "#D#021214;065947;2237.7552;N;11404.8851;E;0.000;;170.9;5;1.74;NA;NA;;NA;NA")); + + verifyPositions(decoder, text( + "#B#080914;073235;5027.50625;N;03026.19321;E;0.700;0.000;NA;4;NA;NA;NA;;NA;Батарея:3:100 %|080914;073420;5027.50845;N;03026.18854;E;1.996;292.540;NA;4;NA;NA;NA;;NA;Батарея:3:100 %")); + + verifyPositions(decoder, text( + "#B#110914;102132;5027.50728;N;03026.20369;E;1.979;288.170;NA;NA;NA;NA;NA;;NA;Батарея:3:100 %")); + + verifyPositions(decoder, text( + "#B#110315;045857;5364.0167;N;06127.8262;E;0;155;965;7;2.40;4;0;;NA;Uacc:2:3.4,Iacc:2:0.000,Uext:2:13.2,Tcpu:2:14.4,Balance:2:167.65,GPS:3:Off")); + + verifyPositions(decoder, text( + "#B#110315;045857;5364.0167;N;06127.8262;E;0;155;965;7;2.40;4;0;14.77,0.02,3.6;AB45DF01145;")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java new file mode 100644 index 000000000..642473f2d --- /dev/null +++ b/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java @@ -0,0 +1,28 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class WondexFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + WondexFrameDecoder decoder = new WondexFrameDecoder(); + + assertNull( + decoder.decode(null, null, binary("f0d70b0001ca9a3b"))); + + assertEquals( + binary("313034343938393630312c32303133303332333039353531352c31332e3537323737362c35322e3430303833382c302c3030302c37322c302c32"), + decoder.decode(null, null, binary("313034343938393630312c32303133303332333039353531352c31332e3537323737362c35322e3430303833382c302c3030302c37322c302c320d0a"))); + + assertEquals(binary("d0d70b0001ca9a3b"), + decoder.decode(null, null, binary("d0d70b0001ca9a3b"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java new file mode 100644 index 000000000..f01a763a1 --- /dev/null +++ b/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java @@ -0,0 +1,62 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class WondexProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + WondexProtocolDecoder decoder = new WondexProtocolDecoder(null); + + verifyPosition(decoder, buffer( + "2000000108,20151030145404,76.948633,43.354700,0,140,15,100,1,1325,125.4,10.5,0.0"), + position("2015-10-30 14:54:04.000", true, 43.35470, 76.94863)); + + verifyPosition(decoder, buffer( + "2000000257,20151030145351,69.379976,53.283905,0,0,16,2,0,0,469.1,58.9,0.0"), + position("2015-10-30 14:53:51.000", true, 53.28390, 69.37998)); + + verifyPosition(decoder, buffer( + "2000000232,20151030145206,51.166900,43.651353,0,132,11,2,0,0,0.0,0.0,0.0")); + + verifyPosition(decoder, buffer( + "2000000259,20151030145653,69.380826,53.283890,9,10,15,2,1,695,1002.6,108.2,0.0")); + + verifyPosition(decoder, buffer( + "1044989601,20130323074605,0.000000,90.000000,0,000,0,0,2")); + + verifyPosition(decoder, buffer( + "123456789000001,20120101123200,130.000000,60.000000,0,000,0,0,0,0")); + + verifyPosition(decoder, buffer( + "210000001,20070313170040,121.123456,12.654321,0,233,0,9,2,0.0,0,0.00,0.00,0")); + + verifyPosition(decoder, buffer( + "1044989601,20130322172647,13.572583,52.401070,22,204,49,0,2")); + + verifyPosition(decoder, buffer( + "1044989601,20130322172647,13.572583,52.401070,22,204,-49,0,2")); + + verifyPosition(decoder, buffer( + "3997324533,20140326074908,28.797603,47.041635,0,48,0,6,2,3.90V,0")); + + verifyPosition(decoder, buffer( + "2000000001,20140529213210,-63.179111,9.781493,0,0,54.0,8,2,0.0,0,0.01,0.01,0,0,0,0")); + + verifyNotNull(decoder, buffer( + "$OK:VER=M7 2.003 DVB rev02c,V2")); + + verifyNotNull(decoder, buffer( + "$OK:REBOOT")); + + verifyNotNull(decoder, buffer( + "$ERR:GETLOCATION=1")); + + verifyNull(decoder, binary( + "d0d70b0001ca9a3b")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java new file mode 100644 index 000000000..8209fc412 --- /dev/null +++ b/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class WondexProtocolEncoderTest extends ProtocolTest { + @Test + public void testEncode() throws Exception { + + WondexProtocolEncoder encoder = new WondexProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(2); + command.setType(Command.TYPE_POSITION_SINGLE); + command.set(Command.KEY_DEVICE_PASSWORD, "0000"); + + assertEquals("$WP+GETLOCATION=0000", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java new file mode 100644 index 000000000..5635ce3d4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java @@ -0,0 +1,36 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class WristbandProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + WristbandProtocolDecoder decoder = new WristbandProtocolDecoder(null); + + verifyNotNull(decoder, binary( + "000102004459583836383730343034343735303035357c56312e307c317c7b4630342331382c30372c332c3539303139322c33303a31382c30372c332c3539303139322c33307d0d0afffefc")); + + verifyNotNull(decoder, binary( + "000102009c59583836383730343034343735303035357c56312e307c317c7b4630332330383a30353a38313a64383a31383a38372c2d37365f30303a37663a32383a63373a62613a63312c2d37375f39633a33643a63663a65643a62643a36622c2d36335f64383a65623a39373a65653a37373a32342c2d38327c31382c30372c332c3539303735342c33303a31382c30372c332c3539303735342c33307d0d0afffefc")); + + verifyNull(decoder, binary( + "000102002259583836383730343034343735303035357c56312e307c307c7b46363423317d0d0afffefc")); + + verifyPositions(decoder, binary( + "00010200bc59583836383730343034343735303035357c56312e307c317c7b4630322337372e3437373831372c2d33382e3839363239322c3230313831323239313235352c302e35387c37372e3437373739362c2d33382e3839363234352c3230313831323239313235352c302e30307c37372e3437373738392c2d33382e3839363233322c3230313831323239313235352c302e30307c37372e3437373737362c2d33382e3839363232322c3230313831323239313235352c302e30307d0d0afffefc")); + + verifyNull(decoder, binary( + "000102004759583836383730343034343735303035357c56312e307c317c7b463931233331305f30307c30307c30307c30307c57414e444149323031382f31322f31342031353a35367d0d0afffefc")); + + verifyNull(decoder, binary( + "000102004159583336373535313631303030303934347c56312e307c317c7b4639312330317c30307c30307c33475f7065745f323031382f30352f31362031313a30307d0d0afffefc")); + + verifyPositions(decoder, false, binary( + "000102003559583836383730343034343735303035357c56312e307c317c7b4630312339342c312c3130302c302c33313030302c3930307d0d0afffefc")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java b/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java new file mode 100644 index 000000000..8fc628bdb --- /dev/null +++ b/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +import static org.junit.Assert.assertEquals; + +public class XexunFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + XexunFrameDecoder decoder = new XexunFrameDecoder(); + + assertEquals( + binary("4750524d432c3230353933352e3030302c412c353134302e343335302c4e2c3530312e303638362c452c302e30302c302e30302c3132313031352c30302c303030302e302c412a37302c462c2c696d65693a3335393538373031343731383339322c"), + decoder.decode(null, null, binary("313531303132313435392c2b33313635323435343932372c4750524d432c3230353933352e3030302c412c353134302e343335302c4e2c3530312e303638362c452c302e30302c302e30302c3132313031352c30302c303030302e302c412a37302c462c2c696d65693a3335393538373031343731383339322c31323249"))); + + assertEquals( + binary("4750524d432c3130333733312e3633362c412c343534352e353236362c4e2c30303434382e383235392c452c32312e31322c3237362e30312c3135303631352c2c2c412a35372c4c2c2c20696d65693a3031333934393030323032363637352c"), + decoder.decode(null, null, binary("3135303631353132333733312c2b33333634373338343631312c4750524d432c3130333733312e3633362c412c343534352e353236362c4e2c30303434382e383235392c452c32312e31322c3237362e30312c3135303631352c2c2c412a35372c4c2c2c20696d65693a3031333934393030323032363637352c30342c333532322e392c463a332e3732562c302c3134322c32313734342c3230382c30312c303730322c394338430a0d"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java new file mode 100644 index 000000000..8b0f245a2 --- /dev/null +++ b/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java @@ -0,0 +1,118 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class XexunProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + XexunProtocolDecoder decoder = new XexunProtocolDecoder(null, false); + + verifyAttributes(decoder, text( + "GPRMC,.000,A,0.000000,S,0.0000,W,0.00,0.00,,00,0000.0,A*55,L,,imei:353579010727036,")); + + verifyPosition(decoder, text( + "GPRMC,113518.000,A,5303.4150,N,10.2368,E,60.73,207.42,260216,00,0000.0,A*74,F,,imei:351525018007873,")); + + verifyPosition(decoder, text( + "GPRMC,215853.000,A,5304.9600,N,6.7907,E,1.43,80.67,250216,00,0000.0,A*47,F,,imei:351525018007873,")); + + verifyPosition(decoder, text( + "GPRMC,121535.000,A,5417.2666,N,04822.1264,E,1.452,30.42,031014,0.0,A*4D\r\n,L,imei:355227042011730,")); + + verifyPosition(decoder, text( + "GPRMC,150120.000,A,3346.4463,S,15057.3083,E,0.0,117.4,010911,,,A*76,F,imei:351525010943661,"), + position("2011-09-01 15:01:20.000", true, -33.77411, 150.95514)); + + verifyPosition(decoder, text( + "GPRMC,010203.000,A,0102.0003,N,00102.0003,E,1.02,1.02,010203,,,A*00,F,,imei:10000000000000,")); + + verifyPosition(decoder, text( + "GPRMC,233842.000,A,5001.3060,N,01429.3243,E,0.00,,210211,,,A*74,F,imei:354776030495631,")); + + verifyPosition(decoder, text( + "GPRMC,080303.000,A,5546.7313,N,03738.6005,E,0.56,160.13,100311,,,A*6A,L,imei:354778030461167,")); + + verifyPosition(decoder, text( + "GPRMC,220828.678,A,5206.1446,N,02038.2403,,0,0,160912,,,E*23,L,imei:358948012501019,")); + + verifyPosition(decoder, text( + "GNRMC,134418.000,A,5533.8973,N,03745.4398,E,0.00,308.85,160215,,,A*7A,F,, imei:864244028033115,")); + + verifyPosition(decoder, text( + "GPRMC,093341.000,A,1344.5716,N,10033.6648,E,0.00,0.00,240215,,,A*68,F,,imei:865328028306149,")); + + verifyPosition(decoder, text( + "GPRMC,103731.636,A,4545.5266,N,00448.8259,E,21.12,276.01,150615,,,A*57,L,, imei:013949002026675,")); + + verifyPosition(decoder, text( + "GPRMC,014623.000,A,4710.8260,N,1948.1220,E,0.11,105.40,111212,00,0000.0,A*49,F,,imei:357713002048962,")); + + verifyPosition(decoder, text( + "GPRMC,043435.000,A,811.299200,S,11339.9500,E,0.93,29.52,160313,00,0000.0,A*65,F,,imei:359585014597923,")); + + decoder = new XexunProtocolDecoder(null, true); + + verifyPosition(decoder, text( + "171007160505,,GPRMC,160505.000,A,5323.4680,N,00252.4202,W,000.0,129.7,071017,,,A*7A,F,ACCStart, imei:864504031916915,10,41.1,F:4.28V,1,135,19824,234,15,0062,B7D5")); + + verifyPosition(decoder, text( + "171007160525,,GPRMC,160525.000,A,5323.4680,N,00252.4202,W,000.0,129.7,071017,,,A*78,F,ACCStop, imei:864504031916915,10,41.1,F:4.28V,1,134,42896,234,15,0062,B7D5")); + + verifyPosition(decoder, text( + "170505103845,TELKOMSEL,GPRMC,103845.000,A,0340.2482,N,09841.9689,E,0.00,68.23,050517,,,A*5D,F,ACC On, imei:013227002782161,05,-8.2,F:4.22V,1,141,44712,510,10,2BE5,EC47")); + + verifyPosition(decoder, text( + "170607031932,+6282167979090,GPRMC,031932.000,A,0347.2515,N,09841.9433,E,0.00,261.22,070617,,,A*6C,F,ACC OFF, imei:013226004613135,11,23.1,F:4.25V,1,148,44989,510,10,2B34,0268")); + + verifyNull(decoder, text( + ",+48606717068,,L,, imei:012207005047292,,,F:4.28V,1,52,11565,247,01,000E,1FC5")); + + verifyPosition(decoder, text( + "130302125349,+79604870506,GPRMC,085349.000,A,4503.2392,N,03858.5660,E,6.95,154.65,020313,,,A*6C,F,, imei:012207007744243,03,-1.5,F:4.15V,1,139,28048,250,01,278A,5072"), + position("2013-03-02 08:53:49.000", true, 45.05399, 38.97610)); + + verifyPosition(decoder, text( + "111111120009,+436763737552,GPRMC,120009.590,A,4639.6774,N,01418.5737,E,0.00,0.00,111111,,,A*68,F,, imei:359853000144328,04,481.2,F:4.15V,0,139,2689,232,03,2725,0576")); + + verifyPosition(decoder, text( + "111111120009,+436763737552,GPRMC,120600.000,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,,,A*68,F,help me!, imei:123456789012345,04,481.2,F:4.15V,0,139,2689,232,03,2725,0576")); + + verifyPosition(decoder, text( + "111111120009,+436763737552,GPRMC,120600.000,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,,,A*68,F,help me!, imei:123456789012345,04,481.2,L:3.5V,0,139,2689,232,03,2725,0576")); + + verifyPosition(decoder, text( + "111111120009,436763737552,GPRMC,120600.000,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,,,A*68,F,help me!, imei:123456789012345,04,481.2,L:3.5V,0,139,2689,232,03,2725,0576")); + + verifyPosition(decoder, text( + "111111120009,+1234,GPRMC,204530.4,A,6000.0000,N,13000.0000,E,0.0,,010112,0.0,E,A*68,F,imei:123456789012345,04,123.5,F:3.55V,0,139,,232,03,272CE1,0576")); + + verifyPosition(decoder, text( + "111111120009,+1234,GPRMC,204530.4,A,6000.000,N,01000.6288,E,0.0,0.00,230713,0.0,E,A*3C,F,imei:123456789012345,00,,F:3.88V,0,125,,262,01,224CE1,379B")); + + verifyPosition(decoder, text( + "111111120009,+1234,GPRMC,215840.7,A,6000.000,N,01000.6253,E,0.0,0.00,230713,0.0,E,A*34,F,imei:123456789012345,00,,F:3.9V,0,124,,262,01,224CE1,379B")); + + verifyPosition(decoder, text( + "130725134142,,GPRMC,134142.591,A,3845.6283,N,00909.8876,W,2.08,287.33,250713,,,A*71,F,, imei:013227000526784,03,-50.7,L:3.69V,0,128,65337,268,03,177A,119F")); + + verifyPosition(decoder, text( + "140602152533,TESCO_INFO,GPRMC,152533.000,A,5145.4275,N,00000.3448,E,0.00,0.00,020614,,,A*66,F,, imei:013227002781643,06,35.1,F:4.15V,1,135,38950,234,10,10B4,5235")); + + verifyPosition(decoder, text( + "150216154418,5277,GNRMC,134418.000,A,5533.8973,N,03745.4398,E,0.00,308.85,160215,,,A*7A,F,, imei:864244028033115,10,169.8,F:4.28V,1,132,48269,250,99,6D0D,8572")); + + verifyPosition(decoder, text( + "150224173341,+66961544651,GPRMC,093341.000,A,1344.5716,N,10033.6648,E,0.00,0.00,240215,,,A*68,F,,imei:865328028306149,05,106.4,F:4.01V/ADC1=0.20V/ADC2=0.00V,0,159,955,520,01,5DE8,0399,6.21km")); + + verifyPosition(decoder, text( + "150316182840,07872167745,GPRMC,182840.000,A,5126.1310,N,00055.5573,W,0.00,0.00,160315,,,A*7C,F,,imei:865328023469306,06,54.3,F:4.10V/ADC1=0.76V/ADC2=0.00V,0,157,38486,234,10,34DC,48A6,3.70km")); + + verifyPosition(decoder, text( + "150615123731,+33647384611,GPRMC,103731.636,A,4545.5266,N,00448.8259,E,21.12,276.01,150615,,,A*57,L,, imei:013949002026675,04,3522.9,F:3.72V,0,142,21744,208,01,0702,9C8C")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java new file mode 100644 index 000000000..f795742fd --- /dev/null +++ b/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java @@ -0,0 +1,76 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class XirgoProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecodeCustom() throws Exception { + + XirgoProtocolDecoder decoder = new XirgoProtocolDecoder(null); + + decoder.setForm("UID,EV,D,T,LT,LN,AL,GSPT,HD,SV,HP,BV,CQ,GS,SI,IG,OT"); + + verifyPosition(decoder, text( + "$$183900034,4002,03/30/2019,02:15:22,46.848577,-114.022213,978,0.0,172.3,16,1.2,13.291,20,3,2,2,1##")); + + verifyPosition(decoder, text( + "$$184800793,4002,03/30/2019,02:10:13,46.848600,-114.022256,9723,0.0,1645,17,1.2,13.283,18,3,89011703278246523594,2,0##")); + + decoder.setForm("UID,EV,D,T,LT,LN,AL,GSPT,SV,HP,BV,CQ,MI,GS,SI,IG,OT"); + + verifyPosition(decoder, text( + "$$184800793,4002,03/15/2019,21:30:21,46.848582,-114.022237,9733,0.0,18,1.1,13.605,20,0,3,89011703278246523602,2,0##")); + + } + + @Test + public void testDecodeNew() throws Exception { + + XirgoProtocolDecoder decoder = new XirgoProtocolDecoder(null); + + verifyPosition(decoder, text( + "$$352054058132185,4001,2017/04/21,00:01:05,32.54659,-116.90670,143.2,0,0,0,598,0.0,12,0.9,765840,7.0,14.5,19,1,1,0011,8.5,63.2,5,21999,184,255,671,207,100,185##")); + + verifyPosition(decoder, text( + "$$352054058132185,6011,2017/04/21,04:57:10,32.49658,-116.85957,250.9,0,0,0,602,0.0,12,0.8,765876,7.0,14.1,21,1,1,0011,10.1,0.0,5,170917890,280,255,627,0,100,167##")); + + verifyPosition(decoder, text( + "$$355922061611345,6001,2016/08/25,20:10:51,51.13042,-114.22752,1197,44.7,0.0,0.0,2622,27,12,0.8,1,0.0,13.9,24,1,0,0.0,-70,-809,688##")); + + verifyPosition(decoder, text( + "$$355922061611345,6001,2016/08/25,20:10:38,51.12948,-114.22637,1203,34.8,0.0,0.0,1377,215,12,0.8,1,0.0,13.8,28,1,0,0.0,-309,-566,754##")); + + verifyPosition(decoder, text( + "$$354898045650537,6031,2015/02/26,15:47:26,33.42552,-112.30308,287.8,0,0,0,0,0.0,7,1.2,2,0.0,12.2,22,1,0,82.3")); + + verifyPosition(decoder, text( + "$$355922060162167,6015,2016/04/21,17:26:52,39.83267,-76.66139,230,0.0,0.0,0.0,779,0,8,1.2,0,0.0,13.0,19,1,1C4BJWDG4GL191009,X0z1-1137CD1,0402,3GATT,0,83.9,-70,-715,738##")); + + verifyPosition(decoder, text( + "$$355922060162167,4002,2016/04/21,17:04:50,39.83253,-76.66102,232,0.0,0.0,0.0,0,0,12,1.2,0,0.0,9.2,15,1,0,0.0,35,-8,1059##")); + + } + + @Test + public void testDecodeOld() throws Exception { + + XirgoProtocolDecoder decoder = new XirgoProtocolDecoder(null); + + verifyPosition(decoder, text( + "$$354660046140722,6001,2013/01/22,15:36:18,25.80907,-80.32531,7.1,19,165.2,11,0.8,11.1,17,1,1,3.9,2##"), + position("2013-01-22 15:36:18.000", true, 25.80907, -80.32531)); + + verifyPosition(decoder, text( + "$$357207059646786,4003,2015/05/19,15:54:56,-20.21422,-70.14927,37.5,1.8,0.0,11,0.8,12.9,31,297,1,0,0.0,0.0,0,1,1,1##")); + + verifyPosition(decoder, text( + "$$354898045650537,6031,2015/02/26,15:47:26,33.42552,-112.30308,287.8,0,0,0,0,0.0,7,1.2,2,0.0,12.2,22,1,0,82.3")); + + verifyPosition(decoder, text( + "$$357207059646786,4003,2015/05/19,15:55:27,-20.21421,-70.14920,33.6,0.4,0.0,11,0.8,12.9,31,297,1,0,0.0,0.0,0,1,1,1##")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java new file mode 100644 index 000000000..dd2e939c9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java @@ -0,0 +1,26 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class XirgoProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncode() throws Exception { + + XirgoProtocolEncoder encoder = new XirgoProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_OUTPUT_CONTROL); + command.set(Command.KEY_INDEX, 0); + command.set(Command.KEY_DATA, 1); + + assertEquals("+XT:7005,2,1", encoder.encodeCommand(command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java new file mode 100644 index 000000000..0f15f31b4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java @@ -0,0 +1,33 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Xrb28ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Xrb28ProtocolDecoder decoder = new Xrb28ProtocolDecoder(null); + + verifyAttributes(decoder, text( + "*SCOR,OM,123456789123456,Q0,412,80,28#")); + + verifyPosition(decoder, text( + "*SCOR,OM,867584030387299,D0,0,012102.00,A,0608.00062,S,10659.70331,E,12,0.69,151118,30.3,M,A#")); + + verifyAttributes(decoder, text( + "*SCOR,OM,863158022988725,H0,0,412,28,80,0#")); + + verifyAttributes(decoder, text( + "*HBCR,OM,123456789123456,R0,0,55,1234,1497689816#")); + + verifyPosition(decoder, text( + "*HBCR,OM,123456789123456,D0,0,124458.00,A,2237.7514,N,11408.6214,E,6,0.21,151216,10,M,A#")); + + verifyPosition(decoder, text( + "*SCOR,OM,863158022988725,D0,0,124458.00,A,2237.7514,N,11408.6214,E,6,0.21,151216,10,M,A#")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java new file mode 100644 index 000000000..49476d694 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java @@ -0,0 +1,39 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; +import org.traccar.model.Command; + +import static org.junit.Assert.assertEquals; + +public class Xrb28ProtocolEncoderTest extends ProtocolTest { + + @Test + public void testEncodePositionPeriodic() { + + Xrb28ProtocolEncoder encoder = new Xrb28ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_POSITION_PERIODIC); + command.set(Command.KEY_FREQUENCY, 300); + + assertEquals("\u00ff\u00ff*SCOS,OM,123456789012345,D1,300#\n", encoder.encodeCommand(null, command)); + + } + + @Test + public void testEncodeCustom() { + + Xrb28ProtocolEncoder encoder = new Xrb28ProtocolEncoder(); + + Command command = new Command(); + command.setDeviceId(1); + command.setType(Command.TYPE_CUSTOM); + command.set(Command.KEY_DATA, "S7,0,3,0,0,20,25"); + + assertEquals("\u00ff\u00ff*SCOS,OM,123456789012345,S7,0,3,0,0,20,25#\n", encoder.encodeCommand(null, command)); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java new file mode 100644 index 000000000..aa44929ab --- /dev/null +++ b/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Xt013ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Xt013ProtocolDecoder decoder = new Xt013ProtocolDecoder(null); + + verifyPosition(decoder, text( + "TK,862950021650364,150131090859,+53.267863,+5.767363,0,38,12,0,F,204,08,C94,336C,24,,4.09,1,,,,,,,,"), + position("2015-01-31 09:08:59.000", true, 53.26786, 5.76736)); + + verifyPosition(decoder, text( + "TK,862950021650364,150118113832,+53.267722,+5.767143,0,86,12,0,F,204,08,C94,336C,22,,4.21,1,,,,,,,,")); + + verifyPosition(decoder, text( + "HI,862950021650364TK,862950021650364,150118113832,+53.267722,+5.767143,0,86,12,0,F,204,08,C94,336C,22,,4.21,1,,,,,,,,")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java new file mode 100644 index 000000000..f4a78b5bd --- /dev/null +++ b/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java @@ -0,0 +1,25 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Xt2400ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Xt2400ProtocolDecoder decoder = new Xt2400ProtocolDecoder(null); + + decoder.setConfig("\n:wycfg pcr[0] 001001030406070809570a13121714100565\n"); + + verifyPosition(decoder, binary( + "000a344f1f0259766ae002074289f8f1c4b200e80000026712068000130000029300883559464255524845364650323433343235")); + + decoder.setConfig("\n:wycfg pcr[0] 000f01030406070809570a131217141005\n"); + + verifyPosition(decoder, binary( + "0009c4fb9b0b58a771e4020742d9f8f1c4c300bc0000000011077c0015000000000001")); + + } + +} diff --git a/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java new file mode 100644 index 000000000..332d15fa5 --- /dev/null +++ b/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java @@ -0,0 +1,31 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class YwtProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + YwtProtocolDecoder decoder = new YwtProtocolDecoder(null); + + verifyPosition(decoder, text( + "%RP,1222102985:1,170509033842,E102.146563,N14.582175,,0,320,10,0,00-00-00-00-00-00-00-00-00-00-00-00,,1db2-02b3-52004,3>941.523-32,7>1,19>-16,20>30.9V")); + + verifyNull(decoder, text( + "%SN,0417061042:0,0,140117041203,404")); + + verifyPosition(decoder, text( + "%GP,3000012345:0,090723182813,E114.602345,N22.069725,,30,160,4,0,00,,2794-10FF-46000,3>0-0")); + + verifyPosition(decoder, text( + "%RP,3000012345:0,090807182815,E114.602345,N22.069725,,30,160,4,0,00"), + position("2009-08-07 18:28:15.000", true, 22.06973, 114.60235)); + + verifyPosition(decoder, text( + "%KP,3000012345:0,090807183115,E114.602345,N22.069725,,30,160,5,0,00;")); + + } + +} diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java new file mode 100644 index 000000000..01b9c276f --- /dev/null +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -0,0 +1,390 @@ +package org.traccar.reports; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.TimeZone; + +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.TestIdentityManager; +import org.traccar.model.Position; +import org.traccar.reports.model.StopReport; +import org.traccar.reports.model.TripReport; +import org.traccar.reports.model.TripsConfig; + +public class ReportUtilsTest extends BaseTest { + + private Date date(String time) throws ParseException { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat.parse(time); + } + + private Position position(String time, double speed, double totalDistance) throws ParseException { + + Position position = new Position(); + + position.setTime(date(time)); + position.setValid(true); + position.setSpeed(speed); + position.set(Position.KEY_TOTAL_DISTANCE, totalDistance); + + return position; + } + + @Test + public void testCalculateDistance() { + Position startPosition = new Position(); + startPosition.set(Position.KEY_TOTAL_DISTANCE, 500.0); + Position endPosition = new Position(); + endPosition.set(Position.KEY_TOTAL_DISTANCE, 700.0); + assertEquals(ReportUtils.calculateDistance(startPosition, endPosition), 200.0, 10); + startPosition.set(Position.KEY_ODOMETER, 50000); + endPosition.set(Position.KEY_ODOMETER, 51000); + assertEquals(ReportUtils.calculateDistance(startPosition, endPosition), 1000.0, 10); + } + + @Test + public void testCalculateSpentFuel() { + Position startPosition = new Position(); + Position endPosition = new Position(); + assertEquals(ReportUtils.calculateFuel(startPosition, endPosition), 0.0, 0.01); + startPosition.set(Position.KEY_FUEL_LEVEL, 0.7); + endPosition.set(Position.KEY_FUEL_LEVEL, 0.5); + assertEquals(ReportUtils.calculateFuel(startPosition, endPosition), 0.2, 0.01); + } + + @Test + public void testDetectTripsSimple() throws ParseException { + + List data = Arrays.asList( + position("2016-01-01 00:00:00.000", 0, 0), + position("2016-01-01 00:01:00.000", 0, 0), + position("2016-01-01 00:02:00.000", 10, 0), + position("2016-01-01 00:03:00.000", 10, 1000), + position("2016-01-01 00:04:00.000", 10, 2000), + position("2016-01-01 00:05:00.000", 0, 3000), + position("2016-01-01 00:06:00.000", 0, 3000), + position("2016-01-01 00:07:00.000", 0, 3000)); + + TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01); + + Collection trips = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class); + + assertNotNull(trips); + assertFalse(trips.isEmpty()); + + TripReport itemTrip = trips.iterator().next(); + + assertEquals(date("2016-01-01 00:02:00.000"), itemTrip.getStartTime()); + assertEquals(date("2016-01-01 00:05:00.000"), itemTrip.getEndTime()); + assertEquals(180000, itemTrip.getDuration()); + assertEquals(10, itemTrip.getAverageSpeed(), 0.01); + assertEquals(10, itemTrip.getMaxSpeed(), 0.01); + assertEquals(3000, itemTrip.getDistance(), 0.01); + + Collection stops = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class); + + assertNotNull(stops); + assertFalse(stops.isEmpty()); + + Iterator iterator = stops.iterator(); + + StopReport itemStop = iterator.next(); + + assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getEndTime()); + assertEquals(120000, itemStop.getDuration()); + + itemStop = iterator.next(); + + assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:07:00.000"), itemStop.getEndTime()); + assertEquals(120000, itemStop.getDuration()); + + } + + @Test + public void testDetectTripsSimpleWithIgnition() throws ParseException { + + List data = Arrays.asList( + position("2016-01-01 00:00:00.000", 0, 0), + position("2016-01-01 00:01:00.000", 0, 0), + position("2016-01-01 00:02:00.000", 10, 0), + position("2016-01-01 00:03:00.000", 10, 1000), + position("2016-01-01 00:04:00.000", 10, 2000), + position("2016-01-01 00:05:00.000", 0, 3000), + position("2016-01-01 00:06:00.000", 0, 3000), + position("2016-01-01 00:07:00.000", 0, 3000)); + + data.get(5).set(Position.KEY_IGNITION, false); + + TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, true, false, 0.01); + + Collection trips = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class); + + assertNotNull(trips); + assertFalse(trips.isEmpty()); + + TripReport itemTrip = trips.iterator().next(); + + assertEquals(date("2016-01-01 00:02:00.000"), itemTrip.getStartTime()); + assertEquals(date("2016-01-01 00:05:00.000"), itemTrip.getEndTime()); + assertEquals(180000, itemTrip.getDuration()); + assertEquals(10, itemTrip.getAverageSpeed(), 0.01); + assertEquals(10, itemTrip.getMaxSpeed(), 0.01); + assertEquals(3000, itemTrip.getDistance(), 0.01); + + trips = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class); + + assertNotNull(trips); + assertFalse(trips.isEmpty()); + + itemTrip = trips.iterator().next(); + + assertEquals(date("2016-01-01 00:02:00.000"), itemTrip.getStartTime()); + assertEquals(date("2016-01-01 00:05:00.000"), itemTrip.getEndTime()); + assertEquals(180000, itemTrip.getDuration()); + assertEquals(10, itemTrip.getAverageSpeed(), 0.01); + assertEquals(10, itemTrip.getMaxSpeed(), 0.01); + assertEquals(3000, itemTrip.getDistance(), 0.01); + + Collection stops = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class); + + assertNotNull(stops); + assertFalse(stops.isEmpty()); + + Iterator iterator = stops.iterator(); + + StopReport itemStop = iterator.next(); + + assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getEndTime()); + assertEquals(120000, itemStop.getDuration()); + + itemStop = iterator.next(); + + assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:07:00.000"), itemStop.getEndTime()); + assertEquals(120000, itemStop.getDuration()); + + } + + @Test + public void testDetectTripsWithFluctuation() throws ParseException { + + List data = Arrays.asList( + position("2016-01-01 00:00:00.000", 0, 0), + position("2016-01-01 00:01:00.000", 0, 0), + position("2016-01-01 00:02:00.000", 10, 0), + position("2016-01-01 00:03:00.000", 10, 1000), + position("2016-01-01 00:04:00.000", 10, 2000), + position("2016-01-01 00:05:00.000", 10, 3000), + position("2016-01-01 00:06:00.000", 10, 4000), + position("2016-01-01 00:07:00.000", 0, 5000), + position("2016-01-01 00:08:00.000", 10, 6000), + position("2016-01-01 00:09:00.000", 0, 7000), + position("2016-01-01 00:10:00.000", 0, 7000), + position("2016-01-01 00:11:00.000", 0, 7000)); + + TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01); + + Collection trips = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class); + + assertNotNull(trips); + assertFalse(trips.isEmpty()); + + TripReport itemTrip = trips.iterator().next(); + + assertEquals(date("2016-01-01 00:02:00.000"), itemTrip.getStartTime()); + assertEquals(date("2016-01-01 00:09:00.000"), itemTrip.getEndTime()); + assertEquals(420000, itemTrip.getDuration()); + assertEquals(8.57, itemTrip.getAverageSpeed(), 0.01); + assertEquals(10, itemTrip.getMaxSpeed(), 0.01); + assertEquals(7000, itemTrip.getDistance(), 0.01); + + Collection stops = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class); + + assertNotNull(stops); + assertFalse(stops.isEmpty()); + + Iterator iterator = stops.iterator(); + + StopReport itemStop = iterator.next(); + + assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getEndTime()); + assertEquals(120000, itemStop.getDuration()); + + itemStop = iterator.next(); + + assertEquals(date("2016-01-01 00:09:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:11:00.000"), itemStop.getEndTime()); + assertEquals(120000, itemStop.getDuration()); + + } + + @Test + public void testDetectStopsOnly() throws ParseException { + + Collection data = Arrays.asList( + position("2016-01-01 00:00:00.000", 0, 0), + position("2016-01-01 00:01:00.000", 0, 0), + position("2016-01-01 00:02:00.000", 1, 0), + position("2016-01-01 00:03:00.000", 0, 0), + position("2016-01-01 00:04:00.000", 1, 0), + position("2016-01-01 00:05:00.000", 0, 0)); + + TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + + Collection result = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class); + + assertNotNull(result); + assertFalse(result.isEmpty()); + + StopReport itemStop = result.iterator().next(); + + assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getEndTime()); + assertEquals(300000, itemStop.getDuration()); + + } + + @Test + public void testDetectStopsWithTripCut() throws ParseException { + + Collection data = Arrays.asList( + position("2016-01-01 00:00:00.000", 0, 0), + position("2016-01-01 00:01:00.000", 0, 0), + position("2016-01-01 00:02:00.000", 0, 0), + position("2016-01-01 00:03:00.000", 0, 0), + position("2016-01-01 00:04:00.000", 1, 0), + position("2016-01-01 00:05:00.000", 2, 0)); + + TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + + Collection result = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class); + + assertNotNull(result); + assertFalse(result.isEmpty()); + + StopReport itemStop = result.iterator().next(); + + assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:04:00.000"), itemStop.getEndTime()); + assertEquals(240000, itemStop.getDuration()); + + } + + @Test + public void testDetectStopsStartedFromTrip() throws ParseException { + + Collection data = Arrays.asList( + position("2016-01-01 00:00:00.000", 2, 0), + position("2016-01-01 00:01:00.000", 1, 0), + position("2016-01-01 00:02:00.000", 0, 0), + position("2016-01-01 00:03:00.000", 0, 0), + position("2016-01-01 00:04:00.000", 0, 0), + position("2016-01-01 00:05:00.000", 0, 0)); + + TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + + Collection result = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class); + + assertNotNull(result); + assertFalse(result.isEmpty()); + + StopReport itemStop = result.iterator().next(); + + assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getEndTime()); + assertEquals(180000, itemStop.getDuration()); + + } + + @Test + public void testDetectStopsMoving() throws ParseException { + + Collection data = Arrays.asList( + position("2016-01-01 00:00:00.000", 5, 0), + position("2016-01-01 00:01:00.000", 5, 0), + position("2016-01-01 00:02:00.000", 3, 0), + position("2016-01-01 00:03:00.000", 5, 0), + position("2016-01-01 00:04:00.000", 5, 0), + position("2016-01-01 00:05:00.000", 5, 0)); + + TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + + Collection result = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class); + + assertNotNull(result); + assertTrue(result.isEmpty()); + + } + + @Test + public void testDetectTripAndStopByGap() throws ParseException { + + Collection data = Arrays.asList( + position("2016-01-01 00:00:00.000", 7, 100), + position("2016-01-01 00:01:00.000", 7, 300), + position("2016-01-01 00:02:00.000", 5, 500), + position("2016-01-01 00:03:00.000", 5, 600), + position("2016-01-01 00:04:00.000", 3, 700), + position("2016-01-01 00:23:00.000", 2, 700), + position("2016-01-01 00:24:00.000", 5, 800), + position("2016-01-01 00:25:00.000", 5, 900)); + + TripsConfig tripsConfig = new TripsConfig(500, 200000, 200000, 900000, false, false, 0.01); + + Collection trips = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class); + + assertNotNull(trips); + assertFalse(trips.isEmpty()); + + TripReport itemTrip = trips.iterator().next(); + + assertEquals(date("2016-01-01 00:00:00.000"), itemTrip.getStartTime()); + assertEquals(date("2016-01-01 00:04:00.000"), itemTrip.getEndTime()); + assertEquals(240000, itemTrip.getDuration()); + assertEquals(6.75, itemTrip.getAverageSpeed(), 0.01); + assertEquals(7, itemTrip.getMaxSpeed(), 0.01); + assertEquals(600, itemTrip.getDistance(), 0.01); + + Collection stops = ReportUtils.detectTripsAndStops( + new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class); + + assertNotNull(stops); + assertFalse(stops.isEmpty()); + + StopReport itemStop = stops.iterator().next(); + + assertEquals(date("2016-01-01 00:04:00.000"), itemStop.getStartTime()); + assertEquals(date("2016-01-01 00:24:00.000"), itemStop.getEndTime()); + assertEquals(1200000, itemStop.getDuration()); + } + +} diff --git a/src/test/java/org/traccar/web/WebServerTest.java b/src/test/java/org/traccar/web/WebServerTest.java new file mode 100644 index 000000000..5a79fbac2 --- /dev/null +++ b/src/test/java/org/traccar/web/WebServerTest.java @@ -0,0 +1,29 @@ +package org.traccar.web; + +import org.junit.Test; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +public class WebServerTest { + + @Test + public void contextTest() throws NamingException { + DataSource mockDataSource = (DataSource) Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[] { DataSource.class }, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return null; + } + }); + + Context context = new InitialContext(); + context.bind("java:/DefaultDS", mockDataSource); + } + +} -- cgit v1.2.3