djiparsetxt
fieldOutput.cpp
Go to the documentation of this file.
1 /**********
2 This program is free software: you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation, either version 3 of the License, or
5 (at your option) any later version.
6 
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11 
12 You should have received a copy of the GNU General Public License
13 along with this program. If not, see <http://www.gnu.org/licenses/>.
14 **********/
15 /*
16  A C++ program to parse DJI's ".txt" log files (recorded by the "DJI Go 4" app).
17  Version 2021-05-20
18 
19  Copyright (c) 2021 Live Networks, Inc. All rights reserved.
20  For the latest version of this program (and more information), visit http://djilogs.live555.com
21 
22  Outputting a single field of data from the table.
23  Implementation.
24 */
25 
26 #include "FieldDatabase.hh"
27 #include <stdio.h>
28 #include <time.h>
29 
30 void FieldDatabase::outputField(char const* label, unsigned numFractionalDigits) {
31  FieldValue const* fieldValue = lookupFieldValue(label);
32  if (fieldValue == NULL) return; // output nothing for a nonexistent field
33 
34  int timeIsInMilliseconds = 0; // by default
35 
36  switch (fieldValue->fType) {
37  case IntegerByteUnsigned: {
38  printf("%u", fieldValue->fByte);
39  break;
40  }
41  case IntegerByteSigned: {
42  printf("%d", (int8_t)(fieldValue->fByte));
43  break;
44  }
45  case Integer2ByteUnsigned: {
46  printf("%u", fieldValue->fBytes2);
47  break;
48  }
49  case Integer2ByteSigned: {
50  printf("%d", (int16_t)(fieldValue->fBytes2));
51  break;
52  }
53  case Date2Byte: {
54  // Interpret the two bytes as: 7 bits (years since 1980) + 4 bits (month) + 5 bits (day of month):
55  printf("%u/%02u/%02u",
56  ((fieldValue->fBytes2&0xFE00)>>9) + 1980,
57  (fieldValue->fBytes2&0x01E0)>>5,
58  (fieldValue->fBytes2&0x001F));
59 
60  break;
61  }
62  case Integer4ByteUnsigned: {
63  printf("%u", fieldValue->fBytes4);
64  break;
65  }
66  case Integer4ByteSigned: {
67  printf("%d", (int32_t)(fieldValue->fBytes4));
68  break;
69  }
70  case Version4Byte: {
71  // Use the first 3 bytes (big-endian) as version numbers:
72  u_int32_t v = fieldValue->fBytes4;
73  printf("%u.%u.%u", (v>>24)&0xFF, (v>>16)&0xFF, (v>>8)&0xFF);
74  break;
75  }
76  case Float: {
77  printf("%.*f", numFractionalDigits, fieldValue->fFloat);
78  break;
79  }
80  case Double: {
81  printf("%.*f", numFractionalDigits, fieldValue->fDouble);
82  break;
83  }
85  timeIsInMilliseconds = 1;
86  // fall through to:
87  }
89  u_int64_t time = fieldValue->fBytes8;
90  u_int64_t timeInSeconds;
91  unsigned milliseconds;
92 
93  if (timeIsInMilliseconds) {
94  timeInSeconds = time/1000;
95  milliseconds = time%1000;
96  } else {
97  timeInSeconds = time;
98  milliseconds = 0;
99  }
100 
101  struct tm* convertedTime = gmtime((time_t*)&timeInSeconds);
102  if (convertedTime == NULL) {
103  fprintf(stderr, "outputField(8-byte timestamp): gmtime(%llu) failed!\n", timeInSeconds);
104  return;
105  }
106  printf("%u/%02u/%02u %02u:%02u:%02u",
107  convertedTime->tm_year + 1900, convertedTime->tm_mon + 1, convertedTime->tm_mday,
108  convertedTime->tm_hour, convertedTime->tm_min, convertedTime->tm_sec);
109  if (timeIsInMilliseconds) {
110  printf(".%03u", milliseconds);
111  }
112  break;
113  }
114  case String: {
115  printf("%s", fieldValue->fStr);
116  break;
117  }
118  }
119 }
120 
121 void FieldDatabase::outputFieldAsBoolean(char const* label) {
122  FieldValue const* fieldValue = lookupFieldValue(label);
123  if (fieldValue == NULL) return; // output nothing for a nonexistent field
124 
125  int booleanValue = 0;
126 
127  switch (fieldValue->fType) {
128  case IntegerByteUnsigned:
129  case IntegerByteSigned: {
130  booleanValue = fieldValue->fByte != 0;
131  break;
132  }
134  case Integer2ByteSigned: {
135  booleanValue = fieldValue->fBytes2 != 0;
136  break;
137  }
139  case Integer4ByteSigned: {
140  booleanValue = fieldValue->fBytes4 != 0;
141  break;
142  }
143  default: {
144  return; // print nothing if the field cannot be interpreted as Boolean
145  }
146  }
147 
148  printf(booleanValue ? "True" : "False");
149 }
150 
151 void FieldDatabase::outputFieldInterpreted(char const* label, char const* interpretedLabel) {
152  // First, check whether we currently have a value for the field "label":
153  FieldValue const* fieldValue = lookupFieldValue(label);
154  if (fieldValue == NULL) return; // output nothing for a nonexistent field
155 
156  // Next, check its type. It needs to be an unsigned integer type <= 4 bytes long:
157  u_int32_t intValue;
158  switch (fieldValue->fType) {
159  case IntegerByteUnsigned: {
160  intValue = (u_int32_t)(fieldValue->fByte);
161  break;
162  }
163  case Integer2ByteUnsigned: {
164  intValue = (u_int32_t)(fieldValue->fBytes2);
165  break;
166  }
167  case Integer4ByteUnsigned: {
168  intValue = fieldValue->fBytes4;;
169  break;
170  }
171  default: {
172  return; // bad type
173  }
174  }
175 
176  // Now, look up an InterpretationTable for "interpretedLabel":
177  InterpretationTable* interpretationTable = fInterpretationTableMap[interpretedLabel];
178  if (interpretationTable == NULL) return;
179 
180  // And use this to look up (and print) a string 'interpretation' of our integer value:
181  printf("%s", interpretationTable->lookup(intValue));
182 }
FieldType fType
char const * fStr
u_int64_t fBytes8
void outputFieldInterpreted(char const *label, char const *interpretedLabel)
double fDouble
u_int16_t fBytes2
std::unordered_map< char const *, InterpretationTable * > fInterpretationTableMap
u_int32_t fBytes4
u_int8_t fByte
void outputField(char const *label, unsigned numFractionalDigits=0)
Definition: fieldOutput.cpp:30
void outputFieldAsBoolean(char const *label)
char const * lookup(u_int32_t intValue)
FieldValue const * lookupFieldValue(char const *label)