Skip to content

Commit e4a82d3

Browse files
committed
Merge pull request #340 from dronekit/release-1.4.4.beta.3
Release 1.4.4 beta 3
2 parents 379fc1a + e65e27c commit e4a82d3

File tree

5 files changed

+170
-27
lines changed

5 files changed

+170
-27
lines changed

ClientLib/build.gradle

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ ext {
44
VERSION_MAJOR = 2
55
VERSION_MINOR = 6
66
VERSION_PATCH = 9
7-
VERSION_SUFFIX = "alpha2"
7+
VERSION_SUFFIX = "alpha3"
88

99
PUBLISH_ARTIFACT_ID = 'dronekit-android'
1010
PUBLISH_VERSION = generateVersionName("", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_SUFFIX)
@@ -40,6 +40,10 @@ android {
4040
abortOnError false
4141
}
4242

43+
testOptions {
44+
unitTests.returnDefaultValues = true
45+
}
46+
4347
android.libraryVariants.all { variant ->
4448
variant.outputs.each { output ->
4549
def file = output.outputFile

ClientLib/src/main/java/com/o3dr/services/android/lib/drone/companion/solo/tlv/TLVMessageParser.java

+58-24
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,23 @@
88
import java.util.ArrayList;
99
import java.util.List;
1010

11-
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.*;
11+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_ARTOO_INPUT_REPORT_MESSAGE;
12+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_CABLE_CAM_OPTIONS;
13+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_CABLE_CAM_WAYPOINT;
14+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_FOLLOW_OPTIONS;
15+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_GET_BUTTON_SETTING;
16+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_GOPRO_RECORD;
17+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_GOPRO_REQUEST_STATE;
18+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_GOPRO_SET_REQUEST;
19+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_GOPRO_STATE;
20+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_MESSAGE_GET_CURRENT_SHOT;
21+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_MESSAGE_LOCATION;
22+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_MESSAGE_RECORD_POSITION;
23+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_MESSAGE_SET_CURRENT_SHOT;
24+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_MESSAGE_SHOT_MANAGER_ERROR;
25+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_SET_BUTTON_SETTING;
26+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_SHOT_ERROR;
27+
import static com.o3dr.services.android.lib.drone.companion.solo.tlv.TLVMessageTypes.TYPE_SOLO_SHOT_OPTIONS;
1228

1329
/**
1430
* Utility class to generate tlv packet from received bytes.
@@ -37,42 +53,52 @@ public static List<TLVPacket> parseTLVPacket(ByteBuffer packetBuffer) {
3753
final ByteOrder originalOrder = packetBuffer.order();
3854
packetBuffer.order(TLVPacket.TLV_BYTE_ORDER);
3955

40-
while(packetBuffer.remaining() > 0) {
41-
int messageType = -1;
42-
try {
56+
int messageType = -1;
57+
try {
58+
59+
while (packetBuffer.remaining() >= TLVPacket.MIN_TLV_PACKET_SIZE) {
4360
messageType = packetBuffer.getInt();
4461
final int messageLength = packetBuffer.getInt();
45-
Log.d(TAG, String.format("Received message %d of with value of length %d. Remaining buffer size is %d", messageType, messageLength, packetBuffer.remaining()));
62+
63+
int remaining = packetBuffer.remaining();
64+
Log.d(TAG, String.format("Received message %d of with value of length %d. Remaining buffer size is %d", messageType, messageLength, remaining));
65+
66+
if (messageLength > remaining) {
67+
break;
68+
}
69+
70+
TLVPacket packet = null;
71+
packetBuffer.mark();
4672

4773
switch (messageType) {
4874
case TYPE_SOLO_MESSAGE_GET_CURRENT_SHOT:
4975
case TYPE_SOLO_MESSAGE_SET_CURRENT_SHOT: {
5076
final int shotType = packetBuffer.getInt();
5177
if (messageType == TYPE_SOLO_MESSAGE_GET_CURRENT_SHOT)
52-
packetList.add(new SoloMessageShotGetter(shotType));
78+
packet = new SoloMessageShotGetter(shotType);
5379
else
54-
packetList.add(new SoloMessageShotSetter(shotType));
80+
packet = new SoloMessageShotSetter(shotType);
5581
break;
5682
}
5783

5884
case TYPE_SOLO_MESSAGE_LOCATION: {
5985
final double latitude = packetBuffer.getDouble();
6086
final double longitude = packetBuffer.getDouble();
6187
final float altitude = packetBuffer.getFloat();
62-
packetList.add(new SoloMessageLocation(latitude, longitude, altitude));
88+
packet = new SoloMessageLocation(latitude, longitude, altitude);
6389
break;
6490
}
6591

6692
case TYPE_SOLO_MESSAGE_RECORD_POSITION: {
67-
packetList.add(new SoloMessageRecordPosition());
93+
packet = new SoloMessageRecordPosition();
6894
break;
6995
}
7096

7197
case TYPE_SOLO_CABLE_CAM_OPTIONS: {
7298
final short camInterpolation = packetBuffer.getShort();
7399
final short yawDirectionClockwise = packetBuffer.getShort();
74100
final float cruiseSpeed = packetBuffer.getFloat();
75-
packetList.add(new SoloCableCamOptions(camInterpolation, yawDirectionClockwise, cruiseSpeed));
101+
packet = new SoloCableCamOptions(camInterpolation, yawDirectionClockwise, cruiseSpeed);
76102
break;
77103
}
78104

@@ -83,35 +109,35 @@ public static List<TLVPacket> parseTLVPacket(ByteBuffer packetBuffer) {
83109
final int shotType = packetBuffer.getInt();
84110
final int flightMode = packetBuffer.getInt();
85111
if (messageType == TYPE_SOLO_GET_BUTTON_SETTING)
86-
packetList.add(new SoloButtonSettingGetter(button, event, shotType, flightMode));
112+
packet = new SoloButtonSettingGetter(button, event, shotType, flightMode);
87113
else
88-
packetList.add(new SoloButtonSettingSetter(button, event, shotType, flightMode));
114+
packet = new SoloButtonSettingSetter(button, event, shotType, flightMode);
89115
break;
90116
}
91117

92118
case TYPE_SOLO_FOLLOW_OPTIONS: {
93119
final float cruiseSpeed = packetBuffer.getFloat();
94120
final int lookAtValue = packetBuffer.getInt();
95-
packetList.add(new SoloFollowOptions(cruiseSpeed, lookAtValue));
121+
packet = new SoloFollowOptions(cruiseSpeed, lookAtValue);
96122
break;
97123
}
98124

99125
case TYPE_SOLO_SHOT_OPTIONS: {
100126
final float cruiseSpeed = packetBuffer.getFloat();
101-
packetList.add(new SoloShotOptions(cruiseSpeed));
127+
packet = new SoloShotOptions(cruiseSpeed);
102128
break;
103129
}
104130

105131
case TYPE_SOLO_SHOT_ERROR: {
106132
final int errorType = packetBuffer.getInt();
107-
packetList.add(new SoloShotError(errorType));
133+
packet = new SoloShotError(errorType);
108134
break;
109135
}
110136

111137
case TYPE_SOLO_MESSAGE_SHOT_MANAGER_ERROR: {
112138
final byte[] exceptionData = new byte[messageLength];
113139
packetBuffer.get(exceptionData);
114-
packetList.add(new SoloMessageShotManagerError(new String(exceptionData)));
140+
packet = new SoloMessageShotManagerError(new String(exceptionData));
115141
break;
116142
}
117143

@@ -122,7 +148,7 @@ public static List<TLVPacket> parseTLVPacket(ByteBuffer packetBuffer) {
122148
final float degreesYaw = packetBuffer.getFloat();
123149
final float pitch = packetBuffer.getFloat();
124150

125-
packetList.add(new SoloCableCamWaypoint(latitude, longitude, altitude, degreesYaw, pitch));
151+
packet = new SoloCableCamWaypoint(latitude, longitude, altitude, degreesYaw, pitch);
126152
break;
127153
}
128154

@@ -132,39 +158,47 @@ public static List<TLVPacket> parseTLVPacket(ByteBuffer packetBuffer) {
132158
final short gimbalRate = packetBuffer.getShort();
133159
final short battery = packetBuffer.getShort();
134160

135-
packetList.add(new ControllerMessageInputReport(timestamp, gimbalY, gimbalRate, battery));
161+
packet = new ControllerMessageInputReport(timestamp, gimbalY, gimbalRate, battery);
136162
break;
137163
}
138164

139165
case TYPE_SOLO_GOPRO_SET_REQUEST: {
140166
@SoloGoproConstants.RequestCommand final short command = packetBuffer.getShort();
141167
@SoloGoproConstants.RequestCommandValue final short value = packetBuffer.getShort();
142-
packetList.add(new SoloGoproSetRequest(command, value));
168+
packet = new SoloGoproSetRequest(command, value);
143169
break;
144170
}
145171

146172
case TYPE_SOLO_GOPRO_RECORD: {
147173
@SoloGoproConstants.RecordCommand final int command = packetBuffer.getInt();
148-
packetList.add(new SoloGoproRecord(command));
174+
packet = new SoloGoproRecord(command);
149175
break;
150176
}
151177

152178
case TYPE_SOLO_GOPRO_STATE: {
153-
packetList.add(new SoloGoproState(packetBuffer));
179+
packet = new SoloGoproState(packetBuffer);
154180
break;
155181
}
156182

157183
case TYPE_SOLO_GOPRO_REQUEST_STATE: {
158-
packetList.add(new SoloGoproRequestState());
184+
packet = new SoloGoproRequestState();
159185
break;
160186
}
161187

162188
default:
163189
break;
164190
}
165-
} catch (BufferUnderflowException e) {
166-
Log.e(TAG, "Invalid data for tlv packet of type " + messageType);
191+
192+
if (packet != null && packet.getMessageLength() == messageLength) {
193+
packetList.add(packet);
194+
} else {
195+
packetBuffer.reset();
196+
packetBuffer.position(packetBuffer.position() + messageLength);
197+
}
167198
}
199+
200+
} catch (BufferUnderflowException e) {
201+
Log.e(TAG, "Invalid data for tlv packet of type " + messageType);
168202
}
169203

170204
packetBuffer.order(originalOrder);

ClientLib/src/main/java/com/o3dr/services/android/lib/drone/companion/solo/tlv/TLVPacket.java

+21-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
public abstract class TLVPacket implements Parcelable {
1313

14+
public static final int MIN_TLV_PACKET_SIZE = 4 + 4; //4 bytes for the message type and 4 bytes for the message length.
1415
public static final ByteOrder TLV_BYTE_ORDER = ByteOrder.LITTLE_ENDIAN;
1516

1617
private final int messageType;
@@ -22,7 +23,7 @@ public TLVPacket(int type, int length){
2223
this.messageType = type;
2324
this.messageLength = length;
2425

25-
byteBuffer = ByteBuffer.allocate(4 + 4 + messageLength);
26+
byteBuffer = ByteBuffer.allocate(MIN_TLV_PACKET_SIZE + messageLength);
2627
byteBuffer.order(TLV_BYTE_ORDER);
2728
}
2829

@@ -49,6 +50,25 @@ public final byte[] toBytes(){
4950
return bytes;
5051
}
5152

53+
@Override
54+
public boolean equals(Object o) {
55+
if (this == o) return true;
56+
if (!(o instanceof TLVPacket)) return false;
57+
58+
TLVPacket tlvPacket = (TLVPacket) o;
59+
60+
if (messageType != tlvPacket.messageType) return false;
61+
return messageLength == tlvPacket.messageLength;
62+
63+
}
64+
65+
@Override
66+
public int hashCode() {
67+
int result = messageType;
68+
result = 31 * result + messageLength;
69+
return result;
70+
}
71+
5272
protected abstract void getMessageValue(ByteBuffer valueCarrier);
5373

5474
@Override

ServiceApp/build.gradle

+5-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ dependencies {
4242
def versionMajor = 1
4343
def versionMinor = 4
4444
def versionPatch = 4
45-
def versionBuild = 2 //bump for dogfood builds, public betas, etc.
45+
def versionBuild = 3 //bump for dogfood builds, public betas, etc.
4646
def versionPrefix = "3DR Services v"
4747

4848
//Log levels values
@@ -155,6 +155,10 @@ android {
155155
lintOptions {
156156
abortOnError false
157157
}
158+
159+
testOptions {
160+
unitTests.returnDefaultValues = true
161+
}
158162
}
159163

160164
def getAppKeystoreFile() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.o3dr.services.android.lib.drone.companion.solo.tlv;
2+
3+
import org.junit.Test;
4+
5+
import java.nio.ByteBuffer;
6+
import java.util.List;
7+
8+
import static org.junit.Assert.*;
9+
10+
/**
11+
* Unit test for the TLVMessageParser class.
12+
*/
13+
public class TLVMessageParserTest {
14+
15+
@Test
16+
public void testParseTLVPacket() throws Exception {
17+
List<TLVPacket> results = null;
18+
19+
//Test for invalid parameters
20+
results = TLVMessageParser.parseTLVPacket((byte[]) null);
21+
assertNull(results);
22+
23+
results = TLVMessageParser.parseTLVPacket(new byte[0]);
24+
assertNull(results);
25+
26+
//Single message parsing test
27+
SoloMessageLocation messageLoc = new SoloMessageLocation(5.3488066,-4.0499032, 10);
28+
byte[] messageLocBytes = messageLoc.toBytes();
29+
results = TLVMessageParser.parseTLVPacket(messageLocBytes);
30+
assertNotNull(results);
31+
assertTrue(results.size() == 1);
32+
33+
TLVPacket resultPacket = results.get(0);
34+
assertTrue(resultPacket.getMessageLength() == messageLoc.getMessageLength());
35+
assertTrue(resultPacket.getMessageType() == messageLoc.getMessageType());
36+
assertTrue(resultPacket instanceof SoloMessageLocation);
37+
38+
SoloMessageLocation castedResult = (SoloMessageLocation) resultPacket;
39+
assertTrue(castedResult.getCoordinate().equals(messageLoc.getCoordinate()));
40+
41+
42+
//Multiple message parsing test
43+
//1.
44+
ByteBuffer inputData = ByteBuffer.allocate(46);
45+
SoloMessageShotGetter shotGetter = new SoloMessageShotGetter(SoloMessageShot.SHOT_CABLECAM);
46+
TLVPacket[] inputPackets = {messageLoc, shotGetter};
47+
for(TLVPacket packet: inputPackets){
48+
inputData.put(packet.toBytes());
49+
}
50+
inputData.rewind();
51+
52+
results = TLVMessageParser.parseTLVPacket(inputData);
53+
assertNotNull(results);
54+
assertTrue(results.size() == inputPackets.length);
55+
assertTrue(inputData.remaining() == 6);
56+
57+
for(int i = 0; i < inputPackets.length; i++){
58+
TLVPacket inputPacket = inputPackets[i];
59+
TLVPacket outputPacket = results.get(i);
60+
assertTrue(inputPacket.equals(outputPacket));
61+
}
62+
63+
//2.
64+
inputData = ByteBuffer.allocate(40);
65+
for(TLVPacket packet: inputPackets){
66+
inputData.put(packet.toBytes());
67+
}
68+
inputData.rewind();
69+
70+
results = TLVMessageParser.parseTLVPacket(inputData);
71+
assertNotNull(results);
72+
assertTrue(results.size() == inputPackets.length);
73+
assertTrue(inputData.remaining() == 0);
74+
75+
for(int i = 0; i < inputPackets.length; i++){
76+
TLVPacket inputPacket = inputPackets[i];
77+
TLVPacket outputPacket = results.get(i);
78+
assertTrue(inputPacket.equals(outputPacket));
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)