Cycle race track lap counter

Posted on
Page
of 2
/ 2
Next
  • As already mentioned here I try to develop a kind of BLE based race track lap counter .

    The base station is a MDBT42s with external antenna, big LIPO batteries, a LCD, a few buttons, a piezo buzzer and a RGB LED.
    The transponders are just Puck.js devices advertising at the highest rate.

    The Puck/transponder code is quite simple: flash a LED once in a while to show it's active, detect keypress > 2 s for switching on/off

    The MDBT42s/tracker code has gotten quite complex:

    • scan for transponders in range
    • monitor RSSI values and detect out-of-range (timeouts)
    • count lap when RSSI reaches a certain threshold
    • display various status pages (Laps, RSSI, RX counter, Battery)
    • log laps to array in RAM

    Basically everything works, but after running a certain time/detecting some dozen laps everything freezes and things become quite unstable:

    • keypresses are still handled (setWatch() handler causes a beep)
    • display update loop (setInterval() seems stuck, connecting to the console and just once calling the display handler function seems to cure the setInterval() loop again
    • connecting the terminal via BLE after this stuck situation lasts forever

    process.memory().free still shows ~390 when this happens, so I don't thinks this is a memory issue.

    I have uploaded the current code.
    Maybe someone has some pointers or an idea what might go wrong here.

    The code is capsulated into classes with either dynamic or static methods, maybe some of this was not a good idea?


    2 Attachments

  • Another issue/detail:

    This is the status after tracking 4 transponders for a while:

    >Velo.list
    ={
      "f1:04:79:ec:15:2d random": Velo: {
        id: "A",
        rssi: -78, rssiMin: -98, rssiMax: -57, laps: 42, bat: 65,
        tStart: 1628779258.06911659240, tRssiMax: null, tRssiLast: 1628791487.25615882873, tLastLap: 1628780850.37148475646, tPreviousLap: 1628780823.29253578186,
        rxCount: NaN, state: 0 },
      "dd:16:f9:6a:28:44 random": Velo: {
        id: "B",
        rssi: -65, rssiMin: -96, rssiMax: -57, laps: 44, bat: 78,
        tStart: 1628779258.02102088928, tRssiMax: null, tRssiLast: 1628791487.26290321350, tLastLap: 1628780850.51058387756, tPreviousLap: 1628780823.81463050842,
        rxCount: 11411, state: 0 },
      "f9:2d:30:24:38:a4 random": Velo: {
        id: "C",
        rssi: -65, rssiMin: -97, rssiMax: -63, laps: 57, bat: 100,
        tStart: 1628779258.01436805725, tRssiMax: null, tRssiLast: 1628791487.24501991271, tLastLap: 1628780850.97222328186, tPreviousLap: 1628780823.97481727600,
        rxCount: 27610, state: 0 },
      "e8:44:6b:5f:3e:f0 random": Velo: {
        id: "D",
        rssi: -86, rssiMin: -98, rssiMax: -69, laps: 42, bat: 82,
        tStart: 1628779296.86849403381, tRssiMax: null, tRssiLast: 1628791487.26839637756, tLastLap: 1628780850.93142127990, tPreviousLap: 1628780823.74621009826,
        rxCount: NaN, state: 0 },
      "c2:fc:b0:90:61:c7 random": Velo: {
        id: "E",
        rssi: null, rssiMin: null, rssiMax: null, laps: 0, bat: null,
        tStart: null, tRssiMax: null, tRssiLast: null, tLastLap: null, tPreviousLap: null,
        rxCount: 0, state: 0 },
      "f5:23:d4:cf:c7:8a random": Velo: {
        id: "F",
        rssi: null, rssiMin: null, rssiMax: null, laps: 0, bat: null,
        tStart: null, tRssiMax: null, tRssiLast: null, tLastLap: null, tPreviousLap: null,
        rxCount: 0, state: 0 },
      "c7:da:df:68:c9:fc random": Velo: {
        id: "G",
        rssi: null, rssiMin: null, rssiMax: null, laps: 0, bat: null,
        tStart: null, tRssiMax: null, tRssiLast: null, tLastLap: null, tPreviousLap: null,
        rxCount: 0, state: 0 },
      "d3:8f:95:28:f0:02 random": Velo: {
        id: "H",
        rssi: null, rssiMin: null, rssiMax: null, laps: 0, bat: null,
        tStart: null, tRssiMax: null, tRssiLast: null, tLastLap: null, tPreviousLap: null,
        rxCount: 0, state: 0 }
     }
    

    How can rxCount be set to NaN when this is the only way it is changed in the code:

      this.rxCount = 0;
      this.rxCount += 1;
    
  • ...interesting: @ChristianW , for most of the time you use function X {} when X is a singleton and then stick everything to it with something like X.val = 0; or X.init = function(...) { ... };. What is the reason for declaring the singleton as a function rather than as below with a object from a code literal like you do for const PAGES = { ... };:

    var X =
      { val: 0
      , init: function( ... ) {
          ...
        }
    };
    

    Of course, this does not answer your question(s)... yet... f0r sure not the last one (...NaN).

    Reading @Gordon 's post #150 - http://forum.espruino.com/comments/16107­155/ - in conversation about Please post what you're working on! and my own experience w/ displays hint to me that the update of the display takes too long and you may run into event buffer overflows, last but least you run advertising at utmost frequency and use a fixed interval for updating the display (though not absolutely sure about the latter).

    In my case, it took too long to update the display with all GPS data, so I updated only parts at a time and only when the value changed. Of course, my display was a color display and I used vector fonts, which did for sure not help with keeping the JS streak for updating the display as 'short' as possible.

    I have no insight into wether the execution is really completely (logically) single single threaded as expected with JS, but I know from other experiences in environments where underlaying system code makes it quasi multi-threaded by responding to interrupts and then not does not just updated a synchronized (event) buffer but also pushes data thru into the space of the single thread in execution by calling (callback) functions of the single threaded code space.

    The scan may also hold up serving intervals timely.

    Therefore, I'd replace intervals with with combination of timeout and self-call to not run into a backup of interval timeouts. To further shorten the JS streaks, you can break up loops in JS into sequence of timeout calls - one for each element - by keeping the index in the global space. Yes, it makes the code more complicated but you can tune the execution load better.

    Btw, there is a simple way for clearing an interval or timeout. Assume var iId =null; and later iId= setInterval(... and var tId = null and later tId = setTimeout(... have happened, the clearing can go like this: if (iId) iId = clearInterval(iId); and if (tId) tId = clearTimeout(tId);, respective, since clearing returns undefined (you could even omit the init with null at declaration).

    Furthermore, to make sure you never 'multi-interval' or 'multi-timeout' one and the same 'thing', check respective id before setup and throw Error. For timeouts, it requires clearing the id in the timeout execution with tId = null;.

    Do you know the ' for a while' time and did you make the calculation of average time per rx received?

    ...and on a completely different note: why Velo and VELOS and not Fahrrad and FAHRRAEDER (Fahrräder)?

  • Forgot to say: Quite an elaborate project with a lot of moving parts - nifty challenges.

  • Regarding the objects / singletons:
    I am not 100 % fluent in JS, most of the things I have looked up somewhere.

    From what I understood the Objects/Classes are declared as functions and since I don't need dynamic instances I'd mostly stick to static Objects, so (I thought):

    function Foo() {} 
    

    would be a static object and

    Foo.bar = function() {
       Foo.some = 123;
    }
    

    would declare a static method to it while

    Foo.prototype.baz = function() {
        this.thing = 123;
    }
    

    would be a dynamic method working on real instances of the object created with

    var foo = new Foo();
    

    Could some awkward style of my code cause some runtime trouble?
    If your example regarding objects is more common / recommended, I can change my code.

    Also thanks for the pointers regarding the draw() method, it is really awkward that it just blocks up sometimes. I'll try to break it into smaller chunks and move things to the background.
    Do you think the timeout value is relevant? Or is it just to have it running asynchronously like

    Object.keys(list).forEach((i)=>{
       setTimeout(()=>{
          …
       }, 1);
    });
    

    Can the timeout value actually be 0 as well?

    Regarding

    Do you know the ' for a while' time and did you make the calculation of average time per rx received?

    Sorry, I am not sure what you are asking here. Could you elaborate?

    Regarding Velo: It is mainly about riding/racing Velomobiles (those fully faired three-wheeled recumbents), not bicycles... ;-)

  • @ChristianW,

    Object literals are a very compact definition and you can use this very naturally. I did use function definition as object and stick my application methods to it, but very rarely. I try to stay more in the confines to not have unexpected side effects. I understand the static aspect and it is helpful to have limited number of globals. Used in Smalltalk (st) the class object as the repository for the instances and related retrieval and storage methods. In st the classes are instances of Class and are also 1st class objects. A lot what I do is still modeled after st. Inheritance is quite different in the various oo languages, but it does not bother me since I use more the composition rather than inheritance. I would not call your approach awkward, but yes it could have some runtime challenges, since yo may not want to inherit certain things of, for example, the function.

    Having setTimeout() in the loop for processing of each of the elements is not exactly what I thought about, because you just stack up all the invocations. I was more thinking along the lines of open loop with the loop index being outside.... similar to the approach you use for the led flashing. I made a similar thing a while ago when flashing combination codes w/ green and red led. I constructed a String such as gGgg and RRr and concatenated - queued - for every error code blink to something like that gGggbRRrbRRrr, uppercase for longer and lower case for shorter blink, and b for a break, almost like Morse code.

    I do not know what a setTimout() does with 0 [ms]. I use 1 and if I want to stretch it out, I use a higher value, but with 'serialized calls': call the next one at the end of the previous one (as long as there is elements to process in an array or characters in a string).

    To have some timing numbers, I was thinking to take the runtime since start and divide by the sum or rxCounts to get a figure how much time could be spent on average to handle an rx event. The other approach for you to figure whether the processor is 'in overdrive'/loaded, you can use setBusyIndicator(pin) or setSleepIndicator(pin).

    Furthermore, what I experienced in regard of timing is that minified code just rans faster... especially with long identifiers / symbols that are reduced (most of the time) to single lettes. I also use in general short(er) identifiers, after all the context makes it clear what is going on, a beauty of oo environment (encapsultion).

  • Thanks @allObjects for the insights.
    I will try to understand what you were saying and refactor my code a bit.
    It seems there were a fews ways of doing OOP in Javascript for some historical reasons, but it is hard to find the "right" just for the Espruino world since there are not many examples here.
    Most of the code snippets here are just simple and short and just do everything globally.
    I felt like having some things encapsulated, so this it what I ended up with.

    Minification is a thing to try, but I was worried about possible error messages and not being able to track them back to their source.

    Actually after one session when everything froze I had a syntax error in my ErrorLog object:

    >ErrorLog.log
    =[
      SyntaxError: SyntaxError: Got ')' expected EOF
     ]
    

    Any idea about that?
    The code had no errors when it was uploaded. May it have changed itself?
    Memory issues?

  • Both of the errors you noticed are very strange. I have the suspicion that some things does net get finished...

    I did not wanted to critique the coding style, I just was looking for reasons, because there are multiple ways to skin the js cat, end even more so on a platform with extreme low amount of resources.

    modularization / objectification / encapsulation is the way to go! On Espruino boards it just has to be a bit different than in JS in the browser or a nodeJS server. I already went down the path of having self-identifying - simple - data structures (arrays) and separate process, even though this is not real oo. As long as the thinking / concepts are oo / with encapsulation, it is a good to go for me.

    Have to study your code a bit more and may be even run it... I have pixelJSs and PuckJSs and BangleJSs to do the setup. Do you have some emulation code to 'fake' the transmission strength so I have not to get real velos going?

  • Hi @allObjects, I just refactored the whole code and changed every object - except Velo which is dynamically created and I don't know how that works in the way you suggested.

    However, I ran into an issue. Look at this simple example:

    var Obj = {
        message: "foo",
    
        init: function() {
            setInterval(this.log, 1000);
        },
    
        log: function() {
            console.log(this.message);
        }
    };
    
    Obj.init();
    
    undefined
    undefined
    undefined
    …
    

    The interval output is just undefined and not foo as you would expect.
    Somehow passing the callback this.log to setInterval() loses the object context.

    Can you explain this or do you have any solution for this other than using Obj.message instead of this.message inside the log() method?
    Passing Obj.log as callback does not help by the way...

    Very strange.

  • OK - found the solution myself.
    This works:

    var Obj = {
        message: "foo",
    
        init: function() {
            this.message = "foo";
            setInterval(()=>{
              this.log();
            }, 1000);
        },
    
        log: function() {
            console.log(this.message);
        }
    };
    
    Obj.init();
    

    Something about scope and references I guess.

  • @allObjects OK, after ironing out the first batch of issues this is a basically working (but still untested) new version.
    The draw() function was a bit tricky since I feared that setInterval() could cause overlaps, so I run a number of setTimeout()s in a row, calling the next one recursively until the queue is empty.
    Hope that is what you suggested and have in mind.

    The next thing would be to patch my Puck.js fleet to turn their radio on and off at intervals to simulate track laps.
    This way I can run extended testing without leaving the room.


    1 Attachment

  • OK - testing again.
    After about 10 minutes everything gets stuck and comes to a grinding halt.

    No display updates, no keypress recognitions.

    The first time it happened external BLE console connect was possible (but took looong) and dozens of lines with

    Execution interrupted
    Execution interrupted
    …
    

    appeared.

    The second time the module is not even connectable via bluetooth.
    Some time after starting the test it dropped the still open BLE console from my computer but still worked.
    Now after 10 minutes when it froze I cannot even find it via LightBlue anymore.

    May this be an internal bug in the Javascript engine?
    How to proceed?

  • OK.
    Some more tests show that it may have been a memory issue.
    Limiting the stored lap data to 250 records resulted in the test running for about two hours now.

    However, somehow the Transponders stop advertising now somehow after a few hundered iterations being toggled on and off.
    This is the modified code:

    /** ========================================­=============
     * throw off unknown BLE clients
     * @constructor
     */
    var Firewall = {
      whitelist: {
        '14:7d:da:3f:53:31 public': 'Macbook Work',
        '50:ed:3c:01:69:ab public': 'Macbook Air'
      },
    
      init: function () {
        NRF.on("connect", (addr) => {
          if (!(addr in this.whitelist)) {
            NRF.disconnect();
          }
        });
      },
    }; // Firewall
    
    var id = 0;
    var on = true;
    function toggle() {
      if(id == 0) {
        NRF.wake();
        digitalPulse(LED2, 1, 200);
        id = setInterval(
          ()=>{
            digitalPulse(LED3, 1, 30);
            on = ! on;
            advertise();
          },
         5000
        );
      }
      else {
        digitalPulse(LED1, 1, 500);
        clearInterval(id);
        id = 0;
        NRF.sleep();
      }
    }
    
    var longId = 0;
    
    function longPress(state) {
      if(state) {
        if(0 == longId) {
          longId = setTimeout(
            () => {
              toggle();
              longId = 0;
            },
            2000
          );
        }
      }
      else {
        if(longId > 0) {
          clearTimeout(longId);
          longId = 0;
        }
      }
    }
    
    function advertise() {
      if(on) {
        NRF.setAdvertising(
          {},
          {
            name: "Velo" + NRF.getAddress().substr(-5).replace(":",­ ""),
            showName: true,
            discoverable: true,
            connectable: true,
            scannable: true,
            interval: 20,
            manufacturer: 0x0590,
            manufacturerData: [Puck.getBatteryPercentage()]
          }
        );
      }
      else {
        NRF.setAdvertising();
      }
    }
    
    function onInit() {
      Firewall.init();
    
      advertise();
      setInterval(advertise, 60000);
    
      toggle();
      setWatch(
        (btn) => longPress(btn.state),
        BTN,
        { repeat:true, edge:"both", debounce: 50 }
      );
    }
    

    The effect is this:
    The blue flashing still occurs, but the change to advertise the manufacturer id doesn't seem to happen, because the Puck is not recognized by the tracker anymore.
    Toggling on/off via button (resutls in NRF.sleep() / NRF.wake()does not help.
    Doing a reboot (power cycle) makes it work again.

    It seems the repeatedly change via NRF.setAdvertising() breaks something over time.

    Very strange, but no issue for the later use case.

  • Sun 2021.08.15

    Has a periodic memory availability check been performed using process.memory()?

    http://www.espruino.com/Reference#proces­s

  • @ChristianW,

    sorry being off for a bit... did some woodworking... a totally different beast but great balance to the 'just sitting' and hacking.

    To begin with the post #9* where some off the oddities (JavaScript: The Good Parts... Douglas Crockford): context of the 'this': For a generic understanding, JavaScript is - next to other many other things - a scripting language that supports functions and provides very low entry level in coding.... and that is what happens with the setTimeout() and setInterval(): the first argument is a function(), nothing else... and when it is 'finally' called, the function knows nothing about the very high level concept of coding nor oo - context - (anymore) when it was passed as argument to the setTimeout() and setInterval(). The execution hits the 'this' and tries to resolve it... and it may get a context, just not the one you intended.

    Recall of code from post #9:

    var Obj = {
        message: "foo",
        init: function() {
            this.message = "foo";
            setInterval(()=>{
              this.log();
            }, 1000);
        },
        log: function() {
            console.log(this.message);
        }
    };
    
    Obj.init();
    

    This - original context not known anymore - is not all bad, because:

    • do you always need a context
    • and plain scripting in a simple problem needs only one (global context), so why demand a context?

    But you figure... and you figured it - almost - because another oddity made it right: fat arrow functions do not have their own context like a regular function... oops... you got mocked by JS's understanding of context... again... The fat arrow function has no own context like a regular function has but takes the creation context and holds on to it...

    Therefore, to overcome the 'this' context for setTimeout() and setInterval() with regular functions, JavaScript offers multiple options:

    The first, always working one, is to bind the function to the context you want before passing:

    var obj = {
        message: "foo",
        init: function() {
            setInterval(this.log.bind(this), 1000);
        },
        log: function() {
            console.log(this.message);
        }
    };
    
    function onInit() {
            obj.init();
    }
    
    setInterval(onInit,999);
    

    The bind() in line #4 makes sure the any this in function passed refers to the context (and object) you intended.

    Alternative and not to use the bind(), you set a local variable to point to the context (this) and used that in the function (some use 'that' for that - word play). In the beginning I used _this, but most of the time I just use _ for the variable name and create an anonymous function (the bind() does this behind the scene... and is even more efficient):

    var obj = {
        message: "foo",
        init: function() {
            var _ = this;
            setInterval(function(){ _.log(); }, 1000);
        },
        log: function() {
            console.log(this.message);
        }
    };
    
    function onInit() {
            obj.init();
    }
    
    setInterval(onInit,999);
    

    You may notice some other things:

    • A good convention in oo is to leave uppercase beginning names for 'class' like things... (in JS constructor function), or for constants, some times globals too... but it can get confusing. So I stick with former.
    • I wrapped the init() invocation into the 'famous' onInit function
    • I used a timeout to trigger the onInit()... which I then remove on last upload (to RAM) before save()-ing the code into the FlashEEProM.

    Latter two have nothing to do with what we discuss here. Have an onInit() to get the code activated at a 'conscious' point is a good practice. Last one makes sure that applicaiton code does not mess with the upload... because the upload is a running js code as well... (Espruino understands only JS thru the REPL in the console, and therefore, what is going on on upload is javascript execution. You can read about this in conversation about: simple explanation how to save code that espruino run on start?. I has aged... but is still true when uploading into the RAM. For simple examples it is never an issue, but if code is active - especially timeouts and intervals and dynamic inits, it is a bad practice to get them going before the upload is complete. @Gordon has done a lot to make the execution save and avoid contentions with the upload, but there is always the possibility that the application or a used driver to connect to a sensor or actuator has an initialization that cannot be know to the save() command nor to a (re)load and resume on power up / power cycle.

    More is to be said about context... but this is enough for now.

    Not having a clear - reproducible - initialization after power cycle / messing w/ the upload can cause some of the unpredictable things... like the ) found ( ...found ( Got ')' expected EOF ).

  • Handling buttons is a challenge... I would never ever (sorry for the strong 'never ever') trust those things... You already use in your code concepts of too rapidly firing things and put a stop to it by defining a minimal time range for something - event - to be in the past for accepting the same thing - event -again. Handling touches or presses is a business of itself. Therefore, when I want to be safe to not have bouncing - even though debouncing is built-in - I enforce it myself.

    The easiest is to not take the press but watch the release and watch it only once. Then do all the business I want to do and then - if I need the button again watched (to establish, for example, a toggle), I set the watch again, on release and only once again. With hat I make sure I do not create race conditions that you may have had... Bad thing about race conditions is that they can be so unpredictable that only with heave machinery they can be shown. If they can be prevented by logic, then let's do so.

  • Btw: cool thing about you emulation of the puck coming into reception range amd leaving it by starting and stopping transmission / advertising. Adding a finesse would still be the increase and decrease of transmit power to have some of you code covered. Instead of that, I was thinking of putting one to many tin cans over the puck to mess with the signal strength.... ;)

  • Yes, I show process.memory().free on one of my status pages as you can see in the code.
    That's how I found out about the freezing issue.
    Memory was not actually near zero, it was a bit above 100 when strange things happened.
    So I just limited the number of logged laps (I cannot log forever, actually I just consider pushing them to a SD card) and things got more stable.

  • That's what I also had in mind, but it was a bit too complicated for a quick first test.
    I have experimented with radio wave shielding mesh for shielding off rooms and created small containers to "move" objects out of range just by dropping them in.

    But this requires mechanical work, I'd have to build a rig to get it going for minutes (hours?) that's why I came up with just fiddling with the transponder side and it worked. ;-)

  • Thanks for pointing that out.
    But actually there were no issues with the buttons yet other than there was no response at all with the setHandler() part when the whole thing got stuck.
    Do you see any issue in my code?
    The freezes happened even when not pressing any button for a longer period.

  • Aaah - thanks for the brief explanation.
    I was aware of the scope of this and the technique of using that but did not expect it to be an issue with just referencing a callback function like setTimeout(this.log, …) expecting it to be resolved just before the timeout is started.
    However, the bind() function was new to me, thanks for the suggestion.
    And that function() {} is different from () => {} regarding the scope of this did not occur to me.
    Javascript is easy and nice in some aspects, but has a lot of oddities when digging deeper...

  • @ChristianW, indeed... but that is what you get:

    oddities when digging deeper

    ...with - I would call it - conceiving a brilliant language and implementation that can handle simple scripting as well as advanced application constructs. Sure, there are other very powerful languages out there with all their strength and hardship (weakness would be too easy to say it). If I need something to quickly try something out: the browser and html5 is my friend: I can do logic, I can do display, I can ui, I can single step debug with value setting... I do not need to compile... I do not need a separate ide... incredible. To pay the price for not being pure oo, not having interfaces, needing special stuff to do inheritance the easy way... JS is still good bet. Not for nothing took nodeJS off... against much 'older' stuff, like Python or so. Worked and still working with all kinds of environments - language and runtime - and somewhat 'like' them all. When I have an issue with my code it is most of the time I do not understand the application / biz problem. After getting that - meat - part, implementing becomes due diligent work. But that's me. Of course the right tool for the right material - like a hammer when have to deal with nails - is a good start... but may be considering nails was the problem.

    For some further conversation it would be good to know with what (programming) language you spent and/or still are spending most of your coding.

    Another thing I wanted to bring to your attention is this:

    Assuming you use a constructor function for creating instances that then have the same state properties you specify in the constructor and behavioral properties that you specify in the prototype. After you constructed the instance, you are free to add or remove and replace state properties and add or replace behavioral properties (methods)... Many languages do not easily support such flexibility but also prevent you from making it the abyss you easily can fall into. A lot is up to your coding discipline and conventions. Some extensions can help with that but need preprocessing, since the execution is after all JS running in a JSVM, same as with many other languages that boil down to Java and run in a JVM.

    I'll pull now a couple puckJSs and a PixleJS and see if I can get your code going...

  • @allObjects you are absolutely right.
    I used PHP for most of the time, and a bit of MySQL too. I did some Web/Frontend stuff too. JQuery mostly, but maybe lacked a deeper understanding of the Javascript language which was slightly changing over the years too.

    I also like it because it is so easy to try. And pretty fast too...

    I will update my other Puck.js today to run the lap-simulation code and then run a thorough test again.

    One last question:
    Does it matter that the console still stays attached to the BLE service, even if there is no active connection?
    Can this cause issues?
    I would expect that any output or error occurring will be queued somewhere in RAM and flushed to the console once you reconnect to the BLE service some time later.
    That's why I added the ErrorLog mechanism, but it lacks a proper stack trace.
    Are there better ways?

  • OK - some updates:

    1. I blew up my MDBT42s somehow. It still works, but days ago I overloaded one of the LED pins and was curious about the bad battery runtime and the high amps (> 40 mA) even with everything switched off.
      Pulled everything apart to sort it out, put it back together (minus LED, don't need it) - yes D27 is gone.
      So I replaced it with a spare device, unfortunately not with external antenna (just ordered replacements yesterday)

    2. I run tests again and ran into issues again after ~30 minutes runtime and ~160 - 200 simulated laps with two Pucks:

    • the lap array is limited to 200 entries, so process.memory().free stays way above 400 mostly
    • at some point everything freezes. No display updates, no button reponses, amps at ~15 mA (also with Backlight on which is only a few mA) all the time, no BLE connection possible, no advertising either
    • doing it a second time I tried to stay connected via Web Console, after ~ 10 minutes I lost connection, reconnected and monitored memory a few times.
      This is the final output before and after reconnect and before the freeze:

      ={ free: 900, usage: 1600, total: 2500, history: 10,
      gc: 0, gctime: 6.43920898437, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 891, usage: 1609, total: 2500, history: 10,
      gc: 0, gctime: 6.50024414062, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 888, usage: 1612, total: 2500, history: 10,
      gc: 0, gctime: 6.65283203125, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 873, usage: 1627, total: 2500, history: 10,
      gc: 0, gctime: 6.53076171875, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 873, usage: 1627, total: 2500, history: 10,
      gc: 0, gctime: 6.53076171875, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      Disconnected from Web Bluetooth, MDBT42Q cd4f
      >
      <- Serial1
      Found MDBT42Q, 2v08
      >
      Connected to Web Bluetooth, MDBT42Q cd4f
      >process.memory()
      ={ free: 603, usage: 1897, total: 2500, history: 10,
      gc: 0, gctime: 7.2021484375, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 510, usage: 1990, total: 2500, history: 10,
      gc: 0, gctime: 7.4462890625, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 447, usage: 2053, total: 2500, history: 10,
      gc: 0, gctime: 7.87353515625, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 511, usage: 1989, total: 2500, history: 10,
      gc: 0, gctime: 7.41577148437, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 510, usage: 1990, total: 2500, history: 10,
      gc: 0, gctime: 7.41577148437, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 468, usage: 2032, total: 2500, history: 10,
      gc: 0, gctime: 7.53784179687, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      >process.memory()
      ={ free: 502, usage: 1998, total: 2500, history: 10,
      gc: 0, gctime: 7.4462890625, blocksize: 16, stackEndAddress: 536928912, flash_start: 0,
      flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 }
      ERROR: Ctrl-C while processing interval - removing it.
      Execution Interrupted during event processing.
      New interpreter error: CALLBACK,LOW_MEMORY,MEMORY
      ERROR: Ctrl-C while processing interval - removing it.
      Execution Interrupted during event processing.
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      New interpreter error:
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      >
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      Execution Interrupted
      

      The errors happened just when calling process.memory()

    Any ideas someone?
    I'll remove the logging into RAM completely now and see if that helps.

  • Having started a new test and just pressing buttons very quickly gives me this:

    Running onInit()...
    WARNING: jsble_exec_pending: Unknown enum type 216
    36 12 3
    WARNING: jsble_exec_pending: Unknown enum type 56
    7 89 80
    WARNING: jsble_exec_pending: Unknown enum type 56
    19 89 80
    WARNING: jsble_exec_pending: Unknown enum type 56
    11 62 53
    WARNING: jsble_exec_pending: Unknown enum type 120
    0 22 13
    New interpreter error: FIFO_FULL
    WARNING: jsble_exec_pending: Unknown enum type 152
    10 61 52
    WARNING: jsble_exec_pending: Unknown enum type 56
    2 177 168
    

    But everything seems to keep working after that. Nothing got stuck.
    What is this about?

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

Cycle race track lap counter

Posted by Avatar for ChristianW @ChristianW

Actions