1
0
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:
James Cotton 2012-08-13 23:47:37 -05:00
parent 2d7bb4d3bb
commit 653702ac23

View File

@ -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");