djiparsetxt
Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes
RecordAndDetailsParser Class Reference

#include <RecordAndDetailsParser.hh>

Inheritance diagram for RecordAndDetailsParser:
Inheritance graph
[legend]
Collaboration diagram for RecordAndDetailsParser:
Collaboration graph
[legend]

Public Member Functions

 RecordAndDetailsParser ()
 
virtual ~RecordAndDetailsParser ()
 
int parseJPEGRecord (u_int8_t const *&ptr, u_int8_t const *limit)
 

Static Public Member Functions

static DJITxtParsercreateNew ()
 

Private Member Functions

virtual void parseDetailsArea (u_int8_t const *&ptr, u_int8_t const *limit)
 
virtual int parseRecord (u_int8_t const *&ptr, u_int8_t const *limit, int isScrambled)
 
virtual void summarizeRecordParsing ()
 
virtual void outputOneRow (int outputColumnLabels)
 
void parseRecord_OSD (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_HOME (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_GIMBAL (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_RC (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_CUSTOM (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_DEFORM (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_CENTER_BATTERY (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_SMART_BATTERY (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_APP_TIP (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_APP_WARN (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_RECOVER (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_APP_GPS (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_FIRMWARE (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_APP_SER_WARN (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecord_COMPONENT (u_int8_t const *&ptr, u_int8_t const *limit)
 
int parseRecord_JPEG (u_int8_t const *&ptr, u_int8_t const *limit)
 
void parseRecordUnknownFormat (char const *recordTypeName, u_int8_t const *&ptr, u_int8_t const *limit)
 
void enterSubByteField (char const *label, u_int8_t byte, u_int8_t mask)
 
void noteByteField (char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)
 
void note2ByteField (char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int16_t offset=0, int isSigned=0)
 
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 note4ByteField (char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)
 
void note4ByteFloatField (char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0)
 
void note8ByteDoubleField (char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
 
void note8ByteLatitudeOrLongitudeFieldInRadians (char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
 
void note8ByteLatitudeOrLongitudeFieldInDegrees (char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
 
void note2ByteDateField (char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
 
void note8ByteTimestampField (char const *label, u_int8_t const *&ptr, u_int8_t const *limit, int isInMilliseconds=0)
 
void noteStringField (char const *label, u_int8_t const *&ptr, unsigned stringLength, u_int8_t const *limit)
 
void note3ByteVersionField (char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
 

Private Attributes

unsigned fNumRecords
 
RecordTypeStat fRecordTypeStats [256]
 
char const * fRecordTypeName [256]
 
unsigned fMaxNumRecordsForOneType
 
FieldDatabasefFieldDatabase
 

Detailed Description

Definition at line 45 of file RecordAndDetailsParser.hh.

Constructor & Destructor Documentation

◆ RecordAndDetailsParser()

RecordAndDetailsParser::RecordAndDetailsParser ( )

Definition at line 41 of file RecordAndDetailsParser.cpp.

43 #ifdef DEBUG_RECORD_PARSING
44  // Initialize "fRecordTypeName":
45  for (unsigned i = 0; i < 256; ++i) {
46  fRecordTypeName[i] = NULL;
47  }
48  fRecordTypeName[0x01] = "OSD";
49  fRecordTypeName[0x02] = "HOME";
50  fRecordTypeName[0x03] = "GIMBAL";
51  fRecordTypeName[0x04] = "RC";
52  fRecordTypeName[0x05] = "CUSTOM";
53  fRecordTypeName[0x06] = "DEFORM";
54  fRecordTypeName[0x07] = "CENTER_BATTERY";
55  fRecordTypeName[0x08] = "SMART_BATTERY";
56  fRecordTypeName[0x09] = "APP_TIP";
57  fRecordTypeName[0x0A] = "APP_WARN";
58  fRecordTypeName[0x0B] = "RC_GPS";
59  fRecordTypeName[0x0C] = "RC_DEBUG";
60  fRecordTypeName[0x0D] = "RECOVER";
61  fRecordTypeName[0x0E] = "APP_GPS";
62  fRecordTypeName[0x0F] = "FIRMWARE";
63  fRecordTypeName[0x10] = "OFDM_DEBUG";
64  fRecordTypeName[0x11] = "VISION_GROUP";
65  fRecordTypeName[0x12] = "VISION_WARN";
66  fRecordTypeName[0x13] = "MC_PARAM";
67  fRecordTypeName[0x14] = "APP_OPERATION";
68  // What is record type 0x16? #####
69  fRecordTypeName[0x18] = "APP_SER_WARN";
70  // What is record type 0x19? #####
71  // What is record type 0x1a? #####
72  // What is record type 0x1e? #####
73  // What is record type 0x28? #####
74  fRecordTypeName[0x39] = "JPEG";
75  fRecordTypeName[0xFE] = "OTHER";
76 #endif
77 }

References fRecordTypeName.

◆ ~RecordAndDetailsParser()

RecordAndDetailsParser::~RecordAndDetailsParser ( )
virtual

Definition at line 79 of file RecordAndDetailsParser.cpp.

79  {
80  delete fFieldDatabase;
81 }

References fFieldDatabase.

Member Function Documentation

◆ createNew()

DJITxtParser * DJITxtParser::createNew ( )
staticinherited

Definition at line 29 of file RecordAndDetailsParser.cpp.

Referenced by main().

◆ enterSubByteField()

void RecordAndDetailsParser::enterSubByteField ( char const *  label,
u_int8_t  byte,
u_int8_t  mask 
)
private

Definition at line 29 of file parseFieldWithinRecord.cpp.

29  {
30  // First, use "mask" to select the bits that we want, and move them to the low-order part of the byte:
31  byte &= mask;
32  while (mask != 0x00 && (mask&0x01) == 0) {
33  byte >>= 1;
34  mask >>= 1;
35  }
36 
37  fFieldDatabase->addByteField(label, byte, 0);
38 }
void addByteField(char const *label, u_int8_t value, int isSigned)

Referenced by parseRecord_DEFORM(), parseRecord_GIMBAL(), parseRecord_HOME(), parseRecord_OSD(), parseRecord_RC(), and parseRecord_SMART_BATTERY().

◆ note2ByteDateField()

void RecordAndDetailsParser::note2ByteDateField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 123 of file parseFieldWithinRecord.cpp.

123  {
124  u_int16_t bytes = get2BytesLE(ptr, limit);
125  fFieldDatabase->add2ByteDateField(label, bytes);
126 }
void add2ByteDateField(char const *label, u_int16_t value)
u_int16_t get2BytesLE(u_int8_t const *&ptr, u_int8_t const *limit)

References get2BytesLE().

Referenced by parseRecord_CENTER_BATTERY().

◆ note2ByteField()

void RecordAndDetailsParser::note2ByteField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit,
float  divisor = 0.0,
int16_t  offset = 0,
int  isSigned = 0 
)
private

Definition at line 56 of file parseFieldWithinRecord.cpp.

57  {
58  u_int16_t bytes = get2BytesLE(ptr, limit);
59  bytes -= offset;
60 
61  if (divisor != 0.0) {
62  // Divide by this, and store the resulting value as a 'float' instead:
63  float value = isSigned ? (int16_t)bytes/divisor : bytes/divisor;
64  fFieldDatabase->addFloatField(label, value);
65  } else {
66  // Normal case:
67  fFieldDatabase->add2ByteField(label, bytes, isSigned);
68  }
69 }
void add2ByteField(char const *label, u_int16_t value, int isSigned)
void addFloatField(char const *label, float value)
u_int16_t get2BytesLE(u_int8_t const *&ptr, u_int8_t const *limit)

References get2BytesLE().

Referenced by noteSigned2ByteField(), and noteUnsigned2ByteField().

◆ note3ByteVersionField()

void RecordAndDetailsParser::note3ByteVersionField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 148 of file parseFieldWithinRecord.cpp.

148  {
149  u_int8_t v1 = getByte(ptr, limit);
150  u_int8_t v2 = getByte(ptr, limit);
151  u_int8_t v3 = getByte(ptr, limit);
152 
153  // Pack these three bytes into a 4-byte value (big-endian), and store this:
154  u_int32_t value = (v1<<24)|(v2<<16)|(v3<<8);
155  fFieldDatabase->add4ByteVersionField(label, value);
156 }
u_int8_t getByte(u_int8_t const *&ptr, u_int8_t const *limit)
void add4ByteVersionField(char const *label, u_int32_t value)

References getByte().

Referenced by parseDetailsArea(), parseRecord_FIRMWARE(), and parseRecord_RECOVER().

◆ note4ByteField()

void RecordAndDetailsParser::note4ByteField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit,
float  divisor = 0.0,
int  isSigned = 0 
)
private

Definition at line 72 of file parseFieldWithinRecord.cpp.

73  {
74  u_int32_t bytes = getWord32LE(ptr, limit);
75 
76  if (divisor != 0.0) {
77  // Divide by this, and store the resulting value as a 'float' instead:
78  float value = isSigned ? (int32_t)bytes/divisor : bytes/divisor;
79  fFieldDatabase->addFloatField(label, value);
80  } else {
81  // Normal case:
82  fFieldDatabase->add4ByteField(label, bytes, isSigned);
83  }
84 }
unsigned getWord32LE(u_int8_t const *&ptr, u_int8_t const *limit)
void addFloatField(char const *label, float value)
void add4ByteField(char const *label, u_int32_t value, int isSigned)

References getWord32LE().

Referenced by parseDetailsArea(), parseRecord_CENTER_BATTERY(), and parseRecord_SMART_BATTERY().

◆ note4ByteFloatField()

void RecordAndDetailsParser::note4ByteFloatField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit,
float  divisor = 0.0 
)
private

Definition at line 87 of file parseFieldWithinRecord.cpp.

88  {
89  u_int32_t bytes = getWord32LE(ptr, limit);
90  float value = *(float*)&bytes;
91  if (divisor != 0.0) value /= divisor;
92  fFieldDatabase->addFloatField(label, value);
93 }
unsigned getWord32LE(u_int8_t const *&ptr, u_int8_t const *limit)
void addFloatField(char const *label, float value)

References getWord32LE().

Referenced by parseDetailsArea(), parseRecord_APP_GPS(), parseRecord_CUSTOM(), parseRecord_HOME(), and parseRecord_SMART_BATTERY().

◆ note8ByteDoubleField()

void RecordAndDetailsParser::note8ByteDoubleField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 96 of file parseFieldWithinRecord.cpp.

96  {
97  u_int64_t bytes = getWord64LE(ptr, limit);
98  fFieldDatabase->addDoubleField(label, *(double*)&bytes);
99 }
u_int64_t getWord64LE(u_int8_t const *&ptr, u_int8_t const *limit)
void addDoubleField(char const *label, double value)

References getWord64LE().

Referenced by parseDetailsArea().

◆ note8ByteLatitudeOrLongitudeFieldInDegrees()

void RecordAndDetailsParser::note8ByteLatitudeOrLongitudeFieldInDegrees ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 115 of file parseFieldWithinRecord.cpp.

115  {
116  u_int64_t bytes = getWord64LE(ptr, limit);
117  double* value = (double*)&bytes;
118 
119  fFieldDatabase->addDoubleField(label, *value);
120 }
u_int64_t getWord64LE(u_int8_t const *&ptr, u_int8_t const *limit)
void addDoubleField(char const *label, double value)

References getWord64LE().

Referenced by parseRecord_APP_GPS().

◆ note8ByteLatitudeOrLongitudeFieldInRadians()

void RecordAndDetailsParser::note8ByteLatitudeOrLongitudeFieldInRadians ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 106 of file parseFieldWithinRecord.cpp.

106  {
107  u_int64_t bytes = getWord64LE(ptr, limit);
108  double* value = (double*)&bytes;
109 
110  // This value is in radians. Convert it to degrees before storing it as a 'double':
111  fFieldDatabase->addDoubleField(label, (*value)*(180/PI));
112 }
u_int64_t getWord64LE(u_int8_t const *&ptr, u_int8_t const *limit)
void addDoubleField(char const *label, double value)
#define PI

References getWord64LE(), and PI.

Referenced by parseRecord_HOME(), and parseRecord_OSD().

◆ note8ByteTimestampField()

void RecordAndDetailsParser::note8ByteTimestampField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit,
int  isInMilliseconds = 0 
)
private

Definition at line 129 of file parseFieldWithinRecord.cpp.

130  {
131  u_int64_t value = getWord64LE(ptr, limit);
132  fFieldDatabase->add8ByteTimestampField(label, value, isInMilliseconds);
133 }
u_int64_t getWord64LE(u_int8_t const *&ptr, u_int8_t const *limit)
void add8ByteTimestampField(char const *label, u_int64_t value, int isInMilliseconds)

References getWord64LE().

Referenced by parseDetailsArea(), parseRecord_CUSTOM(), and parseRecord_RECOVER().

◆ noteByteField()

void RecordAndDetailsParser::noteByteField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit,
float  divisor = 0.0,
int  isSigned = 0 
)
private

Definition at line 41 of file parseFieldWithinRecord.cpp.

42  {
43  u_int8_t byte = getByte(ptr, limit);
44 
45  if (divisor != 0.0) {
46  // Divide by this, and store the resulting value as a 'float' instead:
47  float value = isSigned ? (int8_t)byte/divisor : byte/divisor;
48  fFieldDatabase->addFloatField(label, value);
49  } else {
50  // Normal case:
51  fFieldDatabase->addByteField(label, byte, isSigned);
52  }
53 }
u_int8_t getByte(u_int8_t const *&ptr, u_int8_t const *limit)
void addByteField(char const *label, u_int8_t value, int isSigned)
void addFloatField(char const *label, float value)

References getByte().

Referenced by parseDetailsArea(), parseRecord_CENTER_BATTERY(), parseRecord_GIMBAL(), parseRecord_HOME(), parseRecord_OSD(), parseRecord_RECOVER(), and parseRecord_SMART_BATTERY().

◆ noteSigned2ByteField()

void RecordAndDetailsParser::noteSigned2ByteField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit,
float  divisor = 0.0,
int16_t  offset = 0 
)
inlineprivate

Definition at line 87 of file RecordAndDetailsParser.hh.

88  {
89  note2ByteField(label, ptr, limit, divisor, offset, 1);
90  }
void note2ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int16_t offset=0, int isSigned=0)

References note2ByteField().

Referenced by parseRecord_GIMBAL(), parseRecord_HOME(), parseRecord_OSD(), and parseRecord_RC().

◆ noteStringField()

void RecordAndDetailsParser::noteStringField ( char const *  label,
u_int8_t const *&  ptr,
unsigned  stringLength,
u_int8_t const *  limit 
)
private

Definition at line 136 of file parseFieldWithinRecord.cpp.

136  {
137  if (limit != NULL && ptr > limit - stringLength) throw END_OF_DATA;
138 
139  char str[stringLength+1];
140  unsigned i;
141  for (i = 0; i < stringLength; ++i) str[i] = *ptr++;
142  str[i] = '\0';
143 
144  fFieldDatabase->addStringField(label, str);
145 }
#define END_OF_DATA
Definition: DJITxtParser.hh:47
void addStringField(char const *label, char const *str)

References END_OF_DATA.

Referenced by parseDetailsArea(), parseRecord_APP_SER_WARN(), parseRecord_APP_TIP(), parseRecord_APP_WARN(), parseRecord_COMPONENT(), and parseRecord_RECOVER().

◆ noteUnsigned2ByteField()

void RecordAndDetailsParser::noteUnsigned2ByteField ( char const *  label,
u_int8_t const *&  ptr,
u_int8_t const *  limit,
float  divisor = 0.0,
int16_t  offset = 0 
)
inlineprivate

Definition at line 91 of file RecordAndDetailsParser.hh.

92  {
93  note2ByteField(label, ptr, limit, divisor, offset, 0);
94  }
void note2ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int16_t offset=0, int isSigned=0)

References note2ByteField().

Referenced by parseRecord_CENTER_BATTERY(), parseRecord_HOME(), parseRecord_OSD(), and parseRecord_SMART_BATTERY().

◆ outputOneRow()

void RecordAndDetailsParser::outputOneRow ( int  outputColumnLabels)
privatevirtual

Implements DJITxtParser.

Definition at line 39 of file rowOutput.cpp.

39  {
40  oFirst("CUSTOM.updateTime");
41  oFrac("CUSTOM.hSpeed", 2);
42  oFrac("CUSTOM.distance", 2);
43  oFrac("OSD.latitude", 6);
44  oFrac("OSD.longitude", 6);
45  oFrac("OSD.height", 1);
46  oFrac("OSD.xSpeed", 1);
47  oFrac("OSD.ySpeed", 1);
48  oFrac("OSD.zSpeed", 1);
49  oFrac("OSD.pitch", 1);
50  oFrac("OSD.roll", 1);
51  oFrac("OSD.yaw", 1);
52  oInterpreted("OSD.flycState.RAW", "OSD.flycState");
53  oInterpreted("OSD.flycCommand.RAW", "OSD.flycCommand");
54  oBoolean("OSD.canIOCWork");
55  oInterpreted("OSD.groundOrSky.RAW", "OSD.groundOrSky");
56  oBoolean("OSD.isMotorUp");
57  oBoolean("OSD.isSwaveWork");
58  oInterpreted("OSD.goHomeStatus.RAW", "OSD.goHomeStatus");
59  oBoolean("OSD.isImuPreheated");
60  oBoolean("OSD.isVisionUsed");
61  o("OSD.voltageWarning");
62  o("OSD.modeChannel");
63  oBoolean("OSD.compassError");
64  oBoolean("OSD.waveError");
65  o("OSD.gpsLevel");
66  oInterpreted("OSD.batteryType.RAW", "OSD.batteryType");
67  oBoolean("OSD.isAcceletorOverRange");
68  oBoolean("OSD.isVibrating");
69  oBoolean("OSD.isBarometerDeadInAir");
70  oBoolean("OSD.isMotorBlocked");
71  oBoolean("OSD.isNotEnoughForce");
72  oBoolean("OSD.isPropellerCatapult");
73  oBoolean("OSD.isGoHomeHeightModified");
74  oBoolean("OSD.isOutOfLimit");
75  o("OSD.gpsNum");
76  o("OSD.flightAction");
77  oInterpreted("OSD.flightAction.RAW", "OSD.flightAction");
78  oInterpreted("OSD.motorStartFailedCause.RAW", "OSD.motorStartFailedCause");
79  oInterpreted("OSD.nonGPSCause.RAW", "OSD.nonGPSCause");
80  oBoolean("OSD.isQuickSpin");
81  o("OSD.battery");
82  oFrac("OSD.sWaveHeight", 1);
83  oFrac("OSD.flyTime", 1);
84  o("OSD.motorRevolution");
85  o("OSD.flycVersion");
86  oInterpreted("OSD.droneType.RAW", "OSD.droneType");
87  oInterpreted("OSD.imuInitFailReason.RAW", "OSD.imuInitFailReason");
88  oInterpreted("OSD.motorFailReason.RAW", "OSD.motorFailReason");
89  oInterpreted("OSD.ctrlDevice.RAW", "OSD.ctrlDevice");
90  oFrac("GIMBAL.pitch", 1);
91  oFrac("GIMBAL.roll", 1);
92  oFrac("GIMBAL.yaw", 1);
93  oInterpreted("GIMBAL.mode.RAW", "GIMBAL.mode");
94  oFrac("GIMBAL.rollAdjust", 1);
95  oFrac("GIMBAL.yawAngle", 1);
96  oBoolean("GIMBAL.isAutoCalibration");
97  o("GIMBAL.autoCalibrationResult");
98  oBoolean("GIMBAL.isPitchInLimit");
99  oBoolean("GIMBAL.isRollInLimit");
100  oBoolean("GIMBAL.isYawInLimit");
101  oBoolean("GIMBAL.isStuck");
102  o("GIMBAL.version");
103  oBoolean("GIMBAL.isSingleClick");
104  oBoolean("GIMBAL.isDoubleClick");
105  oBoolean("GIMBAL.isTripleClick");
106  o("RC.aileron");
107  o("RC.elevator");
108  o("RC.throttle");
109  o("RC.rudder");
110  o("RC.gimbal");
111  o("RC.goHome");
112  o("RC.mode");
113  o("RC.wheelOffset");
114  o("RC.record");
115  o("RC.shutter");
116  o("RC.playback");
117  o("RC.custom1");
118  o("RC.custom2");
119  o("CENTER_BATTERY.relativeCapacity");
120  o("CENTER_BATTERY.currentPV");
121  o("CENTER_BATTERY.currentCapacity");
122  o("CENTER_BATTERY.fullCapacity");
123  o("CENTER_BATTERY.life");
124  o("CENTER_BATTERY.loopNum");
125  o("CENTER_BATTERY.errorType");
126  o("CENTER_BATTERY.current");
127  o("CENTER_BATTERY.voltageCell1");
128  o("CENTER_BATTERY.voltageCell2");
129  o("CENTER_BATTERY.voltageCell3");
130  o("CENTER_BATTERY.voltageCell4");
131  o("CENTER_BATTERY.voltageCell5");
132  o("CENTER_BATTERY.voltageCell6");
133  o("CENTER_BATTERY.serialNo");
134  o("CENTER_BATTERY.productDate");
135  o("CENTER_BATTERY.temperature");
136  o("CENTER_BATTERY.connStatus");
137  o("CENTER_BATTERY.totalStudyCycle");
138  o("CENTER_BATTERY.lastStudyCycle");
139  o("CENTER_BATTERY.isNeedStudy");
140  o("CENTER_BATTERY.isBatteryOnCharge");
141  o("SMART_BATTERY.usefulTime");
142  o("SMART_BATTERY.goHomeTime");
143  o("SMART_BATTERY.landTime");
144  o("SMART_BATTERY.goHomeBattery");
145  o("SMART_BATTERY.landBattery");
146  o("SMART_BATTERY.safeFlyRadius");
147  o("SMART_BATTERY.volumeConsume");
148  oInterpreted("SMART_BATTERY.status.RAW", "SMART_BATTERY.status");
149  oInterpreted("SMART_BATTERY.goHomeStatus.RAW", "SMART_BATTERY.goHomeStatus");
150  o("SMART_BATTERY.goHomeCountdown");
151  o("SMART_BATTERY.voltage");
152  o("SMART_BATTERY.battery");
153  o("SMART_BATTERY.lowWarning");
154  o("SMART_BATTERY.lowWarningGoHome");
155  o("SMART_BATTERY.seriousLowWarning");
156  o("SMART_BATTERY.seriousLowWarningLanding");
157  o("SMART_BATTERY.voltagePercent");
158  o("DEFORM.isDeformProtected");
159  oInterpreted("DEFORM.deformStatus.RAW", "DEFORM.deformStatus");
160  oInterpreted("DEFORM.deformMode.RAW","DEFORM.deformMode");
161  oFrac("HOME.latitude", 6);
162  oFrac("HOME.longitude", 6);
163  oFrac("HOME.height", 2);
164  oBoolean("HOME.isHomeRecord");
165  o("HOME.goHomeMode");
166  o("HOME.aircraftHeadDirection");
167  oBoolean("HOME.isDynamicHomePointEnabled");
168  o("HOME.goHomeStatus");
169  oBoolean("HOME.hasGoHome");
170  o("HOME.compassCeleStatus");
171  oBoolean("HOME.isCompassCeleing");
172  oBoolean("HOME.isBeginnerMode");
173  oBoolean("HOME.isIOCEnabled");
174  oInterpreted("HOME.iocMode.RAW", "HOME.iocMode");
175  o("HOME.goHomeHeight");
176  oFrac("HOME.courseLockAngle", 1);
177  o("HOME.dataRecorderStatus");
178  o("HOME.dataRecorderRemainCapacity");
179  o("HOME.dataRecorderRemainTime");
180  o("HOME.dataRecorderFileIndex");
181  o("HOME.maxAllowedHeight");
182  oInterpreted("RECOVER.droneType.RAW", "RECOVER.droneType");
183  oInterpreted("RECOVER.appType.RAW", "RECOVER.appType");
184  o("RECOVER.appVersion");
185  o("RECOVER.aircraftSn");
186  o("RECOVER.aircraftName");
187  o("RECOVER.activeTimestamp");
188  o("RECOVER.cameraSn");
189  o("RECOVER.rcSn");
190  o("RECOVER.batterySn");
191  o("FIRMWARE.version");
192  o("COMPONENT.cameraSn");
193  o("COMPONENT.aircraftSn");
194  o("COMPONENT.rcSn");
195  o("COMPONENT.batterySn");
196  o("DETAILS.street");
197  o("DETAILS.citypart");
198  o("DETAILS.city");
199  o("DETAILS.area");
200  o("DETAILS.isFavorite");
201  o("DETAILS.isNew");
202  o("DETAILS.needUpload");
203  o("DETAILS.recordLineCount");
204  o("DETAILS.timestamp");
205  oFrac("DETAILS.latitude", 6);
206  oFrac("DETAILS.longitude", 6);
207  oFrac("DETAILS.totalDistance", 2);
208  oFrac("DETAILS.totalTime", 1);
209  oFrac("DETAILS.maxHeight", 1);
210  oFrac("DETAILS.maxHorizontalSpeed", 2);
211  oFrac("DETAILS.maxVerticalSpeed", 1);
212  o("DETAILS.photoNum");
213  o("DETAILS.videoTime");
214  o("DETAILS.activeTimestamp");
215  o("DETAILS.aircraftName");
216  o("DETAILS.aircraftSn");
217  o("DETAILS.cameraSn");
218  o("DETAILS.rcSn");
219  o("DETAILS.batterySn");
220  oInterpreted("DETAILS.appType.RAW", "DETAILS.appType");
221  o("DETAILS.appVersion");
222  oFrac("APP_GPS.latitude", 6);
223  oFrac("APP_GPS.longitude", 6);
224  o("APP_GPS.accuracy");
225  o("APP_TIP.tip");
226  o("APP_WARN.warn");
227  o("APP_SER_WARN.warn");
228  printf("\n");
229 }
#define o(label)
Definition: rowOutput.cpp:35
#define oInterpreted(label, interpretedLabel)
Definition: rowOutput.cpp:36
#define oFrac(label, nFrac)
Definition: rowOutput.cpp:34
#define oFirst(label)
Definition: rowOutput.cpp:33
#define oBoolean(label)
Definition: rowOutput.cpp:37

References o, oBoolean, oFirst, oFrac, and oInterpreted.

Referenced by parseRecord().

◆ parseDetailsArea()

void RecordAndDetailsParser::parseDetailsArea ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
privatevirtual

Implements DJITxtParser.

Definition at line 28 of file parseDetails.cpp.

28  {
29  // DETAILS.cityPart: string (length 20):
30  noteStringField("DETAILS.cityPart", ptr, 20, limit);
31 
32  // DETAILS.street: string (length 20):
33  noteStringField("DETAILS.street", ptr, 20, limit);
34 
35  // DETAILS.city: string (length 20):
36  noteStringField("DETAILS.city", ptr, 20, limit);
37 
38  // DETAILS.area: string (length 20):
39  noteStringField("DETAILS.area", ptr, 20, limit);
40 
41  // DETAILS.isFavorite: 1 byte unsigned:
42  noteByteField("DETAILS.isFavorite", ptr, limit);
43 
44  // DETAILS.isNew: 1 byte unsigned:
45  noteByteField("DETAILS.isNew", ptr, limit);
46 
47  // DETAILS.needsUpload: 1 byte unsigned:
48  noteByteField("DETAILS.needUpload", ptr, limit);
49 
50  // DETAILS.recordLineCount: 4 bytes little-endian unsigned::
51  note4ByteField("DETAILS.recordLineCount", ptr, limit);
52 
53  // unknown (4 bytes):
54  ptr += 4;
55 
56  // DETAILS.timestamp: 8 bytes little-endian, multiple of 0.001 seconds, in Unix time format:
57  note8ByteTimestampField("DETAILS.timestamp", ptr, limit, 1/*is in ms*/);
58 
59  // DETAILS.longitude: 8 bytes little-endian double, in degrees:
60  note8ByteDoubleField("DETAILS.longitude", ptr, limit);
61 
62  // DETAILS.latitude: 8 bytes little-endian double, in degrees:
63  note8ByteDoubleField("DETAILS.latitude", ptr, limit);
64 
65  // DETAILS.totalDistance: 4 bytes little-endian float:
66  note4ByteFloatField("DETAILS.totalDistance", ptr, limit);
67 
68  // DETAILS.totalTime: 4 bytes little-endian unsigned, multiple of 0.001m; convert to meters:
69  note4ByteField("DETAILS.totalTime", ptr, limit, 1000.0);
70 
71  // DETAILS.maxHeight: 4 bytes little-endian float:
72  note4ByteFloatField("DETAILS.maxHeight", ptr, limit);
73 
74  // DETAILS.maxHorizontalSpeed: 4 bytes little-endian float:
75  note4ByteFloatField("DETAILS.maxHorizontalSpeed", ptr, limit);
76 
77  // DETAILS.maxVerticalSpeed: 4 bytes little-endian float:
78  note4ByteFloatField("DETAILS.maxVerticalSpeed", ptr, limit);
79 
80  // DETAILS.photoNum: 4 bytes little-endian unsigned:
81  note4ByteField("DETAILS.photoNum", ptr, limit);
82 
83  // DETAILS.videoTime: 4 bytes little-endian unsigned:
84  note4ByteField("DETAILS.videoTime", ptr, limit);
85 
86  // The format from here on depends upon the file version:
87  extern u_int8_t fileVersionNumber;
88  if (fileVersionNumber < 0x06) {
89  // unknown (124 bytes)
90  ptr += 124;
91 
92  // DETAILS.aircraftSnBytes: string (length 10):
93  noteStringField("DETAILS.aircraftSn", ptr, 10, limit);
94 
95  // unknown (1 byte)
96  ++ptr;
97 
98  // DETAILS.aircraftName: string (length 25):
99  noteStringField("DETAILS.aircraftName", ptr, 25, limit);
100 
101  // unknown (7 bytes)
102  ptr += 7;
103 
104  // DETAILS.activeTimestamp: 8 bytes little-endian, in Unix time format:
105  note8ByteTimestampField("DETAILS.activeTimestamp", ptr, limit);
106 
107  // DETAILS.cameraSn: string (length 10):
108  noteStringField("DETAILS.cameraSn", ptr, 10, limit);
109 
110  // DETAILS.rcSn: string (length 10):
111  noteStringField("DETAILS.rcSn", ptr, 10, limit);
112 
113  // DETAILS.batterySn: string (length 10):
114  noteStringField("DETAILS.batterySn", ptr, 10, limit);
115  } else {
116  // Where is "DETAILS.activeTimestamp", and how is it formatted? #####
117  // unknown (137 bytes)
118  ptr += 137;
119 
120  // DETAILS.aircraftName: string (length 32):
121  noteStringField("DETAILS.aircraftName", ptr, 32, limit);
122 
123  // DETAILS.aircraftSnBytes: string (length 16):
124  noteStringField("DETAILS.aircraftSn", ptr, 16, limit);
125 
126  // DETAILS.cameraSn: string (length 16):
127  noteStringField("DETAILS.cameraSn", ptr, 16, limit);
128 
129  // DETAILS.rcSn: string (length 16):
130  noteStringField("DETAILS.rcSn", ptr, 16, limit);
131 
132  // DETAILS.batterySn: string (length 16):
133  noteStringField("DETAILS.batterySn", ptr, 16, limit);
134  }
135 
136  // DETAILS.appType.RAW: 1 byte unsigned:
137  noteByteField("DETAILS.appType.RAW", ptr, limit);
138 
139  // DETAILS.appVersion: 3 bytes:
140  note3ByteVersionField("DETAILS.appVersion", ptr, limit);
141 }
void note8ByteDoubleField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
u_int8_t fileVersionNumber
Definition: djiparsetxt.cpp:35
void note4ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)
void note8ByteTimestampField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, int isInMilliseconds=0)
void note3ByteVersionField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
void noteStringField(char const *label, u_int8_t const *&ptr, unsigned stringLength, u_int8_t const *limit)
void note4ByteFloatField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0)
void noteByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)

References fileVersionNumber, note3ByteVersionField(), note4ByteField(), note4ByteFloatField(), note8ByteDoubleField(), note8ByteTimestampField(), noteByteField(), and noteStringField().

◆ parseJPEGRecord()

int RecordAndDetailsParser::parseJPEGRecord ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)

◆ parseRecord()

int RecordAndDetailsParser::parseRecord ( u_int8_t const *&  ptr,
u_int8_t const *  limit,
int  isScrambled 
)
privatevirtual

Implements DJITxtParser.

Definition at line 62 of file parseRecord.cpp.

62  {
63  // Attempt to parse a record; Returns 1 iff it succeeds.
64  try {
65  // The first two bytes are the 'record type' and the 'record length':
66  u_int8_t recordType = getByte(ptr, limit);
67  unsigned recordLength = getByte(ptr, limit);
68 
69  // Record statistics about the record type and length:
70  ++fNumRecords;
71  RecordTypeStat& stat = fRecordTypeStats[recordType]; // alias
72  ++stat.count;
74  if (recordLength < stat.minLength) stat.minLength = recordLength;
75  if (recordLength > stat.maxLength) stat.maxLength = recordLength;
76 #ifdef DEBUG_RECORD_PARSING
77  char const* recordTypeName = fRecordTypeName[recordType];
78  if (recordTypeName == NULL) recordTypeName = "???";
79  fprintf(stderr, "[%d]\trecordType %d[%s], recordLength %d\n", fRecordTypeStats[RECORD_TYPE_OSD].count, recordType, recordTypeName, recordLength);
80 #endif
81 
82  if (recordType == RECORD_TYPE_JPEG) {
83  u_int16_t next2Bytes = get2BytesBE(ptr, limit); ptr -= 2; // back up over those two bytes
84  if (next2Bytes == 0x0000) {
85  // This record contains one or more JPEG images, and needs to be handled especially.
86  // (In particular, the 'recordLength' seems to be irrelevant in this case)
87  return parseRecord_JPEG(ptr, limit);
88  }
89  } else if (recordType == 0xFF && recordLength == JPEG_SOI_BYTE) {
90  // Some old log formats start JPEG images this way. Back up 4 bytes; handle them the same way:
91  ptr -=4;
92  return parseRecord_JPEG(ptr, limit);
93  }
94 
95  // Check the record length, and whether there's a 0xFF byte at the end:
96  if (ptr + recordLength + 1 >= limit) throw END_OF_DATA;
97  if (ptr[recordLength] != 0xFF) {
98  // In newer versions of the format, some records have an extra byte before the 0xFF. Check:
99  if (ptr + recordLength + 2 < limit && ptr[recordLength+1] == 0xFF) {
100  fprintf(stderr, "Extra byte 0x%02x seen in record (type 0x%x)\n", ptr[recordLength], recordType);
101  ++recordLength;
102  } else {
103  fprintf(stderr, "'End of record' byte (0xFF) not seen; advancing to the next 0xFF\n");
104  do {
105  ++recordLength;
106  } while (ptr + recordLength + 1 < limit && ptr[recordLength+1] != 0xFF);
107  if (ptr + recordLength + 1 >= limit) throw END_OF_DATA;
108  }
109  }
110  u_int8_t const* recordStart = ptr;
111  u_int8_t const* recordLimit = ptr + recordLength; // position of the 0xFF 'End of record' byte
112  ptr += recordLength + 1; // advance to the next record, if any
113 
114  u_int8_t unscrambledRecord[recordLength-1]; // used only if "isScrambled"
115  if (isScrambled) {
116  // We need to unscramble the record data before we can parse it.
117 
118  // The next byte (along with the 'record type') is used as a key to unscramble the data:
119  u_int8_t keyByte = getByte(recordStart, limit);
120  --recordLength;
121 
122  // Get an array of 8 bytes - used to unscramble the data:
123  u_int8_t scrambleBytes[8];
124  getScrambleBytes(recordType, keyByte, scrambleBytes);
125 
126  // Unscramble each byte in the record by XORing it with the 'scrambleBytes':
127  for (unsigned i = 0; i < recordLength; ++i) {
128  unscrambledRecord[i] = recordStart[i] ^ scrambleBytes[i%8];
129  }
130 
131  recordStart = unscrambledRecord;
132  recordLimit = unscrambledRecord + recordLength;
133  }
134 
135  switch (recordType) {
136  case RECORD_TYPE_OSD: {
137  // Because an 'OSD' record effectively starts a new row of data, output a row of data
138  // before we parse it (except for the very first 'OSD' record, where we output
139  // the column labels instead):
141  parseRecord_OSD(recordStart, recordLimit);
142  break;
143  }
144  case RECORD_TYPE_HOME: {
145  parseRecord_HOME(recordStart, recordLimit);
146  break;
147  }
148  case RECORD_TYPE_GIMBAL: {
149  parseRecord_GIMBAL(recordStart, recordLimit);
150  break;
151  }
152  case RECORD_TYPE_RC: {
153  parseRecord_RC(recordStart, recordLimit);
154  break;
155  }
156  case RECORD_TYPE_CUSTOM: {
157  parseRecord_CUSTOM(recordStart, recordLimit);
158  break;
159  }
160  case RECORD_TYPE_DEFORM: {
161  parseRecord_DEFORM(recordStart, recordLimit);
162  break;
163  }
165  parseRecord_CENTER_BATTERY(recordStart, recordLimit);
166  break;
167  }
169  parseRecord_SMART_BATTERY(recordStart, recordLimit);
170  break;
171  }
172  case RECORD_TYPE_APP_TIP: {
173  parseRecord_APP_TIP(recordStart, recordLimit);
174  break;
175  }
176  case RECORD_TYPE_APP_WARN: {
177  parseRecord_APP_WARN(recordStart, recordLimit);
178  break;
179  }
180  case RECORD_TYPE_RC_GPS: {
181  parseRecordUnknownFormat("RC_GPS", recordStart, recordLimit);
182  break;
183  }
184  case RECORD_TYPE_RC_DEBUG: {
185  parseRecordUnknownFormat("RC_DEBUG", recordStart, recordLimit);
186  break;
187  }
188  case RECORD_TYPE_RECOVER: {
189  parseRecord_RECOVER(recordStart, recordLimit);
190  break;
191  }
192  case RECORD_TYPE_APP_GPS: {
193  parseRecord_APP_GPS(recordStart, recordLimit);
194  break;
195  }
196  case RECORD_TYPE_FIRMWARE: {
197  parseRecord_FIRMWARE(recordStart, recordLimit);
198  break;
199  }
200  case RECORD_TYPE_OFDM_DEBUG: {
201  parseRecordUnknownFormat("OFDM_DEBUG", recordStart, recordLimit);
202  break;
203  }
205  parseRecordUnknownFormat("VISION_GROUP", recordStart, recordLimit);
206  break;
207  }
209  parseRecordUnknownFormat("VISION_WARN", recordStart, recordLimit);
210  break;
211  }
212  case RECORD_TYPE_MC_PARAM: {
213  parseRecordUnknownFormat("MC_PARAM", recordStart, recordLimit);
214  break;
215  }
217  parseRecordUnknownFormat("APP_OPERATION", recordStart, recordLimit);
218  break;
219  }
221  parseRecord_APP_SER_WARN(recordStart, recordLimit);
222  break;
223  }
224  case RECORD_TYPE_COMPONENT: {
225  parseRecord_COMPONENT(recordStart, recordLimit);
226  break;
227  }
228  default: {
229 #ifdef DEBUG_RECORD_PARSING
230  char const* recordTypeName = fRecordTypeName[recordType];
231  if (recordTypeName == NULL) {
232  fprintf(stderr, "Unknown record type 0x%02x\n", recordType);
233  } else {
234  fprintf(stderr, "Unhandled record type 0x%02x [%s]\n", recordType, recordTypeName);
235  }
236 #else
237  fprintf(stderr, "Unhandled record type 0x%02x\n", recordType);
238 #endif
239  }
240  }
241  } catch (int /*e*/) {
242  fprintf(stderr, "Unexpected error in parsing\n");
243  return 0;
244  }
245 
246  return 1;
247 }
void parseRecord_HOME(u_int8_t const *&ptr, u_int8_t const *limit)
u_int8_t getByte(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_OSD
Definition: parseRecord.cpp:31
#define RECORD_TYPE_SMART_BATTERY
Definition: parseRecord.cpp:38
#define RECORD_TYPE_VISION_WARN
Definition: parseRecord.cpp:48
RecordTypeStat fRecordTypeStats[256]
void parseRecord_RECOVER(u_int8_t const *&ptr, u_int8_t const *limit)
void parseRecord_APP_GPS(u_int8_t const *&ptr, u_int8_t const *limit)
void parseRecordUnknownFormat(char const *recordTypeName, u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_APP_TIP
Definition: parseRecord.cpp:39
void getScrambleBytes(u_int8_t recordType, u_int8_t keyByte, u_int8_t *resultScrambleBytes)
#define RECORD_TYPE_COMPONENT
Definition: parseRecord.cpp:56
#define RECORD_TYPE_RC
Definition: parseRecord.cpp:34
void parseRecord_APP_WARN(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_RC_GPS
Definition: parseRecord.cpp:41
#define END_OF_DATA
Definition: DJITxtParser.hh:47
#define RECORD_TYPE_DEFORM
Definition: parseRecord.cpp:36
#define RECORD_TYPE_GIMBAL
Definition: parseRecord.cpp:33
void parseRecord_COMPONENT(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_HOME
Definition: parseRecord.cpp:32
void parseRecord_CENTER_BATTERY(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_RC_DEBUG
Definition: parseRecord.cpp:42
#define RECORD_TYPE_APP_OPERATION
Definition: parseRecord.cpp:50
void parseRecord_CUSTOM(u_int8_t const *&ptr, u_int8_t const *limit)
void parseRecord_DEFORM(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_APP_SER_WARN
Definition: parseRecord.cpp:52
#define RECORD_TYPE_FIRMWARE
Definition: parseRecord.cpp:45
void parseRecord_APP_TIP(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_OFDM_DEBUG
Definition: parseRecord.cpp:46
#define RECORD_TYPE_APP_GPS
Definition: parseRecord.cpp:44
#define RECORD_TYPE_APP_WARN
Definition: parseRecord.cpp:40
#define JPEG_SOI_BYTE
Definition: parseRecord.cpp:60
int parseRecord_JPEG(u_int8_t const *&ptr, u_int8_t const *limit)
void parseRecord_RC(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_CENTER_BATTERY
Definition: parseRecord.cpp:37
void parseRecord_APP_SER_WARN(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_CUSTOM
Definition: parseRecord.cpp:35
void parseRecord_SMART_BATTERY(u_int8_t const *&ptr, u_int8_t const *limit)
void parseRecord_GIMBAL(u_int8_t const *&ptr, u_int8_t const *limit)
virtual void outputOneRow(int outputColumnLabels)
Definition: rowOutput.cpp:39
#define RECORD_TYPE_VISION_GROUP
Definition: parseRecord.cpp:47
void parseRecord_FIRMWARE(u_int8_t const *&ptr, u_int8_t const *limit)
#define RECORD_TYPE_MC_PARAM
Definition: parseRecord.cpp:49
#define RECORD_TYPE_RECOVER
Definition: parseRecord.cpp:43
#define RECORD_TYPE_JPEG
Definition: parseRecord.cpp:57
u_int16_t get2BytesBE(u_int8_t const *&ptr, u_int8_t const *limit)
void parseRecord_OSD(u_int8_t const *&ptr, u_int8_t const *limit)

References RecordTypeStat::count, END_OF_DATA, fMaxNumRecordsForOneType, fNumRecords, fRecordTypeName, fRecordTypeStats, get2BytesBE(), getByte(), getScrambleBytes(), JPEG_SOI_BYTE, RecordTypeStat::maxLength, RecordTypeStat::minLength, outputOneRow(), parseRecord_APP_GPS(), parseRecord_APP_SER_WARN(), parseRecord_APP_TIP(), parseRecord_APP_WARN(), parseRecord_CENTER_BATTERY(), parseRecord_COMPONENT(), parseRecord_CUSTOM(), parseRecord_DEFORM(), parseRecord_FIRMWARE(), parseRecord_GIMBAL(), parseRecord_HOME(), parseRecord_JPEG(), parseRecord_OSD(), parseRecord_RC(), parseRecord_RECOVER(), parseRecord_SMART_BATTERY(), parseRecordUnknownFormat(), RECORD_TYPE_APP_GPS, RECORD_TYPE_APP_OPERATION, RECORD_TYPE_APP_SER_WARN, RECORD_TYPE_APP_TIP, RECORD_TYPE_APP_WARN, RECORD_TYPE_CENTER_BATTERY, RECORD_TYPE_COMPONENT, RECORD_TYPE_CUSTOM, RECORD_TYPE_DEFORM, RECORD_TYPE_FIRMWARE, RECORD_TYPE_GIMBAL, RECORD_TYPE_HOME, RECORD_TYPE_JPEG, RECORD_TYPE_MC_PARAM, RECORD_TYPE_OFDM_DEBUG, RECORD_TYPE_OSD, RECORD_TYPE_RC, RECORD_TYPE_RC_DEBUG, RECORD_TYPE_RC_GPS, RECORD_TYPE_RECOVER, RECORD_TYPE_SMART_BATTERY, RECORD_TYPE_VISION_GROUP, and RECORD_TYPE_VISION_WARN.

◆ parseRecord_APP_GPS()

void RecordAndDetailsParser::parseRecord_APP_GPS ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_APP_GPS.cpp.

28  {
29  // APP_GPS.latitude: 8 bytes little-endian double, in degrees:
30  note8ByteLatitudeOrLongitudeFieldInDegrees("APP_GPS.latitude", ptr, limit);
31 
32  // APP_GPS.longitude: 8 bytes little-endian double, in degrees:
33  note8ByteLatitudeOrLongitudeFieldInDegrees("APP_GPS.longitude", ptr, limit);
34 
35  // APP_GPS.accuracy: 4 bytes little-endian float:
36  note4ByteFloatField("APP_GPS.accuracy", ptr, limit);
37 }
void note8ByteLatitudeOrLongitudeFieldInDegrees(char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
void note4ByteFloatField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0)

References note4ByteFloatField(), and note8ByteLatitudeOrLongitudeFieldInDegrees().

Referenced by parseRecord().

◆ parseRecord_APP_SER_WARN()

void RecordAndDetailsParser::parseRecord_APP_SER_WARN ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_APP_SER_WARN.cpp.

28  {
29  // APP_SER_WARN.warn: string (length of the entire record):
30  noteStringField("APP_SER_WARN.warn", ptr, limit-ptr, limit);
31 }
void noteStringField(char const *label, u_int8_t const *&ptr, unsigned stringLength, u_int8_t const *limit)

References noteStringField().

Referenced by parseRecord().

◆ parseRecord_APP_TIP()

void RecordAndDetailsParser::parseRecord_APP_TIP ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_APP_TIP.cpp.

28  {
29  // APP_TIP.tip: string (length of the entire record):
30  noteStringField("APP_TIP.tip", ptr, limit-ptr, limit);
31 }
void noteStringField(char const *label, u_int8_t const *&ptr, unsigned stringLength, u_int8_t const *limit)

References noteStringField().

Referenced by parseRecord().

◆ parseRecord_APP_WARN()

void RecordAndDetailsParser::parseRecord_APP_WARN ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_APP_WARN.cpp.

28  {
29  // APP_WARN.warn: string (length of the entire record):
30  noteStringField("APP_WARN.warn", ptr, limit-ptr, limit);
31 }
void noteStringField(char const *label, u_int8_t const *&ptr, unsigned stringLength, u_int8_t const *limit)

References noteStringField().

Referenced by parseRecord().

◆ parseRecord_CENTER_BATTERY()

void RecordAndDetailsParser::parseRecord_CENTER_BATTERY ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_CENTER_BATTERY.cpp.

28  {
29  // CENTER_BATTERY.relativeCapacity: 1 byte unsigned:
30  noteByteField("CENTER_BATTERY.relativeCapacity", ptr, limit);
31 
32  // CENTER_BATTERY.currentPV: 2 bytes unsigned little-endian; multiple of 0.001 volts; convert to volts:
33  noteUnsigned2ByteField("CENTER_BATTERY.currentPV", ptr, limit, 1000.0);
34 
35  // CENTER_BATTERY.currentCapacity: 2 bytes unsigned little-endian:
36  noteUnsigned2ByteField("CENTER_BATTERY.currentCapacity", ptr, limit);
37 
38  // CENTER_BATTERY.fullCapacity: 2 bytes unsigned little-endian:
39  noteUnsigned2ByteField("CENTER_BATTERY.fullCapacity", ptr, limit);
40 
41  // CENTER_BATTERY.life: 1 byte unsigned:
42  noteByteField("CENTER_BATTERY.life", ptr, limit);
43 
44  // CENTER_BATTERY.loopNum: 2 bytes unsigned little-endian:
45  noteUnsigned2ByteField("CENTER_BATTERY.loopNum", ptr, limit);
46 
47  // CENTER_BATTERY.errorType: 4 bytes unsigned little-endian:
48  note4ByteField("CENTER_BATTERY.errorType", ptr, limit);
49 
50  // CENTER_BATTERY.current: 2 bytes unsigned little-endian, multiple of 0.001 amps; convert to amps:
51  noteUnsigned2ByteField("CENTER_BATTERY.current", ptr, limit, 1000.0);
52  // CHECK VALUE! #####
53 
54  // CENTER_BATTERY.voltageCell(1 through 6): 2 bytes unsigned little-endian, multiple of 0.001 volts; convert to volts:
55  noteUnsigned2ByteField("CENTER_BATTERY.voltageCell1", ptr, limit, 1000.0);
56  noteUnsigned2ByteField("CENTER_BATTERY.voltageCell2", ptr, limit, 1000.0);
57  noteUnsigned2ByteField("CENTER_BATTERY.voltageCell3", ptr, limit, 1000.0);
58  noteUnsigned2ByteField("CENTER_BATTERY.voltageCell4", ptr, limit, 1000.0);
59  noteUnsigned2ByteField("CENTER_BATTERY.voltageCell5", ptr, limit, 1000.0);
60  noteUnsigned2ByteField("CENTER_BATTERY.voltageCell6", ptr, limit, 1000.0);
61 
62  // CENTER_BATTERY.serialNo: 2 bytes unsigned little-endian:
63  noteUnsigned2ByteField("CENTER_BATTERY.serialNo", ptr, limit);
64 
65  // CENTER_BATTERY.productDate: 2 bytes little-endian: 7 bits (years since 1980) + 4 bits (month) + 5 bits (day of month):
66  note2ByteDateField("CENTER_BATTERY.productDate", ptr, limit);
67 
68  // CENTER_BATTERY.temperature: 2 bytes unsigned little-endian, multiple of 0.01 C; convert to C:
69  noteUnsigned2ByteField("CENTER_BATTERY.temperature", ptr, limit, 100.0);
70  // CHECK VALUE #####
71 
72  // CENTER_BATTERY.connStatus.RAW: 1 byte unsigned:
73  noteByteField("CENTER_BATTERY.connStatus.RAW", ptr, limit);
74 }
void noteUnsigned2ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int16_t offset=0)
void note4ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)
void noteByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)
void note2ByteDateField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit)

References note2ByteDateField(), note4ByteField(), noteByteField(), and noteUnsigned2ByteField().

Referenced by parseRecord().

◆ parseRecord_COMPONENT()

void RecordAndDetailsParser::parseRecord_COMPONENT ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_COMPONENT.cpp.

28  {
29  // Because these records always seem to appear at the beginning of the file, before the
30  // first OSD record, treat each (known) component type as a separate column in the output:
31 
32  // COMPONENT.type: 2 bytes little-endian unsigned
33  u_int16_t componentType = get2BytesLE(ptr, limit);
34 
35  // Length of the following serial number: 1 byte
36  unsigned serialNumberLength = getByte(ptr, limit);
37 
38  // COMPONENT.<type>Sn: string (length "serialNumberLength"):
39  noteStringField(componentType == 1 ? "COMPONENT.cameraSn":
40  componentType == 2 ? "COMPONENT.aircraftSn":
41  componentType == 3 ? "COMPONENT.rcSn":
42  componentType == 4 ? "COMPONENT.batterySn":
43  "COMPONENT.unknownSn",
44  ptr, serialNumberLength, limit);
45 }
u_int8_t getByte(u_int8_t const *&ptr, u_int8_t const *limit)
u_int16_t get2BytesLE(u_int8_t const *&ptr, u_int8_t const *limit)
void noteStringField(char const *label, u_int8_t const *&ptr, unsigned stringLength, u_int8_t const *limit)

References get2BytesLE(), getByte(), and noteStringField().

Referenced by parseRecord().

◆ parseRecord_CUSTOM()

void RecordAndDetailsParser::parseRecord_CUSTOM ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_CUSTOM.cpp.

28  {
29  // unknown (2 bytes):
30  ptr += 2;
31 
32  // CUSTOM.hSpeed: 4 bytes little-endian float:
33  note4ByteFloatField("CUSTOM.hSpeed", ptr, limit);
34 
35  // CUSTOM.distance: 4 bytes little-endian float:
36  note4ByteFloatField("CUSTOM.distance", ptr, limit);
37 
38  // CUSTOM.updateTime: 8 bytes little-endian, multiple of 0.001 seconds, in Unix time format:
39  note8ByteTimestampField("CUSTOM.updateTime", ptr, limit, 1/*is in ms*/);
40 }
void note8ByteTimestampField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, int isInMilliseconds=0)
void note4ByteFloatField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0)

References note4ByteFloatField(), and note8ByteTimestampField().

Referenced by parseRecord().

◆ parseRecord_DEFORM()

void RecordAndDetailsParser::parseRecord_DEFORM ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_DEFORM.cpp.

28  {
29  // unknown (2 bits) + DEFORM.deformMode.RAW (2 bits) + DEFORM.deformStatus.RAW (3 bits) + DEFORM.isDeformProtected (1 bit):
30  u_int8_t byte = getByte(ptr, limit);
31  enterSubByteField("DEFORM.deformMode.RAW", byte, 0x30);
32  enterSubByteField("DEFORM.deformStatus.RAW", byte, 0x0E);
33  enterSubByteField("DEFORM.isDeformProtected", byte, 0x01);
34 }
u_int8_t getByte(u_int8_t const *&ptr, u_int8_t const *limit)
void enterSubByteField(char const *label, u_int8_t byte, u_int8_t mask)

References enterSubByteField(), and getByte().

Referenced by parseRecord().

◆ parseRecord_FIRMWARE()

void RecordAndDetailsParser::parseRecord_FIRMWARE ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_FIRMWARE.cpp.

28  {
29  // unknown (2 bytes)
30  ptr += 2;
31 
32  // FIRMWARE.version: 3 bytes:
33  note3ByteVersionField("FIRMWARE.version", ptr, limit);
34 
35  // unknown (109 bytes)
36 }
void note3ByteVersionField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit)

References note3ByteVersionField().

Referenced by parseRecord().

◆ parseRecord_GIMBAL()

void RecordAndDetailsParser::parseRecord_GIMBAL ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_GIMBAL.cpp.

28  {
29  // GIMBAL.pitch: 2 bytes signed little-endian, multiple of 0.1 degrees; convert to degrees:
30  noteSigned2ByteField("GIMBAL.pitch", ptr, limit, 10.0);
31 
32  // GIMBAL.roll: 2 bytes signed little-endian, multiple of 0.1 degrees; convert to degrees:
33  noteSigned2ByteField("GIMBAL.roll", ptr, limit, 10.0);
34 
35  // GIMBAL.yaw: 2 bytes signed little-endian, multiple of 0.1 degrees; convert to degrees:
36  noteSigned2ByteField("GIMBAL.yaw", ptr, limit, 10.0);
37 
38  // GIMBAL.mode.RAW(2 bits) + unknown(6 bits):
39  u_int8_t byte = getByte(ptr, limit);
40  enterSubByteField("GIMBAL.mode.RAW", byte, 0xC0);
41 
42  // GIMBAL.rollAdjust: 1 byte signed, multiple of 0.1:
43  noteByteField("GIMBAL.rollAdjust", ptr, limit, 10.0, 1/*isSigned*/);
44 
45  // GIMBAL.yawAngle: 2 bytes signed little-endian, multiple of 0.1 degrees; convert to degrees:
46  noteSigned2ByteField("GIMBAL.yawAngle", ptr, limit, 10.0);
47 
48  // 8 bits (Boolean flags); from high to low:
49  // unknown
50  // GIMBAL.isStuck
51  // unknown
52  // GIMBAL.autoCalibrationResult
53  // GIMBAL.isAutoCalibration
54  // GIMBAL.isYawInLimit
55  // GIMBAL.isRollInLimit
56  // GIMBAL.isPitchInLimit
57  byte = getByte(ptr, limit);
58  enterSubByteField("GIMBAL.isStuck", byte, 0x40);
59  enterSubByteField("GIMBAL.autoCalibrationResult", byte, 0x10);
60  enterSubByteField("GIMBAL.isAutoCalibration", byte, 0x08);
61  enterSubByteField("GIMBAL.isYawInLimit", byte, 0x04);
62  enterSubByteField("GIMBAL.isRollInLimit", byte, 0x02);
63  enterSubByteField("GIMBAL.isPitchInLimit", byte, 0x01);
64 
65  // GIMBAL.isSingleClick (1 bit) + GIMBAL.isTripleClick (1 bit) + GIMBAL.isDoubleClick (1 bit) + unknown (1 bit) + GIMBAL.version (4 bits):
66  byte = getByte(ptr, limit);
67  enterSubByteField("GIMBAL.isSingleClick", byte, 0x80);
68  enterSubByteField("GIMBAL.isTripleClick", byte, 0x40);
69  enterSubByteField("GIMBAL.isDoubleClick", byte, 0x20);
70  enterSubByteField("GIMBAL.version", byte, 0x0F);
71 }
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 enterSubByteField(char const *label, u_int8_t byte, u_int8_t mask)
void noteByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)

References enterSubByteField(), getByte(), noteByteField(), and noteSigned2ByteField().

Referenced by parseRecord().

◆ parseRecord_HOME()

void RecordAndDetailsParser::parseRecord_HOME ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_HOME.cpp.

28  {
29  // HOME.longitude: 8 bytes little-endian double, in radians; convert to degrees:
30  note8ByteLatitudeOrLongitudeFieldInRadians("HOME.longitude", ptr, limit);
31 
32  // HOME.latitude: 8 bytes little-endian double, in radians; convert to degrees:
33  note8ByteLatitudeOrLongitudeFieldInRadians("HOME.latitude", ptr, limit);
34 
35  // HOME.height: 4 bytes little-endian float, multiple of 0.1 meters; convert to meters:
36  note4ByteFloatField("HOME.height", ptr, limit, 10.0);
37 
38  // HOME.hasGoHome (1 bit) + HOME.goHomeStatus (3 bits) + HOME.isDynamicHomePointEnabled (1 bit) + HOME.aircraftHeadDirection (1 bit) + HOME.goHomeMode (1 bit) + HOME.isHomeRecord (1 bit):
39  u_int8_t byte = getByte(ptr, limit);
40  enterSubByteField("HOME.hasGoHome", byte, 0x80);
41  enterSubByteField("HOME.goHomeStatus", byte, 0x70);
42  enterSubByteField("HOME.isDynamicHomePointEnabled", byte, 0x08);
43  enterSubByteField("HOME.aircraftHeadDirection", byte, 0x04);
44  enterSubByteField("HOME.goHomeMode", byte, 0x02);
45  enterSubByteField("HOME.isHomeRecord", byte, 0x01);
46 
47  // HOME.iocMode.RAW (3 bits) + HOME.isIOCEnabled (1 bit) + HOME.isBeginnerMode (1 bit) + HOME.isCompassCeleing (1 bit) + HOME.compassCeleStatus (2 bits):
48  byte = getByte(ptr, limit);
49  enterSubByteField("HOME.iocMode.RAW", byte, 0xE0);
50  enterSubByteField("HOME.isIOCEnabled", byte, 0x10);
51  enterSubByteField("HOME.isBeginnerMode", byte, 0x08);
52  enterSubByteField("HOME.isCompassCeleing", byte, 0x04);
53  enterSubByteField("HOME.compassCeleStatus", byte, 0x03);
54 
55  // HOME.goHomeHeight: 2 bytes little-endian unsigned, meters:
56  noteUnsigned2ByteField("HOME.goHomeHeight", ptr, limit);
57 
58  // HOME.courseLockAngle: 2 bytes little-endian signed, multiple of 0.1 degrees, convert to degrees:
59  noteSigned2ByteField("HOME.courseLockAngle", ptr, limit, 10.0);
60 
61  // HOME.dataRecorderStatus: 1 byte unsigned:
62  noteByteField("HOME.dataRecorderStatus", ptr, limit);
63 
64  // HOME.dataRecorderRemainCapacity: 1 byte unsigned:
65  noteByteField("HOME.dataRecorderRemainCapacity", ptr, limit);
66 
67  // HOME.dataRecorderRemainTime: 2 bytes little-endian unsigned:
68  noteUnsigned2ByteField("HOME.dataRecorderRemainTime", ptr, limit);
69 
70  // HOME.dataRecorderFileIndex: 2 bytes little-endian unsigned:
71  noteUnsigned2ByteField("HOME.dataRecorderFileIndex", ptr, limit);
72 
73  // unknown (5 bytes)
74  ptr += 5;
75 
76  // HOME.maxAllowedHeight: 4 bytes little-endian float:
77  note4ByteFloatField("HOME.maxAllowedHeight", ptr, limit);
78 }
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 note4ByteFloatField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0)
void noteByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)

References enterSubByteField(), getByte(), note4ByteFloatField(), note8ByteLatitudeOrLongitudeFieldInRadians(), noteByteField(), noteSigned2ByteField(), and noteUnsigned2ByteField().

Referenced by parseRecord().

◆ parseRecord_JPEG()

int RecordAndDetailsParser::parseRecord_JPEG ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 56 of file parseRecord_JPEG.cpp.

56  {
57  // Skip the first two bytes (both zero) in the record:
58  (void)get2BytesBE(ptr, limit);
59 
60  if (ptr == limit) return 1; // We're done; there are no JPEG images in the record
61 
62  // The next two bytes should be the JPEG 'start of image' code:
63  if (get2BytesBE(ptr, limit) != JPEG_SOI) {
64  // Unknown contents. Skip all bytes up to and including the next 0xFF (or until "limit"):
65  while (ptr < limit && *ptr++ != 0xFF) {}
66  return 1;
67  }
68 
69  // The JPEG data is all following data, up to (and including) the next JPEG 'end of image' code,
70  // that's not then immediately followed by a JPEG 'start of image' code:
71  FILE* outputFid = NULL;
72  if (outputJPGFiles) {
73  outputFid = openOutputJPGFile();
74  if (outputFid == NULL) return 0;
75  }
76 
77  while (1) {
78  u_int16_t next2Bytes = get2BytesBE(ptr, limit);
79  if (next2Bytes == JPEG_EOI) {
80  if (outputJPGFiles) {
81  // We've finished writing the JPG file:
82  fputc(JPEG_EOI>>8, outputFid); fputc(JPEG_EOI, outputFid);
83  fclose(outputFid);
84  }
85 
86  // Look for an immediately following JPEG 'start of image' code (if there's more data left):
87  if (ptr == limit) return 1; // we're done
88  next2Bytes = get2BytesBE(ptr, limit);
89  if (next2Bytes == JPEG_SOI) {
90  if (outputJPGFiles) {
91  outputFid = openOutputJPGFile();
92  if (outputFid == NULL) return 0;
93  }
94  } else {
95  ptr -= 2;
96  return 1;
97  }
98  } else {
99  // Output the first byte, then continue:
100  if (outputJPGFiles) {
101  u_int8_t firstByte = next2Bytes >> 8;
102  fputc(firstByte, outputFid);
103  }
104  --ptr;
105  }
106  }
107 
108  return 0; // never reached
109 }
static FILE * openOutputJPGFile()
int outputJPGFiles
#define JPEG_EOI
#define JPEG_SOI
u_int16_t get2BytesBE(u_int8_t const *&ptr, u_int8_t const *limit)

References get2BytesBE(), JPEG_EOI, JPEG_SOI, openOutputJPGFile(), and outputJPGFiles.

Referenced by parseRecord().

◆ parseRecord_OSD()

void RecordAndDetailsParser::parseRecord_OSD ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_OSD.cpp.

28  {
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 noteByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)

References enterSubByteField(), getByte(), note8ByteLatitudeOrLongitudeFieldInRadians(), noteByteField(), noteSigned2ByteField(), and noteUnsigned2ByteField().

Referenced by parseRecord().

◆ parseRecord_RC()

void RecordAndDetailsParser::parseRecord_RC ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_RC.cpp.

28  {
29  // RC.aileron: 2 bytes little-endian, signed: subtract 1024, and divide by 0.066(?):
30  noteSigned2ByteField("RC.aileron", ptr, limit, 0.066, 1024);
31 
32  // RC.elevator: 2 bytes little-endian, signed: subtract 1024, and divide by 0.066(?):
33  noteSigned2ByteField("RC.elevator", ptr, limit, 0.066, 1024);
34 
35  // RC.throttle: 2 bytes little-endian, signed: subtract 1024, and divide by 0.066(?):
36  noteSigned2ByteField("RC.throttle", ptr, limit, 0.066, 1024);
37 
38  // RC.rudder: 2 bytes little-endian, signed: subtract 1024, and divide by 0.066(?):
39  noteSigned2ByteField("RC.rudder", ptr, limit, 0.066, 1024);
40 
41  // RC.gimbal: 2 bytes little-endian, signed: subtract 1024, and divide by 0.066(?):
42  noteSigned2ByteField("RC.gimbal", ptr, limit, 0.066, 1024);
43 
44  // unknown(2 bits) + RC.wheelOffset(5 bits) + unknown(1 bit):
45  u_int8_t byte = getByte(ptr, limit);
46  enterSubByteField("RC.wheelOffset", byte, 0x3E);
47 
48  // unknown(2 bits) + RC.mode(2 bits) + RC.goHome(1 bit) + unknown(3 bits):
49  byte = getByte(ptr, limit);
50  enterSubByteField("RC.mode", byte, 0x30);
51  enterSubByteField("RC.goHome", byte, 0x08);
52 
53  // 8 bits (Boolean flags); from high to low:
54  // RC.record
55  // RC.shutter
56  // RC.playback
57  // RC.custom1
58  // RC.custom2
59  // unknown(3 bits)
60  byte = getByte(ptr, limit);
61  enterSubByteField("RC.record", byte, 0x80);
62  enterSubByteField("RC.shutter", byte, 0x40);
63  enterSubByteField("RC.playback", byte, 0x20);
64  enterSubByteField("RC.custom1", byte, 0x10);
65  enterSubByteField("RC.custom2", byte, 0x08);
66 }
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 enterSubByteField(char const *label, u_int8_t byte, u_int8_t mask)

References enterSubByteField(), getByte(), and noteSigned2ByteField().

Referenced by parseRecord().

◆ parseRecord_RECOVER()

void RecordAndDetailsParser::parseRecord_RECOVER ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_RECOVER.cpp.

28  {
29  // Note: Some of the field lengths here may have been different in older ".txt" versions
30 
31  if (limit-ptr < 109) return; // This record is smaller than we expect; we can't handle it
32 
33  // RECOVER.droneType.RAW: 1 byte unsigned:
34  noteByteField("RECOVER.droneType.RAW", ptr, limit);
35 
36  // RECOVER.appType.RAW: 1 byte unsigned:
37  noteByteField("RECOVER.appType.RAW", ptr, limit);
38 
39  // RECOVER.appVersion: 3 bytes;
40  note3ByteVersionField("RECOVER.appVersion", ptr, limit);
41 
42  // RECOVER.aircraftSn: string (length 16):
43  noteStringField("RECOVER.aircraftSn", ptr, 16, limit);
44 
45  // RECOVER.aircraftName: string (length 32):
46  noteStringField("RECOVER.aircraftName", ptr, 32, limit);
47 
48  // RECOVER.activeTimestamp: 8 bytes little-endian, in Unix time format:
49  note8ByteTimestampField("RECOVER.activeTimestamp", ptr, limit);
50 
51  // RECOVER.cameraSn: string (length 16):
52  noteStringField("RECOVER.cameraSn", ptr, 16, limit);
53 
54  // RECOVER.rcSn: string (length 16):
55  noteStringField("RECOVER.rcSn", ptr, 16, limit);
56 
57  // RECOVER.batterySn: string (length 16):
58  noteStringField("RECOVER.batterySn", ptr, 16, limit);
59 }
void note8ByteTimestampField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, int isInMilliseconds=0)
void note3ByteVersionField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit)
void noteStringField(char const *label, u_int8_t const *&ptr, unsigned stringLength, 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)

References note3ByteVersionField(), note8ByteTimestampField(), noteByteField(), and noteStringField().

Referenced by parseRecord().

◆ parseRecord_SMART_BATTERY()

void RecordAndDetailsParser::parseRecord_SMART_BATTERY ( u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 28 of file parseRecord_SMART_BATTERY.cpp.

28  {
29  // SMART_BATTERY.usefulTime: 2 bytes little-endian unsigned:
30  noteUnsigned2ByteField("SMART_BATTERY.usefulTime", ptr, limit);
31 
32  // SMART_BATTERY.goHomeTime: 2 bytes little-endian unsigned:
33  noteUnsigned2ByteField("SMART_BATTERY.goHomeTime", ptr, limit);
34 
35  // SMART_BATTERY.landTime: 2 bytes little-endian unsigned:
36  noteUnsigned2ByteField("SMART_BATTERY.landTime", ptr, limit);
37 
38  // SMART_BATTERY.goHomeBattery: 2 bytes little-endian unsigned:
39  noteUnsigned2ByteField("SMART_BATTERY.goHomeBattery", ptr, limit);
40 
41  // SMART_BATTERY.landBattery: 2 bytes little-endian unsigned:
42  noteUnsigned2ByteField("SMART_BATTERY.landBattery", ptr, limit);
43 
44  // SMART_BATTERY.safeFlyRadius: 4 bytes little-endian unsigned:
45  note4ByteField("SMART_BATTERY.safeFlyRadius", ptr, limit);
46 
47  // SMART_BATTERY.volumeConsume: 4 bytes little-endian float:
48  note4ByteFloatField("SMART_BATTERY.volumeConsume", ptr, limit);
49 
50  // SMART_BATTERY.status.RAW: 4 bytes little-endian unsigned:
51  note4ByteField("SMART_BATTERY.status.RAW", ptr, limit);
52 
53  // SMART_BATTERY.goHomeStatus.RAW: 1 byte unsigned:
54  noteByteField("SMART_BATTERY.goHomeStatus.RAW", ptr, limit);
55 
56  // SMART_BATTERY.goHomeCountdown: 1 byte unsigned:
57  noteByteField("SMART_BATTERY.goHomeCountdown", ptr, limit);
58 
59  // SMART_BATTERY.voltage: 2 bytes little-endian unsigned; multiple of 0.001 volts; convert to volts:
60  noteUnsigned2ByteField("SMART_BATTERY.voltage", ptr, limit, 1000.0);
61 
62  // SMART_BATTERY.battery: 1 byte unsigned:
63  noteByteField("SMART_BATTERY.battery", ptr, limit);
64 
65  // SMART_BATTERY.lowWarningGoHome (1 bit) + SMART_BATTERY.lowWarning (7 bits):
66  u_int8_t byte = getByte(ptr, limit);
67  enterSubByteField("SMART_BATTERY.lowWarningGoHome", byte, 0x80);
68  enterSubByteField("SMART_BATTERY.lowWarning", byte, 0x7F);
69 
70  // SMART_BATTERY.seriousLowWarningLanding (1 bit) + SMART_BATTERY.seriousLowWarning (7 bits):
71  byte = getByte(ptr, limit);
72  enterSubByteField("SMART_BATTERY.seriousLowWarningLanding", byte, 0x80);
73  enterSubByteField("SMART_BATTERY.seriousLowWarning", byte, 0x7F);
74 
75  // SMART_BATTERY.voltagePercent: 1 byte unsigned:
76  noteByteField("SMART_BATTERY.voltagePercent", ptr, limit);
77 }
u_int8_t getByte(u_int8_t const *&ptr, u_int8_t const *limit)
void noteUnsigned2ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int16_t offset=0)
void enterSubByteField(char const *label, u_int8_t byte, u_int8_t mask)
void note4ByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)
void note4ByteFloatField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0)
void noteByteField(char const *label, u_int8_t const *&ptr, u_int8_t const *limit, float divisor=0.0, int isSigned=0)

References enterSubByteField(), getByte(), note4ByteField(), note4ByteFloatField(), noteByteField(), and noteUnsigned2ByteField().

Referenced by parseRecord().

◆ parseRecordUnknownFormat()

void RecordAndDetailsParser::parseRecordUnknownFormat ( char const *  recordTypeName,
u_int8_t const *&  ptr,
u_int8_t const *  limit 
)
private

Definition at line 32 of file parseRecordUnknownFormat.cpp.

33  {
34  fprintf(stderr, "%s (unknown format), %ld bytes: ", recordTypeName, (long)(limit-ptr));
35  printHex(NULL, ptr, limit);
36 }
void printHex(char const *label, u_int8_t const *&ptr, u_int8_t const *limit)

References printHex().

Referenced by parseRecord().

◆ summarizeRecordParsing()

void RecordAndDetailsParser::summarizeRecordParsing ( )
privatevirtual

Implements DJITxtParser.

Definition at line 249 of file parseRecord.cpp.

249  {
250 #ifdef DEBUG_RECORD_PARSING
251  fprintf(stderr, "%d records parsed; max num records for one type: %d\n", fNumRecords, fMaxNumRecordsForOneType);
252  unsigned maxRecordTypeFieldLen = 0;
253  for (unsigned i = 0; i < 256; ++i) {
254  char const* recordTypeName = fRecordTypeName[i];
255  unsigned recordTypeNameLen = recordTypeName == NULL ? 3 : strlen(recordTypeName);
256  unsigned iLog10 = i<10 ? 0 : i<100 ? 1 : 2;
257  unsigned recordTypeFieldLen = iLog10 + 2 + recordTypeNameLen + 2;
258  if (recordTypeFieldLen > maxRecordTypeFieldLen) maxRecordTypeFieldLen = recordTypeFieldLen;
259  }
260  unsigned maxNumTabs = maxRecordTypeFieldLen/8 + 1;
261 
262  for (unsigned i = 0; i < 255; ++i) {
263  if (fRecordTypeStats[i].count > 0) {
264  char const* recordTypeName = fRecordTypeName[i];
265  if (recordTypeName == NULL) recordTypeName = "???";
266  unsigned iLog10 = i<10 ? 0 : i<100 ? 1 : 2;
267  unsigned recordTypeFieldLen = iLog10 + 2 + strlen(recordTypeName) + 2;
268  unsigned numTabs = maxNumTabs - recordTypeFieldLen/8; // >0
269 
270  fprintf(stderr, "%d[%s]:", i, recordTypeName);
271  for (unsigned j = 0; j < numTabs; ++j) fprintf(stderr, "\t");
272  fprintf(stderr, "%d\t", fRecordTypeStats[i].count);
273  if (fRecordTypeStats[i].minLength == fRecordTypeStats[i].maxLength) {
274  fprintf(stderr, "length:\t\t%d\n", fRecordTypeStats[i].minLength);
275  } else {
276  fprintf(stderr, "lengths:\t%d-%d\n", fRecordTypeStats[i].minLength, fRecordTypeStats[i].maxLength);
277  }
278  }
279  }
280 #endif
281 }
RecordTypeStat fRecordTypeStats[256]

References fMaxNumRecordsForOneType, fNumRecords, fRecordTypeName, and fRecordTypeStats.

Field Documentation

◆ fFieldDatabase

FieldDatabase* RecordAndDetailsParser::fFieldDatabase
private

Definition at line 116 of file RecordAndDetailsParser.hh.

Referenced by ~RecordAndDetailsParser().

◆ fMaxNumRecordsForOneType

unsigned RecordAndDetailsParser::fMaxNumRecordsForOneType
private

Definition at line 114 of file RecordAndDetailsParser.hh.

Referenced by parseRecord(), and summarizeRecordParsing().

◆ fNumRecords

unsigned RecordAndDetailsParser::fNumRecords
private

Definition at line 111 of file RecordAndDetailsParser.hh.

Referenced by parseRecord(), and summarizeRecordParsing().

◆ fRecordTypeName

char const* RecordAndDetailsParser::fRecordTypeName[256]
private

◆ fRecordTypeStats

RecordTypeStat RecordAndDetailsParser::fRecordTypeStats[256]
private

Definition at line 112 of file RecordAndDetailsParser.hh.

Referenced by parseRecord(), and summarizeRecordParsing().


The documentation for this class was generated from the following files: