djiparsetxt
parseRecord_OSD.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  Parsing OSD records within DJI ".txt" files.
23  Implementation.
24 */
25 
27 
28 void RecordAndDetailsParser::parseRecord_OSD(u_int8_t const*& ptr, u_int8_t const* limit) {
29  // OSD.longitude: 8 bytes little-endian double, in radians; convert to degrees:
30  note8ByteLatitudeOrLongitudeFieldInRadians("OSD.longitude", ptr, limit);
31 
32  // OSD.latitude: 8 bytes little-endian double, in radians; convert to degrees:
33  note8ByteLatitudeOrLongitudeFieldInRadians("OSD.latitude", ptr, limit);
34 
35  // OSD.height: 2 bytes signed(?) little-endian, multiple of 0.1 meters; convert to meters:
36  noteSigned2ByteField("OSD.height", ptr, limit, 10.0);
37 
38  // OSD.xSpeed: 2 bytes signed little-endian, multiple of 0.1 m/s; convert to m/s:
39  noteSigned2ByteField("OSD.xSpeed", ptr, limit, 10.0);
40 
41  // OSD.ySpeed: 2 bytes signed little-endian, multiple of 0.1 m/s; convert to m/s:
42  noteSigned2ByteField("OSD.ySpeed", ptr, limit, 10.0);
43 
44  // OSD.zSpeed: 2 bytes signed little-endian, multiple of 0.1 m/s; convert to m/s:
45  noteSigned2ByteField("OSD.zSpeed", ptr, limit, 10.0);
46 
47  // OSD.pitch: 2 bytes signed little-endian, multiple of 0.1 degrees; convert to degrees:
48  noteSigned2ByteField("OSD.pitch", ptr, limit, 10.0);
49 
50  // OSD.roll: 2 bytes signed little-endian, multiple of 0.1 degrees; convert to degrees:
51  noteSigned2ByteField("OSD.roll", ptr, limit, 10.0);
52 
53  // OSD.yaw: 2 bytes signed little-endian, multiple of 0.1 degrees; convert to degrees:
54  noteSigned2ByteField("OSD.yaw", ptr, limit, 10.0);
55 
56  // OSD.rcState(1 bit) + OSD.flycState.RAW (7 bits):
57  u_int8_t byte = getByte(ptr, limit);
58  enterSubByteField("OSD.rcState", byte, 0x80);
59  enterSubByteField("OSD.flycState.RAW", byte, 0x7F);
60 
61  // OSD.flycCommand.RAW: 1 byte unsigned:
62  noteByteField("OSD.flycCommand.RAW", ptr, limit);
63 
64  // OSD.goHomeStatus.RAW(3 bits) + OSD.isSwaveWork(1 bit) + OSD.isMotorUp(1 bit) + OSD.groundOrSky.RAW(2 bits) + OSD.canIOCWork(1 bit)
65  byte = getByte(ptr, limit);
66  enterSubByteField("OSD.goHomeStatus.RAW", byte, 0xE0);
67  enterSubByteField("OSD.isSwaveWork", byte, 0x10);
68  enterSubByteField("OSD.isMotorUp", byte, 0x08);
69  enterSubByteField("OSD.groundOrSky.RAW", byte, 0x06); // only the high bit is used?
70  enterSubByteField("OSD.canIOCWork", byte, 0x01);
71 
72  // unknown(1 bit) + OSD.modeChannel(2 bits) + OSD.isImuPreheated(1 bit) + unknown(1 bit) + OSD.voltageWarning(2 bits) + OSD.isVisionUsed(1 bit)
73  byte = getByte(ptr, limit);
74  enterSubByteField("OSD.modeChannel", byte, 0x60);
75  enterSubByteField("OSD.isImuPreheated", byte, 0x10);
76  enterSubByteField("OSD.voltageWarning", byte, 0x06);
77  enterSubByteField("OSD.isVisionUsed", byte, 0x01);
78 
79  // OSD.batteryType.RAW(2 bits) + OSD.gpsLevel(4 bits) + OSD.waveError(1 bit) + OSD.compassError(1 bit)
80  byte = getByte(ptr, limit);
81  enterSubByteField("OSD.batteryType.RAW", byte, 0xC0);
82  enterSubByteField("OSD.gpsLevel", byte, 0x3C);
83  enterSubByteField("OSD.waveError", byte, 0x02);
84  enterSubByteField("OSD.compassError", byte, 0x01);
85 
86  // 8 bits (Boolean flags); from high to low:
87  // OSD.isAcceletorOverRange (sic)
88  // OSD.isVibrating
89  // OSD.isBarometerDeadInAir
90  // OSD.isMotorBlocked
91  // OSD.isNotEnoughForce
92  // OSD.isPropellerCatapult
93  // OSD.isGoHomeHeightModified
94  // OSD.isOutOfLimit
95  byte = getByte(ptr, limit);
96  enterSubByteField("OSD.isAcceletorOverRange", byte, 0x80);
97  enterSubByteField("OSD.isVibrating", byte, 0x40);
98  enterSubByteField("OSD.isBarometerDeadInAir", byte, 0x20);
99  enterSubByteField("OSD.isNotEnoughForce", byte, 0x10);
100  enterSubByteField("OSD.isMotorBlocked", byte, 0x08);
101  enterSubByteField("OSD.isPropellerCatapult", byte, 0x04);
102  enterSubByteField("OSD.isGoHomeHeightModified", byte, 0x02);
103  enterSubByteField("OSD.isOutOfLimit", byte, 0x01);
104 
105  // OSD.gpsNum: 1 byte unsigned:
106  noteByteField("OSD.gpsNum", ptr, limit);
107 
108  // OSD.flightAction.RAW: 1 byte unsigned:
109  noteByteField("OSD.flightAction.RAW", ptr, limit);
110 
111  // OSD.motorStartFailedCause.RAW: 1 byte unsigned:
112  noteByteField("OSD.motorStartFailedCause.RAW", ptr, limit);
113 
114  // unknown (3 bits) + OSD.waypointLimitMode (1 bit) + OSD.nonGPSCause.RAW (4 bits):
115  byte = getByte(ptr, limit);
116  enterSubByteField("OSD.waypointLimitMode", byte, 0x10);
117  enterSubByteField("OSD.nonGPSCause.RAW", byte, 0x0F);
118 
119  // OSD.battery: 1 byte unsigned:
120  noteByteField("OSD.battery", ptr, limit);
121 
122  // OSD.sWaveHeight: 1 byte unsigned, multiple of 0.1 meters; convert to meters:
123  noteByteField("OSD.sWaveHeight", ptr, limit, 10.0);
124 
125  // OSD.flyTime: 2 bytes unsigned little-endian, multiple of 0.1 seconds; convert to seconds:
126  noteUnsigned2ByteField("OSD.flyTime", ptr, limit, 10.0);
127 
128  // OSD.motorRevolution: 1 byte unsigned:
129  noteByteField("OSD.motorRevolution", ptr, limit);
130 
131  // unknown (2 bytes):
132  ptr += 2;
133 
134  // OSD.flycVersion: 1 byte unsigned:
135  noteByteField("OSD.flycVersion", ptr, limit);
136 
137  // OSD.droneType.RAW: 1 byte unsigned:
138  noteByteField("OSD.droneType.RAW", ptr, limit);
139 
140  // OSD.imuInitFailReason.RAW: 1 byte unsigned:
141  noteByteField("OSD.imuInitFailReason.RAW", ptr, limit);
142 
143  // The following fields are not present in some versions of .txt files:
144  if (limit - ptr > 3) {
145  // OSD.motorFailReason.RAW: 1 byte unsigned:
146  noteByteField("OSD.motorFailReason.RAW", ptr, limit);
147 
148  // unknown (1 byte):
149  ++ptr;
150 
151  // OSD.ctrlDevice.RAW: 1 byte unsigned:
152  noteByteField("OSD.ctrlDevice.RAW", ptr, limit);
153 
154  // unknown (1 byte):
155  ++ptr;
156  }
157 }
u_int8_t getByte(u_int8_t const *&ptr, u_int8_t const *limit)
void noteSigned2ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int16_t offset=0)
void noteUnsigned2ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int16_t offset=0)
void note8ByteLatitudeOrLongitudeFieldInRadians(char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
void enterSubByteField(char const *label, u_int8_t byte, u_int8_t mask)
void parseRecord_OSD(u_int8_t const *&ptr, u_int8_t const *limit)
void noteByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)