Skip to content

Commit

Permalink
add support for dji txt logs
Browse files Browse the repository at this point in the history
  • Loading branch information
Williangalvani committed Nov 17, 2024
1 parent aa6f61e commit d12041b
Show file tree
Hide file tree
Showing 9 changed files with 291 additions and 13 deletions.
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"colormap": "^2.3.2",
"crypto-browserify": "^3.12.0",
"d3": "^7.6.1",
"dji-log-parser-js": "^0.5.4",
"epic-spinners": "^1.1.0",
"eslint-config-standard": "^16.0.3",
"eslint-loader": "^4.0.2",
Expand Down
4 changes: 4 additions & 0 deletions src/components/CesiumViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import tzlookup from 'tz-lookup'
import { store } from './Globals.js'
import { DataflashDataExtractor } from '../tools/dataflashDataExtractor'
import { MavlinkDataExtractor } from '../tools/mavlinkDataExtractor'
import { djiDataExtractor } from '../tools/djiDataExtractor'
import 'cesium/Build/Cesium/Widgets/widgets.css'
import CesiumSettingsWidget from './widgets/CesiumSettingsWidget.vue'
import ColorCoderMode from './cesiumExtra/colorCoderMode.js'
Expand Down Expand Up @@ -1116,6 +1117,9 @@ export default {
let dataExtractor = null
if (this.state.logType === 'tlog') {
dataExtractor = MavlinkDataExtractor
} else if (this.state.logType === 'dji') {
console.log('Using DJI extractor')
dataExtractor = djiDataExtractor
} else {
dataExtractor = DataflashDataExtractor
}
Expand Down
17 changes: 11 additions & 6 deletions src/components/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { Color } from 'cesium'
import colormap from 'colormap'
import { DataflashDataExtractor } from '../tools/dataflashDataExtractor'
import { MavlinkDataExtractor } from '../tools/mavlinkDataExtractor'
import { DjiDataExtractor } from '../tools/djiDataExtractor'
import MagFitTool from '@/components/widgets/MagFitTool.vue'
import EkfHelperTool from '@/components/widgets/EkfHelperTool.vue'
import Vue from 'vue'
Expand Down Expand Up @@ -85,6 +86,8 @@ export default {
if (this.dataExtractor === null) {
if (this.state.logType === 'tlog') {
this.dataExtractor = MavlinkDataExtractor
} else if (this.state.logType === 'dji') {
this.dataExtractor = DjiDataExtractor
} else {
this.dataExtractor = DataflashDataExtractor
}
Expand Down Expand Up @@ -113,17 +116,19 @@ export default {
this.state.vehicle = this.dataExtractor.extractVehicleType(this.state.messages)
if (this.state.params === undefined) {
this.state.params = this.dataExtractor.extractParams(this.state.messages)
this.state.defaultParams = this.dataExtractor.extractDefaultParams(this.state.messages)
if (this.state.params !== undefined) {
this.$eventHub.$on('cesium-time-changed', (time) => {
this.state.params.seek(time)
})
this.state.defaultParams = this.dataExtractor.extractDefaultParams(this.state.messages)
if (this.state.params !== undefined) {
this.$eventHub.$on('cesium-time-changed', (time) => {
this.state.params.seek(time)
})
}
}
}
if (this.state.vehicle === 'quadcopter') {
if (this.state.params.get('FRAME_TYPE') === 0) {
if (this.state.params?.get('FRAME_TYPE') === 0) {
this.state.vehicle += '+'
} else if (this.state.params.get('FRAME_TYPE') === 1) {
} else {
this.state.vehicle += 'x'
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/components/Plotly.vue
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,11 @@ export default {
try {
x = this.state.messages.ATT.time_boot_ms
} catch {
x = this.state.messages.ATTITUDE.time_boot_ms
try {
x = this.state.messages.ATTITUDE.time_boot_ms
} catch {
x = this.state.messages.osd.time_boot_ms
}
}
}
// used to find the corresponding time indexes between messages
Expand Down
17 changes: 13 additions & 4 deletions src/components/SideBarFileManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ export default {
this.transferMessage = 'Download Done'
this.sampleLoaded = true
worker.postMessage({ action: 'parse', file: arrayBuffer, isTlog: (url.indexOf('.tlog') > 0) })
worker.postMessage({
action: 'parse',
file: arrayBuffer,
isTlog: (url.indexOf('.tlog') > 0),
isDji: (url.indexOf('.txt') > 0)
})
}
oReq.addEventListener('progress', (e) => {
if (e.lengthComputable) {
Expand Down Expand Up @@ -142,11 +147,14 @@ export default {
worker.postMessage({
action: 'parse',
file: data,
isTlog: (file.name.endsWith('tlog'))
isTlog: (file.name.endsWith('tlog')),
isDji: (file.name.endsWith('txt'))
})
}
this.state.logType = file.name.endsWith('tlog') ? 'tlog' : 'bin'
if (file.name.endsWith('.txt')) {
this.state.logType = 'dji'
}
reader.readAsArrayBuffer(file)
},
uploadFile () {
Expand Down Expand Up @@ -215,7 +223,8 @@ export default {
worker.postMessage({
action: 'parse',
file: event.data.data,
isTlog: false
isTlog: false,
isDji: false
})
}
})
Expand Down
2 changes: 1 addition & 1 deletion src/tools/parsers/JsDataflashParser
Submodule JsDataflashParser updated 2 files
+1 −1 index.html
+25 −34 parser.js
236 changes: 236 additions & 0 deletions src/tools/parsers/djiParser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import { DJILog } from "dji-log-parser-js";
const messageTypes = {
OSD: {
expressions: [
"flyTime",
"latitude",
"longitude",
"height",
"heightMax",
"vpsHeight",
"altitude",
"xSpeed",
"xSpeedMax",
"ySpeed",
"ySpeedMax",
"zSpeed",
"zSpeedMax",
"pitch",
"roll",
"yaw",
"flycState",
"flycCommand",
"flightAction",
"isGpdUsed",
"nonGpsCause",
"gpsNum",
"gpsLevel",
"droneType",
"isSwaveWork",
"waveError",
"goHomeStatus",
"batteryType",
"isOnGround",
"isMotorOn",
"isMotorBlocked",
"motorStartFailedCause",
"isImuPreheated",
"imuInitFailReason",
"isAcceletorOverRange",
"isBarometerDeadInAir",
"isCompassError",
"isGoHomeHeightModified",
"canIocWork",
"isNotEnoughForce",
"isOutOfLimit",
"isPropellerCatapult",
"isVibrating",
"isVisionUsed",
"voltageWarning"
]
},
gimbal: {
expressions: [
"mode",
"pitch",
"roll",
"yaw",
"isPitchAtLimit",
"isRollAtLimit",
"isYawAtLimit",
"isStuck"
]
},
CAMERA: {
expressions: [
"isPhoto",
"isVideo",
"sdCardIsInserted",
"sdCardState"
]
},
RC: {
expressions: [
"downlinkSignal",
"uplinkSignal",
"aileron",
"elevator",
"throttle",
"rudder"
]
},
BATTERY: {
expressions: [
"chargeLevel",
"voltage",
"current",
"currentCapacity",
"fullCapacity",
"cellNum",
"isCellVoltageEstimated",
"cellVoltages",
"cellVoltageDeviation",
"maxCellVoltageDeviation",
"temperature",
"minTemperature",
"maxTemperature"
]
},
HOME: {
expressions: [
"latitude",
"longitude",
"altitude",
"heightLimit",
"isHomeRecord",
"goHomeMode",
"isDynamicHomePointEnabled",
"isNearDistanceLimit",
"isNearHeightLimit",
"isCompassCalibrating",
"isMultipleModeEnabled",
"isBeginnerMode",
"isIocEnabled",
"goHomeHeight",
"maxAllowedHeight",
"currentFlightRecordIndex"
]
},
RECOVER: {
expressions: [
"appPlatform",
"appVersion",
"aircraftName",
"aircraftSn",
"cameraSn",
"rcSn",
"batterySn"
]
},
APP: {
expressions: [
"tip",
"warn"
]
}
}

for (const key of Object.keys(messageTypes)) {
messageTypes[key].complexFields = messageTypes[key].expressions.map(e => {
return {
name: e,
units: "?",
multiplier: 1
}
})
}
function transformData(dataArray, startTime) {
if (!dataArray || dataArray.length === 0) {
return {};
}

// Helper function to capitalize first letter
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1).toUpperCase();

// Initialize the messages object
const messages = {};

// First pass: initialize the structure based on the first item
const firstItem = dataArray[0];
Object.keys(firstItem).forEach(key => {
const capitalizedKey = capitalize(key);
messages[capitalizedKey] = {
time_boot_ms: []
};

// Helper function to initialize arrays for nested objects
function initializeArraysForObject(obj, targetObj) {
Object.keys(obj).forEach(nestedKey => {
if (typeof obj[nestedKey] === "object" && !Array.isArray(obj[nestedKey])) {
targetObj[nestedKey] = {};
initializeArraysForObject(obj[nestedKey], targetObj[nestedKey]);
} else {
targetObj[nestedKey] = [];
}
});
}

// Initialize arrays for the current section
if (firstItem[key] && typeof firstItem[key] === "object") {
initializeArraysForObject(firstItem[key], messages[capitalizedKey]);
}
});

// Second pass: populate the arrays
dataArray.forEach(item => {
const timestamp = new Date(item.custom.dateTime).getTime() - startTime;
Object.keys(item).forEach(key => {
const capitalizedKey = capitalize(key);
if (messages[capitalizedKey]) {
// Add timestamp to this section
messages[capitalizedKey].time_boot_ms.push(timestamp);

// Helper function to populate arrays for nested objects
function populateArrays(sourceObj, targetObj) {
Object.keys(sourceObj).forEach(nestedKey => {
if (typeof sourceObj[nestedKey] === "object" && !Array.isArray(sourceObj[nestedKey])) {
populateArrays(sourceObj[nestedKey], targetObj[nestedKey]);
} else if (targetObj[nestedKey]) { // Check if the target array exists
targetObj[nestedKey].push(sourceObj[nestedKey]);
}
});
}

// Populate arrays for the current section
if (item[key] && typeof item[key] === "object") {
populateArrays(item[key], messages[capitalizedKey]);
}
}
});
});
console.log(messages)
return messages;
}

class DjiParser {

loadType() {
console.warn("DjiParser.loadType() is not implemented")
}

async processData(data) {
const parser = new DJILog(new Uint8Array(data));
const keychains = await parser.fetchKeychains(
"f05e96fa44f3f36eb9962948bac0f77",
"http://new.galvanicloop.com:5000/https://dev.dji.com/openapi/v1/flight-records/keychains"
);
const frames = parser.frames(keychains)
const startTime = new Date(frames[0].custom.dateTime).getTime()
self.postMessage({ metadata: {startTime: new Date(frames[0].custom.dateTime).getTime()}})
self.postMessage({ availableMessages: messageTypes })
self.postMessage({ messages: transformData(frames, startTime) })
self.postMessage({ messagesDoneLoading: true })

}
}
export default DjiParser
Loading

0 comments on commit d12041b

Please sign in to comment.