Complete
over 4 years ago

WERETECH-11147

Fixed

The burn-in protection on Venu2(s) devices with CIQ4 falsely triggers and turns off the display

I have ported several watch faces with Venu1 AOD support to the Venu2 and Venu2s devices.

My AOD modes are straight forward. I'm using a dense pattern clearing every 2nd pixel row or column on the screen alternating each minute starting with the first row/column or the second row/column.

This ensures that less than 10% of the pixels are on and no particular pixel is on for more than 1 minute.

On the Venu2 the simulator detects a screen burn-in. On the Screen Burn-In Simulation window it looks like the overlay pattern is ignored.

Also some drawing artifacts are missing on the burn-in screen for example the minute and hour hands.

I'm in contact with 2 other developers who have similar problems with at least some of their watch faces.

I already uploaded my watch faces with Venu2 support to the Connect IQ store and received feedback from a user who also owns a Venu1 that

the AOD is not working on his new Venu2. - It turns off the screen.

So this is potentially not only a problem of the simulator but also of the actual device.

Here is a screen recording of the problem in action highlighting the differences between Venu1 and Venu2:

https://drive.google.com/file/d/123bDerdGzCovWEcJlxonKbRBSo96lqrq/view?usp=drivesdk

Parents
  • Ok, to make this easier.

    I have generated a test project that displays the issue fully. For venu, venud, venusq, venusqm it works perfectly. For venu2, venu2s, smallwearable2021 and wearable2021 I see a burn in error as soon as I toggle power mode.

    I cannot either attach files or insert formatted code, so here is the view class in raw text:

    /////////////////////////////////////

    import Toybox.Graphics;
    import Toybox.Lang;
    import Toybox.System;
    import Toybox.WatchUi;

    class LabReqBurninView extends WatchUi.WatchFace {
        var lowPower;
        var requiresBurnInProtection;
        var burnInClockRadius;
        var burnInDegrees;
        var burnInR;
        var burnInFont;

        function initialize() {
            WatchFace.initialize();
            lowPower = false;
        }

        // Load your resources here
        function onLayout(dc as Dc) as Void {
            setLayout(Rez.Layouts.WatchFace(dc));
            var sets = System.getDeviceSettings();
            requiresBurnInProtection = sets has :requiresBurnInProtection ? sets.requiresBurnInProtection : false;
            burnInDegrees = 0.0;
            burnInFont = Graphics.FONT_NUMBER_MEDIUM;
            burnInClockRadius = dc.getWidth() * 44 / 200;
            burnInR = dc.getWidth() / 2 - burnInClockRadius; 
        }

        // Called when this View is brought to the foreground. Restore
        // the state of this View and prepare it to be shown. This includes
        // loading resources into memory.
        function onShow() as Void {
        }

        // Update the view
        function onUpdate(dc as Dc) as Void {
            // SET BLACKSCREEN
            dc.setColor(Graphics.COLOR_WHITE,Graphics.COLOR_BLACK);
            dc.clear();
            var clockTime = System.getClockTime();
            var hour = clockTime.hour;
            if(!System.getDeviceSettings().is24Hour) {  
                hour %= 12;
                if(hour == 0) {         hour = 12;          }
            }
            if(lowPower) {
                burnInDegrees += 52;
                var rads = burnInDegrees * Math.PI / 180;
                var str = hour.format("%02d") + ":\n" + clockTime.min.format("%02d");
                var posx = dc.getWidth()/2+Math.cos(rads)*burnInR;
                var posy = dc.getHeight()/2+Math.sin(rads)*burnInR;
                dc.drawText(posx,posy,burnInFont,str,Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
            } else {
                // Get and show the current time
                // Fill the screen with stuff...
                dc.setColor(Graphics.COLOR_RED,Graphics.COLOR_WHITE);
                var val=dc.getWidth(),pos=val/2,lim=val/3;
                for(var x=0;x<lim;x+=3,val-=6) {
                    dc.drawRectangle(x, x, val, val);
                    dc.drawCircle(pos, pos, val/2);
                }
                dc.setColor(Graphics.COLOR_WHITE,Graphics.COLOR_BLACK);
                var tstr = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min.format("%02d")]);
                dc.drawText(pos, pos, Graphics.FONT_NUMBER_THAI_HOT, tstr, Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
            }
        }
        // Called when this View is removed from the screen. Save the
        // state of this View here. This includes freeing resources from
        // memory.
        function onHide() as Void {
        }

        // The user has just looked at their watch. Timers and animations may be started here.
        function onExitSleep() as Void {
           System.println("LOW POWER EXIT");
           lowPower = false;
        }

        // Terminate any active timers and prepare for slow updates.
        function onEnterSleep() as Void {
           System.println("LOW POWER DETECTED");
           lowPower = true;
        }

    }
    //////////////////////////
Comment
  • Ok, to make this easier.

    I have generated a test project that displays the issue fully. For venu, venud, venusq, venusqm it works perfectly. For venu2, venu2s, smallwearable2021 and wearable2021 I see a burn in error as soon as I toggle power mode.

    I cannot either attach files or insert formatted code, so here is the view class in raw text:

    /////////////////////////////////////

    import Toybox.Graphics;
    import Toybox.Lang;
    import Toybox.System;
    import Toybox.WatchUi;

    class LabReqBurninView extends WatchUi.WatchFace {
        var lowPower;
        var requiresBurnInProtection;
        var burnInClockRadius;
        var burnInDegrees;
        var burnInR;
        var burnInFont;

        function initialize() {
            WatchFace.initialize();
            lowPower = false;
        }

        // Load your resources here
        function onLayout(dc as Dc) as Void {
            setLayout(Rez.Layouts.WatchFace(dc));
            var sets = System.getDeviceSettings();
            requiresBurnInProtection = sets has :requiresBurnInProtection ? sets.requiresBurnInProtection : false;
            burnInDegrees = 0.0;
            burnInFont = Graphics.FONT_NUMBER_MEDIUM;
            burnInClockRadius = dc.getWidth() * 44 / 200;
            burnInR = dc.getWidth() / 2 - burnInClockRadius; 
        }

        // Called when this View is brought to the foreground. Restore
        // the state of this View and prepare it to be shown. This includes
        // loading resources into memory.
        function onShow() as Void {
        }

        // Update the view
        function onUpdate(dc as Dc) as Void {
            // SET BLACKSCREEN
            dc.setColor(Graphics.COLOR_WHITE,Graphics.COLOR_BLACK);
            dc.clear();
            var clockTime = System.getClockTime();
            var hour = clockTime.hour;
            if(!System.getDeviceSettings().is24Hour) {  
                hour %= 12;
                if(hour == 0) {         hour = 12;          }
            }
            if(lowPower) {
                burnInDegrees += 52;
                var rads = burnInDegrees * Math.PI / 180;
                var str = hour.format("%02d") + ":\n" + clockTime.min.format("%02d");
                var posx = dc.getWidth()/2+Math.cos(rads)*burnInR;
                var posy = dc.getHeight()/2+Math.sin(rads)*burnInR;
                dc.drawText(posx,posy,burnInFont,str,Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
            } else {
                // Get and show the current time
                // Fill the screen with stuff...
                dc.setColor(Graphics.COLOR_RED,Graphics.COLOR_WHITE);
                var val=dc.getWidth(),pos=val/2,lim=val/3;
                for(var x=0;x<lim;x+=3,val-=6) {
                    dc.drawRectangle(x, x, val, val);
                    dc.drawCircle(pos, pos, val/2);
                }
                dc.setColor(Graphics.COLOR_WHITE,Graphics.COLOR_BLACK);
                var tstr = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min.format("%02d")]);
                dc.drawText(pos, pos, Graphics.FONT_NUMBER_THAI_HOT, tstr, Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
            }
        }
        // Called when this View is removed from the screen. Save the
        // state of this View here. This includes freeing resources from
        // memory.
        function onHide() as Void {
        }

        // The user has just looked at their watch. Timers and animations may be started here.
        function onExitSleep() as Void {
           System.println("LOW POWER EXIT");
           lowPower = false;
        }

        // Terminate any active timers and prepare for slow updates.
        function onEnterSleep() as Void {
           System.println("LOW POWER DETECTED");
           lowPower = true;
        }

    }
    //////////////////////////
Children
  • Change 

    dc.setColor(Graphics.COLOR_WHITE,Graphics.COLOR_BLACK);

    to

    dc.setColor(Graphics.COLOR_BLACK,Graphics.COLOR_BLACK);

    Does it then work?

    You'll need to add something like:

    dc.setColor(Graphics.COLOR_WHITE,Graphics.COLOR_TRANSPARENT);

    before the draw text