Skip to content

Commit

Permalink
Refactor sleep logic
Browse files Browse the repository at this point in the history
- Remove "charging" based logic, it doesn't work because when NRF is off it reports board as not charging so it makes the board deep sleep anyway.
- Add toggle-able sleep modes (idea from adi4086)
- Refactor mcu_pwr.c to keep LED's off in light sleep
- Refactor globals to user_kb.h
- Move light sleep wake to pre_process_kb to guarantee immediate wake on action to not lose first keystroke.
  • Loading branch information
jincao1 committed Mar 5, 2024
1 parent 4c44f8d commit 3a85bcb
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 94 deletions.
40 changes: 18 additions & 22 deletions keyboards/nuphy/air75_v2/ansi/ansi.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "usb_main.h"
#include "mcu_pwr.h"

extern bool f_rf_sw_press;
extern bool f_sleep_show;
extern bool f_dev_reset_press;
extern bool f_bat_num_show;
extern bool f_rgb_test_press;
extern bool f_bat_hold;
extern uint16_t no_act_time;
extern uint8_t rf_sw_temp;
extern uint16_t rf_sw_press_delay;
extern uint16_t rf_linking_time;
extern uint16_t sleep_time_delay;
extern user_config_t user_config;
extern DEV_INFO_STRUCT dev_info;
extern uint8_t rf_blink_cnt;

/* qmk process record */
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
bool pre_process_record_kb(uint16_t keycode, keyrecord_t *record) {
no_act_time = 0;
rf_linking_time = 0;

if (!process_record_user(keycode, record)) {
// wakeup check for light sleep/no sleep - fire this immediately to not lose wake keys.
if (f_wakeup_prepare) {
f_wakeup_prepare = 0;
if (user_config.sleep_mode) exit_light_sleep();
}

if (!pre_process_record_user(keycode, record)) {
return false;
}

return true;
}

/* qmk process record */
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
if (!process_record_user(keycode, record)) {
return false;
}
switch (keycode) {
case RF_DFU:
if (record->event.pressed) {
Expand Down Expand Up @@ -200,9 +198,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) {

case SLEEP_MODE:
if (record->event.pressed) {
user_config.sleep_enable = !user_config.sleep_enable;
f_sleep_show = 1;
eeconfig_update_kb_datablock(&user_config);
toggle_sleep_mode();
}
return false;

Expand Down Expand Up @@ -237,7 +233,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
case KB_SLP:
if (record->event.pressed) {
uint16_t mask = (100 * 30) ^ SLEEP_TIME_DELAY; // 30s or default
sleep_time_delay ^= mask; // XOR swap
sleep_time_delay ^= mask; // XOR swap
}
return false;

Expand Down
6 changes: 5 additions & 1 deletion keyboards/nuphy/air75_v2/ansi/customizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ This sets how long the board tries to connect (left light blinking) before givin
- `Fn + M + D` toggles QMK debugging. Don't turn this on when not connected to QMK toolbox.
The letter `D` will light up red when enabled.
- Side indicators will flash red for 0.5s when board enters sleep mode, as an indicator.
This is a deep sleep state. It only happens if the board is not charging, otherwise the board enters a light sleep state with no indicators.
This is a deep sleep state. There are no indicators in other sleep modes.
- Bluetooth connection indicators will be lit blue when establishing connection. This lights the corresponding
BT mode key. No indicator for RF as the sidelight is a different colour.
- Default startup LED brightness set to zero and side led set to lowest brightness. This is because I don't use LEDs so I don't need to toggle them off when resetting the board or flashing new firmware.
- 3ms debounce instead of 2ms (potential stability)
- 3 sleep modes (inspired by @adi4086) - Toggle with the default sleep mode button.
- Deep Sleep (NRF off, MCU off, LED off) - lowest power consumption. This is the default.
- Light Sleep (NRF off, LED off) - no real reason to use this, but might wake up quicker.
- No Sleep - for those that want their board to always be on...

## Fixes

Expand Down
7 changes: 5 additions & 2 deletions keyboards/nuphy/air75_v2/ansi/mcu_pwr.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
extern DEV_INFO_STRUCT dev_info;

static bool f_usb_deinit = 0;
static bool sleeping = false;
static bool side_led_powered_off = 0;
static bool rgb_led_powered_off = 0;
static bool tim6_enabled = false;
Expand Down Expand Up @@ -216,6 +217,7 @@ void enter_light_sleep(void) {

led_pwr_sleep_handle();
clear_report_buffer();
sleeping = true;
}

/**
Expand All @@ -234,6 +236,7 @@ void exit_light_sleep(void) {

// flag for RF wakeup workload.
dev_info.rf_state = RF_WAKE;
sleeping = false;
}

void led_pwr_sleep_handle(void) {
Expand Down Expand Up @@ -271,7 +274,7 @@ void pwr_rgb_led_off(void) {
}

void pwr_rgb_led_on(void) {
if (rgb_led_on) return;
if (sleeping || rgb_led_on) return;
// LED power supply on
gpio_set_pin_output(DC_BOOST_PIN);
gpio_write_pin_high(DC_BOOST_PIN);
Expand All @@ -287,7 +290,7 @@ void pwr_side_led_off(void) {
}

void pwr_side_led_on(void) {
if (side_led_on) return;
if (sleeping || side_led_on) return;
gpio_set_pin_output(DRIVER_SIDE_CS_PIN);
gpio_write_pin_low(DRIVER_SIDE_CS_PIN);
side_led_on = 1;
Expand Down
1 change: 0 additions & 1 deletion keyboards/nuphy/air75_v2/ansi/rf_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "rf_queue.h"

/* Variable declaration */
extern DEV_INFO_STRUCT dev_info;
extern report_buffer_t report_buff_a;
extern report_buffer_t report_buff_b;
extern rf_queue_t rf_queue;
Expand Down
35 changes: 16 additions & 19 deletions keyboards/nuphy/air75_v2/ansi/side.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,6 @@ const uint8_t side_led_index_tab[SIDE_LINE][2] = {
};
// clang-format on

extern DEV_INFO_STRUCT dev_info;
extern user_config_t user_config;
extern uint8_t rf_blink_cnt;
extern uint16_t rf_link_show_time;
extern uint16_t side_led_last_act;
extern bool f_bat_hold;
extern bool f_sys_show;
extern bool f_sleep_show;
extern RGB bat_pct_rgb;

void side_ws2812_setleds(rgb_led_t *ledarray, uint16_t leds);
void rgb_matrix_update_pwm_buffers(void);

Expand Down Expand Up @@ -321,15 +311,22 @@ void sleep_sw_led_show(void) {
}

if (sleep_show_flag) {
if (user_config.sleep_enable) {
r_temp = 0x00;
g_temp = 0x80;
b_temp = 0x00;
} else {
r_temp = 0x80;
g_temp = 0x00;
b_temp = 0x00;
r_temp = 0x00;
g_temp = 0x00;
b_temp = 0x00;
switch (user_config.sleep_mode) {
case SLEEP_MODE_OFF:
r_temp = 0x80;
break;
case SLEEP_MODE_LIGHT:
r_temp = 0x80;
g_temp = 0x40;
break;
case SLEEP_MODE_DEEP:
g_temp = 0x80;
break;
}

if ((timer_elapsed32(sleep_show_timer) / 500) % 2 == 0) {
set_right_rgb(r_temp, g_temp, b_temp);
} else {
Expand Down Expand Up @@ -483,7 +480,7 @@ static void side_off_mode_show(void) {
* @brief rf_led_show.
*/
void rf_led_show(void) {
static uint32_t rf_blink_timer = 0;
static uint32_t rf_blink_timer = 0;
uint16_t rf_blink_period = 0;

if (rf_blink_cnt || (rf_link_show_time < RF_LINK_SHOW_TIME)) {
Expand Down
41 changes: 6 additions & 35 deletions keyboards/nuphy/air75_v2/ansi/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void deep_sleep_handle(void) {
// Without doing this, the WS2812 driver wouldn't flush as the previous state is the same as current.
rgb_matrix_set_color_all(0, 0, 0);
flush_side_leds = true;
no_act_time = 0; // required to not cause an immediate sleep on first wake
no_act_time = 0; // required to not cause an immediate sleep on first wake
}

/**
Expand All @@ -77,42 +77,13 @@ void sleep_handle(void) {
rf_disconnect_time = 0;
rf_linking_time = 0;

if (user_config.sleep_enable) {
bool deep_sleep = 1;
// light sleep if charging? Charging event might keep waking MCU. To be confirmed...
if (dev_info.rf_charge & 0x01) {
deep_sleep = 0;
}
// or if it's in USB mode but USB state is suspended
// TODO: How to detect if USB is unplugged? I only use RF so not a big deal I guess...
else if (dev_info.link_mode == LINK_USB && USB_DRIVER.state == USB_SUSPENDED) {
deep_sleep = 0;
}

if (deep_sleep) {
deep_sleep_handle();
return; // don't need to do anything else
} else {
enter_light_sleep();
}
}
f_wakeup_prepare = 1; // only if light sleep.
}

// wakeup check
// we only arrive here on light sleep.
if (f_wakeup_prepare) {
if (no_act_time < 10) { // activity wake up
f_wakeup_prepare = 0;
if (user_config.sleep_enable) exit_light_sleep();
}
// No longer charging? Go deep sleep.
// TODO: don't really know true charge bit logic. I'm just guessing here.
else if (user_config.sleep_enable && (dev_info.rf_charge & 0x01) == 0) {
f_wakeup_prepare = 0;
if (user_config.sleep_mode == SLEEP_MODE_DEEP) {
deep_sleep_handle();
return;
return; // don't need to do anything else
} else if (user_config.sleep_mode == SLEEP_MODE_LIGHT) {
enter_light_sleep();
}
f_wakeup_prepare = 1; // only if light sleep.
}

// sleep check, won't reach here on deep sleep.
Expand Down
22 changes: 12 additions & 10 deletions keyboards/nuphy/air75_v2/ansi/user_kb.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,7 @@ uint16_t sleep_time_delay = SLEEP_TIME_DELAY;
host_driver_t *m_host_driver = 0;
RGB bat_pct_rgb = {.r = 0x80, .g = 0x80, .b = 0x00};

extern bool f_rf_new_adv_ok;
extern report_keyboard_t *keyboard_report;
extern report_nkro_t *nkro_report;
extern host_driver_t rf_host_driver;
extern uint8_t side_mode;
extern uint8_t side_light;
extern uint8_t side_speed;
extern uint8_t side_rgb;
extern uint8_t side_colour;
extern host_driver_t rf_host_driver;

/**
* @brief gpio initial.
Expand Down Expand Up @@ -423,7 +415,7 @@ void user_config_reset(void) {
user_config.ee_side_speed = side_speed;
user_config.ee_side_rgb = side_rgb;
user_config.ee_side_colour = side_colour;
user_config.sleep_enable = true;
user_config.sleep_mode = SLEEP_MODE_DEEP;
user_config.rf_link_timeout = LINK_TIMEOUT_ALT;
eeconfig_update_kb_datablock(&user_config);
}
Expand Down Expand Up @@ -522,4 +514,14 @@ void led_power_handle(void) {
pwr_side_led_on();
}
}
}

void toggle_sleep_mode(void) {
if (user_config.sleep_mode > SLEEP_MODE_OFF) {
user_config.sleep_mode--;
} else {
user_config.sleep_mode = SLEEP_MODE_DEEP;
}
f_sleep_show = 1;
eeconfig_update_kb_datablock(&user_config);
}
42 changes: 38 additions & 4 deletions keyboards/nuphy/air75_v2/ansi/user_kb.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ typedef enum {

} TYPE_RX_STATE;


// clang-format off
#define RF_IDLE 0
#define RF_PAIRING 1
#define RF_LINKING 2
Expand Down Expand Up @@ -108,6 +108,11 @@ typedef enum {
#define DEV_RESET_PRESS_DELAY 30
#define RGB_TEST_PRESS_DELAY 30

#define SLEEP_MODE_OFF 0
#define SLEEP_MODE_LIGHT 1
#define SLEEP_MODE_DEEP 2
// clang-format on

typedef struct {
uint8_t RXDState;
uint8_t RXDLen;
Expand All @@ -120,8 +125,7 @@ typedef struct {
uint8_t RXDBuf[UART_MAX_LEN];
} USART_MGR_STRUCT;

typedef struct
{
typedef struct {
uint8_t link_mode;
uint8_t rf_channel;
uint8_t ble_channel;
Expand All @@ -139,12 +143,41 @@ typedef struct {
uint8_t ee_side_speed;
uint8_t ee_side_rgb;
uint8_t ee_side_colour;
uint8_t sleep_enable;
uint8_t sleep_mode;
uint16_t rf_link_timeout;
uint8_t retain1;
uint8_t retain2;
} user_config_t;

// Globals
extern DEV_INFO_STRUCT dev_info;
extern user_config_t user_config;
extern uint8_t rf_blink_cnt;
extern uint16_t rf_link_show_time;
extern uint16_t side_led_last_act;
extern bool f_bat_hold;
extern bool f_sys_show;
extern bool f_sleep_show;
extern RGB bat_pct_rgb;
extern bool f_rf_sw_press;
extern bool f_dev_reset_press;
extern bool f_bat_num_show;
extern bool f_rgb_test_press;
extern uint16_t no_act_time;
extern uint8_t rf_sw_temp;
extern uint16_t rf_sw_press_delay;
extern uint16_t rf_linking_time;
extern uint16_t sleep_time_delay;
extern bool f_wakeup_prepare;
extern bool f_rf_new_adv_ok;
extern report_keyboard_t *keyboard_report;
extern report_nkro_t * nkro_report;
extern uint8_t side_mode;
extern uint8_t side_light;
extern uint8_t side_speed;
extern uint8_t side_rgb;
extern uint8_t side_colour;

void dev_sts_sync(void);
void rf_uart_init(void);
void rf_device_init(void);
Expand All @@ -171,4 +204,5 @@ void load_eeprom_data(void);
void user_config_reset(void);
void user_set_rgb_color(int index, uint8_t red, uint8_t green, uint8_t blue);
void led_power_handle(void);
void toggle_sleep_mode(void);
uint8_t uart_send_cmd(uint8_t cmd, uint8_t ack_cnt, uint8_t delayms);

0 comments on commit 3a85bcb

Please sign in to comment.