Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Soft shutdown of keyboard #1292

Closed
dxmh opened this issue May 7, 2022 · 16 comments
Closed

Feature request: Soft shutdown of keyboard #1292

dxmh opened this issue May 7, 2022 · 16 comments
Labels
core Core functionality/behavior of ZMK enhancement New feature or request

Comments

@dxmh
Copy link
Collaborator

dxmh commented May 7, 2022

Lots of users request the ability to power off their keyboard (in the absence of a physical power switch).

The reason behind most of the requests is so that the keyboard can be transported in a bag without accidentally sending keystrokes and/or draining battery. However, it's also just nice to be able to turn things off when they're not being used. 🙂

@dxmh dxmh added enhancement New feature or request core Core functionality/behavior of ZMK labels May 7, 2022
@R3XP
Copy link

R3XP commented May 7, 2022

How would that work in theory? Would it shut down until a certain keycombo is pressed? If yes, how often does the mcu scan for the combo? If no, is there another way to start it again? Pluging it into something maybe? Or a designated button to restart it? Maybe a reset button?

{just brainstorming out loud here ^^}

@dxmh
Copy link
Collaborator Author

dxmh commented May 7, 2022

Good question. There was some discussion about this on Discord a few days ago. Here are some relevant snippets to aid the brainstorming:

hxy:
How would you power-on the keyboard after a soft shutdown?

nef:
reset switch would work...

petejohanson:
We could have a software shutdown, that stops BLE and reduces scan frequency.
So we could still detect key presses, but much more slowly.
Or we set a flag and go into deep sleep, so if a key press does wake us, still stay in "software lockout mode"

@R3XP
Copy link

R3XP commented May 7, 2022

Hmm I see. What do you think about a user defined combo where the mcu would only ever scan one of the columns of the combo so that there wouldnt be as much activity as usally but when theres any key pressed in that column it would start scanning for the whole combo again?

@grasegger
Copy link

Hmm I see. What do you think about a user defined combo where the mcu would only ever scan one of the columns of the combo so that there wouldnt be as much activity as usally but when theres any key pressed in that column it would start scanning for the whole combo again?

Not every board uses a matrix, some use direct pin assignments (but I guess you could make that configurable at compile time).

What about split keyboards? I guess since the slave side already operates very power efficient it could be ignored, but maybe some users would like to shut down both sides.

@manna-harbour
Copy link

Also see #405.

@freqmod
Copy link

freqmod commented Oct 2, 2022

Hi, i did a 2 hour stab at this (instead of figuring how to solder a power switch to my corne helix), and found a solution that seems to work for me on nice nano v2. I haven't measured the current draw, but i do not get any presses until reset i pressed.
Use the &suspend key behaviour (and include the reset header if necessary) in the keyboard layout. For split keyboard add the key on both halves and suspend the right half before the left (if you want both to be off).

The following patches are needed (if someone wants to make this into a proper upstream feature it would be great. feel free, and use the MIT license. It would be great if you'd mention my name in the commit message):
(Based on zmk revision fc511e4)

commit 726a482165964d67f1f8d4cd1dd3dcde67e4de57 (HEAD -> nrf_suspend)
Author: Frederik M.J.V <freqmod@gmail.com>
Date:   Sun Oct 2 12:05:30 2022 +0200

    Support for supend for nrf52

diff --git a/app/dts/behaviors/reset.dtsi b/app/dts/behaviors/reset.dtsi
index cb246814..f1192023 100644
--- a/app/dts/behaviors/reset.dtsi
+++ b/app/dts/behaviors/reset.dtsi
@@ -20,5 +20,11 @@
                        type = <RST_UF2>;
                        #binding-cells = <0>;
                };
+               suspend: behavior_reset_suspend {
+                       compatible = "zmk,behavior-reset";
+                       label = "SUSPEND";
+                       type = <RST_SUSPEND>;
+                       #binding-cells = <0>;
+               };
        };
 };
diff --git a/app/include/dt-bindings/zmk/reset.h b/app/include/dt-bindings/zmk/reset.h
index 2b3d8760..4ebb8d0f 100644
--- a/app/include/dt-bindings/zmk/reset.h
+++ b/app/include/dt-bindings/zmk/reset.h
@@ -10,4 +10,5 @@
 // AdaFruit nrf52 Bootloader Specific. See
 // https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/d6b28e66053eea467166f44875e3c7ec741cb471/src/main.c#L107

-#define RST_UF2 0x57
\ No newline at end of file
+#define RST_UF2 0x57
+#define RST_SUSPEND 0xFE
\ No newline at end of file

And for zephyr (on revision 8adeab429a2480198d22df9847933cfe3f9ea410 ):

commit d1eee565d5c3aab021839aa77743a48b32575815 (HEAD -> nrf52_suspend)
Author: Frederik M.J.V <freqmod@gmail.com>
Date:   Sun Oct 2 12:09:46 2022 +0200

    Allow soft power off of nrf52 boards

diff --git a/soc/arm/nordic_nrf/nrf52/soc.c b/soc/arm/nordic_nrf/nrf52/soc.c
index e1e63e9f8..51e4665bb 100644
--- a/soc/arm/nordic_nrf/nrf52/soc.c
+++ b/soc/arm/nordic_nrf/nrf52/soc.c
@@ -18,6 +18,7 @@
 #include <hal/nrf_power.h>
 #include <soc/nrfx_coredep.h>
 #include <logging/log.h>
+#include <pm/state.h>

 #ifdef CONFIG_RUNTIME_NMI
 extern void z_arm_nmi_init(void);
@@ -51,8 +52,13 @@ LOG_MODULE_REGISTER(soc);
    Set general purpose retention register and reboot */
 void sys_arch_reboot(int type)
 {
-       nrf_power_gpregret_set(NRF_POWER, (uint8_t)type);
-       NVIC_SystemReset();
+       if (type == 0xFE){
+               nrf_power_system_off(NRF_POWER);
+       }
+       else{
+               nrf_power_gpregret_set(NRF_POWER, (uint8_t)type);
+               NVIC_SystemReset();
+       }
 }

 static int nordicsemi_nrf52_init(const struct device *arg)

jacobsamlarose added a commit to jacobsamlarose/zmk that referenced this issue Oct 8, 2022
jacobsamlarose added a commit to jacobsamlarose/zmk that referenced this issue Oct 8, 2022
jacobsamlarose added a commit to jacobsamlarose/zephyr that referenced this issue Oct 8, 2022
@manna-harbour
Copy link

@freqmod To make your changes easier to test, here they are in separate branches, including a change to the zmk manifest to use the zephyr fork.

Support is also included in Miryoku ZMK.

@manna-harbour
Copy link

@freqmod Could this be implemented using BEHAVIOR_LOCALITY_GLOBAL?

@freqmod
Copy link

freqmod commented Oct 9, 2022

Initially i tried to do global behaviour. As far as i could see from the implementation the global behaviour first sends a command to the peripheral (right side) and then executes the command itself. I was a bit concerned that the command to the peripheral side seems to be put in a queue. If the right side executes before the queue element is processed then it will power down the right side before the left side gets the command to power of. I guess there are ways to handle this e.g. by putting the command to power down the left side in the queue after the other command. Another option may be to sleep, but if you block the queue processing it does not help. I just wanted something that worked within a reasonable implementation time, so i haven't investigated this, and rather went with the local behaviour.

Btw i have been testing this for a week without any issues (except sometimes reconnecting after wakeup, but i guess that is present if you use a hard power off switch too). It seems my battery stays charged too.

Also it may be useful see https://github.com/freqmod/zmk where i have applied the zmk (but not zephyr) patch, in addition to other patches i use. I will rebase this now and then, whenever I want new zmk firmware on my keyboards.

@jacobsamlarose
Copy link

@freqmod Question (and please excuse my noobiness): I'm testing this on a Corne with OLED displays; I usually keep the OLEDs off unless diagnosing a fault, but kept them on to test this soft shutdown. I have a "travel layer" with a keymap full of &nones that I'd usually toggle on before packing the board; I've now added &suspend keys to each side in that layer. When I press the &suspend keys, the Bluetooth connection shuts down and the keys are non-responsive (as I'd expect for a shutdown) but the OLEDs continue to display whatever was showing when I pressed the suspend keys— is that expected?

@frederik-vestre-pexip
Copy link

frederik-vestre-pexip commented Oct 10, 2022

I am not sure what the nrf52 suspend does. Have you considered seeing if the external power off behaviour turns off the displays, maybe they can be combined with this in a macro or something?

If so it may be sensible to add external power down etc. in the code pre shutdown. I am not sure what is required on startup though, if you need specific code to power it up at that time.

@jacobsamlarose
Copy link

Something like:
ZMK_MACRO(shutdown, wait-ms = <30>; tap-ms = <40>; bindings = <&ext_power EP_OFF &suspend>; )

? I'll give this a go and see.

@MartianH
Copy link

Any update on this?

@freqmod
Copy link

freqmod commented Nov 16, 2022

At least for my side I am not intending to try to spend effort to try to upstream this(I. e. get this merged). Especially since it requires changes to zephyr too (to reset the device).

If anybody else wants to do the work that would be great though.

@caksoylar
Copy link
Contributor

Would be resolved by #1942.

@elpekenin
Copy link
Contributor

Closed by #2085

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Core functionality/behavior of ZMK enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

10 participants