Disable slack overflow in the simulator?

Hello all Wave tone1,

I am working on a mock, acting as a `Toybox.BluetoothLowEnergy` replacement.

It thus have to print the command sent, as well as triggering the correct delegate with the correct value...

But I always get a 'Stack Overflow Error', has the number of functions on the stack can be quite larger than the 8 (from memory) the physical stack can handle.

My question is then the following:

Is there a way to run the simulator so that the 'Stack Overflow Error' is ignored?

Thank you!

++GG

ps: I am not using any testing feature. Should I?

  • Another option would be to rewrite their code so it has fewer levels of recursion / nested function calls, but:

    - I don't know the details of their code

    - I assume that if it were simple to do so, it would have already been done

    Not sure how well it would fit with a stack overflow

    The concept is pretty simple. Hopefully I'm not missing something obvious.

    For the sake of a small example, say the stack is small enough that going more than 4 functions deep causes a stack overflow. Again for the sake of simplicity, say I want to run my own chain of functions A()  > B() > C() > D() in response to onTimerLap() in a data field, and for some reason it's not feasible rewrite this code to avoid recursion / nesting.

    Here's the initial approach, where onTimerLap() calls A(), which calls B(), etc:

    onTimerLap() > A() > B() > C() > D() [stack overflow]

    This crashes on the call to D() to due to a stack overflow.

    Now let's say I rewrite that to use a timer.

    onTimerLap() > A() > B() > [set Timer T to schedule C() in 0 or 1 ms]

    [T expires]: C() > D()

    I think this avoids a stack overflow because C() runs in a different context than B(), since B() doesn't directly call C() in this case.

    I think the only questions are:

    - whether you pick and choose which functions to launch with a timer or whether you just use the timer to launch *everything*

    - whether there's anything that actually needs to be truly synchronous in response to whatever events OP is interested in (in this case, BLE messages). Obviously if some action needs to take place synchronously, then this approach won't be helpful

  • 50ms is the min timer (so 0 or 1ms isn't possible), and no timers in DFs (onTimerLap() is for DFs only)

    The basic issue here for me, is that BLE in CIQ is already async by nature.  Do something, and when done, there's a callback.  I do use a timer to handle the display update and handle things like no onConnectedStateChanged() callback X seconds a paring was attempted.

  • Ok, I think I pinpointed why we're keeping arguing!

    When I talk about a device, it is not a watch or bikecomp, but the device produced by our client.

    So the cost is closer to a thousand bucks than 10$ (~400$ for the watch + ~10$ for the dongle + ~500$ for the device).

    Also, our team being remote and the members being located on opposite side of the country does make sharing the setup quite a spicy endeavour!

  • 50ms is the min timer (so 0 or 1ms isn't possible)

    Good point.

    and no timers in DFs (onTimerLap() is for DFs only)

    Sorry, it was just meant to be a toy example (I picked a bad one)

    The basic issue here for me, is that BLE in CIQ is already async by nature. 

    That's why I said I don't know the details of OP's code and why it causes a stack overflow.

  • You can try to use invoking of method, maybe system treats it other way.

  • Simulating a stack overflow is pretty easy if you try to use recursion.  Here's an ultra simple app that will do that, and shows how a timer can be used to prevent it.  Use the || true as part of the if on line 20 to cause the stack overflow.  Otherwise, every 5 calls it gives up control to the timer. (I make the timer 5 sec so you can see what's happening

    import Toybox.Graphics;
    import Toybox.WatchUi;
    
    class recurseView extends WatchUi.View {
    	var timer;
    	var next;
    	
        function initialize() {
            View.initialize();
    		timer= new Timer.Timer();
    		recurse(1);
        }
        
        function onTimer()  {
        	recurse(next);
        }
        
        function recurse(a) {
        	System.println("now="+a);
        	if(a%5!=0) {	// || true) {
        		recurse(a+1);
        	} else {
        		next=a+1;
        		timer.start( method(:onTimer), 5000, false);
        	} 
        }	
    
    }
    

    But this all gets back to what you are trying to do.  Using CIQ to simulate a CIQ app talking to a BLE sensor, with no connection to the sensor and no data from the sensor.  I don't understand how this helps.  Isn't this just something you could do in something like Python and not even involve CIQ?

  • Simulating a stack overflow is pretty easy if you try to use recursion.  Here's an ultra simple app that will do that, and shows how a timer can be used to prevent it.

    I thought you just said that the concept of using a timer to avoid a stack overflow would not be helpful?????? Your example is literally what I suggested in the first place.

    Using a Timer to split things up would make more sense if you had issues with the Watchdog Timer.  Not sure how well it would fit with a stack overflow

    I guess what you really meant to say was you didn't understand why there's so much recursion / so many nested function calls in the first place, which is exactly what I said.

    I don't understand how this helps. 

    It helps if they have no other way of avoiding a stack overflow, assuming that they are intent on doing things in a certain way. The question of whether what they're doing in the first place is the right thing to do is a separate question from "how do i avoid a stack overflow".

  • It's much more complex to do in an app that's more involved and not a single recursive function.

    I would look at the root case and fix my code before I used a timer, but wanted to show a real example of how it could be done.

  • The stack overflow looks like a symptom of something deeper.  I still can't see why CIQ is even involved, and might not even be an issue in something like python.

  • It's much more complex to do in an app that's more involved and not a single recursive function.

    I would look at the root case and fix my code before I used a timer, but wanted to show a real example of how it could be done.

    I agree on all points, but:

    1) keep in mind this is only for testing

    2) I too questioned whether the OP's code *needs* to be nested so deeply it causes a stack overflow

    3) I suggested this workaround, and you basically said "what a dumb idea - so unhelpful", then you went ahead and provided an example. I find that pretty hilarious tbh.