mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-03-02 19:29:15 +01:00
AndroidGCS Telemetry: Finish moving telemetry into a runnable.
This commit is contained in:
parent
2d7bb4d3bb
commit
653702ac23
@ -42,16 +42,17 @@ import android.util.Log;
|
|||||||
|
|
||||||
public class Telemetry {
|
public class Telemetry {
|
||||||
/**
|
/**
|
||||||
* Telemetry provides a messaging handler to handle all the object updates and transfer
|
* Telemetry provides a messaging handler to handle all the object updates
|
||||||
* requests. This handler can either be attached to a new loop attached to the thread
|
* and transfer requests. This handler can either be attached to a new loop
|
||||||
* started by the telemetry service.
|
* attached to the thread started by the telemetry service.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private final String TAG = "Telemetry";
|
private final String TAG = "Telemetry";
|
||||||
public static int LOGLEVEL = 1;
|
public static int LOGLEVEL = 0;
|
||||||
public static boolean WARN = LOGLEVEL > 2;
|
public static boolean WARN = LOGLEVEL > 2;
|
||||||
public static boolean DEBUG = LOGLEVEL > 1;
|
public static boolean DEBUG = LOGLEVEL > 1;
|
||||||
public static boolean ERROR = LOGLEVEL > 0;
|
public static boolean ERROR = LOGLEVEL > 0;
|
||||||
|
|
||||||
public class TelemetryStats {
|
public class TelemetryStats {
|
||||||
public int txBytes;
|
public int txBytes;
|
||||||
public int rxBytes;
|
public int rxBytes;
|
||||||
@ -66,8 +67,10 @@ public class Telemetry {
|
|||||||
|
|
||||||
class ObjectTimeInfo {
|
class ObjectTimeInfo {
|
||||||
UAVObject obj;
|
UAVObject obj;
|
||||||
int updatePeriodMs; /** Update period in ms or 0 if no periodic updates are needed */
|
int updatePeriodMs;
|
||||||
int timeToNextUpdateMs; /** Time delay to the next update */
|
/** Update period in ms or 0 if no periodic updates are needed */
|
||||||
|
int timeToNextUpdateMs;
|
||||||
|
/** Time delay to the next update */
|
||||||
};
|
};
|
||||||
|
|
||||||
class ObjectQueueInfo {
|
class ObjectQueueInfo {
|
||||||
@ -79,10 +82,12 @@ public class Telemetry {
|
|||||||
public boolean equals(Object e) {
|
public boolean equals(Object e) {
|
||||||
try {
|
try {
|
||||||
ObjectQueueInfo o = (ObjectQueueInfo) e;
|
ObjectQueueInfo o = (ObjectQueueInfo) e;
|
||||||
return o.obj.getObjID() == obj.getObjID() && o.event == event && o.allInstances == allInstances;
|
return o.obj.getObjID() == obj.getObjID() && o.event == event
|
||||||
|
&& o.allInstances == allInstances;
|
||||||
} catch (Exception err) {
|
} catch (Exception err) {
|
||||||
|
|
||||||
};
|
}
|
||||||
|
;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -98,16 +103,20 @@ public class Telemetry {
|
|||||||
/**
|
/**
|
||||||
* Events generated by objects. Not enum because used in mask.
|
* Events generated by objects. Not enum because used in mask.
|
||||||
*/
|
*/
|
||||||
private static final int EV_UNPACKED = 0x01; /** Object data updated by unpacking */
|
private static final int EV_UNPACKED = 0x01;
|
||||||
private static final int EV_UPDATED = 0x02; /** Object data updated by changing the data structure */
|
/** Object data updated by unpacking */
|
||||||
private static final int EV_UPDATED_MANUAL = 0x04; /** Object update event manually generated */
|
private static final int EV_UPDATED = 0x02;
|
||||||
private static final int EV_UPDATE_REQ = 0x08; /** Request to update object data */
|
/** Object data updated by changing the data structure */
|
||||||
|
private static final int EV_UPDATED_MANUAL = 0x04;
|
||||||
|
/** Object update event manually generated */
|
||||||
|
private static final int EV_UPDATE_REQ = 0x08;
|
||||||
|
|
||||||
|
/** Request to update object data */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public Telemetry(UAVTalk utalkIn, UAVObjectManager objMngr, Looper l)
|
public Telemetry(UAVTalk utalkIn, UAVObjectManager objMngr, Looper l) {
|
||||||
{
|
|
||||||
this.utalk = utalkIn;
|
this.utalk = utalkIn;
|
||||||
this.objMngr = objMngr;
|
this.objMngr = objMngr;
|
||||||
|
|
||||||
@ -118,7 +127,8 @@ public class Telemetry {
|
|||||||
List<List<UAVObject>> objs = objMngr.getObjects();
|
List<List<UAVObject>> objs = objMngr.getObjects();
|
||||||
ListIterator<List<UAVObject>> li = objs.listIterator();
|
ListIterator<List<UAVObject>> li = objs.listIterator();
|
||||||
while (li.hasNext())
|
while (li.hasNext())
|
||||||
registerObject(li.next().get(0)); // we only need to register one instance per object type
|
registerObject(li.next().get(0)); // we only need to register one
|
||||||
|
// instance per object type
|
||||||
|
|
||||||
// Listen to new object creations
|
// Listen to new object creations
|
||||||
objMngr.addNewInstanceObserver(new Observer() {
|
objMngr.addNewInstanceObserver(new Observer() {
|
||||||
@ -135,8 +145,7 @@ public class Telemetry {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Listen to transaction completions from uavtalk
|
// Listen to transaction completions from uavtalk
|
||||||
utalk.setOnTransactionCompletedListener(
|
utalk.setOnTransactionCompletedListener(utalk.new OnTransactionCompletedListener() {
|
||||||
utalk.new OnTransactionCompletedListener() {
|
|
||||||
@Override
|
@Override
|
||||||
void TransactionSucceeded(UAVObject data) {
|
void TransactionSucceeded(UAVObject data) {
|
||||||
try {
|
try {
|
||||||
@ -146,10 +155,12 @@ public class Telemetry {
|
|||||||
utalk.setOnTransactionCompletedListener(null);
|
utalk.setOnTransactionCompletedListener(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void TransactionFailed(UAVObject data) {
|
void TransactionFailed(UAVObject data) {
|
||||||
try {
|
try {
|
||||||
if (DEBUG) Log.d(TAG, "TransactionFailed(" + data.getName() + ")");
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "TransactionFailed(" + data.getName() + ")");
|
||||||
|
|
||||||
transactionCompleted(data, false);
|
transactionCompleted(data, false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -223,8 +234,7 @@ public class Telemetry {
|
|||||||
/**
|
/**
|
||||||
* Register a new object for periodic updates (if enabled)
|
* Register a new object for periodic updates (if enabled)
|
||||||
*/
|
*/
|
||||||
private synchronized void registerObject(UAVObject obj)
|
private synchronized void registerObject(UAVObject obj) {
|
||||||
{
|
|
||||||
// Setup object for periodic updates
|
// Setup object for periodic updates
|
||||||
addObject(obj);
|
addObject(obj);
|
||||||
|
|
||||||
@ -235,15 +245,14 @@ public class Telemetry {
|
|||||||
/**
|
/**
|
||||||
* Add an object in the list used for periodic updates
|
* Add an object in the list used for periodic updates
|
||||||
*/
|
*/
|
||||||
private synchronized void addObject(UAVObject obj)
|
private synchronized void addObject(UAVObject obj) {
|
||||||
{
|
|
||||||
// Check if object type is already in the list
|
// Check if object type is already in the list
|
||||||
ListIterator<ObjectTimeInfo> li = objList.listIterator();
|
ListIterator<ObjectTimeInfo> li = objList.listIterator();
|
||||||
while (li.hasNext()) {
|
while (li.hasNext()) {
|
||||||
ObjectTimeInfo n = li.next();
|
ObjectTimeInfo n = li.next();
|
||||||
if( n.obj.getObjID() == obj.getObjID() )
|
if (n.obj.getObjID() == obj.getObjID()) {
|
||||||
{
|
// Object type (not instance!) is already in the list, do
|
||||||
// Object type (not instance!) is already in the list, do nothing
|
// nothing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,16 +268,15 @@ public class Telemetry {
|
|||||||
/**
|
/**
|
||||||
* Update the object's timers
|
* Update the object's timers
|
||||||
*/
|
*/
|
||||||
private synchronized void setUpdatePeriod(UAVObject obj, int periodMs)
|
private synchronized void setUpdatePeriod(UAVObject obj, int periodMs) {
|
||||||
{
|
|
||||||
// Find object type (not instance!) and update its period
|
// Find object type (not instance!) and update its period
|
||||||
ListIterator<ObjectTimeInfo> li = objList.listIterator();
|
ListIterator<ObjectTimeInfo> li = objList.listIterator();
|
||||||
while (li.hasNext()) {
|
while (li.hasNext()) {
|
||||||
ObjectTimeInfo n = li.next();
|
ObjectTimeInfo n = li.next();
|
||||||
if ( n.obj.getObjID() == obj.getObjID() )
|
if (n.obj.getObjID() == obj.getObjID()) {
|
||||||
{
|
|
||||||
n.updatePeriodMs = periodMs;
|
n.updatePeriodMs = periodMs;
|
||||||
n.timeToNextUpdateMs = (int) (periodMs * (new java.util.Random()).nextDouble()); // avoid bunching of updates
|
n.timeToNextUpdateMs = (int) (periodMs * (new java.util.Random())
|
||||||
|
.nextDouble()); // avoid bunching of updates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,17 +310,18 @@ public class Telemetry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to all instances of an object depending on the event mask specified
|
* Connect to all instances of an object depending on the event mask
|
||||||
|
* specified
|
||||||
*/
|
*/
|
||||||
private synchronized void connectToObjectInstances(UAVObject obj, int eventMask)
|
private synchronized void connectToObjectInstances(UAVObject obj,
|
||||||
{
|
int eventMask) {
|
||||||
List<UAVObject> objs = objMngr.getObjectInstances(obj.getObjID());
|
List<UAVObject> objs = objMngr.getObjectInstances(obj.getObjID());
|
||||||
ListIterator<UAVObject> li = objs.listIterator();
|
ListIterator<UAVObject> li = objs.listIterator();
|
||||||
while(li.hasNext())
|
while (li.hasNext()) {
|
||||||
{
|
|
||||||
obj = li.next();
|
obj = li.next();
|
||||||
|
|
||||||
// Disconnect all previous observers from telemetry. This is imortant as this can
|
// Disconnect all previous observers from telemetry. This is
|
||||||
|
// imortant as this can
|
||||||
// be called multiple times
|
// be called multiple times
|
||||||
obj.removeUnpackedObserver(unpackedObserver);
|
obj.removeUnpackedObserver(unpackedObserver);
|
||||||
obj.removeUpdatedAutoObserver(updatedAutoObserver);
|
obj.removeUpdatedAutoObserver(updatedAutoObserver);
|
||||||
@ -334,47 +343,42 @@ public class Telemetry {
|
|||||||
/**
|
/**
|
||||||
* Update an object based on its metadata properties
|
* Update an object based on its metadata properties
|
||||||
*/
|
*/
|
||||||
private void updateObject(UAVObject obj)
|
private void updateObject(UAVObject obj) {
|
||||||
{
|
|
||||||
// Get metadata
|
// Get metadata
|
||||||
UAVObject.Metadata metadata = obj.getMetadata();
|
UAVObject.Metadata metadata = obj.getMetadata();
|
||||||
|
|
||||||
// Setup object depending on update mode
|
// Setup object depending on update mode
|
||||||
int eventMask;
|
int eventMask;
|
||||||
if ( metadata.GetGcsTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_PERIODIC )
|
if (metadata.GetGcsTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_PERIODIC) {
|
||||||
{
|
|
||||||
// Set update period
|
// Set update period
|
||||||
setUpdatePeriod(obj, metadata.gcsTelemetryUpdatePeriod);
|
setUpdatePeriod(obj, metadata.gcsTelemetryUpdatePeriod);
|
||||||
// Connect signals for all instances
|
// Connect signals for all instances
|
||||||
eventMask = EV_UPDATED_MANUAL | EV_UPDATE_REQ;
|
eventMask = EV_UPDATED_MANUAL | EV_UPDATE_REQ;
|
||||||
if (obj.isMetadata())
|
if (obj.isMetadata())
|
||||||
eventMask |= EV_UNPACKED; // we also need to act on remote updates (unpack events)
|
eventMask |= EV_UNPACKED; // we also need to act on remote
|
||||||
|
// updates (unpack events)
|
||||||
|
|
||||||
connectToObjectInstances(obj, eventMask);
|
connectToObjectInstances(obj, eventMask);
|
||||||
}
|
} else if (metadata.GetGcsTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_ONCHANGE) {
|
||||||
else if ( metadata.GetGcsTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_ONCHANGE )
|
|
||||||
{
|
|
||||||
// Set update period
|
// Set update period
|
||||||
setUpdatePeriod(obj, 0);
|
setUpdatePeriod(obj, 0);
|
||||||
// Connect signals for all instances
|
// Connect signals for all instances
|
||||||
eventMask = EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ;
|
eventMask = EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ;
|
||||||
if (obj.isMetadata())
|
if (obj.isMetadata())
|
||||||
eventMask |= EV_UNPACKED; // we also need to act on remote updates (unpack events)
|
eventMask |= EV_UNPACKED; // we also need to act on remote
|
||||||
|
// updates (unpack events)
|
||||||
|
|
||||||
connectToObjectInstances(obj, eventMask);
|
connectToObjectInstances(obj, eventMask);
|
||||||
}
|
} else if (metadata.GetGcsTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_THROTTLED) {
|
||||||
else if ( metadata.GetGcsTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_THROTTLED )
|
|
||||||
{
|
|
||||||
// TODO
|
// TODO
|
||||||
}
|
} else if (metadata.GetGcsTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_MANUAL) {
|
||||||
else if ( metadata.GetGcsTelemetryUpdateMode() == UAVObject.UpdateMode.UPDATEMODE_MANUAL )
|
|
||||||
{
|
|
||||||
// Set update period
|
// Set update period
|
||||||
setUpdatePeriod(obj, 0);
|
setUpdatePeriod(obj, 0);
|
||||||
// Connect signals for all instances
|
// Connect signals for all instances
|
||||||
eventMask = EV_UPDATED_MANUAL | EV_UPDATE_REQ;
|
eventMask = EV_UPDATED_MANUAL | EV_UPDATE_REQ;
|
||||||
if (obj.isMetadata())
|
if (obj.isMetadata())
|
||||||
eventMask |= EV_UNPACKED; // we also need to act on remote updates (unpack events)
|
eventMask |= EV_UNPACKED; // we also need to act on remote
|
||||||
|
// updates (unpack events)
|
||||||
|
|
||||||
connectToObjectInstances(obj, eventMask);
|
connectToObjectInstances(obj, eventMask);
|
||||||
}
|
}
|
||||||
@ -382,17 +386,18 @@ public class Telemetry {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a transaction is successfully completed (uavtalk event)
|
* Called when a transaction is successfully completed (uavtalk event)
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void transactionCompleted(UAVObject obj, boolean result) throws IOException
|
private void transactionCompleted(UAVObject obj, boolean result)
|
||||||
{
|
throws IOException {
|
||||||
if (DEBUG) Log.d(TAG,"UAVTalk transactionCompleted");
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "UAVTalk transactionCompleted");
|
||||||
// Check if there is a pending transaction and the objects match
|
// Check if there is a pending transaction and the objects match
|
||||||
if ( transPending && transInfo.obj.getObjID() == obj.getObjID() )
|
if (transPending && transInfo.obj.getObjID() == obj.getObjID()) {
|
||||||
{
|
|
||||||
if (DEBUG) Log.d(TAG, "Telemetry: transaction completed for " + obj.getName());
|
if (DEBUG) Log.d(TAG, "Telemetry: transaction completed for " + obj.getName());
|
||||||
// Complete transaction
|
|
||||||
|
|
||||||
|
// Complete transaction
|
||||||
synchronized(transTimer) {
|
synchronized(transTimer) {
|
||||||
transTimer.cancel();
|
transTimer.cancel();
|
||||||
transPending = false;
|
transPending = false;
|
||||||
@ -400,41 +405,44 @@ public class Telemetry {
|
|||||||
|
|
||||||
//Send signal
|
//Send signal
|
||||||
obj.transactionCompleted(result);
|
obj.transactionCompleted(result);
|
||||||
// Process new object updates from queue
|
} else {
|
||||||
processObjectQueue();
|
if (ERROR)
|
||||||
} else
|
Log.e(TAG,
|
||||||
{
|
"Error: received a transaction completed when did not expect it.");
|
||||||
if (ERROR) Log.e(TAG,"Error: received a transaction completed when did not expect it.");
|
|
||||||
transPending = false;
|
transPending = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a transaction is not completed within the timeout period (timer event)
|
* Called when a transaction is not completed within the timeout period
|
||||||
|
* (timer event)
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void transactionTimeout() throws IOException
|
private void transactionTimeout() throws IOException {
|
||||||
{
|
if (DEBUG)
|
||||||
if (DEBUG) Log.d(TAG,"Telemetry: transaction timeout.");
|
Log.d(TAG, "Telemetry: transaction timeout.");
|
||||||
synchronized (transTimer) {
|
synchronized (transTimer) {
|
||||||
transTimer.cancel();
|
transTimer.cancel();
|
||||||
// Proceed only if there is a pending transaction
|
// Proceed only if there is a pending transaction
|
||||||
if ( transPending )
|
if (transPending) {
|
||||||
{
|
|
||||||
// Check if more retries are pending
|
// Check if more retries are pending
|
||||||
if (transInfo.retriesRemaining > 0)
|
if (transInfo.retriesRemaining > 0) {
|
||||||
{
|
|
||||||
--transInfo.retriesRemaining;
|
--transInfo.retriesRemaining;
|
||||||
processObjectTransaction();
|
processObjectTransaction();
|
||||||
++txRetries;
|
++txRetries;
|
||||||
}
|
} else {
|
||||||
else
|
if (ERROR)
|
||||||
{
|
Log.e(TAG,
|
||||||
if (ERROR) Log.e(TAG, "Transaction failed for: " + transInfo.obj.getName());
|
"Transaction failed for: "
|
||||||
|
+ transInfo.obj.getName());
|
||||||
|
|
||||||
// Terminate transaction. This triggers UAVTalk to send a transaction
|
// Terminate transaction. This triggers UAVTalk to send a
|
||||||
// failed signal which will make the next queue entry be processed
|
// transaction
|
||||||
// Note this is UAVTalk listener TransactionFailed function and not the
|
// failed signal which will make the next queue entry be
|
||||||
|
// processed
|
||||||
|
// Note this is UAVTalk listener TransactionFailed function
|
||||||
|
// and not the
|
||||||
// object specific transaction failed.
|
// object specific transaction failed.
|
||||||
utalk.cancelPendingTransaction(transInfo.obj);
|
utalk.cancelPendingTransaction(transInfo.obj);
|
||||||
++txErrors;
|
++txErrors;
|
||||||
@ -444,117 +452,115 @@ public class Telemetry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start an object transaction with UAVTalk, all information is stored in transInfo
|
* Start an object transaction with UAVTalk, all information is stored in
|
||||||
|
* transInfo
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void processObjectTransaction() throws IOException
|
private void processObjectTransaction() throws IOException {
|
||||||
{
|
if (transPending) {
|
||||||
if (transPending)
|
if (DEBUG)
|
||||||
{
|
Log.d(TAG,
|
||||||
if (DEBUG) Log.d(TAG, "Process Object transaction for " + transInfo.obj.getName());
|
"Process Object transaction for "
|
||||||
|
+ transInfo.obj.getName());
|
||||||
// Initiate transaction
|
// Initiate transaction
|
||||||
if (transInfo.objRequest)
|
if (transInfo.objRequest) {
|
||||||
{
|
|
||||||
utalk.sendObjectRequest(transInfo.obj, transInfo.allInstances);
|
utalk.sendObjectRequest(transInfo.obj, transInfo.allInstances);
|
||||||
}
|
} else {
|
||||||
else
|
utalk.sendObject(transInfo.obj, transInfo.acked,
|
||||||
{
|
transInfo.allInstances);
|
||||||
utalk.sendObject(transInfo.obj, transInfo.acked, transInfo.allInstances);
|
|
||||||
}
|
}
|
||||||
// Start timer if a response is expected
|
// Start timer if a response is expected
|
||||||
if ( transInfo.objRequest || transInfo.acked )
|
if (transInfo.objRequest || transInfo.acked) {
|
||||||
{
|
|
||||||
transTimerSetPeriod(REQ_TIMEOUT_MS);
|
transTimerSetPeriod(REQ_TIMEOUT_MS);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
synchronized (transTimer) {
|
synchronized (transTimer) {
|
||||||
transTimer.cancel();
|
transTimer.cancel();
|
||||||
transPending = false;
|
transPending = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
{
|
if (ERROR)
|
||||||
if (ERROR) Log.e(TAG,"Error: inside of processObjectTransaction with no transPending");
|
Log.e(TAG,
|
||||||
|
"Error: inside of processObjectTransaction with no transPending");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process events from the object queue
|
* Process events from the object queue
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void processObjectQueue() throws IOException
|
private void processObjectQueue() throws IOException {
|
||||||
{
|
if (DEBUG)
|
||||||
if (DEBUG) Log.d(TAG, "Process object queue - Depth " + objQueue.size() + " priority " + objPriorityQueue.size());
|
Log.d(TAG, "Process object queue - Depth " + objQueue.size()
|
||||||
|
+ " priority " + objPriorityQueue.size());
|
||||||
|
|
||||||
// Don nothing if a transaction is already in progress (should not happen)
|
// Don nothing if a transaction is already in progress (should not
|
||||||
if (transPending)
|
// happen)
|
||||||
{
|
if (transPending) {
|
||||||
if (WARN) Log.e(TAG,"Dequeue while a transaction pending");
|
if (WARN)
|
||||||
|
Log.e(TAG, "Dequeue while a transaction pending");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get object information from queue (first the priority and then the regular queue)
|
// Get object information from queue (first the priority and then the
|
||||||
|
// regular queue)
|
||||||
ObjectQueueInfo objInfo;
|
ObjectQueueInfo objInfo;
|
||||||
synchronized (objPriorityQueue) {
|
synchronized (objPriorityQueue) {
|
||||||
if ( !objPriorityQueue.isEmpty() )
|
if (!objPriorityQueue.isEmpty()) {
|
||||||
{
|
|
||||||
objInfo = objPriorityQueue.remove();
|
objInfo = objPriorityQueue.remove();
|
||||||
} else {
|
} else {
|
||||||
synchronized (objQueue) {
|
synchronized (objQueue) {
|
||||||
if ( !objQueue.isEmpty() )
|
if (!objQueue.isEmpty()) {
|
||||||
{
|
|
||||||
objInfo = objQueue.remove();
|
objInfo = objQueue.remove();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a connection has been established, only process GCSTelemetryStats updates
|
// Check if a connection has been established, only process
|
||||||
|
// GCSTelemetryStats updates
|
||||||
// (used to establish the connection)
|
// (used to establish the connection)
|
||||||
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
||||||
if ( ((String) gcsStatsObj.getField("Status").getValue()).compareTo("Connected") != 0 )
|
if (((String) gcsStatsObj.getField("Status").getValue())
|
||||||
{
|
.compareTo("Connected") != 0) {
|
||||||
objQueue.clear();
|
objQueue.clear();
|
||||||
if ( objInfo.obj.getObjID() != objMngr.getObject("GCSTelemetryStats").getObjID() )
|
if (objInfo.obj.getObjID() != objMngr
|
||||||
{
|
.getObject("GCSTelemetryStats").getObjID()) {
|
||||||
if (DEBUG) Log.d(TAG,"transactionCompleted(false) due to receiving object not GCSTelemetryStats while not connected.");
|
if (DEBUG)
|
||||||
|
Log.d(TAG,
|
||||||
|
"transactionCompleted(false) due to receiving object not GCSTelemetryStats while not connected.");
|
||||||
objInfo.obj.transactionCompleted(false);
|
objInfo.obj.transactionCompleted(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup transaction (skip if unpack event)
|
// Setup transaction (skip if unpack event)
|
||||||
if ( objInfo.event != EV_UNPACKED )
|
if (objInfo.event != EV_UNPACKED) {
|
||||||
{
|
|
||||||
UAVObject.Metadata metadata = objInfo.obj.getMetadata();
|
UAVObject.Metadata metadata = objInfo.obj.getMetadata();
|
||||||
transInfo.obj = objInfo.obj;
|
transInfo.obj = objInfo.obj;
|
||||||
transInfo.allInstances = objInfo.allInstances;
|
transInfo.allInstances = objInfo.allInstances;
|
||||||
transInfo.retriesRemaining = MAX_RETRIES;
|
transInfo.retriesRemaining = MAX_RETRIES;
|
||||||
transInfo.acked = metadata.GetGcsTelemetryAcked();
|
transInfo.acked = metadata.GetGcsTelemetryAcked();
|
||||||
if ( objInfo.event == EV_UPDATED || objInfo.event == EV_UPDATED_MANUAL )
|
if (objInfo.event == EV_UPDATED
|
||||||
{
|
|| objInfo.event == EV_UPDATED_MANUAL) {
|
||||||
transInfo.objRequest = false;
|
transInfo.objRequest = false;
|
||||||
}
|
} else if (objInfo.event == EV_UPDATE_REQ) {
|
||||||
else if ( objInfo.event == EV_UPDATE_REQ )
|
|
||||||
{
|
|
||||||
transInfo.objRequest = true;
|
transInfo.objRequest = true;
|
||||||
}
|
}
|
||||||
// Start transaction
|
// Start transaction
|
||||||
transPending = true;
|
transPending = true;
|
||||||
processObjectTransaction();
|
processObjectTransaction();
|
||||||
} else
|
} else {
|
||||||
{
|
// qDebug() <<
|
||||||
// qDebug() << QString("Process object queue: this is an unpack event for %1").arg(objInfo.obj->getName());
|
// QString("Process object queue: this is an unpack event for %1").arg(objInfo.obj->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a metaobject then make necessary telemetry updates
|
// If this is a metaobject then make necessary telemetry updates
|
||||||
if (objInfo.obj.isMetadata())
|
if (objInfo.obj.isMetadata()) {
|
||||||
{
|
|
||||||
UAVMetaObject metaobj = (UAVMetaObject) objInfo.obj;
|
UAVMetaObject metaobj = (UAVMetaObject) objInfo.obj;
|
||||||
updateObject(metaobj.getParentObject());
|
updateObject(metaobj.getParentObject());
|
||||||
}
|
}
|
||||||
@ -569,58 +575,59 @@ public class Telemetry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check is any objects are pending for periodic updates
|
* Check is any objects are pending for periodic updates TODO: Clean-up
|
||||||
* TODO: Clean-up
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void processPeriodicUpdates() throws IOException
|
private void processPeriodicUpdates() throws IOException {
|
||||||
{
|
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "processPeriodicUpdates()");
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "processPeriodicUpdates()");
|
||||||
// Stop timer
|
// Stop timer
|
||||||
|
|
||||||
updateTimer.cancel();
|
updateTimer.cancel();
|
||||||
|
|
||||||
// Iterate through each object and update its timer, if zero then transmit object.
|
// Iterate through each object and update its timer, if zero then
|
||||||
// Also calculate smallest delay to next update (will be used for setting timeToNextUpdateMs)
|
// transmit object.
|
||||||
|
// Also calculate smallest delay to next update (will be used for
|
||||||
|
// setting timeToNextUpdateMs)
|
||||||
int minDelay = MAX_UPDATE_PERIOD_MS;
|
int minDelay = MAX_UPDATE_PERIOD_MS;
|
||||||
ObjectTimeInfo objinfo;
|
ObjectTimeInfo objinfo;
|
||||||
int elapsedMs = 0;
|
int elapsedMs = 0;
|
||||||
long startTime;
|
long startTime;
|
||||||
int offset;
|
int offset;
|
||||||
ListIterator<ObjectTimeInfo> li = objList.listIterator();
|
ListIterator<ObjectTimeInfo> li = objList.listIterator();
|
||||||
while(li.hasNext())
|
while (li.hasNext()) {
|
||||||
{
|
|
||||||
objinfo = li.next();
|
objinfo = li.next();
|
||||||
// If object is configured for periodic updates
|
// If object is configured for periodic updates
|
||||||
if (objinfo.updatePeriodMs > 0)
|
if (objinfo.updatePeriodMs > 0) {
|
||||||
{
|
|
||||||
objinfo.timeToNextUpdateMs -= timeToNextUpdateMs;
|
objinfo.timeToNextUpdateMs -= timeToNextUpdateMs;
|
||||||
// Check if time for the next update
|
// Check if time for the next update
|
||||||
if (objinfo.timeToNextUpdateMs <= 0)
|
if (objinfo.timeToNextUpdateMs <= 0) {
|
||||||
{
|
|
||||||
// Reset timer
|
// Reset timer
|
||||||
offset = (-objinfo.timeToNextUpdateMs) % objinfo.updatePeriodMs;
|
offset = (-objinfo.timeToNextUpdateMs)
|
||||||
objinfo.timeToNextUpdateMs = objinfo.updatePeriodMs - offset;
|
% objinfo.updatePeriodMs;
|
||||||
|
objinfo.timeToNextUpdateMs = objinfo.updatePeriodMs
|
||||||
|
- offset;
|
||||||
// Send object
|
// Send object
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
handler.updatedManual(objinfo.obj);
|
handler.updatedManual(objinfo.obj);
|
||||||
//enqueueObjectUpdates(objinfo.obj, EV_UPDATED_MANUAL, true, false);
|
// enqueueObjectUpdates(objinfo.obj, EV_UPDATED_MANUAL,
|
||||||
|
// true, false);
|
||||||
elapsedMs = (int) (System.currentTimeMillis() - startTime);
|
elapsedMs = (int) (System.currentTimeMillis() - startTime);
|
||||||
// Update timeToNextUpdateMs with the elapsed delay of sending the object;
|
// Update timeToNextUpdateMs with the elapsed delay of
|
||||||
|
// sending the object;
|
||||||
timeToNextUpdateMs += elapsedMs;
|
timeToNextUpdateMs += elapsedMs;
|
||||||
}
|
}
|
||||||
// Update minimum delay
|
// Update minimum delay
|
||||||
if (objinfo.timeToNextUpdateMs < minDelay)
|
if (objinfo.timeToNextUpdateMs < minDelay) {
|
||||||
{
|
|
||||||
minDelay = objinfo.timeToNextUpdateMs;
|
minDelay = objinfo.timeToNextUpdateMs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if delay for the next update is too short
|
// Check if delay for the next update is too short
|
||||||
if (minDelay < MIN_UPDATE_PERIOD_MS)
|
if (minDelay < MIN_UPDATE_PERIOD_MS) {
|
||||||
{
|
|
||||||
minDelay = MIN_UPDATE_PERIOD_MS;
|
minDelay = MIN_UPDATE_PERIOD_MS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,8 +638,7 @@ public class Telemetry {
|
|||||||
updateTimerSetPeriod(timeToNextUpdateMs);
|
updateTimerSetPeriod(timeToNextUpdateMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TelemetryStats getStats()
|
public TelemetryStats getStats() {
|
||||||
{
|
|
||||||
// Get UAVTalk stats
|
// Get UAVTalk stats
|
||||||
UAVTalk.ComStats utalkStats = utalk.getStats();
|
UAVTalk.ComStats utalkStats = utalk.getStats();
|
||||||
|
|
||||||
@ -652,29 +658,24 @@ public class Telemetry {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetStats()
|
public void resetStats() {
|
||||||
{
|
|
||||||
utalk.resetStats();
|
utalk.resetStats();
|
||||||
txErrors = 0;
|
txErrors = 0;
|
||||||
txRetries = 0;
|
txRetries = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void newObject(UAVObject obj) {
|
||||||
private void newObject(UAVObject obj)
|
|
||||||
{
|
|
||||||
registerObject(obj);
|
registerObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void newInstance(UAVObject obj)
|
private synchronized void newInstance(UAVObject obj) {
|
||||||
{
|
|
||||||
registerObject(obj);
|
registerObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop all the telemetry timers
|
* Stop all the telemetry timers
|
||||||
*/
|
*/
|
||||||
public void stopTelemetry()
|
public void stopTelemetry() {
|
||||||
{
|
|
||||||
if (updateTimerTask != null)
|
if (updateTimerTask != null)
|
||||||
updateTimerTask.cancel();
|
updateTimerTask.cancel();
|
||||||
updateTimerTask = null;
|
updateTimerTask = null;
|
||||||
@ -729,9 +730,12 @@ public class Telemetry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ! Generic enqueue
|
// ! Generic enqueue
|
||||||
void enqueueObjectUpdates(UAVObject obj, int event, boolean allInstances, boolean priority) {
|
void enqueueObjectUpdates(UAVObject obj, int event,
|
||||||
|
boolean allInstances, boolean priority) {
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "Enqueing update " + obj.getName() + " event " + event);
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "Enqueing update " + obj.getName() + " event "
|
||||||
|
+ event);
|
||||||
|
|
||||||
ObjectQueueInfo objInfo = new ObjectQueueInfo();
|
ObjectQueueInfo objInfo = new ObjectQueueInfo();
|
||||||
objInfo.obj = obj;
|
objInfo.obj = obj;
|
||||||
@ -753,7 +757,7 @@ public class Telemetry {
|
|||||||
|
|
||||||
// ! Enqueue an updated manual event
|
// ! Enqueue an updated manual event
|
||||||
void updatedManual(UAVObject obj) {
|
void updatedManual(UAVObject obj) {
|
||||||
enqueueObjectUpdates(obj, EV_UPDATE_REQ, false, true);
|
enqueueObjectUpdates(obj, EV_UPDATED_MANUAL, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! Enqueue an update requested event
|
// ! Enqueue an update requested event
|
||||||
@ -767,7 +771,9 @@ public class Telemetry {
|
|||||||
|
|
||||||
// ! Transaction information to perform
|
// ! Transaction information to perform
|
||||||
private final ObjectQueueInfo objInfo;
|
private final ObjectQueueInfo objInfo;
|
||||||
// private final ObjectTransactionInfo transInfo = new ObjectTransactionInfo();
|
|
||||||
|
// private final ObjectTransactionInfo transInfo = new
|
||||||
|
// ObjectTransactionInfo();
|
||||||
|
|
||||||
ObjectRunnable(ObjectQueueInfo info) {
|
ObjectRunnable(ObjectQueueInfo info) {
|
||||||
Assert.assertNotNull(info);
|
Assert.assertNotNull(info);
|
||||||
@ -777,83 +783,78 @@ public class Telemetry {
|
|||||||
// ! Perform the transaction on the looper thread
|
// ! Perform the transaction on the looper thread
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.d(TAG,"object transaction running");
|
if (DEBUG) Log.d(TAG, "Object transaction running. Event:" + objInfo.event);
|
||||||
// 1. Check GCS is connected, throw this out if not
|
// 1. Check GCS is connected, throw this out if not
|
||||||
// 2. Set up a transaction which includes multiple retries, whether to wait for ack etc
|
// 2. Set up a transaction which includes multiple retries, whether
|
||||||
|
// to wait for ack etc
|
||||||
// 3. Send UAVTalk message
|
// 3. Send UAVTalk message
|
||||||
// 4. Based on transaction type either wait for update or end
|
// 4. Based on transaction type either wait for update or end
|
||||||
|
|
||||||
// 1. Check if a connection has been established, only process GCSTelemetryStats updates
|
// 1. Check if a connection has been established, only process
|
||||||
|
// GCSTelemetryStats updates
|
||||||
// (used to establish the connection)
|
// (used to establish the connection)
|
||||||
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
||||||
if ( ((String) gcsStatsObj.getField("Status").getValue()).compareTo("Connected") != 0 )
|
if (((String) gcsStatsObj.getField("Status").getValue())
|
||||||
{
|
.compareTo("Connected") != 0) {
|
||||||
if ( objInfo.obj.getObjID() != objMngr.getObject("GCSTelemetryStats").getObjID() )
|
if (objInfo.obj.getObjID() != objMngr.getObject(
|
||||||
{
|
"GCSTelemetryStats").getObjID()) {
|
||||||
if (DEBUG) Log.d(TAG,"transactionCompleted(false) due to receiving object not GCSTelemetryStats while not connected.");
|
if (DEBUG)
|
||||||
|
Log.d(TAG,
|
||||||
|
"transactionCompleted(false) due to receiving object not GCSTelemetryStats while not connected.");
|
||||||
objInfo.obj.transactionCompleted(false);
|
objInfo.obj.transactionCompleted(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.e(TAG, "A");
|
|
||||||
// 2. Setup transaction (skip if unpack event)
|
// 2. Setup transaction (skip if unpack event)
|
||||||
if ( objInfo.event != EV_UNPACKED )
|
if (objInfo.event != EV_UNPACKED) {
|
||||||
{
|
|
||||||
Log.e(TAG, "A1");
|
|
||||||
UAVObject.Metadata metadata = objInfo.obj.getMetadata();
|
UAVObject.Metadata metadata = objInfo.obj.getMetadata();
|
||||||
transInfo.obj = objInfo.obj;
|
transInfo.obj = objInfo.obj;
|
||||||
transInfo.allInstances = objInfo.allInstances;
|
transInfo.allInstances = objInfo.allInstances;
|
||||||
transInfo.retriesRemaining = MAX_RETRIES;
|
transInfo.retriesRemaining = MAX_RETRIES;
|
||||||
transInfo.acked = metadata.GetGcsTelemetryAcked();
|
transInfo.acked = metadata.GetGcsTelemetryAcked();
|
||||||
if ( objInfo.event == EV_UPDATED || objInfo.event == EV_UPDATED_MANUAL )
|
if (objInfo.event == EV_UPDATED
|
||||||
{
|
|| objInfo.event == EV_UPDATED_MANUAL) {
|
||||||
transInfo.objRequest = false;
|
transInfo.objRequest = false;
|
||||||
}
|
} else if (objInfo.event == EV_UPDATE_REQ) {
|
||||||
else if ( objInfo.event == EV_UPDATE_REQ )
|
|
||||||
{
|
|
||||||
transInfo.objRequest = true;
|
transInfo.objRequest = true;
|
||||||
}
|
}
|
||||||
// Start transaction
|
// Start transaction
|
||||||
transPending = true;
|
transPending = true;
|
||||||
}
|
}
|
||||||
Log.e(TAG, "B");
|
|
||||||
// If this is a metaobject then make necessary telemetry updates (this is why we catch unpack)
|
// If this is a metaobject then make necessary telemetry updates
|
||||||
if (objInfo.obj.isMetadata())
|
// (this is why we catch unpack)
|
||||||
{
|
if (objInfo.obj.isMetadata()) {
|
||||||
UAVMetaObject metaobj = (UAVMetaObject) objInfo.obj;
|
UAVMetaObject metaobj = (UAVMetaObject) objInfo.obj;
|
||||||
updateObject(metaobj.getParentObject());
|
updateObject(metaobj.getParentObject());
|
||||||
}
|
}
|
||||||
Log.e(TAG, "C");
|
|
||||||
// 3. Execute transaction
|
// 3. Execute transaction
|
||||||
if (transPending)
|
if (transPending) {
|
||||||
{
|
|
||||||
Log.e(TAG, "D");
|
|
||||||
try {
|
try {
|
||||||
if (DEBUG || true) Log.d(TAG, "Process Object transaction for " + transInfo.obj.getName());
|
if (DEBUG) Log.d(TAG, "Process Object transaction for " + transInfo.obj.getName());
|
||||||
|
|
||||||
// Initiate transaction
|
// Initiate transaction
|
||||||
if (transInfo.objRequest)
|
if (transInfo.objRequest) {
|
||||||
{
|
if (DEBUG) Log.d(TAG, "Sending object request");
|
||||||
utalk.sendObjectRequest(transInfo.obj, transInfo.allInstances);
|
utalk.sendObjectRequest(transInfo.obj, transInfo.allInstances);
|
||||||
}
|
} else {
|
||||||
else
|
if (DEBUG) Log.d(TAG, "Sending object " + transInfo.obj.getName() + " " + transInfo.obj.toStringData());
|
||||||
{
|
|
||||||
Log.d(TAG, "Sending object");
|
|
||||||
utalk.sendObject(transInfo.obj, transInfo.acked, transInfo.allInstances);
|
utalk.sendObject(transInfo.obj, transInfo.acked, transInfo.allInstances);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Block if request expected (??)
|
// TODO: Block if request expected (??)
|
||||||
if ( transInfo.objRequest || transInfo.acked )
|
if (transInfo.objRequest || transInfo.acked ) {
|
||||||
{
|
|
||||||
transTimerSetPeriod(REQ_TIMEOUT_MS);
|
transTimerSetPeriod(REQ_TIMEOUT_MS);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
synchronized(transTimer) {
|
synchronized(transTimer) {
|
||||||
transTimer.cancel();
|
transTimer.cancel();
|
||||||
transPending = false;
|
transPending = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
Log.e(TAG, "E");
|
Log.e(TAG, "E");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user