Skip to content

Commit

Permalink
Implement power modes and sfjl sleep
Browse files Browse the repository at this point in the history
  • Loading branch information
kareltucek committed Feb 27, 2025
1 parent 13664ff commit c750657
Show file tree
Hide file tree
Showing 24 changed files with 549 additions and 138 deletions.
54 changes: 25 additions & 29 deletions device/src/keyboard/charger.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "charger.h"
#include "keyboard/charger.h"
#include "nrf52840.h"
#include "power_mode.h"
#include "shell.h"
#include "timer.h"
#include "event_scheduler.h"
Expand Down Expand Up @@ -132,27 +133,6 @@ void Charger_EnableCharging(bool enabled) {
}
}

static bool isStillDepleted() {
updatePowered();
return !batteryState.powered;
}

void Charger_EnterSleepIfDepleted(bool enter) {
if (enter) {
NVIC_SystemReset();
}
if (isStillDepleted()) {
LogU("Going to enter low power mode because of depleted battery!\n");
while (isStillDepleted()) {

k_sleep(K_MSEC(10000));
}

NVIC_SystemReset();
}
}


void updateChargerEnabled(battery_state_t *batteryState, battery_manager_config_t* config) {
battery_manager_automaton_state_t newState = BatteryManager_UpdateState(
currentChargingAutomatonState,
Expand All @@ -164,7 +144,7 @@ void updateChargerEnabled(battery_state_t *batteryState, battery_manager_config_
currentChargingAutomatonState = newState;
switch (newState) {
case BatteryManagerAutomatonState_TurnOff:
Charger_EnterSleepIfDepleted(true);
PowerMode_ActivateMode(PowerMode_ShutDown, false);
break;
case BatteryManagerAutomatonState_Charging:
Charger_EnableCharging(true);
Expand Down Expand Up @@ -305,11 +285,30 @@ void chargerStatCallback(const struct device *port, struct gpio_callback *cb, gp
EventScheduler_Reschedule(CurrentTime + CHARGER_STAT_PERIOD, EventSchedulerEvent_UpdateBattery, "charger - stat callback");
}

// charging battery with CHARGER_EN yields STAT 0
// fully charged battery with CHARGER_EN yields STAT 1
// CHARGER_EN 0 yields STAT 1
bool Charger_ShouldRemainInDepletedMode(bool checkVoltage) {
updatePowered();
if (checkVoltage) {
uint16_t voltage = getVoltage();
return !batteryState.powered && voltage < getCurrentBatteryConfig()->minWakeupVoltage;
} else {
return !batteryState.powered;
}
}

bool Charger_ShouldEnterDepletedMode() {
updatePowered();
uint16_t voltage = getVoltage();
return !batteryState.powered && voltage < getCurrentBatteryConfig()->minVoltage;
}

void InitCharger_Min(void) {
adc_channel_setup_dt(&adc_channel);
(void)adc_sequence_init_dt(&adc_channel, &sequence);
}

void InitCharger(void) {
InitCharger_Min();

gpio_pin_configure_dt(&chargerEnDt, GPIO_OUTPUT);
Charger_EnableCharging(true);

Expand All @@ -318,10 +317,6 @@ void InitCharger(void) {
gpio_init_callback(&callbackStruct, chargerStatCallback, BIT(chargerStatDt.pin));
gpio_add_callback(chargerStatDt.port, &callbackStruct);

adc_channel_setup_dt(&adc_channel);

(void)adc_sequence_init_dt(&adc_channel, &sequence);

const nrfx_power_usbevt_config_t config = {
.handler = &powerCallback
};
Expand All @@ -334,3 +329,4 @@ void InitCharger(void) {

// TODO: Update battery level. See bas_notify()
}

5 changes: 4 additions & 1 deletion device/src/keyboard/charger.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@
// Functions:

void InitCharger(void);
void InitCharger_Min(void);
void Charger_PrintState();
void Charger_UpdateBatteryState();
void Charger_EnableCharging(bool enabled);
void Charger_EnterSleepIfDepleted(bool enter);

bool Charger_ShouldRemainInDepletedMode(bool checkVoltage);
bool Charger_ShouldEnterDepletedMode();

#endif // __CHARGER_H__
135 changes: 130 additions & 5 deletions device/src/keyboard/key_scanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "layouts/key_layout.h"
#include "layouts/key_layout_80_to_universal.h"
#include "test_switches.h"
#include "power_mode.h"
#include "keyboard/leds.h"

// Thread definitions

Expand Down Expand Up @@ -63,6 +65,8 @@ volatile bool KeyPressed;

volatile bool KeyScanner_ResendKeyStates = false;

static void scanAllKeys();

ATTR_UNUSED static void reportChange(uint8_t sourceIndex, bool active) {
uint8_t slotId = DEVICE_IS_UHK80_LEFT ? SlotId_LeftKeyboardHalf : SlotId_RightKeyboardHalf;
uint8_t keyId = KeyLayout_Uhk80_to_Uhk60[slotId][sourceIndex];
Expand All @@ -74,12 +78,106 @@ ATTR_UNUSED static void reportChange(uint8_t sourceIndex, bool active) {
}
}

static void scanKeys() {
static bool scanKey(uint8_t rowId, uint8_t colId) {
gpio_pin_set_dt(&rows[rowId], 1);
bool keyState = gpio_pin_get_dt(&cols[colId]);
gpio_pin_set_dt(&rows[rowId], 0);
return keyState;
}

static bool isSfjlKey(uint8_t rowId, uint8_t colId) {
if (DEVICE_IS_UHK80_LEFT) {
return (rowId == 3 && (colId == 2 || colId == 4));
}
if (DEVICE_IS_UHK80_RIGHT) {
return (rowId == 3 && (colId == 1 || colId == 3));
}
return false;
}

static sfjl_scan_result_t scanSfjl(bool fullScan) {
bool somethingPressed = false;
bool success = true;

#define CHECK(EXPECTED, EXPR) if (EXPR) { success &= EXPECTED; somethingPressed = true; } else { success &= !EXPECTED; }

if (DEVICE_IS_UHK80_LEFT) {
CHECK(true, scanKey(3, 2));
CHECK(true, scanKey(3, 4));
}

if (DEVICE_IS_UHK80_RIGHT) {
CHECK(true, scanKey(3, 1));
CHECK(true, scanKey(3, 3));
}

for (uint8_t rowId=0; rowId<KEY_MATRIX_ROWS; rowId++) {
if (!success && !fullScan) {
break;
}

gpio_pin_set_dt(&rows[rowId], 1);
for (uint8_t colId=0; colId<KEY_MATRIX_COLS; colId++) {
bool keyState = gpio_pin_get_dt(&cols[colId]);
bool isSfjl = isSfjlKey(rowId, colId);
CHECK(isSfjl, keyState);
}
gpio_pin_set_dt(&rows[rowId], 0);
}

sfjl_scan_result_t res = success ? SfjlScanResult_FullMatch : (somethingPressed ? SfjlScanResult_SomethingPressed : SfjlScanResult_NonePressed);
return res;
}

static sfjl_scan_result_t scanKeysOnce(sfjl_scan_result_t defaultResult, bool fullScan) {
// In the lock mode, do both scans
if (CurrentPowerMode < PowerMode_SfjlSleep) {
scanAllKeys();
}

if (CurrentPowerMode > PowerMode_LightSleep) {
defaultResult = MAX(defaultResult, scanSfjl(fullScan));
}
return defaultResult;
}

static bool scanSfjlWithBlinking(bool fullScan) {
const uint16_t blinkCount = 3;
const uint16_t blinktimeOn = 100;
const uint16_t blinktimeOff = 200;
const uint16_t scanInterval = PowerModeConfig[CurrentPowerMode].keyScanInterval;

sfjl_scan_result_t result = SfjlScanResult_NonePressed;

result = scanKeysOnce(result, fullScan);

if (result == SfjlScanResult_NonePressed || !fullScan) {
return result == SfjlScanResult_FullMatch;
}

for (uint16_t i=0; i<blinkCount; i++) {
Leds_BlinkSfjl(blinktimeOn);

result = scanKeysOnce(result, fullScan);

for (uint16_t time = 0; time < blinktimeOff && i < blinkCount-1; time += scanInterval) {
k_msleep(scanInterval);
result = scanKeysOnce(result, fullScan);
}

if (result == SfjlScanResult_FullMatch || CurrentPowerMode < PowerMode_LightSleep) {
return true;
}
}

return false;
}

static void scanAllKeys() {
bool somethingChanged = false;
static bool keyStateBuffer[KEY_MATRIX_ROWS*KEY_MATRIX_COLS];
bool keyPressed = false;

CurrentTime = k_uptime_get_32();

for (uint8_t rowId=0; rowId<KEY_MATRIX_ROWS; rowId++) {
gpio_pin_set_dt(&rows[rowId], 1);
Expand Down Expand Up @@ -156,21 +254,46 @@ static void scanKeys() {
}
}

bool KeyScanner_ScanAndWakeOnSfjl(bool fullScan, bool wake) {
if (scanSfjlWithBlinking(true)) {
if (wake) {
PowerMode_ActivateMode(PowerMode_Awake, false);
EventVector_Set(EventVector_LedManagerFullUpdateNeeded);
}
return true;
}
return false;
}

static void scanKeys() {
CurrentTime = k_uptime_get_32();

if (CurrentPowerMode > PowerMode_LightSleep) {
KeyScanner_ScanAndWakeOnSfjl(true, true);
} else {
scanAllKeys();
}
}

void keyScanner() {
while (true) {
scanKeys();
k_msleep(1);
k_msleep(PowerModeConfig[CurrentPowerMode].keyScanInterval);
}
}

void InitKeyScanner(void)
{
void InitKeyScanner_Min(void) {
for (uint8_t rowId=0; rowId<6; rowId++) {
gpio_pin_configure_dt(&rows[rowId], GPIO_OUTPUT);
}
for (uint8_t colId=0; colId<COLS_COUNT; colId++) {
gpio_pin_configure_dt(&cols[colId], GPIO_INPUT);
}
}

void InitKeyScanner(void)
{
InitKeyScanner_Min();

k_thread_create(
&thread_data, stack_area,
Expand All @@ -181,3 +304,5 @@ void InitKeyScanner(void)
);
k_thread_name_set(&thread_data, "key_scanner");
}


11 changes: 11 additions & 0 deletions device/src/keyboard/key_scanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@
#include "stdint.h"
#include "stdbool.h"

// Typedefs:

typedef enum {
SfjlScanResult_NonePressed,
SfjlScanResult_SomethingPressed,
SfjlScanResult_FullMatch
} sfjl_scan_result_t;

// Variables:


extern volatile bool KeyPressed;
extern volatile bool KeyScanner_ResendKeyStates;

// Functions:

extern void InitKeyScanner(void);
extern void InitKeyScanner_Min(void);
extern bool KeyScanner_ScanAndWakeOnSfjl(bool fullScan, bool wake);

#endif // KEY_SCANNER_H__
Loading

0 comments on commit c750657

Please sign in to comment.