• I have been working on a Bangle.js app for work. After leaving the code to run for a while, the app starts throwing errors continually (probably once every time some event is fired). The errors thrown were very peculiar to me. For example in latest build:

    Uncaught ReferenceError: "ointStep" is not defined
     at line 1 col 1
    ointStep(){var
    ^
    in function called from system
    

    (where the function in question is supposed to be notifyCheckpointStep(), is not even a function call but rather a method definition within a class, and is most certainly not at line 1 column 1)

    and

    Uncaught SyntaxError: Unexpected end of Input
     at line 1 col 30
    t c=0;const l={normal:1,move
    

    It almost seems like Espruino is reading the program as a 30-byte fragment of the full program, and crashing because the resulting syntax within the fragment is invalid.

    We know for a fact that the program file itself is intact, as resetting the Bangle and starting the app again works fine (until a few minutes later when it starts throwing the exact same errors again).

    For context, the program uses a relatively large amount of RAM, with only less than 300 blocks left out of the usable 2100 blocks, and that's when no function is running and everything is just waiting for events. I don't know exactly how much memory is used at maximum. We have already run into other problems caused by low free memory (which fortunately we have managed to work around) so I hope this is not yet another one of them.

    May I ask what causes this, and how we could solve this problem? Thank you.

  • Which firmware version are you using on Bangle.js?

    Normally when you upload code to flash, Espruino will attempt to execute the code directly from external flash. What can happen is if something was writing code to Storage and Storage got full, Espruino would then 'compact' the storage, re-writing external flash and removing all the 'erased' files to make room for more data.

    In the old firmwares, Espruino wasn't aware that a function might have been executing from the code in flash, so if things moved around in flash it'd then end up referencing the wrong code and something like you're seeing could be happening.

    Firmware 2v09 and later should have fixed that, however if you're triggering Storage compacts often enough for this to be an issue on earlier firmwares you might want to look at your code, as writing to flash memory that often won't be great for power usage or the longevity of the memory on the device.

  • Hi Gordon, thanks for the reply. We do write to flash very frequently, but it is important for us that it does that. Still, thanks for your advice regarding power usage and longevity, we now know to watch out for those. That said, we are using firmware 2v09, so maybe something else is happening? Thanks.

  • Ok, thanks - if it's 2v09 then I would have hoped you wouldn't have seen problems, however I guess it is possible that there are cases where you have recursion and a function being executed doesn't get its pointer updated.

    If you were able to come up with a really cut-down bit of example code that demonstrated the problem then that would really help me to track it down/fix it.

    Until then, to rule out Storage, please could you:

    • Remove any files from Bangle.js's storage that your program code removes or modifies
    • Write your program code
    • Run require("Storage").compact() on the left-hand side of the IDE
    • Now run your app and/or upload other files you need

    So now, even if Storage does get compacted, the files containing your code won't get moved around. If that actually fixes the problem for you I guess it's a workaround for now, but it'll also help me to figure out where I need to focus my efforts

  • Unfortunately, the errors produced are rather different every time the code changes. It does seem to be happening in the same module (we're using Webpack), and that particular module does contain a recursive function along the lines of:

    class C {
        ...
        f() {
            ...
            somePromise.then(() => {
                ...
                f()
            })
        }
        ....
    }
    

    However, the errors occur at other functions, some only ever called before said recursive function, and some always called after it. One possible commonality (I've only just noticed so I haven't been able to verify just yet) is that they all seem to use promises. Then again, it might simply be because that particular class uses promises in a few different places.

    By the way, after trying to follow the above instruction to do storage compaction, I tried to reset (long press BTN3), and got the following exception:

    >require('Storage').compact()
    =undefined
    >
    Uncaught ReferenceError: "attery" is not defined
     at line 1 col 3
    W+CHARP;var d=new Date();g.reset();g.setFont("6x8");g.setF­ontAlign...
            ^
    in function called from system
     at line 1 col 1
    attery()*(s-12)/100,y+17);g.setColor(-1)­;}Bangle.on('chargin...
    ^
    in function called from system
    

    and when I tried to run the app it turned out the file was corrupted (with sequences of \ff at two places in the file). Is this to be expected? I repeated the steps and it the file was not corrupted the second time, though I got the same exception from long pressing BTN3.

  • Oh and I forgot to mention that after storage compaction the same errors still occur.

  • Unfortunately, the errors produced are rather different every time the code changes.

    Hi - this is what you'd expect... The actual line of code pointed to will be wrong. If there are actually function names in the stack trace (eg in function XYZ) then those will likely be correct though.

    I got the same exception from long pressing BTN3.

    Which exception was that? "attery" is not defined?

    So just to be clear, you ran require('Storage').compact() and there weren't errors, but then when you long-pressed BTN3 you started seeing errors, even though the app worked fine before the storage compact?

    file was corrupted (with sequences of \ff at two places in the file)

    How did you check the contents of the file? By loading it again with the IDE?

    Or was it just that you saw \ff in the stack traces from errors?

    If you can actually reliably get the file corrupted by running compact then that's great - if you can send me the steps (privately if you need to keep your code private) such that I can reproduce it then it'll be much easier for me to fix.

  • Which exception was that? "attery" is not defined?

    So just to be clear, you ran require('Storage').compact() and there weren't errors, but then when you long-pressed BTN3 you started seeing errors, even though the app worked fine before the storage compact?

    Yes. To be clear, I was on the morphing clock app just so our own app wouldn't be running during compaction (as the instructions above seem to only ask to run the app after compaction). The error I saw was indeed the above "attery" is not defined. It didn't break the app per se, only the current running instance of the app. I did another reset and it worked fine. For context I had ~300 files (260-512 bytes each) in storage, in total probably < 200 kB.

    How did you check the contents of the file? By loading it again with the IDE?

    Or was it just that you saw \ff in the stack traces from errors?

    By opening the file using the storage tool in the IDE. Just to be clear this is our own app's file, this and the "attery" is not defined error (which happened while running morphing clock) were two separate issues. I knew it was \ff because the file viewer in the IDE was showing hex alongside ASCII.

    By the way I did the above compaction steps again, and this time a different error (once again from the morphing clock app):

    Uncaught ReferenceError: "fffa" is not defined
     at line 1 col 3
    W+CHARP;var d=new Date();g.reset();g.setFont("6x8");g.setF­ontAlign...
            ^
    in function called from system
     at line 1 col 1
    fffaff ?[204] ?[204] ?[204] ?[204] ffafffff ?[204] ?[204] ?[204] ?[204] ?[204] ?[204] ?[204] ?[204] ffffa?[204] ?[204] ?[204] ?[204]...
    

    It happened after I moved my hand, instead of after long pressing BTN3.

    If you can actually reliably get the file corrupted by running compact then that's great - if you can send me the steps (privately if you need to keep your code private) such that I can reproduce it then it'll be much easier for me to fix.

    The corruption is not actually reliable. It only happened the first time I tried running compaction. The next three times were fine. That said every time I did it the morphing clock app seems to throw errors, so that one is reliable.

    As for the replication steps:

    1. Run our app, and start logging. Since I haven't yet sent you the code, the way this works is using a combination of StorageFile and normal fixed-length files. StorageFile (in base64) is used to allow for appending, and once that StorageFile reaches a given size limit (currently 349) the content is converted to binary and moved to a fixed-length "checkpoint" file.
    2. Leave it running until it starts throwing errors continually.
    3. Reset Bangle.js and go back to the morphing clock app.
    4. Perform the compaction steps above while running morphing clock
    5. I'm not sure what will fail here. 3 times out of 4, long-pressing BTN3 throws an error, and 1 out of 4, moving the device throws an error.
  • As for the code, I will try to ask for permission, but the day is over at my timezone so most likely I wouldn't get a reply before Monday.

  • @Gordon I'm not sure if this is correct (I am not familiar with Espruino internals after all), most code execution on our app run during event handling, and the errors that occurred with Morphing Clock also only happened during events like button presses, so perhaps the event handlers are not updated regarding the callbacks' locations in storage?

    Also, I managed to replicate the problem manually with the following steps:

    1. Open Morphing Clock
    2. Open a StorageFile and write some arbitrary data
    3. Erase said StorageFile
    4. Call require('Storage').compact()
    5. Press BTN1

    which throws the following exception:

    Uncaught ReferenceError: "fffa" is not defined
     at line 1 col 3
    W+CHARP;var d=new Date();g.reset();g.setFont("6x8");g.setF­ontAlign...
            ^
    in function called from system
     at line 1 col 1
    fffaff ?[204] ?[204] ?[204] ?[204] ffafffff ?[204] ?[204] ?[204] ?[204] ?[204] ?[204] ?[204] ?[204] ffffa?[204] ?[204] ?[204] ?[204]...
    
  • Hi, thanks for this - those last steps are really handy - I'll see if I can reproduce.

    Actually have you tried just install default apps from the app loader, and then trying again? I guess it's possible that the Storage got corrupted somehow and this is causing continued compaction errors. Starting from scratch might help.

    StorageFile reaches a given size limit (currently 349) the content is converted to binary and moved to a fixed-length "checkpoint" file.

    While it shouldn't be the cause of your problems, I'm not sure that's actually going to be the best way of doing things. Internally Storagefile allocates a big chunk of data in order to do appends, so honestly I'd have thought you would be better off just writing to a standard 'Storage' file directly in the first place...

    Either just keep everything in RAM if possible, or maybe use Storage.write with the offset functionality: http://www.espruino.com/Reference#l_Stor­age_write

  • Actually have you tried just install default apps from the app loader, and then trying again? I guess it's possible that the Storage got corrupted somehow and this is causing continued compaction errors. Starting from scratch might help.

    Yeah I've tried that, it still gives the same errors.

    While it shouldn't be the cause of your problems, I'm not sure that's actually going to be the best way of doing things. Internally Storagefile allocates a big chunk of data in order to do appends, so honestly I'd have thought you would be better off just writing to a standard 'Storage' file directly in the first place...

    Either just keep everything in RAM if possible, or maybe use Storage.write with the offset functionality: http://www.espruino.com/Reference#l_Stor­age_write

    Hmm... I have thought about that as well. I was concerned that Storage.write() might repeatedly rewrite the same page until the 4096 bytes are filled. Is that a problem, and if it is would it be more / less of a problem than using StorageFile?

  • I was concerned that Storage.write() might repeatedly rewrite the same page until the 4096 bytes are filled

    No, it'd actually be doing the same thing StorageFile does - afaik repeated writes to a page are not a big issue, it's just the amount of times you can erase the page that causes flash wear.

    I believe StorageFile now allocates at least 40kB for each file on Bangle.js - so it probably isn't that efficient for you!

  • I believe StorageFile now allocates at least 40kB for each file on Bangle.js - so it probably isn't that efficient for you!

    Oh wow that's pretty crazy. By using normal 'Storage' files we could probably reduce the production of un-erased flash pages by 40-fold, so compaction happens 40 times less frequently. Thanks!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Bangle.js program being read partially and giving errors

Posted by Avatar for user128983 @user128983

Actions