-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Improve Dataflash Save To File #4627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
5a6a08e
9a8a201
ecd64f6
4b591de
d652ec8
68fe053
6d1f80f
af0f746
83e8efd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2449,148 +2449,92 @@ MspHelper.prototype.setRawRx = function (channels) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Send a request to read a block of data from the dataflash at the given address and pass that address and a dataview | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* of the returned data to the given callback (or null for the data if an error occured). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Send a request to read a block of data from the dataflash at the given address | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* and pass that address, a DataView of the returned data, and bytesCompressed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* to the given callback. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MspHelper.prototype.dataflashRead = function (address, blockSize, onDataCallback) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let outData = [address & 0xff, (address >> 8) & 0xff, (address >> 16) & 0xff, (address >> 24) & 0xff]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
outData = outData.concat([blockSize & 0xff, (blockSize >> 8) & 0xff]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let outData = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
address & 0xff, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(address >> 8) & 0xff, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(address >> 16) & 0xff, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(address >> 24) & 0xff, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
blockSize & 0xff, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(blockSize >> 8) & 0xff, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1, // allow compression | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+2457
to
+2465
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 🧩 Analysis chainGate the new request format by API version (avoid breaking older FCs). You’ve changed MSP_DATAFLASH_READ to include blockSize and a compression flag. Some firmware builds expect only the 4‑byte address. Add an API guard and fall back to the legacy 4‑byte request for older targets. - let outData = [
- address & 0xff,
- (address >> 8) & 0xff,
- (address >> 16) & 0xff,
- (address >> 24) & 0xff,
- blockSize & 0xff,
- (blockSize >> 8) & 0xff,
- 1, // allow compression
- ];
+ const supportsLenAndCompression = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47); // confirm required version
+ let outData = [
+ address & 0xff,
+ (address >> 8) & 0xff,
+ (address >> 16) & 0xff,
+ (address >> 24) & 0xff,
+ ];
+ if (supportsLenAndCompression) {
+ outData.push(
+ blockSize & 0xff,
+ (blockSize >> 8) & 0xff,
+ 1, // allow compression
+ );
+ } If you’re unsure of the minimal API version that accepts (addr, len, compressFlag), please confirm before merging. 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo ">>> rg for MSP_DATAFLASH_READ"
rg -n --hidden "MSP_DATAFLASH_READ" || true
echo -e "\n>>> locate MSPHelper.js"
rg -n --hidden "MSPHelper.js" || true
echo -e "\n>>> print src/js/msp/MSPHelper.js around 2440-2475 if present"
if [ -f "src/js/msp/MSPHelper.js" ]; then
sed -n '2438,2475p' src/js/msp/MSPHelper.js || true
else
echo "file not found: src/js/msp/MSPHelper.js"
fi
echo -e "\n>>> search for API_VERSION_* and apiVersion"
rg -n --hidden "API_VERSION_" || true
rg -n --hidden "\bapiVersion\b" || true
echo -e "\n>>> search for FC.CONFIG"
rg -n --hidden "FC\.CONFIG" || true
echo -e "\n>>> search for semver.gte usage"
rg -n --hidden "semver\.gte" || true
echo -e "\n>>> search for dataflash references"
rg -n --hidden "dataflash|DATAFLASH" || true Length of output: 148916 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo ">>> show MSPHelper.js 1408-1465"
sed -n '1408,1465p' src/js/msp/MSPHelper.js Length of output: 2817 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo ">>> show test/js/msp/MSPHelper.test.js"
sed -n '1,240p' test/js/msp/MSPHelper.test.js || true Length of output: 7050 Gate MSP_DATAFLASH_READ format behind an API-version check (avoid breaking older FCs). New format adds blockSize + compression flag; older firmware can expect only the 4‑byte address — guard and fall back to the legacy 4‑byte request. Location: src/js/msp/MSPHelper.js — dataflashRead (around lines 2456–2475) - let outData = [
- address & 0xff,
- (address >> 8) & 0xff,
- (address >> 16) & 0xff,
- (address >> 24) & 0xff,
- blockSize & 0xff,
- (blockSize >> 8) & 0xff,
- 1, // allow compression
- ];
+ const supportsLenAndCompression = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47); // confirm required version
+ let outData = [
+ address & 0xff,
+ (address >> 8) & 0xff,
+ (address >> 16) & 0xff,
+ (address >> 24) & 0xff,
+ ];
+ if (supportsLenAndCompression) {
+ outData.push(
+ blockSize & 0xff,
+ (blockSize >> 8) & 0xff,
+ 1, // allow compression
+ );
+ } Confirm the minimal API version that accepts (addr, len, compressFlag) before merging.
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Allow compression | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
outData = outData.concat([1]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const mspObj = this.msp || (typeof MSP !== "undefined" ? MSP : null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!mspObj) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.error("MSP object not found, cannot read dataflash."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onDataCallback(address, null, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MSP.send_message( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mspObj.send_message( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MSPCodes.MSP_DATAFLASH_READ, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
outData, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function (response) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!response.crcError) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const chunkAddress = response.data.readU32(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let payloadView = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let bytesCompressed = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (response && response.data) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const headerSize = 7; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const chunkAddress = response.data.readU32(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const dataSize = response.data.readU16(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const dataCompressionType = response.data.readU8(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Verify that the address of the memory returned matches what the caller asked for and there was not a CRC error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (chunkAddress == address) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/* Strip that address off the front of the reply and deliver it separately so the caller doesn't have to | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* figure out the reply format: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (dataCompressionType == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onDataCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
address, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
new DataView(response.data.buffer, response.data.byteOffset + headerSize, dataSize), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else if (dataCompressionType == 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Read compressed char count to avoid decoding stray bit sequences as bytes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const compressedCharCount = response.data.readU16(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Compressed format uses 2 additional bytes as a pseudo-header to denote the number of uncompressed bytes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const compressedArray = new Uint8Array( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (chunkAddress === address) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (dataCompressionType === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
payloadView = new DataView( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response.data.buffer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response.data.byteOffset + headerSize, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dataSize, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bytesCompressed = dataSize; // treat uncompressed as same size | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else if (dataCompressionType === 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const compressedCharCount = response.data.readU16(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const compressedArray = new Uint8Array( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response.data.buffer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response.data.byteOffset + headerSize + 2, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dataSize - 2, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const decompressedArray = huffmanDecodeBuf( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
compressedArray, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
compressedCharCount, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaultHuffmanTree, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaultHuffmanLenIndex, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
payloadView = new DataView(decompressedArray.buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bytesCompressed = compressedCharCount; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+2498
to
+2512
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bytesCompressed is wrong for compressed chunks (breaks compression stats). For type 1 (Huffman), bytesCompressed should reflect on‑wire payload size, not the uncompressed char count. This skews the mean compression factor. - } else if (dataCompressionType === 1) {
- const compressedCharCount = response.data.readU16();
+ } else if (dataCompressionType === 1) {
+ const uncompressedLen = response.data.readU16();
const compressedArray = new Uint8Array(
response.data.buffer,
response.data.byteOffset + headerSize + 2,
- dataSize - 2,
+ dataSize - 2,
);
const decompressedArray = huffmanDecodeBuf(
compressedArray,
- compressedCharCount,
+ uncompressedLen,
defaultHuffmanTree,
defaultHuffmanLenIndex,
);
- payloadView = new DataView(decompressedArray.buffer);
- bytesCompressed = compressedCharCount;
+ payloadView = new DataView(decompressedArray.buffer, 0, uncompressedLen);
+ // Count the transmitted payload bytes (includes the 2-byte uncompressedLen header)
+ bytesCompressed = dataSize;
} 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.warn("Decompression or read failed, delivering raw data anyway"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
payloadView = new DataView( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response.data.buffer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response.data.byteOffset + headerSize + 2, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dataSize - 2, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const decompressedArray = huffmanDecodeBuf( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
compressedArray, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
compressedCharCount, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaultHuffmanTree, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaultHuffmanLenIndex, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
response.data.byteOffset + headerSize, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dataSize, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onDataCallback(address, new DataView(decompressedArray.buffer), dataSize); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bytesCompressed = dataSize; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Report address error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log(`Expected address ${address} but received ${chunkAddress} - retrying`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onDataCallback(address, null); // returning null to the callback forces a retry | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log(`Expected address ${address} but received ${chunkAddress}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Report crc error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log(`CRC error for address ${address} - retrying`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onDataCallback(address, null); // returning null to the callback forces a retry | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MspHelper.prototype.sendServoConfigurations = function (onCompleteCallback) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let nextFunction = send_next_servo_configuration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onDataCallback(address, payloadView, bytesCompressed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let servoIndex = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (FC.SERVO_CONFIG.length == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onCompleteCallback(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nextFunction(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function send_next_servo_configuration() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const buffer = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// send one at a time, with index | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const servoConfiguration = FC.SERVO_CONFIG[servoIndex]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push8(servoIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push16(servoConfiguration.min) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push16(servoConfiguration.max) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push16(servoConfiguration.middle) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push8(servoConfiguration.rate); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let out = servoConfiguration.indexOfChannelToForward; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (out == undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
out = 255; // Cleanflight defines "CHANNEL_FORWARDING_DISABLED" as "(uint8_t)0xFF" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
buffer.push8(out).push32(servoConfiguration.reversedInputSources); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// prepare for next iteration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
servoIndex++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (servoIndex == FC.SERVO_CONFIG.length) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nextFunction = onCompleteCallback; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MSP.send_message(MSPCodes.MSP_SET_SERVO_CONFIGURATION, buffer, false, nextFunction); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MspHelper.prototype.sendModeRanges = function (onCompleteCallback) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let nextFunction = send_next_mode_range; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let modeRangeIndex = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (FC.MODE_RANGES.length == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onCompleteCallback(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
send_next_mode_range(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function send_next_mode_range() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const modeRange = FC.MODE_RANGES[modeRangeIndex]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const buffer = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push8(modeRangeIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push8(modeRange.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push8(modeRange.auxChannelIndex) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push8((modeRange.range.start - 900) / 25) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.push8((modeRange.range.end - 900) / 25); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const modeRangeExtra = FC.MODE_RANGES_EXTRA[modeRangeIndex]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
buffer.push8(modeRangeExtra.modeLogic).push8(modeRangeExtra.linkedTo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// prepare for next iteration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
modeRangeIndex++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (modeRangeIndex == FC.MODE_RANGES.length) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nextFunction = onCompleteCallback; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MSP.send_message(MSPCodes.MSP_SET_MODE_RANGE, buffer, false, nextFunction); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!response || response.crcError) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log(`CRC error or missing data at address ${address} - delivering whatever we got`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else if (payloadView) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log(`Block at ${address} received (${payloadView.byteLength} bytes)`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); // end of send_message | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; // end of dataflashRead | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MspHelper.prototype.sendAdjustmentRanges = function (onCompleteCallback) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let nextFunction = send_next_adjustment_range; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restore promise chaining in FileSystem.writeChunk/closeFile
By dropping the
await
(or a returned promise) we now resolve these async wrappers immediately, so downstream.catch
handlers never fire and anywrite
/close
failure becomes an unhandled rejection. Please keep propagating the original promises so callers can observe failures and so we don’t mark the transfer complete before the data actually hits disk.📝 Committable suggestion
🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to fix ther async await as above ,but this just made it stallmuch more frequently, with logs like this:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ctzsnooze, thank you for testing the suggested change! Your experience confirms something important about this specific use case. The logs show exactly what the retrieved learnings indicated - the MSP queue becomes overwhelmed when the download loop is slowed down.
By removing the
await
, you've made the file write operations non-blocking from the perspective of the download loop. This keeps the loop running fast enough to prevent the MSP queue from backing up. When you restored theawait
, it introduced delays that allowed the queue to grow faster than it could be processed, leading to the timeouts and exponential queue growth you observed.In this specific context, the "fire-and-forget" approach for file operations is actually the correct solution. The download process prioritizes throughput over immediate error detection from file writes. Since the FileStream API is designed to handle writes asynchronously anyway, and you're processing blocks sequentially, the risk of unhandled write failures is minimal compared to the benefit of preventing MSP queue stalls.
This is a good example of where the "correct" async/await pattern can actually be detrimental to performance in a specific use case. Your original implementation correctly prioritizes keeping the download loop responsive.
✏️ Learnings added
🧠 Learnings used