Datafield Causing Edge 830 to Crash while Booting

I've been developing a DataField and testing it in the simulator and on my Edge 830. After some minor changes to my code and loading it onto my Edge yesterday, the device got stuck in a loop where it would crash while booting and then restart... only to crash a few seconds later in a forever repeating cycle.  After much fiddling with button presses I eventually got to a diagnostics screen and after that it booted up with factory defaults - I had to reconfigure all settings, profiles, sensors, connections etc.  

After some experimentation I found the issue seems to be related to my code size/usage - see below:

* First I removed a section of source code (lets call it Block A) and the Datafield loaded and worked.

* Then I replaced Block A, but removed a different section (Block B), and again it worked fine.

* Then I replaced Block B and it crashed.

* I then updated the SDK from 3.1.4 to 3.1.5, but the Datafield still crashed

I had thought I was comfortably below the device limits, according to the Simulator:

    Memory Usage: 32.2/124.6kB

    Peak Memory: 35.2kB

    Object Usage: 40/65535

    Peak Objects: 61

Please try help me figure this out

1. Is the above Memory usage info in the Simulator a reliable/accurate check?  Is there a bug in the system or am I missing something?

2. If the repeating crash cycle occurs, how should it be stopped? (What button press sequence)

3. Is it possible to recover from the above without reverting to factory defaults, or to save/restore a configuration?

I am quite new to Connect IQ development so apologies if it's something obvious, but any help would be much appreciated.

Thanks

Mark

  • Do you have a background process in the DF?  Normally it won't be loaded until you start and activity.

    As far as recovery, you should have been able to just plug it into to a PC and delete the .prg if that was the cause.

  • Thanks, I think the answer to background process is no, but I do have the following code:

    using Toybox.WatchUi;
    using Toybox.Application;
    using Toybox.Graphics;
    
    class Background extends WatchUi.Drawable {
    
        hidden var mColor;
    
        function initialize() {
            var dictionary = {
                :identifier => "Background"
            };
    
            Drawable.initialize(dictionary);
        }
    
        function setColor(color) {
            mColor = color;
        }
    
        function draw(dc) {
            dc.setColor(Graphics.COLOR_TRANSPARENT, mColor);
            dc.clear();
        }
    
    }
    

    Note that both blocks of code that I could remove to prevent the crash are in my DF view's onUpdate(dc) function.

    With regards recovery, I tried plugging my Edge 830 into a PC but it continued to repeatedly reboot itself and I was unable to access the file system from the PC and so was unable to delete .prg file.  At first I thought I'd bricked my device and it was only after experimenting with extended button presses that I somehow got it to factory defaults.

  • Former Member
    Former Member in reply to Mark

    that bit of code is standard in all datafields (it's literally the screen background) and isn't the background process jim was asking about.  

    lets see your onupdate code then.   using too much memory (and most / all errors i've seen) usually just blows up the datafield itself but your garmin will still boot fine.  you'll see an IQ! instead.

  • Thanks

    Yes, I've dealt with IQ! errors before but this is *way* different as it practically bricks my Edge! I could probably refactor my code to get it working but I want to understand what's going on and how to gauge how close I am to maxing out the resources a target device.  I'm concerned I might end up deploying something which simulates fine like this did but then causes such issues on a user's device!

    From my testing and looking at the symptoms it really does seem to be caused by my code getting too large. But from my understanding of the simulator's memory usage reporting I should be fine and have loads of headroom? 

    I'm not posting my full unUpdate() code at this stage - there's a lot of it, it's messy and overdue for tidy up. It's really just loads of text output and drawing code. Below is one of the blocks of code mentioned in my original post (the other block is not that different to this). Note that by removing either of these blocks, my DF works fine. 

        HR_TOP = globalGearsVisible ? 184 : 207; 
        var bar2_cur;
        var bar2_avg;
        var bar2_max;
        var bar2_avg2;		
        var bar2_colour;
        
        if(show_cadenceBar) {
            bar2_cur = info.currentCadence;
            bar2_avg = info.averageCadence;
            bar2_max = info.maxCadence;
            bar2_avg2 = CadenceAccumulator/8;
            bar2_colour = colGrn;        
        } else {
            bar2_cur = info.currentHeartRate;
            bar2_avg = info.averageHeartRate;
            bar2_max = info.maxHeartRate;
            bar2_avg2 = HeartAccumulator/64;
            bar2_colour = colRed;        
        }
                
        var bpmCurHpos = bar2_cur != null ? (dc.getWidth() * bar2_cur/200) : 0;		
        if(bpmCurHpos > dc.getWidth()) {
        	bpmCurHpos = dc.getWidth();
        }
        var bpmAvgHpos = bar2_avg != null ? (dc.getWidth() * bar2_avg/200) : 0;		
        if(bpmAvgHpos > dc.getWidth()) {
        	bpmAvgHpos = dc.getWidth();
        }
        var bpm_avg2Hpos = (dc.getWidth() * bar2_avg2/200);							
        if(bpm_avg2Hpos > dc.getWidth()) {
        	bpm_avg2Hpos = dc.getWidth();
        }
    
        if(show_heartCtlr & 4) {		
    	    dc.setColor(bar2_colour, Graphics.COLOR_BLACK);	
    	    var pen_widths = [1, 2, 4, 8];
    	    var bar_width = pen_widths[show_heartCtlr & 3];
    	    dc.setPenWidth(bar_width);
            for(var i=0;i<246;i+=bar_width) {
            	var y = show_cadenceBar ?  histCadence[(histCadenceIdx-i/bar_width-1)&0xFF]/140.0f :		
            	                          (histHeart[(histHeartIdx-i/bar_width-1)&0xFF]-100.0f)/100.0f;		
            	if(y > 0) {
            		if (y > 1) { y = 1;	}
    		        dc.drawLine(246-i-bar_width/2, HR_TOP+PWR_HEIGHT-bar_width/2, 246-i-bar_width/2, HR_TOP+PWR_HEIGHT-y*PWR_HEIGHT+bar_width/2);
            	}
    	    }
    	    dc.setPenWidth(1);
    	    if(show_heartCtlr & 8) {		
    		    dc.setColor(colDraw, Graphics.COLOR_BLACK);	
    	        dc.drawLine(0, HR_TOP, 246, HR_TOP);
    	        dc.drawLine(0, HR_TOP+PWR_HEIGHT, 246, HR_TOP+PWR_HEIGHT);
    		}
        } else {	    
            if(info.averageHeartRate != null) {	    	    
    	        DrawDownTriangle(dc, bpmAvgHpos, HR_TOP-1, 8);
    	        DrawUpTriangle(dc, bpmAvgHpos, HR_TOP+PWR_HEIGHT+1, 8);
    	    }
    	    dc.setColor(bar2_colour, Graphics.COLOR_BLACK);							
    	    dc.fillRectangle(0, HR_TOP+PWR_LW, bpmCurHpos, PWR_HEIGHT-2*PWR_LW);
    	    dc.setColor(colBar, Graphics.COLOR_BLACK);							
    	    dc.fillRectangle(bpmCurHpos, HR_TOP+PWR_LW, dc.getWidth()-bpmCurHpos, PWR_HEIGHT-2*PWR_LW);
    	    dc.setColor(getBackgroundColor(), getBackgroundColor());
    	    dc.setColor(show_cadenceBar ? Graphics.COLOR_GREEN : Graphics.COLOR_RED, getBackgroundColor());
    	    dc.setPenWidth(PWR_LW);
    	    dc.drawLine(0, HR_TOP+PWR_LW/2, bpm_avg2Hpos, HR_TOP+PWR_LW/2);									
    	    dc.drawLine(0, HR_TOP+PWR_HEIGHT-(PWR_LW+1)/2, bpm_avg2Hpos, HR_TOP+PWR_HEIGHT-(PWR_LW+1)/2);	 	    	    	    
    	    dc.setPenWidth(1);
    	    dc.setColor(getBackgroundColor(), getBackgroundColor());
    	    dc.drawLine(bpmCurHpos, HR_TOP+PWR_LW, bpmCurHpos, HR_TOP+PWR_HEIGHT-PWR_LW);		
        }
        
        dc.setColor(colDraw, Graphics.COLOR_TRANSPARENT );
        dc.drawText(95,  HR_TOP+PWR_HEIGHT/2-dc.getFontHeight(Graphics.FONT_NUMBER_MEDIUM)/2+5,  Graphics.FONT_NUMBER_MEDIUM, bar2_cur != null ? bar2_cur.format("%d") : "-", Graphics.TEXT_JUSTIFY_RIGHT);
        dc.drawText(100, HR_TOP+PWR_HEIGHT/2-dc.getFontHeight(Graphics.FONT_NUMBER_MEDIUM)/2+13, Graphics.FONT_SYSTEM_MEDIUM, (show_cadenceBar ? "r" : "b") + "pm", Graphics.TEXT_JUSTIFY_LEFT);
    
        if((bar2_avg != null) && (bar2_max != null)) {
            switch(show_heartCtlr & 3)
            {
            	case 1 :
    		        dc.drawText(dc.getWidth()-4, HR_TOP+PWR_LW-4,  Graphics.FONT_SYSTEM_TINY, "Avg", Graphics.TEXT_JUSTIFY_RIGHT);
    		        dc.drawText(dc.getWidth()-4, HR_TOP+PWR_HEIGHT-PWR_LW-30, Graphics.FONT_NUMBER_MILD, bar2_avg.format("%d"), Graphics.TEXT_JUSTIFY_RIGHT);
    		        break;
            	case 2 :
    		        dc.drawText(dc.getWidth()-4, HR_TOP+PWR_LW-4,  Graphics.FONT_SYSTEM_TINY, "Max", Graphics.TEXT_JUSTIFY_RIGHT);
    		        dc.drawText(dc.getWidth()-4, HR_TOP+PWR_HEIGHT-PWR_LW-30, Graphics.FONT_NUMBER_MILD, bar2_max.format("%d"), Graphics.TEXT_JUSTIFY_RIGHT);
    		        break;
            	case 3 :
    		        dc.drawText(224, HR_TOP-1,  Graphics.FONT_SYSTEM_MEDIUM, bar2_avg.format("%d"), Graphics.TEXT_JUSTIFY_RIGHT);
    		        dc.drawText(224, HR_TOP+PWR_HEIGHT-PWR_LW-23, Graphics.FONT_SYSTEM_MEDIUM, bar2_max.format("%d"), Graphics.TEXT_JUSTIFY_RIGHT);
    		        break;
    		}
            dc.setColor(colDraw, Graphics.COLOR_TRANSPARENT );
    
            if ((show_heartCtlr & 3)==3) { DrawAvgSymbol(dc, 235, HR_TOP+PWR_LW+9, 5); }
            if ((show_heartCtlr & 3)==3) { DrawMaxSymbol(dc, 235, HR_TOP+PWR_HEIGHT-PWR_LW-12, 6); }
    	}
    

  • Former Member
    Former Member in reply to Mark

    have you looked in the ciq_log.yml file yet to see if there are any clues in there?  it's on your garmin in garmin/app/logs.

    also try removing the datafield from your activity screens (which it should be now that you had to do the factory reset), put the prg on the garmin, then boot and see what happens with it not being on any datascreen.   then add it to a datascreen and see what happens then.  does it immediately crash?

    in my experience, the simulator will run out of memory before the actual garmin does.  (ie, when you show multiple datafields the memory jumps up a bit, but on your garmin you'll only be running it in one position)  so that seems unlikely.

  • Thanks and for your input. It turns out that the entire app was being loaded as a background process and I was just exceeding the smaller 32kB background heap when I included both of those code blocks.  I had ticked the box in the Manifest settings unnecessarily. The following build warning helped me figure it out, but only after the input from this thread and reading up on background processes:

    BUILD: WARNING: edge830: The background permission was enabled but no source code was annotated. The entire application will be loaded as a background process. (background application)

    I changed my Manifest settings by un-checking the 'Background' permission box and it now runs fine on my Edge. 

    It does appear there is a bug in the simulator where it doesn't reflect the reduced heap space when simulating background processes/applications.

  • Yes, there's a bug report related to this.  With a a larger app with the background permission set but no code annotated for the background, you see two warnings in the sim when you start the app, as it tried to run the whole app as a background app.

    In general you only want to set the permissions you need, or the user must ok things when downloading from the store.