Skip to content
This repository has been archived by the owner on Dec 18, 2024. It is now read-only.

Commit

Permalink
Merge pull request #296 from UltimateHackingKeyboard/manual_sleep_mode
Browse files Browse the repository at this point in the history
Implement macro-controlled sleep mode.
  • Loading branch information
mondalaci authored Oct 2, 2024
2 parents f009a7d + a6a2edf commit 3e8fd59
Show file tree
Hide file tree
Showing 24 changed files with 285 additions and 50 deletions.
7 changes: 7 additions & 0 deletions device/src/device_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "state_sync.h"
#include "shared/slave_protocol.h"
#include "legacy/event_scheduler.h"
#include "legacy/power_mode.h"

static connection_type_t isConnected[ConnectionId_Count] = {};

Expand Down Expand Up @@ -56,9 +57,15 @@ void handleStateTransition(connection_id_t remoteId, bool connected) {
if (connected) {
StateSync_ResetRightDongleLink(true);
}
Widget_Refresh(&TargetWidget);
EventScheduler_Reschedule(CurrentTime + POWER_MODE_UPDATE_DELAY, EventSchedulerEvent_PowerMode, "update sleep mode from device state dongle");
break;
case ConnectionId_UsbHid:
Widget_Refresh(&TargetWidget);
break;
case ConnectionId_BluetoothHid:
Widget_Refresh(&TargetWidget);
EventScheduler_Reschedule(CurrentTime + POWER_MODE_UPDATE_DELAY, EventSchedulerEvent_PowerMode, "update sleep mode from device state bluetooth hid");
break;
default:
break;
Expand Down
69 changes: 48 additions & 21 deletions device/src/keyboard/oled/oled.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#define THREAD_STACK_SIZE 1000
#define THREAD_PRIORITY 5
#define OLED_FADE_TIME 2*255
#define OLED_FADE_STEP 1

static K_THREAD_STACK_DEFINE(stack_area, THREAD_STACK_SIZE);
static struct k_thread thread_data;
Expand Down Expand Up @@ -90,6 +92,14 @@ static uint16_t currentXShift = 0;
static uint16_t currentYShift = 0;
static bool wantScreenShift;

static uint8_t computeBrightness() {
if (ActiveScreen == ScreenId_Debug && DisplayBrightness == 0) {
return 255;
} else {
return DisplayBrightness;
}
}

static void forceRedraw() {
for (uint16_t x = 0; x < DISPLAY_WIDTH; x+=2) {
for (uint16_t y = 0; y < DISPLAY_HEIGHT; y++) {
Expand Down Expand Up @@ -158,26 +168,31 @@ static uint16_t roundToEven(uint16_t a) {
}

static void adjustBrightness() {
uint8_t brightness = DisplayBrightness;
uint8_t targetBrightness = computeBrightness();

uint8_t nextBrightness = lastBrightness;

if (nextBrightness != targetBrightness) {
if (nextBrightness - OLED_FADE_STEP > targetBrightness) {
nextBrightness -= OLED_FADE_STEP;
} else if (nextBrightness + OLED_FADE_STEP < targetBrightness) {
nextBrightness += OLED_FADE_STEP;
} else {
nextBrightness = targetBrightness;
}
}

if (brightness == 0) {
if (nextBrightness == 0) {
oledCommand1(0, OledCommand_SetDisplayOff);
} else {
oledCommand1(0, OledCommand_SetDisplayOn);
oledCommand2(0, OledCommand_SetContrast, DisplayBrightness);
oledCommand2(0, OledCommand_SetContrast, nextBrightness);
}

lastBrightness = brightness;
lastBrightness = nextBrightness;
}

static void diffUpdate() {
k_mutex_lock(&SpiMutex, K_FOREVER);

if (lastBrightness != DisplayBrightness) {
adjustBrightness();
}


setA0(true);
setOledCs(true);

Expand Down Expand Up @@ -226,16 +241,10 @@ static void diffUpdate() {
}
setOledCs(false);
// printk("update took %ims\n", k_uptime_get_32() - time);

k_mutex_unlock(&SpiMutex);
}

void sleepDisplay() {
k_mutex_lock(&SpiMutex, K_FOREVER);
adjustBrightness();
k_mutex_unlock(&SpiMutex);

while (DisplayBrightness == 0) {
while (computeBrightness() == 0 && lastBrightness == 0) {
k_sleep(K_FOREVER);
}
}
Expand All @@ -251,17 +260,35 @@ void oledUpdater() {
currentScreen->draw(currentScreen, OledBuffer);
forceRedraw();

bool lastOledNeedsRedraw = true;

while (true) {
diffUpdate();
{
k_mutex_lock(&SpiMutex, K_FOREVER);

if (!oledNeedsRedraw) {
if (lastBrightness != computeBrightness()) {
adjustBrightness();
}

if (lastOledNeedsRedraw) {
lastOledNeedsRedraw = false;
diffUpdate();
}

k_mutex_unlock(&SpiMutex);
}

if (!oledNeedsRedraw && lastBrightness == computeBrightness()) {
k_sleep(K_FOREVER);
} else {
k_sleep(K_MSEC(OLED_FADE_TIME / (255/OLED_FADE_STEP)));
}

if (lastBrightness != DisplayBrightness) {
if (lastBrightness == 0) {
sleepDisplay();
}

lastOledNeedsRedraw = oledNeedsRedraw;
oledNeedsRedraw = false;

if (wantScreenShift) {
Expand Down
2 changes: 1 addition & 1 deletion device/src/keyboard/oled/screens/debug_screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

// Typedefs:

#define DEBUG_SCREEN_NOTIFICATION_TIMEOUT 60000
#define DEBUG_SCREEN_NOTIFICATION_TIMEOUT 10000

// Variables:

Expand Down
5 changes: 4 additions & 1 deletion device/src/keyboard/oled/widgets/console_widget.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "../oled_buffer.h"
#include "../oled_text_renderer.h"
#include "../oled.h"
#include "../screens/screen_manager.h"

#define MIN_CHAR_WIDTH 5
#define MIN_CHAR_HEIGHT 7
Expand Down Expand Up @@ -65,7 +66,9 @@ void Oled_LogConstant(const char* text)
consoleBuffer[consoleBufferStart][CONSOLE_BUFFER_LINE_LENGTH-1] = '\0';

consoleBufferIsDirty = true;
Widget_Refresh(NULL);

ScreenManager_ActivateScreen(ScreenId_Debug);
// Widget_Refresh(NULL);
}

void Oled_Log(const char *fmt, ...)
Expand Down
1 change: 1 addition & 0 deletions device/src/legacy/power_mode.c
1 change: 1 addition & 0 deletions device/src/legacy/power_mode.h
4 changes: 4 additions & 0 deletions device/src/state_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <stdint.h>
#include <zephyr/kernel.h>
#include "legacy/peripherals/merge_sensor.h"
#include "power_mode.h"

#define THREAD_STACK_SIZE 2000
#define THREAD_PRIORITY 5
Expand Down Expand Up @@ -119,6 +120,7 @@ static state_sync_prop_t stateSyncProps[StateSyncPropertyId_Count] = {
EMPTY(LeftModuleDisconnected, SyncDirection_LeftToRight, DirtyState_Clean),
SIMPLE(MergeSensor, SyncDirection_LeftToRight, DirtyState_Clean, &MergeSensor_HalvesAreMerged),
SIMPLE(FunctionalColors, SyncDirection_RightToLeft, DirtyState_Clean, &Cfg.KeyActionColors),
SIMPLE(PowerMode, SyncDirection_RightToLeft, DirtyState_Clean, &CurrentPowerMode),
};

static void invalidateProperty(state_sync_prop_id_t propId) {
Expand Down Expand Up @@ -505,6 +507,7 @@ static bool handlePropertyUpdateRightToLeft() {

if (KeyBacklightBrightness != 0 && Cfg.BacklightingMode != BacklightingMode_ConstantRGB) {
// Update relevant data
UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_PowerMode);
UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_FunctionalColors);
UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_LayerActionFirst + ActiveLayer);
UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ActiveKeymap);
Expand Down Expand Up @@ -640,6 +643,7 @@ void StateSync_ResetRightLeftLink(bool bidirectional) {
invalidateProperty(StateSyncPropertyId_ActiveLayer);
invalidateProperty(StateSyncPropertyId_Backlight);
invalidateProperty(StateSyncPropertyId_FunctionalColors);
invalidateProperty(StateSyncPropertyId_PowerMode);
}
if (DEVICE_ID == DeviceId_Uhk80_Left) {
invalidateProperty(StateSyncPropertyId_Battery);
Expand Down
1 change: 1 addition & 0 deletions device/src/state_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
StateSyncPropertyId_LeftModuleDisconnected,
StateSyncPropertyId_MergeSensor,
StateSyncPropertyId_FunctionalColors,
StateSyncPropertyId_PowerMode,
StateSyncPropertyId_Count,
} state_sync_prop_id_t;

Expand Down
41 changes: 40 additions & 1 deletion device/src/usb/usb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ extern "C" {
#include "legacy/user_logic.h"
#include <device.h>
#include <zephyr/kernel.h>
#include "logger.h"
#include "legacy/power_mode.h"
}
#include "command_app.hpp"
#include "controls_app.hpp"
Expand Down Expand Up @@ -129,7 +131,39 @@ struct usb_manager {

private:
usb_manager()
{}
{
device_.set_power_event_delegate([](usb::df::device &dev, usb::df::device::event ev) {
using event = enum usb::df::device::event;
switch (ev) {
case event::CONFIGURATION_CHANGE:
// printk("USB configured: %u, granted current: %uuA\n", dev.configured(), dev.granted_bus_current_uA());
break;
case event::POWER_STATE_CHANGE:
// printk("USB power state: L%u, granted current: %uuA\n", 3 - static_cast<uint8_t>(dev.power_state()), dev.granted_bus_current_uA());
switch (dev.power_state()) {
case usb::power::state::L2_SUSPEND:
// TODO: handle suspend, maybe only when the HID target is USB?
// TODO: stop battery charging, maybe only if dev.configured(),
// to distinguish between USB host and charger

Log("L2 Suspend\n");
// uncomment when the waking stuff works.
PowerMode_SetUsbAwake(false);
break;
case usb::power::state::L0_ON:
//TODO: handle wakeup, only if in suspend

Log("L0 ON\n");
PowerMode_SetUsbAwake(true);
break;
default:
Log("L state %i\n", (int)ev);
break;
}
break;
}
});
}

usb::df::zephyr::udc_mac mac_{DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0))};
usb::df::microsoft::alternate_enumeration<usb::speeds(usb::speed::FULL)> ms_enum_{};
Expand All @@ -146,6 +180,11 @@ extern "C" void USB_DisableHid()
usb_manager::instance().select_config(Hid_Empty);
}

extern "C" void USB_RemoteWakeup()
{
usb_manager::instance().device().remote_wakeup();
}

#if DEVICE_IS_UHK80_RIGHT

using multi_hid_full = multi_hid<keyboard_app, mouse_app, command_app, controls_app, gamepad_app>;
Expand Down
1 change: 1 addition & 0 deletions device/src/usb/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@
void USB_DisableHid(void);
void USB_EnableHid(void);
void USB_SetSerialNumber(uint32_t serialNumber);
void USB_RemoteWakeup(void);

#endif // __USB_HEADER__
4 changes: 4 additions & 0 deletions doc-dev/reference-manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ COMMAND = {startMouse|stopMouse} {move DIRECTION|scroll DIRECTION|accelerate|dec
COMMAND = setVar <variable name (IDENTIFIER)> <value (PARENTHESSED_EXPRESSION)>
COMMAND = {pressKey|holdKey|tapKey|releaseKey} SHORTCUT
COMMAND = tapKeySeq [SHORTCUT]+
COMMAND = powerMode [toggle] { wake | sleep }
COMMAND = set module.MODULEID.navigationMode.LAYERID_BASIC NAVIGATION_MODE
COMMAND = set module.MODULEID.baseSpeed <non-xcelerated speed, 0-10.0 (FLOAT)>
COMMAND = set module.MODULEID.speed <xcelerated speed, 0-10.0 (FLOAT)>
Expand Down Expand Up @@ -315,6 +316,9 @@ COMMAND = setEmergencyKey KEYID
- `resetTrackpoint` resets the internal trackpoint board. Can be used to recover the trackpoint from drift conditions. Drifts usually happen if you keep the cursor moving at slow constant speeds, because of the boards's internal adaptive calibration. Since the board's parameters cannot be altered, the only way around is or you to learn not to do the type of movement which triggers them.
- `i2cBaudRate <baud rate, default 100000(INT)>` sets i2c baud rate. Lowering this value may improve module reliability, while increasing latency.
- `{|}` Braces allow grouping multiple commands as if they were a single command. Please note that from the point of view of the engine, braces are (almost) regular commands, and have to be followed by newlines like any other command. Therefore idioms like `} else {` are not possible at the moment.
- `powerMode [toggle] { wake | sleep }`
- `sleep` will disable all leds, disables USB output, and puts the device into a low-power mode. If `toggle` is specified and the device is already in the mode, it will wake the device instead.
- `wake` will wake up the device from sleep mode.

### Triggering keyboard actions (pressing keys, clicking, etc.):

Expand Down
2 changes: 1 addition & 1 deletion lib/agent
Submodule agent updated 112 files
4 changes: 4 additions & 0 deletions right/src/event_scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "led_manager.h"
#include "slave_drivers/uhk_module_driver.h"
#include "peripherals/merge_sensor.h"
#include "power_mode.h"

#ifdef __ZEPHYR__
#include "keyboard/oled/screens/screen_manager.h"
Expand Down Expand Up @@ -93,6 +94,9 @@ static void processEvt(event_scheduler_event_t evt)
DISABLE_IN_EVENTLOOP_SCHEDULE_DEBUG();
MergeSensor_Update();
break;
case EventSchedulerEvent_PowerMode:
PowerMode_Update();
break;
default:
return;
}
Expand Down
1 change: 1 addition & 0 deletions right/src/event_scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
EventSchedulerEvent_MouseController,
EventSchedulerEvent_ReenableUart,
EventSchedulerEvent_UpdateMergeSensor,
EventSchedulerEvent_PowerMode,
EventSchedulerEvent_Count
} event_scheduler_event_t;

Expand Down
4 changes: 2 additions & 2 deletions right/src/led_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
#include "led_display.h"
#include "usb_report_updater.h"
#include "test_switches.h"
#include "power_mode.h"

#ifdef __ZEPHYR__
#include <zephyr/sys/util.h>
#include "state_sync.h"
#include "keyboard/charger.h"
#include "keyboard/oled/oled.h"
#define SleepModeActive false
#else
#include "device.h"
#endif
Expand All @@ -25,7 +25,7 @@ uint8_t KeyBacklightBrightness = 0xff;

static void recalculateLedBrightness()
{
bool globalSleepMode = !Cfg.LedsEnabled || SleepModeActive || Cfg.LedBrightnessMultiplier == 0.0f;
bool globalSleepMode = !Cfg.LedsEnabled || CurrentPowerMode > PowerMode_Awake || Cfg.LedBrightnessMultiplier == 0.0f;

if (globalSleepMode || KeyBacklightSleepModeActive) {
KeyBacklightBrightness = 0;
Expand Down
Loading

0 comments on commit 3e8fd59

Please sign in to comment.