dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
uavobjectfield.cpp
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  *
30  * Additional note on redistribution: The copyright and license notices above
31  * must be maintained in each individual source file that is a derivative work
32  * of this source file; otherwise redistribution is prohibited.
33  */
34 
35 #include "uavobjectfield.h"
36 #include <QtEndian>
37 #include <QDebug>
38 #include <cfloat>
39 
40 UAVObjectField::UAVObjectField(const QString &name, const QString &units, FieldType type,
41  int numElements, const QStringList &options,
42  const QList<int> &indices, const QString &limits,
43  const QString &description, const QList<QVariant> defaultValues,
44  const DisplayType display)
45 {
46  QStringList elementNames;
47  // Set element names
48  for (auto n = 0; n < numElements; ++n) {
49  elementNames.append(QString("%1").arg(n));
50  }
51  // Initialize
52  constructorInitialize(name, units, type, elementNames, options, indices, limits, description,
53  defaultValues, display);
54 }
55 
56 UAVObjectField::UAVObjectField(const QString &name, const QString &units, FieldType type,
57  const QStringList &elementNames, const QStringList &options,
58  const QList<int> &indices, const QString &limits,
59  const QString &description, const QList<QVariant> defaultValues,
60  const DisplayType display)
61 {
62  constructorInitialize(name, units, type, elementNames, options, indices, limits, description,
63  defaultValues, display);
64 }
65 
66 void UAVObjectField::constructorInitialize(const QString &name, const QString &units,
67  FieldType type, const QStringList &elementNames,
68  const QStringList &options, const QList<int> &indices,
69  const QString &limits, const QString &description,
70  const QList<QVariant> defaultValues,
71  const DisplayType display)
72 {
73  // Copy params
74  this->name = name;
75  this->units = units;
76  this->type = type;
77  this->options = options;
78  this->indices = indices;
79  this->numElements = elementNames.length();
80  this->offset = 0;
81  this->data = NULL;
82  this->obj = NULL;
83  this->elementNames = elementNames;
84  this->description = description;
85  this->display = display;
86 
87  // Set field size
88  switch (type) {
89  case INT8:
90  elementSize = sizeof(qint8);
91  break;
92  case INT16:
93  elementSize = sizeof(qint16);
94  break;
95  case INT32:
96  elementSize = sizeof(qint32);
97  break;
98  case UINT8:
99  elementSize = sizeof(quint8);
100  break;
101  case UINT16:
102  elementSize = sizeof(quint16);
103  break;
104  case UINT32:
105  elementSize = sizeof(quint32);
106  break;
107  case FLOAT32:
108  elementSize = sizeof(quint32);
109  break;
110  case ENUM:
111  elementSize = sizeof(quint8);
112  break;
113  case BITFIELD:
114  elementSize = sizeof(quint8);
115  this->options = QStringList() << tr("0") << tr("1");
116  this->indices = QList<int>() << 0 << 1;
117  break;
118  case STRING:
119  elementSize = sizeof(quint8);
120  break;
121  }
122  limitsInitialize(limits);
123 
124  // store default values, default to zero when not provided
125  this->defaultValues = defaultValues;
126  for (auto i = this->defaultValues.length(); i < this->numElements; i++)
127  this->defaultValues << QVariant(0);
128 
129  // fast lookup
130  for (int i = 0; i < indices.length(); i++)
131  enumToIndex.emplace(std::make_pair(indices.at(i), i));
132 }
133 
134 void UAVObjectField::limitsInitialize(const QString &limits)
135 {
142  if (limits.isEmpty())
143  return;
144  QStringList stringPerElement = limits.split(",");
145  int index = 0;
146  foreach (const QString &str, stringPerElement) {
147  QStringList ruleList = str.split(";");
148  QList<LimitStruct> limitList;
149  foreach (const QString &rule, ruleList) {
150  QString _str = rule.trimmed();
151  if (_str.isEmpty())
152  continue;
153  QStringList valuesPerElement = _str.split(":");
154  LimitStruct lstruc;
155  bool startFlag = valuesPerElement.at(0).startsWith("%");
156  bool maxIndexFlag = index < numElements;
157  bool elemNumberSizeFlag = valuesPerElement.at(0).size() == 3;
158  bool aux;
159  valuesPerElement.at(0).mid(1, 4).toInt(&aux, 16);
160  bool b4 = ((valuesPerElement.at(0).size()) == 7 && aux);
161  if (startFlag && maxIndexFlag && (elemNumberSizeFlag || b4)) {
162  if (b4)
163  lstruc.board = valuesPerElement.at(0).mid(1, 4).toInt(&aux, 16);
164  else
165  lstruc.board = 0;
166  if (valuesPerElement.at(0).right(2) == "EQ")
167  lstruc.type = EQUAL;
168  else if (valuesPerElement.at(0).right(2) == "NE")
169  lstruc.type = NOT_EQUAL;
170  else if (valuesPerElement.at(0).right(2) == "BE")
171  lstruc.type = BETWEEN;
172  else if (valuesPerElement.at(0).right(2) == "BI")
173  lstruc.type = BIGGER;
174  else if (valuesPerElement.at(0).right(2) == "SM")
175  lstruc.type = SMALLER;
176  else
177  qDebug() << "limits parsing failed (invalid property) on UAVObjectField"
178  << name;
179  valuesPerElement.removeAt(0);
180  foreach (const QString &_value, valuesPerElement) {
181  QString value = _value.trimmed();
182  switch (type) {
183  case UINT8:
184  case UINT16:
185  case UINT32:
186  case BITFIELD:
187  lstruc.values.append((quint32)value.toULong());
188  break;
189  case INT8:
190  case INT16:
191  case INT32:
192  lstruc.values.append((qint32)value.toLong());
193  break;
194  case FLOAT32:
195  lstruc.values.append((float)value.toFloat());
196  break;
197  case ENUM:
198  lstruc.values.append((QString)value);
199  break;
200  case STRING:
201  lstruc.values.append((QString)value);
202  break;
203  default:
204  lstruc.values.append(QVariant());
205  }
206  }
207  limitList.append(lstruc);
208  } else {
209  if (!valuesPerElement.at(0).isEmpty() && !startFlag)
210  qDebug()
211  << "limits parsing failed (property doesn't start with %) on UAVObjectField"
212  << name;
213  else if (!maxIndexFlag)
214  qDebug() << "limits parsing failed (index>numelements) on UAVObjectField"
215  << name << "index" << index << "numElements" << numElements;
216  else if (!elemNumberSizeFlag || !b4)
217  qDebug() << "limits parsing failed limit not starting with %XX or %YYYYXX "
218  "where XX is the limit type and YYYY is the board type on "
219  "UAVObjectField"
220  << name;
221  }
222  }
223  elementLimits.insert(index, limitList);
224  ++index;
225  }
226 }
227 
228 bool UAVObjectField::isWithinLimits(QVariant var, int index, int board) const
229 {
230  if (!elementLimits.keys().contains(index))
231  return true;
232 
233  foreach (const LimitStruct &struc, elementLimits.value(index)) {
234  if ((struc.board != board) && board != 0 && struc.board != 0)
235  continue;
236  switch (struc.type) {
237  case EQUAL:
238  switch (type) {
239  case INT8:
240  case INT16:
241  case INT32:
242  foreach (const QVariant &vars, struc.values) {
243  if (var.toInt() == vars.toInt())
244  return true;
245  }
246  return false;
247  break;
248  case UINT8:
249  case UINT16:
250  case UINT32:
251  case BITFIELD:
252  foreach (const QVariant &vars, struc.values) {
253  if (var.toUInt() == vars.toUInt())
254  return true;
255  }
256  return false;
257  break;
258  case ENUM:
259  case STRING:
260  foreach (const QVariant &vars, struc.values) {
261  if (var.toString() == vars.toString())
262  return true;
263  }
264  return false;
265  break;
266  case FLOAT32:
267  foreach (const QVariant &vars, struc.values) {
268  if (var.toFloat() == vars.toFloat())
269  return true;
270  }
271  return false;
272  break;
273  default:
274  return true;
275  }
276  break;
277  case NOT_EQUAL:
278  switch (type) {
279  case INT8:
280  case INT16:
281  case INT32:
282  foreach (const QVariant &vars, struc.values) {
283  if (var.toInt() == vars.toInt())
284  return false;
285  }
286  return true;
287  break;
288  case UINT8:
289  case UINT16:
290  case UINT32:
291  case BITFIELD:
292  foreach (const QVariant &vars, struc.values) {
293  if (var.toUInt() == vars.toUInt())
294  return false;
295  }
296  return true;
297  break;
298  case ENUM:
299  case STRING:
300  foreach (const QVariant &vars, struc.values) {
301  if (var.toString() == vars.toString())
302  return false;
303  }
304  return true;
305  break;
306  case FLOAT32:
307  foreach (const QVariant &vars, struc.values) {
308  if (var.toFloat() == vars.toFloat())
309  return false;
310  }
311  return true;
312  break;
313  default:
314  return true;
315  }
316  break;
317  case BETWEEN:
318  if (struc.values.length() < 2) {
319  qDebug() << __FUNCTION__
320  << "between limit with less than 1 pair, aborting; field:" << name;
321  return true;
322  }
323  if (struc.values.length() > 2)
324  qDebug() << __FUNCTION__
325  << "between limit with more than 1 pair, using first; field" << name;
326  switch (type) {
327  case INT8:
328  case INT16:
329  case INT32:
330  if (!(var.toInt() >= struc.values.at(0).toInt()
331  && var.toInt() <= struc.values.at(1).toInt()))
332  return false;
333  return true;
334  break;
335  case UINT8:
336  case UINT16:
337  case UINT32:
338  case BITFIELD:
339  if (!(var.toUInt() >= struc.values.at(0).toUInt()
340  && var.toUInt() <= struc.values.at(1).toUInt()))
341  return false;
342  return true;
343  break;
344  case ENUM:
345  // OK, I think this is OK with parents. Because we'll
346  // consider the limit to mean "as ordered in this object".
347  // So no need to map to underlying types.
348  if (!(options.indexOf(var.toString())
349  >= options.indexOf(struc.values.at(0).toString())
350  && options.indexOf(var.toString())
351  <= options.indexOf(struc.values.at(1).toString())))
352  return false;
353  return true;
354  break;
355  case STRING:
356  return true;
357  break;
358  case FLOAT32:
359  if (!(var.toFloat() >= struc.values.at(0).toFloat()
360  && var.toFloat() <= struc.values.at(1).toFloat()))
361  return false;
362  return true;
363  break;
364  default:
365  return true;
366  }
367  break;
368  case BIGGER:
369  if (struc.values.length() < 1) {
370  qDebug() << __FUNCTION__
371  << "BIGGER limit with less than 1 value, aborting; field:" << name;
372  return true;
373  }
374  if (struc.values.length() > 1)
375  qDebug() << __FUNCTION__
376  << "BIGGER limit with more than 1 value, using first; field" << name;
377  switch (type) {
378  case INT8:
379  case INT16:
380  case INT32:
381  if (!(var.toInt() >= struc.values.at(0).toInt()))
382  return false;
383  return true;
384  break;
385  case UINT8:
386  case UINT16:
387  case UINT32:
388  case BITFIELD:
389  if (!(var.toUInt() >= struc.values.at(0).toUInt()))
390  return false;
391  return true;
392  break;
393  case ENUM:
394  if (!(options.indexOf(var.toString())
395  >= options.indexOf(struc.values.at(0).toString())))
396  return false;
397  return true;
398  break;
399  case STRING:
400  return true;
401  break;
402  case FLOAT32:
403  if (!(var.toFloat() >= struc.values.at(0).toFloat()))
404  return false;
405  return true;
406  break;
407  default:
408  return true;
409  }
410  break;
411  case SMALLER:
412  switch (type) {
413  case INT8:
414  case INT16:
415  case INT32:
416  if (!(var.toInt() <= struc.values.at(0).toInt()))
417  return false;
418  return true;
419  break;
420  case UINT8:
421  case UINT16:
422  case UINT32:
423  case BITFIELD:
424  if (!(var.toUInt() <= struc.values.at(0).toUInt()))
425  return false;
426  return true;
427  break;
428  case ENUM:
429  if (!(options.indexOf(var.toString())
430  <= options.indexOf(struc.values.at(0).toString())))
431  return false;
432  return true;
433  break;
434  case STRING:
435  return true;
436  break;
437  case FLOAT32:
438  if (!(var.toFloat() <= struc.values.at(0).toFloat()))
439  return false;
440  return true;
441  break;
442  default:
443  return true;
444  }
445  }
446  }
447  return true;
448 }
449 
450 QVariant UAVObjectField::getMaxLimit(int index, int board) const
451 {
452  if (!elementLimits.keys().contains(index)) {
453  // if nothing explicitly specified, assume max possible value
454  switch (type) {
455  case INT8:
456  return INT8_MAX;
457  case INT16:
458  return INT16_MAX;
459  case INT32:
460  return INT32_MAX;
461  case UINT8:
462  return UINT8_MAX;
463  case UINT16:
464  return UINT16_MAX;
465  case UINT32:
466  return UINT32_MAX;
467  case FLOAT32:
468  return FLT_MAX;
469  case ENUM: // TODO: could do better for this one
470  case BITFIELD:
471  case STRING:
472  break;
473  }
474  return QVariant();
475  }
476 
477  foreach (const LimitStruct &struc, elementLimits.value(index)) {
478  if ((struc.board != board) && board != 0 && struc.board != 0)
479  continue;
480  switch (struc.type) {
481  case EQUAL:
482  case NOT_EQUAL:
483  case BIGGER:
484  return QVariant();
485  break;
486  break;
487  case BETWEEN:
488  return struc.values.at(1);
489  break;
490  case SMALLER:
491  return struc.values.at(0);
492  break;
493  default:
494  return QVariant();
495  break;
496  }
497  }
498  return QVariant();
499 }
500 QVariant UAVObjectField::getMinLimit(int index, int board) const
501 {
502  if (!elementLimits.keys().contains(index)) {
503  // if nothing explicitly specified, assume min possible value
504  switch (type) {
505  case INT8:
506  return INT8_MIN;
507  case INT16:
508  return INT16_MIN;
509  case INT32:
510  return INT32_MIN;
511  case UINT8:
512  case UINT16:
513  case UINT32:
514  return 0;
515  case FLOAT32:
516  return FLT_MIN;
517  case ENUM: // TODO: could do better for this one
518  case BITFIELD:
519  case STRING:
520  break;
521  }
522  return QVariant();
523  }
524 
525  foreach (LimitStruct struc, elementLimits.value(index)) {
526  if ((struc.board != board) && board != 0 && struc.board != 0)
527  return QVariant();
528  switch (struc.type) {
529  case EQUAL:
530  case NOT_EQUAL:
531  case SMALLER:
532  return QVariant();
533  break;
534  break;
535  case BETWEEN:
536  return struc.values.at(0);
537  break;
538  case BIGGER:
539  return struc.values.at(0);
540  break;
541  default:
542  return QVariant();
543  break;
544  }
545  }
546  return QVariant();
547 }
548 void UAVObjectField::initialize(quint8 *data, quint32 dataOffset, UAVObject *obj)
549 {
550  this->data = data;
551  this->offset = dataOffset;
552  this->obj = obj;
553  clear();
554 }
555 
557 {
558  return type;
559 }
560 
562 {
563  switch (type) {
565  return "int8";
567  return "int16";
569  return "int32";
571  return "uint8";
573  return "uint16";
575  return "uint32";
577  return "float32";
579  return "enum";
581  return "bitfield";
583  return "string";
584  default:
585  return "";
586  }
587 }
588 
590 {
591  return elementNames;
592 }
593 
594 QString UAVObjectField::getElementName(int index) const
595 {
596  if (index < 0 || index >= elementNames.length()) {
597  Q_ASSERT(false);
598  qWarning() << "Invalid element:" << index << " max=" << elementNames.length();
599  return "";
600  }
601  return elementNames.at(index);
602 }
603 
609 int UAVObjectField::getElementIndex(const QString &name) const
610 {
611  for (int i = 0; i < elementNames.length(); i++) {
612  if (elementNames.at(i) == name)
613  return i;
614  }
615  return -1;
616 }
617 
619 {
620  return obj;
621 }
622 
624 {
625  switch (type) {
626  case BITFIELD:
627  memset(&data[offset], 0, elementSize * ((quint32)(1 + (numElements - 1) / 8)));
628  break;
629  default:
630  memset(&data[offset], 0, elementSize * numElements);
631  break;
632  }
633 }
634 
635 QString UAVObjectField::getName() const
636 {
637  return name;
638 }
639 
641 {
642  return units;
643 }
644 
645 QStringList UAVObjectField::getOptions() const
646 {
647  return options;
648 }
649 
650 bool UAVObjectField::hasOption(const QString &option)
651 {
652  return options.contains(option);
653 }
654 
656 {
657  return numElements;
658 }
659 
661 {
662  if (type == BITFIELD)
663  return elementSize * static_cast<size_t>((1 + (numElements - 1) / 8));
664  return elementSize * static_cast<size_t>(numElements);
665 }
666 
668 {
669  QString sout;
670  sout.append(QString("%1: [ ").arg(name));
671  for (auto n = 0; n < numElements; ++n) {
672  if (type == ENUM) {
673  sout.append(QString("%1 ").arg(getValue(n).toString()));
674  } else {
675  sout.append(QString("%1 ").arg(getDouble(n)));
676  }
677  }
678  sout.append(QString("] %1\n").arg(units));
679  return sout;
680 }
681 
682 qint32 UAVObjectField::pack(quint8 *dataOut)
683 {
684  // Pack each element in output buffer
685  switch (type) {
686  case INT8:
687  memcpy(dataOut, &data[offset], numElements);
688  break;
689  case INT16:
690  for (auto index = 0; index < numElements; ++index) {
691  qint16 value;
692  memcpy(&value, &data[offset + elementSize * index], elementSize);
693  qToLittleEndian<qint16>(value, &dataOut[elementSize * index]);
694  }
695  break;
696  case INT32:
697  for (auto index = 0; index < numElements; ++index) {
698  qint32 value;
699  memcpy(&value, &data[offset + elementSize * index], elementSize);
700  qToLittleEndian<qint32>(value, &dataOut[elementSize * index]);
701  }
702  break;
703  case UINT8:
704  for (auto index = 0; index < numElements; ++index) {
705  dataOut[elementSize * index] = data[offset + elementSize * index];
706  }
707  break;
708  case UINT16:
709  for (auto index = 0; index < numElements; ++index) {
710  quint16 value;
711  memcpy(&value, &data[offset + elementSize * index], elementSize);
712  qToLittleEndian<quint16>(value, &dataOut[elementSize * index]);
713  }
714  break;
715  case UINT32:
716  for (auto index = 0; index < numElements; ++index) {
717  quint32 value;
718  memcpy(&value, &data[offset + elementSize * index], elementSize);
719  qToLittleEndian<quint32>(value, &dataOut[elementSize * index]);
720  }
721  break;
722  case FLOAT32:
723  for (auto index = 0; index < numElements; ++index) {
724  quint32 value;
725  memcpy(&value, &data[offset + elementSize * index], elementSize);
726  qToLittleEndian<quint32>(value, &dataOut[elementSize * index]);
727  }
728  break;
729  case ENUM:
730  for (auto index = 0; index < numElements; ++index) {
731  dataOut[elementSize * index] = data[offset + elementSize * index];
732  }
733  break;
734  case BITFIELD:
735  for (auto index = 0; index < (1 + (numElements - 1) / 8); ++index) {
736  dataOut[elementSize * index] = data[offset + elementSize * index];
737  }
738  break;
739  case STRING:
740  memcpy(dataOut, &data[offset], numElements);
741  break;
742  }
743  // Done
744  return getNumBytes();
745 }
746 
747 qint32 UAVObjectField::unpack(const quint8 *dataIn)
748 {
749  // Unpack each element from input buffer
750  switch (type) {
751  case INT8:
752  memcpy(&data[offset], dataIn, numElements);
753  break;
754  case INT16:
755  for (auto index = 0; index < numElements; ++index) {
756  qint16 value;
757  value = qFromLittleEndian<qint16>(&dataIn[elementSize * index]);
758  memcpy(&data[offset + elementSize * index], &value, elementSize);
759  }
760  break;
761  case INT32:
762  for (auto index = 0; index < numElements; ++index) {
763  qint32 value;
764  value = qFromLittleEndian<qint32>(&dataIn[elementSize * index]);
765  memcpy(&data[offset + elementSize * index], &value, elementSize);
766  }
767  break;
768  case UINT8:
769  for (auto index = 0; index < numElements; ++index) {
770  data[offset + elementSize * index] = dataIn[elementSize * index];
771  }
772  break;
773  case UINT16:
774  for (auto index = 0; index < numElements; ++index) {
775  quint16 value;
776  value = qFromLittleEndian<quint16>(&dataIn[elementSize * index]);
777  memcpy(&data[offset + elementSize * index], &value, elementSize);
778  }
779  break;
780  case UINT32:
781  for (auto index = 0; index < numElements; ++index) {
782  quint32 value;
783  value = qFromLittleEndian<quint32>(&dataIn[elementSize * index]);
784  memcpy(&data[offset + elementSize * index], &value, elementSize);
785  }
786  break;
787  case FLOAT32:
788  for (auto index = 0; index < numElements; ++index) {
789  quint32 value;
790  value = qFromLittleEndian<quint32>(&dataIn[elementSize * index]);
791  memcpy(&data[offset + elementSize * index], &value, elementSize);
792  }
793  break;
794  case ENUM:
795  for (auto index = 0; index < numElements; ++index) {
796  data[offset + elementSize * index] = dataIn[elementSize * index];
797  }
798  break;
799  case BITFIELD:
800  for (auto index = 0; index < (1 + (numElements - 1) / 8); ++index) {
801  data[offset + elementSize * index] = dataIn[elementSize * index];
802  }
803  break;
804  case STRING:
805  memcpy(&data[offset], dataIn, numElements);
806  break;
807  }
808  // Done
809  return getNumBytes();
810 }
811 
813 {
814  switch (type) {
815  case INT8:
816  case INT16:
817  case INT32:
818  case UINT8:
819  case UINT16:
820  case UINT32:
821  case FLOAT32:
822  case BITFIELD:
823  return true;
824  case ENUM:
825  case STRING:
826  break;
827  }
828  return false;
829 }
830 
832 {
833  switch (type) {
834  case INT8:
835  case INT16:
836  case INT32:
837  case UINT8:
838  case UINT16:
839  case UINT32:
840  case FLOAT32:
841  case BITFIELD:
842  return false;
843  case ENUM:
844  case STRING:
845  break;
846  }
847  return true;
848 }
849 
850 QVariant UAVObjectField::getValue(int index) const
851 {
852  // Check that index is not out of bounds
853  if (index < 0 || index >= numElements) {
854  return QVariant();
855  }
856 
857  const void *d = &data[offset + elementSize * static_cast<unsigned>(index)];
858 
859  switch (type) {
860  case INT8:
861  // QVariant treats qint8 as char :(
862  return QVariant::fromValue(static_cast<int>(*static_cast<const qint8 *>(d)));
863  case INT16:
864  return QVariant::fromValue(*static_cast<const qint16 *>(d));
865  case INT32:
866  return QVariant::fromValue(*static_cast<const qint32 *>(d));
867  case UINT8:
868  // QVariant treats quint8 as char :(
869  return QVariant::fromValue(static_cast<int>(*static_cast<const quint8 *>(d)));
870  case UINT16:
871  return QVariant::fromValue(*static_cast<const quint16 *>(d));
872  case UINT32:
873  return QVariant::fromValue(*static_cast<const quint32 *>(d));
874  case FLOAT32:
875  return QVariant::fromValue(*static_cast<const float *>(d));
876  case ENUM:
877  try {
878  auto i = enumToIndex.at(*static_cast<const quint8 *>(d));
879  return QVariant::fromValue(options[i]);
880  } catch (const std::out_of_range &e) {
881  qWarning() << "Invalid value" << *static_cast<const quint8 *>(d)
882  << "for ENUM field" << name << ":" << e.what();
883  }
884  return QVariant::fromValue(QStringLiteral("Bad Value"));
885  case BITFIELD: {
886  d = &data[offset + elementSize * static_cast<unsigned>(index / 8)];
887  quint8 val = (*static_cast<const quint8 *>(d) >> (index % 8)) & 1;
888  return QVariant::fromValue(val > 0 ? QChar('1') : QChar('0'));
889  }
890  case STRING:
891  return QVariant::fromValue(QString::fromLatin1(static_cast<const char *>(d),
892  static_cast<int>(strnlen(static_cast<const char *>(d),
893  static_cast<size_t>(numElements)))));
894  }
895  // If this point is reached then we got an invalid type
896  Q_ASSERT(false);
897  return QVariant();
898 }
899 
900 bool UAVObjectField::checkValue(const QVariant &value, int index) const
901 {
902  // Check that index is not out of bounds
903  if (index < 0 || index >= numElements) {
904  return false;
905  }
906  // Get metadata
907  UAVObject::Metadata mdata = obj->getMetadata();
908  // Update value if the access mode permits
910  switch (type) {
911  case INT8:
912  case INT16:
913  case INT32:
914  case UINT8:
915  case UINT16:
916  case UINT32:
917  case FLOAT32:
918  case STRING:
919  case BITFIELD:
920  return true;
921  case ENUM:
922  if (static_cast<QMetaType::Type>(value.type()) == QMetaType::QString) {
923  int idx = options.indexOf(value.toString());
924  if (idx >= 0 && idx < indices.length())
925  return true;
926  } else if (value.canConvert(QMetaType::Int)) {
927  if (indices.contains(value.toInt()))
928  return true;
929  }
930  return false;
931  }
932  }
933  return true;
934 }
935 
936 void UAVObjectField::setValue(const QVariant &value, int index)
937 {
938  // Check that index is not out of bounds
939  if (index < 0 || index >= numElements) {
940  return;
941  }
942 
943  void *d = &data[offset + elementSize * static_cast<unsigned>(index)];
944 
945  // Get metadata
946  UAVObject::Metadata mdata = obj->getMetadata();
947  // Update value if the access mode permits
949  switch (type) {
950  case INT8:
951  *static_cast<qint8 *>(d) = static_cast<qint8>(value.toInt());
952  break;
953  case INT16:
954  *static_cast<qint16 *>(d) = static_cast<qint16>(value.toInt());
955  break;
956  case INT32:
957  *static_cast<qint32 *>(d) = static_cast<qint32>(value.toInt());
958  break;
959  case UINT8:
960  *static_cast<quint8 *>(d) = static_cast<quint8>(value.toUInt());
961  break;
962  case UINT16:
963  *static_cast<quint16 *>(d) = static_cast<quint16>(value.toUInt());
964  break;
965  case UINT32:
966  *static_cast<quint32 *>(d) = static_cast<quint32>(value.toUInt());
967  break;
968  case FLOAT32:
969  *static_cast<float *>(d) = value.toFloat();
970  break;
971  case ENUM:
972  if (static_cast<QMetaType::Type>(value.type()) == QMetaType::QString) {
973  int idx = options.indexOf(value.toString());
974  if (idx < 0 || idx >= indices.length()) {
975  Q_ASSERT(false);
976  qWarning() << "Invalid option!" << obj->getName() << name << value.toString();
977  return;
978  }
979  *static_cast<quint8 *>(d) = static_cast<quint8>(indices[idx]);
980  } else if (value.canConvert(QMetaType::Int)) {
981  if (!indices.contains(value.toInt())) {
982  Q_ASSERT(false);
983  qWarning() << "Invalid option!" << obj->getName() << name << value.toInt();
984  return;
985  }
986  *static_cast<quint8 *>(d) = static_cast<quint8>(value.toInt());
987  } else {
988  Q_ASSERT(false);
989  qWarning() << "Invalid type!" << obj->getName() << name << value;
990  return;
991  }
992  break;
993  case BITFIELD:
994  d = &data[offset + elementSize * static_cast<unsigned>(index / 8)];
995  *static_cast<quint8 *>(d) &= ~(1 << (index % 8));
996  *static_cast<quint8 *>(d) |= ((value.toUInt() != 0 ? 1 : 0) << (index % 8));
997  break;
998  case STRING: {
999  QByteArray barray = value.toString().toLatin1();
1000  barray.resize(numElements);
1001  barray[numElements - 1] = '\0';
1002  memcpy(d, barray.constData(), static_cast<size_t>(numElements));
1003  break;
1004  }
1005  }
1006  }
1007 }
1008 
1009 double UAVObjectField::getDouble(int index) const
1010 {
1011  return getValue(index).toDouble();
1012 }
1013 
1014 void UAVObjectField::setDouble(double value, int index)
1015 {
1016  setValue(QVariant(value), index);
1017 }
1018 
1020 {
1021  return description;
1022 }
1023 
1024 QVariant UAVObjectField::getDefaultValue(int index) const
1025 {
1026  return defaultValues.at(index);
1027 }
1028 
1030 {
1031  switch (type) {
1032  case INT8:
1033  case INT16:
1034  case INT32: {
1035  int val = getValue(index).toInt();
1036  int defVal = getDefaultValue(index).toInt();
1037  return val == defVal;
1038  }
1039  case BITFIELD:
1040  case UINT8:
1041  case UINT16:
1042  case UINT32: {
1043  unsigned val = getValue(index).toUInt();
1044  unsigned defVal = getDefaultValue(index).toUInt();
1045  return val == defVal;
1046  }
1047  case FLOAT32: {
1048  float val = getValue(index).toFloat();
1049  float defVal = getDefaultValue(index).toFloat();
1050  return qFuzzyCompare(val, defVal);
1051  }
1052  case ENUM:
1053  case STRING: {
1054  const QString val = getValue(index).toString();
1055  const QString defVal = getDefaultValue(index).toString();
1056  return val == defVal;
1057  }
1058  }
1059 
1060  Q_ASSERT(false);
1061  return false;
1062 }
1063 
1065 {
1066  switch (display) {
1067  case HEX:
1068  return 16;
1069  case BIN:
1070  return 2;
1071  case OCT:
1072  return 8;
1073  default:
1074  return 10;
1075  }
1076 }
1077 
1079 {
1080  switch (display) {
1081  case HEX:
1082  return QStringLiteral("0x");
1083  case BIN:
1084  return QStringLiteral("0b");
1085  case OCT:
1086  return QStringLiteral("0");
1087  default:
1088  return QString();
1089  }
1090 }
1091 
bool checkValue(const QVariant &data, int index=0) const
bool isDefaultValue(int index=0)
Check if the element is set to default value.
QString getTypeAsString() const
void limitsInitialize(const QString &limits)
qint32 unpack(const quint8 *dataIn)
size_t getNumBytes() const
UAVObject * getObject() const
QVariant getDefaultValue(int index=0) const
Get the default value (defined in the UAVO def) for the element.
UAVObjectField(const QString &name, const QString &units, FieldType type, int numElements, const QStringList &options, const QList< int > &indices, const QString &limits=QString(), const QString &description=QString(), const QList< QVariant > defaultValues=QList< QVariant >(), const DisplayType display=DEC)
DisplayType display
double getDouble(int index=0) const
QString getDisplayPrefix() const
Get the prefix for the preferred display format.
QVariant getValue(int index=0) const
UAVObject * obj
QMap< int, QList< LimitStruct > > elementLimits
int getNumElements() const
QString getElementName(int index=0) const
bool isText() const
for i
Definition: OPPlots.m:140
DataFields data
int getElementIndex(const QString &name) const
Get the index of an element from it's name.
virtual Metadata getMetadata()=0
QString getDescription() const
QStringList getOptions() const
QList< QVariant > defaultValues
void setValue(const QVariant &data, int index=0)
QList< QVariant > values
numElements
QList< int > indices
bool hasOption(const QString &option)
hasOption Check if the given option exists
bool isNumeric() const
Eccentricity n
Definition: OPPlots.m:137
QString getName() const
QVariant getMinLimit(int index, int board=0) const
QString toString() const
QStringList options
void initialize(quint8 *data, quint32 dataOffset, UAVObject *obj)
QStringList getElementNames() const
QStringList elementNames
QString getUnits() const
QString getName()
Definition: uavobject.cpp:131
std::map< int, int > enumToIndex
static AccessMode GetFlightAccess(const Metadata &meta)
Definition: uavobject.cpp:377
QVariant getMaxLimit(int index, int board=0) const
void setDouble(double value, int index=0)
qint32 pack(quint8 *dataOut)
bool isWithinLimits(QVariant var, int index, int board=0) const
int getDisplayIntegerBase() const
Get the preferred integer base for this field.
e
Definition: OPPlots.m:99
void constructorInitialize(const QString &name, const QString &units, FieldType type, const QStringList &elementNames, const QStringList &options, const QList< int > &indices, const QString &limits, const QString &description, const QList< QVariant > defaultValues, const DisplayType display)
FieldType getType() const
static AccessMode GetGcsAccess(const Metadata &meta)
Definition: uavobject.cpp:397