Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/graph_spectrum.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ export function FlightLogAnalyser(flightLog, canvas, analyserCanvas) {
let that = this,
analyserZoomX = 1.0 /* 100% */,
analyserZoomY = 1.0 /* 100% */,
dataReload = false,
fftData = null,
prefs = new PrefStorage(),
dataBuffer = {
fieldIndex: 0,
curve: 0,
curve: null,
fieldName: null,
},
dataReload = false,
fftData = null,
prefs = new PrefStorage();
};

try {
let isFullscreen = false;
Expand Down Expand Up @@ -128,11 +128,9 @@ export function FlightLogAnalyser(flightLog, canvas, analyserCanvas) {
analyser on screen*/
this.plotSpectrum = function (fieldIndex, curve, fieldName) {
// Store the data pointers
dataBuffer = {
fieldIndex: fieldIndex,
curve: curve,
fieldName: fieldName,
};
dataBuffer.fieldIndex = fieldIndex;
dataBuffer.curve = curve;
dataBuffer.fieldName = fieldName;

// Detect change of selected field.... reload and redraw required.
if (fftData == null || fieldIndex != fftData.fieldIndex || dataReload) {
Expand Down Expand Up @@ -208,6 +206,13 @@ export function FlightLogAnalyser(flightLog, canvas, analyserCanvas) {
userSettings.spectrumType = optionSelected;
saveOneUserSetting("spectrumType", userSettings.spectrumType);

// Restore dataBuffer if it was corrupted
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai any reason why dataBuffer could be corrupted ? Can you find any root causes ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for all usages of dataBuffer to understand how it's manipulated
echo "=== Searching for dataBuffer usage patterns ==="
rg "dataBuffer" -A 3 -B 1

echo -e "\n=== Searching for setDataBuffer usage ==="
rg "setDataBuffer" -A 3 -B 1

echo -e "\n=== Searching for curve property assignments ==="
rg "\.curve\s*=" -A 2 -B 1

echo -e "\n=== Looking for object resets or assignments to dataBuffer ==="
rg "dataBuffer\s*=" -A 2 -B 1

Length of output: 8010


@haslinghuis Looking at the codebase, the "corruption" is most likely not actual data corruption but rather a timing/initialization issue. Here's what I found:

Root Cause Analysis

Primary cause: Uninitialized state, not corruption

The dataBuffer is initialized with curve: null:

dataBuffer = {
  fieldIndex: 0,
  curve: null,  // Initially null
  fieldName: null,
};

The curve property is only set when plotSpectrum() is called:

this.plotSpectrum = function (fieldIndex, curve, fieldName) {
  dataBuffer.fieldIndex = fieldIndex;
  dataBuffer.curve = curve;        // Set from parameter
  dataBuffer.fieldName = fieldName;
  // ...
};

The issue occurs when:

  1. User changes spectrum type before any graph data has been plotted
  2. dataBuffer.curve is still null (its initial value)
  3. The spectrum type change handler detects !dataBuffer.curve and assumes "corruption"
  4. It restores from GraphSpectrumCalc._dataBuffer which should have valid data

Why This Happens

From my analysis, there are no other code paths that reset or corrupt dataBuffer. The check is essentially a defensive measure against this timing scenario:

  • User opens the spectrum analyzer
  • User immediately changes spectrum type before any field is selected/plotted
  • plotSpectrum() hasn't been called yet, so curve is still null
  • The change handler treats this as corruption and restores from the calc module's backup

This is good defensive programming - it ensures the spectrum analyzer can recover even when users interact with controls before the initial data load completes.

Alternative scenarios (less likely):

  • Rapid UI interactions causing race conditions
  • Error states preventing plotSpectrum() from being called
  • Async operations interfering with the data flow

The current fix is appropriate as it provides a safety net for these edge cases.


🧬 Code Graph Analysis Results

Relevant snippets from src/graph_spectrum_calc.js (lines 24-38, 182-190, 478-485)

export const GraphSpectrumCalc = {
  _analyserTimeRange : {
      in: 0,
      out: MAX_ANALYSER_LENGTH,
  },
  _blackBoxRate : 0,
  _dataBuffer : {
      fieldIndex: 0,
      curve: null,
      fieldName: null,
  },
  _flightLog : null,
  _sysConfig : null,
  _motorPoles : null,
};
const fftData = {
      fieldIndex   : this._dataBuffer.fieldIndex,
      fieldName  : this._dataBuffer.fieldName,
      fftLength  : fftChunkLength,
      fftOutput  : matrixFftOutput,
      maxNoise   : maxNoise,
      blackBoxRate : this._blackBoxRate,
      vsRange    : { min: flightSamples.minValue, max: flightSamples.maxValue},
  };
const fftData = {
    fieldIndex   : this._dataBuffer.fieldIndex,
    fieldName  : this._dataBuffer.fieldName,
    fftLength  : fftLength,
    fftOutput  : fftOutput,
    maxNoiseIdx  : maxNoiseIdx,
    blackBoxRate : this._blackBoxRate,
  };

Summary:
The GraphSpectrumCalc object holds internal state including _dataBuffer which contains fieldIndex, curve, and fieldName. The fftData objects returned by various data loading functions include references to these _dataBuffer fields. This suggests that dataBuffer in FlightLogAnalyser is linked to GraphSpectrumCalc._dataBuffer. Corruption of dataBuffer could be related to how _dataBuffer is managed or updated inside GraphSpectrumCalc.


Relevant snippet from src/graph_spectrum.js (lines ~150-190)

// Inside FlightLogAnalyser constructor

let dataBuffer = {
  fieldIndex: 0,
  curve: null,
  fieldName: null,
};

...

this.plotSpectrum = function (fieldIndex, curve, fieldName) {
  // Store the data pointers
  dataBuffer.fieldIndex = fieldIndex;
  dataBuffer.curve = curve;
  dataBuffer.fieldName = fieldName;

  // Detect change of selected field.... reload and redraw required.
  if (fftData == null || fieldIndex != fftData.fieldIndex || dataReload) {
    dataReload = false;
    dataLoad();
    GraphSpectrumPlot.setData(fftData, userSettings.spectrumType);
  }

  that.draw(); // draw the analyser on the canvas....
};

...

spectrumTypeElem
  .change(function () {
    const optionSelected = parseInt(spectrumTypeElem.val(), 10);

    if (optionSelected != userSettings.spectrumType) {
      userSettings.spectrumType = optionSelected;
      saveOneUserSetting("spectrumType", userSettings.spectrumType);

      // Restore dataBuffer if it was corrupted
      if (!dataBuffer.curve) {
        dataBuffer.curve = GraphSpectrumCalc._dataBuffer.curve;
        dataBuffer.fieldName = GraphSpectrumCalc._dataBuffer.fieldName;
        dataBuffer.fieldIndex = GraphSpectrumCalc._dataBuffer.fieldIndex;
        console.warn("The dataBuffer was corrupted (set to default zeroes) in FlightLogAnalyser.spectrumTypeElem.change event");
      }
      // Recalculate the data, for the same curve than now, and draw it
      dataReload = true;
      that.plotSpectrum(
        dataBuffer.fieldIndex,
        dataBuffer.curve,
        dataBuffer.fieldName,
      );
    }

Summary:
dataBuffer is a local object in FlightLogAnalyser that stores the current field index, curve, and field name. It is updated in plotSpectrum. When the spectrum type changes, if dataBuffer.curve is falsy (indicating possible corruption or reset), it is restored from GraphSpectrumCalc._dataBuffer. This indicates that dataBuffer can become corrupted or reset, and the code attempts to recover it from the internal _dataBuffer of GraphSpectrumCalc.


Relevant snippet from src/pref_storage.js (lines 6-63)

export function PrefStorage(keyPrefix) {
  let LOCALSTORAGE = 0,
    CHROME_STORAGE_LOCAL = 1,
    mode;

  this.get = function (name, onGet) {
    name = keyPrefix + name;

    switch (mode) {
      case LOCALSTORAGE:
        var parsed = null;

        try {
          parsed = JSON.parse(window.localStorage[name]);
        } catch (e) {}

        onGet(parsed);
        break;
      case CHROME_STORAGE_LOCAL:
        chrome.storage.local.get(name, function (data) {
          onGet(data[name]);
        });
        break;
    }
  };

  this.set = function (name, value) {
    name = keyPrefix + name;

    switch (mode) {
      case LOCALSTORAGE:
        window.localStorage[name] = JSON.stringify(value);
        break;
      case CHROME_STORAGE_LOCAL:
        var data = {};

        data[name] = value;

        chrome.storage.local.set(data);
        break;
    }
  };

  if (window.chrome && window.chrome.storage && window.chrome.storage.local) {
    mode = CHROME_STORAGE_LOCAL;
  } else {
    mode = LOCALSTORAGE;
  }

  keyPrefix = keyPrefix || "";
}

Summary:
PrefStorage is used in FlightLogAnalyser to save and retrieve user settings asynchronously. This could indirectly affect dataBuffer if user settings influence data loading or spectrum type, but it does not directly manipulate dataBuffer.


Relevant snippet from src/spectrum-exporter.js (lines 13-42)

export function SpectrumExporter(fftData, opts = {}) {
  opts = _.merge(
    {
      columnDelimiter: ",",
      quoteStrings: true,
    },
    opts,
  );

  function dump(success) {
    const worker = new Worker("/js/webworkers/spectrum-export-worker.js");

    worker.onmessage = (event) => {
      success(event.data);
      worker.terminate();
    };

    worker.postMessage({fftOutput: fftData.fftOutput,
                        blackBoxRate: fftData.blackBoxRate,
                        opts: opts});
  }

  return {
    dump: dump,
  };
}

Summary:
SpectrumExporter uses fftData to export spectrum data asynchronously via a web worker. This relates to fftData but does not directly affect dataBuffer.


Relevant snippet from src/graph_spectrum_plot.js (lines 31-51)

export const GraphSpectrumPlot = window.GraphSpectrumPlot || {
  _isFullScreen: false,
  _cachedCanvas: null,
  _cachedDataCanvas: null,
  _canvasCtx: null,
  _fftData: null,
  _mousePosition: {
    x: 0,
    y: 0,
  },
  _overdrawType: null,
  _spectrumType: null,
  _sysConfig: null,
  _zoomX: 1.0,
  _zoomY: 1.0,
  _drawingParams: {
    fontSizeFrameLabel: "6",
    fontSizeFrameLabelFullscreen: "9",
  },
  _importedSpectrumsData: [],
};

Summary:
GraphSpectrumPlot holds internal state related to the spectrum plot including _fftData. This is set in FlightLogAnalyser after data loading. It does not directly manipulate dataBuffer but is part of the data flow.


Summary of relevant context for dataBuffer corruption:

  • dataBuffer in FlightLogAnalyser is a local object holding references to the current field index, curve, and field name.
  • It is updated in plotSpectrum and used to load data via GraphSpectrumCalc.
  • GraphSpectrumCalc has an internal _dataBuffer with similar structure.
  • When spectrum type changes, if dataBuffer.curve is falsy (indicating corruption or reset), it is restored from GraphSpectrumCalc._dataBuffer.
  • The root cause of dataBuffer corruption could be related to how GraphSpectrumCalc._dataBuffer is managed or how plotSpectrum is called.
  • No direct error handling or validation is shown for dataBuffer outside the spectrum type change event.
  • User settings and asynchronous storage via PrefStorage may indirectly affect data loading and dataBuffer.
  • The fftData object returned from GraphSpectrumCalc functions references _dataBuffer fields, linking the data flow.

This context is relevant to investigate potential root causes of dataBuffer corruption in src/graph_spectrum.js.

if (!dataBuffer.curve) {
dataBuffer.curve = GraphSpectrumCalc._dataBuffer.curve;
dataBuffer.fieldName = GraphSpectrumCalc._dataBuffer.fieldName;
dataBuffer.fieldIndex = GraphSpectrumCalc._dataBuffer.fieldIndex;
console.warn("The dataBuffer was corrupted (set to default zeroes) in FlightLogAnalyser.spectrumTypeElem.change event");
}
// Recalculate the data, for the same curve than now, and draw it
dataReload = true;
that.plotSpectrum(
Expand Down
6 changes: 4 additions & 2 deletions src/graph_spectrum_calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const GraphSpectrumCalc = {
_blackBoxRate : 0,
_dataBuffer : {
fieldIndex: 0,
curve: 0,
curve: null,
fieldName: null,
},
_flightLog : null,
Expand Down Expand Up @@ -85,7 +85,9 @@ GraphSpectrumCalc.setOutTime = function(time) {
};

GraphSpectrumCalc.setDataBuffer = function(dataBuffer) {
this._dataBuffer = dataBuffer;
this._dataBuffer.curve = dataBuffer.curve;
this._dataBuffer.fieldName = dataBuffer.fieldName;
this._dataBuffer.fieldIndex = dataBuffer.fieldIndex;
return undefined;
};

Expand Down