AsteroidOS / asteroid

Build script for AsteroidOS, an open-source operating system for smartwatches
http://asteroidos.org
GNU General Public License v2.0
883 stars 64 forks source link

Always on display #58

Closed Doomsdayrs closed 4 years ago

Doomsdayrs commented 6 years ago

I always have found it to be a great tool when using the watch, simply looking at it for the time instead of having to turn it on with a button. And i find it would be a great addition to the watch itself.

That's just an idea i had for the sw3.

FlorentRevest commented 6 years ago

Thanks for your suggestion @Doomsdayrs, I edited the name of your issue to be more generic (there is no reason why always on display should only work on the SW3). There is no plan for this as of today because it is a very complex problem that would require a lot of work but I let your issue open to keep track of it.

Doomsdayrs commented 6 years ago

@FlorentRevest Understood, lots of people can benefit from it if it ever happens 😄

532910 commented 6 years ago

I'm also would like this feature!

Really when I tried AsteroidOS with dory it was possible to say some command (I don't remember it) on the clock to prevent display turn off. But IPS backlight eats battery so I sell them.

FlorentRevest commented 6 years ago

You can use: mcetool -D on to enable "demo mode" that will keep the screen on with full brightness. But your CPU won't enter deep sleep mode and the battery will be emptied very quickly. An actually efficient "always on screen" mode would require much more work and deeper integration to various system components.

532910 commented 6 years ago

Exactly! But, a. I'm absolutely sure I was able to set minimal brightness after "mcetool -D on" b. Are you sure if it's possible to deep sleep and update the screen every second? c. Fuck fuel economy! The only way I can use the watch is when display is always on and shows actually seconds. (Otherwise it's just a garbage on my wrist.) Dory with not new battery was enough for about 8-12 hours, But as I understand the main load was an IPS white LED emitter, not CPU. I'd like to test some wathc with OLED screen but don't know which one to choose. The enough operating time between battery charge is 24 hours for me.

FlorentRevest commented 6 years ago

a) Yes you can b) It is technically possible (android wear does it) but very complex in practice. Again, it requires a major architectural overhaul that is not in sight for the near future. c) I don't think an OLED screen with asteroid in demo mode, without the CPU entering deep sleep (and kernel putting various buses/devices at sleep as well) can get you 24 hours of battery life, but feel free to experiment.

532910 commented 6 years ago

Could you suggest me the watch with OLED?

FlorentRevest commented 6 years ago

I'm afraid I am clueless about that.

eLtMosen commented 6 years ago

Lenok (lg watch r) and bass (lg watch urbane) both have P-OLED displays, became cheap and are nicely supported!

Rudloff commented 6 years ago

Having this (even a rough version) would be useful on watches that don't support vibration (yet) since it would allow to see more easily if there is a new notification.

Doomsdayrs commented 6 years ago

The SW3 has a tft display if i am not incorrect

violoncelloCH commented 6 years ago

I would also like an always on display mode. only showing the watchface without the background would be extremely useful for watches with OLED screens

faeinthebay commented 6 years ago

@Doomsdayrs the Smartwatch 3 has a transflective display, which is notable because it doesn't need backlight for greyscale images. The Smartwatch 3 may have panel self-refresh which would explain how to have good battery life for always-on mode. If so, the challenge may be figuring out the commands to the display driver IC.

FlorentRevest commented 6 years ago

Creating a 'tetra'-specific mechanism for always on display isn't a viable solution. We'd probably need to find the API that wearOS uses to abstract this transflective display's capabilities instead.

NeonHorizon commented 6 years ago

Just tried Asteroid on my Zenwatch 3 and I love it, its so smooth and responsive and looks fantastic, great work guys! Apologies for the "me too" post but I too would really like to see an always on, I always thought it was one of Android Wears killer features compared to the competition, would be great to see it on Asteroid.

eLtMosen commented 6 years ago

I looked into the matter and reflashed a lenok to stock wearOS. When you do top via adb shell it is kind of obvious that the process com.google.android.wearable.ambient only is doing work when the watch is showing the always-on-screen. Further search brought me to https://developer.android.com/training/wearables/apps/always-on were the usage of AmbientModeSupport is explained. How exactly the low-power ambient mode works is not explained, maybe someone else will pick on from here and can find more sources now that we have a name for the thing. I have the strong feeling that it is more simple than we imagined. All the talk is just about oled displays turing off black pixels. So use much black and update only every minute and you have your low-power mode on oled? Can't be that simple, can it? How to find out what com.google.android.wearable.ambient actually does?

kmccurley commented 5 years ago

As far as I'm concerned this is reason enough to put my watch back in a box. Or just send it to electronic waste. A watch that doesn't tell you the time when you just look at it is a 40 year regression - not exactly what I would call advanced technology.

Doomsdayrs commented 5 years ago

Indeed, it's sad that there hasn't been much referenced development on this @kmccurley

MagneFire commented 4 years ago

I've got the display to stay on while letting the soc got to deep-sleep mode! Currently it's very experimental, but at least there is some progress :) To get it to work changes are needed for mce(https://github.com/MagneFire/mce/commits/master), ~lipstick(https://github.com/MagneFire/lipstick/commits/master)~ and qt5-qpa-hwcomposer-plugin(https://github.com/MagneFire/qt5-qpa-hwcomposer-plugin/commits/master).

I did look into the decompiled code from ClockworkAmbient. But didn't find anything special. Main things that I noticed from the code are:

Initially I thought that the mce tool was a great starting point to look into, since it is responsible for screen brightness and screen on/off stuff. mce uses a state machine to control the display. This is the main thing to look at(https://github.com/MagneFire/mce/blob/master/modules/display.c#L7559). At some point it fades the screen to black(STM_WAIT_FADE_TO_BLACK) and turns off the display(mce_fbdev_set_power).

mce sends a D-Bus command to lipstick (the compositor) (setUpdatesEnabled() function) which sends a command to the Qt5 backend to turn off the display. The Qt5 backend uses the libhybris backend to control the display(libhybris uses the hwcomposer module for this). the sleepDisplay function is used to turn off the display. All we need to do is change the HWC_POWER_MODE_OFF to HWC_POWER_MODE_DOZE_SUSPEND(https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware/hwcomposer_defs.h#299) to keep the screen awak while letting the system enter deep sleep.

This is all just a very minimal way to get it to work. Current issues are:

Currently I am using the LPM feature of mce to lower the brightness before entering deep-sleep. This may or may not be the best solution.

I've tested this for about 4 hours now and the battery drained about 3% with Bluetooth disabled and manually waking the screen every hour.

Relevant part of the kernel panic

``` May 15 05:55:55 sturgeon kernel: mdss_dsi_off: Panel power off failed May 15 05:55:55 sturgeon kernel: ------------[ cut here ]------------ May 15 05:55:55 sturgeon kernel: WARNING: at drivers/video/msm/mdss/mdss_mdp_intf_cmd.c:990 mdss_mdp_cmd_stop+0x374/0x444() May 15 05:55:55 sturgeon kernel: intf 2 unblank error (-598599664) May 15 05:55:55 sturgeon kernel: CPU: 0 PID: 33 Comm: kworker/u8:1 Tainted: G W 3.10.40 #1 May 15 05:55:55 sturgeon kernel: Workqueue: autosleep try_to_suspend May 15 05:55:55 sturgeon kernel: Backtrace: May 15 05:55:55 sturgeon kernel: [] (dump_backtrace+0x0/0x104) from [] (show_stack+0x18/0x1c) May 15 05:55:55 sturgeon kernel: r7:000003de r6:c0bf5f91 r5:00000009 r4:dd5e3b50 May 15 05:55:55 sturgeon kernel: [] (show_stack+0x0/0x1c) from [] (dump_stack+0x20/0x28) May 15 05:55:55 sturgeon kernel: [] (dump_stack+0x0/0x28) from [] (warn_slowpath_common+0x50/0x70) May 15 05:55:55 sturgeon kernel: [] (warn_slowpath_common+0x0/0x70) from [] (warn_slowpath_fmt+0x38/0x40) May 15 05:55:55 sturgeon kernel: r9:00000003 r8:c0f3b1d4 r7:c0ea4230 r6:00000001 r5:dc521810 r4:dc520810 May 15 05:55:55 sturgeon kernel: [] (warn_slowpath_fmt+0x0/0x40) from [] (mdss_mdp_cmd_stop+0x374/0x444) May 15 05:55:55 sturgeon kernel: r3:00000002 r2:c0bf5f75 May 15 05:55:55 sturgeon kernel: [] (mdss_mdp_cmd_stop+0x0/0x444) from [] (mdss_mdp_ctl_stop+0xf0/0x398) May 15 05:55:55 sturgeon kernel: [] (mdss_mdp_ctl_stop+0x0/0x398) from [] (mdss_mdp_overlay_off+0xb8/0x334) May 15 05:55:55 sturgeon kernel: [] (mdss_mdp_overlay_off+0x0/0x334) from [] (mdss_fb_blank_blank+0x12c/0x1a4) May 15 05:55:55 sturgeon kernel: r9:00000002 r8:00000001 r7:dc4e83ac r6:dc4e8344 r5:00000003 r4:dc4e8270 May 15 05:55:55 sturgeon kernel: [] (mdss_fb_blank_blank+0x0/0x1a4) from [] (mdss_fb_blank_sub.isra.10+0x184/0x280) May 15 05:55:55 sturgeon kernel: r8:00000000 r7:dc56f044 r6:00000001 r5:c0ea61f8 r4:dc4e8270 May 15 05:55:55 sturgeon kernel: [] (mdss_fb_blank_sub.isra.10+0x0/0x280) from [] (mdss_fb_suspend_sub+0xc0/0x10c) May 15 05:55:55 sturgeon kernel: r7:dc56f044 r6:c0fb9764 r5:00000000 r4:dc4e8270 May 15 05:55:55 sturgeon kernel: [] (mdss_fb_suspend_sub+0x0/0x10c) from [] (mdss_fb_pm_suspend+0x48/0x5c) May 15 05:55:55 sturgeon kernel: r7:dc56f044 r6:c0fb9764 r5:dc56f010 r4:dc4e8270 May 15 05:55:55 sturgeon kernel: [] (mdss_fb_pm_suspend+0x0/0x5c) from [] (platform_pm_suspend+0x34/0x6c) May 15 05:55:55 sturgeon kernel: r5:c04634ac r4:dc56f010 May 15 05:55:55 sturgeon kernel: [] (platform_pm_suspend+0x0/0x6c) from [] (dpm_run_callback+0x34/0x54) May 15 05:55:55 sturgeon kernel: [] (dpm_run_callback+0x0/0x54) from [] (__device_suspend+0x12c/0x294) May 15 05:55:55 sturgeon kernel: r5:00000002 r4:dc56f010 May 15 05:55:55 sturgeon kernel: [] (__device_suspend+0x0/0x294) from [] (dpm_suspend+0x16c/0x1ec) May 15 05:55:55 sturgeon kernel: r9:00000002 r8:dc56f010 r7:c0e64ec8 r6:dc56f074 r5:00000000 r4:c0fb9764 May 15 05:55:55 sturgeon kernel: [] (dpm_suspend+0x0/0x1ec) from [] (dpm_suspend_start+0x58/0x60) May 15 05:55:55 sturgeon kernel: [] (dpm_suspend_start+0x0/0x60) from [] (suspend_devices_and_enter+0xb8/0x21c) May 15 05:55:55 sturgeon kernel: r5:00000000 r4:00000003 May 15 05:55:55 sturgeon kernel: [] (suspend_devices_and_enter+0x0/0x21c) from [] (pm_suspend+0x160/0x220) May 15 05:55:55 sturgeon kernel: r7:c0ea12a8 r6:00000003 r5:00000000 r4:c0fb9764 May 15 05:55:55 sturgeon kernel: [] (pm_suspend+0x0/0x220) from [] (try_to_suspend+0x88/0xcc) May 15 05:55:55 sturgeon kernel: r7:dd40e800 r6:c0e35b9c r5:dd5e2000 r4:dd5c0980 May 15 05:55:55 sturgeon kernel: [] (try_to_suspend+0x0/0xcc) from [] (process_one_work+0x278/0x3e8) May 15 05:55:55 sturgeon kernel: [] (process_one_work+0x0/0x3e8) from [] (worker_thread+0x1c0/0x338) May 15 05:55:55 sturgeon kernel: [] (worker_thread+0x0/0x338) from [] (kthread+0xa8/0xb4) May 15 05:55:55 sturgeon kernel: [] (kthread+0x0/0xb4) from [] (ret_from_fork+0x14/0x3c) May 15 05:55:55 sturgeon kernel: r7:00000000 r6:00000000 r5:c0144680 r4:dd483e68 May 15 05:55:55 sturgeon kernel: ---[ end trace 20bfc2e6814626d0 ]--- May 15 05:55:55 sturgeon kernel: mdss_mdp_ctl_stop: error powering off intf ctl=0 May 15 05:55:55 sturgeon kernel: active wakeup source: IDLE_ON_WAKELOCK May 15 05:55:55 sturgeon kernel: PM: Some devices failed to suspend ```

EDIT: lipstick doesn't actually require any change :) EDIT2: Turns out that you need to set the display mode to FB_BLANK_VSYNC_SUSPEND. This fixes the kernel panic and the touch-to-wake not working.

Doomsdayrs commented 4 years ago

After 2 years, we have a genius! Thank you @MagneFire

MagneFire commented 4 years ago

So I have got everything mostly working.

There is still a small bug where the time is one minute behind in ambient mode. This happens because the watch goes to sleep before the watchface has completed painting the Canvas'.

I propose the following to solve the issue:

And if the watchface does not obay the new API we get:

Finally, here is some relevant code that watchfaces can use:

Connections {
    target: Lipstick.compositor
    onDisplayAmbientEntered:
    onDisplayAmbientLeft:
    onDisplayAmbientUpdate:
}
Lipstick.compositor.displayAmbient // Is the display currently in ambient mode?
Lipstick.compositor.ambientEnabled

I have adjusted the following components:

Here is a simple diagram to show what I think the ideal flow should be. Ambient Mode Flow

Another small issue has something to do with timed. When I schedule a alarm event. A dbus signal is send to com.nokia.voland when the alarm fires. Which always starts the alarm-presenter from asteroid-alarmclock. Do you know if there is a proper way to filter clock events for asteroid-alarmclock with systemd? This would remove the need for any changes in timed.

Here is a short demo of it all in action: Demo

532910 commented 4 years ago

Is it usable with one second update (with second hand)?

MagneFire commented 4 years ago

Currently I have about 40~50% battery left at the end of the day. This is with a one minute update.

Of course it is be possible to change the update to something arbitrary, this will have a significant hit on the battery life though. I think your watch won't make it through the day then...

One thing you can do is disable tilt-to-wake, this will increase the battery life.

eLtMosen commented 4 years ago

Great work, fantastic! I think the burn-in offset between the minutely watchface placements needs to be even bigger. With heavy weight fonts i would guess it is necessary to offset by the width of the thickest element on screen to prevent the center most pixels of those elements/fonts to be always on?

Since i am slow, could you link to the stock watchface you ambienized already so i can see what is happening and learn from the example?

MagneFire commented 4 years ago

Thanks! :)

I agree on the changes for burn in. I am actually thinking that we may also want to desynchronize the watchface and wallpaper. And maybe add a dark filter for the watchface.

Ambient mode settings will then become something like:

I didn't ambienize any watchface. The demo shows behaviour without any change to the watchfaces. The idea is something I am thinking of implementing. What do you think of this idea? If it isn't really clear I can create a simple prototype for this.

EDIT: Now that I am thinking about it. Different watchfaces have a different usable area. So we may want to let the watchface decide how large burn in prevention area is. For a digital watchface the region can be a lot larger that it is now. But for an analog style watchface the current region might be enough.

eLtMosen commented 4 years ago

Understood! Much easier than i thought. My 2 cents

MagneFire commented 4 years ago

Thanks for your feedback!

I put together a quick demo of your feedback. What do you think of it?

Hide Wallpaper

kmccurley commented 4 years ago

There is always a balance between having too many options in the settings and providing adequate usability for every use case. I stopped using Asteroid because it wouldn't keep the time showing, but some people might think battery life is more important. This suggests to me that it should be controlled by at least one setting. Other settings like brightness in ambient mode might be deferred if there is a disagreement, but I think having some kind of ambient mode with the time displayed is a showstopper and I'm a big fan of this demo.

MagneFire commented 4 years ago

@kmccurley I guess the default will be what you see in the short demo. With the only setting you have to change is enabling ambient mode.

Ambient mode, obviously, consumes more batter power. For this reason alone, the default might be to have ambient mode disabled by default. Unless @FlorentRevest finds this a super important feature that should be enabled by default :wink:

All other options are considered advanced.

eLtMosen commented 4 years ago

Gorgeous @MagneFire ! I second @kmccurley when thinking about special user demands. +1 For the requested settings option to disable the AmbientMode. To overthink a little, i could see users want to end the AmbientMode only by certain actions. E.g. some users complained about "Too much wallpaper/color" and demanded a black wallpaper to be stock. (Which Kido did not grant to my relief) Setting:

EDIT, above could also be used on devices where eg. the button on my lenok is often pressed accidentally to rule it out from ending AmbientMode.

Philosophy wise, i would advise to keep the AmbientMode on for stock delivery

FlorentRevest commented 4 years ago

I am all-in for having AmbientMode enabled by default. This is what most users want, this is what should be set as default.

There should be an option to disable AmbientMode and come back to what we have right now (screen off) in asteroid-settings because it's still a setup that can make sense in some situations. However, I think that anything else should be either not-configurable (have sane default) or only configurable from the command line (with mcetool for instance). For example, the brightness of ambient mode or whether we should show a wallpaper in ambient mode or not. By the way I agree with eLtMosen that there should be no wallpaper in ambientmode by default, it saves some battery life, improves the readability and probably makes the screen last longer too.

I will review the patches when my time will permit but I of course share the excitement of everyone here about this feature which we have been missing for a long time. :)