Skip to content

Commit 8e3d516

Browse files
Kwash67NexInfinite
andauthored
Real time on x-axis as long as there is GPS data (#579)
* shouldve put this in previous ticket lol * added function to convert date * complete * Fix: Prevent stack overflow when calculating max timestamp for large datasets --------- Co-authored-by: Julian Jones <37962677+NexInfinite@users.noreply.github.com>
1 parent 86f80c4 commit 8e3d516

4 files changed

Lines changed: 98 additions & 11 deletions

File tree

gcs/src/components/fla/graph.jsx

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -251,13 +251,48 @@ export default function Graph({
251251
// https://stackoverflow.com/a/8179549/10077669
252252
const labelColor = backgroundColor.replace(/[^,]+(?=\))/, "1")
253253

254+
// Critical fix: Convert timestamp to Date object for time scale
255+
let xMinValue = flightMode.TimeUS;
256+
let xMaxValue = xMax;
257+
258+
// Check if we're using a time scale
259+
const isTimeScale = config.scales?.x?.type === "time";
260+
261+
// Convert timestamps to Date objects when using time scale
262+
if (isTimeScale) {
263+
xMinValue = new Date(flightMode.TimeUS);
264+
265+
// Handle xMax
266+
if (nextFlightMode !== undefined) {
267+
xMaxValue = new Date(nextFlightMode.TimeUS);
268+
} else {
269+
// Stretch to the latest date
270+
let maxTime = 0;
271+
data.datasets.forEach((dataset) => {
272+
dataset.data.forEach((point) => {
273+
if (point.x > maxTime) {
274+
maxTime = point.x;
275+
}
276+
});
277+
});
278+
const maxDate = new Date(maxTime);
279+
xMaxValue = maxDate;
280+
}
281+
282+
} else {
283+
// For non-time scales, handle next flight mode
284+
if (nextFlightMode !== undefined) {
285+
xMaxValue = nextFlightMode.TimeUS;
286+
}
287+
}
288+
254289
const flightModeChange = {
255290
type: "box",
256291
xScaleID: "x",
257292
yMin: "end",
258293
yMax: "start",
259-
xMin: flightMode.TimeUS,
260-
xMax: xMax,
294+
xMin: xMinValue,
295+
xMax: xMaxValue,
261296
backgroundColor: backgroundColor,
262297
borderWidth: 0,
263298
display: true,
@@ -271,12 +306,6 @@ export default function Graph({
271306
},
272307
}
273308

274-
// If there is a next flight mode, then set the xMax of the current flight
275-
// mode to the xMin of the next flight mode
276-
if (nextFlightMode !== undefined) {
277-
flightModeChange.xMax = nextFlightMode.TimeUS
278-
}
279-
280309
annotations.push(flightModeChange)
281310
}
282311
}

gcs/src/components/fla/graphConfigs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export const fgcsOptions = {
9393
tooltip: {
9494
callbacks: {
9595
title: function (context) {
96-
return moment(context[0].parsed.x).format("HH:mm:ss")
96+
return moment(context[0].parsed.x).format("MMMM Do YYYY, h:mm:ss a")
9797
},
9898
},
9999
},

gcs/src/fla.jsx

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
setLogEvents,
4949
setFlightModeMessages,
5050
setLogType,
51+
setUtcAvailable,
5152
setMessageFilters,
5253
setMessageMeans,
5354
setChartData,
@@ -127,6 +128,7 @@ export default function FLA() {
127128
logEvents,
128129
flightModeMessages,
129130
logType,
131+
utcAvailable,
130132
messageFilters,
131133
messageMeans,
132134
chartData,
@@ -153,6 +155,8 @@ export default function FLA() {
153155
const updateFlightModeMessages = (newFlightModeMessages) =>
154156
dispatch(setFlightModeMessages(newFlightModeMessages))
155157
const updateLogType = (newLogType) => dispatch(setLogType(newLogType))
158+
const updateUtcAvailable = (newUtcAvailable) =>
159+
dispatch(setUtcAvailable(newUtcAvailable))
156160
const updateMessageFilters = (newMessageFilters) =>
157161
dispatch(setMessageFilters(newMessageFilters))
158162
const updateMessageMeans = (newMessageMeans) =>
@@ -177,6 +181,8 @@ export default function FLA() {
177181
setLoadingFile(true)
178182
const result = await window.ipcRenderer.loadFile(file.path)
179183

184+
let gpsOffset = null; // To store the offset between TimeUS and TimeUTC
185+
180186
if (result.success) {
181187
// Load messages into states
182188
setLoadingFile(false)
@@ -198,6 +204,7 @@ export default function FLA() {
198204
if (result.logType === "dataflash") {
199205
updateFlightModeMessages(loadedLogMessages.MODE)
200206
} else if (result.logType === "fgcs_telemetry") {
207+
updateUtcAvailable(true)
201208
// Get the heartbeat messages only where index is the first or last or the mode changes
202209
const modeMessages = []
203210
for (let i = 0; i < loadedLogMessages.HEARTBEAT.length; i++) {
@@ -268,8 +275,33 @@ export default function FLA() {
268275
delete logMessageFilterDefaultState["ESC"]
269276
}
270277

278+
let tempLoadedLogMessages = { ...loadedLogMessages }
279+
280+
if ("GPS" in loadedLogMessages && result.logType === "dataflash" && gpsOffset === null) {
281+
const messageObj = tempLoadedLogMessages["GPS"][0] // Get the first GPS message
282+
283+
// Calculate the offset
284+
if (messageObj.GWk !== undefined && messageObj.GMS !== undefined) {
285+
const utcTime = gpsToUTC(messageObj.GWk, messageObj.GMS);
286+
gpsOffset = utcTime.getTime() - messageObj.TimeUS/1000;
287+
}
288+
289+
// Loop through all messages and replace TimeUS with UTC
290+
Object.keys(tempLoadedLogMessages).forEach((key) => {
291+
if (key !== "format" && key !== "units") {
292+
tempLoadedLogMessages[key] = tempLoadedLogMessages[key].map((message) => {
293+
return {
294+
...message,
295+
TimeUS: message.TimeUS/1000 + gpsOffset, // Add the new property
296+
};
297+
});
298+
}
299+
});
300+
updateUtcAvailable(true)
301+
updateFlightModeMessages(tempLoadedLogMessages.MODE)
302+
}
303+
271304
if (loadedLogMessages["BAT"]) {
272-
let tempLoadedLogMessages = { ...loadedLogMessages }
273305
let tempMsgFormat = { ...loadedLogMessages["format"] }
274306

275307
// Load each BATT data into its own array
@@ -286,6 +318,7 @@ export default function FLA() {
286318
tempLoadedLogMessages[battName].push({
287319
...battData,
288320
name: battName,
321+
TimeUS: battData.TimeUS/1000 + gpsOffset
289322
})
290323

291324
// Add filter state for new BATT
@@ -344,6 +377,20 @@ export default function FLA() {
344377
}
345378
}
346379

380+
function gpsToUTC(gpsWeek, gms, leapSeconds = 18) {
381+
// GPS epoch starts at 1980-01-06 00:00:00 UTC
382+
const gpsEpoch = new Date(Date.UTC(1980, 0, 6));
383+
384+
// Calculate total milliseconds since Unix epoch
385+
const totalMs =
386+
gpsEpoch.getTime() +
387+
gpsWeek * 604_800_000 + // Convert weeks to milliseconds
388+
gms - // Add GPS milliseconds
389+
leapSeconds * 1_000; // Subtract leap seconds
390+
391+
return new Date(totalMs);
392+
}
393+
347394
// Get a list of the recent FGCS telemetry logs
348395
async function getFgcsLogs() {
349396
setRecentFgcsLogs(await window.ipcRenderer.getRecentLogs())
@@ -368,6 +415,7 @@ export default function FLA() {
368415
updateChartData({ datasets: [] })
369416
updateMessageFilters(null)
370417
updateCustomColors({})
418+
updateUtcAvailable(false)
371419
updateColorIndex(0)
372420
updateLogEvents(null)
373421
updateLogType("dataflash")
@@ -880,6 +928,11 @@ export default function FLA() {
880928
),
881929
}
882930

931+
// Skip categories with no valid filters
932+
if (filteredCategory.filters.length === 0) {
933+
return null
934+
}
935+
883936
return (
884937
<Fragment key={category.name}>
885938
<PresetAccordionItem
@@ -932,7 +985,7 @@ export default function FLA() {
932985
events={logEvents}
933986
flightModes={flightModeMessages}
934987
graphConfig={
935-
logType === "dataflash" ? dataflashOptions : fgcsOptions
988+
utcAvailable ? fgcsOptions: dataflashOptions
936989
}
937990
clearFilters={clearFilters}
938991
canSavePreset={canSavePreset}

gcs/src/redux/logAnalyserSlice.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const logAnalyserSlice = createSlice({
77
units: {},
88
formatMessages: {},
99
logMessages: null,
10+
utcAvailable: false,
1011
logEvents: null,
1112
flightModeMessages: [],
1213
logType: "dataflash",
@@ -31,6 +32,9 @@ const logAnalyserSlice = createSlice({
3132
setLogMessages: (state, action) => {
3233
state.logMessages = action.payload
3334
},
35+
setUtcAvailable: (state, action) => {
36+
state.utcAvailable = action.payload
37+
},
3438
setLogEvents: (state, action) => {
3539
state.logEvents = action.payload
3640
},
@@ -69,6 +73,7 @@ export const {
6973
setUnits,
7074
setFormatMessages,
7175
setLogMessages,
76+
setUtcAvailable,
7277
setLogEvents,
7378
setFlightModeMessages,
7479
setLogType,

0 commit comments

Comments
 (0)