Skip to content

Conversation

@hydra
Copy link
Contributor

@hydra hydra commented Aug 8, 2019

Tested with hex files generated firmware from betaflight/betaflight#8679

All existing .hex files generated by the build are not suitable for flashing using the configurator as they don't have the zero fill. This issue wasn't known about until the code in this PR was written and tested.

Instructions for use:

Notes:

  • "Full chip erase" will erase the entire external flash, blackbox log, config, firmware and badblock sectors.
  • When "Full chip erase" is NOT selected, the config is NOT erased. See bootloader instructions if you need to erase your config.

Video here:

IMAGE ALT TEXT

https://youtu.be/jyFupDg1biQ

Parsing `0800` was ok, but parsing `97CE` was not.
The sign was not correctly handled, this uses `>>> 0` to force unsigned
result.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#%3E%3E%3E_(Zero-fill_right_shift)
@mikeller
Copy link
Member

mikeller commented Aug 8, 2019

as they don't have the zero fill.

Not sure why you would need to have a zero fill when using .hex files to flash - .hex files allow for the target address of non-contiguos blocks to be explicitly set, so unless you need the space in between two blocks to be 0, just specifying the first block, beginning at its start address, and then the second block, also beginning at its start address, will work with .hex files.

console.log('Using transfer size: ' + self.transferSize);
self.clearStatus(function () {
self.upload_procedure(1);
if (typeof chipInfo.internal_flash != "undefined") {
Copy link
Member

Choose a reason for hiding this comment

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

Should be a non-coercing not equals.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

});
});
}
} else if (typeof chipInfo.external_flash != "undefined") {
Copy link
Member

Choose a reason for hiding this comment

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

Should be a non-coercing not equals.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@hydra
Copy link
Contributor Author

hydra commented Aug 8, 2019

as they don't have the zero fill.

Not sure why you would need to have a zero fill when using .hex files to flash - .hex files allow for the target address of non-contiguos blocks to be explicitly set, so unless you need the space in between two blocks to be 0, just specifying the first block, beginning at its start address, and then the second block, also beginning at its start address, will work with .hex files.

yes, the zero fill is needed because the 0's are used for exst hash calculation.

I didnt see any other command line arguments to objcopy that allow the gap to be set, it would also require additional code in the hex parser anyway, iirc.

@mikeller
Copy link
Member

mikeller commented Aug 8, 2019

it would also require additional code in the hex parser anyway, iirc

The .hex file parser in the Betaflight configurator can already handle non-contiguos blocks - that's how it is possible to update the firmware without resetting the configuration.

@hydra
Copy link
Contributor Author

hydra commented Aug 8, 2019

@mikeller yes I know it does non-continguous blocks. I had a good look at the code and step-debugged through a lot of it to see how it dealt with hex data sections, etc. However that is not the issue here.

The issue is that the EXST hash is computed on the firmware BINARY, minus the last 64 byte block, this binary contains 0's as defined by the linker script. However, when you use objcopy to generate a hex file from the patched .elf file it does not output the area between the end of firmware and the start of the hash block.

Since the configurator will erase pages as needed, based on the addresses in the hex file and sector boundaries of the flash, and these erased pages on NAND flash have a default value of 0xFF when read, the hash computed from the content on flash won't match the hash at the end of the firmware block.

To me the simplest solution is to generate a .hex file have the same binary content as the .bin file.

@hydra
Copy link
Contributor Author

hydra commented Aug 8, 2019

@mikeller with regards to use of "typeof" it seems kinda weird that in the same file, stm32usbdfu.js there are now two ways to check if something is defined, in some cases negating the comparison. e.g.

                if (resultCode != 0 || typeof chipInfo === "undefined") {
                    ...
                } else {
                    if (chipInfo.internal_flash != undefined) {
                   ...

Initially the way I had it was to use typeof for consistency, can you shed some light on why you requested the non-coercing expression? My JS is a bit rusty at the moment so maybe I'm missing something here?

@hydra hydra requested a review from mikeller August 8, 2019 15:43
@mikeller
Copy link
Member

mikeller commented Aug 8, 2019

@hydra: You misunderstood me. All I meant you to do was to change the != in the expression typeof chipInfo.external_flash != "undefined" to a !==.
In my opinion, typeof x !== "undefined" is a wordy way to check x !== undefined, but it is correct.
But == and != should only ever be used in JavaScript if one wants to specifically check 'is there a way to cast x into y?'. In every other case === and !== should be used.
Coming from C, this is a major pitfall in JavaScript for me.

@Docteh
Copy link
Contributor

Docteh commented Aug 8, 2019

Looking at the use of undefined in quotes might be worth a look.

I'm the sort of guy that has to go and look up what coercing means as far as javascript goes, but I've noticed that we've got some code that has been unmodified since baseflight-configurator

We're using undefined outside of quotes a lot more than inside of quotes

Looks like all the "undefined" in stm32usbdfu.js are from one commit: 20b6d65

src/js/main.js:        CliAutoComplete.setEnabled(typeof result.cliAutoComplete == 'undefined' || result.cliAutoComplete); // On by default
src/js/protocols/stm32usbdfu.js:    if (typeof _timeout === "undefined") {
src/js/protocols/stm32usbdfu.js:                            if(typeof abort === "undefined" || abort) {
src/js/protocols/stm32usbdfu.js:                if (resultCode != 0 || typeof chipInfo === "undefined") {
src/js/protocols/stm32usbdfu.js:                    if (typeof chipInfo.internal_flash === "undefined") {
src/js/protocols/stm32usbdfu.js:                if (typeof self.chipInfo.option_bytes === "undefined") {
src/js/tabs/failsafe.js:        if (typeof RSSI_CONFIG.channel !== 'undefined')  {
src/js/serial_backend.js:        if (result.auto_connect === 'undefined' || result.auto_connect) {

@mikeller
Copy link
Member

mikeller commented Aug 8, 2019

@Docteh:

There's the difference:

  • undefined is a constant that is assigned to any variable / property on declaration (potentially implicit);
  • "undefined" is the type of undefined.

The type system in JavaScript, and the typeof operator (evaluating to a string) are things that were done in a hurry in JavaScript, and they are ugly and clunky.

Type checking with typeof makes sense for most types, but in the case of "undefined" it is pretty much redundant, since this type will only ever be returned by undefined, making typeof(x) === "undefined" equivalent to x === undefined.

If you want to get into the nitty gritty of JavaScript, I can recommend Douglas Crockford's presentations on it: https://www.youtube.com/watch?v=JxAXlJEmNMg

@hydra
Copy link
Contributor Author

hydra commented Aug 8, 2019

will fix this up in the morning. thanks for feedback and info.

hydra added 2 commits August 9, 2019 13:14
In this case, it's invalid if the HEX file doesn't contain any data in
the address range of the chip to flash.
@hydra
Copy link
Contributor Author

hydra commented Aug 9, 2019

@hydra: You misunderstood me. All I meant you to do was to change the != in the expression typeof chipInfo.external_flash != "undefined" to a !==.

ok done.

In my opinion, typeof x !== "undefined" is a wordy way to check x !== undefined, but it is correct.

agreed!

LGTM!

@McGiverGim
Copy link
Member

In my opinion, typeof x !== "undefined" is a wordy way to check x !== undefined, but it is correct.

Now I'm working on a PR that uses this, and both are different.

https://github.com/McGiverGim/betaflight-configurator/blob/af423ddb8b82605ffb4608d59bafbb35b5c704b3/src/js/tabs/vtx.js#L22-L32

If I remove the typeof the result is different. This is an ugly hack to execute a MSP command in a loop to retrieve an array. The MSP is async so I needed this kind of things to make it working.

@hydra
Copy link
Contributor Author

hydra commented Aug 9, 2019

If I remove the typeof the result is different. This is an ugly hack to execute a MSP command in a loop to retrieve an array. The MSP is async so I needed this kind of things to make it working.

you must use undefined (keyword) rather than "undefined" (string literal) if you also remove the typeof.

Since this PR checks the same object for two properties and results in false for the first expression and true for the second one when flashing an EXST target we can be sure that all versions of the expression work OK. i.e. For this PR, both the original expression, the second version and the current expression all work fine.

I'm happy to use any of the expressions so far, but like @mikeller I often err on the side of strictness when it comes to languages that do type coercion so that the reader of the code can clearly see the intent.

}
}

if (erase_pages.length == 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Same deal here, should be ===.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

case 0x04: // extended linear address record
extended_linear_address = (parseInt(content.substr(0, 2), 16) << 24) | parseInt(content.substr(2, 2), 16) << 16;
// input address is UNSIGNED
extended_linear_address = ((parseInt(content.substr(0, 2), 16) << 24) | parseInt(content.substr(2, 2), 16) << 16) >>> 0;
Copy link
Member

Choose a reason for hiding this comment

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

Not sure why you are adding the >>> 0 here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Byte overflow? not sure on the right term. I checked with the binary he has posted:

Did console.log of extended_linear_address when it was set.
Hex conversion is what windows calculator says.
Old way: -1748107264    FFFF FFFF 97CE 0000
New way:  2546860032              97CE 0000

I got suggested this when I looked for 'uint32 javascript' so it seems reasonable.
https://stackoverflow.com/questions/22335853/hack-to-convert-javascript-number-to-uint32

Copy link
Contributor Author

@hydra hydra Aug 11, 2019

Choose a reason for hiding this comment

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

yes, it's because all bitwise operators in JS are 32 bit signed. The >>> 0 forces the result to UNSIGNED.

Copy link
Member

Choose a reason for hiding this comment

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

Heh, signed bitwise operators, who wouldn't want those.

@hydra
Copy link
Contributor Author

hydra commented Aug 11, 2019

ready for merge now?

case 0x04: // extended linear address record
extended_linear_address = (parseInt(content.substr(0, 2), 16) << 24) | parseInt(content.substr(2, 2), 16) << 16;
// input address is UNSIGNED
extended_linear_address = ((parseInt(content.substr(0, 2), 16) << 24) | parseInt(content.substr(2, 2), 16) << 16) >>> 0;
Copy link
Member

Choose a reason for hiding this comment

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

Heh, signed bitwise operators, who wouldn't want those.

@mikeller mikeller added this to the 10.6.0 milestone Aug 11, 2019
@mikeller mikeller merged commit 7189363 into betaflight:master Aug 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants