From c3dda27db63533623d8bba5c7970775b0ee19319 Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Sun, 27 Aug 2023 16:53:08 +0200 Subject: [PATCH 01/11] feat: remove message parsing, use dart-odid alter pigeon schema, rename MessagePack to Container DT-2604 --- .../dronetag/flutter_opendroneid/Pigeon.java | 2275 +---------------- .../FlutterOpendroneidPlugin.kt | 48 +- .../flutter_opendroneid/OdidMessageHandler.kt | 331 --- .../flutter_opendroneid/OdidPayloadHandler.kt | 21 + .../scanner/BluetoothScanner.kt | 91 +- .../scanner/WifiNaNScanner.kt | 89 +- .../scanner/WifiScanner.kt | 108 +- ios/Classes/Models/BasicIdMessage.swift | 38 - ios/Classes/Models/LocationMessage.swift | 144 -- ios/Classes/Models/OdidMessage.swift | 40 - ios/Classes/Models/OperatorIdMessage.swift | 30 - ios/Classes/OdidParser.swift | 200 -- ios/Classes/Scanner/BluetoothScanner.swift | 98 +- .../SwiftFlutterOpendroneidPlugin.swift | 24 +- ios/Classes/pigeon.h | 368 +-- ios/Classes/pigeon.m | 718 +----- ios/Classes/{ => utils}/StreamHandler.swift | 0 ios/Classes/{ => utils}/Utils.swift | 0 lib/flutter_opendroneid.dart | 238 +- lib/models/compare_extension.dart | 61 - lib/models/message_container.dart | 206 ++ lib/models/message_pack.dart | 178 -- lib/pigeon.dart | 891 +------ lib/utils/compare_extension.dart | 52 + lib/{models => utils}/conversions.dart | 16 +- pigeon/schema.dart | 305 +-- pubspec.yaml | 3 +- 27 files changed, 677 insertions(+), 5896 deletions(-) delete mode 100644 android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidMessageHandler.kt create mode 100644 android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidPayloadHandler.kt delete mode 100644 ios/Classes/Models/BasicIdMessage.swift delete mode 100644 ios/Classes/Models/LocationMessage.swift delete mode 100644 ios/Classes/Models/OdidMessage.swift delete mode 100644 ios/Classes/Models/OperatorIdMessage.swift delete mode 100644 ios/Classes/OdidParser.swift rename ios/Classes/{ => utils}/StreamHandler.swift (100%) rename ios/Classes/{ => utils}/Utils.swift (100%) delete mode 100644 lib/models/compare_extension.dart create mode 100644 lib/models/message_container.dart delete mode 100644 lib/models/message_pack.dart create mode 100644 lib/utils/compare_extension.dart rename lib/{models => utils}/conversions.dart (80%) diff --git a/android/src/main/java/cz/dronetag/flutter_opendroneid/Pigeon.java b/android/src/main/java/cz/dronetag/flutter_opendroneid/Pigeon.java index d5992dd..7dd778f 100644 --- a/android/src/main/java/cz/dronetag/flutter_opendroneid/Pigeon.java +++ b/android/src/main/java/cz/dronetag/flutter_opendroneid/Pigeon.java @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.0.0), do not edit directly. +// Autogenerated from Pigeon (v10.1.6), do not edit directly. // See also: https://pub.dev/packages/pigeon package cz.dronetag.flutter_opendroneid; @@ -57,23 +57,7 @@ protected static ArrayList wrapError(@NonNull Throwable exception) { return errorList; } - /** ODID Message Type */ - public enum MessageType { - BASIC_ID(0), - LOCATION(1), - AUTH(2), - SELF_ID(3), - SYSTEM(4), - OPERATOR_ID(5), - MESSAGE_PACK(6); - - final int index; - - private MessageType(final int index) { - this.index = index; - } - } - + /** Higher priority drains battery but receives more data */ public enum ScanPriority { HIGH(0), LOW(1); @@ -100,129 +84,6 @@ private MessageSource(final int index) { } } - /** Identification type */ - public enum IdType { - NONE(0), - SERIAL_NUMBER(1), - CAA_REGISTRATION_ID(2), - UTM_ASSIGNED_ID(3), - SPECIFIC_SESSION_ID(4); - - final int index; - - private IdType(final int index) { - this.index = index; - } - } - - /** Unmanned aircraft type */ - public enum UaType { - NONE(0), - AEROPLANE(1), - HELICOPTER_OR_MULTIROTOR(2), - GYROPLANE(3), - HYBRID_LIFT(4), - ORNITHOPTER(5), - GLIDER(6), - KITE(7), - FREE_BALLOON(8), - CAPTIVE_BALLOON(9), - AIRSHIP(10), - FREE_FALL_PARACHUTE(11), - ROCKET(12), - TETHERED_POWERED_AIRCRAFT(13), - GROUND_OBSTACLE(14), - OTHER(15); - - final int index; - - private UaType(final int index) { - this.index = index; - } - } - - /** Aircraft flight status */ - public enum AircraftStatus { - UNDECLARED(0), - GROUND(1), - AIRBORNE(2), - EMERGENCY(3), - REMOTE_ID_SYSTEM_FAILURE(4); - - final int index; - - private AircraftStatus(final int index) { - this.index = index; - } - } - - /** Height value type */ - public enum HeightType { - TAKEOFF(0), - GROUND(1); - - final int index; - - private HeightType(final int index) { - this.index = index; - } - } - - /** Horizontal accuracy */ - public enum HorizontalAccuracy { - UNKNOWN(0), - KILOMETERS_18_52(1), - KILOMETERS_7_408(2), - KILOMETERS_3_704(3), - KILOMETERS_1_852(4), - METERS_926(5), - METERS_555_6(6), - METERS_185_2(7), - METERS_92_6(8), - METERS_30(9), - METERS_10(10), - METERS_3(11), - METERS_1(12); - - final int index; - - private HorizontalAccuracy(final int index) { - this.index = index; - } - } - - /** Vertical accuracy */ - public enum VerticalAccuracy { - UNKNOWN(0), - METERS_150(1), - METERS_45(2), - METERS_25(3), - METERS_10(4), - METERS_3(5), - METERS_1(6); - - final int index; - - private VerticalAccuracy(final int index) { - this.index = index; - } - } - - /** Speed accuracy */ - public enum SpeedAccuracy { - UNKNOWN(0), - METER_PER_SECOND_10(1), - METER_PER_SECOND_3(2), - METER_PER_SECOND_1(3), - METER_PER_SECOND_0_3(4); - - final int index; - - private SpeedAccuracy(final int index) { - this.index = index; - } - } - /** State of the Bluetooth adapter */ public enum BluetoothState { UNKNOWN(0), @@ -236,1684 +97,42 @@ public enum BluetoothState { private BluetoothState(final int index) { this.index = index; - } - } - - /** State of the Wifi adapter */ - public enum WifiState { - DISABLING(0), - DISABLED(1), - ENABLING(2), - ENABLED(3); - - final int index; - - private WifiState(final int index) { - this.index = index; - } - } - - public enum AuthType { - NONE(0), - UAS_ID_SIGNATURE(1), - OPERATOR_ID_SIGNATURE(2), - MESSAGE_SET_SIGNATURE(3), - NETWORK_REMOTE_ID(4), - SPECIFIC_AUTHENTICATION(5), - PRIVATE_USE_0X_A(6), - PRIVATE_USE_0X_B(7), - PRIVATE_USE_0X_C(8), - PRIVATE_USE_0X_D(9), - PRIVATE_USE_0X_E(10), - PRIVATE_USE_0X_F(11); - - final int index; - - private AuthType(final int index) { - this.index = index; - } - } - - public enum AircraftCategory { - UNDECLARED(0), - EU_OPEN(1), - EU_SPECIFIC(2), - EU_CERTIFIED(3); - - final int index; - - private AircraftCategory(final int index) { - this.index = index; - } - } - - public enum AircraftClass { - UNDECLARED(0), - EU_CLASS_0(1), - EU_CLASS_1(2), - EU_CLASS_2(3), - EU_CLASS_3(4), - EU_CLASS_4(5), - EU_CLASS_5(6), - EU_CLASS_6(7); - - final int index; - - private AircraftClass(final int index) { - this.index = index; - } - } - - public enum OperatorLocationType { - TAKE_OFF(0), - LIVE_GNSS(1), - FIXED_LOCATION(2), - INVALID(3); - - final int index; - - private OperatorLocationType(final int index) { - this.index = index; - } - } - - public enum ClassificationType { - UNDECLARED(0), - EU(1); - - final int index; - - private ClassificationType(final int index) { - this.index = index; - } - } - - /** Generated class from Pigeon that represents data sent in messages. */ - public static final class BasicIdMessage { - private @NonNull Long receivedTimestamp; - - public @NonNull Long getReceivedTimestamp() { - return receivedTimestamp; - } - - public void setReceivedTimestamp(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"receivedTimestamp\" is null."); - } - this.receivedTimestamp = setterArg; - } - - private @NonNull String macAddress; - - public @NonNull String getMacAddress() { - return macAddress; - } - - public void setMacAddress(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"macAddress\" is null."); - } - this.macAddress = setterArg; - } - - private @Nullable MessageSource source; - - public @Nullable MessageSource getSource() { - return source; - } - - public void setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - } - - private @Nullable Long rssi; - - public @Nullable Long getRssi() { - return rssi; - } - - public void setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - } - - /** - * The primary identifier of UAS - * (Dronetag devices use their serial number as their UAS ID) - */ - private @NonNull String uasId; - - public @NonNull String getUasId() { - return uasId; - } - - public void setUasId(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"uasId\" is null."); - } - this.uasId = setterArg; - } - - /** Identification type */ - private @Nullable IdType idType; - - public @Nullable IdType getIdType() { - return idType; - } - - public void setIdType(@Nullable IdType setterArg) { - this.idType = setterArg; - } - - /** Type of the aircraft */ - private @Nullable UaType uaType; - - public @Nullable UaType getUaType() { - return uaType; - } - - public void setUaType(@Nullable UaType setterArg) { - this.uaType = setterArg; - } - - /** Constructor is non-public to enforce null safety; use Builder. */ - BasicIdMessage() {} - - public static final class Builder { - - private @Nullable Long receivedTimestamp; - - public @NonNull Builder setReceivedTimestamp(@NonNull Long setterArg) { - this.receivedTimestamp = setterArg; - return this; - } - - private @Nullable String macAddress; - - public @NonNull Builder setMacAddress(@NonNull String setterArg) { - this.macAddress = setterArg; - return this; - } - - private @Nullable MessageSource source; - - public @NonNull Builder setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - return this; - } - - private @Nullable Long rssi; - - public @NonNull Builder setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - return this; - } - - private @Nullable String uasId; - - public @NonNull Builder setUasId(@NonNull String setterArg) { - this.uasId = setterArg; - return this; - } - - private @Nullable IdType idType; - - public @NonNull Builder setIdType(@Nullable IdType setterArg) { - this.idType = setterArg; - return this; - } - - private @Nullable UaType uaType; - - public @NonNull Builder setUaType(@Nullable UaType setterArg) { - this.uaType = setterArg; - return this; - } - - public @NonNull BasicIdMessage build() { - BasicIdMessage pigeonReturn = new BasicIdMessage(); - pigeonReturn.setReceivedTimestamp(receivedTimestamp); - pigeonReturn.setMacAddress(macAddress); - pigeonReturn.setSource(source); - pigeonReturn.setRssi(rssi); - pigeonReturn.setUasId(uasId); - pigeonReturn.setIdType(idType); - pigeonReturn.setUaType(uaType); - return pigeonReturn; - } - } - - @NonNull - ArrayList toList() { - ArrayList toListResult = new ArrayList(7); - toListResult.add(receivedTimestamp); - toListResult.add(macAddress); - toListResult.add(source == null ? null : source.index); - toListResult.add(rssi); - toListResult.add(uasId); - toListResult.add(idType == null ? null : idType.index); - toListResult.add(uaType == null ? null : uaType.index); - return toListResult; - } - - static @NonNull BasicIdMessage fromList(@NonNull ArrayList list) { - BasicIdMessage pigeonResult = new BasicIdMessage(); - Object receivedTimestamp = list.get(0); - pigeonResult.setReceivedTimestamp((receivedTimestamp == null) ? null : ((receivedTimestamp instanceof Integer) ? (Integer) receivedTimestamp : (Long) receivedTimestamp)); - Object macAddress = list.get(1); - pigeonResult.setMacAddress((String) macAddress); - Object source = list.get(2); - pigeonResult.setSource(source == null ? null : MessageSource.values()[(int) source]); - Object rssi = list.get(3); - pigeonResult.setRssi((rssi == null) ? null : ((rssi instanceof Integer) ? (Integer) rssi : (Long) rssi)); - Object uasId = list.get(4); - pigeonResult.setUasId((String) uasId); - Object idType = list.get(5); - pigeonResult.setIdType(idType == null ? null : IdType.values()[(int) idType]); - Object uaType = list.get(6); - pigeonResult.setUaType(uaType == null ? null : UaType.values()[(int) uaType]); - return pigeonResult; - } - } - - /** Generated class from Pigeon that represents data sent in messages. */ - public static final class LocationMessage { - private @NonNull Long receivedTimestamp; - - public @NonNull Long getReceivedTimestamp() { - return receivedTimestamp; - } - - public void setReceivedTimestamp(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"receivedTimestamp\" is null."); - } - this.receivedTimestamp = setterArg; - } - - private @NonNull String macAddress; - - public @NonNull String getMacAddress() { - return macAddress; - } - - public void setMacAddress(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"macAddress\" is null."); - } - this.macAddress = setterArg; - } - - private @Nullable MessageSource source; - - public @Nullable MessageSource getSource() { - return source; - } - - public void setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - } - - private @Nullable Long rssi; - - public @Nullable Long getRssi() { - return rssi; - } - - public void setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - } - - /** The reported current status of the aircraft */ - private @Nullable AircraftStatus status; - - public @Nullable AircraftStatus getStatus() { - return status; - } - - public void setStatus(@Nullable AircraftStatus setterArg) { - this.status = setterArg; - } - - /** - * The type of reported height - * - * (The default type is takeoff height) - */ - private @Nullable HeightType heightType; - - public @Nullable HeightType getHeightType() { - return heightType; - } - - public void setHeightType(@Nullable HeightType setterArg) { - this.heightType = setterArg; - } - - /** Direction of the aircraft heading (in degrees) */ - private @Nullable Double direction; - - public @Nullable Double getDirection() { - return direction; - } - - public void setDirection(@Nullable Double setterArg) { - this.direction = setterArg; - } - - /** Horizontal speed of the aircraft */ - private @Nullable Double speedHorizontal; - - public @Nullable Double getSpeedHorizontal() { - return speedHorizontal; - } - - public void setSpeedHorizontal(@Nullable Double setterArg) { - this.speedHorizontal = setterArg; - } - - /** Vertical speed of the aircraft */ - private @Nullable Double speedVertical; - - public @Nullable Double getSpeedVertical() { - return speedVertical; - } - - public void setSpeedVertical(@Nullable Double setterArg) { - this.speedVertical = setterArg; - } - - /** Location latitude of the aircraft */ - private @Nullable Double latitude; - - public @Nullable Double getLatitude() { - return latitude; - } - - public void setLatitude(@Nullable Double setterArg) { - this.latitude = setterArg; - } - - /** Location longitude of the aircraft */ - private @Nullable Double longitude; - - public @Nullable Double getLongitude() { - return longitude; - } - - public void setLongitude(@Nullable Double setterArg) { - this.longitude = setterArg; - } - - /** Altitude calculcated from barometric pressure (in meters) */ - private @Nullable Double altitudePressure; - - public @Nullable Double getAltitudePressure() { - return altitudePressure; - } - - public void setAltitudePressure(@Nullable Double setterArg) { - this.altitudePressure = setterArg; - } - - /** Altitude calculated from GNSS data (in meters) */ - private @Nullable Double altitudeGeodetic; - - public @Nullable Double getAltitudeGeodetic() { - return altitudeGeodetic; - } - - public void setAltitudeGeodetic(@Nullable Double setterArg) { - this.altitudeGeodetic = setterArg; - } - - /** Current height of the aircraft */ - private @Nullable Double height; - - public @Nullable Double getHeight() { - return height; - } - - public void setHeight(@Nullable Double setterArg) { - this.height = setterArg; - } - - /** Horizontal accuracy of reported position via GNSS */ - private @Nullable HorizontalAccuracy horizontalAccuracy; - - public @Nullable HorizontalAccuracy getHorizontalAccuracy() { - return horizontalAccuracy; - } - - public void setHorizontalAccuracy(@Nullable HorizontalAccuracy setterArg) { - this.horizontalAccuracy = setterArg; - } - - /** Vertical accuracy of reported altitude via GNSS */ - private @Nullable VerticalAccuracy verticalAccuracy; - - public @Nullable VerticalAccuracy getVerticalAccuracy() { - return verticalAccuracy; - } - - public void setVerticalAccuracy(@Nullable VerticalAccuracy setterArg) { - this.verticalAccuracy = setterArg; - } - - /** Vertical accuracy of reported altitude via barometric pressure */ - private @Nullable VerticalAccuracy baroAccuracy; - - public @Nullable VerticalAccuracy getBaroAccuracy() { - return baroAccuracy; - } - - public void setBaroAccuracy(@Nullable VerticalAccuracy setterArg) { - this.baroAccuracy = setterArg; - } - - /** Speed accuracy of reported position via GNSS */ - private @Nullable SpeedAccuracy speedAccuracy; - - public @Nullable SpeedAccuracy getSpeedAccuracy() { - return speedAccuracy; - } - - public void setSpeedAccuracy(@Nullable SpeedAccuracy setterArg) { - this.speedAccuracy = setterArg; - } - - /** Time of the location report */ - private @Nullable Long time; - - public @Nullable Long getTime() { - return time; - } - - public void setTime(@Nullable Long setterArg) { - this.time = setterArg; - } - - /** Accuracy of timestamp values */ - private @Nullable Double timeAccuracy; - - public @Nullable Double getTimeAccuracy() { - return timeAccuracy; - } - - public void setTimeAccuracy(@Nullable Double setterArg) { - this.timeAccuracy = setterArg; - } - - /** Constructor is non-public to enforce null safety; use Builder. */ - LocationMessage() {} - - public static final class Builder { - - private @Nullable Long receivedTimestamp; - - public @NonNull Builder setReceivedTimestamp(@NonNull Long setterArg) { - this.receivedTimestamp = setterArg; - return this; - } - - private @Nullable String macAddress; - - public @NonNull Builder setMacAddress(@NonNull String setterArg) { - this.macAddress = setterArg; - return this; - } - - private @Nullable MessageSource source; - - public @NonNull Builder setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - return this; - } - - private @Nullable Long rssi; - - public @NonNull Builder setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - return this; - } - - private @Nullable AircraftStatus status; - - public @NonNull Builder setStatus(@Nullable AircraftStatus setterArg) { - this.status = setterArg; - return this; - } - - private @Nullable HeightType heightType; - - public @NonNull Builder setHeightType(@Nullable HeightType setterArg) { - this.heightType = setterArg; - return this; - } - - private @Nullable Double direction; - - public @NonNull Builder setDirection(@Nullable Double setterArg) { - this.direction = setterArg; - return this; - } - - private @Nullable Double speedHorizontal; - - public @NonNull Builder setSpeedHorizontal(@Nullable Double setterArg) { - this.speedHorizontal = setterArg; - return this; - } - - private @Nullable Double speedVertical; - - public @NonNull Builder setSpeedVertical(@Nullable Double setterArg) { - this.speedVertical = setterArg; - return this; - } - - private @Nullable Double latitude; - - public @NonNull Builder setLatitude(@Nullable Double setterArg) { - this.latitude = setterArg; - return this; - } - - private @Nullable Double longitude; - - public @NonNull Builder setLongitude(@Nullable Double setterArg) { - this.longitude = setterArg; - return this; - } - - private @Nullable Double altitudePressure; - - public @NonNull Builder setAltitudePressure(@Nullable Double setterArg) { - this.altitudePressure = setterArg; - return this; - } - - private @Nullable Double altitudeGeodetic; - - public @NonNull Builder setAltitudeGeodetic(@Nullable Double setterArg) { - this.altitudeGeodetic = setterArg; - return this; - } - - private @Nullable Double height; - - public @NonNull Builder setHeight(@Nullable Double setterArg) { - this.height = setterArg; - return this; - } - - private @Nullable HorizontalAccuracy horizontalAccuracy; - - public @NonNull Builder setHorizontalAccuracy(@Nullable HorizontalAccuracy setterArg) { - this.horizontalAccuracy = setterArg; - return this; - } - - private @Nullable VerticalAccuracy verticalAccuracy; - - public @NonNull Builder setVerticalAccuracy(@Nullable VerticalAccuracy setterArg) { - this.verticalAccuracy = setterArg; - return this; - } - - private @Nullable VerticalAccuracy baroAccuracy; - - public @NonNull Builder setBaroAccuracy(@Nullable VerticalAccuracy setterArg) { - this.baroAccuracy = setterArg; - return this; - } - - private @Nullable SpeedAccuracy speedAccuracy; - - public @NonNull Builder setSpeedAccuracy(@Nullable SpeedAccuracy setterArg) { - this.speedAccuracy = setterArg; - return this; - } - - private @Nullable Long time; - - public @NonNull Builder setTime(@Nullable Long setterArg) { - this.time = setterArg; - return this; - } - - private @Nullable Double timeAccuracy; - - public @NonNull Builder setTimeAccuracy(@Nullable Double setterArg) { - this.timeAccuracy = setterArg; - return this; - } - - public @NonNull LocationMessage build() { - LocationMessage pigeonReturn = new LocationMessage(); - pigeonReturn.setReceivedTimestamp(receivedTimestamp); - pigeonReturn.setMacAddress(macAddress); - pigeonReturn.setSource(source); - pigeonReturn.setRssi(rssi); - pigeonReturn.setStatus(status); - pigeonReturn.setHeightType(heightType); - pigeonReturn.setDirection(direction); - pigeonReturn.setSpeedHorizontal(speedHorizontal); - pigeonReturn.setSpeedVertical(speedVertical); - pigeonReturn.setLatitude(latitude); - pigeonReturn.setLongitude(longitude); - pigeonReturn.setAltitudePressure(altitudePressure); - pigeonReturn.setAltitudeGeodetic(altitudeGeodetic); - pigeonReturn.setHeight(height); - pigeonReturn.setHorizontalAccuracy(horizontalAccuracy); - pigeonReturn.setVerticalAccuracy(verticalAccuracy); - pigeonReturn.setBaroAccuracy(baroAccuracy); - pigeonReturn.setSpeedAccuracy(speedAccuracy); - pigeonReturn.setTime(time); - pigeonReturn.setTimeAccuracy(timeAccuracy); - return pigeonReturn; - } - } - - @NonNull - ArrayList toList() { - ArrayList toListResult = new ArrayList(20); - toListResult.add(receivedTimestamp); - toListResult.add(macAddress); - toListResult.add(source == null ? null : source.index); - toListResult.add(rssi); - toListResult.add(status == null ? null : status.index); - toListResult.add(heightType == null ? null : heightType.index); - toListResult.add(direction); - toListResult.add(speedHorizontal); - toListResult.add(speedVertical); - toListResult.add(latitude); - toListResult.add(longitude); - toListResult.add(altitudePressure); - toListResult.add(altitudeGeodetic); - toListResult.add(height); - toListResult.add(horizontalAccuracy == null ? null : horizontalAccuracy.index); - toListResult.add(verticalAccuracy == null ? null : verticalAccuracy.index); - toListResult.add(baroAccuracy == null ? null : baroAccuracy.index); - toListResult.add(speedAccuracy == null ? null : speedAccuracy.index); - toListResult.add(time); - toListResult.add(timeAccuracy); - return toListResult; - } - - static @NonNull LocationMessage fromList(@NonNull ArrayList list) { - LocationMessage pigeonResult = new LocationMessage(); - Object receivedTimestamp = list.get(0); - pigeonResult.setReceivedTimestamp((receivedTimestamp == null) ? null : ((receivedTimestamp instanceof Integer) ? (Integer) receivedTimestamp : (Long) receivedTimestamp)); - Object macAddress = list.get(1); - pigeonResult.setMacAddress((String) macAddress); - Object source = list.get(2); - pigeonResult.setSource(source == null ? null : MessageSource.values()[(int) source]); - Object rssi = list.get(3); - pigeonResult.setRssi((rssi == null) ? null : ((rssi instanceof Integer) ? (Integer) rssi : (Long) rssi)); - Object status = list.get(4); - pigeonResult.setStatus(status == null ? null : AircraftStatus.values()[(int) status]); - Object heightType = list.get(5); - pigeonResult.setHeightType(heightType == null ? null : HeightType.values()[(int) heightType]); - Object direction = list.get(6); - pigeonResult.setDirection((Double) direction); - Object speedHorizontal = list.get(7); - pigeonResult.setSpeedHorizontal((Double) speedHorizontal); - Object speedVertical = list.get(8); - pigeonResult.setSpeedVertical((Double) speedVertical); - Object latitude = list.get(9); - pigeonResult.setLatitude((Double) latitude); - Object longitude = list.get(10); - pigeonResult.setLongitude((Double) longitude); - Object altitudePressure = list.get(11); - pigeonResult.setAltitudePressure((Double) altitudePressure); - Object altitudeGeodetic = list.get(12); - pigeonResult.setAltitudeGeodetic((Double) altitudeGeodetic); - Object height = list.get(13); - pigeonResult.setHeight((Double) height); - Object horizontalAccuracy = list.get(14); - pigeonResult.setHorizontalAccuracy(horizontalAccuracy == null ? null : HorizontalAccuracy.values()[(int) horizontalAccuracy]); - Object verticalAccuracy = list.get(15); - pigeonResult.setVerticalAccuracy(verticalAccuracy == null ? null : VerticalAccuracy.values()[(int) verticalAccuracy]); - Object baroAccuracy = list.get(16); - pigeonResult.setBaroAccuracy(baroAccuracy == null ? null : VerticalAccuracy.values()[(int) baroAccuracy]); - Object speedAccuracy = list.get(17); - pigeonResult.setSpeedAccuracy(speedAccuracy == null ? null : SpeedAccuracy.values()[(int) speedAccuracy]); - Object time = list.get(18); - pigeonResult.setTime((time == null) ? null : ((time instanceof Integer) ? (Integer) time : (Long) time)); - Object timeAccuracy = list.get(19); - pigeonResult.setTimeAccuracy((Double) timeAccuracy); - return pigeonResult; - } - } - - /** Generated class from Pigeon that represents data sent in messages. */ - public static final class OperatorIdMessage { - /** Operator ID */ - private @NonNull Long receivedTimestamp; - - public @NonNull Long getReceivedTimestamp() { - return receivedTimestamp; - } - - public void setReceivedTimestamp(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"receivedTimestamp\" is null."); - } - this.receivedTimestamp = setterArg; - } - - private @NonNull String macAddress; - - public @NonNull String getMacAddress() { - return macAddress; - } - - public void setMacAddress(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"macAddress\" is null."); - } - this.macAddress = setterArg; - } - - private @Nullable MessageSource source; - - public @Nullable MessageSource getSource() { - return source; - } - - public void setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - } - - private @Nullable Long rssi; - - public @Nullable Long getRssi() { - return rssi; - } - - public void setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - } - - private @NonNull String operatorId; - - public @NonNull String getOperatorId() { - return operatorId; - } - - public void setOperatorId(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"operatorId\" is null."); - } - this.operatorId = setterArg; - } - - /** Constructor is non-public to enforce null safety; use Builder. */ - OperatorIdMessage() {} - - public static final class Builder { - - private @Nullable Long receivedTimestamp; - - public @NonNull Builder setReceivedTimestamp(@NonNull Long setterArg) { - this.receivedTimestamp = setterArg; - return this; - } - - private @Nullable String macAddress; - - public @NonNull Builder setMacAddress(@NonNull String setterArg) { - this.macAddress = setterArg; - return this; - } - - private @Nullable MessageSource source; - - public @NonNull Builder setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - return this; - } - - private @Nullable Long rssi; - - public @NonNull Builder setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - return this; - } - - private @Nullable String operatorId; - - public @NonNull Builder setOperatorId(@NonNull String setterArg) { - this.operatorId = setterArg; - return this; - } - - public @NonNull OperatorIdMessage build() { - OperatorIdMessage pigeonReturn = new OperatorIdMessage(); - pigeonReturn.setReceivedTimestamp(receivedTimestamp); - pigeonReturn.setMacAddress(macAddress); - pigeonReturn.setSource(source); - pigeonReturn.setRssi(rssi); - pigeonReturn.setOperatorId(operatorId); - return pigeonReturn; - } - } - - @NonNull - ArrayList toList() { - ArrayList toListResult = new ArrayList(5); - toListResult.add(receivedTimestamp); - toListResult.add(macAddress); - toListResult.add(source == null ? null : source.index); - toListResult.add(rssi); - toListResult.add(operatorId); - return toListResult; - } - - static @NonNull OperatorIdMessage fromList(@NonNull ArrayList list) { - OperatorIdMessage pigeonResult = new OperatorIdMessage(); - Object receivedTimestamp = list.get(0); - pigeonResult.setReceivedTimestamp((receivedTimestamp == null) ? null : ((receivedTimestamp instanceof Integer) ? (Integer) receivedTimestamp : (Long) receivedTimestamp)); - Object macAddress = list.get(1); - pigeonResult.setMacAddress((String) macAddress); - Object source = list.get(2); - pigeonResult.setSource(source == null ? null : MessageSource.values()[(int) source]); - Object rssi = list.get(3); - pigeonResult.setRssi((rssi == null) ? null : ((rssi instanceof Integer) ? (Integer) rssi : (Long) rssi)); - Object operatorId = list.get(4); - pigeonResult.setOperatorId((String) operatorId); - return pigeonResult; - } - } - - /** Generated class from Pigeon that represents data sent in messages. */ - public static final class AuthenticationMessage { - private @NonNull Long receivedTimestamp; - - public @NonNull Long getReceivedTimestamp() { - return receivedTimestamp; - } - - public void setReceivedTimestamp(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"receivedTimestamp\" is null."); - } - this.receivedTimestamp = setterArg; - } - - private @NonNull String macAddress; - - public @NonNull String getMacAddress() { - return macAddress; - } - - public void setMacAddress(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"macAddress\" is null."); - } - this.macAddress = setterArg; - } - - private @Nullable MessageSource source; - - public @Nullable MessageSource getSource() { - return source; - } - - public void setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - } - - private @Nullable Long rssi; - - public @Nullable Long getRssi() { - return rssi; - } - - public void setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - } - - private @Nullable AuthType authType; - - public @Nullable AuthType getAuthType() { - return authType; - } - - public void setAuthType(@Nullable AuthType setterArg) { - this.authType = setterArg; - } - - private @NonNull Long authDataPage; - - public @NonNull Long getAuthDataPage() { - return authDataPage; - } - - public void setAuthDataPage(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"authDataPage\" is null."); - } - this.authDataPage = setterArg; - } - - private @NonNull Long authLastPageIndex; - - public @NonNull Long getAuthLastPageIndex() { - return authLastPageIndex; - } - - public void setAuthLastPageIndex(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"authLastPageIndex\" is null."); - } - this.authLastPageIndex = setterArg; - } - - private @NonNull Long authLength; - - public @NonNull Long getAuthLength() { - return authLength; - } - - public void setAuthLength(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"authLength\" is null."); - } - this.authLength = setterArg; - } - - private @NonNull Long authTimestamp; - - public @NonNull Long getAuthTimestamp() { - return authTimestamp; - } - - public void setAuthTimestamp(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"authTimestamp\" is null."); - } - this.authTimestamp = setterArg; - } - - private @NonNull String authData; - - public @NonNull String getAuthData() { - return authData; - } - - public void setAuthData(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"authData\" is null."); - } - this.authData = setterArg; - } - - /** Constructor is non-public to enforce null safety; use Builder. */ - AuthenticationMessage() {} - - public static final class Builder { - - private @Nullable Long receivedTimestamp; - - public @NonNull Builder setReceivedTimestamp(@NonNull Long setterArg) { - this.receivedTimestamp = setterArg; - return this; - } - - private @Nullable String macAddress; - - public @NonNull Builder setMacAddress(@NonNull String setterArg) { - this.macAddress = setterArg; - return this; - } - - private @Nullable MessageSource source; - - public @NonNull Builder setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - return this; - } - - private @Nullable Long rssi; - - public @NonNull Builder setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - return this; - } - - private @Nullable AuthType authType; - - public @NonNull Builder setAuthType(@Nullable AuthType setterArg) { - this.authType = setterArg; - return this; - } - - private @Nullable Long authDataPage; - - public @NonNull Builder setAuthDataPage(@NonNull Long setterArg) { - this.authDataPage = setterArg; - return this; - } - - private @Nullable Long authLastPageIndex; - - public @NonNull Builder setAuthLastPageIndex(@NonNull Long setterArg) { - this.authLastPageIndex = setterArg; - return this; - } - - private @Nullable Long authLength; - - public @NonNull Builder setAuthLength(@NonNull Long setterArg) { - this.authLength = setterArg; - return this; - } - - private @Nullable Long authTimestamp; - - public @NonNull Builder setAuthTimestamp(@NonNull Long setterArg) { - this.authTimestamp = setterArg; - return this; - } - - private @Nullable String authData; - - public @NonNull Builder setAuthData(@NonNull String setterArg) { - this.authData = setterArg; - return this; - } - - public @NonNull AuthenticationMessage build() { - AuthenticationMessage pigeonReturn = new AuthenticationMessage(); - pigeonReturn.setReceivedTimestamp(receivedTimestamp); - pigeonReturn.setMacAddress(macAddress); - pigeonReturn.setSource(source); - pigeonReturn.setRssi(rssi); - pigeonReturn.setAuthType(authType); - pigeonReturn.setAuthDataPage(authDataPage); - pigeonReturn.setAuthLastPageIndex(authLastPageIndex); - pigeonReturn.setAuthLength(authLength); - pigeonReturn.setAuthTimestamp(authTimestamp); - pigeonReturn.setAuthData(authData); - return pigeonReturn; - } - } - - @NonNull - ArrayList toList() { - ArrayList toListResult = new ArrayList(10); - toListResult.add(receivedTimestamp); - toListResult.add(macAddress); - toListResult.add(source == null ? null : source.index); - toListResult.add(rssi); - toListResult.add(authType == null ? null : authType.index); - toListResult.add(authDataPage); - toListResult.add(authLastPageIndex); - toListResult.add(authLength); - toListResult.add(authTimestamp); - toListResult.add(authData); - return toListResult; - } - - static @NonNull AuthenticationMessage fromList(@NonNull ArrayList list) { - AuthenticationMessage pigeonResult = new AuthenticationMessage(); - Object receivedTimestamp = list.get(0); - pigeonResult.setReceivedTimestamp((receivedTimestamp == null) ? null : ((receivedTimestamp instanceof Integer) ? (Integer) receivedTimestamp : (Long) receivedTimestamp)); - Object macAddress = list.get(1); - pigeonResult.setMacAddress((String) macAddress); - Object source = list.get(2); - pigeonResult.setSource(source == null ? null : MessageSource.values()[(int) source]); - Object rssi = list.get(3); - pigeonResult.setRssi((rssi == null) ? null : ((rssi instanceof Integer) ? (Integer) rssi : (Long) rssi)); - Object authType = list.get(4); - pigeonResult.setAuthType(authType == null ? null : AuthType.values()[(int) authType]); - Object authDataPage = list.get(5); - pigeonResult.setAuthDataPage((authDataPage == null) ? null : ((authDataPage instanceof Integer) ? (Integer) authDataPage : (Long) authDataPage)); - Object authLastPageIndex = list.get(6); - pigeonResult.setAuthLastPageIndex((authLastPageIndex == null) ? null : ((authLastPageIndex instanceof Integer) ? (Integer) authLastPageIndex : (Long) authLastPageIndex)); - Object authLength = list.get(7); - pigeonResult.setAuthLength((authLength == null) ? null : ((authLength instanceof Integer) ? (Integer) authLength : (Long) authLength)); - Object authTimestamp = list.get(8); - pigeonResult.setAuthTimestamp((authTimestamp == null) ? null : ((authTimestamp instanceof Integer) ? (Integer) authTimestamp : (Long) authTimestamp)); - Object authData = list.get(9); - pigeonResult.setAuthData((String) authData); - return pigeonResult; - } - } - - /** Generated class from Pigeon that represents data sent in messages. */ - public static final class SelfIdMessage { - private @NonNull Long receivedTimestamp; - - public @NonNull Long getReceivedTimestamp() { - return receivedTimestamp; - } - - public void setReceivedTimestamp(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"receivedTimestamp\" is null."); - } - this.receivedTimestamp = setterArg; - } - - private @NonNull String macAddress; - - public @NonNull String getMacAddress() { - return macAddress; - } - - public void setMacAddress(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"macAddress\" is null."); - } - this.macAddress = setterArg; - } - - private @Nullable MessageSource source; - - public @Nullable MessageSource getSource() { - return source; - } - - public void setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - } - - private @Nullable Long rssi; - - public @Nullable Long getRssi() { - return rssi; - } - - public void setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - } - - private @NonNull Long descriptionType; - - public @NonNull Long getDescriptionType() { - return descriptionType; - } - - public void setDescriptionType(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"descriptionType\" is null."); - } - this.descriptionType = setterArg; - } - - private @NonNull String operationDescription; - - public @NonNull String getOperationDescription() { - return operationDescription; - } - - public void setOperationDescription(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"operationDescription\" is null."); - } - this.operationDescription = setterArg; - } - - /** Constructor is non-public to enforce null safety; use Builder. */ - SelfIdMessage() {} - - public static final class Builder { - - private @Nullable Long receivedTimestamp; - - public @NonNull Builder setReceivedTimestamp(@NonNull Long setterArg) { - this.receivedTimestamp = setterArg; - return this; - } - - private @Nullable String macAddress; - - public @NonNull Builder setMacAddress(@NonNull String setterArg) { - this.macAddress = setterArg; - return this; - } - - private @Nullable MessageSource source; - - public @NonNull Builder setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - return this; - } - - private @Nullable Long rssi; - - public @NonNull Builder setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - return this; - } - - private @Nullable Long descriptionType; - - public @NonNull Builder setDescriptionType(@NonNull Long setterArg) { - this.descriptionType = setterArg; - return this; - } - - private @Nullable String operationDescription; - - public @NonNull Builder setOperationDescription(@NonNull String setterArg) { - this.operationDescription = setterArg; - return this; - } - - public @NonNull SelfIdMessage build() { - SelfIdMessage pigeonReturn = new SelfIdMessage(); - pigeonReturn.setReceivedTimestamp(receivedTimestamp); - pigeonReturn.setMacAddress(macAddress); - pigeonReturn.setSource(source); - pigeonReturn.setRssi(rssi); - pigeonReturn.setDescriptionType(descriptionType); - pigeonReturn.setOperationDescription(operationDescription); - return pigeonReturn; - } - } - - @NonNull - ArrayList toList() { - ArrayList toListResult = new ArrayList(6); - toListResult.add(receivedTimestamp); - toListResult.add(macAddress); - toListResult.add(source == null ? null : source.index); - toListResult.add(rssi); - toListResult.add(descriptionType); - toListResult.add(operationDescription); - return toListResult; - } - - static @NonNull SelfIdMessage fromList(@NonNull ArrayList list) { - SelfIdMessage pigeonResult = new SelfIdMessage(); - Object receivedTimestamp = list.get(0); - pigeonResult.setReceivedTimestamp((receivedTimestamp == null) ? null : ((receivedTimestamp instanceof Integer) ? (Integer) receivedTimestamp : (Long) receivedTimestamp)); - Object macAddress = list.get(1); - pigeonResult.setMacAddress((String) macAddress); - Object source = list.get(2); - pigeonResult.setSource(source == null ? null : MessageSource.values()[(int) source]); - Object rssi = list.get(3); - pigeonResult.setRssi((rssi == null) ? null : ((rssi instanceof Integer) ? (Integer) rssi : (Long) rssi)); - Object descriptionType = list.get(4); - pigeonResult.setDescriptionType((descriptionType == null) ? null : ((descriptionType instanceof Integer) ? (Integer) descriptionType : (Long) descriptionType)); - Object operationDescription = list.get(5); - pigeonResult.setOperationDescription((String) operationDescription); - return pigeonResult; - } - } - - /** Generated class from Pigeon that represents data sent in messages. */ - public static final class SystemDataMessage { - private @NonNull Long receivedTimestamp; - - public @NonNull Long getReceivedTimestamp() { - return receivedTimestamp; - } - - public void setReceivedTimestamp(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"receivedTimestamp\" is null."); - } - this.receivedTimestamp = setterArg; - } - - private @NonNull String macAddress; - - public @NonNull String getMacAddress() { - return macAddress; - } - - public void setMacAddress(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"macAddress\" is null."); - } - this.macAddress = setterArg; - } - - private @Nullable MessageSource source; - - public @Nullable MessageSource getSource() { - return source; - } - - public void setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - } - - private @Nullable Long rssi; - - public @Nullable Long getRssi() { - return rssi; - } - - public void setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - } - - private @Nullable OperatorLocationType operatorLocationType; - - public @Nullable OperatorLocationType getOperatorLocationType() { - return operatorLocationType; - } - - public void setOperatorLocationType(@Nullable OperatorLocationType setterArg) { - this.operatorLocationType = setterArg; - } - - private @Nullable ClassificationType classificationType; - - public @Nullable ClassificationType getClassificationType() { - return classificationType; - } - - public void setClassificationType(@Nullable ClassificationType setterArg) { - this.classificationType = setterArg; - } - - private @NonNull Double operatorLatitude; - - public @NonNull Double getOperatorLatitude() { - return operatorLatitude; - } - - public void setOperatorLatitude(@NonNull Double setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"operatorLatitude\" is null."); - } - this.operatorLatitude = setterArg; - } - - private @NonNull Double operatorLongitude; - - public @NonNull Double getOperatorLongitude() { - return operatorLongitude; - } - - public void setOperatorLongitude(@NonNull Double setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"operatorLongitude\" is null."); - } - this.operatorLongitude = setterArg; - } - - private @NonNull Long areaCount; - - public @NonNull Long getAreaCount() { - return areaCount; - } - - public void setAreaCount(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"areaCount\" is null."); - } - this.areaCount = setterArg; - } - - private @NonNull Long areaRadius; - - public @NonNull Long getAreaRadius() { - return areaRadius; - } - - public void setAreaRadius(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"areaRadius\" is null."); - } - this.areaRadius = setterArg; - } - - private @NonNull Double areaCeiling; - - public @NonNull Double getAreaCeiling() { - return areaCeiling; - } - - public void setAreaCeiling(@NonNull Double setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"areaCeiling\" is null."); - } - this.areaCeiling = setterArg; - } - - private @NonNull Double areaFloor; - - public @NonNull Double getAreaFloor() { - return areaFloor; - } - - public void setAreaFloor(@NonNull Double setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"areaFloor\" is null."); - } - this.areaFloor = setterArg; - } - - private @Nullable AircraftCategory category; - - public @Nullable AircraftCategory getCategory() { - return category; - } - - public void setCategory(@Nullable AircraftCategory setterArg) { - this.category = setterArg; - } - - private @Nullable AircraftClass classValue; - - public @Nullable AircraftClass getClassValue() { - return classValue; - } - - public void setClassValue(@Nullable AircraftClass setterArg) { - this.classValue = setterArg; - } - - private @NonNull Double operatorAltitudeGeo; - - public @NonNull Double getOperatorAltitudeGeo() { - return operatorAltitudeGeo; - } - - public void setOperatorAltitudeGeo(@NonNull Double setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"operatorAltitudeGeo\" is null."); - } - this.operatorAltitudeGeo = setterArg; - } - - /** Constructor is non-public to enforce null safety; use Builder. */ - SystemDataMessage() {} - - public static final class Builder { - - private @Nullable Long receivedTimestamp; - - public @NonNull Builder setReceivedTimestamp(@NonNull Long setterArg) { - this.receivedTimestamp = setterArg; - return this; - } - - private @Nullable String macAddress; - - public @NonNull Builder setMacAddress(@NonNull String setterArg) { - this.macAddress = setterArg; - return this; - } - - private @Nullable MessageSource source; - - public @NonNull Builder setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - return this; - } - - private @Nullable Long rssi; - - public @NonNull Builder setRssi(@Nullable Long setterArg) { - this.rssi = setterArg; - return this; - } - - private @Nullable OperatorLocationType operatorLocationType; - - public @NonNull Builder setOperatorLocationType(@Nullable OperatorLocationType setterArg) { - this.operatorLocationType = setterArg; - return this; - } - - private @Nullable ClassificationType classificationType; - - public @NonNull Builder setClassificationType(@Nullable ClassificationType setterArg) { - this.classificationType = setterArg; - return this; - } - - private @Nullable Double operatorLatitude; - - public @NonNull Builder setOperatorLatitude(@NonNull Double setterArg) { - this.operatorLatitude = setterArg; - return this; - } - - private @Nullable Double operatorLongitude; - - public @NonNull Builder setOperatorLongitude(@NonNull Double setterArg) { - this.operatorLongitude = setterArg; - return this; - } - - private @Nullable Long areaCount; - - public @NonNull Builder setAreaCount(@NonNull Long setterArg) { - this.areaCount = setterArg; - return this; - } - - private @Nullable Long areaRadius; - - public @NonNull Builder setAreaRadius(@NonNull Long setterArg) { - this.areaRadius = setterArg; - return this; - } - - private @Nullable Double areaCeiling; - - public @NonNull Builder setAreaCeiling(@NonNull Double setterArg) { - this.areaCeiling = setterArg; - return this; - } - - private @Nullable Double areaFloor; - - public @NonNull Builder setAreaFloor(@NonNull Double setterArg) { - this.areaFloor = setterArg; - return this; - } - - private @Nullable AircraftCategory category; - - public @NonNull Builder setCategory(@Nullable AircraftCategory setterArg) { - this.category = setterArg; - return this; - } - - private @Nullable AircraftClass classValue; - - public @NonNull Builder setClassValue(@Nullable AircraftClass setterArg) { - this.classValue = setterArg; - return this; - } + } + } - private @Nullable Double operatorAltitudeGeo; + /** State of the Wifi adapter */ + public enum WifiState { + DISABLING(0), + DISABLED(1), + ENABLING(2), + ENABLED(3); - public @NonNull Builder setOperatorAltitudeGeo(@NonNull Double setterArg) { - this.operatorAltitudeGeo = setterArg; - return this; - } + final int index; - public @NonNull SystemDataMessage build() { - SystemDataMessage pigeonReturn = new SystemDataMessage(); - pigeonReturn.setReceivedTimestamp(receivedTimestamp); - pigeonReturn.setMacAddress(macAddress); - pigeonReturn.setSource(source); - pigeonReturn.setRssi(rssi); - pigeonReturn.setOperatorLocationType(operatorLocationType); - pigeonReturn.setClassificationType(classificationType); - pigeonReturn.setOperatorLatitude(operatorLatitude); - pigeonReturn.setOperatorLongitude(operatorLongitude); - pigeonReturn.setAreaCount(areaCount); - pigeonReturn.setAreaRadius(areaRadius); - pigeonReturn.setAreaCeiling(areaCeiling); - pigeonReturn.setAreaFloor(areaFloor); - pigeonReturn.setCategory(category); - pigeonReturn.setClassValue(classValue); - pigeonReturn.setOperatorAltitudeGeo(operatorAltitudeGeo); - return pigeonReturn; - } + private WifiState(final int index) { + this.index = index; } + } - @NonNull - ArrayList toList() { - ArrayList toListResult = new ArrayList(15); - toListResult.add(receivedTimestamp); - toListResult.add(macAddress); - toListResult.add(source == null ? null : source.index); - toListResult.add(rssi); - toListResult.add(operatorLocationType == null ? null : operatorLocationType.index); - toListResult.add(classificationType == null ? null : classificationType.index); - toListResult.add(operatorLatitude); - toListResult.add(operatorLongitude); - toListResult.add(areaCount); - toListResult.add(areaRadius); - toListResult.add(areaCeiling); - toListResult.add(areaFloor); - toListResult.add(category == null ? null : category.index); - toListResult.add(classValue == null ? null : classValue.index); - toListResult.add(operatorAltitudeGeo); - return toListResult; + /** + * Payload send from native to dart contains raw data and metadata + * + * Generated class from Pigeon that represents data sent in messages. + */ + public static final class ODIDPayload { + private @NonNull byte[] rawData; + + public @NonNull byte[] getRawData() { + return rawData; } - static @NonNull SystemDataMessage fromList(@NonNull ArrayList list) { - SystemDataMessage pigeonResult = new SystemDataMessage(); - Object receivedTimestamp = list.get(0); - pigeonResult.setReceivedTimestamp((receivedTimestamp == null) ? null : ((receivedTimestamp instanceof Integer) ? (Integer) receivedTimestamp : (Long) receivedTimestamp)); - Object macAddress = list.get(1); - pigeonResult.setMacAddress((String) macAddress); - Object source = list.get(2); - pigeonResult.setSource(source == null ? null : MessageSource.values()[(int) source]); - Object rssi = list.get(3); - pigeonResult.setRssi((rssi == null) ? null : ((rssi instanceof Integer) ? (Integer) rssi : (Long) rssi)); - Object operatorLocationType = list.get(4); - pigeonResult.setOperatorLocationType(operatorLocationType == null ? null : OperatorLocationType.values()[(int) operatorLocationType]); - Object classificationType = list.get(5); - pigeonResult.setClassificationType(classificationType == null ? null : ClassificationType.values()[(int) classificationType]); - Object operatorLatitude = list.get(6); - pigeonResult.setOperatorLatitude((Double) operatorLatitude); - Object operatorLongitude = list.get(7); - pigeonResult.setOperatorLongitude((Double) operatorLongitude); - Object areaCount = list.get(8); - pigeonResult.setAreaCount((areaCount == null) ? null : ((areaCount instanceof Integer) ? (Integer) areaCount : (Long) areaCount)); - Object areaRadius = list.get(9); - pigeonResult.setAreaRadius((areaRadius == null) ? null : ((areaRadius instanceof Integer) ? (Integer) areaRadius : (Long) areaRadius)); - Object areaCeiling = list.get(10); - pigeonResult.setAreaCeiling((Double) areaCeiling); - Object areaFloor = list.get(11); - pigeonResult.setAreaFloor((Double) areaFloor); - Object category = list.get(12); - pigeonResult.setCategory(category == null ? null : AircraftCategory.values()[(int) category]); - Object classValue = list.get(13); - pigeonResult.setClassValue(classValue == null ? null : AircraftClass.values()[(int) classValue]); - Object operatorAltitudeGeo = list.get(14); - pigeonResult.setOperatorAltitudeGeo((Double) operatorAltitudeGeo); - return pigeonResult; + public void setRawData(@NonNull byte[] setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"rawData\" is null."); + } + this.rawData = setterArg; } - } - /** Generated class from Pigeon that represents data sent in messages. */ - public static final class ConnectionMessage { private @NonNull Long receivedTimestamp; public @NonNull Long getReceivedTimestamp() { @@ -1940,16 +159,6 @@ public void setMacAddress(@NonNull String setterArg) { this.macAddress = setterArg; } - private @Nullable MessageSource source; - - public @Nullable MessageSource getSource() { - return source; - } - - public void setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - } - private @Nullable Long rssi; public @Nullable Long getRssi() { @@ -1960,62 +169,30 @@ public void setRssi(@Nullable Long setterArg) { this.rssi = setterArg; } - private @NonNull String transportType; - - public @NonNull String getTransportType() { - return transportType; - } - - public void setTransportType(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"transportType\" is null."); - } - this.transportType = setterArg; - } - - private @NonNull Long lastSeen; + private @NonNull MessageSource source; - public @NonNull Long getLastSeen() { - return lastSeen; + public @NonNull MessageSource getSource() { + return source; } - public void setLastSeen(@NonNull Long setterArg) { + public void setSource(@NonNull MessageSource setterArg) { if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"lastSeen\" is null."); + throw new IllegalStateException("Nonnull field \"source\" is null."); } - this.lastSeen = setterArg; - } - - private @NonNull Long firstSeen; - - public @NonNull Long getFirstSeen() { - return firstSeen; + this.source = setterArg; } - public void setFirstSeen(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"firstSeen\" is null."); - } - this.firstSeen = setterArg; - } + /** Constructor is non-public to enforce null safety; use Builder. */ + ODIDPayload() {} - private @NonNull Long msgDelta; + public static final class Builder { - public @NonNull Long getMsgDelta() { - return msgDelta; - } + private @Nullable byte[] rawData; - public void setMsgDelta(@NonNull Long setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"msgDelta\" is null."); + public @NonNull Builder setRawData(@NonNull byte[] setterArg) { + this.rawData = setterArg; + return this; } - this.msgDelta = setterArg; - } - - /** Constructor is non-public to enforce null safety; use Builder. */ - ConnectionMessage() {} - - public static final class Builder { private @Nullable Long receivedTimestamp; @@ -2031,13 +208,6 @@ public static final class Builder { return this; } - private @Nullable MessageSource source; - - public @NonNull Builder setSource(@Nullable MessageSource setterArg) { - this.source = setterArg; - return this; - } - private @Nullable Long rssi; public @NonNull Builder setRssi(@Nullable Long setterArg) { @@ -2045,80 +215,47 @@ public static final class Builder { return this; } - private @Nullable String transportType; - - public @NonNull Builder setTransportType(@NonNull String setterArg) { - this.transportType = setterArg; - return this; - } - - private @Nullable Long lastSeen; - - public @NonNull Builder setLastSeen(@NonNull Long setterArg) { - this.lastSeen = setterArg; - return this; - } - - private @Nullable Long firstSeen; - - public @NonNull Builder setFirstSeen(@NonNull Long setterArg) { - this.firstSeen = setterArg; - return this; - } - - private @Nullable Long msgDelta; + private @Nullable MessageSource source; - public @NonNull Builder setMsgDelta(@NonNull Long setterArg) { - this.msgDelta = setterArg; + public @NonNull Builder setSource(@NonNull MessageSource setterArg) { + this.source = setterArg; return this; } - public @NonNull ConnectionMessage build() { - ConnectionMessage pigeonReturn = new ConnectionMessage(); + public @NonNull ODIDPayload build() { + ODIDPayload pigeonReturn = new ODIDPayload(); + pigeonReturn.setRawData(rawData); pigeonReturn.setReceivedTimestamp(receivedTimestamp); pigeonReturn.setMacAddress(macAddress); - pigeonReturn.setSource(source); pigeonReturn.setRssi(rssi); - pigeonReturn.setTransportType(transportType); - pigeonReturn.setLastSeen(lastSeen); - pigeonReturn.setFirstSeen(firstSeen); - pigeonReturn.setMsgDelta(msgDelta); + pigeonReturn.setSource(source); return pigeonReturn; } } @NonNull ArrayList toList() { - ArrayList toListResult = new ArrayList(8); + ArrayList toListResult = new ArrayList(5); + toListResult.add(rawData); toListResult.add(receivedTimestamp); toListResult.add(macAddress); - toListResult.add(source == null ? null : source.index); toListResult.add(rssi); - toListResult.add(transportType); - toListResult.add(lastSeen); - toListResult.add(firstSeen); - toListResult.add(msgDelta); + toListResult.add(source == null ? null : source.index); return toListResult; } - static @NonNull ConnectionMessage fromList(@NonNull ArrayList list) { - ConnectionMessage pigeonResult = new ConnectionMessage(); - Object receivedTimestamp = list.get(0); + static @NonNull ODIDPayload fromList(@NonNull ArrayList list) { + ODIDPayload pigeonResult = new ODIDPayload(); + Object rawData = list.get(0); + pigeonResult.setRawData((byte[]) rawData); + Object receivedTimestamp = list.get(1); pigeonResult.setReceivedTimestamp((receivedTimestamp == null) ? null : ((receivedTimestamp instanceof Integer) ? (Integer) receivedTimestamp : (Long) receivedTimestamp)); - Object macAddress = list.get(1); + Object macAddress = list.get(2); pigeonResult.setMacAddress((String) macAddress); - Object source = list.get(2); - pigeonResult.setSource(source == null ? null : MessageSource.values()[(int) source]); Object rssi = list.get(3); pigeonResult.setRssi((rssi == null) ? null : ((rssi instanceof Integer) ? (Integer) rssi : (Long) rssi)); - Object transportType = list.get(4); - pigeonResult.setTransportType((String) transportType); - Object lastSeen = list.get(5); - pigeonResult.setLastSeen((lastSeen == null) ? null : ((lastSeen instanceof Integer) ? (Integer) lastSeen : (Long) lastSeen)); - Object firstSeen = list.get(6); - pigeonResult.setFirstSeen((firstSeen == null) ? null : ((firstSeen instanceof Integer) ? (Integer) firstSeen : (Long) firstSeen)); - Object msgDelta = list.get(7); - pigeonResult.setMsgDelta((msgDelta == null) ? null : ((msgDelta instanceof Integer) ? (Integer) msgDelta : (Long) msgDelta)); + Object source = list.get(4); + pigeonResult.setSource(source == null ? null : MessageSource.values()[(int) source]); return pigeonResult; } } @@ -2165,7 +302,7 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable Api api) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.startScanBluetooth", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.startScanBluetooth", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2192,7 +329,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.startScanWifi", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.startScanWifi", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2219,7 +356,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.stopScanBluetooth", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.stopScanBluetooth", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2246,7 +383,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.stopScanWifi", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.stopScanWifi", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2273,7 +410,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.setBtScanPriority", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.setBtScanPriority", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2302,7 +439,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.isScanningBluetooth", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.isScanningBluetooth", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2329,7 +466,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.isScanningWifi", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.isScanningWifi", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2356,7 +493,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.bluetoothState", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.bluetoothState", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2383,7 +520,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.wifiState", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.wifiState", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2410,7 +547,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.btExtendedSupported", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.btExtendedSupported", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2437,7 +574,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.btMaxAdvDataLen", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.btMaxAdvDataLen", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2464,7 +601,7 @@ public void error(Throwable error) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.Api.wifiNaNSupported", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.Api.wifiNaNSupported", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -2491,28 +628,16 @@ public void error(Throwable error) { } } - private static class MessageApiCodec extends StandardMessageCodec { - public static final MessageApiCodec INSTANCE = new MessageApiCodec(); + private static class PayloadApiCodec extends StandardMessageCodec { + public static final PayloadApiCodec INSTANCE = new PayloadApiCodec(); - private MessageApiCodec() {} + private PayloadApiCodec() {} @Override protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { switch (type) { case (byte) 128: - return AuthenticationMessage.fromList((ArrayList) readValue(buffer)); - case (byte) 129: - return BasicIdMessage.fromList((ArrayList) readValue(buffer)); - case (byte) 130: - return ConnectionMessage.fromList((ArrayList) readValue(buffer)); - case (byte) 131: - return LocationMessage.fromList((ArrayList) readValue(buffer)); - case (byte) 132: - return OperatorIdMessage.fromList((ArrayList) readValue(buffer)); - case (byte) 133: - return SelfIdMessage.fromList((ArrayList) readValue(buffer)); - case (byte) 134: - return SystemDataMessage.fromList((ArrayList) readValue(buffer)); + return ODIDPayload.fromList((ArrayList) readValue(buffer)); default: return super.readValueOfType(type, buffer); } @@ -2520,27 +645,9 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { @Override protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { - if (value instanceof AuthenticationMessage) { + if (value instanceof ODIDPayload) { stream.write(128); - writeValue(stream, ((AuthenticationMessage) value).toList()); - } else if (value instanceof BasicIdMessage) { - stream.write(129); - writeValue(stream, ((BasicIdMessage) value).toList()); - } else if (value instanceof ConnectionMessage) { - stream.write(130); - writeValue(stream, ((ConnectionMessage) value).toList()); - } else if (value instanceof LocationMessage) { - stream.write(131); - writeValue(stream, ((LocationMessage) value).toList()); - } else if (value instanceof OperatorIdMessage) { - stream.write(132); - writeValue(stream, ((OperatorIdMessage) value).toList()); - } else if (value instanceof SelfIdMessage) { - stream.write(133); - writeValue(stream, ((SelfIdMessage) value).toList()); - } else if (value instanceof SystemDataMessage) { - stream.write(134); - writeValue(stream, ((SystemDataMessage) value).toList()); + writeValue(stream, ((ODIDPayload) value).toList()); } else { super.writeValue(stream, value); } @@ -2548,233 +655,33 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { } /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ - public interface MessageApi { + public interface PayloadApi { - @Nullable - Long determineMessageType(@NonNull byte[] payload, @NonNull Long offset); + @NonNull + ODIDPayload getPayload(@NonNull byte[] rawData, @NonNull MessageSource source, @NonNull String macAddress, @NonNull Long rssi, @NonNull Long receivedTimestamp); - @Nullable - BasicIdMessage fromBufferBasic(@NonNull byte[] payload, @NonNull Long offset, @NonNull String macAddress); - - @Nullable - LocationMessage fromBufferLocation(@NonNull byte[] payload, @NonNull Long offset, @NonNull String macAddress); - - @Nullable - OperatorIdMessage fromBufferOperatorId(@NonNull byte[] payload, @NonNull Long offset, @NonNull String macAddress); - - @Nullable - SelfIdMessage fromBufferSelfId(@NonNull byte[] payload, @NonNull Long offset, @NonNull String macAddress); - - @Nullable - AuthenticationMessage fromBufferAuthentication(@NonNull byte[] payload, @NonNull Long offset, @NonNull String macAddress); - - @Nullable - SystemDataMessage fromBufferSystemData(@NonNull byte[] payload, @NonNull Long offset, @NonNull String macAddress); - - @Nullable - ConnectionMessage fromBufferConnection(@NonNull byte[] payload, @NonNull Long offset, @NonNull String macAddress); - - /** The codec used by MessageApi. */ + /** The codec used by PayloadApi. */ static @NonNull MessageCodec getCodec() { - return MessageApiCodec.INSTANCE; + return PayloadApiCodec.INSTANCE; } - /**Sets up an instance of `MessageApi` to handle messages through the `binaryMessenger`. */ - static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable MessageApi api) { - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.MessageApi.determineMessageType", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - byte[] payloadArg = (byte[]) args.get(0); - Number offsetArg = (Number) args.get(1); - try { - Long output = api.determineMessageType(payloadArg, (offsetArg == null) ? null : offsetArg.longValue()); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.MessageApi.fromBufferBasic", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - byte[] payloadArg = (byte[]) args.get(0); - Number offsetArg = (Number) args.get(1); - String macAddressArg = (String) args.get(2); - try { - BasicIdMessage output = api.fromBufferBasic(payloadArg, (offsetArg == null) ? null : offsetArg.longValue(), macAddressArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.MessageApi.fromBufferLocation", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - byte[] payloadArg = (byte[]) args.get(0); - Number offsetArg = (Number) args.get(1); - String macAddressArg = (String) args.get(2); - try { - LocationMessage output = api.fromBufferLocation(payloadArg, (offsetArg == null) ? null : offsetArg.longValue(), macAddressArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.MessageApi.fromBufferOperatorId", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - byte[] payloadArg = (byte[]) args.get(0); - Number offsetArg = (Number) args.get(1); - String macAddressArg = (String) args.get(2); - try { - OperatorIdMessage output = api.fromBufferOperatorId(payloadArg, (offsetArg == null) ? null : offsetArg.longValue(), macAddressArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.MessageApi.fromBufferSelfId", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - byte[] payloadArg = (byte[]) args.get(0); - Number offsetArg = (Number) args.get(1); - String macAddressArg = (String) args.get(2); - try { - SelfIdMessage output = api.fromBufferSelfId(payloadArg, (offsetArg == null) ? null : offsetArg.longValue(), macAddressArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.MessageApi.fromBufferAuthentication", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - byte[] payloadArg = (byte[]) args.get(0); - Number offsetArg = (Number) args.get(1); - String macAddressArg = (String) args.get(2); - try { - AuthenticationMessage output = api.fromBufferAuthentication(payloadArg, (offsetArg == null) ? null : offsetArg.longValue(), macAddressArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.MessageApi.fromBufferSystemData", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - ArrayList wrapped = new ArrayList(); - ArrayList args = (ArrayList) message; - byte[] payloadArg = (byte[]) args.get(0); - Number offsetArg = (Number) args.get(1); - String macAddressArg = (String) args.get(2); - try { - SystemDataMessage output = api.fromBufferSystemData(payloadArg, (offsetArg == null) ? null : offsetArg.longValue(), macAddressArg); - wrapped.add(0, output); - } - catch (Throwable exception) { - ArrayList wrappedError = wrapError(exception); - wrapped = wrappedError; - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } + /**Sets up an instance of `PayloadApi` to handle messages through the `binaryMessenger`. */ + static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable PayloadApi api) { { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.MessageApi.fromBufferConnection", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.PayloadApi.getPayload", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { ArrayList wrapped = new ArrayList(); ArrayList args = (ArrayList) message; - byte[] payloadArg = (byte[]) args.get(0); - Number offsetArg = (Number) args.get(1); + byte[] rawDataArg = (byte[]) args.get(0); + MessageSource sourceArg = args.get(1) == null ? null : MessageSource.values()[(int) args.get(1)]; String macAddressArg = (String) args.get(2); + Number rssiArg = (Number) args.get(3); + Number receivedTimestampArg = (Number) args.get(4); try { - ConnectionMessage output = api.fromBufferConnection(payloadArg, (offsetArg == null) ? null : offsetArg.longValue(), macAddressArg); + ODIDPayload output = api.getPayload(rawDataArg, sourceArg, macAddressArg, (rssiArg == null) ? null : rssiArg.longValue(), (receivedTimestampArg == null) ? null : receivedTimestampArg.longValue()); wrapped.add(0, output); } catch (Throwable exception) { diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/FlutterOpendroneidPlugin.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/FlutterOpendroneidPlugin.kt index ae6ddb2..06b260a 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/FlutterOpendroneidPlugin.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/FlutterOpendroneidPlugin.kt @@ -24,20 +24,13 @@ class FlutterOpendroneidPlugin : FlutterPlugin, ActivityAware, Pigeon.Api { private lateinit var context: Context private lateinit var activity: Activity - private val basicStreamHandler = StreamHandler() - private val locationStreamHandler = StreamHandler() - private val operatorIdStreamHandler = StreamHandler() + private val odidPayloadStreamHandler = StreamHandler() private val bluetoothStateStreamHandler = StreamHandler() private val wifiStateStreamHandler = StreamHandler() - private val selfIdMessagesHandler = StreamHandler() - private val authentificationMessagesHandler = StreamHandler() - private val systemDataMessagesHandler = StreamHandler() private var scanner: BluetoothScanner = BluetoothScanner( - basicStreamHandler, locationStreamHandler, operatorIdStreamHandler, - selfIdMessagesHandler, authentificationMessagesHandler, systemDataMessagesHandler, - bluetoothStateStreamHandler, + odidPayloadStreamHandler, bluetoothStateStreamHandler, ) private lateinit var wifiScanner: WifiScanner private lateinit var wifiNaNScanner: WifiNaNScanner @@ -51,14 +44,9 @@ class FlutterOpendroneidPlugin : FlutterPlugin, ActivityAware, Pigeon.Api { StreamHandler.bindMultipleHandlers( flutterPluginBinding.binaryMessenger, mapOf( - "flutter_basic_messages" to basicStreamHandler, - "flutter_location_messages" to locationStreamHandler, - "flutter_operatorid_messages" to operatorIdStreamHandler, - "flutter_selfid_messages" to selfIdMessagesHandler, - "flutter_auth_messages" to authentificationMessagesHandler, - "flutter_system_messages" to systemDataMessagesHandler, - "flutter_odid_bt_state" to bluetoothStateStreamHandler, - "flutter_odid_wifi_state" to wifiStateStreamHandler + "flutter_odid_data" to odidPayloadStreamHandler, + "flutter_odid_bt_state" to bluetoothStateStreamHandler, + "flutter_odid_wifi_state" to wifiStateStreamHandler ) ) @@ -72,19 +60,11 @@ class FlutterOpendroneidPlugin : FlutterPlugin, ActivityAware, Pigeon.Api { wifiScanner = WifiScanner( - basicStreamHandler, locationStreamHandler, operatorIdStreamHandler, - selfIdMessagesHandler, authentificationMessagesHandler, systemDataMessagesHandler, - wifiStateStreamHandler, - wifiManager, - context + odidPayloadStreamHandler, wifiStateStreamHandler, wifiManager, context ) wifiNaNScanner = WifiNaNScanner( - basicStreamHandler, locationStreamHandler, operatorIdStreamHandler, - selfIdMessagesHandler, authentificationMessagesHandler, systemDataMessagesHandler, - wifiStateStreamHandler, - wifiAwareManager, - context + odidPayloadStreamHandler, wifiStateStreamHandler, wifiAwareManager, context ) } @@ -115,14 +95,12 @@ class FlutterOpendroneidPlugin : FlutterPlugin, ActivityAware, Pigeon.Api { wifiScanner.cancel() wifiNaNScanner.cancel() StreamHandler.clearMultipleHandlers( - binding.binaryMessenger, - listOf( - "flutter_basic_messages", - "flutter_location_messages", - "flutter_operatorid_messages", - "flutter_odid_bt_state", - "flutter_odid_scan_state", - ) + binding.binaryMessenger, + listOf( + "flutter_odid_data", + "flutter_odid_bt_state", + "flutter_odid_wifi_state", + ) ) } diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidMessageHandler.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidMessageHandler.kt deleted file mode 100644 index 4db97b7..0000000 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidMessageHandler.kt +++ /dev/null @@ -1,331 +0,0 @@ -package cz.dronetag.flutter_opendroneid - -import java.nio.ByteBuffer -import java.nio.ByteOrder -import kotlin.experimental.and -import io.flutter.Log - -class OdidMessageHandler : Pigeon.MessageApi { - companion object { - const val MAX_MESSAGE_SIZE = 25 - const val MAX_ID_BYTE_SIZE = 20 - const val MAX_STRING_BYTE_SIZE = 23 - const val MAX_AUTH_DATA_PAGES = 16 - const val MAX_AUTH_PAGE_ZERO_SIZE = 17 - const val MAX_AUTH_PAGE_NON_ZERO_SIZE = 23 - const val MAX_AUTH_DATA = - MAX_AUTH_PAGE_ZERO_SIZE + (MAX_AUTH_DATA_PAGES - 1) * MAX_AUTH_PAGE_NON_ZERO_SIZE - const val MAX_MESSAGES_IN_PACK = 9 - val MAX_MESSAGE_PACK_SIZE: Int = MAX_MESSAGE_SIZE * MAX_MESSAGES_IN_PACK - const val LAT_LONG_MULTIPLIER = 1e-7 - const val SPEED_VERTICAL_MULTIPLIER = 0.5; - } - - override fun fromBufferBasic( - payload: ByteArray, - offset: Long, - macAddress: String - ): Pigeon.BasicIdMessage? { - if (payload.size < offset + MAX_MESSAGE_SIZE) return null - val byteBuffer = ByteBuffer.wrap(payload, offset.toInt(), MAX_MESSAGE_SIZE) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - val b: Int = (byteBuffer.get() and 0xFF.toByte()).toInt() - return parseBasicMessage(byteBuffer, macAddress) - } - - override fun fromBufferLocation( - payload: ByteArray, - offset: Long, - macAddress: String - ): Pigeon.LocationMessage? { - if (payload.size < offset + MAX_MESSAGE_SIZE) return null - val byteBuffer = ByteBuffer.wrap(payload, offset.toInt(), MAX_MESSAGE_SIZE) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - val b: Int = (byteBuffer.get() and 0xFF.toByte()).toInt() - return parseLocationMessage(byteBuffer, macAddress) - } - - override fun fromBufferOperatorId( - payload: ByteArray, - offset: Long, - macAddress: String - ): Pigeon.OperatorIdMessage? { - if (payload.size < offset + MAX_MESSAGE_SIZE) return null - val byteBuffer = ByteBuffer.wrap(payload, offset.toInt(), MAX_MESSAGE_SIZE) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - val b: Int = (byteBuffer.get() and 0xFF.toByte()).toInt() - return parseOperatorIdMessage(byteBuffer, macAddress) - } - - override fun fromBufferSelfId( - payload: ByteArray, - offset: Long, - macAddress: String - ): Pigeon.SelfIdMessage? { - if (payload.size < offset + MAX_MESSAGE_SIZE) return null - val byteBuffer = ByteBuffer.wrap(payload, offset.toInt(), MAX_MESSAGE_SIZE) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - val b: Int = (byteBuffer.get() and 0xFF.toByte()).toInt() - return parseSelfIdMessage(byteBuffer, macAddress) - } - - override fun fromBufferConnection( - payload: ByteArray, - offset: Long, - macAddress: String - ): Pigeon.ConnectionMessage? { - if (payload.size < offset + MAX_MESSAGE_SIZE) return null - val byteBuffer = ByteBuffer.wrap(payload, offset.toInt(), MAX_MESSAGE_SIZE) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - val b: Int = (byteBuffer.get() and 0xFF.toByte()).toInt() - return parseConnectionMessage(byteBuffer, macAddress) - } - - override fun fromBufferAuthentication( - payload: ByteArray, - offset: Long, - macAddress: String - ): Pigeon.AuthenticationMessage? { - if (payload.size < offset + MAX_MESSAGE_SIZE) return null - val byteBuffer = ByteBuffer.wrap(payload, offset.toInt(), MAX_MESSAGE_SIZE) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - val b: Int = (byteBuffer.get() and 0xFF.toByte()).toInt() - return parseAuthenticationMessage(byteBuffer, macAddress) - } - - override fun fromBufferSystemData( - payload: ByteArray, - offset: Long, - macAddress: String - ): Pigeon.SystemDataMessage? { - if (payload.size < offset + MAX_MESSAGE_SIZE) return null - val byteBuffer = ByteBuffer.wrap(payload, offset.toInt(), MAX_MESSAGE_SIZE) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - val b: Int = (byteBuffer.get() and 0xFF.toByte()).toInt() - return parseSystemDataMessage(byteBuffer, macAddress) - } - - override fun determineMessageType(payload: ByteArray, offset: Long): Long? { - if (payload.size < offset + MAX_MESSAGE_SIZE){ - return null - } - - val byteBuffer = ByteBuffer.wrap(payload, offset.toInt(), MAX_MESSAGE_SIZE) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - - val b: Int = (byteBuffer.get() and 0xFF.toByte()).toInt() - val typeData = (b and 0xF0) shr 4 - // message pack - if (typeData.toInt() == 15) - { - return 6; - } - if (typeData > 5){ - return null - } - return typeData.toLong() - } - - private fun parseBasicMessage( - byteBuffer: ByteBuffer, - macAddress: String - ): Pigeon.BasicIdMessage { - val builder = Pigeon.BasicIdMessage.Builder() - val type: Int = byteBuffer.get().toInt() - val uasId = ByteArray(OdidMessageHandler.MAX_ID_BYTE_SIZE) - builder.setReceivedTimestamp(System.currentTimeMillis()) - builder.setIdType(Pigeon.IdType.values().getOrElse(type and 0xF0 shr 4) {Pigeon.IdType.NONE}) - builder.setUaType(Pigeon.UaType.values().getOrElse(type and 0x0F) {Pigeon.UaType.NONE}) - builder.setMacAddress(macAddress) - byteBuffer.get(uasId, 0, OdidMessageHandler.MAX_ID_BYTE_SIZE) - var uasIdStr = String(uasId) - if (uasIdStr.contains('\u0000')) { - uasIdStr = uasIdStr.split('\u0000').first() - } - builder.setUasId(uasIdStr) - return builder.build() - } - - private fun parseLocationMessage( - byteBuffer: ByteBuffer, - macAddress: String - ): Pigeon.LocationMessage { - val builder = Pigeon.LocationMessage.Builder() - val b = byteBuffer.get().toInt() - val status = b and 0xF0 shr 4 - val heightType = b and 0x04 shr 2 - val ewDirection = b and 0x02 shr 1 - val speedMult = b and 0x01 - - builder.setMacAddress(macAddress) - builder.setReceivedTimestamp(System.currentTimeMillis()) - - builder.setDirection( - calcDirection((byteBuffer.get().toInt() and 0xFF.toInt()), ewDirection) - ) - builder.setSpeedHorizontal( - calcSpeed((byteBuffer.get().toInt() and 0xFF.toInt()), speedMult) - ) - builder.setSpeedVertical(SPEED_VERTICAL_MULTIPLIER * byteBuffer.get().toInt()) - val lat = LAT_LONG_MULTIPLIER * byteBuffer.int - builder.setLatitude(lat) - builder.setLongitude(LAT_LONG_MULTIPLIER * byteBuffer.int) - builder.setAltitudePressure(calcAltitude(byteBuffer.short.toUShort().toInt())) - builder.setAltitudeGeodetic(calcAltitude(byteBuffer.short.toUShort().toInt())) - builder.setHeight(calcAltitude(byteBuffer.short.toUShort().toInt())) - val horiVertAccuracy = byteBuffer.get().toInt() - builder.setHorizontalAccuracy(Pigeon.HorizontalAccuracy.values().getOrElse(horiVertAccuracy and 0x0F) {Pigeon.HorizontalAccuracy.UNKNOWN}) - builder.setVerticalAccuracy( - Pigeon.VerticalAccuracy.values().getOrElse(horiVertAccuracy and 0xF0 shr 4) {Pigeon.VerticalAccuracy.UNKNOWN} - ) - val speedBaroAccuracy = byteBuffer.get().toInt() - builder.setBaroAccuracy(Pigeon.VerticalAccuracy.values().getOrElse(speedBaroAccuracy and 0xF0 shr 4) {Pigeon.VerticalAccuracy.UNKNOWN}) - builder.setSpeedAccuracy(speedAccToEnum(speedBaroAccuracy and 0x0F)) - builder.setTime(byteBuffer.short.toUShort().toLong()) - builder.setTimeAccuracy((byteBuffer.get() and 0x0F).toInt() * 0.1) - builder.setStatus(Pigeon.AircraftStatus.values().getOrElse(status) {Pigeon.AircraftStatus.UNDECLARED}) - builder.setHeightType(Pigeon.HeightType.values().getOrElse(heightType) {Pigeon.HeightType.TAKEOFF}) - return builder.build() - } - - private fun parseOperatorIdMessage( - byteBuffer: ByteBuffer, - macAddress: String - ): Pigeon.OperatorIdMessage { - val builder = Pigeon.OperatorIdMessage.Builder() - builder.setMacAddress(macAddress) - builder.setReceivedTimestamp(System.currentTimeMillis()) - val type: Int = byteBuffer.get().toInt() - val operatorId = ByteArray(OdidMessageHandler.MAX_ID_BYTE_SIZE) - - byteBuffer.get(operatorId, 0, OdidMessageHandler.MAX_ID_BYTE_SIZE) - var operatorIdStr = String(operatorId) - - if (operatorIdStr.contains('\u0000')) { - operatorIdStr = operatorIdStr.split('\u0000').first() - } - builder.setOperatorId(operatorIdStr) - - return builder.build() - } - - private fun parseSelfIdMessage( - byteBuffer: ByteBuffer, - macAddress: String - ): Pigeon.SelfIdMessage { - val builder = Pigeon.SelfIdMessage.Builder() - var opDesc: String = "" - var it = 0 - builder.setMacAddress(macAddress) - builder.setReceivedTimestamp(System.currentTimeMillis()) - builder.setDescriptionType((byteBuffer.get() and 0xFF.toByte()).toLong()) - while (it++ < MAX_STRING_BYTE_SIZE) { - opDesc += byteBuffer.get().toChar() - } - builder.setOperationDescription(opDesc) - return builder.build() - } - - private fun parseAuthenticationMessage( - byteBuffer: ByteBuffer, - macAddress: String - ): Pigeon.AuthenticationMessage { - val builder = Pigeon.AuthenticationMessage.Builder() - builder.setMacAddress(macAddress) - builder.setReceivedTimestamp(System.currentTimeMillis()) - val type = byteBuffer.get().toInt() - val authType = type and 0xF0 shr 4 - val authDataPage: Long = (type and 0x0F).toLong() - var authLength: Long = 0 - var authTimestamp: Long = 0 - var authLastPageIndex: Long = 0 - var authData: String = "" - - var offset: Long = 0 - var amount: Int = MAX_AUTH_PAGE_ZERO_SIZE - if (authDataPage === 0L) { - authLastPageIndex = (byteBuffer.get() and 0xFF.toByte()).toLong() - authLength = (byteBuffer.get() and 0xFF.toByte()).toLong() - authTimestamp = (byteBuffer.int and 0xFFFFFFFFL.toInt()).toLong() - // For an explanation, please see the description for struct ODID_Auth_data in: - // https://github.com/opendroneid/opendroneid-core-c/blob/master/libopendroneid/opendroneid.h - val len: Long = - (authLastPageIndex * MAX_AUTH_PAGE_NON_ZERO_SIZE + MAX_AUTH_PAGE_ZERO_SIZE) - .toLong() - if (authLastPageIndex >= MAX_AUTH_DATA_PAGES || authLength > len) { - authLastPageIndex = 0 - authLength = 0 - authTimestamp = 0 - } else { - // Display both normal authentication data and any possible additional data - authLength = len - } - } else { - offset = MAX_AUTH_PAGE_ZERO_SIZE + (authDataPage - 1) * MAX_AUTH_PAGE_NON_ZERO_SIZE - amount = MAX_AUTH_PAGE_NON_ZERO_SIZE - } - if (authDataPage >= 0 && authDataPage < MAX_AUTH_DATA_PAGES) - for (i in offset until offset + amount) authData += byteBuffer.get() - builder.setAuthLength(authLength) - builder.setAuthData(authData) - builder.setAuthLastPageIndex(authLastPageIndex) - builder.setAuthTimestamp(authTimestamp) - builder.setAuthType(Pigeon.AuthType.values().getOrElse(authType) {Pigeon.AuthType.NONE}) - builder.setAuthDataPage(authDataPage) - return builder.build() - } - - private fun parseConnectionMessage( - byteBuffer: ByteBuffer, - macAddress: String - ): Pigeon.ConnectionMessage { - val builder = Pigeon.ConnectionMessage.Builder() - builder.setMacAddress(macAddress) - builder.setReceivedTimestamp(System.currentTimeMillis()) - return builder.build() - } - - private fun parseSystemDataMessage( - byteBuffer: ByteBuffer, - macAddress: String - ): Pigeon.SystemDataMessage { - val builder = Pigeon.SystemDataMessage.Builder() - builder.setMacAddress(macAddress) - builder.setReceivedTimestamp(System.currentTimeMillis()) - - var b = byteBuffer.get().toInt() - builder.setOperatorLocationType(Pigeon.OperatorLocationType.values().getOrElse(b and 0x03) {Pigeon.OperatorLocationType.INVALID}) - builder.setClassificationType(Pigeon.ClassificationType.values().getOrElse(b and 0x1C shr 2) {Pigeon.ClassificationType.UNDECLARED}) - builder.setOperatorLatitude(LAT_LONG_MULTIPLIER * byteBuffer.int.toDouble()) - builder.setOperatorLongitude(LAT_LONG_MULTIPLIER * byteBuffer.int.toDouble()) - builder.setAreaCount((byteBuffer.short and 0xFFFF.toShort()).toLong()) - builder.setAreaRadius((byteBuffer.get() and 0xFF.toByte()).toLong() * 10) - builder.setAreaCeiling(calcAltitude((byteBuffer.short and 0xFFFF.toShort()).toInt())) - builder.setAreaFloor(calcAltitude((byteBuffer.short and 0xFFFF.toShort()).toInt())) - b = byteBuffer.get().toInt() - builder.setCategory(Pigeon.AircraftCategory.values().getOrElse(b and 0xF0 shr 4) {Pigeon.AircraftCategory.UNDECLARED}) - builder.setClassValue(Pigeon.AircraftClass.values().getOrElse(b and 0x0F) {Pigeon.AircraftClass.UNDECLARED}) - builder.setOperatorAltitudeGeo(calcAltitude((byteBuffer.short and 0xFFFF.toShort()).toInt())) - - return builder.build() - } - - private fun calcSpeed(value: Int, mult: Int): Double { - return if (mult == 0) value.toDouble() * 0.25 else (value.toDouble() * 0.75) + (255 * 0.25) - } - - private fun speedAccToEnum(acc: Int): Pigeon.SpeedAccuracy { - if (acc == 10) return Pigeon.SpeedAccuracy.METER_PER_SECOND_10 - else if (acc == 3) return Pigeon.SpeedAccuracy.METER_PER_SECOND_3 - else if (acc == 1) return Pigeon.SpeedAccuracy.METER_PER_SECOND_1 - return Pigeon.SpeedAccuracy.UNKNOWN - } - - private fun calcDirection(value: Int, EW: Int): Double { - return if (EW == 0) value.toDouble() else (value + 180).toDouble() - } - - private fun calcAltitude(value: Int): Double { - return value.toDouble() / 2 - 1000 - } -} diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidPayloadHandler.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidPayloadHandler.kt new file mode 100644 index 0000000..0e6beea --- /dev/null +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidPayloadHandler.kt @@ -0,0 +1,21 @@ +package cz.dronetag.flutter_opendroneid + +import java.nio.ByteBuffer +import java.nio.ByteOrder +import kotlin.experimental.and +import io.flutter.Log + +class OdidPayloadHandler : Pigeon.PayloadApi { + + override fun getPayload(rawData: ByteArray, source: Pigeon.MessageSource, macAddress: String, rssi: Long, receivedTimestamp: Long): Pigeon.ODIDPayload { + val builder = Pigeon.ODIDPayload.Builder() + + builder.setRawData(rawData) + builder.setReceivedTimestamp(receivedTimestamp) + builder.setMacAddress(macAddress) + builder.setSource(source) + builder.setRssi(rssi) + + return builder.build() + } +} diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt index 14c9a59..5996513 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt @@ -15,14 +15,13 @@ import java.nio.ByteBuffer import java.nio.ByteOrder class BluetoothScanner( - private val basicMessagesHandler: StreamHandler, - private val locationMessagesHandler: StreamHandler, - private val operatorIdMessagesHandler: StreamHandler, - private val selfIdMessagesHandler: StreamHandler, - private val authenticationMessagesHandler: StreamHandler, - private val systemDataMessagesHandler: StreamHandler, + private val odidPayloadStreamHandler: StreamHandler, private val bluetoothStateHandler: StreamHandler, ) { + companion object { + const val MAX_MESSAGE_SIZE = 25 + } + var isScanning = false get() = field set(value) { @@ -42,7 +41,7 @@ class BluetoothScanner( private val serviceParcelUuid = ParcelUuid(serviceUuid) private val odidAdCode = byteArrayOf(0x0D.toByte()) - private val messageHandler: OdidMessageHandler = OdidMessageHandler() + private val payloadHandler: OdidPayloadHandler = OdidPayloadHandler() @RequiresApi(Build.VERSION_CODES.O) fun scan() { @@ -66,10 +65,10 @@ class BluetoothScanner( bluetoothAdapter.isLeExtendedAdvertisingSupported ) { scanSettings = ScanSettings.Builder() - .setScanMode(scanMode) - .setLegacy(false) - .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED) - .build() + .setScanMode(scanMode) + .setLegacy(false) + .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED) + .build() } bluetoothLeScanner.startScan(scanFilters, scanSettings, scanCallback) @@ -123,68 +122,26 @@ class BluetoothScanner( } } - fun handleOdidMessage(result: ScanResult, offset: Long) { + fun handleODIDPayload(result: ScanResult, offset: Long) { val scanRecord: ScanRecord = result.scanRecord ?: return val bytes = scanRecord.bytes ?: return var source = Pigeon.MessageSource.BLUETOOTH_LEGACY; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && bluetoothAdapter.isLeCodedPhySupported()) { if (result.getPrimaryPhy() == BluetoothDevice.PHY_LE_CODED) source = Pigeon.MessageSource.BLUETOOTH_LONG_RANGE; } - val typeOrdinal = messageHandler.determineMessageType(bytes, offset) ?: return; - val type = Pigeon.MessageType.values()[typeOrdinal.toInt()] - if(type == Pigeon.MessageType.BASIC_ID) - { - val message: Pigeon.BasicIdMessage? = messageHandler.fromBufferBasic(bytes, offset, result.device.address) - message?.source = source; - message?.rssi = result.rssi.toLong(); - basicMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.LOCATION) - { - val message = messageHandler.fromBufferLocation(bytes, offset, result.device.address) - message?.source = source; - message?.rssi = result.rssi.toLong(); - locationMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.OPERATOR_ID) - { - val message = messageHandler.fromBufferOperatorId(bytes, offset, result.device.address) - message?.source = source; - message?.rssi = result.rssi.toLong(); - operatorIdMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.SELF_ID) - { - val message: Pigeon.SelfIdMessage? = messageHandler.fromBufferSelfId(bytes, offset, result.device.address) - message?.source = source; - message?.rssi = result.rssi.toLong(); - selfIdMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.AUTH) - { - val message = messageHandler.fromBufferAuthentication(bytes, offset, result.device.address) - message?.source = source; - message?.rssi = result.rssi.toLong(); - authenticationMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.SYSTEM) - { - val message = messageHandler.fromBufferSystemData(bytes, offset, result.device.address) - message?.source = source; - message?.rssi = result.rssi.toLong(); - systemDataMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.MESSAGE_PACK) - { - var packOffset = offset.toInt() + 1 - val messageSize = bytes[packOffset++]; - val messages = bytes[packOffset++]; - for (i in 0..(messages - 1)) { - handleOdidMessage(result, packOffset.toLong()) - packOffset += messageSize - } - } + if (bytes.size < offset + MAX_MESSAGE_SIZE) return + + val payload = payloadHandler.getPayload( + bytes.copyOfRange(offset.toInt(), MAX_MESSAGE_SIZE + offset.toInt()), + source, + result.device.address, + result.rssi.toLong(), + System.currentTimeMillis() + ) + + odidPayloadStreamHandler.send(payload?.toList() as Any) } val adapterStateReceiver: BroadcastReceiver = object : BroadcastReceiver() { @@ -205,7 +162,7 @@ class BluetoothScanner( private val scanCallback: ScanCallback = object : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult) { - handleOdidMessage(result, 6) + handleODIDPayload(result, 6) } override fun onBatchScanResults(results: List?) { diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt index 1535dec..b7e35e5 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt @@ -27,21 +27,21 @@ import java.util.List; class WifiNaNScanner ( - private val basicMessagesHandler: StreamHandler, - private val locationMessagesHandler: StreamHandler, - private val operatorIdMessagesHandler: StreamHandler, - private val selfIdMessagesHandler: StreamHandler, - private val authenticationMessagesHandler: StreamHandler, - private val systemDataMessagesHandler: StreamHandler, + private val odidPayloadStreamHandler: StreamHandler, private val wifiStateHandler: StreamHandler, private val wifiAwareManager: WifiAwareManager?, private val context: Context ) { - private val messageHandler = OdidMessageHandler() + companion object { + const val MAX_MESSAGE_SIZE = 25 + } + private var wifiAwareSession: WifiAwareSession? = null private val wifiScanEnabled = true private var wifiAwareSupported = true var isScanning = false + + private val payloadHandler: OdidPayloadHandler = OdidPayloadHandler() private val TAG: String = WifiNaNScanner::class.java.getSimpleName() init{ @@ -83,70 +83,33 @@ class WifiNaNScanner ( val transportType = "NAN" val timeNano: Long = SystemClock.elapsedRealtimeNanos() - receiveDataNaN( - serviceSpecificInfo, - peerHandle.hashCode(), - timeNano, - transportType - ) + if(serviceSpecificInfo != null) + receiveData( + serviceSpecificInfo, + peerHandle.hashCode(), + timeNano, + transportType + ) } }, null) } } - fun receiveDataNaN( - data: ByteArray?, peerHash: Int, timeNano: Long, + fun receiveData( + data: ByteArray, peerHash: Int, timeNano: Long, transportType: String? ) { - val typeOrdinal = messageHandler.determineMessageType(data as ByteArray, 4); - val byteBuffer = ByteBuffer.wrap(data, 4, 25) - byteBuffer.order(ByteOrder.LITTLE_ENDIAN) - if(typeOrdinal == null) - return; - val type = Pigeon.MessageType.values()[typeOrdinal.toInt()] - if(type == Pigeon.MessageType.BASIC_ID) - { - val message: Pigeon.BasicIdMessage? = messageHandler.fromBufferBasic(data as ByteArray, 4,peerHash.hashCode().toString()) - message?.source = Pigeon.MessageSource.WIFI_NAN - message?.rssi = 0 - basicMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.LOCATION) - { - val message = messageHandler.fromBufferLocation(data, 4,peerHash.hashCode().toString()) - message?.source = Pigeon.MessageSource.WIFI_NAN; - message?.rssi = 0 - locationMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.OPERATOR_ID) - { - val message = messageHandler.fromBufferOperatorId(data, 4,peerHash.hashCode().toString()) - message?.source = Pigeon.MessageSource.WIFI_NAN - message?.rssi = 0 - operatorIdMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.SELF_ID) - { - val message: Pigeon.SelfIdMessage? = messageHandler.fromBufferSelfId(data, 4,peerHash.hashCode().toString()) - message?.source = Pigeon.MessageSource.WIFI_NAN; - message?.rssi = 0 - selfIdMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.AUTH) - { - val message = messageHandler.fromBufferAuthentication(data, 4,peerHash.hashCode().toString()) - message?.source = Pigeon.MessageSource.WIFI_NAN; - message?.rssi = 0 - authenticationMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.SYSTEM) - { - val message = messageHandler.fromBufferSystemData(data, 4,peerHash.hashCode().toString()) - message?.source = Pigeon.MessageSource.WIFI_NAN; - message?.rssi = 0 - systemDataMessagesHandler.send(message?.toList() as Any) - } + val offset = 4 + val payload = payloadHandler.getPayload( + data.copyOfRange(offset, MAX_MESSAGE_SIZE + offset), + Pigeon.MessageSource.WIFI_NAN, + peerHash.hashCode().toString(), + 0, + System.currentTimeMillis() + ) + + odidPayloadStreamHandler.send(payload?.toList() as Any) } @TargetApi(Build.VERSION_CODES.O) diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt index f7eca9e..467fa58 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt @@ -13,17 +13,15 @@ import java.nio.ByteOrder import java.util.* class WifiScanner ( - private val basicMessagesHandler: StreamHandler, - private val locationMessagesHandler: StreamHandler, - private val operatorIdMessagesHandler: StreamHandler, - private val selfIdMessagesHandler: StreamHandler, - private val authenticationMessagesHandler: StreamHandler, - private val systemDataMessagesHandler: StreamHandler, + private val odidPayloadStreamHandler: StreamHandler, private val wifiStateHandler: StreamHandler, private val wifiManager: WifiManager?, private val context: Context ) { - private val messageHandler = OdidMessageHandler() + companion object { + const val MAX_MESSAGE_SIZE = 25 + } + private val CIDLen = 3 private val driStartByteOffset = 4 private val DRICID = intArrayOf(0xFA, 0x0B, 0xBC) @@ -34,6 +32,7 @@ class WifiScanner ( private var scanFailed = 0 private val wifiScanEnabled = true private val scanTimerInterval = 2 + private val payloadHandler: OdidPayloadHandler = OdidPayloadHandler() var isScanning = false private var countDownTimer: CountDownTimer? = null @@ -77,23 +76,24 @@ class WifiScanner ( val valueBytes = element.javaClass.getField("bytes")[element] ?: continue val buf: ByteBuffer = ByteBuffer.wrap(valueBytes as ByteArray).asReadOnlyBuffer() - processRemoteIdVendorIE(scanResult, buf) + receiveData(scanResult, buf) } } } else { for (element in scanResult.informationElements) { if (element != null && element.id == 221) { val buf: ByteBuffer = element.bytes - processRemoteIdVendorIE(scanResult, buf) + receiveData(scanResult, buf) } } } } - fun processRemoteIdVendorIE(scanResult: ScanResult, buf: ByteBuffer) { + fun receiveData(scanResult: ScanResult, buf: ByteBuffer) { if (buf.remaining() < 30){ return } + val offset = 1 val dri_CID = ByteArray(CIDLen) var arr = ByteArray(buf.remaining()) buf.get(dri_CID, 0, CIDLen) @@ -107,87 +107,19 @@ class WifiScanner ( && vendorType[0] == vendorTypeValue.toByte() ) { - buf.position(driStartByteOffset) - buf.get(arr, 0, buf.remaining()) - val typeOrdinal = messageHandler.determineMessageType(arr, 1); - if(typeOrdinal == null) - { - return; - } - handleODIDMessage(arr, scanResult, 0, typeOrdinal) + val payload = payloadHandler.getPayload( + arr.copyOfRange(offset, MAX_MESSAGE_SIZE + offset), + Pigeon.MessageSource.WIFI_BEACON, + scanResult.BSSID, + scanResult.level.toLong(), + System.currentTimeMillis() + ) + + odidPayloadStreamHandler.send(payload?.toList() as Any) } } - fun handleODIDMessage(arr: ByteArray, scanResult: ScanResult, offset: Long, typeOrdinal: Long) - { - val type = Pigeon.MessageType.values()[typeOrdinal.toInt()] - if(type == Pigeon.MessageType.BASIC_ID) - { - var message: Pigeon.BasicIdMessage? - if(offset.toInt() == 0) - { - message = messageHandler.fromBufferBasic(arr, 6, scanResult.BSSID) - } - else - { - message = messageHandler.fromBufferBasic(arr, offset + 1, scanResult.BSSID) - } - message?.source = Pigeon.MessageSource.WIFI_BEACON; - message?.rssi = scanResult.level.toLong(); - basicMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.LOCATION) - { - val message = messageHandler.fromBufferLocation(arr, offset + 1,scanResult.BSSID) - message?.source = Pigeon.MessageSource.WIFI_BEACON; - message?.rssi = scanResult.level.toLong(); - locationMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.OPERATOR_ID) - { - val message = messageHandler.fromBufferOperatorId(arr, offset + 1, scanResult.BSSID) - message?.source = Pigeon.MessageSource.WIFI_BEACON; - message?.rssi = scanResult.level.toLong(); - operatorIdMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.SELF_ID) - { - val message: Pigeon.SelfIdMessage? = messageHandler.fromBufferSelfId(arr, offset + 1, scanResult.BSSID) - message?.source = Pigeon.MessageSource.WIFI_BEACON - message?.rssi = scanResult.level.toLong(); - selfIdMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.AUTH) - { - val message = messageHandler.fromBufferAuthentication(arr,offset + 1, scanResult.BSSID) - message?.source = Pigeon.MessageSource.WIFI_BEACON - message?.rssi = scanResult.level.toLong(); - authenticationMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.SYSTEM) - { - val message = messageHandler.fromBufferSystemData(arr, offset + 1, scanResult.BSSID) - message?.source = Pigeon.MessageSource.WIFI_BEACON - message?.rssi = scanResult.level.toLong(); - systemDataMessagesHandler.send(message?.toList() as Any) - } - else if(type == Pigeon.MessageType.MESSAGE_PACK) - { - val messageSize = arr[2]; - val messages = arr[3]; - var packOffset = 3; - for (i in 0..messages - 1) { - val mtypeOrdinal = messageHandler.determineMessageType(arr, (packOffset + 1).toLong()); - if(mtypeOrdinal == null) - { - return; - } - // recursively call method to handle message - handleODIDMessage(arr, scanResult, packOffset.toLong(), mtypeOrdinal) - packOffset += messageSize - } - } - } + fun cancel() { if (!wifiScanEnabled) { diff --git a/ios/Classes/Models/BasicIdMessage.swift b/ios/Classes/Models/BasicIdMessage.swift deleted file mode 100644 index 8aeb54e..0000000 --- a/ios/Classes/Models/BasicIdMessage.swift +++ /dev/null @@ -1,38 +0,0 @@ -import Foundation - -class BasicIdMessage: OdidMessage { - let idType: Int - let uaType: Int - let uasId: String - - init(idType: Int, uaType: Int, uasId: String) { - self.idType = idType - self.uaType = uaType - self.uasId = uasId - } - - func getType() -> OdidMessageType { - return .BASIC_ID - } - - func toJson() -> Dictionary { - return [ - "idType": idType, - "uaType": uaType, - "uasId": uasId - ] - } - - static func fromData(_ data: Data) -> BasicIdMessage { - let bytes = Array(data) - let typeByte = bytes[0] - let idType = Int((typeByte & 0xF0) >> 4) - let uaType = Int(typeByte & 0x0F) - let uasId = String(bytes: bytes[1...], encoding: .ascii) - - return BasicIdMessage( - idType: idType, uaType: uaType, uasId: uasId ?? "" - ) - } - -} diff --git a/ios/Classes/Models/LocationMessage.swift b/ios/Classes/Models/LocationMessage.swift deleted file mode 100644 index 8300d50..0000000 --- a/ios/Classes/Models/LocationMessage.swift +++ /dev/null @@ -1,144 +0,0 @@ -import Foundation - -class LocationMessage: OdidMessage { - let status: Int - let heightType: Int - let direction: Int - let speedHori: Double - let speedVert: Double - let latitude: Double - let longitude: Double - let altitudePressure: Double - let altitudeGeodetic: Double - let height: Double - let horizontalAccuracy: Int - let verticalAccuracy: Int - let baroAccuracy: Int - let speedAccuracy: Int - let timestamp: Int - let timeAccuracy: Double - let distance: Double - - static let LAT_LONG_MULTIPLIER = 1e-7 - - init( - status: Int, - heightType: Int, - direction: Int, - speedHori: Double, - speedVert: Double, - latitude: Double, - longitude: Double, - altitudePressure: Double, - altitudeGeodetic: Double, - height: Double, - horizontalAccuracy: Int, - verticalAccuracy: Int, - baroAccuracy: Int, - speedAccuracy: Int, - timestamp: Int, - timeAccuracy: Double, - distance: Double - ) { - self.status = status - self.heightType = heightType - self.direction = direction - self.speedHori = speedHori - self.speedVert = speedVert - self.latitude = latitude - self.longitude = longitude - self.altitudePressure = altitudePressure - self.altitudeGeodetic = altitudeGeodetic - self.height = height - self.horizontalAccuracy = horizontalAccuracy - self.verticalAccuracy = verticalAccuracy - self.baroAccuracy = baroAccuracy - self.speedAccuracy = speedAccuracy - self.timestamp = timestamp - self.timeAccuracy = timeAccuracy - self.distance = distance - } - - func getType() -> OdidMessageType { - return .LOCATION - } - - func toJson() -> Dictionary { - return [ - "status": status, - "heightType": heightType, - "direction": direction, - "speedHorizontal": speedHori, - "speedVertical": speedVert, - "latitude": latitude, - "longitude": longitude, - "altitudePressure": altitudePressure, - "altitudeGeodetic": altitudeGeodetic, - "height": height, - "accuracyHorizontal": horizontalAccuracy, - "accuracyVertical": verticalAccuracy, - "accuracyBaro": baroAccuracy, - "accuracySpeed": speedAccuracy, - "locationTimestamp": timestamp, - "timeAccuracy": timeAccuracy, - "distance": distance, - ] - } - - static func decodeSpeed(value: Int, multiplier: Int) -> Double { - return multiplier == 0 ? Double(value) * 0.25 : Double(value) * 0.75 + 255 * 0.25 // 🤨 - } - - static func decodeDirection(value: Int, ew: Int) -> Int { - return ew == 0 ? value : (value + 180) - } - - static func decodeAltitude(value: Int) -> Double { - return Double(value) / 2 - 1000 - } - - static func fromData(_ data: Data) -> LocationMessage { - let bytes = Array(data) - let dataSlice = Data(bytes) - let meta = bytes[0] - - let status = Int((meta & 0xF0) >> 4) - let heightType = Int((meta & 0x04) >> 2) - let ewDirection = Int((meta & 0x02) >> 1) - let speedMult = Int((meta & 0x01)) - let direction = Int(dataSlice[1] & 0xFF) - let speedHori = Int(dataSlice[2] & 0xFF) - let speedVert = Int(dataSlice[3]) - let latitude = Int(dataSlice[4...7].uint32) - let longitude = Int(dataSlice[8...11].uint32) - let altitudePressure = Int(dataSlice[12...13].uint16) - let altitudeGeodetic = Int(dataSlice[14...15].uint16) - let height = Int(dataSlice[16...17].uint16) - let horizontalAccuracy = Int(dataSlice[18] & 0x0F) - let verticalAccuracy = Int((dataSlice[18] & 0xF0) >> 4) - let baroAccuracy = Int(dataSlice[19] & 0x0F) - let speedAccuracy = Int((dataSlice[19] & 0xF0) >> 4) - let timestamp = Int(dataSlice[20...21].uint16) - let timeAccuracy = Int(dataSlice[22] & 0x0F) - - return LocationMessage( - status: status, - heightType: heightType, - direction: decodeDirection(value: direction, ew: ewDirection), - speedHori: decodeSpeed(value: speedHori, multiplier: speedMult), - speedVert: decodeSpeed(value: speedVert, multiplier: speedMult), - latitude: LocationMessage.LAT_LONG_MULTIPLIER * Double(latitude), - longitude: LocationMessage.LAT_LONG_MULTIPLIER * Double(longitude), - altitudePressure: decodeAltitude(value: altitudePressure), - altitudeGeodetic: decodeAltitude(value: altitudeGeodetic), - height: decodeAltitude(value: height), - horizontalAccuracy: horizontalAccuracy, - verticalAccuracy: verticalAccuracy, - baroAccuracy: baroAccuracy, - speedAccuracy: speedAccuracy, - timestamp: timestamp, - timeAccuracy: Double(timeAccuracy) * 0.1, - distance: 0.0 - ) - } -} diff --git a/ios/Classes/Models/OdidMessage.swift b/ios/Classes/Models/OdidMessage.swift deleted file mode 100644 index afe4acd..0000000 --- a/ios/Classes/Models/OdidMessage.swift +++ /dev/null @@ -1,40 +0,0 @@ -import Foundation - -enum OdidMessageType: Int { - case BASIC_ID = 0 - case LOCATION = 1 - case OPERATOR_ID = 5 -} - -enum OdidMessageSource: Int { - case BLUETOOTH_LEGACY = 0 - case BLUETOOTH_LONGRANGE = 1 - case WIFI_NAN = 2 - case WIFI_BEACON = 3 -} - -class OdidMessageHeader { - public let type: OdidMessageType? - public let version: Int? - - init(type: OdidMessageType?, version: Int?) { - self.type = type - self.version = version - } - - static func fromData(_ byte: UInt8) throws -> OdidMessageHeader { - let type = Int((byte & 0xF0) >> 4) - guard type <= 5 else { - throw OdidParseFail.NotSupportedMessageType - } - return OdidMessageHeader( - type: OdidMessageType(rawValue: type), - version: Int(byte & 0xFF) - ) - } -} - -protocol OdidMessage { - func getType() -> OdidMessageType - func toJson() -> Dictionary -} diff --git a/ios/Classes/Models/OperatorIdMessage.swift b/ios/Classes/Models/OperatorIdMessage.swift deleted file mode 100644 index 8e45f9a..0000000 --- a/ios/Classes/Models/OperatorIdMessage.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation - -class OperatorIdMessage: OdidMessage { - let idType: Int - let operatorId: String - - init(idType: Int, operatorId: String) { - self.idType = idType - self.operatorId = operatorId - } - - func getType() -> OdidMessageType { - return .OPERATOR_ID - } - - func toJson() -> Dictionary { - return ["idType": idType, "operatorId": operatorId] - } - - static func fromData(_ data: Data) -> OperatorIdMessage { - let bytes = Array(data) - let idBytes = Array(data)[1...] - let operatorId = String(cString: Array(idBytes)) - - return OperatorIdMessage( - idType: Int(bytes[0]), - operatorId: operatorId - ) - } -} diff --git a/ios/Classes/OdidParser.swift b/ios/Classes/OdidParser.swift deleted file mode 100644 index 27102d3..0000000 --- a/ios/Classes/OdidParser.swift +++ /dev/null @@ -1,200 +0,0 @@ -import Foundation - -enum OdidParseFail: Error { - case NotODIDMessage - case NotSupportedMessageType -} - -class OdidParser: NSObject, DTGMessageApi { - func determineMessageTypePayload(_ payload: FlutterStandardTypedData, offset: NSNumber, error: AutoreleasingUnsafeMutablePointer) -> NSNumber? { - - let type = Int((payload.data[2] & 0xF0) >> 4) - guard type <= 5 else { - return -1; - } - return type as NSNumber - } - - func fromBufferBasicPayload(_ payload: FlutterStandardTypedData, offset: NSNumber, macAddress: String, error: AutoreleasingUnsafeMutablePointer) -> DTGBasicIdMessage? { - let bytes = Array(payload.data) - let typeByte = bytes[3] - let idType = Int((typeByte & 0xF0) >> 4) - let uaType = Int(typeByte & 0x0F) - let uasId = String(bytes: bytes[4...(4+OdidParser.MAX_ID_BYTE_SIZE-1)], encoding: .ascii) ?? "" - let systimestamp = Int(Date().timeIntervalSince1970 * 1000) - - return DTGBasicIdMessage.make(withReceivedTimestamp: systimestamp as NSNumber, macAddress: macAddress, source: DTGMessageSource.bluetoothLegacy, rssi: 0, uasId: uasId, idType: DTGIdType(rawValue: UInt(idType))!, uaType: DTGUaType(rawValue: UInt(uaType))!) - } - - func fromBufferLocationPayload(_ payload: FlutterStandardTypedData, offset: NSNumber, macAddress: String, error: AutoreleasingUnsafeMutablePointer) -> DTGLocationMessage? { - let bytes = Array(payload.data) - let dataSlice = Data(bytes) - let meta = bytes[3] - let systimestamp = Int(Date().timeIntervalSince1970 * 1000) - let status = Int((meta & 0xF0) >> 4) - let heightType = Int((meta & 0x04) >> 2) - let ewDirection = Int((meta & 0x02) >> 1) - let speedMult = Int((meta & 0x01)) - let direction = OdidParser.decodeDirection(value: Int(dataSlice[4] & 0xFF), ew: ewDirection) - let speedHori = OdidParser.decodeSpeed(value: Int(dataSlice[5] & 0xFF), multiplier: speedMult) - let speedVert = OdidParser.SPEED_VERTICAL_MULTIPLIER * Double(dataSlice[6]) - var latRaw = Int32(littleEndian: dataSlice[7...10].withUnsafeBytes { $0.pointee }) - var longRaw = Int32(littleEndian: dataSlice[11...14].withUnsafeBytes { $0.pointee }) - let latitude = OdidParser.LAT_LONG_MULTIPLIER * Double(latRaw) - let longitude = OdidParser.LAT_LONG_MULTIPLIER * Double(longRaw) - let altPressureRaw = UInt16(littleEndian: dataSlice[15...16].withUnsafeBytes { $0.pointee }) - let altGeodeticRaw = UInt16(littleEndian: dataSlice[17...18].withUnsafeBytes { $0.pointee }) - let altitudePressure = OdidParser.decodeAltitude(value: Int(altPressureRaw)) - let altitudeGeodetic = OdidParser.decodeAltitude(value: Int(altGeodeticRaw)) - let heightRaw = UInt16(littleEndian: dataSlice[19...20].withUnsafeBytes { $0.pointee }) - let height = OdidParser.decodeAltitude(value: Int(heightRaw)) - let horizontalAccuracy = Int(dataSlice[21] & 0x0F) - let verticalAccuracy = Int((dataSlice[21] & 0xF0) >> 4) - let baroAccuracy = Int((dataSlice[22] & 0xF0) >> 4) - let speedAccuracy = Int(dataSlice[22] & 0x0F) - let timestamp = Int(dataSlice[20...21].uint16) - let timeAccuracy = Double(dataSlice[25] & 0x0F) * 0.1 - return DTGLocationMessage.make(withReceivedTimestamp: systimestamp as NSNumber, macAddress: macAddress, source: DTGMessageSource.bluetoothLegacy, rssi: 0, status: DTGAircraftStatus(rawValue: UInt(status))!, heightType: DTGHeightType(rawValue: UInt(heightType))!, direction: direction as NSNumber, speedHorizontal: speedHori as NSNumber, speedVertical: speedVert as NSNumber, latitude: latitude as NSNumber, longitude: longitude as NSNumber, altitudePressure: altitudePressure as NSNumber, altitudeGeodetic: altitudeGeodetic as NSNumber, height: height as NSNumber, horizontalAccuracy: DTGHorizontalAccuracy(rawValue: UInt(horizontalAccuracy))!, verticalAccuracy: DTGVerticalAccuracy(rawValue: UInt(verticalAccuracy))!, baroAccuracy: DTGVerticalAccuracy(rawValue: UInt(baroAccuracy))!, speedAccuracy: OdidParser.decodeSpeedAccuracy(acc: speedAccuracy), time: timestamp as NSNumber, timeAccuracy: timeAccuracy as NSNumber) - } - - func fromBufferOperatorIdPayload(_ payload: FlutterStandardTypedData, offset: NSNumber, macAddress: String, error: AutoreleasingUnsafeMutablePointer) -> DTGOperatorIdMessage? { - let idBytes = Array(payload.data)[4...] - - let operatorId = String(cString: Array(idBytes)) - let systimestamp = Int(Date().timeIntervalSince1970 * 1000) - - return DTGOperatorIdMessage.make(withReceivedTimestamp: systimestamp as NSNumber, macAddress: macAddress, source: DTGMessageSource.bluetoothLegacy, rssi: 0, operatorId: operatorId) - } - - func fromBufferSelfIdPayload(_ payload: FlutterStandardTypedData, offset: NSNumber, macAddress: String, error: AutoreleasingUnsafeMutablePointer) -> DTGSelfIdMessage? { - let bytes = Array(payload.data) - var opDesc: String = "" - var it = 0 - let opDecType = (bytes[3] & 0xFF) - while(it < OdidParser.MAX_STRING_BYTE_SIZE) { - opDesc += String(bytes[4+it]) - it += 1 - } - let systimestamp = Int(Date().timeIntervalSince1970 * 1000) - return DTGSelfIdMessage.make(withReceivedTimestamp: systimestamp as NSNumber, macAddress: macAddress, source: DTGMessageSource.bluetoothLegacy, rssi: 0, descriptionType: opDecType as NSNumber, operationDescription: opDesc); - } - - func fromBufferConnectionPayload(_ payload: FlutterStandardTypedData, offset: NSNumber, macAddress: String, error: AutoreleasingUnsafeMutablePointer) -> DTGConnectionMessage? { - let systimestamp = Int(Date().timeIntervalSince1970 * 1000) - return DTGConnectionMessage.make(withReceivedTimestamp: systimestamp as NSNumber, macAddress: macAddress, source: DTGMessageSource.bluetoothLegacy, rssi: 0, transportType: "", lastSeen: 0, firstSeen: 0, msgDelta: 0) - } - - func fromBufferAuthenticationPayload(_ payload: FlutterStandardTypedData, offset: NSNumber, macAddress: String, error: AutoreleasingUnsafeMutablePointer) -> DTGAuthenticationMessage? { - let bytes = Array(payload.data) - let dataSlice = Data(bytes) - let type = bytes[3] - let authType = (type & 0xF0) >> 4 - let authDataPage: UInt8 = type & 0x0F - var authLength: UInt8 = 0 - var authTimestamp: UInt32 = 0 - var authLastPageIndex: UInt8 = 0 - var authData: String = "" - let systimestamp = Int(Date().timeIntervalSince1970 * 1000) - - var offset: UInt8 = 0 - var amount: Int = OdidParser.MAX_AUTH_PAGE_ZERO_SIZE - if (authDataPage == 0) { - authLastPageIndex = (bytes[4] & 0xFF) - authLength = bytes[5] & 0xFF - authTimestamp = UInt32(littleEndian: dataSlice[6...9].withUnsafeBytes { $0.pointee }) & 0xFFFFFFF - // For an explanation, please see the description for struct ODID_Auth_data in: - // https://github.com/opendroneid/opendroneid-core-c/blob/master/libopendroneid/opendroneid.h - var len: UInt8 = - UInt8((Int(authLastPageIndex) * OdidParser.MAX_AUTH_PAGE_NON_ZERO_SIZE + - OdidParser.MAX_AUTH_PAGE_ZERO_SIZE)) - if (authLastPageIndex >= OdidParser.MAX_AUTH_DATA_PAGES || authLength > len){ - authLastPageIndex = 0 - authLength = 0 - authTimestamp = 0 - } - else { - // Display both normal authentication data and any possible additional data - authLength = len - } - } - else { - offset = UInt8(OdidParser.MAX_AUTH_PAGE_ZERO_SIZE + (Int(authDataPage) - 0x1) * OdidParser.MAX_AUTH_PAGE_NON_ZERO_SIZE) - amount = OdidParser.MAX_AUTH_PAGE_NON_ZERO_SIZE - } - if (authDataPage >= 0 && authDataPage < OdidParser.MAX_AUTH_DATA_PAGES){ - var index = 10 - let maxLen = 26 - for _ in offset ... offset + UInt8(amount){ - if(index > maxLen){ - break - } - authData += String(bytes[index]) - index += 1 - } - } - return DTGAuthenticationMessage.make(withReceivedTimestamp: systimestamp as NSNumber, macAddress: macAddress, source: DTGMessageSource.bluetoothLegacy, rssi: 0, authType: DTGAuthType(rawValue: UInt(authType))!, authDataPage: authDataPage as NSNumber, authLastPageIndex: authLastPageIndex as NSNumber, authLength: authLength as NSNumber, authTimestamp: authTimestamp as NSNumber, authData: authData) - } - - func fromBufferSystemDataPayload(_ payload: FlutterStandardTypedData, offset: NSNumber, macAddress: String, error: AutoreleasingUnsafeMutablePointer) -> DTGSystemDataMessage? { - let bytes = Array(payload.data) - let dataSlice = Data(bytes) - var b = bytes[3] - let opLocType = b & 0x03 - let classType = (b & 0x1C) >> 2 - let systimestamp = Int(Date().timeIntervalSince1970 * 1000) - let opLat: Double = OdidParser.LAT_LONG_MULTIPLIER * Double(Int32(littleEndian: dataSlice[4...7].withUnsafeBytes { $0.pointee})) - let opLong: Double = OdidParser.LAT_LONG_MULTIPLIER * Double(Int32(littleEndian: dataSlice[8...11].withUnsafeBytes { $0.pointee})) - let areaCnt = UInt16(littleEndian: dataSlice[12...13].withUnsafeBytes { $0.pointee}) & 0xFFFF - let areaRad = (dataSlice[14] & 0xFF) * 10 - let areaCeil: Double = OdidParser.decodeAltitude(value: Int(littleEndian: dataSlice[15...16].withUnsafeBytes { $0.pointee}) & 0xFFFF) - let areaFloor: Double = OdidParser.decodeAltitude(value: Int(littleEndian: dataSlice[17...18].withUnsafeBytes { $0.pointee}) & 0xFFFF) - b = dataSlice[19] - let airCat = (b & 0xF0) >> 4 - let airClass = b & 0x0F - let altGeo : Double = OdidParser.decodeAltitude(value: Int(littleEndian: dataSlice[20...21].withUnsafeBytes { $0.pointee} & 0xFFFF)) - - return DTGSystemDataMessage.make(withReceivedTimestamp: systimestamp as NSNumber, macAddress: macAddress, source: DTGMessageSource.bluetoothLegacy, rssi: 0, operatorLocationType: DTGOperatorLocationType(rawValue: UInt(opLocType))!, classificationType: DTGClassificationType(rawValue: UInt(classType))!, operatorLatitude: opLat as NSNumber, operatorLongitude: opLong as NSNumber, areaCount: areaCnt as NSNumber, areaRadius: areaRad as NSNumber, areaCeiling: areaCeil as NSNumber, areaFloor: areaFloor as NSNumber, category: DTGAircraftCategory(rawValue: UInt(airCat))!, classValue: DTGAircraftClass(rawValue: UInt(airClass))!, operatorAltitudeGeo: altGeo as NSNumber) - } - - static let odidAdCode: [UInt8] = [ 0x0D ] - static let LAT_LONG_MULTIPLIER = 1e-7 - static let SPEED_VERTICAL_MULTIPLIER = 0.5 - static let MAX_MESSAGE_SIZE = 25 - static let MAX_ID_BYTE_SIZE = 20 - static let MAX_STRING_BYTE_SIZE = 23 - static let MAX_AUTH_DATA_PAGES = 16 - static let MAX_AUTH_PAGE_ZERO_SIZE = 17 - static let MAX_AUTH_PAGE_NON_ZERO_SIZE = 23 - static let MAX_AUTH_DATA = - MAX_AUTH_PAGE_ZERO_SIZE + (MAX_AUTH_DATA_PAGES - 1) * MAX_AUTH_PAGE_NON_ZERO_SIZE - static let MAX_MESSAGES_IN_PACK = 9 - static let MAX_MESSAGE_PACK_SIZE: Int = MAX_MESSAGE_SIZE * MAX_MESSAGES_IN_PACK - - - static func decodeSpeed(value: Int, multiplier: Int) -> Double { - return multiplier == 0 ? Double(value) * 0.25 : Double(value) * 0.75 + 255 * 0.25 // 🤨 - } - - static func decodeSpeedAccuracy(acc: Int) -> DTGSpeedAccuracy { - if(acc == 10){ - return DTGSpeedAccuracy.meter_per_second_10 - - } - else if(acc == 3){ - return DTGSpeedAccuracy.meter_per_second_3 - } - else if(acc == 1){ - return DTGSpeedAccuracy.meter_per_second_1 - } - //meter_per_second_0_3 - return DTGSpeedAccuracy.unknown - } - - static func decodeDirection(value: Int, ew: Int) -> Double { - return Double(ew == 0 ? value : (value + 180)) - } - - static func decodeAltitude(value: Int) -> Double { - return Double(value) / 2 - 1000 - } -} diff --git a/ios/Classes/Scanner/BluetoothScanner.swift b/ios/Classes/Scanner/BluetoothScanner.swift index 53b18e4..39f6f0a 100644 --- a/ios/Classes/Scanner/BluetoothScanner.swift +++ b/ios/Classes/Scanner/BluetoothScanner.swift @@ -1,15 +1,9 @@ import Foundation import CoreBluetooth -class BluetoothScanner: NSObject, CBCentralManagerDelegate { - private let operatoridMessageHandler: StreamHandler - private let basicMessageHandler: StreamHandler - private let locationMessageHandler: StreamHandler - private let selfidMessageHandler: StreamHandler - private let authMessageHandler: StreamHandler - private let systemMessageHandler: StreamHandler +class BluetoothScanner: NSObject, CBCentralManagerDelegate, DTGPayloadApi { + private let odidPayloadStreamHandler: StreamHandler private let scanStateHandler: StreamHandler - private let dataParser: OdidParser private var centralManager: CBCentralManager! private var scanPriority: DTGScanPriority = .high @@ -18,16 +12,11 @@ class BluetoothScanner: NSObject, CBCentralManagerDelegate { let dispatchQueue: DispatchQueue = DispatchQueue(label: "BluetoothScanner") static let serviceUUID = CBUUID(string: "0000fffa-0000-1000-8000-00805f9b34fb") + static let odidAdCode: [UInt8] = [ 0x0D ] - init(basicMessageHandler: StreamHandler, locationMessageHandler: StreamHandler, operatoridMessageHandler: StreamHandler, authMessageHandler: StreamHandler, systemMessageHandler: StreamHandler, selfidMessageHandler: StreamHandler, scanStateHandler: StreamHandler) { - self.basicMessageHandler = basicMessageHandler - self.operatoridMessageHandler = operatoridMessageHandler - self.locationMessageHandler = locationMessageHandler - self.authMessageHandler = authMessageHandler - self.selfidMessageHandler = selfidMessageHandler - self.systemMessageHandler = systemMessageHandler + init(odidPayloadStreamHandler: StreamHandler, scanStateHandler: StreamHandler) { + self.odidPayloadStreamHandler = odidPayloadStreamHandler self.scanStateHandler = scanStateHandler - self.dataParser = OdidParser() super.init() centralManager = CBCentralManager(delegate: self, queue: dispatchQueue) @@ -94,7 +83,7 @@ class BluetoothScanner: NSObject, CBCentralManagerDelegate { } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { - handleOdidMessage(advertisementData: advertisementData, didDiscover: peripheral, rssi: RSSI, offset: 6) + handleOdidMessage(advertisementData: advertisementData, didDiscover: peripheral, rssi: RSSI, offset: 2) } private func scanForPeripherals(){ @@ -105,72 +94,24 @@ class BluetoothScanner: NSObject, CBCentralManagerDelegate { ] ) } + + func getPayloadRawData(_ rawData: FlutterStandardTypedData, source: DTGMessageSource, macAddress: String, rssi: NSNumber, receivedTimestamp: NSNumber, error: AutoreleasingUnsafeMutablePointer) -> DTGODIDPayload? { + return DTGODIDPayload.make(withRawData: rawData, receivedTimestamp: receivedTimestamp, macAddress: macAddress, rssi: rssi, source: source) + } private func handleOdidMessage(advertisementData: [String : Any], didDiscover peripheral: CBPeripheral, rssi RSSI: NSNumber, offset: NSNumber){ - guard let data = getOdidPayload(from: advertisementData) else { + guard let data = getOdidData(from: advertisementData, offset: offset) else { // This advertisement is not an ODID ad data return } - - do { - var err: FlutterError? - let typeOrdinal = UInt(exactly: dataParser.determineMessageTypePayload(data, offset: offset, error: &err)!) - let type = DTGMessageType(rawValue: typeOrdinal!) - if(type == DTGMessageType.basicId) - { - let message : DTGBasicIdMessage? = dataParser.fromBufferBasicPayload(data, offset: offset, macAddress: peripheral.identifier.uuidString, error: &err) - message!.rssi = RSSI.intValue as NSNumber - basicMessageHandler.send(message!.toList() as Any) - } - else if(type == DTGMessageType.location) - { - let message : DTGLocationMessage? = dataParser.fromBufferLocationPayload(data, offset: offset, macAddress: peripheral.identifier.uuidString, error: &err) - message!.rssi = RSSI.intValue as NSNumber - locationMessageHandler.send(message!.toList() as Any) - } - else if(type == DTGMessageType.operatorId) - { - let message : DTGOperatorIdMessage? = dataParser.fromBufferOperatorIdPayload(data, offset: offset, macAddress: peripheral.identifier.uuidString, error: &err) - message!.rssi = RSSI.intValue as NSNumber - operatoridMessageHandler.send(message!.toList() as Any) - } - else if(type == DTGMessageType.selfId) - { - let message : DTGSelfIdMessage? = dataParser.fromBufferSelfIdPayload(data, offset: offset, macAddress: peripheral.identifier.uuidString, error: &err) - message!.rssi = RSSI.intValue as NSNumber - selfidMessageHandler.send(message!.toList() as Any) - } - else if(type == DTGMessageType.auth) - { - let message : DTGAuthenticationMessage? = dataParser.fromBufferAuthenticationPayload(data, offset: offset, macAddress: peripheral.identifier.uuidString, error: &err) - message!.rssi = RSSI.intValue as NSNumber - authMessageHandler.send(message!.toList() as Any) - } - else if(type == DTGMessageType.system) - { - let message : DTGSystemDataMessage? = dataParser.fromBufferSystemDataPayload(data, offset: offset, macAddress: peripheral.identifier.uuidString, error: &err) - message!.rssi = RSSI.intValue as NSNumber - systemMessageHandler.send(message!.toList() as Any) - } - else if(type == DTGMessageType.messagePack) - { - let bytes = Array(data.data) - var packOffset = offset as! Int + 1 - let messageSize = bytes[packOffset]; - packOffset += 1 - let messages = bytes[packOffset]; - packOffset += 1 - for _ in 0 ... (messages - 1) { - handleOdidMessage(advertisementData: advertisementData, didDiscover: peripheral, rssi: RSSI, offset: packOffset as NSNumber) - packOffset += Int(messageSize) - } - } - } catch { - return - } + var err: FlutterError? + let systimestamp = Int(Date().timeIntervalSince1970 * 1000) + let payload = getPayloadRawData(data, source: DTGMessageSource.bluetoothLegacy, macAddress: peripheral.identifier.uuidString, rssi: RSSI.intValue as NSNumber, receivedTimestamp: systimestamp as NSNumber, error: &err) + + odidPayloadStreamHandler.send(payload!.toList() as Any) } - private func getOdidPayload(from advertisementData: [String : Any]) -> FlutterStandardTypedData? { + private func getOdidData(from advertisementData: [String : Any], offset: NSNumber) -> FlutterStandardTypedData? { // Peripheral must have service data guard let serviceData = advertisementData["kCBAdvDataServiceData"] else { return nil @@ -184,9 +125,10 @@ class BluetoothScanner: NSObject, CBCentralManagerDelegate { } let data = serviceDataDict[BluetoothScanner.serviceUUID] as! Data - let dataF = FlutterStandardTypedData(bytes: data) + // offset data + let dataF = FlutterStandardTypedData(bytes: data.dropFirst(offset.intValue)) // All data must start with 0x0D - guard data.starts(with: OdidParser.odidAdCode) else { + guard data.starts(with: BluetoothScanner.odidAdCode) else { return nil } return dataF diff --git a/ios/Classes/SwiftFlutterOpendroneidPlugin.swift b/ios/Classes/SwiftFlutterOpendroneidPlugin.swift index c0d7a04..7611505 100644 --- a/ios/Classes/SwiftFlutterOpendroneidPlugin.swift +++ b/ios/Classes/SwiftFlutterOpendroneidPlugin.swift @@ -3,14 +3,10 @@ import UIKit @available(iOS 13.0.0, *) public class SwiftFlutterOpendroneidPlugin: NSObject, FlutterPlugin, DTGApi{ + private var bluetoothScanner: BluetoothScanner! - private let locationMessagesStreamHandler = StreamHandler() - private let operatoridMessagesStreamHandler = StreamHandler() - private let basicMessagesStreamHandler = StreamHandler() - private let authMessagesStreamHandler = StreamHandler() - private let selfidMessagesStreamHandler = StreamHandler() - private let systemMessagesStreamHandler = StreamHandler() + private let odidPayloadStreamHandler = StreamHandler() private let bluetoothStateStreamHandler = StreamHandler() private let wifiStateStreamHandler = StreamHandler() @@ -19,26 +15,14 @@ public class SwiftFlutterOpendroneidPlugin: NSObject, FlutterPlugin, DTGApi{ let instance : SwiftFlutterOpendroneidPlugin & DTGApi & NSObjectProtocol = SwiftFlutterOpendroneidPlugin.init() DTGApiSetup(messenger, instance); - //let instance = SwiftFlutterOpendroneidPlugin() - // Event channels - FlutterEventChannel(name: "flutter_location_messages", binaryMessenger: registrar.messenger()).setStreamHandler(instance.locationMessagesStreamHandler) - FlutterEventChannel(name: "flutter_operatorid_messages", binaryMessenger: registrar.messenger()).setStreamHandler(instance.operatoridMessagesStreamHandler) - FlutterEventChannel(name: "flutter_basic_messages", binaryMessenger: registrar.messenger()).setStreamHandler(instance.basicMessagesStreamHandler) - FlutterEventChannel(name: "flutter_system_messages", binaryMessenger: registrar.messenger()).setStreamHandler(instance.systemMessagesStreamHandler) - FlutterEventChannel(name: "flutter_selfid_messages", binaryMessenger: registrar.messenger()).setStreamHandler(instance.selfidMessagesStreamHandler) - FlutterEventChannel(name: "flutter_auth_messages", binaryMessenger: registrar.messenger()).setStreamHandler(instance.authMessagesStreamHandler) + FlutterEventChannel(name: "flutter_odid_data", binaryMessenger: registrar.messenger()).setStreamHandler(instance.odidPayloadStreamHandler) FlutterEventChannel(name: "flutter_odid_bt_state", binaryMessenger: registrar.messenger()).setStreamHandler(instance.bluetoothStateStreamHandler) FlutterEventChannel(name: "flutter_odid_wifi_state", binaryMessenger: registrar.messenger()).setStreamHandler(instance.wifiStateStreamHandler) // Register bluetooth scanner instance.bluetoothScanner = BluetoothScanner( - basicMessageHandler: instance.basicMessagesStreamHandler, - locationMessageHandler: instance.locationMessagesStreamHandler, - operatoridMessageHandler: instance.operatoridMessagesStreamHandler, - authMessageHandler: instance.authMessagesStreamHandler, - systemMessageHandler: instance.systemMessagesStreamHandler, - selfidMessageHandler: instance.selfidMessagesStreamHandler, + odidPayloadStreamHandler: instance.odidPayloadStreamHandler, scanStateHandler: instance.bluetoothStateStreamHandler ) } diff --git a/ios/Classes/pigeon.h b/ios/Classes/pigeon.h index cade147..9165fa6 100644 --- a/ios/Classes/pigeon.h +++ b/ios/Classes/pigeon.h @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.0.0), do not edit directly. +// Autogenerated from Pigeon (v10.1.6), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @@ -10,17 +10,7 @@ NS_ASSUME_NONNULL_BEGIN -/// ODID Message Type -typedef NS_ENUM(NSUInteger, DTGMessageType) { - DTGMessageTypeBasicId = 0, - DTGMessageTypeLocation = 1, - DTGMessageTypeAuth = 2, - DTGMessageTypeSelfId = 3, - DTGMessageTypeSystem = 4, - DTGMessageTypeOperatorId = 5, - DTGMessageTypeMessagePack = 6, -}; - +/// Higher priority drains battery but receives more data typedef NS_ENUM(NSUInteger, DTGScanPriority) { DTGScanPriorityHigh = 0, DTGScanPriorityLow = 1, @@ -35,87 +25,6 @@ typedef NS_ENUM(NSUInteger, DTGMessageSource) { DTGMessageSourceUnknown = 4, }; -/// Identification type -typedef NS_ENUM(NSUInteger, DTGIdType) { - DTGIdTypeNone = 0, - DTGIdTypeSerial_Number = 1, - DTGIdTypeCAA_Registration_ID = 2, - DTGIdTypeUTM_Assigned_ID = 3, - DTGIdTypeSpecific_Session_ID = 4, -}; - -/// Unmanned aircraft type -typedef NS_ENUM(NSUInteger, DTGUaType) { - DTGUaTypeNone = 0, - DTGUaTypeAeroplane = 1, - DTGUaTypeHelicopter_or_Multirotor = 2, - DTGUaTypeGyroplane = 3, - DTGUaTypeHybrid_Lift = 4, - DTGUaTypeOrnithopter = 5, - DTGUaTypeGlider = 6, - DTGUaTypeKite = 7, - DTGUaTypeFree_balloon = 8, - DTGUaTypeCaptive_balloon = 9, - DTGUaTypeAirship = 10, - DTGUaTypeFree_fall_parachute = 11, - DTGUaTypeRocket = 12, - DTGUaTypeTethered_powered_aircraft = 13, - DTGUaTypeGround_obstacle = 14, - DTGUaTypeOther = 15, -}; - -/// Aircraft flight status -typedef NS_ENUM(NSUInteger, DTGAircraftStatus) { - DTGAircraftStatusUndeclared = 0, - DTGAircraftStatusGround = 1, - DTGAircraftStatusAirborne = 2, - DTGAircraftStatusEmergency = 3, - DTGAircraftStatusRemote_ID_System_Failure = 4, -}; - -/// Height value type -typedef NS_ENUM(NSUInteger, DTGHeightType) { - DTGHeightTypeTakeoff = 0, - DTGHeightTypeGround = 1, -}; - -/// Horizontal accuracy -typedef NS_ENUM(NSUInteger, DTGHorizontalAccuracy) { - DTGHorizontalAccuracyUnknown = 0, - DTGHorizontalAccuracyKilometers_18_52 = 1, - DTGHorizontalAccuracyKilometers_7_408 = 2, - DTGHorizontalAccuracyKilometers_3_704 = 3, - DTGHorizontalAccuracyKilometers_1_852 = 4, - DTGHorizontalAccuracyMeters_926 = 5, - DTGHorizontalAccuracyMeters_555_6 = 6, - DTGHorizontalAccuracyMeters_185_2 = 7, - DTGHorizontalAccuracyMeters_92_6 = 8, - DTGHorizontalAccuracyMeters_30 = 9, - DTGHorizontalAccuracyMeters_10 = 10, - DTGHorizontalAccuracyMeters_3 = 11, - DTGHorizontalAccuracyMeters_1 = 12, -}; - -/// Vertical accuracy -typedef NS_ENUM(NSUInteger, DTGVerticalAccuracy) { - DTGVerticalAccuracyUnknown = 0, - DTGVerticalAccuracyMeters_150 = 1, - DTGVerticalAccuracyMeters_45 = 2, - DTGVerticalAccuracyMeters_25 = 3, - DTGVerticalAccuracyMeters_10 = 4, - DTGVerticalAccuracyMeters_3 = 5, - DTGVerticalAccuracyMeters_1 = 6, -}; - -/// Speed accuracy -typedef NS_ENUM(NSUInteger, DTGSpeedAccuracy) { - DTGSpeedAccuracyUnknown = 0, - DTGSpeedAccuracyMeter_per_second_10 = 1, - DTGSpeedAccuracyMeter_per_second_3 = 2, - DTGSpeedAccuracyMeter_per_second_1 = 3, - DTGSpeedAccuracyMeter_per_second_0_3 = 4, -}; - /// State of the Bluetooth adapter typedef NS_ENUM(NSUInteger, DTGBluetoothState) { DTGBluetoothStateUnknown = 0, @@ -134,264 +43,23 @@ typedef NS_ENUM(NSUInteger, DTGWifiState) { DTGWifiStateEnabled = 3, }; -typedef NS_ENUM(NSUInteger, DTGAuthType) { - DTGAuthTypeNone = 0, - DTGAuthTypeUAS_ID_Signature = 1, - DTGAuthTypeOperator_ID_Signature = 2, - DTGAuthTypeMessage_Set_Signature = 3, - DTGAuthTypeNetwork_Remote_ID = 4, - DTGAuthTypeSpecific_Authentication = 5, - DTGAuthTypePrivate_Use_0xA = 6, - DTGAuthTypePrivate_Use_0xB = 7, - DTGAuthTypePrivate_Use_0xC = 8, - DTGAuthTypePrivate_Use_0xD = 9, - DTGAuthTypePrivate_Use_0xE = 10, - DTGAuthTypePrivate_Use_0xF = 11, -}; - -typedef NS_ENUM(NSUInteger, DTGAircraftCategory) { - DTGAircraftCategoryUndeclared = 0, - DTGAircraftCategoryEU_Open = 1, - DTGAircraftCategoryEU_Specific = 2, - DTGAircraftCategoryEU_Certified = 3, -}; - -typedef NS_ENUM(NSUInteger, DTGAircraftClass) { - DTGAircraftClassUndeclared = 0, - DTGAircraftClassEU_Class_0 = 1, - DTGAircraftClassEU_Class_1 = 2, - DTGAircraftClassEU_Class_2 = 3, - DTGAircraftClassEU_Class_3 = 4, - DTGAircraftClassEU_Class_4 = 5, - DTGAircraftClassEU_Class_5 = 6, - DTGAircraftClassEU_Class_6 = 7, -}; - -typedef NS_ENUM(NSUInteger, DTGOperatorLocationType) { - DTGOperatorLocationTypeTakeOff = 0, - DTGOperatorLocationTypeLiveGNSS = 1, - DTGOperatorLocationTypeFixedLocation = 2, - DTGOperatorLocationTypeInvalid = 3, -}; - -typedef NS_ENUM(NSUInteger, DTGClassificationType) { - DTGClassificationTypeUndeclared = 0, - DTGClassificationTypeEU = 1, -}; - -@class DTGBasicIdMessage; -@class DTGLocationMessage; -@class DTGOperatorIdMessage; -@class DTGAuthenticationMessage; -@class DTGSelfIdMessage; -@class DTGSystemDataMessage; -@class DTGConnectionMessage; - -@interface DTGBasicIdMessage : NSObject -- (NSArray *)toList; -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - uasId:(NSString *)uasId - idType:(DTGIdType)idType - uaType:(DTGUaType)uaType; -@property(nonatomic, strong) NSNumber * receivedTimestamp; -@property(nonatomic, copy) NSString * macAddress; -@property(nonatomic, assign) DTGMessageSource source; -@property(nonatomic, strong, nullable) NSNumber * rssi; -/// The primary identifier of UAS -/// (Dronetag devices use their serial number as their UAS ID) -@property(nonatomic, copy) NSString * uasId; -/// Identification type -@property(nonatomic, assign) DTGIdType idType; -/// Type of the aircraft -@property(nonatomic, assign) DTGUaType uaType; -@end - -@interface DTGLocationMessage : NSObject -- (NSArray *)toList; -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - status:(DTGAircraftStatus)status - heightType:(DTGHeightType)heightType - direction:(nullable NSNumber *)direction - speedHorizontal:(nullable NSNumber *)speedHorizontal - speedVertical:(nullable NSNumber *)speedVertical - latitude:(nullable NSNumber *)latitude - longitude:(nullable NSNumber *)longitude - altitudePressure:(nullable NSNumber *)altitudePressure - altitudeGeodetic:(nullable NSNumber *)altitudeGeodetic - height:(nullable NSNumber *)height - horizontalAccuracy:(DTGHorizontalAccuracy)horizontalAccuracy - verticalAccuracy:(DTGVerticalAccuracy)verticalAccuracy - baroAccuracy:(DTGVerticalAccuracy)baroAccuracy - speedAccuracy:(DTGSpeedAccuracy)speedAccuracy - time:(nullable NSNumber *)time - timeAccuracy:(nullable NSNumber *)timeAccuracy; -@property(nonatomic, strong) NSNumber * receivedTimestamp; -@property(nonatomic, copy) NSString * macAddress; -@property(nonatomic, assign) DTGMessageSource source; -@property(nonatomic, strong, nullable) NSNumber * rssi; -/// The reported current status of the aircraft -@property(nonatomic, assign) DTGAircraftStatus status; -/// The type of reported height -/// -/// (The default type is takeoff height) -@property(nonatomic, assign) DTGHeightType heightType; -/// Direction of the aircraft heading (in degrees) -@property(nonatomic, strong, nullable) NSNumber * direction; -/// Horizontal speed of the aircraft -@property(nonatomic, strong, nullable) NSNumber * speedHorizontal; -/// Vertical speed of the aircraft -@property(nonatomic, strong, nullable) NSNumber * speedVertical; -/// Location latitude of the aircraft -@property(nonatomic, strong, nullable) NSNumber * latitude; -/// Location longitude of the aircraft -@property(nonatomic, strong, nullable) NSNumber * longitude; -/// Altitude calculcated from barometric pressure (in meters) -@property(nonatomic, strong, nullable) NSNumber * altitudePressure; -/// Altitude calculated from GNSS data (in meters) -@property(nonatomic, strong, nullable) NSNumber * altitudeGeodetic; -/// Current height of the aircraft -@property(nonatomic, strong, nullable) NSNumber * height; -/// Horizontal accuracy of reported position via GNSS -@property(nonatomic, assign) DTGHorizontalAccuracy horizontalAccuracy; -/// Vertical accuracy of reported altitude via GNSS -@property(nonatomic, assign) DTGVerticalAccuracy verticalAccuracy; -/// Vertical accuracy of reported altitude via barometric pressure -@property(nonatomic, assign) DTGVerticalAccuracy baroAccuracy; -/// Speed accuracy of reported position via GNSS -@property(nonatomic, assign) DTGSpeedAccuracy speedAccuracy; -/// Time of the location report -@property(nonatomic, strong, nullable) NSNumber * time; -/// Accuracy of timestamp values -@property(nonatomic, strong, nullable) NSNumber * timeAccuracy; -@end - -@interface DTGOperatorIdMessage : NSObject -- (NSArray *)toList; -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - operatorId:(NSString *)operatorId; -/// Operator ID -@property(nonatomic, strong) NSNumber * receivedTimestamp; -@property(nonatomic, copy) NSString * macAddress; -@property(nonatomic, assign) DTGMessageSource source; -@property(nonatomic, strong, nullable) NSNumber * rssi; -@property(nonatomic, copy) NSString * operatorId; -@end - -@interface DTGAuthenticationMessage : NSObject -- (NSArray *)toList; -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - authType:(DTGAuthType)authType - authDataPage:(NSNumber *)authDataPage - authLastPageIndex:(NSNumber *)authLastPageIndex - authLength:(NSNumber *)authLength - authTimestamp:(NSNumber *)authTimestamp - authData:(NSString *)authData; -@property(nonatomic, strong) NSNumber * receivedTimestamp; -@property(nonatomic, copy) NSString * macAddress; -@property(nonatomic, assign) DTGMessageSource source; -@property(nonatomic, strong, nullable) NSNumber * rssi; -@property(nonatomic, assign) DTGAuthType authType; -@property(nonatomic, strong) NSNumber * authDataPage; -@property(nonatomic, strong) NSNumber * authLastPageIndex; -@property(nonatomic, strong) NSNumber * authLength; -@property(nonatomic, strong) NSNumber * authTimestamp; -@property(nonatomic, copy) NSString * authData; -@end +@class DTGODIDPayload; -@interface DTGSelfIdMessage : NSObject -- (NSArray *)toList; +/// Payload send from native to dart contains raw data and metadata +@interface DTGODIDPayload : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - descriptionType:(NSNumber *)descriptionType - operationDescription:(NSString *)operationDescription; -@property(nonatomic, strong) NSNumber * receivedTimestamp; -@property(nonatomic, copy) NSString * macAddress; -@property(nonatomic, assign) DTGMessageSource source; -@property(nonatomic, strong, nullable) NSNumber * rssi; -@property(nonatomic, strong) NSNumber * descriptionType; -@property(nonatomic, copy) NSString * operationDescription; -@end - -@interface DTGSystemDataMessage : NSObject - (NSArray *)toList; -/// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp ++ (instancetype)makeWithRawData:(FlutterStandardTypedData *)rawData + receivedTimestamp:(NSNumber *)receivedTimestamp macAddress:(NSString *)macAddress - source:(DTGMessageSource)source rssi:(nullable NSNumber *)rssi - operatorLocationType:(DTGOperatorLocationType)operatorLocationType - classificationType:(DTGClassificationType)classificationType - operatorLatitude:(NSNumber *)operatorLatitude - operatorLongitude:(NSNumber *)operatorLongitude - areaCount:(NSNumber *)areaCount - areaRadius:(NSNumber *)areaRadius - areaCeiling:(NSNumber *)areaCeiling - areaFloor:(NSNumber *)areaFloor - category:(DTGAircraftCategory)category - classValue:(DTGAircraftClass)classValue - operatorAltitudeGeo:(NSNumber *)operatorAltitudeGeo; + source:(DTGMessageSource)source; +@property(nonatomic, strong) FlutterStandardTypedData * rawData; @property(nonatomic, strong) NSNumber * receivedTimestamp; @property(nonatomic, copy) NSString * macAddress; -@property(nonatomic, assign) DTGMessageSource source; @property(nonatomic, strong, nullable) NSNumber * rssi; -@property(nonatomic, assign) DTGOperatorLocationType operatorLocationType; -@property(nonatomic, assign) DTGClassificationType classificationType; -@property(nonatomic, strong) NSNumber * operatorLatitude; -@property(nonatomic, strong) NSNumber * operatorLongitude; -@property(nonatomic, strong) NSNumber * areaCount; -@property(nonatomic, strong) NSNumber * areaRadius; -@property(nonatomic, strong) NSNumber * areaCeiling; -@property(nonatomic, strong) NSNumber * areaFloor; -@property(nonatomic, assign) DTGAircraftCategory category; -@property(nonatomic, assign) DTGAircraftClass classValue; -@property(nonatomic, strong) NSNumber * operatorAltitudeGeo; -@end - -@interface DTGConnectionMessage : NSObject -- (NSArray *)toList; -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - transportType:(NSString *)transportType - lastSeen:(NSNumber *)lastSeen - firstSeen:(NSNumber *)firstSeen - msgDelta:(NSNumber *)msgDelta; -@property(nonatomic, strong) NSNumber * receivedTimestamp; -@property(nonatomic, copy) NSString * macAddress; @property(nonatomic, assign) DTGMessageSource source; -@property(nonatomic, strong, nullable) NSNumber * rssi; -@property(nonatomic, copy) NSString * transportType; -@property(nonatomic, strong) NSNumber * lastSeen; -@property(nonatomic, strong) NSNumber * firstSeen; -@property(nonatomic, strong) NSNumber * msgDelta; @end /// The codec used by DTGApi. @@ -414,20 +82,14 @@ NSObject *DTGApiGetCodec(void); extern void DTGApiSetup(id binaryMessenger, NSObject *_Nullable api); -/// The codec used by DTGMessageApi. -NSObject *DTGMessageApiGetCodec(void); +/// The codec used by DTGPayloadApi. +NSObject *DTGPayloadApiGetCodec(void); -@protocol DTGMessageApi -- (nullable NSNumber *)determineMessageTypePayload:(FlutterStandardTypedData *)payload offset:(NSNumber *)offset error:(FlutterError *_Nullable *_Nonnull)error; -- (nullable DTGBasicIdMessage *)fromBufferBasicPayload:(FlutterStandardTypedData *)payload offset:(NSNumber *)offset macAddress:(NSString *)macAddress error:(FlutterError *_Nullable *_Nonnull)error; -- (nullable DTGLocationMessage *)fromBufferLocationPayload:(FlutterStandardTypedData *)payload offset:(NSNumber *)offset macAddress:(NSString *)macAddress error:(FlutterError *_Nullable *_Nonnull)error; -- (nullable DTGOperatorIdMessage *)fromBufferOperatorIdPayload:(FlutterStandardTypedData *)payload offset:(NSNumber *)offset macAddress:(NSString *)macAddress error:(FlutterError *_Nullable *_Nonnull)error; -- (nullable DTGSelfIdMessage *)fromBufferSelfIdPayload:(FlutterStandardTypedData *)payload offset:(NSNumber *)offset macAddress:(NSString *)macAddress error:(FlutterError *_Nullable *_Nonnull)error; -- (nullable DTGAuthenticationMessage *)fromBufferAuthenticationPayload:(FlutterStandardTypedData *)payload offset:(NSNumber *)offset macAddress:(NSString *)macAddress error:(FlutterError *_Nullable *_Nonnull)error; -- (nullable DTGSystemDataMessage *)fromBufferSystemDataPayload:(FlutterStandardTypedData *)payload offset:(NSNumber *)offset macAddress:(NSString *)macAddress error:(FlutterError *_Nullable *_Nonnull)error; -- (nullable DTGConnectionMessage *)fromBufferConnectionPayload:(FlutterStandardTypedData *)payload offset:(NSNumber *)offset macAddress:(NSString *)macAddress error:(FlutterError *_Nullable *_Nonnull)error; +@protocol DTGPayloadApi +/// @return `nil` only when `error != nil`. +- (nullable DTGODIDPayload *)getPayloadRawData:(FlutterStandardTypedData *)rawData source:(DTGMessageSource)source macAddress:(NSString *)macAddress rssi:(NSNumber *)rssi receivedTimestamp:(NSNumber *)receivedTimestamp error:(FlutterError *_Nullable *_Nonnull)error; @end -extern void DTGMessageApiSetup(id binaryMessenger, NSObject *_Nullable api); +extern void DTGPayloadApiSetup(id binaryMessenger, NSObject *_Nullable api); NS_ASSUME_NONNULL_END diff --git a/ios/Classes/pigeon.m b/ios/Classes/pigeon.m index 86c0bcf..1fb85a7 100644 --- a/ios/Classes/pigeon.m +++ b/ios/Classes/pigeon.m @@ -1,8 +1,13 @@ -// Autogenerated from Pigeon (v10.0.0), do not edit directly. +// Autogenerated from Pigeon (v10.1.6), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "pigeon.h" + +#if TARGET_OS_OSX +#import +#else #import +#endif #if !__has_feature(objc_arc) #error File requires ARC to be enabled. @@ -21,481 +26,48 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { return (result == [NSNull null]) ? nil : result; } -@interface DTGBasicIdMessage () -+ (DTGBasicIdMessage *)fromList:(NSArray *)list; -+ (nullable DTGBasicIdMessage *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface DTGLocationMessage () -+ (DTGLocationMessage *)fromList:(NSArray *)list; -+ (nullable DTGLocationMessage *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface DTGOperatorIdMessage () -+ (DTGOperatorIdMessage *)fromList:(NSArray *)list; -+ (nullable DTGOperatorIdMessage *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface DTGAuthenticationMessage () -+ (DTGAuthenticationMessage *)fromList:(NSArray *)list; -+ (nullable DTGAuthenticationMessage *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface DTGSelfIdMessage () -+ (DTGSelfIdMessage *)fromList:(NSArray *)list; -+ (nullable DTGSelfIdMessage *)nullableFromList:(NSArray *)list; +@interface DTGODIDPayload () ++ (DTGODIDPayload *)fromList:(NSArray *)list; ++ (nullable DTGODIDPayload *)nullableFromList:(NSArray *)list; - (NSArray *)toList; @end -@interface DTGSystemDataMessage () -+ (DTGSystemDataMessage *)fromList:(NSArray *)list; -+ (nullable DTGSystemDataMessage *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface DTGConnectionMessage () -+ (DTGConnectionMessage *)fromList:(NSArray *)list; -+ (nullable DTGConnectionMessage *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@implementation DTGBasicIdMessage -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp +@implementation DTGODIDPayload ++ (instancetype)makeWithRawData:(FlutterStandardTypedData *)rawData + receivedTimestamp:(NSNumber *)receivedTimestamp macAddress:(NSString *)macAddress - source:(DTGMessageSource)source rssi:(nullable NSNumber *)rssi - uasId:(NSString *)uasId - idType:(DTGIdType)idType - uaType:(DTGUaType)uaType { - DTGBasicIdMessage* pigeonResult = [[DTGBasicIdMessage alloc] init]; + source:(DTGMessageSource)source { + DTGODIDPayload* pigeonResult = [[DTGODIDPayload alloc] init]; + pigeonResult.rawData = rawData; pigeonResult.receivedTimestamp = receivedTimestamp; pigeonResult.macAddress = macAddress; - pigeonResult.source = source; - pigeonResult.rssi = rssi; - pigeonResult.uasId = uasId; - pigeonResult.idType = idType; - pigeonResult.uaType = uaType; - return pigeonResult; -} -+ (DTGBasicIdMessage *)fromList:(NSArray *)list { - DTGBasicIdMessage *pigeonResult = [[DTGBasicIdMessage alloc] init]; - pigeonResult.receivedTimestamp = GetNullableObjectAtIndex(list, 0); - NSAssert(pigeonResult.receivedTimestamp != nil, @""); - pigeonResult.macAddress = GetNullableObjectAtIndex(list, 1); - NSAssert(pigeonResult.macAddress != nil, @""); - pigeonResult.source = [GetNullableObjectAtIndex(list, 2) integerValue]; - pigeonResult.rssi = GetNullableObjectAtIndex(list, 3); - pigeonResult.uasId = GetNullableObjectAtIndex(list, 4); - NSAssert(pigeonResult.uasId != nil, @""); - pigeonResult.idType = [GetNullableObjectAtIndex(list, 5) integerValue]; - pigeonResult.uaType = [GetNullableObjectAtIndex(list, 6) integerValue]; - return pigeonResult; -} -+ (nullable DTGBasicIdMessage *)nullableFromList:(NSArray *)list { - return (list) ? [DTGBasicIdMessage fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - (self.receivedTimestamp ?: [NSNull null]), - (self.macAddress ?: [NSNull null]), - @(self.source), - (self.rssi ?: [NSNull null]), - (self.uasId ?: [NSNull null]), - @(self.idType), - @(self.uaType), - ]; -} -@end - -@implementation DTGLocationMessage -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - status:(DTGAircraftStatus)status - heightType:(DTGHeightType)heightType - direction:(nullable NSNumber *)direction - speedHorizontal:(nullable NSNumber *)speedHorizontal - speedVertical:(nullable NSNumber *)speedVertical - latitude:(nullable NSNumber *)latitude - longitude:(nullable NSNumber *)longitude - altitudePressure:(nullable NSNumber *)altitudePressure - altitudeGeodetic:(nullable NSNumber *)altitudeGeodetic - height:(nullable NSNumber *)height - horizontalAccuracy:(DTGHorizontalAccuracy)horizontalAccuracy - verticalAccuracy:(DTGVerticalAccuracy)verticalAccuracy - baroAccuracy:(DTGVerticalAccuracy)baroAccuracy - speedAccuracy:(DTGSpeedAccuracy)speedAccuracy - time:(nullable NSNumber *)time - timeAccuracy:(nullable NSNumber *)timeAccuracy { - DTGLocationMessage* pigeonResult = [[DTGLocationMessage alloc] init]; - pigeonResult.receivedTimestamp = receivedTimestamp; - pigeonResult.macAddress = macAddress; - pigeonResult.source = source; - pigeonResult.rssi = rssi; - pigeonResult.status = status; - pigeonResult.heightType = heightType; - pigeonResult.direction = direction; - pigeonResult.speedHorizontal = speedHorizontal; - pigeonResult.speedVertical = speedVertical; - pigeonResult.latitude = latitude; - pigeonResult.longitude = longitude; - pigeonResult.altitudePressure = altitudePressure; - pigeonResult.altitudeGeodetic = altitudeGeodetic; - pigeonResult.height = height; - pigeonResult.horizontalAccuracy = horizontalAccuracy; - pigeonResult.verticalAccuracy = verticalAccuracy; - pigeonResult.baroAccuracy = baroAccuracy; - pigeonResult.speedAccuracy = speedAccuracy; - pigeonResult.time = time; - pigeonResult.timeAccuracy = timeAccuracy; - return pigeonResult; -} -+ (DTGLocationMessage *)fromList:(NSArray *)list { - DTGLocationMessage *pigeonResult = [[DTGLocationMessage alloc] init]; - pigeonResult.receivedTimestamp = GetNullableObjectAtIndex(list, 0); - NSAssert(pigeonResult.receivedTimestamp != nil, @""); - pigeonResult.macAddress = GetNullableObjectAtIndex(list, 1); - NSAssert(pigeonResult.macAddress != nil, @""); - pigeonResult.source = [GetNullableObjectAtIndex(list, 2) integerValue]; - pigeonResult.rssi = GetNullableObjectAtIndex(list, 3); - pigeonResult.status = [GetNullableObjectAtIndex(list, 4) integerValue]; - pigeonResult.heightType = [GetNullableObjectAtIndex(list, 5) integerValue]; - pigeonResult.direction = GetNullableObjectAtIndex(list, 6); - pigeonResult.speedHorizontal = GetNullableObjectAtIndex(list, 7); - pigeonResult.speedVertical = GetNullableObjectAtIndex(list, 8); - pigeonResult.latitude = GetNullableObjectAtIndex(list, 9); - pigeonResult.longitude = GetNullableObjectAtIndex(list, 10); - pigeonResult.altitudePressure = GetNullableObjectAtIndex(list, 11); - pigeonResult.altitudeGeodetic = GetNullableObjectAtIndex(list, 12); - pigeonResult.height = GetNullableObjectAtIndex(list, 13); - pigeonResult.horizontalAccuracy = [GetNullableObjectAtIndex(list, 14) integerValue]; - pigeonResult.verticalAccuracy = [GetNullableObjectAtIndex(list, 15) integerValue]; - pigeonResult.baroAccuracy = [GetNullableObjectAtIndex(list, 16) integerValue]; - pigeonResult.speedAccuracy = [GetNullableObjectAtIndex(list, 17) integerValue]; - pigeonResult.time = GetNullableObjectAtIndex(list, 18); - pigeonResult.timeAccuracy = GetNullableObjectAtIndex(list, 19); - return pigeonResult; -} -+ (nullable DTGLocationMessage *)nullableFromList:(NSArray *)list { - return (list) ? [DTGLocationMessage fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - (self.receivedTimestamp ?: [NSNull null]), - (self.macAddress ?: [NSNull null]), - @(self.source), - (self.rssi ?: [NSNull null]), - @(self.status), - @(self.heightType), - (self.direction ?: [NSNull null]), - (self.speedHorizontal ?: [NSNull null]), - (self.speedVertical ?: [NSNull null]), - (self.latitude ?: [NSNull null]), - (self.longitude ?: [NSNull null]), - (self.altitudePressure ?: [NSNull null]), - (self.altitudeGeodetic ?: [NSNull null]), - (self.height ?: [NSNull null]), - @(self.horizontalAccuracy), - @(self.verticalAccuracy), - @(self.baroAccuracy), - @(self.speedAccuracy), - (self.time ?: [NSNull null]), - (self.timeAccuracy ?: [NSNull null]), - ]; -} -@end - -@implementation DTGOperatorIdMessage -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - operatorId:(NSString *)operatorId { - DTGOperatorIdMessage* pigeonResult = [[DTGOperatorIdMessage alloc] init]; - pigeonResult.receivedTimestamp = receivedTimestamp; - pigeonResult.macAddress = macAddress; - pigeonResult.source = source; pigeonResult.rssi = rssi; - pigeonResult.operatorId = operatorId; - return pigeonResult; -} -+ (DTGOperatorIdMessage *)fromList:(NSArray *)list { - DTGOperatorIdMessage *pigeonResult = [[DTGOperatorIdMessage alloc] init]; - pigeonResult.receivedTimestamp = GetNullableObjectAtIndex(list, 0); - NSAssert(pigeonResult.receivedTimestamp != nil, @""); - pigeonResult.macAddress = GetNullableObjectAtIndex(list, 1); - NSAssert(pigeonResult.macAddress != nil, @""); - pigeonResult.source = [GetNullableObjectAtIndex(list, 2) integerValue]; - pigeonResult.rssi = GetNullableObjectAtIndex(list, 3); - pigeonResult.operatorId = GetNullableObjectAtIndex(list, 4); - NSAssert(pigeonResult.operatorId != nil, @""); - return pigeonResult; -} -+ (nullable DTGOperatorIdMessage *)nullableFromList:(NSArray *)list { - return (list) ? [DTGOperatorIdMessage fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - (self.receivedTimestamp ?: [NSNull null]), - (self.macAddress ?: [NSNull null]), - @(self.source), - (self.rssi ?: [NSNull null]), - (self.operatorId ?: [NSNull null]), - ]; -} -@end - -@implementation DTGAuthenticationMessage -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - authType:(DTGAuthType)authType - authDataPage:(NSNumber *)authDataPage - authLastPageIndex:(NSNumber *)authLastPageIndex - authLength:(NSNumber *)authLength - authTimestamp:(NSNumber *)authTimestamp - authData:(NSString *)authData { - DTGAuthenticationMessage* pigeonResult = [[DTGAuthenticationMessage alloc] init]; - pigeonResult.receivedTimestamp = receivedTimestamp; - pigeonResult.macAddress = macAddress; - pigeonResult.source = source; - pigeonResult.rssi = rssi; - pigeonResult.authType = authType; - pigeonResult.authDataPage = authDataPage; - pigeonResult.authLastPageIndex = authLastPageIndex; - pigeonResult.authLength = authLength; - pigeonResult.authTimestamp = authTimestamp; - pigeonResult.authData = authData; - return pigeonResult; -} -+ (DTGAuthenticationMessage *)fromList:(NSArray *)list { - DTGAuthenticationMessage *pigeonResult = [[DTGAuthenticationMessage alloc] init]; - pigeonResult.receivedTimestamp = GetNullableObjectAtIndex(list, 0); - NSAssert(pigeonResult.receivedTimestamp != nil, @""); - pigeonResult.macAddress = GetNullableObjectAtIndex(list, 1); - NSAssert(pigeonResult.macAddress != nil, @""); - pigeonResult.source = [GetNullableObjectAtIndex(list, 2) integerValue]; - pigeonResult.rssi = GetNullableObjectAtIndex(list, 3); - pigeonResult.authType = [GetNullableObjectAtIndex(list, 4) integerValue]; - pigeonResult.authDataPage = GetNullableObjectAtIndex(list, 5); - NSAssert(pigeonResult.authDataPage != nil, @""); - pigeonResult.authLastPageIndex = GetNullableObjectAtIndex(list, 6); - NSAssert(pigeonResult.authLastPageIndex != nil, @""); - pigeonResult.authLength = GetNullableObjectAtIndex(list, 7); - NSAssert(pigeonResult.authLength != nil, @""); - pigeonResult.authTimestamp = GetNullableObjectAtIndex(list, 8); - NSAssert(pigeonResult.authTimestamp != nil, @""); - pigeonResult.authData = GetNullableObjectAtIndex(list, 9); - NSAssert(pigeonResult.authData != nil, @""); - return pigeonResult; -} -+ (nullable DTGAuthenticationMessage *)nullableFromList:(NSArray *)list { - return (list) ? [DTGAuthenticationMessage fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - (self.receivedTimestamp ?: [NSNull null]), - (self.macAddress ?: [NSNull null]), - @(self.source), - (self.rssi ?: [NSNull null]), - @(self.authType), - (self.authDataPage ?: [NSNull null]), - (self.authLastPageIndex ?: [NSNull null]), - (self.authLength ?: [NSNull null]), - (self.authTimestamp ?: [NSNull null]), - (self.authData ?: [NSNull null]), - ]; -} -@end - -@implementation DTGSelfIdMessage -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - descriptionType:(NSNumber *)descriptionType - operationDescription:(NSString *)operationDescription { - DTGSelfIdMessage* pigeonResult = [[DTGSelfIdMessage alloc] init]; - pigeonResult.receivedTimestamp = receivedTimestamp; - pigeonResult.macAddress = macAddress; - pigeonResult.source = source; - pigeonResult.rssi = rssi; - pigeonResult.descriptionType = descriptionType; - pigeonResult.operationDescription = operationDescription; - return pigeonResult; -} -+ (DTGSelfIdMessage *)fromList:(NSArray *)list { - DTGSelfIdMessage *pigeonResult = [[DTGSelfIdMessage alloc] init]; - pigeonResult.receivedTimestamp = GetNullableObjectAtIndex(list, 0); - NSAssert(pigeonResult.receivedTimestamp != nil, @""); - pigeonResult.macAddress = GetNullableObjectAtIndex(list, 1); - NSAssert(pigeonResult.macAddress != nil, @""); - pigeonResult.source = [GetNullableObjectAtIndex(list, 2) integerValue]; - pigeonResult.rssi = GetNullableObjectAtIndex(list, 3); - pigeonResult.descriptionType = GetNullableObjectAtIndex(list, 4); - NSAssert(pigeonResult.descriptionType != nil, @""); - pigeonResult.operationDescription = GetNullableObjectAtIndex(list, 5); - NSAssert(pigeonResult.operationDescription != nil, @""); - return pigeonResult; -} -+ (nullable DTGSelfIdMessage *)nullableFromList:(NSArray *)list { - return (list) ? [DTGSelfIdMessage fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - (self.receivedTimestamp ?: [NSNull null]), - (self.macAddress ?: [NSNull null]), - @(self.source), - (self.rssi ?: [NSNull null]), - (self.descriptionType ?: [NSNull null]), - (self.operationDescription ?: [NSNull null]), - ]; -} -@end - -@implementation DTGSystemDataMessage -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - operatorLocationType:(DTGOperatorLocationType)operatorLocationType - classificationType:(DTGClassificationType)classificationType - operatorLatitude:(NSNumber *)operatorLatitude - operatorLongitude:(NSNumber *)operatorLongitude - areaCount:(NSNumber *)areaCount - areaRadius:(NSNumber *)areaRadius - areaCeiling:(NSNumber *)areaCeiling - areaFloor:(NSNumber *)areaFloor - category:(DTGAircraftCategory)category - classValue:(DTGAircraftClass)classValue - operatorAltitudeGeo:(NSNumber *)operatorAltitudeGeo { - DTGSystemDataMessage* pigeonResult = [[DTGSystemDataMessage alloc] init]; - pigeonResult.receivedTimestamp = receivedTimestamp; - pigeonResult.macAddress = macAddress; pigeonResult.source = source; - pigeonResult.rssi = rssi; - pigeonResult.operatorLocationType = operatorLocationType; - pigeonResult.classificationType = classificationType; - pigeonResult.operatorLatitude = operatorLatitude; - pigeonResult.operatorLongitude = operatorLongitude; - pigeonResult.areaCount = areaCount; - pigeonResult.areaRadius = areaRadius; - pigeonResult.areaCeiling = areaCeiling; - pigeonResult.areaFloor = areaFloor; - pigeonResult.category = category; - pigeonResult.classValue = classValue; - pigeonResult.operatorAltitudeGeo = operatorAltitudeGeo; return pigeonResult; } -+ (DTGSystemDataMessage *)fromList:(NSArray *)list { - DTGSystemDataMessage *pigeonResult = [[DTGSystemDataMessage alloc] init]; - pigeonResult.receivedTimestamp = GetNullableObjectAtIndex(list, 0); ++ (DTGODIDPayload *)fromList:(NSArray *)list { + DTGODIDPayload *pigeonResult = [[DTGODIDPayload alloc] init]; + pigeonResult.rawData = GetNullableObjectAtIndex(list, 0); + NSAssert(pigeonResult.rawData != nil, @""); + pigeonResult.receivedTimestamp = GetNullableObjectAtIndex(list, 1); NSAssert(pigeonResult.receivedTimestamp != nil, @""); - pigeonResult.macAddress = GetNullableObjectAtIndex(list, 1); + pigeonResult.macAddress = GetNullableObjectAtIndex(list, 2); NSAssert(pigeonResult.macAddress != nil, @""); - pigeonResult.source = [GetNullableObjectAtIndex(list, 2) integerValue]; pigeonResult.rssi = GetNullableObjectAtIndex(list, 3); - pigeonResult.operatorLocationType = [GetNullableObjectAtIndex(list, 4) integerValue]; - pigeonResult.classificationType = [GetNullableObjectAtIndex(list, 5) integerValue]; - pigeonResult.operatorLatitude = GetNullableObjectAtIndex(list, 6); - NSAssert(pigeonResult.operatorLatitude != nil, @""); - pigeonResult.operatorLongitude = GetNullableObjectAtIndex(list, 7); - NSAssert(pigeonResult.operatorLongitude != nil, @""); - pigeonResult.areaCount = GetNullableObjectAtIndex(list, 8); - NSAssert(pigeonResult.areaCount != nil, @""); - pigeonResult.areaRadius = GetNullableObjectAtIndex(list, 9); - NSAssert(pigeonResult.areaRadius != nil, @""); - pigeonResult.areaCeiling = GetNullableObjectAtIndex(list, 10); - NSAssert(pigeonResult.areaCeiling != nil, @""); - pigeonResult.areaFloor = GetNullableObjectAtIndex(list, 11); - NSAssert(pigeonResult.areaFloor != nil, @""); - pigeonResult.category = [GetNullableObjectAtIndex(list, 12) integerValue]; - pigeonResult.classValue = [GetNullableObjectAtIndex(list, 13) integerValue]; - pigeonResult.operatorAltitudeGeo = GetNullableObjectAtIndex(list, 14); - NSAssert(pigeonResult.operatorAltitudeGeo != nil, @""); + pigeonResult.source = [GetNullableObjectAtIndex(list, 4) integerValue]; return pigeonResult; } -+ (nullable DTGSystemDataMessage *)nullableFromList:(NSArray *)list { - return (list) ? [DTGSystemDataMessage fromList:list] : nil; ++ (nullable DTGODIDPayload *)nullableFromList:(NSArray *)list { + return (list) ? [DTGODIDPayload fromList:list] : nil; } - (NSArray *)toList { return @[ + (self.rawData ?: [NSNull null]), (self.receivedTimestamp ?: [NSNull null]), (self.macAddress ?: [NSNull null]), - @(self.source), (self.rssi ?: [NSNull null]), - @(self.operatorLocationType), - @(self.classificationType), - (self.operatorLatitude ?: [NSNull null]), - (self.operatorLongitude ?: [NSNull null]), - (self.areaCount ?: [NSNull null]), - (self.areaRadius ?: [NSNull null]), - (self.areaCeiling ?: [NSNull null]), - (self.areaFloor ?: [NSNull null]), - @(self.category), - @(self.classValue), - (self.operatorAltitudeGeo ?: [NSNull null]), - ]; -} -@end - -@implementation DTGConnectionMessage -+ (instancetype)makeWithReceivedTimestamp:(NSNumber *)receivedTimestamp - macAddress:(NSString *)macAddress - source:(DTGMessageSource)source - rssi:(nullable NSNumber *)rssi - transportType:(NSString *)transportType - lastSeen:(NSNumber *)lastSeen - firstSeen:(NSNumber *)firstSeen - msgDelta:(NSNumber *)msgDelta { - DTGConnectionMessage* pigeonResult = [[DTGConnectionMessage alloc] init]; - pigeonResult.receivedTimestamp = receivedTimestamp; - pigeonResult.macAddress = macAddress; - pigeonResult.source = source; - pigeonResult.rssi = rssi; - pigeonResult.transportType = transportType; - pigeonResult.lastSeen = lastSeen; - pigeonResult.firstSeen = firstSeen; - pigeonResult.msgDelta = msgDelta; - return pigeonResult; -} -+ (DTGConnectionMessage *)fromList:(NSArray *)list { - DTGConnectionMessage *pigeonResult = [[DTGConnectionMessage alloc] init]; - pigeonResult.receivedTimestamp = GetNullableObjectAtIndex(list, 0); - NSAssert(pigeonResult.receivedTimestamp != nil, @""); - pigeonResult.macAddress = GetNullableObjectAtIndex(list, 1); - NSAssert(pigeonResult.macAddress != nil, @""); - pigeonResult.source = [GetNullableObjectAtIndex(list, 2) integerValue]; - pigeonResult.rssi = GetNullableObjectAtIndex(list, 3); - pigeonResult.transportType = GetNullableObjectAtIndex(list, 4); - NSAssert(pigeonResult.transportType != nil, @""); - pigeonResult.lastSeen = GetNullableObjectAtIndex(list, 5); - NSAssert(pigeonResult.lastSeen != nil, @""); - pigeonResult.firstSeen = GetNullableObjectAtIndex(list, 6); - NSAssert(pigeonResult.firstSeen != nil, @""); - pigeonResult.msgDelta = GetNullableObjectAtIndex(list, 7); - NSAssert(pigeonResult.msgDelta != nil, @""); - return pigeonResult; -} -+ (nullable DTGConnectionMessage *)nullableFromList:(NSArray *)list { - return (list) ? [DTGConnectionMessage fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - (self.receivedTimestamp ?: [NSNull null]), - (self.macAddress ?: [NSNull null]), @(self.source), - (self.rssi ?: [NSNull null]), - (self.transportType ?: [NSNull null]), - (self.lastSeen ?: [NSNull null]), - (self.firstSeen ?: [NSNull null]), - (self.msgDelta ?: [NSNull null]), ]; } @end @@ -510,7 +82,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.startScanBluetooth" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.startScanBluetooth" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -527,7 +99,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.startScanWifi" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.startScanWifi" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -544,7 +116,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.stopScanBluetooth" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.stopScanBluetooth" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -561,7 +133,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.stopScanWifi" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.stopScanWifi" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -578,7 +150,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.setBtScanPriority" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.setBtScanPriority" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -597,7 +169,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.isScanningBluetooth" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.isScanningBluetooth" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -614,7 +186,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.isScanningWifi" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.isScanningWifi" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -631,7 +203,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.bluetoothState" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.bluetoothState" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -648,7 +220,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.wifiState" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.wifiState" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -665,7 +237,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.btExtendedSupported" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.btExtendedSupported" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -682,7 +254,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.btMaxAdvDataLen" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.btMaxAdvDataLen" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -699,7 +271,7 @@ void DTGApiSetup(id binaryMessenger, NSObject *a { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.Api.wifiNaNSupported" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.Api.wifiNaNSupported" binaryMessenger:binaryMessenger codec:DTGApiGetCodec()]; if (api) { @@ -714,245 +286,71 @@ void DTGApiSetup(id binaryMessenger, NSObject *a } } } -@interface DTGMessageApiCodecReader : FlutterStandardReader +@interface DTGPayloadApiCodecReader : FlutterStandardReader @end -@implementation DTGMessageApiCodecReader +@implementation DTGPayloadApiCodecReader - (nullable id)readValueOfType:(UInt8)type { switch (type) { case 128: - return [DTGAuthenticationMessage fromList:[self readValue]]; - case 129: - return [DTGBasicIdMessage fromList:[self readValue]]; - case 130: - return [DTGConnectionMessage fromList:[self readValue]]; - case 131: - return [DTGLocationMessage fromList:[self readValue]]; - case 132: - return [DTGOperatorIdMessage fromList:[self readValue]]; - case 133: - return [DTGSelfIdMessage fromList:[self readValue]]; - case 134: - return [DTGSystemDataMessage fromList:[self readValue]]; + return [DTGODIDPayload fromList:[self readValue]]; default: return [super readValueOfType:type]; } } @end -@interface DTGMessageApiCodecWriter : FlutterStandardWriter +@interface DTGPayloadApiCodecWriter : FlutterStandardWriter @end -@implementation DTGMessageApiCodecWriter +@implementation DTGPayloadApiCodecWriter - (void)writeValue:(id)value { - if ([value isKindOfClass:[DTGAuthenticationMessage class]]) { + if ([value isKindOfClass:[DTGODIDPayload class]]) { [self writeByte:128]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[DTGBasicIdMessage class]]) { - [self writeByte:129]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[DTGConnectionMessage class]]) { - [self writeByte:130]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[DTGLocationMessage class]]) { - [self writeByte:131]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[DTGOperatorIdMessage class]]) { - [self writeByte:132]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[DTGSelfIdMessage class]]) { - [self writeByte:133]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[DTGSystemDataMessage class]]) { - [self writeByte:134]; - [self writeValue:[value toList]]; } else { [super writeValue:value]; } } @end -@interface DTGMessageApiCodecReaderWriter : FlutterStandardReaderWriter +@interface DTGPayloadApiCodecReaderWriter : FlutterStandardReaderWriter @end -@implementation DTGMessageApiCodecReaderWriter +@implementation DTGPayloadApiCodecReaderWriter - (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { - return [[DTGMessageApiCodecWriter alloc] initWithData:data]; + return [[DTGPayloadApiCodecWriter alloc] initWithData:data]; } - (FlutterStandardReader *)readerWithData:(NSData *)data { - return [[DTGMessageApiCodecReader alloc] initWithData:data]; + return [[DTGPayloadApiCodecReader alloc] initWithData:data]; } @end -NSObject *DTGMessageApiGetCodec(void) { +NSObject *DTGPayloadApiGetCodec(void) { static FlutterStandardMessageCodec *sSharedObject = nil; static dispatch_once_t sPred = 0; dispatch_once(&sPred, ^{ - DTGMessageApiCodecReaderWriter *readerWriter = [[DTGMessageApiCodecReaderWriter alloc] init]; + DTGPayloadApiCodecReaderWriter *readerWriter = [[DTGPayloadApiCodecReaderWriter alloc] init]; sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; }); return sSharedObject; } -void DTGMessageApiSetup(id binaryMessenger, NSObject *api) { - { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.MessageApi.determineMessageType" - binaryMessenger:binaryMessenger - codec:DTGMessageApiGetCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(determineMessageTypePayload:offset:error:)], @"DTGMessageApi api (%@) doesn't respond to @selector(determineMessageTypePayload:offset:error:)", api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FlutterStandardTypedData *arg_payload = GetNullableObjectAtIndex(args, 0); - NSNumber *arg_offset = GetNullableObjectAtIndex(args, 1); - FlutterError *error; - NSNumber *output = [api determineMessageTypePayload:arg_payload offset:arg_offset error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.MessageApi.fromBufferBasic" - binaryMessenger:binaryMessenger - codec:DTGMessageApiGetCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(fromBufferBasicPayload:offset:macAddress:error:)], @"DTGMessageApi api (%@) doesn't respond to @selector(fromBufferBasicPayload:offset:macAddress:error:)", api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FlutterStandardTypedData *arg_payload = GetNullableObjectAtIndex(args, 0); - NSNumber *arg_offset = GetNullableObjectAtIndex(args, 1); - NSString *arg_macAddress = GetNullableObjectAtIndex(args, 2); - FlutterError *error; - DTGBasicIdMessage *output = [api fromBufferBasicPayload:arg_payload offset:arg_offset macAddress:arg_macAddress error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.MessageApi.fromBufferLocation" - binaryMessenger:binaryMessenger - codec:DTGMessageApiGetCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(fromBufferLocationPayload:offset:macAddress:error:)], @"DTGMessageApi api (%@) doesn't respond to @selector(fromBufferLocationPayload:offset:macAddress:error:)", api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FlutterStandardTypedData *arg_payload = GetNullableObjectAtIndex(args, 0); - NSNumber *arg_offset = GetNullableObjectAtIndex(args, 1); - NSString *arg_macAddress = GetNullableObjectAtIndex(args, 2); - FlutterError *error; - DTGLocationMessage *output = [api fromBufferLocationPayload:arg_payload offset:arg_offset macAddress:arg_macAddress error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.MessageApi.fromBufferOperatorId" - binaryMessenger:binaryMessenger - codec:DTGMessageApiGetCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(fromBufferOperatorIdPayload:offset:macAddress:error:)], @"DTGMessageApi api (%@) doesn't respond to @selector(fromBufferOperatorIdPayload:offset:macAddress:error:)", api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FlutterStandardTypedData *arg_payload = GetNullableObjectAtIndex(args, 0); - NSNumber *arg_offset = GetNullableObjectAtIndex(args, 1); - NSString *arg_macAddress = GetNullableObjectAtIndex(args, 2); - FlutterError *error; - DTGOperatorIdMessage *output = [api fromBufferOperatorIdPayload:arg_payload offset:arg_offset macAddress:arg_macAddress error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.MessageApi.fromBufferSelfId" - binaryMessenger:binaryMessenger - codec:DTGMessageApiGetCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(fromBufferSelfIdPayload:offset:macAddress:error:)], @"DTGMessageApi api (%@) doesn't respond to @selector(fromBufferSelfIdPayload:offset:macAddress:error:)", api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FlutterStandardTypedData *arg_payload = GetNullableObjectAtIndex(args, 0); - NSNumber *arg_offset = GetNullableObjectAtIndex(args, 1); - NSString *arg_macAddress = GetNullableObjectAtIndex(args, 2); - FlutterError *error; - DTGSelfIdMessage *output = [api fromBufferSelfIdPayload:arg_payload offset:arg_offset macAddress:arg_macAddress error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.MessageApi.fromBufferAuthentication" - binaryMessenger:binaryMessenger - codec:DTGMessageApiGetCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(fromBufferAuthenticationPayload:offset:macAddress:error:)], @"DTGMessageApi api (%@) doesn't respond to @selector(fromBufferAuthenticationPayload:offset:macAddress:error:)", api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FlutterStandardTypedData *arg_payload = GetNullableObjectAtIndex(args, 0); - NSNumber *arg_offset = GetNullableObjectAtIndex(args, 1); - NSString *arg_macAddress = GetNullableObjectAtIndex(args, 2); - FlutterError *error; - DTGAuthenticationMessage *output = [api fromBufferAuthenticationPayload:arg_payload offset:arg_offset macAddress:arg_macAddress error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.MessageApi.fromBufferSystemData" - binaryMessenger:binaryMessenger - codec:DTGMessageApiGetCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(fromBufferSystemDataPayload:offset:macAddress:error:)], @"DTGMessageApi api (%@) doesn't respond to @selector(fromBufferSystemDataPayload:offset:macAddress:error:)", api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FlutterStandardTypedData *arg_payload = GetNullableObjectAtIndex(args, 0); - NSNumber *arg_offset = GetNullableObjectAtIndex(args, 1); - NSString *arg_macAddress = GetNullableObjectAtIndex(args, 2); - FlutterError *error; - DTGSystemDataMessage *output = [api fromBufferSystemDataPayload:arg_payload offset:arg_offset macAddress:arg_macAddress error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } +void DTGPayloadApiSetup(id binaryMessenger, NSObject *api) { { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:@"dev.flutter.pigeon.MessageApi.fromBufferConnection" + initWithName:@"dev.flutter.pigeon.flutter_opendroneid.PayloadApi.getPayload" binaryMessenger:binaryMessenger - codec:DTGMessageApiGetCodec()]; + codec:DTGPayloadApiGetCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(fromBufferConnectionPayload:offset:macAddress:error:)], @"DTGMessageApi api (%@) doesn't respond to @selector(fromBufferConnectionPayload:offset:macAddress:error:)", api); + NSCAssert([api respondsToSelector:@selector(getPayloadRawData:source:macAddress:rssi:receivedTimestamp:error:)], @"DTGPayloadApi api (%@) doesn't respond to @selector(getPayloadRawData:source:macAddress:rssi:receivedTimestamp:error:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; - FlutterStandardTypedData *arg_payload = GetNullableObjectAtIndex(args, 0); - NSNumber *arg_offset = GetNullableObjectAtIndex(args, 1); + FlutterStandardTypedData *arg_rawData = GetNullableObjectAtIndex(args, 0); + DTGMessageSource arg_source = [GetNullableObjectAtIndex(args, 1) integerValue]; NSString *arg_macAddress = GetNullableObjectAtIndex(args, 2); + NSNumber *arg_rssi = GetNullableObjectAtIndex(args, 3); + NSNumber *arg_receivedTimestamp = GetNullableObjectAtIndex(args, 4); FlutterError *error; - DTGConnectionMessage *output = [api fromBufferConnectionPayload:arg_payload offset:arg_offset macAddress:arg_macAddress error:&error]; + DTGODIDPayload *output = [api getPayloadRawData:arg_rawData source:arg_source macAddress:arg_macAddress rssi:arg_rssi receivedTimestamp:arg_receivedTimestamp error:&error]; callback(wrapResult(output, error)); }]; } else { diff --git a/ios/Classes/StreamHandler.swift b/ios/Classes/utils/StreamHandler.swift similarity index 100% rename from ios/Classes/StreamHandler.swift rename to ios/Classes/utils/StreamHandler.swift diff --git a/ios/Classes/Utils.swift b/ios/Classes/utils/Utils.swift similarity index 100% rename from ios/Classes/Utils.swift rename to ios/Classes/utils/Utils.swift diff --git a/lib/flutter_opendroneid.dart b/lib/flutter_opendroneid.dart index 4dc6169..294cee8 100644 --- a/lib/flutter_opendroneid.dart +++ b/lib/flutter_opendroneid.dart @@ -1,10 +1,10 @@ import 'dart:async'; import 'dart:io'; +import 'package:dart_opendroneid/dart_opendroneid.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_opendroneid/models/compare_extension.dart'; +import 'package:flutter_opendroneid/models/message_container.dart'; import 'package:flutter_opendroneid/models/permissions_missing_exception.dart'; -import 'models/message_pack.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:device_info_plus/device_info_plus.dart'; @@ -14,53 +14,35 @@ enum UsedTechnologies { Wifi, Bluetooth, Both, None } class FlutterOpenDroneId { static late pigeon.Api _api = pigeon.Api(); - - static const _locationMessagesEventChannel = - const EventChannel('flutter_location_messages'); - static const _operatorIDMessagesEventChannel = - const EventChannel('flutter_operatorid_messages'); - static const _basicMessagesEventChannel = - const EventChannel('flutter_basic_messages'); - static const _systemDataMessagesEventChannel = - const EventChannel('flutter_system_messages'); - // auth messages are not yet supported - //static const _authMessagesEventChannel = - // const EventChannel('flutter_auth_messages'); - static const _selfIdMessagesEventChannel = - const EventChannel('flutter_selfid_messages'); + static const odidPayloadEventChannel = + const EventChannel('flutter_odid_data'); static const _btStateEventChannel = const EventChannel('flutter_odid_bt_state'); static const _wifiStateEventChannel = const EventChannel('flutter_odid_wifi_state'); - static Map _storedPacks = {}; - static final _packController = StreamController.broadcast(); - static StreamSubscription? _locationMessagesSubscription; - static StreamSubscription? _basicMessagesSubscription; - static StreamSubscription? _operatorIDMessagesSubscription; - //static StreamSubscription? _authMessagesSubscription; - static StreamSubscription? _systemDataMessagesSubscription; - static StreamSubscription? _selfIDMessagesSubscription; + static StreamSubscription? _rawDataSubscription; + + static final _packController = StreamController.broadcast(); + static Map _storedPacks = {}; static Stream get bluetoothState => _btStateEventChannel .receiveBroadcastStream() .map((event) => event as bool); - static Stream get allMessages => _packController.stream; + static Stream get allMessages => _packController.stream; static Stream get wifiState => _wifiStateEventChannel .receiveBroadcastStream() .map((event) => event as bool); - static Future get btTurnedOn async { - return await _api.bluetoothState() == - pigeon.BluetoothState.values.indexOf(pigeon.BluetoothState.PoweredOn); - } + static Future get btTurnedOn async => + await _api.bluetoothState() == + pigeon.BluetoothState.values.indexOf(pigeon.BluetoothState.PoweredOn); - static Future get wifiTurnedOn async { - return await _api.wifiState() == - pigeon.WifiState.values.indexOf(pigeon.WifiState.Enabled); - } + static Future get wifiTurnedOn async => + await _api.wifiState() == + pigeon.WifiState.values.indexOf(pigeon.WifiState.Enabled); /// Starts scanning for nearby traffic /// For Bluetooth scanning, bluetooth permissions are required on both platforms, @@ -73,38 +55,10 @@ class FlutterOpenDroneId { /// To further receive data, listen to /// streams. static Future startScan(UsedTechnologies usedTechnologies) async { - _locationMessagesSubscription = - _locationMessagesEventChannel.receiveBroadcastStream().listen((data) { - final message = pigeon.LocationMessage.decode(data); - _updatePacksWithLocation(message); - }); - _basicMessagesSubscription = - _basicMessagesEventChannel.receiveBroadcastStream().listen((data) { - final message = pigeon.BasicIdMessage.decode(data); - _updatePacksWithBasic(message); - }); - _operatorIDMessagesSubscription = - _operatorIDMessagesEventChannel.receiveBroadcastStream().listen((data) { - final message = pigeon.OperatorIdMessage.decode(data); - _updatePacksWithOperatorId(message); - }); - // to-do: debug auth message parsing, causes exception - /*_authMessagesSubscription = - _authMessagesEventChannel.receiveBroadcastStream().listen((data) { - final message = pigeon.AuthenticationMessage.decode(data); - if (message == null) return; - _updatePacksWithAuthentication(message); - });*/ - _systemDataMessagesSubscription = - _systemDataMessagesEventChannel.receiveBroadcastStream().listen((data) { - final message = pigeon.SystemDataMessage.decode(data); - _updatePacksWithSystemData(message); - }); - _selfIDMessagesSubscription = - _selfIdMessagesEventChannel.receiveBroadcastStream().listen((data) { - final message = pigeon.SelfIdMessage.decode(data); - _updatePacksWithSelfId(message); - }); + _rawDataSubscription = odidPayloadEventChannel + .receiveBroadcastStream() + .listen((payload) => _updatePacks(pigeon.ODIDPayload.decode(payload))); + if (usedTechnologies == UsedTechnologies.Bluetooth || usedTechnologies == UsedTechnologies.Both) { await _assertBluetoothPermissions(); @@ -121,18 +75,45 @@ class FlutterOpenDroneId { static Future stopScan() async { if (await _api.isScanningBluetooth()) await _api.stopScanBluetooth(); if (await _api.isScanningWifi()) await _api.stopScanWifi(); - _locationMessagesSubscription?.cancel(); - _basicMessagesSubscription?.cancel(); - _operatorIDMessagesSubscription?.cancel(); - //_authMessagesSubscription?.cancel(); - _selfIDMessagesSubscription?.cancel(); - _systemDataMessagesSubscription?.cancel(); + _rawDataSubscription?.cancel(); } static Future setBtScanPriority(pigeon.ScanPriority priority) async { await _api.setBtScanPriority(priority); } + static Future get isScanningBluetooth async { + return _api.isScanningBluetooth(); + } + + static Future get isBluetoothExtendedSupported async => + await _api.btExtendedSupported(); + + static Future get isWifiNanSupported async => + await _api.wifiNaNSupported(); + + static Future get btMaxAdvDataLen async => await _api.btMaxAdvDataLen(); + + static Future get isScanningWifi async => await _api.isScanningWifi(); + + static void _updatePacks(pigeon.ODIDPayload payload) { + final storedPack = _storedPacks[payload.macAddress] ?? + MessageContainer( + macAddress: payload.macAddress, + source: payload.source, + lastUpdate: + DateTime.fromMillisecondsSinceEpoch(payload.receivedTimestamp), + ); + // TODO: check for duplicate messages + final message = parseODIDMessage(payload.rawData); + if (message == null) return; + _storedPacks[payload.macAddress] = storedPack.update( + message: message, + receivedTimestamp: payload.receivedTimestamp, + rssi: payload.rssi); + _packController.add(_storedPacks[payload.macAddress]!); + } + /// Checks all required Bluetooth permissions and throws /// [PermissionsMissingException] if any of them are not granted. static Future _assertBluetoothPermissions() async { @@ -164,7 +145,7 @@ class FlutterOpenDroneId { if (Platform.isAndroid) { List missingPermissions = []; - final androidVersionNumber = await getAndroidVersionNumber(); + final androidVersionNumber = await _getAndroidVersionNumber(); if (androidVersionNumber == null) return; // Android < 12 also requires location permission // Android 13 has a new nearbyWifiDevicesPermission @@ -180,120 +161,9 @@ class FlutterOpenDroneId { } } - static Future getAndroidVersionNumber() async { + static Future _getAndroidVersionNumber() async { final deviceInfo = DeviceInfoPlugin(); final androidVersion = (await deviceInfo.androidInfo).version.release; return int.tryParse(androidVersion); } - - static Future get isScanningBluetooth async { - return _api.isScanningBluetooth(); - } - - static Future get isBluetoothExtendedSupported async => - await _api.btExtendedSupported(); - - static Future get isWifiNanSupported async => - await _api.wifiNaNSupported(); - - static Future get btMaxAdvDataLen async => await _api.btMaxAdvDataLen(); - - static Future get isScanningWifi async => await _api.isScanningWifi(); - - static void _updatePacksWithBasic(pigeon.BasicIdMessage message) { - final mac = message.macAddress; - final storedPack = _storedPacks[message.macAddress] ?? - MessagePack( - macAddress: mac, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp), - ); - if (storedPack.basicIdMessage != null && - storedPack.basicIdMessage!.containsEqualData(message)) { - return; - } - _storedPacks[mac] = storedPack.updateWithBasic(message); - _packController.add(_storedPacks[message.macAddress]!); - } - - static void _updatePacksWithLocation(pigeon.LocationMessage message) { - final mac = message.macAddress; - final storedPack = _storedPacks[message.macAddress] ?? - MessagePack( - macAddress: mac, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - // skip location updates with same timestamp - if (storedPack.locationValid() && - storedPack.locationMessage!.containsEqualData(message)) { - return; - } - _storedPacks[mac] = storedPack.updateWithLocation(message); - _packController.add(_storedPacks[message.macAddress]!); - } - - static void _updatePacksWithOperatorId(pigeon.OperatorIdMessage message) { - final mac = message.macAddress; - final storedPack = _storedPacks[message.macAddress] ?? - MessagePack( - macAddress: mac, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - if (storedPack.operatorIDValid() && - storedPack.operatorIdMessage!.containsEqualData(message)) { - return; - } - _storedPacks[mac] = storedPack.updateWithOperatorId(message); - _packController.add(_storedPacks[message.macAddress]!); - } - - static void _updatePacksWithSystemData(pigeon.SystemDataMessage message) { - final mac = message.macAddress; - final storedPack = _storedPacks[message.macAddress] ?? - MessagePack( - macAddress: mac, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - if (storedPack.systemDataValid() && - storedPack.systemDataMessage!.containsEqualData(message)) { - return; - } - _storedPacks[mac] = storedPack.updateWithSystemData(message); - _packController.add(_storedPacks[message.macAddress]!); - } - - // ignore: unused_element - static void _updatePacksWithAuthentication( - pigeon.AuthenticationMessage message) { - final mac = message.macAddress; - final storedPack = _storedPacks[message.macAddress] ?? - MessagePack( - macAddress: mac, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - // skip location updates with same timestamp - if (storedPack.authenticationMessage != null && - storedPack.authenticationMessage!.containsEqualData(message)) { - return; - } - _storedPacks[mac] = storedPack.updateWithAuthentication(message); - _packController.add(_storedPacks[message.macAddress]!); - } - - static void _updatePacksWithSelfId(pigeon.SelfIdMessage message) { - final mac = message.macAddress; - final storedPack = _storedPacks[message.macAddress] ?? - MessagePack( - macAddress: mac, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp), - ); - // skip location updates with same timestamp - if (storedPack.selfIdMessage != null && - storedPack.selfIdMessage!.containsEqualData(message)) { - return; - } - _storedPacks[mac] = storedPack.updateWithSelfId(message); - _packController.add(_storedPacks[message.macAddress]!); - } } diff --git a/lib/models/compare_extension.dart b/lib/models/compare_extension.dart deleted file mode 100644 index cf73297..0000000 --- a/lib/models/compare_extension.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter_opendroneid/pigeon.dart'; - -// extensions to check whether messages have the same data -// The messages may not necessarily be the same, timestamp, rssi are ignored -// compares just relevant data fields -extension LocationCompareExtension on LocationMessage { - // consider location with same timestamp equal - bool containsEqualData(LocationMessage other) { - return time == other.time && - latitude == other.latitude && - longitude == other.longitude; - } -} - -extension BasicIdCompareExtension on BasicIdMessage { - bool containsEqualData(BasicIdMessage other) { - return uasId == other.uasId && - idType == other.idType && - uaType == other.uaType; - } -} - -extension OperatorIdCompareExtension on OperatorIdMessage { - bool containsEqualData(OperatorIdMessage other) { - return operatorId == other.operatorId; - } -} - -extension SystemDataCompareExtension on SystemDataMessage { - bool containsEqualData(SystemDataMessage other) { - return areaCeiling == other.areaCeiling && - areaCount == other.areaCount && - areaFloor == other.areaFloor && - areaRadius == other.areaRadius && - category == other.category && - classValue == other.classValue && - classificationType == other.classificationType && - operatorAltitudeGeo == other.operatorAltitudeGeo && - operatorLatitude == other.operatorLatitude && - operatorLocationType == other.operatorLocationType && - operatorLongitude == other.operatorLongitude; - } -} - -extension AuthenticationCompareExtension on AuthenticationMessage { - bool containsEqualData(AuthenticationMessage other) { - return authData == other.authData && - authDataPage == other.authDataPage && - authLastPageIndex == other.authLastPageIndex && - authLength == other.authLength && - authTimestamp == other.authTimestamp && - authType == other.authType; - } -} - -extension SelfIdCompareExtension on SelfIdMessage { - bool containsEqualData(SelfIdMessage other) { - return descriptionType == other.descriptionType && - operationDescription == other.operationDescription; - } -} diff --git a/lib/models/message_container.dart b/lib/models/message_container.dart new file mode 100644 index 0000000..3d3f9cd --- /dev/null +++ b/lib/models/message_container.dart @@ -0,0 +1,206 @@ +import 'dart:ui'; + +import 'package:flutter_opendroneid/models/constants.dart'; +import 'package:flutter_opendroneid/pigeon.dart' as pigeon; +import 'package:dart_opendroneid/src/types.dart'; + +class MessageContainer { + final String macAddress; + final DateTime lastUpdate; + final pigeon.MessageSource source; + final int? lastMessageRssi; + + final BasicIDMessage? basicIdMessage; + final LocationMessage? locationMessage; + final OperatorIDMessage? operatorIdMessage; + final SelfIDMessage? selfIdMessage; + final AuthMessage? authenticationMessage; + final SystemMessage? systemDataMessage; + + MessageContainer({ + required this.macAddress, + required this.lastUpdate, + required this.source, + this.lastMessageRssi, + this.basicIdMessage, + this.locationMessage, + this.operatorIdMessage, + this.selfIdMessage, + this.authenticationMessage, + this.systemDataMessage, + }); + + static const colorMax = 120; + static const colorOffset = 90; + + MessageContainer copyWith({ + String? macAddress, + int? lastMessageRssi, + DateTime? lastUpdate, + pigeon.MessageSource? source, + BasicIDMessage? basicIdMessage, + LocationMessage? locationMessage, + OperatorIDMessage? operatorIdMessage, + SelfIDMessage? selfIdMessage, + AuthMessage? authenticationMessage, + SystemMessage? systemDataMessage, + }) => + MessageContainer( + macAddress: macAddress ?? this.macAddress, + lastMessageRssi: lastMessageRssi ?? this.lastMessageRssi, + lastUpdate: lastUpdate ?? DateTime.now(), + source: source ?? this.source, + basicIdMessage: basicIdMessage ?? this.basicIdMessage, + locationMessage: locationMessage ?? this.locationMessage, + operatorIdMessage: operatorIdMessage ?? this.operatorIdMessage, + selfIdMessage: selfIdMessage ?? this.selfIdMessage, + authenticationMessage: + authenticationMessage ?? this.authenticationMessage, + systemDataMessage: systemDataMessage ?? this.systemDataMessage, + ); + + MessageContainer update({ + required ODIDMessage message, + required int receivedTimestamp, + int? rssi, + }) { + if (message.runtimeType == MessagePack) { + final messages = (message as MessagePack).messages; + var result = this; + for (var packMessage in messages) { + result = result.update( + message: packMessage, receivedTimestamp: receivedTimestamp); + } + return result; + } + return switch (message.runtimeType) { + LocationMessage => copyWith( + locationMessage: message as LocationMessage, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + BasicIDMessage => copyWith( + basicIdMessage: message as BasicIDMessage, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + SelfIDMessage => copyWith( + selfIdMessage: message as SelfIDMessage, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + OperatorIDMessage => copyWith( + operatorIdMessage: message as OperatorIDMessage, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + AuthMessage => copyWith( + authenticationMessage: message as AuthMessage, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + SystemMessage => copyWith( + systemDataMessage: message as SystemMessage, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + _ => this + }; + } + + MessageContainer updateWithOperatorId({ + required OperatorIDMessage message, + required int receivedTimestamp, + int? rssi, + }) { + return copyWith( + operatorIdMessage: message, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)); + } + + MessageContainer updateWithAuthentication({ + required AuthMessage message, + required int receivedTimestamp, + int? rssi, + }) { + return copyWith( + authenticationMessage: message, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)); + } + + MessageContainer updateWithSystemData({ + required SystemMessage message, + required int receivedTimestamp, + int? rssi, + }) { + return copyWith( + systemDataMessage: message, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)); + } + + MessageContainer updateWithSelfId({ + required SelfIDMessage message, + required int receivedTimestamp, + int? rssi, + }) { + return copyWith( + selfIdMessage: message, + lastMessageRssi: rssi, + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)); + } + + pigeon.MessageSource getPackSource() => source; + + /// Calculates a color from mac address, that uniquely identifies the device + Color getPackColor() { + final len = macAddress.length; + return Color.fromARGB( + locationMessage?.status != OperationalStatus.airborne ? 80 : 255, + colorOffset + + 32 + + macAddress + .substring(0, len ~/ 2) + .codeUnits + .reduce((sum, e) => sum + e) % + (colorMax - 32), + colorOffset + + macAddress.codeUnits.reduce((sum, e) => (sum * e) % colorMax), + colorOffset + + macAddress + .substring(len ~/ 2) + .codeUnits + .fold(255, (sum, e) => sum - e % colorMax), + ); + } + + bool operatorIDSet() { + return operatorIdMessage != null && + operatorIdMessage!.operatorID != OPERATOR_ID_NOT_SET; + } + + bool operatorIDValid() { + final validCharacters = RegExp(r'^[a-zA-Z0-9]+$'); + return operatorIdMessage != null && + operatorIdMessage!.operatorID.length == 16 && + validCharacters.hasMatch(operatorIdMessage!.operatorID); + } + + bool systemDataValid() { + return systemDataMessage != null && + systemDataMessage?.operatorLocation != null && + systemDataMessage!.operatorLocation!.latitude != INV_LAT && + systemDataMessage?.operatorLocation!.longitude != INV_LON && + systemDataMessage!.operatorLocation!.latitude <= MAX_LAT && + systemDataMessage!.operatorLocation!.latitude >= MIN_LAT && + systemDataMessage!.operatorLocation!.longitude <= MAX_LON && + systemDataMessage!.operatorLocation!.longitude >= MIN_LON; + } + + bool locationValid() { + return locationMessage != null && + locationMessage?.location != null && + locationMessage!.location!.latitude != INV_LAT && + locationMessage!.location!.longitude != INV_LON && + locationMessage!.location!.latitude <= MAX_LAT && + locationMessage!.location!.longitude <= MAX_LON && + locationMessage!.location!.latitude >= MIN_LAT && + locationMessage!.location!.longitude >= MIN_LON; + } +} diff --git a/lib/models/message_pack.dart b/lib/models/message_pack.dart deleted file mode 100644 index 7f3c008..0000000 --- a/lib/models/message_pack.dart +++ /dev/null @@ -1,178 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter_opendroneid/models/constants.dart'; -import 'package:flutter_opendroneid/pigeon.dart' as pigeon; - -class MessagePack { - // FIXME: Rename to avoid clash with ODID MessagePack - final String macAddress; - final int? lastMessageRssi; - final DateTime lastUpdate; - final pigeon.BasicIdMessage? basicIdMessage; - final pigeon.LocationMessage? locationMessage; - final pigeon.OperatorIdMessage? operatorIdMessage; - final pigeon.SelfIdMessage? selfIdMessage; - final pigeon.AuthenticationMessage? authenticationMessage; - final pigeon.SystemDataMessage? systemDataMessage; - - MessagePack({ - required this.macAddress, - this.lastMessageRssi, - required this.lastUpdate, - this.basicIdMessage, - this.locationMessage, - this.operatorIdMessage, - this.selfIdMessage, - this.authenticationMessage, - this.systemDataMessage, - }); - - static const colorMax = 120; - static const colorOffset = 90; - - MessagePack copyWith({ - String? macAddress, - int? lastMessageRssi, - DateTime? lastUpdate, - pigeon.BasicIdMessage? basicIdMessage, - pigeon.LocationMessage? locationMessage, - pigeon.OperatorIdMessage? operatorIdMessage, - pigeon.SelfIdMessage? selfIdMessage, - pigeon.AuthenticationMessage? authenticationMessage, - pigeon.SystemDataMessage? systemDataMessage, - }) => - MessagePack( - macAddress: macAddress ?? this.macAddress, - lastMessageRssi: lastMessageRssi ?? this.lastMessageRssi, - lastUpdate: lastUpdate ?? DateTime.now(), - basicIdMessage: basicIdMessage ?? this.basicIdMessage, - locationMessage: locationMessage ?? this.locationMessage, - operatorIdMessage: operatorIdMessage ?? this.operatorIdMessage, - selfIdMessage: selfIdMessage ?? this.selfIdMessage, - authenticationMessage: - authenticationMessage ?? this.authenticationMessage, - systemDataMessage: systemDataMessage ?? this.systemDataMessage, - ); - - MessagePack updateWithBasic(pigeon.BasicIdMessage message) { - return copyWith( - basicIdMessage: message, - lastMessageRssi: message.rssi, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - } - - MessagePack updateWithLocation(pigeon.LocationMessage message) { - return copyWith( - locationMessage: message, - lastMessageRssi: message.rssi, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - } - - MessagePack updateWithOperatorId(pigeon.OperatorIdMessage message) { - return copyWith( - operatorIdMessage: message, - lastMessageRssi: message.rssi, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - } - - MessagePack updateWithAuthentication(pigeon.AuthenticationMessage message) { - return copyWith( - authenticationMessage: message, - lastMessageRssi: message.rssi, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - } - - MessagePack updateWithSystemData(pigeon.SystemDataMessage message) { - return copyWith( - systemDataMessage: message, - lastMessageRssi: message.rssi, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - } - - MessagePack updateWithSelfId(pigeon.SelfIdMessage message) { - return copyWith( - selfIdMessage: message, - lastMessageRssi: message.rssi, - lastUpdate: - DateTime.fromMillisecondsSinceEpoch(message.receivedTimestamp)); - } - - pigeon.MessageSource getPackSource() { - if (locationMessage != null && locationMessage!.source != null) - return locationMessage!.source!; - if (selfIdMessage != null && selfIdMessage!.source != null) - return selfIdMessage!.source!; - if (basicIdMessage != null && basicIdMessage!.source != null) - return basicIdMessage!.source!; - if (operatorIdMessage != null && operatorIdMessage!.source != null) - return operatorIdMessage!.source!; - if (systemDataMessage != null && systemDataMessage!.source != null) - return systemDataMessage!.source!; - if (authenticationMessage != null && authenticationMessage!.source != null) - return authenticationMessage!.source!; - return pigeon.MessageSource.Unknown; - } - - /// Calculates a color from mac address, that uniquely identifies the device - Color getPackColor() { - final len = macAddress.length; - return Color.fromARGB( - locationMessage?.status != pigeon.AircraftStatus.Airborne ? 80 : 255, - colorOffset + - 32 + - macAddress - .substring(0, len ~/ 2) - .codeUnits - .reduce((sum, e) => sum + e) % - (colorMax - 32), - colorOffset + - macAddress.codeUnits.reduce((sum, e) => (sum * e) % colorMax), - colorOffset + - macAddress - .substring(len ~/ 2) - .codeUnits - .fold(255, (sum, e) => sum - e % colorMax), - ); - } - - bool operatorIDSet() { - return operatorIdMessage != null && - operatorIdMessage!.operatorId != OPERATOR_ID_NOT_SET; - } - - bool operatorIDValid() { - final validCharacters = RegExp(r'^[a-zA-Z0-9]+$'); - return operatorIdMessage != null && - operatorIdMessage!.operatorId.length == 16 && - validCharacters.hasMatch(operatorIdMessage!.operatorId); - } - - bool systemDataValid() { - return systemDataMessage != null && - systemDataMessage?.operatorLatitude != null && - systemDataMessage?.operatorLongitude != null && - systemDataMessage?.operatorLongitude != INV_LON && - systemDataMessage!.operatorLatitude != INV_LAT && - systemDataMessage!.operatorLatitude <= MAX_LAT && - systemDataMessage!.operatorLatitude >= MIN_LAT && - systemDataMessage!.operatorLongitude <= MAX_LON && - systemDataMessage!.operatorLongitude >= MIN_LON; - } - - bool locationValid() { - return locationMessage != null && - locationMessage?.latitude != null && - locationMessage?.longitude != null && - locationMessage!.latitude != INV_LAT && - locationMessage!.longitude != INV_LON && - locationMessage!.latitude! <= MAX_LAT && - locationMessage!.longitude! <= MAX_LON && - locationMessage!.latitude! >= MIN_LAT && - locationMessage!.longitude! >= MIN_LON; - } -} diff --git a/lib/pigeon.dart b/lib/pigeon.dart index 86e1187..fb640c3 100644 --- a/lib/pigeon.dart +++ b/lib/pigeon.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.0.0), do not edit directly. +// Autogenerated from Pigeon (v10.1.6), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import @@ -8,17 +8,7 @@ import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; -/// ODID Message Type -enum MessageType { - BasicId, - Location, - Auth, - SelfId, - System, - OperatorId, - MessagePack, -} - +/// Higher priority drains battery but receives more data enum ScanPriority { High, Low, @@ -33,87 +23,6 @@ enum MessageSource { Unknown, } -/// Identification type -enum IdType { - None, - Serial_Number, - CAA_Registration_ID, - UTM_Assigned_ID, - Specific_Session_ID, -} - -/// Unmanned aircraft type -enum UaType { - None, - Aeroplane, - Helicopter_or_Multirotor, - Gyroplane, - Hybrid_Lift, - Ornithopter, - Glider, - Kite, - Free_balloon, - Captive_balloon, - Airship, - Free_fall_parachute, - Rocket, - Tethered_powered_aircraft, - Ground_obstacle, - Other, -} - -/// Aircraft flight status -enum AircraftStatus { - Undeclared, - Ground, - Airborne, - Emergency, - Remote_ID_System_Failure, -} - -/// Height value type -enum HeightType { - Takeoff, - Ground, -} - -/// Horizontal accuracy -enum HorizontalAccuracy { - Unknown, - kilometers_18_52, - kilometers_7_408, - kilometers_3_704, - kilometers_1_852, - meters_926, - meters_555_6, - meters_185_2, - meters_92_6, - meters_30, - meters_10, - meters_3, - meters_1, -} - -/// Vertical accuracy -enum VerticalAccuracy { - Unknown, - meters_150, - meters_45, - meters_25, - meters_10, - meters_3, - meters_1, -} - -/// Speed accuracy -enum SpeedAccuracy { - Unknown, - meter_per_second_10, - meter_per_second_3, - meter_per_second_1, - meter_per_second_0_3, -} - /// State of the Bluetooth adapter enum BluetoothState { Unknown, @@ -132,577 +41,44 @@ enum WifiState { Enabled, } -enum AuthType { - None, - UAS_ID_Signature, - Operator_ID_Signature, - Message_Set_Signature, - Network_Remote_ID, - Specific_Authentication, - Private_Use_0xA, - Private_Use_0xB, - Private_Use_0xC, - Private_Use_0xD, - Private_Use_0xE, - Private_Use_0xF, -} - -enum AircraftCategory { - Undeclared, - EU_Open, - EU_Specific, - EU_Certified, -} - -enum AircraftClass { - Undeclared, - EU_Class_0, - EU_Class_1, - EU_Class_2, - EU_Class_3, - EU_Class_4, - EU_Class_5, - EU_Class_6, -} - -enum OperatorLocationType { - TakeOff, - LiveGNSS, - FixedLocation, - Invalid, -} - -enum ClassificationType { - Undeclared, - EU, -} - -class BasicIdMessage { - BasicIdMessage({ - required this.receivedTimestamp, - required this.macAddress, - this.source, - this.rssi, - required this.uasId, - this.idType, - this.uaType, - }); - - int receivedTimestamp; - - String macAddress; - - MessageSource? source; - - int? rssi; - - /// The primary identifier of UAS - /// (Dronetag devices use their serial number as their UAS ID) - String uasId; - - /// Identification type - IdType? idType; - - /// Type of the aircraft - UaType? uaType; - - Object encode() { - return [ - receivedTimestamp, - macAddress, - source?.index, - rssi, - uasId, - idType?.index, - uaType?.index, - ]; - } - - static BasicIdMessage decode(Object result) { - result as List; - return BasicIdMessage( - receivedTimestamp: result[0]! as int, - macAddress: result[1]! as String, - source: result[2] != null - ? MessageSource.values[result[2]! as int] - : null, - rssi: result[3] as int?, - uasId: result[4]! as String, - idType: result[5] != null - ? IdType.values[result[5]! as int] - : null, - uaType: result[6] != null - ? UaType.values[result[6]! as int] - : null, - ); - } -} - -class LocationMessage { - LocationMessage({ - required this.receivedTimestamp, - required this.macAddress, - this.source, - this.rssi, - this.status, - this.heightType, - this.direction, - this.speedHorizontal, - this.speedVertical, - this.latitude, - this.longitude, - this.altitudePressure, - this.altitudeGeodetic, - this.height, - this.horizontalAccuracy, - this.verticalAccuracy, - this.baroAccuracy, - this.speedAccuracy, - this.time, - this.timeAccuracy, - }); - - int receivedTimestamp; - - String macAddress; - - MessageSource? source; - - int? rssi; - - /// The reported current status of the aircraft - AircraftStatus? status; - - /// The type of reported height - /// - /// (The default type is takeoff height) - HeightType? heightType; - - /// Direction of the aircraft heading (in degrees) - double? direction; - - /// Horizontal speed of the aircraft - double? speedHorizontal; - - /// Vertical speed of the aircraft - double? speedVertical; - - /// Location latitude of the aircraft - double? latitude; - - /// Location longitude of the aircraft - double? longitude; - - /// Altitude calculcated from barometric pressure (in meters) - double? altitudePressure; - - /// Altitude calculated from GNSS data (in meters) - double? altitudeGeodetic; - - /// Current height of the aircraft - double? height; - - /// Horizontal accuracy of reported position via GNSS - HorizontalAccuracy? horizontalAccuracy; - - /// Vertical accuracy of reported altitude via GNSS - VerticalAccuracy? verticalAccuracy; - - /// Vertical accuracy of reported altitude via barometric pressure - VerticalAccuracy? baroAccuracy; - - /// Speed accuracy of reported position via GNSS - SpeedAccuracy? speedAccuracy; - - /// Time of the location report - int? time; - - /// Accuracy of timestamp values - double? timeAccuracy; - - Object encode() { - return [ - receivedTimestamp, - macAddress, - source?.index, - rssi, - status?.index, - heightType?.index, - direction, - speedHorizontal, - speedVertical, - latitude, - longitude, - altitudePressure, - altitudeGeodetic, - height, - horizontalAccuracy?.index, - verticalAccuracy?.index, - baroAccuracy?.index, - speedAccuracy?.index, - time, - timeAccuracy, - ]; - } - - static LocationMessage decode(Object result) { - result as List; - return LocationMessage( - receivedTimestamp: result[0]! as int, - macAddress: result[1]! as String, - source: result[2] != null - ? MessageSource.values[result[2]! as int] - : null, - rssi: result[3] as int?, - status: result[4] != null - ? AircraftStatus.values[result[4]! as int] - : null, - heightType: result[5] != null - ? HeightType.values[result[5]! as int] - : null, - direction: result[6] as double?, - speedHorizontal: result[7] as double?, - speedVertical: result[8] as double?, - latitude: result[9] as double?, - longitude: result[10] as double?, - altitudePressure: result[11] as double?, - altitudeGeodetic: result[12] as double?, - height: result[13] as double?, - horizontalAccuracy: result[14] != null - ? HorizontalAccuracy.values[result[14]! as int] - : null, - verticalAccuracy: result[15] != null - ? VerticalAccuracy.values[result[15]! as int] - : null, - baroAccuracy: result[16] != null - ? VerticalAccuracy.values[result[16]! as int] - : null, - speedAccuracy: result[17] != null - ? SpeedAccuracy.values[result[17]! as int] - : null, - time: result[18] as int?, - timeAccuracy: result[19] as double?, - ); - } -} - -class OperatorIdMessage { - OperatorIdMessage({ - required this.receivedTimestamp, - required this.macAddress, - this.source, - this.rssi, - required this.operatorId, - }); - - /// Operator ID - int receivedTimestamp; - - String macAddress; - - MessageSource? source; - - int? rssi; - - String operatorId; - - Object encode() { - return [ - receivedTimestamp, - macAddress, - source?.index, - rssi, - operatorId, - ]; - } - - static OperatorIdMessage decode(Object result) { - result as List; - return OperatorIdMessage( - receivedTimestamp: result[0]! as int, - macAddress: result[1]! as String, - source: result[2] != null - ? MessageSource.values[result[2]! as int] - : null, - rssi: result[3] as int?, - operatorId: result[4]! as String, - ); - } -} - -class AuthenticationMessage { - AuthenticationMessage({ - required this.receivedTimestamp, - required this.macAddress, - this.source, - this.rssi, - this.authType, - required this.authDataPage, - required this.authLastPageIndex, - required this.authLength, - required this.authTimestamp, - required this.authData, - }); - - int receivedTimestamp; - - String macAddress; - - MessageSource? source; - - int? rssi; - - AuthType? authType; - - int authDataPage; - - int authLastPageIndex; - - int authLength; - - int authTimestamp; - - String authData; - - Object encode() { - return [ - receivedTimestamp, - macAddress, - source?.index, - rssi, - authType?.index, - authDataPage, - authLastPageIndex, - authLength, - authTimestamp, - authData, - ]; - } - - static AuthenticationMessage decode(Object result) { - result as List; - return AuthenticationMessage( - receivedTimestamp: result[0]! as int, - macAddress: result[1]! as String, - source: result[2] != null - ? MessageSource.values[result[2]! as int] - : null, - rssi: result[3] as int?, - authType: result[4] != null - ? AuthType.values[result[4]! as int] - : null, - authDataPage: result[5]! as int, - authLastPageIndex: result[6]! as int, - authLength: result[7]! as int, - authTimestamp: result[8]! as int, - authData: result[9]! as String, - ); - } -} - -class SelfIdMessage { - SelfIdMessage({ - required this.receivedTimestamp, - required this.macAddress, - this.source, - this.rssi, - required this.descriptionType, - required this.operationDescription, - }); - - int receivedTimestamp; - - String macAddress; - - MessageSource? source; - - int? rssi; - - int descriptionType; - - String operationDescription; - - Object encode() { - return [ - receivedTimestamp, - macAddress, - source?.index, - rssi, - descriptionType, - operationDescription, - ]; - } - - static SelfIdMessage decode(Object result) { - result as List; - return SelfIdMessage( - receivedTimestamp: result[0]! as int, - macAddress: result[1]! as String, - source: result[2] != null - ? MessageSource.values[result[2]! as int] - : null, - rssi: result[3] as int?, - descriptionType: result[4]! as int, - operationDescription: result[5]! as String, - ); - } -} - -class SystemDataMessage { - SystemDataMessage({ +/// Payload send from native to dart contains raw data and metadata +class ODIDPayload { + ODIDPayload({ + required this.rawData, required this.receivedTimestamp, required this.macAddress, - this.source, this.rssi, - this.operatorLocationType, - this.classificationType, - required this.operatorLatitude, - required this.operatorLongitude, - required this.areaCount, - required this.areaRadius, - required this.areaCeiling, - required this.areaFloor, - this.category, - this.classValue, - required this.operatorAltitudeGeo, + required this.source, }); - int receivedTimestamp; - - String macAddress; - - MessageSource? source; - - int? rssi; - - OperatorLocationType? operatorLocationType; - - ClassificationType? classificationType; - - double operatorLatitude; - - double operatorLongitude; - - int areaCount; - - int areaRadius; - - double areaCeiling; - - double areaFloor; - - AircraftCategory? category; - - AircraftClass? classValue; - - double operatorAltitudeGeo; - - Object encode() { - return [ - receivedTimestamp, - macAddress, - source?.index, - rssi, - operatorLocationType?.index, - classificationType?.index, - operatorLatitude, - operatorLongitude, - areaCount, - areaRadius, - areaCeiling, - areaFloor, - category?.index, - classValue?.index, - operatorAltitudeGeo, - ]; - } - - static SystemDataMessage decode(Object result) { - result as List; - return SystemDataMessage( - receivedTimestamp: result[0]! as int, - macAddress: result[1]! as String, - source: result[2] != null - ? MessageSource.values[result[2]! as int] - : null, - rssi: result[3] as int?, - operatorLocationType: result[4] != null - ? OperatorLocationType.values[result[4]! as int] - : null, - classificationType: result[5] != null - ? ClassificationType.values[result[5]! as int] - : null, - operatorLatitude: result[6]! as double, - operatorLongitude: result[7]! as double, - areaCount: result[8]! as int, - areaRadius: result[9]! as int, - areaCeiling: result[10]! as double, - areaFloor: result[11]! as double, - category: result[12] != null - ? AircraftCategory.values[result[12]! as int] - : null, - classValue: result[13] != null - ? AircraftClass.values[result[13]! as int] - : null, - operatorAltitudeGeo: result[14]! as double, - ); - } -} - -class ConnectionMessage { - ConnectionMessage({ - required this.receivedTimestamp, - required this.macAddress, - this.source, - this.rssi, - required this.transportType, - required this.lastSeen, - required this.firstSeen, - required this.msgDelta, - }); + Uint8List rawData; int receivedTimestamp; String macAddress; - MessageSource? source; - int? rssi; - String transportType; - - int lastSeen; - - int firstSeen; - - int msgDelta; + MessageSource source; Object encode() { return [ + rawData, receivedTimestamp, macAddress, - source?.index, rssi, - transportType, - lastSeen, - firstSeen, - msgDelta, + source.index, ]; } - static ConnectionMessage decode(Object result) { + static ODIDPayload decode(Object result) { result as List; - return ConnectionMessage( - receivedTimestamp: result[0]! as int, - macAddress: result[1]! as String, - source: result[2] != null - ? MessageSource.values[result[2]! as int] - : null, + return ODIDPayload( + rawData: result[0]! as Uint8List, + receivedTimestamp: result[1]! as int, + macAddress: result[2]! as String, rssi: result[3] as int?, - transportType: result[4]! as String, - lastSeen: result[5]! as int, - firstSeen: result[6]! as int, - msgDelta: result[7]! as int, + source: MessageSource.values[result[4]! as int], ); } } @@ -719,7 +95,7 @@ class Api { Future startScanBluetooth() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.startScanBluetooth', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.startScanBluetooth', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -741,7 +117,7 @@ class Api { Future startScanWifi() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.startScanWifi', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.startScanWifi', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -763,7 +139,7 @@ class Api { Future stopScanBluetooth() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.stopScanBluetooth', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.stopScanBluetooth', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -785,7 +161,7 @@ class Api { Future stopScanWifi() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.stopScanWifi', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.stopScanWifi', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -807,7 +183,7 @@ class Api { Future setBtScanPriority(ScanPriority arg_priority) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.setBtScanPriority', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.setBtScanPriority', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_priority.index]) as List?; @@ -829,7 +205,7 @@ class Api { Future isScanningBluetooth() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.isScanningBluetooth', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.isScanningBluetooth', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -856,7 +232,7 @@ class Api { Future isScanningWifi() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.isScanningWifi', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.isScanningWifi', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -883,7 +259,7 @@ class Api { Future bluetoothState() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.bluetoothState', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.bluetoothState', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -910,7 +286,7 @@ class Api { Future wifiState() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.wifiState', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.wifiState', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -937,7 +313,7 @@ class Api { Future btExtendedSupported() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.btExtendedSupported', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.btExtendedSupported', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -964,7 +340,7 @@ class Api { Future btMaxAdvDataLen() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.btMaxAdvDataLen', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.btMaxAdvDataLen', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -991,7 +367,7 @@ class Api { Future wifiNaNSupported() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.Api.wifiNaNSupported', codec, + 'dev.flutter.pigeon.flutter_opendroneid.Api.wifiNaNSupported', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -1017,31 +393,13 @@ class Api { } } -class _MessageApiCodec extends StandardMessageCodec { - const _MessageApiCodec(); +class _PayloadApiCodec extends StandardMessageCodec { + const _PayloadApiCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is AuthenticationMessage) { + if (value is ODIDPayload) { buffer.putUint8(128); writeValue(buffer, value.encode()); - } else if (value is BasicIdMessage) { - buffer.putUint8(129); - writeValue(buffer, value.encode()); - } else if (value is ConnectionMessage) { - buffer.putUint8(130); - writeValue(buffer, value.encode()); - } else if (value is LocationMessage) { - buffer.putUint8(131); - writeValue(buffer, value.encode()); - } else if (value is OperatorIdMessage) { - buffer.putUint8(132); - writeValue(buffer, value.encode()); - } else if (value is SelfIdMessage) { - buffer.putUint8(133); - writeValue(buffer, value.encode()); - } else if (value is SystemDataMessage) { - buffer.putUint8(134); - writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -1051,151 +409,29 @@ class _MessageApiCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 128: - return AuthenticationMessage.decode(readValue(buffer)!); - case 129: - return BasicIdMessage.decode(readValue(buffer)!); - case 130: - return ConnectionMessage.decode(readValue(buffer)!); - case 131: - return LocationMessage.decode(readValue(buffer)!); - case 132: - return OperatorIdMessage.decode(readValue(buffer)!); - case 133: - return SelfIdMessage.decode(readValue(buffer)!); - case 134: - return SystemDataMessage.decode(readValue(buffer)!); + return ODIDPayload.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); } } } -class MessageApi { - /// Constructor for [MessageApi]. The [binaryMessenger] named argument is +class PayloadApi { + /// Constructor for [PayloadApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - MessageApi({BinaryMessenger? binaryMessenger}) + PayloadApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; - static const MessageCodec codec = _MessageApiCodec(); - - Future determineMessageType(Uint8List arg_payload, int arg_offset) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.MessageApi.determineMessageType', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_payload, arg_offset]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return (replyList[0] as int?); - } - } - - Future fromBufferBasic(Uint8List arg_payload, int arg_offset, String arg_macAddress) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.MessageApi.fromBufferBasic', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_payload, arg_offset, arg_macAddress]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return (replyList[0] as BasicIdMessage?); - } - } - - Future fromBufferLocation(Uint8List arg_payload, int arg_offset, String arg_macAddress) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.MessageApi.fromBufferLocation', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_payload, arg_offset, arg_macAddress]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return (replyList[0] as LocationMessage?); - } - } - - Future fromBufferOperatorId(Uint8List arg_payload, int arg_offset, String arg_macAddress) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.MessageApi.fromBufferOperatorId', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_payload, arg_offset, arg_macAddress]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return (replyList[0] as OperatorIdMessage?); - } - } - - Future fromBufferSelfId(Uint8List arg_payload, int arg_offset, String arg_macAddress) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.MessageApi.fromBufferSelfId', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_payload, arg_offset, arg_macAddress]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return (replyList[0] as SelfIdMessage?); - } - } + static const MessageCodec codec = _PayloadApiCodec(); - Future fromBufferAuthentication(Uint8List arg_payload, int arg_offset, String arg_macAddress) async { + Future getPayload(Uint8List arg_rawData, MessageSource arg_source, String arg_macAddress, int arg_rssi, int arg_receivedTimestamp) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.MessageApi.fromBufferAuthentication', codec, + 'dev.flutter.pigeon.flutter_opendroneid.PayloadApi.getPayload', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_payload, arg_offset, arg_macAddress]) as List?; + await channel.send([arg_rawData, arg_source.index, arg_macAddress, arg_rssi, arg_receivedTimestamp]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -1207,52 +443,13 @@ class MessageApi { message: replyList[1] as String?, details: replyList[2], ); - } else { - return (replyList[0] as AuthenticationMessage?); - } - } - - Future fromBufferSystemData(Uint8List arg_payload, int arg_offset, String arg_macAddress) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.MessageApi.fromBufferSystemData', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_payload, arg_offset, arg_macAddress]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return (replyList[0] as SystemDataMessage?); - } - } - - Future fromBufferConnection(Uint8List arg_payload, int arg_offset, String arg_macAddress) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.MessageApi.fromBufferConnection', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_payload, arg_offset, arg_macAddress]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { + } else if (replyList[0] == null) { throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as ConnectionMessage?); + return (replyList[0] as ODIDPayload?)!; } } } diff --git a/lib/utils/compare_extension.dart b/lib/utils/compare_extension.dart new file mode 100644 index 0000000..e2128a3 --- /dev/null +++ b/lib/utils/compare_extension.dart @@ -0,0 +1,52 @@ +import 'package:dart_opendroneid/src/types.dart'; + +// extensions to check whether messages have the same data +// The messages may not necessarily be the same, timestamp, rssi are ignored +// compares just relevant data fields +extension LocationMessageCompareExtension on LocationMessage { + // consider location with same timestamp equal + bool containsEqualData(LocationMessage other) { + return timestamp == other.timestamp && + location?.latitude == other.location?.latitude && + location?.longitude == other.location?.longitude; + } +} + +extension BasicIDCompareExtension on BasicIDMessage { + bool containsEqualData(BasicIDMessage other) { + return uasID == other.uasID && uaType == other.uaType; + } +} + +extension OperatorIDMessageCompareExtension on OperatorIDMessage { + bool containsEqualData(OperatorIDMessage other) { + return operatorID == other.operatorID; + } +} + +extension SystemMessageCompareExtension on SystemMessage { + bool containsEqualData(SystemMessage other) { + return areaCeiling == other.areaCeiling && + areaCount == other.areaCount && + areaFloor == other.areaFloor && + areaRadius == other.areaRadius && + uaClassification == other.uaClassification && + timestamp == other.timestamp && + operatorAltitude == other.operatorAltitude && + operatorLocationType == other.operatorLocationType && + operatorLocation == other.operatorLocation; + } +} + +extension AuthenticationCompareExtension on AuthMessage { + bool containsEqualData(AuthMessage other) { + return rawContent == other.rawContent; + } +} + +extension SelfIDCompareExtension on SelfIDMessage { + bool containsEqualData(SelfIDMessage other) { + return descriptionType == other.descriptionType && + description == other.description; + } +} diff --git a/lib/models/conversions.dart b/lib/utils/conversions.dart similarity index 80% rename from lib/models/conversions.dart rename to lib/utils/conversions.dart index b968466..ddb5d22 100644 --- a/lib/models/conversions.dart +++ b/lib/utils/conversions.dart @@ -1,9 +1,9 @@ -import 'package:flutter_opendroneid/pigeon.dart'; +import 'package:dart_opendroneid/src/types.dart'; /// Conversions extensions const Map _horizontalAccuracyConversionMap = { - HorizontalAccuracy.Unknown: null, + HorizontalAccuracy.unknown: null, HorizontalAccuracy.kilometers_18_52: 18520, HorizontalAccuracy.kilometers_7_408: 7408, HorizontalAccuracy.kilometers_3_704: 3704, @@ -19,7 +19,7 @@ const Map _horizontalAccuracyConversionMap = { }; const Map _verticalAccuracyConversionMap = { - VerticalAccuracy.Unknown: null, + VerticalAccuracy.unknown: null, VerticalAccuracy.meters_150: 150, VerticalAccuracy.meters_45: 45, VerticalAccuracy.meters_25: 25, @@ -29,11 +29,11 @@ const Map _verticalAccuracyConversionMap = { }; const Map _speedAccuracyConversionMap = { - SpeedAccuracy.Unknown: null, - SpeedAccuracy.meter_per_second_10: 10, - SpeedAccuracy.meter_per_second_3: 3, - SpeedAccuracy.meter_per_second_1: 1, - SpeedAccuracy.meter_per_second_0_3: 0.3, + SpeedAccuracy.unknown: null, + SpeedAccuracy.meterPerSecond_10: 10, + SpeedAccuracy.meterPerSecond_3: 3, + SpeedAccuracy.meterPerSecond_1: 1, + SpeedAccuracy.meterPerSecond_0_3: 0.3, }; extension HorizontalAccuracyConversion on HorizontalAccuracy { diff --git a/pigeon/schema.dart b/pigeon/schema.dart index b19a7bc..bb37b13 100644 --- a/pigeon/schema.dart +++ b/pigeon/schema.dart @@ -1,16 +1,6 @@ import 'package:pigeon/pigeon.dart'; -/// ODID Message Type -enum MessageType { - BasicId, - Location, - Auth, - SelfId, - System, - OperatorId, - MessagePack, -} - +/// Higher priority drains battery but receives more data enum ScanPriority { High, Low, @@ -25,87 +15,6 @@ enum MessageSource { Unknown, } -/// Identification type -enum IdType { - None, - Serial_Number, - CAA_Registration_ID, - UTM_Assigned_ID, - Specific_Session_ID, -} - -/// Unmanned aircraft type -enum UaType { - None, - Aeroplane, - Helicopter_or_Multirotor, - Gyroplane, - Hybrid_Lift, // VTOL. Fixed wing aircraft that can take off vertically - Ornithopter, - Glider, - Kite, - Free_balloon, - Captive_balloon, - Airship, - Free_fall_parachute, // Unpowered - Rocket, - Tethered_powered_aircraft, - Ground_obstacle, - Other, -} - -/// Aircraft flight status -enum AircraftStatus { - Undeclared, - Ground, - Airborne, - Emergency, - Remote_ID_System_Failure, -} - -/// Height value type -enum HeightType { - Takeoff, - Ground, -} - -/// Horizontal accuracy -enum HorizontalAccuracy { - Unknown, - kilometers_18_52, - kilometers_7_408, - kilometers_3_704, - kilometers_1_852, - meters_926, - meters_555_6, - meters_185_2, - meters_92_6, - meters_30, - meters_10, - meters_3, - meters_1, -} - -/// Vertical accuracy -enum VerticalAccuracy { - Unknown, - meters_150, - meters_45, - meters_25, - meters_10, - meters_3, - meters_1, -} - -/// Speed accuracy -enum SpeedAccuracy { - Unknown, - meter_per_second_10, - meter_per_second_3, - meter_per_second_1, - meter_per_second_0_3, -} - /// State of the Bluetooth adapter enum BluetoothState { Unknown, @@ -124,189 +33,25 @@ enum WifiState { Enabled, } -enum AuthType { - None, - UAS_ID_Signature, - Operator_ID_Signature, - Message_Set_Signature, - Network_Remote_ID, - Specific_Authentication, - Private_Use_0xA, - Private_Use_0xB, - Private_Use_0xC, - Private_Use_0xD, - Private_Use_0xE, - Private_Use_0xF -} - -enum AircraftCategory { - Undeclared, - EU_Open, - EU_Specific, - EU_Certified, -} +/// Payload send from native to dart contains raw data and metadata +class ODIDPayload { + final Uint8List rawData; -enum AircraftClass { - Undeclared, - EU_Class_0, - EU_Class_1, - EU_Class_2, - EU_Class_3, - EU_Class_4, - EU_Class_5, - EU_Class_6, -} + final int receivedTimestamp; -enum OperatorLocationType { TakeOff, LiveGNSS, FixedLocation, Invalid } - -enum ClassificationType { - Undeclared, - EU, // European Union -} - -class BasicIdMessage { - // common part - late final int receivedTimestamp; - late final String macAddress; - late final MessageSource? source; - late final int? rssi; - - /// The primary identifier of UAS - /// (Dronetag devices use their serial number as their UAS ID) - late final String uasId; - - /// Identification type - late final IdType? idType; - - /// Type of the aircraft - late UaType? uaType; -} + final String macAddress; -class LocationMessage { - // common part - late final int receivedTimestamp; - late final String macAddress; - late final MessageSource? source; - late final int? rssi; - - /// The reported current status of the aircraft - late final AircraftStatus? status; - - /// The type of reported height - /// - /// (The default type is takeoff height) - late final HeightType? heightType; - - /// Direction of the aircraft heading (in degrees) - late final double? direction; - - /// Horizontal speed of the aircraft - late final double? speedHorizontal; - - /// Vertical speed of the aircraft - late final double? speedVertical; - - /// Location latitude of the aircraft - late final double? latitude; - - /// Location longitude of the aircraft - late final double? longitude; - - /// Altitude calculcated from barometric pressure (in meters) - late final double? altitudePressure; - - /// Altitude calculated from GNSS data (in meters) - late final double? altitudeGeodetic; - - /// Current height of the aircraft - late final double? height; - - /// Horizontal accuracy of reported position via GNSS - late final HorizontalAccuracy? horizontalAccuracy; - - /// Vertical accuracy of reported altitude via GNSS - late final VerticalAccuracy? verticalAccuracy; - - /// Vertical accuracy of reported altitude via barometric pressure - late final VerticalAccuracy? baroAccuracy; - - /// Speed accuracy of reported position via GNSS - late final SpeedAccuracy? speedAccuracy; - - /// Time of the location report - late final int? time; - - /// Accuracy of timestamp values - late final double? timeAccuracy; -} - -class OperatorIdMessage { - /// Operator ID - late final int receivedTimestamp; - late final String macAddress; - late final MessageSource? source; - late final int? rssi; - - late final String operatorId; -} - -class AuthenticationMessage { - // common part - late final int receivedTimestamp; - late final String macAddress; - late final MessageSource? source; - late final int? rssi; - - late final AuthType? authType; - late final int authDataPage; - late final int authLastPageIndex; - late final int authLength; - late final int authTimestamp; - late final String authData; -} - -class SelfIdMessage { - // common part - late final int receivedTimestamp; - late final String macAddress; - late final MessageSource? source; - late final int? rssi; - - late final int descriptionType; - late final String operationDescription; -} - -class SystemDataMessage { - // common part - late final int receivedTimestamp; - late final String macAddress; - late final MessageSource? source; - late final int? rssi; - - late final OperatorLocationType? operatorLocationType; - late final ClassificationType? classificationType; - late final double operatorLatitude; - late final double operatorLongitude; - late final int areaCount; - late final int areaRadius; - late final double areaCeiling; - late final double areaFloor; - late final AircraftCategory? category; - late final AircraftClass? classValue; - late final double operatorAltitudeGeo; -} + final int? rssi; -class ConnectionMessage { - // common part - late final int receivedTimestamp; - late final String macAddress; - late final MessageSource? source; - late final int? rssi; + final MessageSource source; - late final String transportType; - late final int lastSeen; - late final int firstSeen; - late final int msgDelta; + ODIDPayload( + this.rawData, + this.receivedTimestamp, + this.macAddress, + this.rssi, + this.source, + ); } @HostApi() @@ -337,21 +82,9 @@ abstract class Api { bool wifiNaNSupported(); } +// ODIDPayload is not generated until used in API @HostApi() -abstract class MessageApi { - int? determineMessageType(Uint8List payload, int offset); - BasicIdMessage? fromBufferBasic( - Uint8List payload, int offset, String macAddress); - LocationMessage? fromBufferLocation( - Uint8List payload, int offset, String macAddress); - OperatorIdMessage? fromBufferOperatorId( - Uint8List payload, int offset, String macAddress); - SelfIdMessage? fromBufferSelfId( - Uint8List payload, int offset, String macAddress); - AuthenticationMessage? fromBufferAuthentication( - Uint8List payload, int offset, String macAddress); - SystemDataMessage? fromBufferSystemData( - Uint8List payload, int offset, String macAddress); - ConnectionMessage? fromBufferConnection( - Uint8List payload, int offset, String macAddress); +abstract class PayloadApi { + ODIDPayload getPayload(Uint8List rawData, MessageSource source, + String macAddress, int rssi, int receivedTimestamp); } diff --git a/pubspec.yaml b/pubspec.yaml index 02b2f66..8528d80 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,9 +10,10 @@ environment: dependencies: flutter: sdk: flutter - pigeon: ^10.0.0 permission_handler: ^10.2.0 device_info_plus: ^8.0.0 +dev_dependencies: + pigeon: ^10.1.6 flutter: plugin: From 715913baa37500d8785236e06d5c4b99cef460f7 Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Sun, 27 Aug 2023 18:13:01 +0200 Subject: [PATCH 02/11] chore: add dart-opendroneid from local path --- pubspec.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pubspec.yaml b/pubspec.yaml index 8528d80..07da811 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,6 +12,11 @@ dependencies: sdk: flutter permission_handler: ^10.2.0 device_info_plus: ^8.0.0 +# change to path to your clone of dart-opendroneid +# TODO: change when dart_opendroneid is released + dart_opendroneid: + path: ../../dart-opendroneid/dart-opendroneid + dev_dependencies: pigeon: ^10.1.6 From c47738842cc2f9c115af3bbb59f8deba431b3d08 Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Mon, 28 Aug 2023 15:54:02 +0200 Subject: [PATCH 03/11] fix: update container with source of current message update DT-2604 --- lib/flutter_opendroneid.dart | 8 +++++--- lib/models/message_container.dart | 30 +++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/flutter_opendroneid.dart b/lib/flutter_opendroneid.dart index 294cee8..664c5a5 100644 --- a/lib/flutter_opendroneid.dart +++ b/lib/flutter_opendroneid.dart @@ -108,9 +108,11 @@ class FlutterOpenDroneId { final message = parseODIDMessage(payload.rawData); if (message == null) return; _storedPacks[payload.macAddress] = storedPack.update( - message: message, - receivedTimestamp: payload.receivedTimestamp, - rssi: payload.rssi); + message: message, + receivedTimestamp: payload.receivedTimestamp, + rssi: payload.rssi, + source: payload.source, + ); _packController.add(_storedPacks[payload.macAddress]!); } diff --git a/lib/models/message_container.dart b/lib/models/message_container.dart index 3d3f9cd..483d34b 100644 --- a/lib/models/message_container.dart +++ b/lib/models/message_container.dart @@ -62,6 +62,7 @@ class MessageContainer { MessageContainer update({ required ODIDMessage message, required int receivedTimestamp, + required pigeon.MessageSource source, int? rssi, }) { if (message.runtimeType == MessagePack) { @@ -69,7 +70,10 @@ class MessageContainer { var result = this; for (var packMessage in messages) { result = result.update( - message: packMessage, receivedTimestamp: receivedTimestamp); + message: packMessage, + receivedTimestamp: receivedTimestamp, + source: source, + ); } return result; } @@ -77,27 +81,39 @@ class MessageContainer { LocationMessage => copyWith( locationMessage: message as LocationMessage, lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), BasicIDMessage => copyWith( basicIdMessage: message as BasicIDMessage, lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), SelfIDMessage => copyWith( selfIdMessage: message as SelfIDMessage, lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), OperatorIDMessage => copyWith( operatorIdMessage: message as OperatorIDMessage, lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), AuthMessage => copyWith( authenticationMessage: message as AuthMessage, lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), SystemMessage => copyWith( systemDataMessage: message as SystemMessage, lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)), + lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), _ => this }; } From b8e2a02fa81b7c1665aae87bd8d261932db36668 Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Tue, 29 Aug 2023 15:26:24 +0200 Subject: [PATCH 04/11] refactor: create common ancestor class for odid scanners DT-2604 --- .../flutter_opendroneid/OdidPayloadHandler.kt | 21 --- .../scanner/BluetoothScanner.kt | 163 ++++++++--------- .../scanner/ODIDScanner.kt | 63 +++++++ .../scanner/WifiNaNScanner.kt | 116 +++++------- .../scanner/WifiScanner.kt | 172 ++++++++---------- 5 files changed, 261 insertions(+), 274 deletions(-) delete mode 100644 android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidPayloadHandler.kt create mode 100644 android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidPayloadHandler.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidPayloadHandler.kt deleted file mode 100644 index 0e6beea..0000000 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/OdidPayloadHandler.kt +++ /dev/null @@ -1,21 +0,0 @@ -package cz.dronetag.flutter_opendroneid - -import java.nio.ByteBuffer -import java.nio.ByteOrder -import kotlin.experimental.and -import io.flutter.Log - -class OdidPayloadHandler : Pigeon.PayloadApi { - - override fun getPayload(rawData: ByteArray, source: Pigeon.MessageSource, macAddress: String, rssi: Long, receivedTimestamp: Long): Pigeon.ODIDPayload { - val builder = Pigeon.ODIDPayload.Builder() - - builder.setRawData(rawData) - builder.setReceivedTimestamp(receivedTimestamp) - builder.setMacAddress(macAddress) - builder.setSource(source) - builder.setRssi(rssi) - - return builder.build() - } -} diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt index 5996513..2af9b43 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt @@ -15,36 +15,27 @@ import java.nio.ByteBuffer import java.nio.ByteOrder class BluetoothScanner( - private val odidPayloadStreamHandler: StreamHandler, - private val bluetoothStateHandler: StreamHandler, -) { - companion object { - const val MAX_MESSAGE_SIZE = 25 - } + odidPayloadStreamHandler: StreamHandler, + private val bluetoothStateHandler: StreamHandler, +) : ODIDScanner(odidPayloadStreamHandler) { + private val TAG: String = BluetoothScanner::class.java.getSimpleName() - var isScanning = false - get() = field - set(value) { - field = value - bluetoothStateHandler.send(value) - } var scanMode = ScanSettings.SCAN_MODE_LOW_LATENCY val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() - /* OpenDroneID Bluetooth beacons identify themselves by setting the GAP AD Type to - * "Service Data - 16-bit UUID" and the value to 0xFFFA for ASTM International, ASTM Remote ID. - * https://www.bluetooth.com/specifications/assigned-numbers/ -> "Generic Access Profile" - * https://www.bluetooth.com/specifications/assigned-numbers/ -> "16-bit UUIDs" - * Vol 3, Part B, Section 2.5.1 of the Bluetooth 5.1 Core Specification - * The AD Application Code is set to 0x0D = Open Drone ID. - */ + + /// OpenDroneID Bluetooth beacons identify themselves by setting the GAP AD Type to + /// "Service Data - 16-bit UUID" and the value to 0xFFFA for ASTM International, ASTM Remote ID. + /// https://www.bluetooth.com/specifications/assigned-numbers/ -> "Generic Access Profile" + /// https://www.bluetooth.com/specifications/assigned-numbers/ -> "16-bit UUIDs" + /// Vol 3, Part B, Section 2.5.1 of the Bluetooth 5.1 Core Specification + /// The AD Application Code is set to 0x0D = Open Drone ID. + private val serviceUuid = UUID.fromString("0000fffa-0000-1000-8000-00805f9b34fb") private val serviceParcelUuid = ParcelUuid(serviceUuid) private val odidAdCode = byteArrayOf(0x0D.toByte()) - private val payloadHandler: OdidPayloadHandler = OdidPayloadHandler() - @RequiresApi(Build.VERSION_CODES.O) - fun scan() { + override fun scan() { if (!bluetoothAdapter.isEnabled) return val bluetoothLeScanner: BluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner val builder: ScanFilter.Builder = ScanFilter.Builder() @@ -52,30 +43,36 @@ class BluetoothScanner( val scanFilters: MutableList = ArrayList() scanFilters.add(builder.build()) - Log.i("bluetooth LE extended supported:", bluetoothAdapter.isLeExtendedAdvertisingSupported.toString()) - Log.i("bluetooth LE coded phy supported:", bluetoothAdapter.isLeCodedPhySupported.toString()) - Log.i("bluetooth multiple advertisement supported:", bluetoothAdapter.isMultipleAdvertisementSupported.toString()) - Log.i("bluetooth max adv data len:", bluetoothAdapter.leMaximumAdvertisingDataLength.toString()) + logAdapterInfo(bluetoothAdapter) - var scanSettings = ScanSettings.Builder() - .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) - .build() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && - bluetoothAdapter.isLeCodedPhySupported && - bluetoothAdapter.isLeExtendedAdvertisingSupported - ) { - scanSettings = ScanSettings.Builder() - .setScanMode(scanMode) - .setLegacy(false) - .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED) - .build() - } + var scanSettings = buildScanSettings() bluetoothLeScanner.startScan(scanFilters, scanSettings, scanCallback) isScanning = true bluetoothStateHandler.send(true) } + override fun cancel() { + isScanning = false + if (!bluetoothAdapter.isEnabled) return + bluetoothStateHandler.send(false) + bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback) + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onAdapterStateReceived() { + val rawState = bluetoothAdapter.state + val commonState = getAdapterState() + if (rawState == BluetoothAdapter.STATE_OFF || rawState == BluetoothAdapter.STATE_TURNING_OFF) { + if (bluetoothAdapter.isEnabled) bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback) + isScanning = false + } else if ((rawState == BluetoothAdapter.STATE_ON) + && !isScanning) { + cancel() + scan() + } + } + fun setScanPriority(priority: Pigeon.ScanPriority) { if(priority == Pigeon.ScanPriority.HIGH) { @@ -105,13 +102,6 @@ class BluetoothScanner( return bluetoothAdapter.leMaximumAdvertisingDataLength; } - fun cancel() { - isScanning = false - if (!bluetoothAdapter.isEnabled) return - bluetoothStateHandler.send(false) - bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback) - } - fun getAdapterState(): Int { return when (bluetoothAdapter.state) { BluetoothAdapter.STATE_OFF -> 4 @@ -122,55 +112,58 @@ class BluetoothScanner( } } - fun handleODIDPayload(result: ScanResult, offset: Long) { - val scanRecord: ScanRecord = result.scanRecord ?: return - val bytes = scanRecord.bytes ?: return - var source = Pigeon.MessageSource.BLUETOOTH_LEGACY; + private val scanCallback: ScanCallback = object : ScanCallback() { + override fun onScanResult(callbackType: Int, result: ScanResult) { + val scanRecord: ScanRecord = result.scanRecord ?: return + val bytes = scanRecord.bytes ?: return + var source = Pigeon.MessageSource.BLUETOOTH_LEGACY; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && bluetoothAdapter.isLeCodedPhySupported()) { - if (result.getPrimaryPhy() == BluetoothDevice.PHY_LE_CODED) - source = Pigeon.MessageSource.BLUETOOTH_LONG_RANGE; - } - if (bytes.size < offset + MAX_MESSAGE_SIZE) return - - val payload = payloadHandler.getPayload( - bytes.copyOfRange(offset.toInt(), MAX_MESSAGE_SIZE + offset.toInt()), - source, - result.device.address, - result.rssi.toLong(), - System.currentTimeMillis() - ) - - odidPayloadStreamHandler.send(payload?.toList() as Any) - } + if (bytes.size < BT_OFFSET + MAX_MESSAGE_SIZE) return - val adapterStateReceiver: BroadcastReceiver = object : BroadcastReceiver() { - @RequiresApi(Build.VERSION_CODES.O) - override fun onReceive(context: Context?, intent: Intent?) { - val rawState = bluetoothAdapter.state - val commonState = getAdapterState() - if (rawState == BluetoothAdapter.STATE_OFF || rawState == BluetoothAdapter.STATE_TURNING_OFF) { - if (bluetoothAdapter.isEnabled) bluetoothAdapter.bluetoothLeScanner.stopScan(scanCallback) - isScanning = false - } else if ((rawState == BluetoothAdapter.STATE_ON) - && !isScanning) { - cancel() - scan() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && bluetoothAdapter.isLeCodedPhySupported()) { + if (result.getPrimaryPhy() == BluetoothDevice.PHY_LE_CODED) + source = Pigeon.MessageSource.BLUETOOTH_LONG_RANGE; } - } - } - private val scanCallback: ScanCallback = object : ScanCallback() { - override fun onScanResult(callbackType: Int, result: ScanResult) { - handleODIDPayload(result, 6) + receiveData( + offsetData(bytes, BT_OFFSET), + result.device.address, + source, + result.rssi.toLong(), + ) } override fun onBatchScanResults(results: List?) { - Log.e("scanner", "Got batch scan results, unable to handle") + Log.e(TAG, "Got batch scan results, unable to handle") } override fun onScanFailed(errorCode: Int) { - Log.e("scanner", "Scan failed: $errorCode") + Log.e(TAG, "Scan failed: $errorCode") + } + } + + private fun logAdapterInfo(bluetoothAdapter: BluetoothAdapter) { + Log.i(TAG, "bluetooth LE extended supported: " + bluetoothAdapter.isLeExtendedAdvertisingSupported.toString()) + Log.i(TAG, "bluetooth LE coded phy supported: " + bluetoothAdapter.isLeCodedPhySupported.toString()) + Log.i(TAG, "bluetooth multiple advertisement supported: " + bluetoothAdapter.isMultipleAdvertisementSupported.toString()) + Log.i(TAG, "bluetooth max adv data len:" + bluetoothAdapter.leMaximumAdvertisingDataLength.toString()) + } + + private fun buildScanSettings() : ScanSettings { + var scanSettings = ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .build() + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && + bluetoothAdapter.isLeCodedPhySupported && + bluetoothAdapter.isLeExtendedAdvertisingSupported + ) { + scanSettings = ScanSettings.Builder() + .setScanMode(scanMode) + .setLegacy(false) + .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED) + .build() } + return scanSettings } } \ No newline at end of file diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt new file mode 100644 index 0000000..8d7a97e --- /dev/null +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt @@ -0,0 +1,63 @@ +package cz.dronetag.flutter_opendroneid + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent + +/// Contains common functinality for ODID scanners +/// Creates [ODIDPayload] instances implementin Pigeon PayloadAPI +abstract class ODIDScanner( + val odidPayloadStreamHandler: StreamHandler +) : Pigeon.PayloadApi { + + companion object { + const val MAX_MESSAGE_SIZE = 25 + const val BT_OFFSET = 6 + const val WIFI_BEACON_OFFSET = 5 + const val WIFI_NAN_OFFSET = 1 + } + + var isScanning = false + get() = field + set(value) { + field = value + } + + val adapterStateReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + onAdapterStateReceived() + } + } + + abstract fun scan() + + abstract fun cancel() + + abstract fun onAdapterStateReceived() + + override fun getPayload(rawData: ByteArray, source: Pigeon.MessageSource, macAddress: String, rssi: Long, receivedTimestamp: Long): Pigeon.ODIDPayload { + val builder = Pigeon.ODIDPayload.Builder() + + builder.setRawData(rawData) + builder.setReceivedTimestamp(receivedTimestamp) + builder.setMacAddress(macAddress) + builder.setSource(source) + builder.setRssi(rssi) + + return builder.build() + } + + /// receive data and metadata, create [ODIDPayload] and sent to stream + fun receiveData( + data: ByteArray, macAddress: String, source: Pigeon.MessageSource, rssi: Long = 0 + ) { + val payload = getPayload( + data, source, macAddress, rssi, System.currentTimeMillis() + ) + + odidPayloadStreamHandler.send(payload?.toList() as Any) + } + + /// returs [ByteArray] without first offset elements + inline fun offsetData(data: ByteArray, offset: Int) : ByteArray = data.copyOfRange(offset, data.size) +} \ No newline at end of file diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt index b7e35e5..6a04a21 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt @@ -27,22 +27,16 @@ import java.util.List; class WifiNaNScanner ( - private val odidPayloadStreamHandler: StreamHandler, + odidPayloadStreamHandler: StreamHandler, private val wifiStateHandler: StreamHandler, private val wifiAwareManager: WifiAwareManager?, private val context: Context -) { - companion object { - const val MAX_MESSAGE_SIZE = 25 - } - +) : ODIDScanner(odidPayloadStreamHandler) { + private val TAG: String = WifiNaNScanner::class.java.getSimpleName() + private var wifiAwareSession: WifiAwareSession? = null private val wifiScanEnabled = true private var wifiAwareSupported = true - var isScanning = false - - private val payloadHandler: OdidPayloadHandler = OdidPayloadHandler() - private val TAG: String = WifiNaNScanner::class.java.getSimpleName() init{ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || @@ -55,14 +49,35 @@ class WifiNaNScanner ( wifiAwareSupported = true } } - - private val myReceiver: BroadcastReceiver = object : BroadcastReceiver() { - @RequiresApi(Build.VERSION_CODES.O) - override fun onReceive(context: Context?, intent: Intent?) { - if (wifiAwareManager!!.isAvailable) { - Log.i(TAG, "WiFi Aware became available.") - startScan() - } + + override fun scan() { + if (!wifiScanEnabled) { + return + } + isScanning = true + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || + !context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)) { + Log.i(TAG, "WiFi Aware is not supported."); + wifiAwareSupported = false + return; + } + wifiAwareSupported = true + context.registerReceiver(adapterStateReceiver, IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED)) + startScan(); + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun cancel() { + if (!wifiAwareSupported) return + isScanning = false; + stopScan() + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onAdapterStateReceived() { + if (wifiAwareManager!!.isAvailable) { + Log.i(TAG, "WiFi Aware became available.") + startScan() } } @@ -80,15 +95,11 @@ class WifiNaNScanner ( serviceSpecificInfo: ByteArray?, matchFilter: MutableList? ) { - val transportType = "NAN" - - val timeNano: Long = SystemClock.elapsedRealtimeNanos() - if(serviceSpecificInfo != null) + if (serviceSpecificInfo != null) receiveData( - serviceSpecificInfo, - peerHandle.hashCode(), - timeNano, - transportType + offsetData(serviceSpecificInfo, WIFI_NAN_OFFSET), + peerHandle.hashCode().toString(), + Pigeon.MessageSource.WIFI_NAN, ) } }, null) @@ -96,22 +107,6 @@ class WifiNaNScanner ( } - fun receiveData( - data: ByteArray, peerHash: Int, timeNano: Long, - transportType: String? - ) { - val offset = 4 - val payload = payloadHandler.getPayload( - data.copyOfRange(offset, MAX_MESSAGE_SIZE + offset), - Pigeon.MessageSource.WIFI_NAN, - peerHash.hashCode().toString(), - 0, - System.currentTimeMillis() - ) - - odidPayloadStreamHandler.send(payload?.toList() as Any) - } - @TargetApi(Build.VERSION_CODES.O) private val identityChangedListener: IdentityChangedListener = object : IdentityChangedListener() { @@ -122,8 +117,13 @@ class WifiNaNScanner ( } } + fun isWifiAwareSupported(): Boolean + { + return wifiAwareSupported; + } + @TargetApi(Build.VERSION_CODES.O) - fun startScan() { + private fun startScan() { if (!wifiAwareSupported) return if (wifiAwareManager!!.isAvailable) { @@ -136,13 +136,8 @@ class WifiNaNScanner ( } } - fun isWifiAwareSupported(): Boolean - { - return wifiAwareSupported; - } - @TargetApi(Build.VERSION_CODES.O) - fun stopScan() { + private fun stopScan() { if (!wifiAwareSupported) return if (wifiAwareManager != null && wifiAwareManager!!.isAvailable && wifiAwareSession != null) { @@ -150,27 +145,4 @@ class WifiNaNScanner ( wifiStateHandler.send(false) } } - - fun scan() { - if (!wifiScanEnabled) { - return - } - isScanning = true - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || - !context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)) { - Log.i(TAG, "WiFi Aware is not supported."); - wifiAwareSupported = false - return; - } - wifiAwareSupported = true - context.registerReceiver(myReceiver, IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED)) - startScan(); - } - - @RequiresApi(Build.VERSION_CODES.O) - fun cancel() { - if (!wifiAwareSupported) return - isScanning = false; - stopScan() - } } \ No newline at end of file diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt index 467fa58..3f0c128 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt @@ -13,28 +13,20 @@ import java.nio.ByteOrder import java.util.* class WifiScanner ( - private val odidPayloadStreamHandler: StreamHandler, + odidPayloadStreamHandler: StreamHandler, private val wifiStateHandler: StreamHandler, private val wifiManager: WifiManager?, private val context: Context -) { - companion object { - const val MAX_MESSAGE_SIZE = 25 - } - +) : ODIDScanner(odidPayloadStreamHandler) { + private val TAG: String = WifiScanner::class.java.getSimpleName() + private val CIDLen = 3 - private val driStartByteOffset = 4 private val DRICID = intArrayOf(0xFA, 0x0B, 0xBC) private val vendorTypeLen = 1 private val vendorTypeValue = 0x0D - private val TAG: String = WifiScanner::class.java.getSimpleName() private var scanSuccess = 0 private var scanFailed = 0 - private val wifiScanEnabled = true private val scanTimerInterval = 2 - private val payloadHandler: OdidPayloadHandler = OdidPayloadHandler() - var isScanning = false - private var countDownTimer: CountDownTimer? = null private val broadcastReceiver = object : BroadcastReceiver() { @@ -60,8 +52,54 @@ class WifiScanner ( } } + override fun scan() { + isScanning = true + wifiStateHandler.send(true) + context.registerReceiver(broadcastReceiver, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) + val ret = wifiManager!!.startScan() + if (ret) { + scanSuccess++ + } else { + scanFailed++ + } + } + + override fun cancel() { + isScanning = false; + wifiStateHandler.send(false) + if (countDownTimer != null) { + countDownTimer!!.cancel(); + } + } + + override fun onAdapterStateReceived() { + if (wifiManager == null) { + return + } + // wifi can be available even if it is turned of + if(wifiManager.isScanAlwaysAvailable()) + return + val rawState = wifiManager.getWifiState() + if (rawState == WifiManager.WIFI_STATE_DISABLED || rawState == WifiManager.WIFI_STATE_DISABLING) { + cancel() + } + } + + fun getAdapterState(): Int { + if (wifiManager == null) { + return 1 + } + // wifi can be available even if it is turned of + if(wifiManager.isScanAlwaysAvailable()) + return 3 + return when (wifiManager.getWifiState()) { + WifiManager.WIFI_STATE_ENABLED -> 3 + else -> 1 + } + } + @Throws(NoSuchFieldException::class, IllegalAccessException::class) - fun handleResult(scanResult: ScanResult) { + private fun handleResult(scanResult: ScanResult) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { // On earlier Android APIs, the information element field is hidden. // Use reflection to access it. @@ -73,86 +111,56 @@ class WifiScanner ( val valueId = element.javaClass.getField("id")[element] ?: continue val id = valueId as Int if (id == 221) { - val valueBytes = element.javaClass.getField("bytes")[element] ?: continue - val buf: ByteBuffer = - ByteBuffer.wrap(valueBytes as ByteArray).asReadOnlyBuffer() - receiveData(scanResult, buf) + val bytes = element.javaClass.getField("bytes")[element] ?: continue + receiveBeaconData(scanResult, bytes as ByteArray) } } } else { for (element in scanResult.informationElements) { if (element != null && element.id == 221) { - val buf: ByteBuffer = element.bytes - receiveData(scanResult, buf) + val bytes = ByteArray(element.bytes.remaining()) + element.bytes.get(bytes) + receiveBeaconData(scanResult, bytes) } } } } - fun receiveData(scanResult: ScanResult, buf: ByteBuffer) { - if (buf.remaining() < 30){ - return - } - val offset = 1 - val dri_CID = ByteArray(CIDLen) - var arr = ByteArray(buf.remaining()) - buf.get(dri_CID, 0, CIDLen) - - val vendorType = ByteArray(vendorTypeLen) - buf.get(vendorType, 0, vendorTypeLen) - - if ((dri_CID[0] and 0xFF.toByte()) == DRICID.get(0).toByte() - && ((dri_CID[1] and 0xFF.toByte()) == DRICID.get(1).toByte()) - && ((dri_CID[2] and 0xFF.toByte()) == DRICID.get(2).toByte()) - && vendorType[0] == vendorTypeValue.toByte() - ) - { - val payload = payloadHandler.getPayload( - arr.copyOfRange(offset, MAX_MESSAGE_SIZE + offset), + private fun receiveBeaconData(scanResult: ScanResult, bytes: ByteArray) { + if(checkDRICID(bytes)){ + receiveData( + offsetData(bytes, WIFI_BEACON_OFFSET), + scanResult.BSSID, Pigeon.MessageSource.WIFI_BEACON, - scanResult.BSSID, scanResult.level.toLong(), - System.currentTimeMillis() ) - - odidPayloadStreamHandler.send(payload?.toList() as Any) } } - - - fun cancel() { - if (!wifiScanEnabled) { - return; + private fun checkDRICID(bytes: ByteArray) : Boolean{ + val buf = ByteBuffer.wrap(bytes as ByteArray).asReadOnlyBuffer() + if (buf.remaining() < MAX_MESSAGE_SIZE + WIFI_BEACON_OFFSET){ + return false } - isScanning = false; - wifiStateHandler.send(false) - if (countDownTimer != null) { - countDownTimer!!.cancel(); - } - } + val dri_CID = ByteArray(CIDLen) + buf.get(dri_CID, 0, CIDLen) - fun scan() { - if (!wifiScanEnabled) { - return - } - isScanning = true - wifiStateHandler.send(true) - context.registerReceiver(broadcastReceiver, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) - val ret = wifiManager!!.startScan() - if (ret) { - scanSuccess++ - } else { - scanFailed++ - } + val vendorType = ByteArray(vendorTypeLen) + buf.get(vendorType, 0, vendorTypeLen) + + return (dri_CID[0] and 0xFF.toByte()) == DRICID.get(0).toByte() + && ((dri_CID[1] and 0xFF.toByte()) == DRICID.get(1).toByte()) + && ((dri_CID[2] and 0xFF.toByte()) == DRICID.get(2).toByte()) + && vendorType[0] == vendorTypeValue.toByte() } + // There are 2 ways to control WiFi scan: // Continuous scan: Calls startSCan() from scan completion callback // Periodic scan: countdown timer triggers startScan after expiry of the timer. // If phone is debug mode and scan throttling is off, scan is triggered from onReceive() callback. // But if scan throttling is turned on on the phone (default setting on the phone), then scan throttling kick in. // In case of throttling, startScan() fails. We need timer thread to periodically kick off scanning. - fun startCountDownTimer() { + private fun startCountDownTimer() { countDownTimer = object : CountDownTimer( Long.MAX_VALUE, (scanTimerInterval * 1000).toLong() @@ -165,32 +173,4 @@ class WifiScanner ( override fun onFinish() {} }.start() } - - val adapterStateReceiver: BroadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - if (wifiManager == null) { - return - } - // wifi can be available even if it is turned of - if(wifiManager.isScanAlwaysAvailable()) - return - val rawState = wifiManager.getWifiState() - if (rawState == WifiManager.WIFI_STATE_DISABLED || rawState == WifiManager.WIFI_STATE_DISABLING) { - cancel() - } - } - } - - fun getAdapterState(): Int { - if (wifiManager == null) { - return 1 - } - // wifi can be available even if it is turned of - if(wifiManager.isScanAlwaysAvailable()) - return 3 - return when (wifiManager.getWifiState()) { - WifiManager.WIFI_STATE_ENABLED -> 3 - else -> 1 - } - } } \ No newline at end of file From f1d1001fe70240d1dee954bf68ec9c9f9296669a Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Wed, 30 Aug 2023 15:32:30 +0200 Subject: [PATCH 05/11] feat: put back duplicate messages filtering --- lib/flutter_opendroneid.dart | 8 +- lib/models/message_container.dart | 149 +++++++++++++----------------- 2 files changed, 72 insertions(+), 85 deletions(-) diff --git a/lib/flutter_opendroneid.dart b/lib/flutter_opendroneid.dart index 664c5a5..45fb806 100644 --- a/lib/flutter_opendroneid.dart +++ b/lib/flutter_opendroneid.dart @@ -107,13 +107,17 @@ class FlutterOpenDroneId { // TODO: check for duplicate messages final message = parseODIDMessage(payload.rawData); if (message == null) return; - _storedPacks[payload.macAddress] = storedPack.update( + final updatedPack = storedPack.update( message: message, receivedTimestamp: payload.receivedTimestamp, rssi: payload.rssi, source: payload.source, ); - _packController.add(_storedPacks[payload.macAddress]!); + // update was refused if updatedPack is null + if (updatedPack != null) { + _storedPacks[payload.macAddress] = updatedPack; + _packController.add(updatedPack); + } } /// Checks all required Bluetooth permissions and throws diff --git a/lib/models/message_container.dart b/lib/models/message_container.dart index 483d34b..bec8d0a 100644 --- a/lib/models/message_container.dart +++ b/lib/models/message_container.dart @@ -3,6 +3,7 @@ import 'dart:ui'; import 'package:flutter_opendroneid/models/constants.dart'; import 'package:flutter_opendroneid/pigeon.dart' as pigeon; import 'package:dart_opendroneid/src/types.dart'; +import 'package:flutter_opendroneid/utils/compare_extension.dart'; class MessageContainer { final String macAddress; @@ -59,7 +60,7 @@ class MessageContainer { systemDataMessage: systemDataMessage ?? this.systemDataMessage, ); - MessageContainer update({ + MessageContainer? update({ required ODIDMessage message, required int receivedTimestamp, required pigeon.MessageSource source, @@ -69,99 +70,81 @@ class MessageContainer { final messages = (message as MessagePack).messages; var result = this; for (var packMessage in messages) { - result = result.update( + final update = result.update( message: packMessage, receivedTimestamp: receivedTimestamp, source: source, ); + if (update != null) result = update; } return result; } + // update pack only if new data differ from saved ones return switch (message.runtimeType) { - LocationMessage => copyWith( - locationMessage: message as LocationMessage, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), - source: source, - ), - BasicIDMessage => copyWith( - basicIdMessage: message as BasicIDMessage, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), - source: source, - ), - SelfIDMessage => copyWith( - selfIdMessage: message as SelfIDMessage, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), - source: source, - ), - OperatorIDMessage => copyWith( - operatorIdMessage: message as OperatorIDMessage, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), - source: source, - ), - AuthMessage => copyWith( - authenticationMessage: message as AuthMessage, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), - source: source, - ), - SystemMessage => copyWith( - systemDataMessage: message as SystemMessage, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), - source: source, - ), - _ => this + LocationMessage => locationMessage != null && + locationMessage!.containsEqualData(message as LocationMessage) + ? null + : copyWith( + locationMessage: message as LocationMessage, + lastMessageRssi: rssi, + lastUpdate: + DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), + BasicIDMessage => basicIdMessage != null && + basicIdMessage!.containsEqualData(message as BasicIDMessage) + ? null + : copyWith( + basicIdMessage: message as BasicIDMessage, + lastMessageRssi: rssi, + lastUpdate: + DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), + SelfIDMessage => selfIdMessage != null && + selfIdMessage!.containsEqualData(message as SelfIDMessage) + ? null + : copyWith( + selfIdMessage: message as SelfIDMessage, + lastMessageRssi: rssi, + lastUpdate: + DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), + OperatorIDMessage => operatorIdMessage != null && + operatorIdMessage!.containsEqualData(message as OperatorIDMessage) + ? null + : copyWith( + operatorIdMessage: message as OperatorIDMessage, + lastMessageRssi: rssi, + lastUpdate: + DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), + AuthMessage => authenticationMessage != null && + authenticationMessage!.containsEqualData(message as AuthMessage) + ? null + : copyWith( + authenticationMessage: message as AuthMessage, + lastMessageRssi: rssi, + lastUpdate: + DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), + SystemMessage => systemDataMessage != null && + systemDataMessage!.containsEqualData(message as SystemMessage) + ? null + : copyWith( + systemDataMessage: message as SystemMessage, + lastMessageRssi: rssi, + lastUpdate: + DateTime.fromMillisecondsSinceEpoch(receivedTimestamp), + source: source, + ), + _ => null }; } - MessageContainer updateWithOperatorId({ - required OperatorIDMessage message, - required int receivedTimestamp, - int? rssi, - }) { - return copyWith( - operatorIdMessage: message, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)); - } - - MessageContainer updateWithAuthentication({ - required AuthMessage message, - required int receivedTimestamp, - int? rssi, - }) { - return copyWith( - authenticationMessage: message, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)); - } - - MessageContainer updateWithSystemData({ - required SystemMessage message, - required int receivedTimestamp, - int? rssi, - }) { - return copyWith( - systemDataMessage: message, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)); - } - - MessageContainer updateWithSelfId({ - required SelfIDMessage message, - required int receivedTimestamp, - int? rssi, - }) { - return copyWith( - selfIdMessage: message, - lastMessageRssi: rssi, - lastUpdate: DateTime.fromMillisecondsSinceEpoch(receivedTimestamp)); - } - pigeon.MessageSource getPackSource() => source; /// Calculates a color from mac address, that uniquely identifies the device From 7b43b5058d013ffaa67b369662e72e39114e215b Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Wed, 30 Aug 2023 18:38:03 +0200 Subject: [PATCH 06/11] feat: add conversions of message values to strings --- lib/utils/conversions.dart | 114 +++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/lib/utils/conversions.dart b/lib/utils/conversions.dart index ddb5d22..702c782 100644 --- a/lib/utils/conversions.dart +++ b/lib/utils/conversions.dart @@ -1,4 +1,6 @@ import 'package:dart_opendroneid/src/types.dart'; +import 'package:dart_opendroneid/src/types/uas_id.dart'; +import 'package:dart_opendroneid/src/types/ua_classification.dart'; /// Conversions extensions @@ -36,6 +38,69 @@ const Map _speedAccuracyConversionMap = { SpeedAccuracy.meterPerSecond_0_3: 0.3, }; +const Map _idTypeConversionMap = { + IDType.none: 'None', + IDType.serialNumber: 'Serial Number', + IDType.CAARegistrationID: 'CAA Registration ID', + IDType.UTMAssignedID: 'UTM Assigned ID', + IDType.specificSessionID: 'Specific Session ID', +}; + +const Map _uaTypeConversionMap = { + UAType.none: 'None', + UAType.aeroplane: 'Aeroplane', + UAType.helicopterOrMultirotor: 'Helicopter Or Multirotor', + UAType.gyroplane: 'Gyroplane', + UAType.hybridLift: 'Hybrid Lift', + UAType.ornithopter: 'Ornithopter', + UAType.glider: 'Glider', + UAType.kite: 'Kite', + UAType.freeBalloon: 'Free Balloon', + UAType.captiveBalloon: 'Captive Balloon', + UAType.airship: 'Airship', + UAType.freeFallParachute: 'Free Fall Parachute', + UAType.rocket: 'Rocket', + UAType.tetheredPoweredAircraft: 'Tethered Powered Aircraft', + UAType.groundObstacle: 'Ground Obstacle', + UAType.other: 'Other', +}; + +const Map _uaClassEuropeConversionMap = { + UAClassEurope.undefined: 'Undefined', + UAClassEurope.EUClass_0: 'EU Class 0', + UAClassEurope.EUClass_1: 'EU Class 1', + UAClassEurope.EUClass_2: 'EU Class 2', + UAClassEurope.EUClass_3: 'EU Class 3', + UAClassEurope.EUClass_4: 'EU Class 4', + UAClassEurope.EUClass_5: 'EU Class 5', + UAClassEurope.EUClass_6: 'EU Class 6', +}; + +const Map _uaCategoryEuropeConversionMap = { + UACategoryEurope.undefined: 'Undefined', + UACategoryEurope.EUOpen: 'EU Open', + UACategoryEurope.EUSpecific: 'EU Specific', + UACategoryEurope.EUCertified: 'EU Certified', +}; + +const Map _operatorLocTypeConversionMap = { + OperatorLocationType.fixed: 'Fixed', + OperatorLocationType.takeOff: 'Take Off', + OperatorLocationType.dynamic: 'Dynamic', +}; + +const Map _heightTypeConversionMap = { + HeightType.aboveGroundLevel: 'Above Ground Level', + HeightType.aboveTakeoff: 'Above Take Off', +}; + +const Map _operationalStatusConversionMap = { + OperationalStatus.ground: 'Grounded', + OperationalStatus.airborne: 'Airborne', + OperationalStatus.emergency: 'Emergency', + OperationalStatus.none: 'Unknown', +}; + extension HorizontalAccuracyConversion on HorizontalAccuracy { double? toMeters() => _horizontalAccuracyConversionMap[this]; } @@ -47,3 +112,52 @@ extension VerticalAccuracyConversion on VerticalAccuracy { extension SpeedAccuracyConversion on SpeedAccuracy { double? toMetersPerSecond() => _speedAccuracyConversionMap[this]; } + +extension UASIDConversion on UASID { + String? asString() => switch (this.runtimeType) { + SerialNumber => (this as SerialNumber).serialNumber, + IDNone() => null, + UTMAssignedID => (this as UTMAssignedID).id.toString(), + SpecificSessionID => (this as SpecificSessionID).id.toString(), + CAARegistrationID => (this as CAARegistrationID).registrationID, + _ => null, + }; +} + +extension IDTypeConversion on IDType { + String? asString() => _idTypeConversionMap[this]; +} + +extension UATypeConversion on UAType { + String? asString() => _uaTypeConversionMap[this]; +} + +extension UAClassificationConversion on UAClassification { + bool isEuropeClassification() => this is UAClassificationEurope; + String? uaClassEuropeString() => isEuropeClassification() + ? (this as UAClassificationEurope).uaClassEurope.asString() + : null; + String? uaCategoryEuropeString() => isEuropeClassification() + ? (this as UAClassificationEurope).uaCategoryEurope.asString() + : null; +} + +extension UACategoryEuropeConversion on UACategoryEurope { + String? asString() => _uaCategoryEuropeConversionMap[this]; +} + +extension UAClassEuropeConversion on UAClassEurope { + String? asString() => _uaClassEuropeConversionMap[this]; +} + +extension OperatorLocationTypeConversion on OperatorLocationType { + String? asString() => _operatorLocTypeConversionMap[this]; +} + +extension HeightTypeConversion on HeightType { + String? asString() => _heightTypeConversionMap[this]; +} + +extension OperationalStatusConversion on OperationalStatus { + String? asString() => _operationalStatusConversionMap[this]; +} From 85e83af2ec35be1d5d255044aca3cffd66c9c9ef Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Thu, 31 Aug 2023 15:46:23 +0200 Subject: [PATCH 07/11] chore: clean and remove unused code DT-2604 --- .../scanner/BluetoothScanner.kt | 68 ++++++++-------- .../scanner/ODIDScanner.kt | 8 +- .../scanner/WifiNaNScanner.kt | 79 +++++++++---------- .../scanner/WifiScanner.kt | 22 +++--- lib/flutter_opendroneid.dart | 7 +- lib/models/message_container.dart | 30 +------ 6 files changed, 96 insertions(+), 118 deletions(-) diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt index 2af9b43..af3622e 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt @@ -19,21 +19,51 @@ class BluetoothScanner( private val bluetoothStateHandler: StreamHandler, ) : ODIDScanner(odidPayloadStreamHandler) { private val TAG: String = BluetoothScanner::class.java.getSimpleName() + private val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() + + private var scanMode = ScanSettings.SCAN_MODE_LOW_LATENCY - var scanMode = ScanSettings.SCAN_MODE_LOW_LATENCY - val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() - /// OpenDroneID Bluetooth beacons identify themselves by setting the GAP AD Type to /// "Service Data - 16-bit UUID" and the value to 0xFFFA for ASTM International, ASTM Remote ID. /// https://www.bluetooth.com/specifications/assigned-numbers/ -> "Generic Access Profile" /// https://www.bluetooth.com/specifications/assigned-numbers/ -> "16-bit UUIDs" /// Vol 3, Part B, Section 2.5.1 of the Bluetooth 5.1 Core Specification /// The AD Application Code is set to 0x0D = Open Drone ID. - private val serviceUuid = UUID.fromString("0000fffa-0000-1000-8000-00805f9b34fb") private val serviceParcelUuid = ParcelUuid(serviceUuid) private val odidAdCode = byteArrayOf(0x0D.toByte()) + /// Callback for receiving data: read data from ScanRecord and call receiveData + private val scanCallback: ScanCallback = object : ScanCallback() { + override fun onScanResult(callbackType: Int, result: ScanResult) { + val scanRecord: ScanRecord = result.scanRecord ?: return + val bytes = scanRecord.bytes ?: return + var source = Pigeon.MessageSource.BLUETOOTH_LEGACY; + + if (bytes.size < BT_OFFSET + MAX_MESSAGE_SIZE) return + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && bluetoothAdapter.isLeCodedPhySupported()) { + if (result.getPrimaryPhy() == BluetoothDevice.PHY_LE_CODED) + source = Pigeon.MessageSource.BLUETOOTH_LONG_RANGE; + } + + receiveData( + offsetData(bytes, BT_OFFSET), + result.device.address, + source, + result.rssi.toLong(), + ) + } + + override fun onBatchScanResults(results: List?) { + Log.e(TAG, "Got batch scan results, unable to handle") + } + + override fun onScanFailed(errorCode: Int) { + Log.e(TAG, "Scan failed: $errorCode") + } + } + @RequiresApi(Build.VERSION_CODES.O) override fun scan() { if (!bluetoothAdapter.isEnabled) return @@ -112,36 +142,6 @@ class BluetoothScanner( } } - private val scanCallback: ScanCallback = object : ScanCallback() { - override fun onScanResult(callbackType: Int, result: ScanResult) { - val scanRecord: ScanRecord = result.scanRecord ?: return - val bytes = scanRecord.bytes ?: return - var source = Pigeon.MessageSource.BLUETOOTH_LEGACY; - - if (bytes.size < BT_OFFSET + MAX_MESSAGE_SIZE) return - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && bluetoothAdapter.isLeCodedPhySupported()) { - if (result.getPrimaryPhy() == BluetoothDevice.PHY_LE_CODED) - source = Pigeon.MessageSource.BLUETOOTH_LONG_RANGE; - } - - receiveData( - offsetData(bytes, BT_OFFSET), - result.device.address, - source, - result.rssi.toLong(), - ) - } - - override fun onBatchScanResults(results: List?) { - Log.e(TAG, "Got batch scan results, unable to handle") - } - - override fun onScanFailed(errorCode: Int) { - Log.e(TAG, "Scan failed: $errorCode") - } - } - private fun logAdapterInfo(bluetoothAdapter: BluetoothAdapter) { Log.i(TAG, "bluetooth LE extended supported: " + bluetoothAdapter.isLeExtendedAdvertisingSupported.toString()) Log.i(TAG, "bluetooth LE coded phy supported: " + bluetoothAdapter.isLeCodedPhySupported.toString()) diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt index 8d7a97e..5ce4401 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt @@ -5,9 +5,11 @@ import android.content.Context import android.content.Intent /// Contains common functinality for ODID scanners -/// Creates [ODIDPayload] instances implementin Pigeon PayloadAPI +/// Derived scanners should use receiveData method that takes raw data and metadata +/// and sends it to stream +/// Creates [ODIDPayload] instances implementing Pigeon PayloadAPI abstract class ODIDScanner( - val odidPayloadStreamHandler: StreamHandler + private val odidPayloadStreamHandler: StreamHandler ) : Pigeon.PayloadApi { companion object { @@ -58,6 +60,6 @@ abstract class ODIDScanner( odidPayloadStreamHandler.send(payload?.toList() as Any) } - /// returs [ByteArray] without first offset elements + /// returns ByteArray without first offset elements inline fun offsetData(data: ByteArray, offset: Int) : ByteArray = data.copyOfRange(offset, data.size) } \ No newline at end of file diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt index 6a04a21..34561c9 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt @@ -33,11 +33,47 @@ class WifiNaNScanner ( private val context: Context ) : ODIDScanner(odidPayloadStreamHandler) { private val TAG: String = WifiNaNScanner::class.java.getSimpleName() - - private var wifiAwareSession: WifiAwareSession? = null private val wifiScanEnabled = true private var wifiAwareSupported = true + private var wifiAwareSession: WifiAwareSession? = null + + // callback for Wi-Fi Aware session advertisement + private val attachCallback: AttachCallback = @RequiresApi(Build.VERSION_CODES.O) + object : AttachCallback() { + override fun onAttached(session: WifiAwareSession) { + if (!wifiAwareSupported) return + wifiAwareSession = session + val config = SubscribeConfig.Builder() + .setServiceName("org.opendroneid.remoteid") + .build() + wifiAwareSession!!.subscribe(config, object : DiscoverySessionCallback() { + override fun onServiceDiscovered( + peerHandle: PeerHandle?, + serviceSpecificInfo: ByteArray?, + matchFilter: MutableList? + ) { + if (serviceSpecificInfo != null) + receiveData( + offsetData(serviceSpecificInfo, WIFI_NAN_OFFSET), + peerHandle.hashCode().toString(), + Pigeon.MessageSource.WIFI_NAN, + ) + } + }, null) + } + } + + @TargetApi(Build.VERSION_CODES.O) + private val identityChangedListener: IdentityChangedListener = + object : IdentityChangedListener() { + override fun onIdentityChanged(mac: ByteArray) { + val macAddress = arrayOfNulls(mac.size) + var i = 0 + for (b in mac) macAddress[i++] = b + } + } + init{ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)) { @@ -51,9 +87,6 @@ class WifiNaNScanner ( } override fun scan() { - if (!wifiScanEnabled) { - return - } isScanning = true if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)) { @@ -81,42 +114,6 @@ class WifiNaNScanner ( } } - private val attachCallback: AttachCallback = @RequiresApi(Build.VERSION_CODES.O) - object : AttachCallback() { - override fun onAttached(session: WifiAwareSession) { - if (!wifiAwareSupported) return - wifiAwareSession = session - val config = SubscribeConfig.Builder() - .setServiceName("org.opendroneid.remoteid") - .build() - wifiAwareSession!!.subscribe(config, object : DiscoverySessionCallback() { - override fun onServiceDiscovered( - peerHandle: PeerHandle?, - serviceSpecificInfo: ByteArray?, - matchFilter: MutableList? - ) { - if (serviceSpecificInfo != null) - receiveData( - offsetData(serviceSpecificInfo, WIFI_NAN_OFFSET), - peerHandle.hashCode().toString(), - Pigeon.MessageSource.WIFI_NAN, - ) - } - }, null) - } - - } - - @TargetApi(Build.VERSION_CODES.O) - private val identityChangedListener: IdentityChangedListener = - object : IdentityChangedListener() { - override fun onIdentityChanged(mac: ByteArray) { - val macAddress = arrayOfNulls(mac.size) - var i = 0 - for (b in mac) macAddress[i++] = b - } - } - fun isWifiAwareSupported(): Boolean { return wifiAwareSupported; diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt index 3f0c128..8d38044 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt @@ -12,6 +12,13 @@ import android.os.CountDownTimer import java.nio.ByteOrder import java.util.* +/// Wi-Fi Beacons Scanner +/// There are 2 ways to control WiFi scan: +/// Continuous scan: Calls startScan() from scan completion callback +/// Periodic scan: countdown timer triggers startScan after expiry of the timer. +/// If phone is debug mode and scan throttling is off, scan is triggered from onReceive() callback. +/// But if scan throttling is turned on on the phone (default setting on the phone), then scan throttling kick in. +/// In case of throttling, startScan() fails. We need timer thread to periodically kick off scanning. class WifiScanner ( odidPayloadStreamHandler: StreamHandler, private val wifiStateHandler: StreamHandler, @@ -19,7 +26,6 @@ class WifiScanner ( private val context: Context ) : ODIDScanner(odidPayloadStreamHandler) { private val TAG: String = WifiScanner::class.java.getSimpleName() - private val CIDLen = 3 private val DRICID = intArrayOf(0xFA, 0x0B, 0xBC) private val vendorTypeLen = 1 @@ -27,8 +33,10 @@ class WifiScanner ( private var scanSuccess = 0 private var scanFailed = 0 private val scanTimerInterval = 2 + private var countDownTimer: CountDownTimer? = null + // callback for receiving Wi-Fi scan results private val broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(contxt: Context?, intent: Intent?) { if (wifiManager == null) { @@ -47,7 +55,8 @@ class WifiScanner ( e.printStackTrace() } } - scan() + if(isScanning) + scan() } } } @@ -154,12 +163,6 @@ class WifiScanner ( && vendorType[0] == vendorTypeValue.toByte() } - // There are 2 ways to control WiFi scan: - // Continuous scan: Calls startSCan() from scan completion callback - // Periodic scan: countdown timer triggers startScan after expiry of the timer. - // If phone is debug mode and scan throttling is off, scan is triggered from onReceive() callback. - // But if scan throttling is turned on on the phone (default setting on the phone), then scan throttling kick in. - // In case of throttling, startScan() fails. We need timer thread to periodically kick off scanning. private fun startCountDownTimer() { countDownTimer = object : CountDownTimer( Long.MAX_VALUE, @@ -167,7 +170,8 @@ class WifiScanner ( ) { // This is called after every ScanTimerInterval sec. override fun onTick(millisUntilFinished: Long) { - scan() + if(isScanning) + scan() } override fun onFinish() {} diff --git a/lib/flutter_opendroneid.dart b/lib/flutter_opendroneid.dart index 45fb806..8cc9885 100644 --- a/lib/flutter_opendroneid.dart +++ b/lib/flutter_opendroneid.dart @@ -21,7 +21,7 @@ class FlutterOpenDroneId { static const _wifiStateEventChannel = const EventChannel('flutter_odid_wifi_state'); - static StreamSubscription? _rawDataSubscription; + static StreamSubscription? _odidDataSubscription; static final _packController = StreamController.broadcast(); static Map _storedPacks = {}; @@ -55,7 +55,7 @@ class FlutterOpenDroneId { /// To further receive data, listen to /// streams. static Future startScan(UsedTechnologies usedTechnologies) async { - _rawDataSubscription = odidPayloadEventChannel + _odidDataSubscription = odidPayloadEventChannel .receiveBroadcastStream() .listen((payload) => _updatePacks(pigeon.ODIDPayload.decode(payload))); @@ -75,7 +75,7 @@ class FlutterOpenDroneId { static Future stopScan() async { if (await _api.isScanningBluetooth()) await _api.stopScanBluetooth(); if (await _api.isScanningWifi()) await _api.stopScanWifi(); - _rawDataSubscription?.cancel(); + _odidDataSubscription?.cancel(); } static Future setBtScanPriority(pigeon.ScanPriority priority) async { @@ -104,7 +104,6 @@ class FlutterOpenDroneId { lastUpdate: DateTime.fromMillisecondsSinceEpoch(payload.receivedTimestamp), ); - // TODO: check for duplicate messages final message = parseODIDMessage(payload.rawData); if (message == null) return; final updatedPack = storedPack.update( diff --git a/lib/models/message_container.dart b/lib/models/message_container.dart index bec8d0a..7b8e357 100644 --- a/lib/models/message_container.dart +++ b/lib/models/message_container.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:flutter_opendroneid/models/constants.dart'; import 'package:flutter_opendroneid/pigeon.dart' as pigeon; import 'package:dart_opendroneid/src/types.dart'; @@ -31,9 +29,6 @@ class MessageContainer { this.systemDataMessage, }); - static const colorMax = 120; - static const colorOffset = 90; - MessageContainer copyWith({ String? macAddress, int? lastMessageRssi, @@ -60,6 +55,9 @@ class MessageContainer { systemDataMessage: systemDataMessage ?? this.systemDataMessage, ); + /// Returns new MessageContainer updated with message. + /// Null is returned if update is refused, because it contains duplicate or + /// corrupted data. MessageContainer? update({ required ODIDMessage message, required int receivedTimestamp, @@ -147,28 +145,6 @@ class MessageContainer { pigeon.MessageSource getPackSource() => source; - /// Calculates a color from mac address, that uniquely identifies the device - Color getPackColor() { - final len = macAddress.length; - return Color.fromARGB( - locationMessage?.status != OperationalStatus.airborne ? 80 : 255, - colorOffset + - 32 + - macAddress - .substring(0, len ~/ 2) - .codeUnits - .reduce((sum, e) => sum + e) % - (colorMax - 32), - colorOffset + - macAddress.codeUnits.reduce((sum, e) => (sum * e) % colorMax), - colorOffset + - macAddress - .substring(len ~/ 2) - .codeUnits - .fold(255, (sum, e) => sum - e % colorMax), - ); - } - bool operatorIDSet() { return operatorIdMessage != null && operatorIdMessage!.operatorID != OPERATOR_ID_NOT_SET; From 2288dd17d4f8be7cd79a2760752127310eaaec4f Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Fri, 1 Sep 2023 17:54:34 +0200 Subject: [PATCH 08/11] chore: use released version of dart-opendroneid --- pubspec.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 07da811..cc76202 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,10 +12,7 @@ dependencies: sdk: flutter permission_handler: ^10.2.0 device_info_plus: ^8.0.0 -# change to path to your clone of dart-opendroneid -# TODO: change when dart_opendroneid is released - dart_opendroneid: - path: ../../dart-opendroneid/dart-opendroneid + dart_opendroneid: ^0.1.0 dev_dependencies: pigeon: ^10.1.6 From 8da4ea2aaff5b75845a63066e809719553a0442a Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Sun, 3 Sep 2023 20:42:55 +0200 Subject: [PATCH 09/11] feat: shorted BLE advertisements to max 31 bytes --- .../flutter_opendroneid/scanner/BluetoothScanner.kt | 6 ++++-- .../cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt index af3622e..6ee3b00 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt @@ -46,9 +46,11 @@ class BluetoothScanner( if (result.getPrimaryPhy() == BluetoothDevice.PHY_LE_CODED) source = Pigeon.MessageSource.BLUETOOTH_LONG_RANGE; } - + // if using BLE, max size of data is MAX_BLE_ADV_SIZE + // if using BT5, data can be longer up to 256 bytes + val isBLE = maxAdvDataLen() <= MAX_BLE_ADV_SIZE receiveData( - offsetData(bytes, BT_OFFSET), + if(isBLE) getDataFromIndex(bytes, BT_OFFSET, MAX_BLE_ADV_SIZE) else offsetData(bytes, BT_OFFSET), result.device.address, source, result.rssi.toLong(), diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt index 5ce4401..8f776b6 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt @@ -15,6 +15,7 @@ abstract class ODIDScanner( companion object { const val MAX_MESSAGE_SIZE = 25 const val BT_OFFSET = 6 + const val MAX_BLE_ADV_SIZE = 31 const val WIFI_BEACON_OFFSET = 5 const val WIFI_NAN_OFFSET = 1 } @@ -62,4 +63,7 @@ abstract class ODIDScanner( /// returns ByteArray without first offset elements inline fun offsetData(data: ByteArray, offset: Int) : ByteArray = data.copyOfRange(offset, data.size) + + /// returns ByteArray with bytes from start to end + inline fun getDataFromIndex(data: ByteArray, start: Int, end: Int) : ByteArray = data.copyOfRange(start, end) } \ No newline at end of file From cdacbaf96f62527513373036fccd952e4ff011d0 Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Mon, 4 Sep 2023 12:13:40 +0200 Subject: [PATCH 10/11] chore: update readme --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e99cbe..3de53e6 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,15 @@ A flutter plugin for reading Wi-Fi and Bluetooth Remote ID advertisements using native Android and iOS platform-specific implementation. The format of data is defined in the [ASTM F3411](https://www.astm.org/f3411-22a.html) Remote ID and the [ASD-STAN prEN 4709-002](http://asd-stan.org/downloads/asd-stan-pren-4709-002-p1/) Direct Remote ID specifications. +The platform-specific implementation reads raw message bytes from Wi-Fi and Bluetooth Remote ID advertisements. Then the raw payload with metadata is passed using event channels to the Dart side. Raw data are parsed to Remote ID messages using [Dart-opendroneid library](https://github.com/dronetag/dart-opendroneid). + +[The pigeon library](https://pub.dev/packages/pigeon) is used to define the messaging protocol between the platform host and Flutter client. The messaging protocol is defined in [schema.dart](pigeon/schema.dart). + The architecture of native code is inspired by [OpenDroneID Android receiver application](https://github.com/opendroneid/receiver-android). ## Pre-requisities -- Flutter 3.0.5 or newer +- Flutter 3.10.0 or newer ## Getting Started From cb59744eb76862ce4bae3a2a8671d6d73b9c251e Mon Sep 17 00:00:00 2001 From: Matej Glejtek Date: Mon, 11 Sep 2023 13:36:23 +0200 Subject: [PATCH 11/11] refactor: rename method to build payload, refactor MessageContainer use getters in message container, add comments DT-2604 --- .../dronetag/flutter_opendroneid/Pigeon.java | 6 +-- .../scanner/BluetoothScanner.kt | 6 +++ .../scanner/ODIDScanner.kt | 10 ++-- .../scanner/WifiNaNScanner.kt | 5 ++ .../scanner/WifiScanner.kt | 5 ++ ios/Classes/Scanner/BluetoothScanner.swift | 4 +- ios/Classes/pigeon.h | 2 +- ios/Classes/pigeon.m | 6 +-- lib/models/message_container.dart | 52 +++++++++---------- lib/pigeon.dart | 4 +- pigeon/schema.dart | 2 +- 11 files changed, 57 insertions(+), 45 deletions(-) diff --git a/android/src/main/java/cz/dronetag/flutter_opendroneid/Pigeon.java b/android/src/main/java/cz/dronetag/flutter_opendroneid/Pigeon.java index 7dd778f..3d0b020 100644 --- a/android/src/main/java/cz/dronetag/flutter_opendroneid/Pigeon.java +++ b/android/src/main/java/cz/dronetag/flutter_opendroneid/Pigeon.java @@ -658,7 +658,7 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { public interface PayloadApi { @NonNull - ODIDPayload getPayload(@NonNull byte[] rawData, @NonNull MessageSource source, @NonNull String macAddress, @NonNull Long rssi, @NonNull Long receivedTimestamp); + ODIDPayload buildPayload(@NonNull byte[] rawData, @NonNull MessageSource source, @NonNull String macAddress, @NonNull Long rssi, @NonNull Long receivedTimestamp); /** The codec used by PayloadApi. */ static @NonNull MessageCodec getCodec() { @@ -669,7 +669,7 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable PayloadApi { BasicMessageChannel channel = new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.PayloadApi.getPayload", getCodec()); + binaryMessenger, "dev.flutter.pigeon.flutter_opendroneid.PayloadApi.buildPayload", getCodec()); if (api != null) { channel.setMessageHandler( (message, reply) -> { @@ -681,7 +681,7 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable PayloadApi Number rssiArg = (Number) args.get(3); Number receivedTimestampArg = (Number) args.get(4); try { - ODIDPayload output = api.getPayload(rawDataArg, sourceArg, macAddressArg, (rssiArg == null) ? null : rssiArg.longValue(), (receivedTimestampArg == null) ? null : receivedTimestampArg.longValue()); + ODIDPayload output = api.buildPayload(rawDataArg, sourceArg, macAddressArg, (rssiArg == null) ? null : rssiArg.longValue(), (receivedTimestampArg == null) ? null : receivedTimestampArg.longValue()); wrapped.add(0, output); } catch (Throwable exception) { diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt index 6ee3b00..11f3665 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/BluetoothScanner.kt @@ -18,6 +18,12 @@ class BluetoothScanner( odidPayloadStreamHandler: StreamHandler, private val bluetoothStateHandler: StreamHandler, ) : ODIDScanner(odidPayloadStreamHandler) { + + companion object { + const val BT_OFFSET = 6 + const val MAX_BLE_ADV_SIZE = 31 + } + private val TAG: String = BluetoothScanner::class.java.getSimpleName() private val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt index 8f776b6..b7d5dbe 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/ODIDScanner.kt @@ -4,7 +4,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -/// Contains common functinality for ODID scanners +/// Contains common functinality for ODID scanners. /// Derived scanners should use receiveData method that takes raw data and metadata /// and sends it to stream /// Creates [ODIDPayload] instances implementing Pigeon PayloadAPI @@ -14,10 +14,6 @@ abstract class ODIDScanner( companion object { const val MAX_MESSAGE_SIZE = 25 - const val BT_OFFSET = 6 - const val MAX_BLE_ADV_SIZE = 31 - const val WIFI_BEACON_OFFSET = 5 - const val WIFI_NAN_OFFSET = 1 } var isScanning = false @@ -38,7 +34,7 @@ abstract class ODIDScanner( abstract fun onAdapterStateReceived() - override fun getPayload(rawData: ByteArray, source: Pigeon.MessageSource, macAddress: String, rssi: Long, receivedTimestamp: Long): Pigeon.ODIDPayload { + override fun buildPayload(rawData: ByteArray, source: Pigeon.MessageSource, macAddress: String, rssi: Long, receivedTimestamp: Long): Pigeon.ODIDPayload { val builder = Pigeon.ODIDPayload.Builder() builder.setRawData(rawData) @@ -54,7 +50,7 @@ abstract class ODIDScanner( fun receiveData( data: ByteArray, macAddress: String, source: Pigeon.MessageSource, rssi: Long = 0 ) { - val payload = getPayload( + val payload = buildPayload( data, source, macAddress, rssi, System.currentTimeMillis() ) diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt index 34561c9..ea85e04 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiNaNScanner.kt @@ -32,6 +32,11 @@ class WifiNaNScanner ( private val wifiAwareManager: WifiAwareManager?, private val context: Context ) : ODIDScanner(odidPayloadStreamHandler) { + + companion object { + const val WIFI_NAN_OFFSET = 1 + } + private val TAG: String = WifiNaNScanner::class.java.getSimpleName() private val wifiScanEnabled = true private var wifiAwareSupported = true diff --git a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt index 8d38044..d13bf8e 100644 --- a/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt +++ b/android/src/main/kotlin/cz/dronetag/flutter_opendroneid/scanner/WifiScanner.kt @@ -25,6 +25,11 @@ class WifiScanner ( private val wifiManager: WifiManager?, private val context: Context ) : ODIDScanner(odidPayloadStreamHandler) { + + companion object { + const val WIFI_BEACON_OFFSET = 5 + } + private val TAG: String = WifiScanner::class.java.getSimpleName() private val CIDLen = 3 private val DRICID = intArrayOf(0xFA, 0x0B, 0xBC) diff --git a/ios/Classes/Scanner/BluetoothScanner.swift b/ios/Classes/Scanner/BluetoothScanner.swift index 39f6f0a..c392f2e 100644 --- a/ios/Classes/Scanner/BluetoothScanner.swift +++ b/ios/Classes/Scanner/BluetoothScanner.swift @@ -95,7 +95,7 @@ class BluetoothScanner: NSObject, CBCentralManagerDelegate, DTGPayloadApi { ) } - func getPayloadRawData(_ rawData: FlutterStandardTypedData, source: DTGMessageSource, macAddress: String, rssi: NSNumber, receivedTimestamp: NSNumber, error: AutoreleasingUnsafeMutablePointer) -> DTGODIDPayload? { + func buildPayloadRawData(_ rawData: FlutterStandardTypedData, source: DTGMessageSource, macAddress: String, rssi: NSNumber, receivedTimestamp: NSNumber, error: AutoreleasingUnsafeMutablePointer) -> DTGODIDPayload? { return DTGODIDPayload.make(withRawData: rawData, receivedTimestamp: receivedTimestamp, macAddress: macAddress, rssi: rssi, source: source) } @@ -106,7 +106,7 @@ class BluetoothScanner: NSObject, CBCentralManagerDelegate, DTGPayloadApi { } var err: FlutterError? let systimestamp = Int(Date().timeIntervalSince1970 * 1000) - let payload = getPayloadRawData(data, source: DTGMessageSource.bluetoothLegacy, macAddress: peripheral.identifier.uuidString, rssi: RSSI.intValue as NSNumber, receivedTimestamp: systimestamp as NSNumber, error: &err) + let payload = buildPayloadRawData(data, source: DTGMessageSource.bluetoothLegacy, macAddress: peripheral.identifier.uuidString, rssi: RSSI.intValue as NSNumber, receivedTimestamp: systimestamp as NSNumber, error: &err) odidPayloadStreamHandler.send(payload!.toList() as Any) } diff --git a/ios/Classes/pigeon.h b/ios/Classes/pigeon.h index 9165fa6..6cfb743 100644 --- a/ios/Classes/pigeon.h +++ b/ios/Classes/pigeon.h @@ -87,7 +87,7 @@ NSObject *DTGPayloadApiGetCodec(void); @protocol DTGPayloadApi /// @return `nil` only when `error != nil`. -- (nullable DTGODIDPayload *)getPayloadRawData:(FlutterStandardTypedData *)rawData source:(DTGMessageSource)source macAddress:(NSString *)macAddress rssi:(NSNumber *)rssi receivedTimestamp:(NSNumber *)receivedTimestamp error:(FlutterError *_Nullable *_Nonnull)error; +- (nullable DTGODIDPayload *)buildPayloadRawData:(FlutterStandardTypedData *)rawData source:(DTGMessageSource)source macAddress:(NSString *)macAddress rssi:(NSNumber *)rssi receivedTimestamp:(NSNumber *)receivedTimestamp error:(FlutterError *_Nullable *_Nonnull)error; @end extern void DTGPayloadApiSetup(id binaryMessenger, NSObject *_Nullable api); diff --git a/ios/Classes/pigeon.m b/ios/Classes/pigeon.m index 1fb85a7..f7350ff 100644 --- a/ios/Classes/pigeon.m +++ b/ios/Classes/pigeon.m @@ -337,11 +337,11 @@ void DTGPayloadApiSetup(id binaryMessenger, NSObject binaryMessenger, NSObject source; + pigeon.MessageSource get packSource => source; - bool operatorIDSet() { - return operatorIdMessage != null && - operatorIdMessage!.operatorID != OPERATOR_ID_NOT_SET; - } + bool get operatorIDSet => + operatorIdMessage != null && + operatorIdMessage!.operatorID != OPERATOR_ID_NOT_SET; - bool operatorIDValid() { + bool get operatorIDValid { final validCharacters = RegExp(r'^[a-zA-Z0-9]+$'); return operatorIdMessage != null && operatorIdMessage!.operatorID.length == 16 && validCharacters.hasMatch(operatorIdMessage!.operatorID); } - bool systemDataValid() { - return systemDataMessage != null && - systemDataMessage?.operatorLocation != null && - systemDataMessage!.operatorLocation!.latitude != INV_LAT && - systemDataMessage?.operatorLocation!.longitude != INV_LON && - systemDataMessage!.operatorLocation!.latitude <= MAX_LAT && - systemDataMessage!.operatorLocation!.latitude >= MIN_LAT && - systemDataMessage!.operatorLocation!.longitude <= MAX_LON && - systemDataMessage!.operatorLocation!.longitude >= MIN_LON; - } + bool get systemDataValid => + systemDataMessage != null && + systemDataMessage?.operatorLocation != null && + systemDataMessage!.operatorLocation!.latitude != INV_LAT && + systemDataMessage?.operatorLocation!.longitude != INV_LON && + systemDataMessage!.operatorLocation!.latitude <= MAX_LAT && + systemDataMessage!.operatorLocation!.latitude >= MIN_LAT && + systemDataMessage!.operatorLocation!.longitude <= MAX_LON && + systemDataMessage!.operatorLocation!.longitude >= MIN_LON; - bool locationValid() { - return locationMessage != null && - locationMessage?.location != null && - locationMessage!.location!.latitude != INV_LAT && - locationMessage!.location!.longitude != INV_LON && - locationMessage!.location!.latitude <= MAX_LAT && - locationMessage!.location!.longitude <= MAX_LON && - locationMessage!.location!.latitude >= MIN_LAT && - locationMessage!.location!.longitude >= MIN_LON; - } + bool get locationValid => + locationMessage != null && + locationMessage?.location != null && + locationMessage!.location!.latitude != INV_LAT && + locationMessage!.location!.longitude != INV_LON && + locationMessage!.location!.latitude <= MAX_LAT && + locationMessage!.location!.longitude <= MAX_LON && + locationMessage!.location!.latitude >= MIN_LAT && + locationMessage!.location!.longitude >= MIN_LON; } diff --git a/lib/pigeon.dart b/lib/pigeon.dart index fb640c3..05bb9b7 100644 --- a/lib/pigeon.dart +++ b/lib/pigeon.dart @@ -426,9 +426,9 @@ class PayloadApi { static const MessageCodec codec = _PayloadApiCodec(); - Future getPayload(Uint8List arg_rawData, MessageSource arg_source, String arg_macAddress, int arg_rssi, int arg_receivedTimestamp) async { + Future buildPayload(Uint8List arg_rawData, MessageSource arg_source, String arg_macAddress, int arg_rssi, int arg_receivedTimestamp) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.flutter_opendroneid.PayloadApi.getPayload', codec, + 'dev.flutter.pigeon.flutter_opendroneid.PayloadApi.buildPayload', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_rawData, arg_source.index, arg_macAddress, arg_rssi, arg_receivedTimestamp]) as List?; diff --git a/pigeon/schema.dart b/pigeon/schema.dart index bb37b13..007a4d9 100644 --- a/pigeon/schema.dart +++ b/pigeon/schema.dart @@ -85,6 +85,6 @@ abstract class Api { // ODIDPayload is not generated until used in API @HostApi() abstract class PayloadApi { - ODIDPayload getPayload(Uint8List rawData, MessageSource source, + ODIDPayload buildPayload(Uint8List rawData, MessageSource source, String macAddress, int rssi, int receivedTimestamp); }