Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / plugins / uavobjects / uavobjectfield.cpp
blob5bf0a02aac6dde410c3da1027032abafb40e1328
1 /**
2 ******************************************************************************
4 * @file uavobjectfield.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @see The GNU Public License (GPL) Version 3
7 * @addtogroup GCSPlugins GCS Plugins
8 * @{
9 * @addtogroup UAVObjectsPlugin UAVObjects Plugin
10 * @{
11 * @brief The UAVUObjects GCS plugin
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "uavobjectfield.h"
30 #include <QtEndian>
31 #include <QDebug>
32 #include <QXmlStreamWriter>
33 #include <QXmlStreamReader>
34 #include <QJsonObject>
35 #include <QJsonArray>
37 UAVObjectField::UAVObjectField(const QString & name, const QString & description, const QString & units, FieldType type, quint32 numElements, const QStringList & options, const QString &limits)
39 QStringList elementNames;
41 // Set element names
42 for (quint32 n = 0; n < numElements; ++n) {
43 elementNames.append(QString("%1").arg(n));
45 // Initialize
46 constructorInitialize(name, description, units, type, elementNames, options, limits);
49 UAVObjectField::UAVObjectField(const QString & name, const QString & description, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits)
51 constructorInitialize(name, description, units, type, elementNames, options, limits);
54 void UAVObjectField::constructorInitialize(const QString & name, const QString & description, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits)
56 // Copy params
57 this->name = name;
58 this->description = description;
59 this->units = units;
60 this->type = type;
61 this->options = options;
62 this->numElements = elementNames.length();
63 this->offset = 0;
64 this->data = NULL;
65 this->obj = NULL;
66 this->elementNames = elementNames;
67 // Set field size
68 switch (type) {
69 case INT8:
70 numBytesPerElement = sizeof(qint8);
71 break;
72 case INT16:
73 numBytesPerElement = sizeof(qint16);
74 break;
75 case INT32:
76 numBytesPerElement = sizeof(qint32);
77 break;
78 case UINT8:
79 numBytesPerElement = sizeof(quint8);
80 break;
81 case UINT16:
82 numBytesPerElement = sizeof(quint16);
83 break;
84 case UINT32:
85 numBytesPerElement = sizeof(quint32);
86 break;
87 case FLOAT32:
88 numBytesPerElement = sizeof(quint32);
89 break;
90 case ENUM:
91 numBytesPerElement = sizeof(quint8);
92 break;
93 case BITFIELD:
94 numBytesPerElement = sizeof(quint8);
95 this->options = QStringList() << tr("0") << tr("1");
96 break;
97 case STRING:
98 numBytesPerElement = sizeof(quint8);
99 break;
100 default:
101 numBytesPerElement = 0;
103 limitsInitialize(limits);
106 void UAVObjectField::limitsInitialize(const QString &limits)
108 // Limit string format:
109 // % - start char
110 // XXXX - optional BOARD_TYPE and BOARD_REVISION (4 hex digits)
111 // TY - rule type (EQ-equal, NE-not equal, BE-between, BI-bigger, SM-smaller)
112 // VAL - values for TY separated by colon
113 // , - rule separator (may have leading or trailing spaces)
114 // ; - element separator (may have leading or trailing spaces)
116 // Examples:
117 // Disable few flight modes for Revo (00903):
118 // "%0903NE:Autotune:VelocityControl:PositionHold:ReturnToBase:Land:PathPlanner"
119 // Original CC board (rev 1), first element bigger than 3 and second element inside [2.3-5.0]:
120 // "%0401BI:3; %BE:2.3:5"
121 // Set applicable range [0-500] for 3 elements of array for all boards:
122 // "%BE:0:500; %BE:0:500; %BE:0:500"
123 if (limits.isEmpty()) {
124 return;
126 QStringList stringPerElement = limits.split(";");
127 quint32 index = 0;
128 foreach(QString str, stringPerElement) {
129 QStringList ruleList = str.split(",");
131 QList<LimitStruct> limitList;
132 foreach(QString rule, ruleList) {
133 QString _str = rule.trimmed();
135 if (_str.isEmpty()) {
136 continue;
138 QStringList valuesPerElement = _str.split(":");
139 LimitStruct lstruc;
140 bool startFlag = valuesPerElement.at(0).startsWith("%");
141 bool maxIndexFlag = (int)(index) < (int)numElements;
142 bool elemNumberSizeFlag = valuesPerElement.at(0).size() == 3;
143 bool aux;
144 valuesPerElement.at(0).mid(1, 4).toInt(&aux, 16);
145 bool b4 = ((valuesPerElement.at(0).size()) == 7 && aux);
146 if (startFlag && maxIndexFlag && (elemNumberSizeFlag || b4)) {
147 if (b4) {
148 lstruc.board = valuesPerElement.at(0).mid(1, 4).toInt(&aux, 16);
149 } else {
150 lstruc.board = 0;
152 if (valuesPerElement.at(0).right(2) == "EQ") {
153 lstruc.type = EQUAL;
154 } else if (valuesPerElement.at(0).right(2) == "NE") {
155 lstruc.type = NOT_EQUAL;
156 } else if (valuesPerElement.at(0).right(2) == "BE") {
157 lstruc.type = BETWEEN;
158 } else if (valuesPerElement.at(0).right(2) == "BI") {
159 lstruc.type = BIGGER;
160 } else if (valuesPerElement.at(0).right(2) == "SM") {
161 lstruc.type = SMALLER;
162 } else {
163 qDebug() << "limits parsing failed (invalid property) on UAVObjectField" << name;
165 valuesPerElement.removeAt(0);
166 foreach(QString _value, valuesPerElement) {
167 QString value = _value.trimmed();
169 switch (type) {
170 case UINT8:
171 case UINT16:
172 case UINT32:
173 case BITFIELD:
174 lstruc.values.append((quint32)value.toULong());
175 break;
176 case INT8:
177 case INT16:
178 case INT32:
179 lstruc.values.append((qint32)value.toLong());
180 break;
181 case FLOAT32:
182 lstruc.values.append((float)value.toFloat());
183 break;
184 case ENUM:
185 lstruc.values.append((QString)value);
186 break;
187 case STRING:
188 lstruc.values.append((QString)value);
189 break;
190 default:
191 lstruc.values.append(QVariant());
194 limitList.append(lstruc);
195 } else {
196 if (!valuesPerElement.at(0).isEmpty() && !startFlag) {
197 qDebug() << "limits parsing failed (property doesn't start with %) on UAVObjectField" << name;
198 } else if (!maxIndexFlag) {
199 qDebug() << "limits parsing failed (index>numelements) on UAVObjectField" << name << "index" << index << "numElements" << numElements;
200 } else if (!elemNumberSizeFlag || !b4) {
201 qDebug() << "limits parsing failed limit not starting with %XX or %YYYYXX where XX is the limit type and YYYY is the board type on UAVObjectField" << name;
205 elementLimits.insert(index, limitList);
206 ++index;
208 // foreach(QList<LimitStruct> limitList, elementLimits) {
209 // foreach(LimitStruct limit, limitList) {
210 // qDebug() << "Limit type" << limit.type << "for board" << limit.board << "for field" << getName();
211 // foreach(QVariant var, limit.values) {
212 // qDebug() << "value" << var;
213 // }
214 // }
215 // }
217 bool UAVObjectField::isWithinLimits(QVariant var, quint32 index, int board)
219 if (!elementLimits.keys().contains(index)) {
220 return true;
223 foreach(LimitStruct struc, elementLimits.value(index)) {
224 if ((struc.board != board) && board != 0 && struc.board != 0) {
225 continue;
227 switch (struc.type) {
228 case EQUAL:
229 switch (type) {
230 case INT8:
231 case INT16:
232 case INT32:
233 foreach(QVariant vars, struc.values) {
234 if (var.toInt() == vars.toInt()) {
235 return true;
238 return false;
240 break;
241 case UINT8:
242 case UINT16:
243 case UINT32:
244 case BITFIELD:
245 foreach(QVariant vars, struc.values) {
246 if (var.toUInt() == vars.toUInt()) {
247 return true;
250 return false;
252 break;
253 case ENUM:
254 case STRING:
255 foreach(QVariant vars, struc.values) {
256 if (var.toString() == vars.toString()) {
257 return true;
260 return false;
262 break;
263 case FLOAT32:
264 foreach(QVariant vars, struc.values) {
265 if (var.toFloat() == vars.toFloat()) {
266 return true;
269 return false;
271 break;
272 default:
273 return true;
275 break;
276 case NOT_EQUAL:
277 switch (type) {
278 case INT8:
279 case INT16:
280 case INT32:
281 foreach(QVariant vars, struc.values) {
282 if (var.toInt() == vars.toInt()) {
283 return false;
286 return true;
288 break;
289 case UINT8:
290 case UINT16:
291 case UINT32:
292 case BITFIELD:
293 foreach(QVariant vars, struc.values) {
294 if (var.toUInt() == vars.toUInt()) {
295 return false;
298 return true;
300 break;
301 case ENUM:
302 case STRING:
303 foreach(QVariant vars, struc.values) {
304 if (var.toString() == vars.toString()) {
305 return false;
308 return true;
310 break;
311 case FLOAT32:
312 foreach(QVariant vars, struc.values) {
313 if (var.toFloat() == vars.toFloat()) {
314 return false;
317 return true;
319 break;
320 default:
321 return true;
323 break;
324 case BETWEEN:
325 if (struc.values.length() < 2) {
326 qDebug() << __FUNCTION__ << "between limit with less than 1 pair, aborting; field:" << name;
327 return true;
329 if (struc.values.length() > 2) {
330 qDebug() << __FUNCTION__ << "between limit with more than 1 pair, using first; field" << name;
332 switch (type) {
333 case INT8:
334 case INT16:
335 case INT32:
336 if (!(var.toInt() >= struc.values.at(0).toInt() && var.toInt() <= struc.values.at(1).toInt())) {
337 return false;
339 return true;
341 break;
342 case UINT8:
343 case UINT16:
344 case UINT32:
345 case BITFIELD:
346 if (!(var.toUInt() >= struc.values.at(0).toUInt() && var.toUInt() <= struc.values.at(1).toUInt())) {
347 return false;
349 return true;
351 break;
352 case ENUM:
353 if (!(options.indexOf(var.toString()) >= options.indexOf(struc.values.at(0).toString()) && options.indexOf(var.toString()) <= options.indexOf(struc.values.at(1).toString()))) {
354 return false;
356 return true;
358 break;
359 case STRING:
360 return true;
362 break;
363 case FLOAT32:
364 if (!(var.toFloat() >= struc.values.at(0).toFloat() && var.toFloat() <= struc.values.at(1).toFloat())) {
365 return false;
367 return true;
369 break;
370 default:
371 return true;
373 break;
374 case BIGGER:
375 if (struc.values.length() < 1) {
376 qDebug() << __FUNCTION__ << "BIGGER limit with less than 1 value, aborting; field:" << name;
377 return true;
379 if (struc.values.length() > 1) {
380 qDebug() << __FUNCTION__ << "BIGGER limit with more than 1 value, using first; field" << name;
382 switch (type) {
383 case INT8:
384 case INT16:
385 case INT32:
386 if (!(var.toInt() >= struc.values.at(0).toInt())) {
387 return false;
389 return true;
391 break;
392 case UINT8:
393 case UINT16:
394 case UINT32:
395 case BITFIELD:
396 if (!(var.toUInt() >= struc.values.at(0).toUInt())) {
397 return false;
399 return true;
401 break;
402 case ENUM:
403 if (!(options.indexOf(var.toString()) >= options.indexOf(struc.values.at(0).toString()))) {
404 return false;
406 return true;
408 break;
409 case STRING:
410 return true;
412 break;
413 case FLOAT32:
414 if (!(var.toFloat() >= struc.values.at(0).toFloat())) {
415 return false;
417 return true;
419 break;
420 default:
421 return true;
423 break;
424 case SMALLER:
425 switch (type) {
426 case INT8:
427 case INT16:
428 case INT32:
429 if (!(var.toInt() <= struc.values.at(0).toInt())) {
430 return false;
432 return true;
434 break;
435 case UINT8:
436 case UINT16:
437 case UINT32:
438 case BITFIELD:
439 if (!(var.toUInt() <= struc.values.at(0).toUInt())) {
440 return false;
442 return true;
444 break;
445 case ENUM:
446 if (!(options.indexOf(var.toString()) <= options.indexOf(struc.values.at(0).toString()))) {
447 return false;
449 return true;
451 break;
452 case STRING:
453 return true;
455 break;
456 case FLOAT32:
457 if (!(var.toFloat() <= struc.values.at(0).toFloat())) {
458 return false;
460 return true;
462 break;
463 default:
464 return true;
466 default:
467 return true;
470 return true;
473 QString UAVObjectField::getLimitsAsString(quint32 index, int board)
475 QString limitString;
477 if (elementLimits.keys().contains(index)) {
478 foreach(LimitStruct struc, elementLimits.value(index)) {
479 if ((struc.board != board) && board != 0 && struc.board != 0) {
480 continue;
482 switch (struc.type) {
483 case EQUAL:
485 limitString.append(tr("one of")).append(" [");
486 bool first = true;
487 foreach(QVariant var, struc.values) {
488 if (!first) {
489 limitString.append(", ");
491 limitString.append(var.toString());
492 first = false;
494 return limitString.append("]");
496 case NOT_EQUAL:
498 limitString.append(tr("none of")).append(" [");
499 bool first = true;
500 foreach(QVariant var, struc.values) {
501 if (!first) {
502 limitString.append(", ");
504 limitString.append(var.toString());
505 first = false;
507 return limitString.append("]");
509 case BIGGER: return limitString.append(QString("%1 %2").arg(tr("more than"), struc.values.at(0).toString()));
511 case BETWEEN: return limitString.append(QString("%1 %2 %3 %4")
512 .arg(tr("between"), struc.values.at(0).toString(),
513 tr(" and "), struc.values.at(1).toString()));
515 case SMALLER: return limitString.append(QString("%1 %2").arg(tr("less than"), struc.values.at(0).toString()));
517 default:
518 break;
522 return limitString;
525 QVariant UAVObjectField::getMaxLimit(quint32 index, int board)
527 if (!elementLimits.keys().contains(index)) {
528 return QVariant();
530 foreach(LimitStruct struc, elementLimits.value(index)) {
531 if ((struc.board != board) && board != 0 && struc.board != 0) {
532 continue;
534 switch (struc.type) {
535 case EQUAL:
536 case NOT_EQUAL:
537 case BIGGER:
538 return QVariant();
540 case BETWEEN:
541 return struc.values.at(1);
543 case SMALLER:
544 return struc.values.at(0);
546 default:
547 return QVariant();
550 return QVariant();
552 QVariant UAVObjectField::getMinLimit(quint32 index, int board)
554 if (!elementLimits.keys().contains(index)) {
555 return QVariant();
557 foreach(LimitStruct struc, elementLimits.value(index)) {
558 if ((struc.board != board) && board != 0 && struc.board != 0) {
559 return QVariant();
561 switch (struc.type) {
562 case EQUAL:
563 case NOT_EQUAL:
564 case SMALLER:
565 return QVariant();
567 case BETWEEN:
568 return struc.values.at(0);
570 case BIGGER:
571 return struc.values.at(0);
573 default:
574 return QVariant();
577 return QVariant();
579 void UAVObjectField::initialize(quint8 *data, quint32 dataOffset, UAVObject *obj)
581 this->data = data;
582 this->offset = dataOffset;
583 this->obj = obj;
584 clear();
587 UAVObjectField::FieldType UAVObjectField::getType()
589 return type;
592 QString UAVObjectField::getTypeAsString()
594 switch (type) {
595 case UAVObjectField::INT8:
596 return "int8";
598 case UAVObjectField::INT16:
599 return "int16";
601 case UAVObjectField::INT32:
602 return "int32";
604 case UAVObjectField::UINT8:
605 return "uint8";
607 case UAVObjectField::UINT16:
608 return "uint16";
610 case UAVObjectField::UINT32:
611 return "uint32";
613 case UAVObjectField::FLOAT32:
614 return "float32";
616 case UAVObjectField::ENUM:
617 return "enum";
619 case UAVObjectField::BITFIELD:
620 return "bitfield";
622 case UAVObjectField::STRING:
623 return "string";
625 default:
626 return "";
630 QStringList UAVObjectField::getElementNames()
632 return elementNames;
635 UAVObject *UAVObjectField::getObject()
637 return obj;
640 void UAVObjectField::clear()
642 QMutexLocker locker(obj->getMutex());
644 switch (type) {
645 case BITFIELD:
646 memset(&data[offset], 0, numBytesPerElement * ((quint32)(1 + (numElements - 1) / 8)));
647 break;
648 default:
649 memset(&data[offset], 0, numBytesPerElement * numElements);
650 break;
654 QString UAVObjectField::getName()
656 return name;
659 QString UAVObjectField::getDescription()
661 return description;
664 QString UAVObjectField::getUnits()
666 return units;
669 QStringList UAVObjectField::getOptions()
671 return options;
674 quint32 UAVObjectField::getNumElements()
676 return numElements;
679 quint32 UAVObjectField::getDataOffset()
681 return offset;
684 quint32 UAVObjectField::getNumBytes()
686 switch (type) {
687 case BITFIELD:
688 return numBytesPerElement * ((quint32)(1 + (numElements - 1) / 8));
690 break;
691 default:
692 return numBytesPerElement * numElements;
694 break;
698 QString UAVObjectField::toString()
700 QString sout;
702 sout.append(QString("%1: [ ").arg(name));
703 for (unsigned int n = 0; n < numElements; ++n) {
704 sout.append(QString("%1 ").arg(getDouble(n)));
706 sout.append(QString("] %1\n").arg(units));
707 return sout;
710 void UAVObjectField::toXML(QXmlStreamWriter *xmlWriter)
712 xmlWriter->writeStartElement("field");
713 xmlWriter->writeAttribute("name", getName());
714 xmlWriter->writeAttribute("type", getTypeAsString());
715 if (!getUnits().isEmpty()) {
716 xmlWriter->writeAttribute("unit", getUnits());
718 for (unsigned int n = 0; n < numElements; ++n) {
719 xmlWriter->writeStartElement("value");
720 if (getElementNames().size() > 1) {
721 xmlWriter->writeAttribute("name", getElementNames().at(n));
723 xmlWriter->writeCharacters(getValue(n).toString());
724 xmlWriter->writeEndElement(); // value
726 xmlWriter->writeEndElement(); // field
729 void UAVObjectField::fromXML(QXmlStreamReader *xmlReader)
731 // Assert we have the correct field by name
732 Q_ASSERT(xmlReader->name() == "field");
733 Q_ASSERT(xmlReader->attributes().value("name") == getName());
734 // Read values, skip overflowing ones if any
735 while (xmlReader->readNextStartElement()) {
736 if (xmlReader->name() == "value") {
737 int index = getElementNames().indexOf(xmlReader->attributes().value("name").toString());
738 if (index >= 0) {
739 setValue(xmlReader->readElementText(), index);
745 void UAVObjectField::toJson(QJsonObject &jsonObject)
747 jsonObject["name"] = getName();
748 jsonObject["type"] = getTypeAsString();
749 jsonObject["unit"] = getUnits();
750 QJsonArray values;
751 for (unsigned int n = 0; n < numElements; ++n) {
752 QJsonObject value;
753 value["name"] = getElementNames().at(n);
754 value["value"] = QJsonValue::fromVariant(getValue(n));
755 values.append(value);
757 jsonObject["values"] = values;
760 void UAVObjectField::fromJson(const QJsonObject &jsonObject)
762 Q_ASSERT(jsonObject["name"].toString() == getName());
763 QJsonArray jsonValues = jsonObject["values"].toArray();
764 for (int i = 0; i < jsonValues.size(); i++) {
765 QJsonObject jsonValue = jsonValues.at(i).toObject();
766 int index = getElementNames().indexOf(jsonValue["name"].toString());
767 if (index >= 0) {
768 setValue(((QJsonValue)jsonValue["value"]).toVariant(), index);
773 qint32 UAVObjectField::pack(quint8 *dataOut)
775 QMutexLocker locker(obj->getMutex());
777 // Pack each element in output buffer
778 switch (type) {
779 case INT8:
780 memcpy(dataOut, &data[offset], numElements);
781 break;
782 case INT16:
783 for (quint32 index = 0; index < numElements; ++index) {
784 qint16 value;
785 memcpy(&value, &data[offset + numBytesPerElement * index], numBytesPerElement);
786 qToLittleEndian<qint16>(value, &dataOut[numBytesPerElement * index]);
788 break;
789 case INT32:
790 for (quint32 index = 0; index < numElements; ++index) {
791 qint32 value;
792 memcpy(&value, &data[offset + numBytesPerElement * index], numBytesPerElement);
793 qToLittleEndian<qint32>(value, &dataOut[numBytesPerElement * index]);
795 break;
796 case UINT8:
797 for (quint32 index = 0; index < numElements; ++index) {
798 dataOut[numBytesPerElement * index] = data[offset + numBytesPerElement * index];
800 break;
801 case UINT16:
802 for (quint32 index = 0; index < numElements; ++index) {
803 quint16 value;
804 memcpy(&value, &data[offset + numBytesPerElement * index], numBytesPerElement);
805 qToLittleEndian<quint16>(value, &dataOut[numBytesPerElement * index]);
807 break;
808 case UINT32:
809 for (quint32 index = 0; index < numElements; ++index) {
810 quint32 value;
811 memcpy(&value, &data[offset + numBytesPerElement * index], numBytesPerElement);
812 qToLittleEndian<quint32>(value, &dataOut[numBytesPerElement * index]);
814 break;
815 case FLOAT32:
816 for (quint32 index = 0; index < numElements; ++index) {
817 quint32 value;
818 memcpy(&value, &data[offset + numBytesPerElement * index], numBytesPerElement);
819 qToLittleEndian<quint32>(value, &dataOut[numBytesPerElement * index]);
821 break;
822 case ENUM:
823 for (quint32 index = 0; index < numElements; ++index) {
824 dataOut[numBytesPerElement * index] = data[offset + numBytesPerElement * index];
826 break;
827 case BITFIELD:
828 for (quint32 index = 0; index < (quint32)(1 + (numElements - 1) / 8); ++index) {
829 dataOut[numBytesPerElement * index] = data[offset + numBytesPerElement * index];
831 break;
832 case STRING:
833 memcpy(dataOut, &data[offset], numElements);
834 break;
836 // Done
837 return getNumBytes();
840 qint32 UAVObjectField::unpack(const quint8 *dataIn)
842 QMutexLocker locker(obj->getMutex());
844 // Unpack each element from input buffer
845 switch (type) {
846 case INT8:
847 memcpy(&data[offset], dataIn, numElements);
848 break;
849 case INT16:
850 for (quint32 index = 0; index < numElements; ++index) {
851 qint16 value;
852 value = qFromLittleEndian<qint16>(&dataIn[numBytesPerElement * index]);
853 memcpy(&data[offset + numBytesPerElement * index], &value, numBytesPerElement);
855 break;
856 case INT32:
857 for (quint32 index = 0; index < numElements; ++index) {
858 qint32 value;
859 value = qFromLittleEndian<qint32>(&dataIn[numBytesPerElement * index]);
860 memcpy(&data[offset + numBytesPerElement * index], &value, numBytesPerElement);
862 break;
863 case UINT8:
864 for (quint32 index = 0; index < numElements; ++index) {
865 data[offset + numBytesPerElement * index] = dataIn[numBytesPerElement * index];
867 break;
868 case UINT16:
869 for (quint32 index = 0; index < numElements; ++index) {
870 quint16 value;
871 value = qFromLittleEndian<quint16>(&dataIn[numBytesPerElement * index]);
872 memcpy(&data[offset + numBytesPerElement * index], &value, numBytesPerElement);
874 break;
875 case UINT32:
876 for (quint32 index = 0; index < numElements; ++index) {
877 quint32 value;
878 value = qFromLittleEndian<quint32>(&dataIn[numBytesPerElement * index]);
879 memcpy(&data[offset + numBytesPerElement * index], &value, numBytesPerElement);
881 break;
882 case FLOAT32:
883 for (quint32 index = 0; index < numElements; ++index) {
884 quint32 value;
885 value = qFromLittleEndian<quint32>(&dataIn[numBytesPerElement * index]);
886 memcpy(&data[offset + numBytesPerElement * index], &value, numBytesPerElement);
888 break;
889 case ENUM:
890 for (quint32 index = 0; index < numElements; ++index) {
891 data[offset + numBytesPerElement * index] = dataIn[numBytesPerElement * index];
893 break;
894 case BITFIELD:
895 for (quint32 index = 0; index < (quint32)(1 + (numElements - 1) / 8); ++index) {
896 data[offset + numBytesPerElement * index] = dataIn[numBytesPerElement * index];
898 break;
899 case STRING:
900 memcpy(&data[offset], dataIn, numElements);
901 break;
903 // Done
904 return getNumBytes();
907 bool UAVObjectField::isNumeric()
909 switch (type) {
910 case INT8:
911 case INT16:
912 case INT32:
913 case UINT8:
914 case UINT16:
915 case UINT32:
916 case FLOAT32:
917 case BITFIELD:
918 return true;
920 break;
921 default:
922 return false;
926 bool UAVObjectField::isInteger()
928 switch (type) {
929 case INT8:
930 case INT16:
931 case INT32:
932 case UINT8:
933 case UINT16:
934 case UINT32:
935 return true;
937 break;
938 default:
939 return false;
943 bool UAVObjectField::isText()
945 switch (type) {
946 case ENUM:
947 case STRING:
948 return true;
950 break;
951 default:
952 return false;
956 QVariant UAVObjectField::getValue(quint32 index)
958 QMutexLocker locker(obj->getMutex());
960 // Check that index is not out of bounds
961 if (index >= numElements) {
962 return QVariant();
964 // Get value
965 switch (type) {
966 case INT8:
968 qint8 tmpint8;
969 memcpy(&tmpint8, &data[offset + numBytesPerElement * index], numBytesPerElement);
970 return QVariant(tmpint8);
972 break;
974 case INT16:
976 qint16 tmpint16;
977 memcpy(&tmpint16, &data[offset + numBytesPerElement * index], numBytesPerElement);
978 return QVariant(tmpint16);
980 break;
982 case INT32:
984 qint32 tmpint32;
985 memcpy(&tmpint32, &data[offset + numBytesPerElement * index], numBytesPerElement);
986 return QVariant(tmpint32);
988 break;
990 case UINT8:
992 quint8 tmpuint8;
993 memcpy(&tmpuint8, &data[offset + numBytesPerElement * index], numBytesPerElement);
994 return QVariant(tmpuint8);
996 break;
998 case UINT16:
1000 quint16 tmpuint16;
1001 memcpy(&tmpuint16, &data[offset + numBytesPerElement * index], numBytesPerElement);
1002 return QVariant(tmpuint16);
1004 break;
1006 case UINT32:
1008 quint32 tmpuint32;
1009 memcpy(&tmpuint32, &data[offset + numBytesPerElement * index], numBytesPerElement);
1010 return QVariant(tmpuint32);
1012 break;
1014 case FLOAT32:
1016 float tmpfloat;
1017 memcpy(&tmpfloat, &data[offset + numBytesPerElement * index], numBytesPerElement);
1018 return QVariant(tmpfloat);
1020 break;
1022 case ENUM:
1024 quint8 tmpenum;
1025 memcpy(&tmpenum, &data[offset + numBytesPerElement * index], numBytesPerElement);
1026 if (tmpenum >= options.length()) {
1027 qDebug() << "Invalid enum" << tmpenum << "for field" << (obj->getName() + ":" + name + "[" + elementNames[index] + "]");
1028 tmpenum = 0;
1030 return QVariant(options[tmpenum]);
1032 break;
1034 case BITFIELD:
1036 quint8 tmpbitfield;
1037 memcpy(&tmpbitfield, &data[offset + numBytesPerElement * ((quint32)(index / 8))], numBytesPerElement);
1038 tmpbitfield = (tmpbitfield >> (index % 8)) & 1;
1039 return QVariant(tmpbitfield);
1041 break;
1043 case STRING:
1045 data[offset + numElements - 1] = '\0';
1046 QString str((char *)&data[offset]);
1047 return QVariant(str);
1049 break;
1052 // If this point is reached then we got an invalid type
1053 return QVariant();
1056 bool UAVObjectField::checkValue(const QVariant & value, quint32 index)
1058 QMutexLocker locker(obj->getMutex());
1060 // Check that index is not out of bounds
1061 if (index >= numElements) {
1062 return false;
1064 // Get metadata
1065 UAVObject::Metadata mdata = obj->getMetadata();
1066 // Update value if the access mode permits
1067 if (UAVObject::GetFlightAccess(mdata) == UAVObject::ACCESS_READWRITE) {
1068 switch (type) {
1069 case INT8:
1070 case INT16:
1071 case INT32:
1072 case UINT8:
1073 case UINT16:
1074 case UINT32:
1075 case FLOAT32:
1076 case STRING:
1077 case BITFIELD:
1078 return true;
1080 break;
1081 case ENUM:
1083 qint8 tmpenum = options.indexOf(value.toString());
1084 return (tmpenum < 0) ? false : true;
1086 break;
1088 default:
1089 qDebug() << "checkValue: other types" << type;
1090 Q_ASSERT(0); // To catch any programming errors where we tried to test invalid values
1091 break;
1094 return true;
1097 void UAVObjectField::setValue(const QVariant & value, quint32 index)
1099 QMutexLocker locker(obj->getMutex());
1101 // Check that index is not out of bounds
1102 if (index >= numElements) {
1103 return;
1105 // Get metadata
1106 UAVObject::Metadata mdata = obj->getMetadata();
1107 // Update value if the access mode permits
1108 if (UAVObject::GetGcsAccess(mdata) == UAVObject::ACCESS_READWRITE) {
1109 switch (type) {
1110 case INT8:
1112 qint8 tmpint8 = value.toInt();
1113 memcpy(&data[offset + numBytesPerElement * index], &tmpint8, numBytesPerElement);
1114 break;
1116 case INT16:
1118 qint16 tmpint16 = value.toInt();
1119 memcpy(&data[offset + numBytesPerElement * index], &tmpint16, numBytesPerElement);
1120 break;
1122 case INT32:
1124 qint32 tmpint32 = value.toInt();
1125 memcpy(&data[offset + numBytesPerElement * index], &tmpint32, numBytesPerElement);
1126 break;
1128 case UINT8:
1130 quint8 tmpuint8 = value.toUInt();
1131 memcpy(&data[offset + numBytesPerElement * index], &tmpuint8, numBytesPerElement);
1132 break;
1134 case UINT16:
1136 quint16 tmpuint16 = value.toUInt();
1137 memcpy(&data[offset + numBytesPerElement * index], &tmpuint16, numBytesPerElement);
1138 break;
1140 case UINT32:
1142 quint32 tmpuint32 = value.toUInt();
1143 memcpy(&data[offset + numBytesPerElement * index], &tmpuint32, numBytesPerElement);
1144 break;
1146 case FLOAT32:
1148 float tmpfloat = value.toFloat();
1149 memcpy(&data[offset + numBytesPerElement * index], &tmpfloat, numBytesPerElement);
1150 break;
1152 case ENUM:
1154 qint8 tmpenum = options.indexOf(value.toString());
1155 // try case insensitive
1156 if (tmpenum < 0) {
1157 QRegExp regexp(value.toString(), Qt::CaseInsensitive);
1158 tmpenum = options.indexOf(regexp);
1159 if (tmpenum >= 0) {
1160 qWarning() << "Enum value" << value.toString() << "should be" << options.at(tmpenum);
1163 // Default to 0 on invalid values.
1164 if (tmpenum < 0) {
1165 tmpenum = 0;
1166 qWarning() << "Enum value" << value.toString() << "not found";
1168 memcpy(&data[offset + numBytesPerElement * index], &tmpenum, numBytesPerElement);
1169 break;
1171 case BITFIELD:
1173 quint8 tmpbitfield;
1174 memcpy(&tmpbitfield, &data[offset + numBytesPerElement * ((quint32)(index / 8))], numBytesPerElement);
1175 tmpbitfield = (tmpbitfield & ~(1 << (index % 8))) | ((value.toUInt() != 0 ? 1 : 0) << (index % 8));
1176 memcpy(&data[offset + numBytesPerElement * ((quint32)(index / 8))], &tmpbitfield, numBytesPerElement);
1177 break;
1179 case STRING:
1181 QString str = value.toString();
1182 QByteArray barray = str.toLatin1();
1183 quint32 index;
1184 for (index = 0; index < (quint32)barray.length() && index < (numElements - 1); ++index) {
1185 data[offset + index] = barray[index];
1187 barray[index] = '\0';
1188 break;
1194 double UAVObjectField::getDouble(quint32 index)
1196 return getValue(index).toDouble();
1199 void UAVObjectField::setDouble(double value, quint32 index)
1201 setValue(QVariant(value), index);