1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-18 03:52:11 +01:00

OP-1122 OP-1125 uavtalk - fixed a number of issues concerning acked multi instance messages :

- all messages now systematically include an instance ID (fixes parsing of messages containing unknown object)
- added missing NACK of object request on fight side
- added more logging and warnings
- misc fixes and cleanups
this commit affects both the firmware and GCS (need to flash new version of firmware)
This commit is contained in:
Philippe Renon 2013-11-26 01:27:25 +01:00
parent 1469277f96
commit 2f0974fda9
7 changed files with 356 additions and 287 deletions

View File

@ -34,10 +34,9 @@
// Private functions
static int32_t objectTransaction(UAVTalkConnectionData *connection, UAVObjHandle objectId, uint16_t instId, uint8_t type, int32_t timeout);
static int32_t sendObject(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type);
static int32_t sendSingleObject(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type);
static int32_t sendNack(UAVTalkConnectionData *connection, uint32_t objId);
static int32_t objectTransaction(UAVTalkConnectionData *connection, uint8_t type, UAVObjHandle obj, uint16_t instId, int32_t timeout);
static int32_t sendObject(UAVTalkConnectionData *connection, uint8_t type, uint32_t objId, uint16_t instId, UAVObjHandle obj);
static int32_t sendSingleObject(UAVTalkConnectionData *connection, uint8_t type, uint32_t objId, uint16_t instId, UAVObjHandle obj);
static int32_t receiveObject(UAVTalkConnectionData *connection, uint8_t type, uint32_t objId, uint16_t instId, uint8_t *data, int32_t length);
static void updateAck(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId);
@ -213,7 +212,8 @@ int32_t UAVTalkSendObjectRequest(UAVTalkConnection connectionHandle, UAVObjHandl
UAVTalkConnectionData *connection;
CHECKCONHANDLE(connectionHandle, connection, return -1);
return objectTransaction(connection, obj, instId, UAVTALK_TYPE_OBJ_REQ, timeout);
return objectTransaction(connection, UAVTALK_TYPE_OBJ_REQ, obj, instId, timeout);
}
/**
@ -231,11 +231,12 @@ int32_t UAVTalkSendObject(UAVTalkConnection connectionHandle, UAVObjHandle obj,
UAVTalkConnectionData *connection;
CHECKCONHANDLE(connectionHandle, connection, return -1);
// Send object
if (acked == 1) {
return objectTransaction(connection, obj, instId, UAVTALK_TYPE_OBJ_ACK, timeoutMs);
return objectTransaction(connection, UAVTALK_TYPE_OBJ_ACK, obj, instId, timeoutMs);
} else {
return objectTransaction(connection, obj, instId, UAVTALK_TYPE_OBJ, timeoutMs);
return objectTransaction(connection, UAVTALK_TYPE_OBJ, obj, instId, timeoutMs);
}
}
@ -254,27 +255,29 @@ int32_t UAVTalkSendObjectTimestamped(UAVTalkConnection connectionHandle, UAVObjH
UAVTalkConnectionData *connection;
CHECKCONHANDLE(connectionHandle, connection, return -1);
// Send object
if (acked == 1) {
return objectTransaction(connection, obj, instId, UAVTALK_TYPE_OBJ_ACK_TS, timeoutMs);
return objectTransaction(connection, UAVTALK_TYPE_OBJ_ACK_TS, obj, instId, timeoutMs);
} else {
return objectTransaction(connection, obj, instId, UAVTALK_TYPE_OBJ_TS, timeoutMs);
return objectTransaction(connection, UAVTALK_TYPE_OBJ_TS, obj, instId, timeoutMs);
}
}
/**
* Execute the requested transaction on an object.
* \param[in] connection UAVTalkConnection to be used
* \param[in] obj Object
* \param[in] instId The instance ID of UAVOBJ_ALL_INSTANCES for all instances.
* \param[in] type Transaction type
* UAVTALK_TYPE_OBJ: send object,
* UAVTALK_TYPE_OBJ_REQ: request object update
* UAVTALK_TYPE_OBJ_ACK: send object with an ack
* \param[in] obj Object
* \param[in] instId The instance ID of UAVOBJ_ALL_INSTANCES for all instances.
* \param[in] timeoutMs Time to wait for the ack, when zero it will return immediately
* \return 0 Success
* \return -1 Failure
*/
static int32_t objectTransaction(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type, int32_t timeoutMs)
static int32_t objectTransaction(UAVTalkConnectionData *connection, uint8_t type, UAVObjHandle obj, uint16_t instId, int32_t timeoutMs)
{
int32_t respReceived;
@ -286,7 +289,7 @@ static int32_t objectTransaction(UAVTalkConnectionData *connection, UAVObjHandle
xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY);
connection->respObj = obj;
connection->respInstId = instId;
sendObject(connection, obj, instId, type);
sendObject(connection, type, UAVObjGetID(obj), instId, obj);
xSemaphoreGiveRecursive(connection->lock);
// Wait for response (or timeout)
respReceived = xSemaphoreTake(connection->respSema, timeoutMs / portTICK_RATE_MS);
@ -305,7 +308,7 @@ static int32_t objectTransaction(UAVTalkConnectionData *connection, UAVObjHandle
}
} else if (type == UAVTALK_TYPE_OBJ || type == UAVTALK_TYPE_OBJ_TS) {
xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY);
sendObject(connection, obj, instId, type);
sendObject(connection, type, UAVObjGetID(obj), instId, obj);
xSemaphoreGiveRecursive(connection->lock);
return 0;
} else {
@ -326,6 +329,7 @@ UAVTalkRxState UAVTalkProcessInputStreamQuiet(UAVTalkConnection connectionHandle
CHECKCONHANDLE(connectionHandle, connection, return -1);
UAVTalkInputProcessor *iproc = &connection->iproc;
++connection->stats.rxBytes;
if (iproc->state == UAVTALK_STATE_ERROR || iproc->state == UAVTALK_STATE_COMPLETE) {
@ -338,6 +342,7 @@ UAVTalkRxState UAVTalkProcessInputStreamQuiet(UAVTalkConnection connectionHandle
// Receive state machine
switch (iproc->state) {
case UAVTALK_STATE_SYNC:
if (rxbyte != UAVTALK_SYNC_VAL) {
break;
}
@ -408,19 +413,18 @@ UAVTalkRxState UAVTalkProcessInputStreamQuiet(UAVTalkConnection connectionHandle
// Determine data length
if (iproc->type == UAVTALK_TYPE_OBJ_REQ || iproc->type == UAVTALK_TYPE_ACK || iproc->type == UAVTALK_TYPE_NACK) {
iproc->length = 0;
iproc->instanceLength = 0;
} else {
if (iproc->obj) {
iproc->length = UAVObjGetNumBytes(iproc->obj);
iproc->instanceLength = (UAVObjIsSingleInstance(iproc->obj) ? 0 : 2);
} else {
// We don't know if it's a multi-instance object, so just assume it's 0.
iproc->instanceLength = 0;
iproc->length = iproc->packet_size - iproc->rxPacketLength;
}
iproc->timestampLength = (iproc->type & UAVTALK_TIMESTAMPED) ? 2 : 0;
}
// Message always contain an instance ID
iproc->instanceLength = 2;
// Check length and determine next state
if (iproc->length >= UAVTALK_MAX_PAYLOAD_LENGTH) {
connection->stats.rxErrors++;
@ -435,28 +439,9 @@ UAVTalkRxState UAVTalkProcessInputStreamQuiet(UAVTalkConnection connectionHandle
break;
}
iproc->instId = 0;
if (iproc->type == UAVTALK_TYPE_NACK) {
// If this is a NACK, we skip to Checksum
iproc->state = UAVTALK_STATE_CS;
}
// Check if this is a single instance object (i.e. if the instance ID field is coming next)
else if ((iproc->obj != 0) && !UAVObjIsSingleInstance(iproc->obj)) {
iproc->state = UAVTALK_STATE_INSTID;
}
// Check if this is a single instance and has a timestamp in it
else if ((iproc->obj != 0) && (iproc->type & UAVTALK_TIMESTAMPED)) {
iproc->timestamp = 0;
iproc->state = UAVTALK_STATE_TIMESTAMP;
} else {
// If there is a payload get it, otherwise receive checksum
if (iproc->length > 0) {
iproc->state = UAVTALK_STATE_DATA;
} else {
iproc->state = UAVTALK_STATE_CS;
}
}
iproc->rxCount = 0;
iproc->instId = 0;
iproc->state = UAVTALK_STATE_INSTID;
break;
@ -713,8 +698,12 @@ static int32_t receiveObject(UAVTalkConnectionData *connection,
// Lock
xSemaphoreTakeRecursive(connection->lock, portMAX_DELAY);
// Get the handle to the Object. Will be zero
// if object does not exist.
// Get the handle to the Object.
// Will be zero if object does not exist.
// Warning :
// Here we ask for instance ID 0 without taking into account the provided instId
// The provided instId will be used later when packing, unpacking, etc...
// TODO the above should be fixed as it is cumbersome and error prone
obj = UAVObjGetByID(objId);
// Process message type
@ -724,9 +713,15 @@ static int32_t receiveObject(UAVTalkConnectionData *connection,
// All instances, not allowed for OBJ messages
if (obj && (instId != UAVOBJ_ALL_INSTANCES)) {
// Unpack object, if the instance does not exist it will be created!
UAVObjUnpack(obj, instId, data);
// Check if an ack is pending
updateAck(connection, obj, instId);
if (UAVObjUnpack(obj, instId, data)) {
// Check if an ack is pending OBJ_ACK below
// TODO is it necessary to do that check?
// TODO if yes, why is the same check not done for OBJ_ACK below?
updateAck(connection, obj, instId);
}
else {
ret = -1;
}
} else {
ret = -1;
}
@ -738,22 +733,30 @@ static int32_t receiveObject(UAVTalkConnectionData *connection,
if (obj && (instId != UAVOBJ_ALL_INSTANCES)) {
// Unpack object, if the instance does not exist it will be created!
if (UAVObjUnpack(obj, instId, data) == 0) {
// Transmit ACK
sendObject(connection, obj, instId, UAVTALK_TYPE_ACK);
// Object updated or created, transmit ACK
sendObject(connection, UAVTALK_TYPE_ACK, objId, instId, NULL);
} else {
ret = -1;
}
} else {
ret = -1;
}
if (ret == -1) {
// failed to update object, transmit NACK
sendObject(connection, UAVTALK_TYPE_NACK, objId, instId, NULL);
}
break;
case UAVTALK_TYPE_OBJ_REQ:
// Send requested object if message is of type OBJ_REQ
if (obj == 0) {
// Transmit NACK
sendNack(connection, objId);
// Check if requested object exists
if (obj && ((instId == UAVOBJ_ALL_INSTANCES) || instId < UAVObjGetNumInstances(obj))) {
// Object found, transmit it
sendObject(connection, UAVTALK_TYPE_OBJ, objId, instId, obj);
} else {
sendObject(connection, obj, instId, UAVTALK_TYPE_OBJ);
ret = -1;
}
if (ret == -1) {
// failed to send object, transmit NACK
sendObject(connection, UAVTALK_TYPE_NACK, objId, instId, NULL);
}
break;
case UAVTALK_TYPE_NACK:
@ -762,7 +765,7 @@ static int32_t receiveObject(UAVTalkConnectionData *connection,
case UAVTALK_TYPE_ACK:
// All instances, not allowed for ACK messages
if (obj && (instId != UAVOBJ_ALL_INSTANCES)) {
// Check if an ack is pending
// Check if an ACK is pending
updateAck(connection, obj, instId);
} else {
ret = -1;
@ -796,19 +799,22 @@ static void updateAck(UAVTalkConnectionData *connection, UAVObjHandle obj, uint1
/**
* Send an object through the telemetry link.
* \param[in] connection UAVTalkConnection to be used
* \param[in] obj Object handle to send
* \param[in] instId The instance ID or UAVOBJ_ALL_INSTANCES for all instances
* \param[in] type Transaction type
* \param[in] objId The object ID
* \param[in] instId The instance ID or UAVOBJ_ALL_INSTANCES for all instances
* \param[in] obj Object handle to send (null when type is NACK)
* \return 0 Success
* \return -1 Failure
*/
static int32_t sendObject(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type)
static int32_t sendObject(UAVTalkConnectionData *connection, uint8_t type, uint32_t objId, uint16_t instId, UAVObjHandle obj)
{
uint32_t numInst;
uint32_t n;
// Important note : obj can be null (when type is NACK for example) so protect all obj dereferences.
// If all instances are requested and this is a single instance object, force instance ID to zero
if (instId == UAVOBJ_ALL_INSTANCES && UAVObjIsSingleInstance(obj)) {
if ((obj != NULL) && (instId == UAVOBJ_ALL_INSTANCES) && UAVObjIsSingleInstance(obj)) {
instId = 0;
}
@ -819,17 +825,17 @@ static int32_t sendObject(UAVTalkConnectionData *connection, UAVObjHandle obj, u
numInst = UAVObjGetNumInstances(obj);
// Send all instances
for (n = 0; n < numInst; ++n) {
sendSingleObject(connection, obj, n, type);
sendSingleObject(connection, type, objId, n, obj);
}
return 0;
} else {
return sendSingleObject(connection, obj, instId, type);
return sendSingleObject(connection, type, objId, instId, obj);
}
} else if (type == UAVTALK_TYPE_OBJ_REQ) {
return sendSingleObject(connection, obj, instId, UAVTALK_TYPE_OBJ_REQ);
} else if (type == UAVTALK_TYPE_ACK) {
return sendSingleObject(connection, UAVTALK_TYPE_OBJ_REQ, objId, instId, obj);
} else if (type == UAVTALK_TYPE_ACK || type == UAVTALK_TYPE_NACK) {
if (instId != UAVOBJ_ALL_INSTANCES) {
return sendSingleObject(connection, obj, instId, UAVTALK_TYPE_ACK);
return sendSingleObject(connection, type, objId, instId, obj);
} else {
return -1;
}
@ -841,24 +847,26 @@ static int32_t sendObject(UAVTalkConnectionData *connection, UAVObjHandle obj, u
/**
* Send an object through the telemetry link.
* \param[in] connection UAVTalkConnection to be used
* \param[in] obj Object handle to send
* \param[in] instId The instance ID (can NOT be UAVOBJ_ALL_INSTANCES, use sendObject() instead)
* \param[in] type Transaction type
* \param[in] objId The object ID
* \param[in] instId The instance ID (can NOT be UAVOBJ_ALL_INSTANCES, use
() instead)
* \param[in] obj Object handle to send (null when type is NACK)
* \return 0 Success
* \return -1 Failure
*/
static int32_t sendSingleObject(UAVTalkConnectionData *connection, UAVObjHandle obj, uint16_t instId, uint8_t type)
static int32_t sendSingleObject(UAVTalkConnectionData *connection, uint8_t type, uint32_t objId, uint16_t instId, UAVObjHandle obj)
{
int32_t length;
int32_t dataOffset;
uint32_t objId;
// Important note : obj can be null (when type is NACK for example) so protect all obj dereferences.
if (!connection->outStream) {
return -1;
}
// Setup type and object id fields
objId = UAVObjGetID(obj);
connection->txBuffer[0] = UAVTALK_SYNC_VAL; // sync byte
connection->txBuffer[1] = type;
// data length inserted here below
@ -866,15 +874,12 @@ static int32_t sendSingleObject(UAVTalkConnectionData *connection, UAVObjHandle
connection->txBuffer[5] = (uint8_t)((objId >> 8) & 0xFF);
connection->txBuffer[6] = (uint8_t)((objId >> 16) & 0xFF);
connection->txBuffer[7] = (uint8_t)((objId >> 24) & 0xFF);
dataOffset = 8;
// Setup instance ID if one is required
if (UAVObjIsSingleInstance(obj)) {
dataOffset = 8;
} else {
connection->txBuffer[8] = (uint8_t)(instId & 0xFF);
connection->txBuffer[9] = (uint8_t)((instId >> 8) & 0xFF);
dataOffset = 10;
}
// The instance ID is always sent
connection->txBuffer[8] = (uint8_t)(instId & 0xFF);
connection->txBuffer[9] = (uint8_t)((instId >> 8) & 0xFF);
dataOffset += 2;
// Add timestamp when the transaction type is appropriate
if (type & UAVTALK_TIMESTAMPED) {
@ -885,7 +890,7 @@ static int32_t sendSingleObject(UAVTalkConnectionData *connection, UAVObjHandle
}
// Determine data length
if (type == UAVTALK_TYPE_OBJ_REQ || type == UAVTALK_TYPE_ACK) {
if (type == UAVTALK_TYPE_OBJ_REQ || type == UAVTALK_TYPE_ACK || type == UAVTALK_TYPE_NACK) {
length = 0;
} else {
length = UAVObjGetNumBytes(obj);
@ -924,50 +929,6 @@ static int32_t sendSingleObject(UAVTalkConnectionData *connection, UAVObjHandle
return 0;
}
/**
* Send a NACK through the telemetry link.
* \param[in] connection UAVTalkConnection to be used
* \param[in] objId Object ID to send a NACK for
* \return 0 Success
* \return -1 Failure
*/
static int32_t sendNack(UAVTalkConnectionData *connection, uint32_t objId)
{
int32_t dataOffset;
if (!connection->outStream) {
return -1;
}
connection->txBuffer[0] = UAVTALK_SYNC_VAL; // sync byte
connection->txBuffer[1] = UAVTALK_TYPE_NACK;
// data length inserted here below
connection->txBuffer[4] = (uint8_t)(objId & 0xFF);
connection->txBuffer[5] = (uint8_t)((objId >> 8) & 0xFF);
connection->txBuffer[6] = (uint8_t)((objId >> 16) & 0xFF);
connection->txBuffer[7] = (uint8_t)((objId >> 24) & 0xFF);
dataOffset = 8;
// Store the packet length
connection->txBuffer[2] = (uint8_t)((dataOffset) & 0xFF);
connection->txBuffer[3] = (uint8_t)(((dataOffset) >> 8) & 0xFF);
// Calculate checksum
connection->txBuffer[dataOffset] = PIOS_CRC_updateCRC(0, connection->txBuffer, dataOffset);
uint16_t tx_msg_len = dataOffset + UAVTALK_CHECKSUM_LENGTH;
int32_t rc = (*connection->outStream)(connection->txBuffer, tx_msg_len);
if (rc == tx_msg_len) {
// Update stats
connection->stats.txBytes += tx_msg_len;
}
// Done
return 0;
}
/**
* @}
* @}

View File

@ -436,6 +436,7 @@ QString UAVObject::toString()
QString sout;
sout.append(toStringBrief());
sout.append('\n');
sout.append(toStringData());
return sout;
}
@ -447,12 +448,12 @@ QString UAVObject::toStringBrief()
{
QString sout;
sout.append(QString("%1 (ID: %2, InstID: %3, NumBytes: %4, SInst: %5)\n")
sout.append(QString("%1 (ID: %2:%3, %4bytes, %5)")
.arg(getName())
.arg(getObjID())
.arg(getInstID())
.arg(getNumBytes())
.arg(isSingleInstance()));
.arg(isSingleInstance() ? "single" : "multiple"));
return sout;
}

View File

@ -65,9 +65,8 @@ Telemetry::Telemetry(UAVTalk *utalk, UAVObjectManager *objMngr)
Telemetry::~Telemetry()
{
for (QMap<quint32, ObjectTransactionInfo *>::iterator itr = transMap.begin(); itr != transMap.end(); ++itr) {
delete itr.value();
}
closeAllTransactions();
}
/**
@ -122,6 +121,7 @@ void Telemetry::setUpdatePeriod(UAVObject *obj, qint32 periodMs)
*/
void Telemetry::connectToObjectInstances(UAVObject *obj, quint32 eventMask)
{
// TODO why connect systematically to all instances?
QList<UAVObject *> objs = objMngr->getObjectInstances(obj->getObjID());
for (int n = 0; n < objs.length(); ++n) {
// Disconnect all
@ -211,21 +211,25 @@ void Telemetry::updateObject(UAVObject *obj, quint32 eventType)
void Telemetry::transactionCompleted(UAVObject *obj, bool success)
{
// Lookup the transaction in the transaction map.
quint32 objId = obj->getObjID();
QMap<quint32, ObjectTransactionInfo *>::iterator itr = transMap.find(objId);
if (itr != transMap.end()) {
ObjectTransactionInfo *transInfo = itr.value();
ObjectTransactionInfo *transInfo = findTransaction(obj);
if (transInfo) {
// Remove this transaction as it's complete.
transInfo->timer->stop();
transMap.remove(objId);
closeTransaction(transInfo);
delete transInfo;
// Send signal
if (success) {
#ifdef VERBOSE_TELEMETRY
qDebug() << "Telemetry - transaction successful for object" << obj->toStringBrief();
#endif
} else {
qWarning() << "Telemetry - !!! transaction failed for object" << obj->toStringBrief();
}
obj->emitTransactionCompleted(success);
// Process new object updates from queue
processObjectQueue();
} else {
qDebug() << "Error: received a transaction completed when did not expect it.";
qWarning() << "Telemetry - Error: received a transaction completed when did not expect it for" << obj->toStringBrief();
}
}
@ -237,6 +241,9 @@ void Telemetry::transactionTimeout(ObjectTransactionInfo *transInfo)
transInfo->timer->stop();
// Check if more retries are pending
if (transInfo->retriesRemaining > 0) {
#ifdef VERBOSE_TELEMETRY
qDebug() << QString("Telemetry - transaction timed out for object %1, retrying...").arg(transInfo->obj->toStringBrief());
#endif
--transInfo->retriesRemaining;
processObjectTransaction(transInfo);
++txRetries;
@ -246,9 +253,11 @@ void Telemetry::transactionTimeout(ObjectTransactionInfo *transInfo)
// Terminate transaction
utalk->cancelTransaction(transInfo->obj);
// Send signal
qWarning() << QString("Telemetry - !!! transaction timed out for object %1").arg(transInfo->obj->toStringBrief());
transInfo->obj->emitTransactionCompleted(false);
// Remove this transaction as it's complete.
transMap.remove(transInfo->obj->getObjID());
// FIXME : also remove transaction from UAVTalk transaction map
closeTransaction(transInfo);
delete transInfo;
// Process new object updates from queue
processObjectQueue();
@ -263,8 +272,14 @@ void Telemetry::processObjectTransaction(ObjectTransactionInfo *transInfo)
{
// Initiate transaction
if (transInfo->objRequest) {
#ifdef VERBOSE_TELEMETRY
qDebug() << QString("Telemetry - sending object request for %1 - %2").arg(transInfo->obj->toStringBrief()).arg(transInfo->acked ? "acked" : "");
#endif
utalk->sendObjectRequest(transInfo->obj, transInfo->allInstances);
} else {
#ifdef VERBOSE_TELEMETRY
qDebug() << QString("Telemetry - sending object %1 - %2").arg(transInfo->obj->toStringBrief()).arg(transInfo->acked ? "acked" : "");
#endif
utalk->sendObject(transInfo->obj, transInfo->acked, transInfo->allInstances);
}
// Start timer if a response is expected
@ -272,7 +287,7 @@ void Telemetry::processObjectTransaction(ObjectTransactionInfo *transInfo)
transInfo->timer->start(REQ_TIMEOUT_MS);
} else {
// Otherwise, remove this transaction as it's complete.
transMap.remove(transInfo->obj->getObjID());
closeTransaction(transInfo);
delete transInfo;
}
}
@ -293,14 +308,15 @@ void Telemetry::processObjectUpdates(UAVObject *obj, EventMask event, bool allIn
objPriorityQueue.enqueue(objInfo);
} else {
++txErrors;
qWarning() << QString("Telemetry - !!! priority event queue is full, event lost (%1)").arg(obj->toStringBrief());
obj->emitTransactionCompleted(false);
qDebug() << tr("Telemetry: priority event queue is full, event lost (%1)").arg(obj->getName());
}
} else {
if (objQueue.length() < MAX_QUEUE_SIZE) {
objQueue.enqueue(objInfo);
} else {
++txErrors;
qWarning() << QString("Telemetry - !!! event queue is full, event lost (%1)").arg(obj->toStringBrief());
obj->emitTransactionCompleted(false);
}
}
@ -340,9 +356,10 @@ void Telemetry::processObjectQueue()
UAVObject::Metadata metadata = objInfo.obj->getMetadata();
UAVObject::UpdateMode updateMode = UAVObject::GetGcsTelemetryUpdateMode(metadata);
if ((objInfo.event != EV_UNPACKED) && ((objInfo.event != EV_UPDATED_PERIODIC) || (updateMode != UAVObject::UPDATEMODE_THROTTLED))) {
QMap<quint32, ObjectTransactionInfo *>::iterator itr = transMap.find(objInfo.obj->getObjID());
if (itr != transMap.end()) {
qDebug() << "!!!!!! Making request for an object: " << objInfo.obj->getName() << " for which a request is already in progress!!!!!!";
if (findTransaction(objInfo.obj)) {
qWarning() << QString("Telemetry - !!! Making request for an object: %1 for which a request is already in progress").arg(objInfo.obj->toStringBrief());
objInfo.obj->emitTransactionCompleted(false);
return;
}
UAVObject::Metadata metadata = objInfo.obj->getMetadata();
ObjectTransactionInfo *transInfo = new ObjectTransactionInfo(this);
@ -357,7 +374,7 @@ void Telemetry::processObjectQueue()
}
transInfo->telem = this;
// Insert the transaction into the transaction map.
transMap.insert(objInfo.obj->getObjID(), transInfo);
openTransaction(transInfo);
processObjectTransaction(transInfo);
}
@ -396,6 +413,7 @@ void Telemetry::processPeriodicUpdates()
qint32 elapsedMs = 0;
QTime time;
qint32 offset;
bool allInstances;
for (int n = 0; n < objList.length(); ++n) {
objinfo = &objList[n];
// If object is configured for periodic updates
@ -408,7 +426,8 @@ void Telemetry::processPeriodicUpdates()
objinfo->timeToNextUpdateMs = objinfo->updatePeriodMs - offset;
// Send object
time.start();
processObjectUpdates(objinfo->obj, EV_UPDATED_PERIODIC, true, false);
allInstances = !objinfo->obj->isSingleInstance();
processObjectUpdates(objinfo->obj, EV_UPDATED_PERIODIC, allInstances, false);
elapsedMs = time.elapsed();
// Update timeToNextUpdateMs with the elapsed delay of sending the object;
timeToNextUpdateMs += elapsedMs;
@ -496,7 +515,6 @@ void Telemetry::objectUnpacked(UAVObject *obj)
void Telemetry::updateRequested(UAVObject *obj)
{
QMutexLocker locker(mutex);
processObjectUpdates(obj, EV_UPDATE_REQ, false, true);
}
@ -514,6 +532,51 @@ void Telemetry::newInstance(UAVObject *obj)
registerObject(obj);
}
ObjectTransactionInfo *Telemetry::findTransaction(UAVObject *obj)
{
// Lookup the transaction in the transaction map
QMap<quint32, ObjectTransactionInfo *> *objTransactions = transMap.value(obj->getObjID());
if (objTransactions != NULL) {
return objTransactions->value(obj->getInstID());
}
return NULL;
}
void Telemetry::openTransaction(ObjectTransactionInfo *trans)
{
QMap<quint32, ObjectTransactionInfo *> *objTransactions = transMap.value(trans->obj->getObjID());
if (objTransactions == NULL) {
objTransactions = new QMap<quint32, ObjectTransactionInfo *>();
transMap.insert(trans->obj->getObjID(), objTransactions);
}
objTransactions->insert(trans->obj->getInstID(), trans);
}
void Telemetry::closeTransaction(ObjectTransactionInfo *trans)
{
QMap<quint32, ObjectTransactionInfo *> *objTransactions = transMap.value(trans->obj->getObjID());
if (objTransactions != NULL) {
objTransactions->remove(trans->obj->getInstID());
// Keep the map even if it is empty
// There are at most 100 different object IDs...
}
}
void Telemetry::closeAllTransactions()
{
foreach(quint32 objId, transMap.keys()) {
QMap<quint32, ObjectTransactionInfo *> *objTransactions = transMap.value(objId);
foreach(quint32 instId, objTransactions->keys()) {
ObjectTransactionInfo *trans = objTransactions->value(instId);
qWarning() << "Telemetry - closing active transaction for object" << trans->obj->toStringBrief();
objTransactions->remove(instId);
delete trans;
}
transMap.remove(objId);
delete objTransactions;
}
}
ObjectTransactionInfo::ObjectTransactionInfo(QObject *parent) : QObject(parent)
{
obj = 0;

View File

@ -118,7 +118,7 @@ private:
QList<ObjectTimeInfo> objList;
QQueue<ObjectQueueInfo> objQueue;
QQueue<ObjectQueueInfo> objPriorityQueue;
QMap<quint32, ObjectTransactionInfo *>transMap;
QMap<quint32, QMap<quint32, ObjectTransactionInfo *> *> transMap;
QMutex *mutex;
QTimer *updateTimer;
QTimer *statsTimer;
@ -136,6 +136,11 @@ private:
void processObjectTransaction(ObjectTransactionInfo *transInfo);
void processObjectQueue();
ObjectTransactionInfo *findTransaction(UAVObject *obj);
void openTransaction(ObjectTransactionInfo *trans);
void closeTransaction(ObjectTransactionInfo *trans);
void closeAllTransactions();
private slots:
void objectUpdatedAuto(UAVObject *obj);
void objectUpdatedManual(UAVObject *obj);

View File

@ -94,6 +94,7 @@ UAVTalk::~UAVTalk()
// According to Qt, it is not necessary to disconnect upon
// object deletion.
// disconnect(io, SIGNAL(readyRead()), this, SLOT(processInputStream()));
closeAllTransactions();
}
@ -154,7 +155,7 @@ bool UAVTalk::sendObjectRequest(UAVObject *obj, bool allInstances)
{
QMutexLocker locker(mutex);
return objectTransaction(obj, TYPE_OBJ_REQ, allInstances);
return objectTransaction(TYPE_OBJ_REQ, obj, allInstances);
}
/**
@ -169,9 +170,9 @@ bool UAVTalk::sendObject(UAVObject *obj, bool acked, bool allInstances)
QMutexLocker locker(mutex);
if (acked) {
return objectTransaction(obj, TYPE_OBJ_ACK, allInstances);
return objectTransaction(TYPE_OBJ_ACK, obj, allInstances);
} else {
return objectTransaction(obj, TYPE_OBJ, allInstances);
return objectTransaction(TYPE_OBJ, obj, allInstances);
}
}
@ -181,15 +182,14 @@ bool UAVTalk::sendObject(UAVObject *obj, bool acked, bool allInstances)
void UAVTalk::cancelTransaction(UAVObject *obj)
{
QMutexLocker locker(mutex);
quint32 objId = obj->getObjID();
if (io.isNull()) {
return;
}
QMap<quint32, Transaction *>::iterator itr = transMap.find(objId);
if (itr != transMap.end()) {
transMap.remove(objId);
delete itr.value();
Transaction *trans = findTransaction(obj);
if (trans != NULL) {
closeTransaction(trans);
delete trans;
}
}
@ -203,21 +203,24 @@ void UAVTalk::cancelTransaction(UAVObject *obj)
* \param[in] allInstances If set true then all instances will be updated
* \return Success (true), Failure (false)
*/
bool UAVTalk::objectTransaction(UAVObject *obj, quint8 type, bool allInstances)
bool UAVTalk::objectTransaction(quint8 type, UAVObject *obj, bool allInstances)
{
Q_ASSERT(obj);
// Send object depending on if a response is needed
// transactions of TYPE_OBJ_REQ are acked by the response
quint16 instId = allInstances ? ALL_INSTANCES : obj->getInstID();
if (type == TYPE_OBJ_ACK || type == TYPE_OBJ_REQ) {
if (transmitObject(obj, type, allInstances)) {
if (transmitObject(type, obj->getObjID(), instId, obj)) {
Transaction *trans = new Transaction();
trans->obj = obj;
trans->allInstances = allInstances;
transMap.insert(obj->getObjID(), trans);
openTransaction(trans);
return true;
} else {
return false;
}
} else if (type == TYPE_OBJ) {
return transmitObject(obj, TYPE_OBJ, allInstances);
return transmitObject(type, obj->getObjID(), instId, obj);
} else {
return false;
}
@ -233,7 +236,8 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
// Update stats
stats.rxBytes++;
rxPacketLength++; // update packet byte count
// update packet byte count
rxPacketLength++;
if (useUDPMirror) {
rxDataArray.append(rxbyte);
@ -332,12 +336,13 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
// Determine data length
if (rxType == TYPE_OBJ_REQ || rxType == TYPE_ACK || rxType == TYPE_NACK) {
rxLength = 0;
rxInstanceLength = 0;
} else {
rxLength = rxObj->getNumBytes();
rxInstanceLength = (rxObj->isSingleInstance() ? 0 : 2);
}
// The instance ID is always sent
rxInstanceLength = 2;
// Check length and determine next state
if (rxLength >= MAX_PAYLOAD_LENGTH) {
stats.rxErrors++;
@ -347,39 +352,18 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
}
// Check the lengths match
if ((rxPacketLength + rxInstanceLength + rxLength) != packetSize) { // packet error - mismatched packet size
if ((rxPacketLength + rxInstanceLength + rxLength) != packetSize) {
// packet error - mismatched packet size
stats.rxErrors++;
rxState = STATE_SYNC;
UAVTALK_QXTLOG_DEBUG("UAVTalk: ObjID->Sync (length mismatch)");
break;
}
// Check if this is a single instance object (i.e. if the instance ID field is coming next)
if (rxObj == NULL) {
// This is a non-existing object, just skip to checksum
// and we'll send a NACK next.
rxState = STATE_CS;
UAVTALK_QXTLOG_DEBUG("UAVTalk: ObjID->CSum (no obj)");
rxInstId = 0;
rxCount = 0;
} else if (rxObj->isSingleInstance()) {
// If there is a payload get it, otherwise receive checksum
if (rxLength > 0) {
rxState = STATE_DATA;
UAVTALK_QXTLOG_DEBUG("UAVTalk: ObjID->Data (needs data)");
} else {
rxState = STATE_CS;
UAVTALK_QXTLOG_DEBUG("UAVTalk: ObjID->Checksum");
}
rxInstId = 0;
rxCount = 0;
} else {
rxState = STATE_INSTID;
UAVTALK_QXTLOG_DEBUG("UAVTalk: ObjID->InstID");
rxCount = 0;
}
rxCount = 0;
rxInstId = 0;
rxState = STATE_INSTID;
}
break;
case STATE_INSTID:
@ -428,14 +412,16 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
// The CRC byte
rxCSPacket = rxbyte;
if (rxCS != rxCSPacket) { // packet error - faulty CRC
if (rxCS != rxCSPacket) {
// packet error - faulty CRC
stats.rxErrors++;
rxState = STATE_SYNC;
UAVTALK_QXTLOG_DEBUG("UAVTalk: CSum->Sync (badcrc)");
break;
}
if (rxPacketLength != packetSize + 1) { // packet error - mismatched packet size
if (rxPacketLength != packetSize + 1) {
// packet error - mismatched packet size
stats.rxErrors++;
rxState = STATE_SYNC;
UAVTALK_QXTLOG_DEBUG("UAVTalk: CSum->Sync (length mismatch)");
@ -443,12 +429,16 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
}
mutex->lock();
receiveObject(rxType, rxObjId, rxInstId, rxBuffer, rxLength);
if (useUDPMirror) {
udpSocketTx->writeDatagram(rxDataArray, QHostAddress::LocalHost, udpSocketRx->localPort());
}
stats.rxObjectBytes += rxLength;
stats.rxObjects++;
mutex->unlock();
rxState = STATE_SYNC;
@ -456,6 +446,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
break;
default:
rxState = STATE_SYNC;
stats.rxErrors++;
UAVTALK_QXTLOG_DEBUG("UAVTalk: \?\?\?->Sync"); // Use the escape character for '?' so that the tripgraph isn't triggered.
@ -488,8 +479,13 @@ bool UAVTalk::receiveObject(quint8 type, quint32 objId, quint16 instId, quint8 *
if (!allInstances) {
// Get object and update its data
obj = updateObject(objId, instId, data);
// Check if an ack is pending
#ifdef VERBOSE_UAVTALK
qDebug() << "UAVTalk - received object" << objId << instId << (obj != NULL ? obj->toStringBrief() : "<null object>");
#endif
if (obj != NULL) {
// Check if an ACK is pending
// TODO is it necessary to do that check?
// TODO if yes, why is the same check not done for OBJ_ACK below?
updateAck(obj);
} else {
error = true;
@ -503,40 +499,55 @@ bool UAVTalk::receiveObject(quint8 type, quint32 objId, quint16 instId, quint8 *
if (!allInstances) {
// Get object and update its data
obj = updateObject(objId, instId, data);
// Transmit ACK
#ifdef VERBOSE_UAVTALK
qDebug() << "UAVTalk - received object (acked)" << objId << instId << (obj != NULL ? obj->toStringBrief() : "<null object>");
#endif
if (obj != NULL) {
transmitObject(obj, TYPE_ACK, false);
// Object updated or created, transmit ACK
transmitObject(TYPE_ACK, objId, instId, obj);
} else {
error = true;
}
} else {
error = true;
}
if (error) {
// failed to update object, transmit NACK
transmitObject(TYPE_NACK, objId, instId, NULL);
}
break;
case TYPE_OBJ_REQ:
// Get object, if all instances are requested get instance 0 of the object
// Check if requested object exists
if (allInstances) {
// All instances, so get instance zero
obj = objMngr->getObject(objId);
} else {
obj = objMngr->getObject(objId, instId);
}
// If object was found transmit it
#ifdef VERBOSE_UAVTALK
qDebug() << "UAVTalk - received object request" << objId << instId << (obj != NULL ? obj->toStringBrief() : "<null object>");
#endif
if (obj != NULL) {
transmitObject(obj, TYPE_OBJ, allInstances);
// Object found, transmit it
transmitObject(TYPE_OBJ, objId, instId, obj);
} else {
// Object was not found, transmit a NACK with the
// objId which was not found.
transmitNack(objId);
error = true;
}
if (error) {
// failed to send object, transmit NACK
transmitObject(TYPE_NACK, objId, instId, NULL);
}
break;
case TYPE_NACK:
// All instances, not allowed for NACK messages
if (!allInstances) {
// Get object
obj = objMngr->getObject(objId, instId);
// Check if object exists:
#ifdef VERBOSE_UAVTALK
qDebug() << "UAVTalk - received nack" << objId << instId << (obj != NULL ? obj->toStringBrief() : "<null object>");
#endif
if (obj != NULL) {
// Check if a NACK is pending
updateNack(obj);
} else {
error = true;
@ -548,8 +559,11 @@ bool UAVTalk::receiveObject(quint8 type, quint32 objId, quint16 instId, quint8 *
if (!allInstances) {
// Get object
obj = objMngr->getObject(objId, instId);
// Check if an ack is pending
#ifdef VERBOSE_UAVTALK
qDebug() << "UAVTalk - received ack" << objId << instId << (obj != NULL ? obj->toStringBrief() : "<null object>");
#endif
if (obj != NULL) {
// Check if an ACK is pending
updateAck(obj);
} else {
error = true;
@ -559,6 +573,9 @@ bool UAVTalk::receiveObject(quint8 type, quint32 objId, quint16 instId, quint8 *
default:
error = true;
}
if (error) {
qWarning() << "UAVTalk - !!! error receiving object" << objId << instId << (obj != NULL ? obj->toStringBrief() : "<null object>");
}
// Done
return !error;
}
@ -608,65 +625,70 @@ void UAVTalk::updateNack(UAVObject *obj)
if (!obj) {
return;
}
quint32 objId = obj->getObjID();
QMap<quint32, Transaction *>::iterator itr = transMap.find(objId);
if (itr != transMap.end() && (itr.value()->obj->getInstID() == obj->getInstID() || itr.value()->allInstances)) {
transMap.remove(objId);
delete itr.value();
Transaction *trans = findTransaction(obj);
// TODO handle allInstances
if (trans != NULL /* || itr.value()->allInstances)*/) {
closeTransaction(trans);
delete trans;
emit transactionCompleted(obj, false);
}
}
/**
* Check if a transaction is pending and if yes complete it.
*/
void UAVTalk::updateAck(UAVObject *obj)
{
quint32 objId = obj->getObjID();
QMap<quint32, Transaction *>::iterator itr = transMap.find(objId);
if (itr != transMap.end() && (itr.value()->obj->getInstID() == obj->getInstID() || itr.value()->allInstances)) {
transMap.remove(objId);
delete itr.value();
Q_ASSERT(obj);
if (!obj) {
return;
}
Transaction *trans = findTransaction(obj);
// TODO handle allInstances
if (trans != NULL /* || itr.value()->allInstances)*/) {
closeTransaction(trans);
delete trans;
emit transactionCompleted(obj, true);
}
}
/**
* Send an object through the telemetry link.
* \param[in] obj Object to send
* \param[in] type Transaction type
* \param[in] allInstances True is all instances of the object are to be sent
* \param[in] objId Object ID to send
* \param[in] instId Instance ID to send
* \param[in] obj Object to send (null when type is NACK)
* \return Success (true), Failure (false)
*/
bool UAVTalk::transmitObject(UAVObject *obj, quint8 type, bool allInstances)
bool UAVTalk::transmitObject(quint8 type, quint32 objId, quint16 instId, UAVObject *obj)
{
// Important note : obj can be null (when type is NACK for example) so protect all obj dereferences.
// If all instances are requested on a single instance object it is an error
if (allInstances && obj->isSingleInstance()) {
allInstances = false;
if ((obj != NULL) && (instId == ALL_INSTANCES) && obj->isSingleInstance()) {
instId = 0;
}
bool allInstances = (instId == ALL_INSTANCES);
// Process message type
if (type == TYPE_OBJ || type == TYPE_OBJ_ACK) {
if (allInstances) {
// Get number of instances
quint32 numInst = objMngr->getNumInstances(obj->getObjID());
quint32 numInst = objMngr->getNumInstances(objId);
// Send all instances
for (quint32 instId = 0; instId < numInst; ++instId) {
UAVObject *inst = objMngr->getObject(obj->getObjID(), instId);
transmitSingleObject(inst, type, false);
for (quint32 n = 0; n < numInst; ++n) {
UAVObject *o = objMngr->getObject(objId, n);
transmitSingleObject(type, objId, n, o);
}
return true;
} else {
return transmitSingleObject(obj, type, false);
return transmitSingleObject(type, objId, instId, obj);
}
} else if (type == TYPE_OBJ_REQ) {
return transmitSingleObject(obj, TYPE_OBJ_REQ, allInstances);
} else if (type == TYPE_ACK) {
return transmitSingleObject(TYPE_OBJ_REQ, objId, instId, obj);
} else if (type == TYPE_ACK || type == TYPE_NACK) {
if (!allInstances) {
return transmitSingleObject(obj, TYPE_ACK, false);
return transmitSingleObject(type, objId, instId, obj);
} else {
return false;
}
@ -675,78 +697,35 @@ bool UAVTalk::transmitObject(UAVObject *obj, quint8 type, bool allInstances)
}
}
/**
* Transmit a NACK through the telemetry link.
* \param[in] objId the ObjectID we rejected
*/
bool UAVTalk::transmitNack(quint32 objId)
{
int dataOffset = 8;
txBuffer[0] = SYNC_VAL;
txBuffer[1] = TYPE_NACK;
qToLittleEndian<quint32>(objId, &txBuffer[4]);
// Calculate checksum
txBuffer[dataOffset] = updateCRC(0, txBuffer, dataOffset);
qToLittleEndian<quint16>(dataOffset, &txBuffer[2]);
// Send buffer, check that the transmit backlog does not grow above limit
if (io && io->isWritable() && io->bytesToWrite() < TX_BUFFER_SIZE) {
io->write((const char *)txBuffer, dataOffset + CHECKSUM_LENGTH);
if (useUDPMirror) {
udpSocketRx->writeDatagram((const char *)txBuffer, dataOffset + CHECKSUM_LENGTH, QHostAddress::LocalHost, udpSocketTx->localPort());
}
} else {
++stats.txErrors;
return false;
}
// Update stats
stats.txBytes += 8 + CHECKSUM_LENGTH;
// Done
return true;
}
/**
* Send an object through the telemetry link.
* \param[in] obj Object handle to send
* \param[in] type Transaction type
* \param[in] objId Object ID to send
* \param[in] instId Instance ID to send
* \param[in] obj Object to send (null when type is NACK)
* \return Success (true), Failure (false)
*/
bool UAVTalk::transmitSingleObject(UAVObject *obj, quint8 type, bool allInstances)
bool UAVTalk::transmitSingleObject(quint8 type, quint32 objId, quint16 instId, UAVObject *obj)
{
#ifdef VERBOSE_UAVTALK
qDebug() << "UAVTalk - transmitting object" << objId << instId << (obj != NULL ? obj->toStringBrief() : "<null object>");
#endif
qint32 length;
qint32 dataOffset;
quint32 objId;
quint16 instId;
quint16 allInstId = ALL_INSTANCES;
// Setup type and object id fields
objId = obj->getObjID();
txBuffer[0] = SYNC_VAL;
txBuffer[1] = type;
// data length inserted here below
qToLittleEndian<quint32>(objId, &txBuffer[4]);
dataOffset = 8;
// Setup instance ID if one is required
if (obj->isSingleInstance()) {
dataOffset = 8;
} else {
// Check if all instances are requested
if (allInstances) {
qToLittleEndian<quint16>(allInstId, &txBuffer[8]);
} else {
instId = obj->getInstID();
qToLittleEndian<quint16>(instId, &txBuffer[8]);
}
dataOffset = 10;
}
// The instance ID is always sent
qToLittleEndian<quint16>(instId, &txBuffer[8]);
dataOffset += 2;
// Determine data length
if (type == TYPE_OBJ_REQ || type == TYPE_ACK) {
if (type == TYPE_OBJ_REQ || type == TYPE_ACK || type == TYPE_NACK) {
length = 0;
} else {
length = obj->getNumBytes();
@ -811,6 +790,7 @@ quint8 UAVTalk::updateCRC(quint8 crc, const quint8 data)
{
return crc_table[crc ^ data];
}
quint8 UAVTalk::updateCRC(quint8 crc, const quint8 *data, qint32 length)
{
while (length--) {
@ -818,3 +798,48 @@ quint8 UAVTalk::updateCRC(quint8 crc, const quint8 *data, qint32 length)
}
return crc;
}
UAVTalk::Transaction *UAVTalk::findTransaction(UAVObject *obj)
{
// Lookup the transaction in the transaction map
QMap<quint32, Transaction *> *objTransactions = transMap.value(obj->getObjID());
if (objTransactions != NULL) {
return objTransactions->value(obj->getInstID());
}
return NULL;
}
void UAVTalk::openTransaction(Transaction *trans)
{
QMap<quint32, Transaction *> *objTransactions = transMap.value(trans->obj->getObjID());
if (objTransactions == NULL) {
objTransactions = new QMap<quint32, Transaction *>();
transMap.insert(trans->obj->getObjID(), objTransactions);
}
objTransactions->insert(trans->obj->getInstID(), trans);
}
void UAVTalk::closeTransaction(Transaction *trans)
{
QMap<quint32, Transaction *> *objTransactions = transMap.value(trans->obj->getObjID());
if (objTransactions != NULL) {
objTransactions->remove(trans->obj->getInstID());
// Keep the map even if it is empty
// There are at most 100 different object IDs...
}
}
void UAVTalk::closeAllTransactions()
{
foreach(quint32 objId, transMap.keys()) {
QMap<quint32, Transaction *> *objTransactions = transMap.value(objId);
foreach(quint32 instId, objTransactions->keys()) {
Transaction *trans = objTransactions->value(instId);
qWarning() << "UAVTalk - closing active transaction for object" << trans->obj->toStringBrief();
objTransactions->remove(instId);
delete trans;
}
transMap.remove(objId);
delete objTransactions;
}
}

View File

@ -93,7 +93,6 @@ private:
static const int MAX_PACKET_LENGTH = (MAX_HEADER_LENGTH + MAX_PAYLOAD_LENGTH + CHECKSUM_LENGTH);
static const quint16 ALL_INSTANCES = 0xFFFF;
static const quint16 OBJID_NOTFOUND = 0x0000;
static const int TX_BUFFER_SIZE = 2 * 1024;
static const quint8 crc_table[256];
@ -105,7 +104,7 @@ private:
QPointer<QIODevice> io;
UAVObjectManager *objMngr;
QMutex *mutex;
QMap<quint32, Transaction *> transMap;
QMap<quint32, QMap<quint32, Transaction *> *> transMap;
quint8 rxBuffer[MAX_PACKET_LENGTH];
quint8 txBuffer[MAX_PACKET_LENGTH];
// Variables used by the receive state machine
@ -129,17 +128,21 @@ private:
QByteArray rxDataArray;
// Methods
bool objectTransaction(UAVObject *obj, quint8 type, bool allInstances);
bool objectTransaction(quint8 type, UAVObject *obj, bool allInstances);
bool processInputByte(quint8 rxbyte);
bool receiveObject(quint8 type, quint32 objId, quint16 instId, quint8 *data, qint32 length);
UAVObject *updateObject(quint32 objId, quint16 instId, quint8 *data);
void updateAck(UAVObject *obj);
void updateNack(UAVObject *obj);
bool transmitNack(quint32 objId);
bool transmitObject(UAVObject *obj, quint8 type, bool allInstances);
bool transmitSingleObject(UAVObject *obj, quint8 type, bool allInstances);
bool transmitObject(quint8 type, quint32 objId, quint16 instId, UAVObject *obj);
bool transmitSingleObject(quint8 type, quint32 objId, quint16 instId, UAVObject *obj);
quint8 updateCRC(quint8 crc, const quint8 data);
quint8 updateCRC(quint8 crc, const quint8 *data, qint32 length);
Transaction *findTransaction(UAVObject *obj);
void openTransaction(Transaction *trans);
void closeTransaction(Transaction *trans);
void closeAllTransactions();
};
#endif // UAVTALK_H

View File

@ -1,18 +1,29 @@
QT += network
TEMPLATE = lib
TARGET = UAVTalk
QT += network
DEFINES += UAVTALK_LIBRARY
#DEFINES += VERBOSE_TELEMETRY
#DEFINES += VERBOSE_UAVTALK
include(../../openpilotgcsplugin.pri)
include(uavtalk_dependencies.pri)
HEADERS += uavtalk.h \
HEADERS += \
uavtalk.h \
uavtalkplugin.h \
telemetrymonitor.h \
telemetrymanager.h \
uavtalk_global.h \
telemetry.h
SOURCES += uavtalk.cpp \
SOURCES += \
uavtalk.cpp \
uavtalkplugin.cpp \
telemetrymonitor.cpp \
telemetrymanager.cpp \
telemetry.cpp
DEFINES += UAVTALK_LIBRARY
OTHER_FILES += UAVTalk.pluginspec