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

Add long press #88

Merged
merged 13 commits into from
Aug 24, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Fixed compilation errors with GCC 12 (@Foxushka)
- Added documentation for JLink (@xianglin1998)
- Added support for ST-Link and debugging documentation (@derGraph)
- Added support for long-press of buttons
nemanjan00 marked this conversation as resolved.
Show resolved Hide resolved

## [v1.0][2023-06-06]
25 changes: 25 additions & 0 deletions firmware/application/src/app_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,29 @@ data_frame_tx_t *cmd_processor_set_button_press_config(uint16_t cmd, uint16_t st
return data_frame_make(cmd, status, 0, NULL);
}

data_frame_tx_t *cmd_processor_get_long_button_press_config(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
uint8_t button_press_config;
if (length == 1 && is_settings_button_type_valid(data[0])) {
button_press_config = settings_get_long_button_press_config(data[0]);
status = STATUS_DEVICE_SUCCESS;
} else {
length = 0;
status = STATUS_PAR_ERR;
}
return data_frame_make(cmd, status, length, (uint8_t *)(&button_press_config));
}

data_frame_tx_t *cmd_processor_set_long_button_press_config(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length == 2 && is_settings_button_type_valid(data[0])) {
settings_set_long_button_press_config(data[0], data[1]);
status = STATUS_DEVICE_SUCCESS;
} else {
length = 0;
status = STATUS_PAR_ERR;
}
return data_frame_make(cmd, status, 0, NULL);
}

#if defined(PROJECT_CHAMELEON_ULTRA)

data_frame_tx_t *cmd_processor_14a_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
Expand Down Expand Up @@ -783,6 +806,8 @@ static cmd_data_map_t m_data_cmd_map[] = {
{ DATA_CMD_GET_BATTERY_INFO, NULL, cmd_processor_get_battery_info, NULL },
{ DATA_CMD_GET_BUTTON_PRESS_CONFIG, NULL, cmd_processor_get_button_press_config, NULL },
{ DATA_CMD_SET_BUTTON_PRESS_CONFIG, NULL, cmd_processor_set_button_press_config, NULL },
{ DATA_CMD_GET_LONG_BUTTON_PRESS_CONFIG, NULL, cmd_processor_get_long_button_press_config, NULL },
{ DATA_CMD_SET_LONG_BUTTON_PRESS_CONFIG, NULL, cmd_processor_set_long_button_press_config, NULL },

#if defined(PROJECT_CHAMELEON_ULTRA)

Expand Down
62 changes: 54 additions & 8 deletions firmware/application/src/app_main.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include "nordic_common.h"
#include "nrf.h"
Expand Down Expand Up @@ -41,9 +42,17 @@ NRF_LOG_MODULE_REGISTER();

// Defining soft timers
APP_TIMER_DEF(m_button_check_timer); // Timer for button debounce

static uint32_t m_last_btn_press = 0;

static bool m_is_btn_long_press = false;

static bool m_is_b_btn_press = false;
static bool m_is_a_btn_press = false;

static bool m_is_b_btn_release = false;
static bool m_is_a_btn_release = false;

// cpu reset reason
static uint32_t m_reset_source;
static uint32_t m_gpregret_val;
Expand Down Expand Up @@ -152,12 +161,41 @@ static void timer_button_event_handle(void *arg) {
if (settings_get_button_press_config('b') != SettingsButtonDisable) {
NRF_LOG_INFO("BUTTON_LEFT"); // Button B?
m_is_b_btn_press = true;
m_last_btn_press = app_timer_cnt_get();
}
}
if (pin == BUTTON_2) {
if (settings_get_button_press_config('a') != SettingsButtonDisable) {
NRF_LOG_INFO("BUTTON_RIGHT"); // Button A?
m_is_a_btn_press = true;
m_last_btn_press = app_timer_cnt_get();
}
}
}

if (nrf_gpio_pin_read(pin) == 0) {
uint32_t now = app_timer_cnt_get();
uint32_t ticks = app_timer_cnt_diff_compute(now, m_last_btn_press);

uint32_t time = ticks * ((APP_TIMER_CONFIG_RTC_FREQUENCY + 1 ) * 1000 ) / APP_TIMER_CLOCK_FREQ;

bool is_long_press = time > 1000;
nemanjan00 marked this conversation as resolved.
Show resolved Hide resolved

if (pin == BUTTON_1 && m_is_b_btn_press == true) {
// If button is disable, we can didn't dispatch key event.
if (settings_get_button_press_config('b') != SettingsButtonDisable) {
NRF_LOG_INFO("BUTTON_LEFT_RELEASE"); // Button B?
m_is_b_btn_release = true;
m_is_b_btn_press = false;
m_is_btn_long_press = is_long_press;
}
}
if (pin == BUTTON_2 && m_is_a_btn_press == true) {
if (settings_get_button_press_config('a') != SettingsButtonDisable) {
NRF_LOG_INFO("BUTTON_RIGHT_RELEASE"); // Button A?
m_is_a_btn_release = true;
m_is_a_btn_press = false;
m_is_btn_long_press = is_long_press;
}
}
}
Expand All @@ -173,7 +211,7 @@ static void button_init(void) {
APP_ERROR_CHECK(err_code);

// Configure SENSE mode, select false for sense configuration
nrf_drv_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(false);
nrf_drv_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
in_config.pull = NRF_GPIO_PIN_PULLDOWN; // Pulldown

// Configure key binding POTR
Expand Down Expand Up @@ -635,14 +673,22 @@ static void run_button_function_by_settings(settings_button_function_t sbf) {
extern bool g_usb_led_marquee_enable;
static void button_press_process(void) {
// Make sure that one of the AB buttons has a click event
if (m_is_b_btn_press || m_is_a_btn_press) {
if (m_is_a_btn_press) {
run_button_function_by_settings(settings_get_button_press_config('a'));
m_is_a_btn_press = false;
if (m_is_b_btn_release || m_is_a_btn_release) {
if (m_is_a_btn_release) {
if(!m_is_btn_long_press) {
run_button_function_by_settings(settings_get_button_press_config('a'));
} else {
run_button_function_by_settings(settings_get_long_button_press_config('a'));
}
m_is_a_btn_release = false;
}
if (m_is_b_btn_press) {
run_button_function_by_settings(settings_get_button_press_config('b'));
m_is_b_btn_press = false;
if (m_is_b_btn_release) {
if(!m_is_btn_long_press) {
run_button_function_by_settings(settings_get_button_press_config('b'));
} else {
run_button_function_by_settings(settings_get_long_button_press_config('b'));
}
m_is_b_btn_release = false;
}
// Disable led marquee for usb at button pressed.
g_usb_led_marquee_enable = false;
Expand Down
2 changes: 2 additions & 0 deletions firmware/application/src/data_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#define DATA_CMD_GET_BATTERY_INFO (1025)
#define DATA_CMD_GET_BUTTON_PRESS_CONFIG (1026)
#define DATA_CMD_SET_BUTTON_PRESS_CONFIG (1027)
#define DATA_CMD_GET_LONG_BUTTON_PRESS_CONFIG (1028)
#define DATA_CMD_SET_LONG_BUTTON_PRESS_CONFIG (1029)

//
// ******************************************************************
Expand Down
54 changes: 54 additions & 0 deletions firmware/application/src/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ void settings_migrate(void) {
settings_update_version_for_config();
break;

case 2:
config.button_a_long_press = SettingsButtonCloneIcUid;
config.button_b_long_press = SettingsButtonCloneIcUid;

/*
* When needed migrations can be implemented like this:
*
Expand Down Expand Up @@ -167,6 +171,31 @@ uint8_t settings_get_button_press_config(char which) {
return SettingsButtonDisable;
}

/**
* @brief Get the long button press config
*
* @param which 'a' or 'b'
* @return uint8_t @link{ settings_button_function_t }
*/
uint8_t settings_get_long_button_press_config(char which) {
switch (which) {
case 'a':
case 'A':
return config.button_a_long_press;

case 'b':
case 'B':
return config.button_b_long_press;

default:
// can't to here.
APP_ERROR_CHECK_BOOL(false);
break;
}
// can't to here.
return SettingsButtonDisable;
}

/**
* @brief Set the button press config
*
Expand All @@ -191,3 +220,28 @@ void settings_set_button_press_config(char which, uint8_t value) {
break;
}
}

/**
* @brief Set the long button press config
*
* @param which 'a' or 'b'
* @param value @link{ settings_button_function_t }
*/
void settings_set_long_button_press_config(char which, uint8_t value) {
switch (which) {
case 'a':
case 'A':
config.button_a_long_press = value;
break;

case 'b':
case 'B':
config.button_b_long_press = value;
break;

default:
// can't to here.
APP_ERROR_CHECK_BOOL(false);
break;
}
}
8 changes: 7 additions & 1 deletion firmware/application/src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include "utils.h"

#define SETTINGS_CURRENT_VERSION 2
#define SETTINGS_CURRENT_VERSION 3

typedef enum {
SettingsAnimationModeFull = 0U,
Expand Down Expand Up @@ -36,6 +36,10 @@ typedef struct ALIGN_U32 {
uint8_t button_a_press : 4;
uint8_t button_b_press : 4;

// 1 byte
uint8_t button_a_long_press : 4;
uint8_t button_b_long_press : 4;

// 8 byte
uint32_t reserved1;
uint32_t reserved2;
Expand All @@ -48,7 +52,9 @@ uint8_t settings_save_config(void);
uint8_t settings_get_animation_config(void);
void settings_set_animation_config(uint8_t value);
uint8_t settings_get_button_press_config(char which);
uint8_t settings_get_long_button_press_config(char which);
void settings_set_button_press_config(char which, uint8_t value);
void settings_set_long_button_press_config(char which, uint8_t value);
bool is_settings_button_type_valid(char type);

#endif
10 changes: 9 additions & 1 deletion software/script/chameleon_cli_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1318,9 +1318,12 @@ def on_exec(self, args: argparse.Namespace):
print("")
for button in button_list:
resp = self.cmd.get_button_press_fun(button)
resp_long = self.cmd.get_long_button_press_fun(button)
button_fn = chameleon_cmd.ButtonPressFunction.from_int(resp.data[0])
button_long_fn = chameleon_cmd.ButtonPressFunction.from_int(resp_long.data[0])
print(f" - {colorama.Fore.GREEN}{button}{colorama.Style.RESET_ALL}: {button_fn}")
print(f" usage: {button_fn.usage()}")
print(f" long press usage: {button_long_fn.usage()}")
print("")
print(" - Successfully get button function from settings")

Expand All @@ -1330,6 +1333,7 @@ class HWButtonSettingsSet(DeviceRequiredUnit):

def args_parser(self) -> ArgumentParserNoExit:
parser = ArgumentParserNoExit()
parser.add_argument('-l', '--long', type=int, required=True, help="1 is Long or 0 Short", choices=[0, 1])
nemanjan00 marked this conversation as resolved.
Show resolved Hide resolved
parser.add_argument('-b', type=str, required=True,
help="Change the function of the pressed button(?).",
choices=chameleon_cmd.ButtonType.list_str())
Expand All @@ -1344,5 +1348,9 @@ def args_parser(self) -> ArgumentParserNoExit:
def on_exec(self, args: argparse.Namespace):
button = chameleon_cmd.ButtonType.from_str(args.b)
function = chameleon_cmd.ButtonPressFunction.from_int(args.f)
self.cmd.set_button_press_fun(button, function)
long = args.long == 1
if long:
self.cmd.set_long_button_press_fun(button, function)
else:
self.cmd.set_button_press_fun(button, function)
print(" - Successfully set button function to settings")
21 changes: 21 additions & 0 deletions software/script/chameleon_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
DATA_CMD_GET_BUTTON_PRESS_CONFIG = 1026
DATA_CMD_SET_BUTTON_PRESS_CONFIG = 1027

DATA_CMD_GET_LONG_BUTTON_PRESS_CONFIG = 1028
DATA_CMD_SET_LONG_BUTTON_PRESS_CONFIG = 1029

DATA_CMD_SCAN_14A_TAG = 2000
DATA_CMD_MF1_SUPPORT_DETECT = 2001
DATA_CMD_MF1_NT_LEVEL_DETECT = 2002
Expand Down Expand Up @@ -769,6 +772,24 @@ def set_button_press_fun(self, button: ButtonType, function: ButtonPressFunction
bytearray([button, function])
)

@expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS)
def get_long_button_press_fun(self, button: ButtonType):
"""
Get config of button press function
"""
return self.device.send_cmd_sync(DATA_CMD_GET_LONG_BUTTON_PRESS_CONFIG, 0x00, bytearray([button]))

@expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS)
def set_long_button_press_fun(self, button: ButtonType, function: ButtonPressFunction):
"""
Set config of button press function
"""
return self.device.send_cmd_sync(
DATA_CMD_SET_LONG_BUTTON_PRESS_CONFIG,
0x00,
bytearray([button, function])
)

if __name__ == '__main__':
# connect to chameleon
dev = chameleon_com.ChameleonCom()
Expand Down
Loading