Advanced Distributed Systems module at HSLU
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

263 lines
7.3 KiB

/*
* Copyright (c) 2019, Erich Styger
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "platform.h"
#if PL_CONFIG_USE_BUTTONS
#include "buttons.h"
#include "McuButton.h"
#include "McuRTOS.h"
#include "McuDebounce.h"
#include "McuRTT.h"
#include "fsl_port.h" /* for KBI and pull up selection */
#include "Event.h"
/* Buttons */
/* User button SW2: PTA14 */
#define PINS_SW2_GPIO GPIOA
#define PINS_SW2_PORT PORTA
#define PINS_SW2_PIN 14U
static McuBtn_Handle_t btnSW2;
bool BTN_SW2ButtonIsPressed(void) {
return McuBtn_IsOn(btnSW2);
}
static uint32_t GetButtons(void) {
uint32_t val = 0;
if (McuBtn_IsOn(btnSW2)) {
val |= BTN_SW2;
}
return val;
}
static void OnDebounceEvent(McuDbnc_EventKinds event, uint32_t buttons);
#define TIMER_PERIOD_MS 20 /* frequency of timer */
static McuDbnc_Desc_t data =
{
.state = MCUDBMC_STATE_IDLE,
.timerPeriodMs = TIMER_PERIOD_MS,
.timer = NULL,
.debounceTimeMs = 100,
.repeatTimeMs = 300,
.longKeyTimeMs = 1000,
.getButtons = GetButtons,
.onDebounceEvent = OnDebounceEvent,
};
static void OnDebounceEvent(McuDbnc_EventKinds event, uint32_t buttons) {
switch(event) {
case MCUDBNC_EVENT_PRESSED:
SEGGER_printf("pressed: %d\r\n", buttons);
EVNT_SetEvent(EVNT_SW1_PRESSED);
break;
case MCUDBNC_EVENT_PRESSED_REPEAT:
SEGGER_printf("repeat: %d\r\n", buttons);
EVNT_SetEvent(EVNT_SW1_PRESSED_REPEAT);
break;
case MCUDBNC_EVENT_LONG_PRESSED:
SEGGER_printf("long pressed: %d\r\n", buttons);
EVNT_SetEvent(EVNT_SW1_LPRESSED);
#if PL_CONFIG_USE_GUI_KEY_NAV
if (buttons&BTN_UP) {
LV_ButtonEvent(LV_BTN_MASK_UP, LV_MASK_PRESSED_LONG);
}
if (buttons&BTN_DOWN) {
LV_ButtonEvent(LV_BTN_MASK_DOWN, LV_MASK_PRESSED_LONG);
}
if (buttons&BTN_LEFT) {
LV_ButtonEvent(LV_BTN_MASK_LEFT, LV_MASK_PRESSED_LONG);
}
if (buttons&BTN_RIGHT) {
LV_ButtonEvent(LV_BTN_MASK_RIGHT, LV_MASK_PRESSED_LONG);
}
if (buttons&BTN_CENTER) {
LV_ButtonEvent(LV_BTN_MASK_CENTER, LV_MASK_PRESSED_LONG);
}
#endif
break;
case MCUDBNC_EVENT_LONG_PRESSED_REPEAT:
SEGGER_printf("long repeat: %d\r\n", buttons);
EVNT_SetEvent(EVNT_SW1_LPRESSED_REPEAT);
break;
case MCUDBNC_EVENT_RELEASED:
SEGGER_printf("released: %d\r\n", buttons);
EVNT_SetEvent(EVNT_SW1_RELEASED);
#if PL_CONFIG_USE_RASPY_UART
RASPYU_OnJoystickEvent(0);
#endif
#if PL_CONFIG_USE_GUI_KEY_NAV
if (buttons&BTN_UP) {
LV_ButtonEvent(LV_BTN_MASK_UP, LV_MASK_RELEASED);
}
if (buttons&BTN_DOWN) {
LV_ButtonEvent(LV_BTN_MASK_DOWN, LV_MASK_RELEASED);
}
if (buttons&BTN_LEFT) {
LV_ButtonEvent(LV_BTN_MASK_LEFT, LV_MASK_RELEASED);
}
if (buttons&BTN_RIGHT) {
LV_ButtonEvent(LV_BTN_MASK_RIGHT, LV_MASK_RELEASED);
}
if (buttons&BTN_CENTER) {
LV_ButtonEvent(LV_BTN_MASK_CENTER, LV_MASK_RELEASED);
}
#endif
break;
default:
case MCUDBNC_EVENT_END:
(void)xTimerStop(data.timer, pdMS_TO_TICKS(100)); /* stop timer */
SEGGER_printf("end: %d\r\n", buttons);
break;
}
}
#if McuLib_CONFIG_SDK_USE_FREERTOS
static void vTimerCallbackDebounce(TimerHandle_t pxTimer) {
/* called with TIMER_PERIOD_MS during debouncing */
(void)pxTimer; /* not used */
McuDbnc_Process(&data);
}
static void StartDebounce(uint32_t buttons, bool fromISR) {
BaseType_t res;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (data.state==MCUDBMC_STATE_IDLE) {
data.scanValue = buttons;
data.state = MCUDBMC_STATE_START;
McuDbnc_Process(&data);
if (fromISR) {
res = xTimerStartFromISR(data.timer, &xHigherPriorityTaskWoken);
} else {
res = xTimerStart(data.timer, pdMS_TO_TICKS(100));
}
#ifdef NDEBUG
(void)res; /* avoid compiler warning about unused variable */
#endif
assert(res==pdPASS);
if (fromISR) {
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
}
#endif
#if !PL_CONFIG_USE_KBI
#if McuLib_CONFIG_SDK_USE_FREERTOS
static void PollButtons(void) {
if (McuBtn_IsOn(btnSW2)) {
StartDebounce(BTN_SW2, false);
}
}
static void BtnTask(void *pv) {
for(;;) {
PollButtons();
vTaskDelay(pdMS_TO_TICKS(50));
}
}
#endif
#else
void PORTA_IRQHandler(void) { /* SW2 is on PORTA (PINS_SW2_PORT) */
uint32_t flags;
flags = GPIO_PortGetInterruptFlags(PINS_SW2_GPIO);
if (flags&(1U<<PINS_SW2_PIN)) {
GPIO_PortClearInterruptFlags(PINS_SW2_GPIO, 1U<<PINS_SW2_PIN);
StartDebounce(BTN_SW2, true);
}
__DSB();
}
#endif
/* because SDK 2.3.0 does not provide this: */
static inline port_pin_config_t PORT_GetPinConfig(PORT_Type *base, uint32_t pin) {
uint32_t addr = (uint32_t)&base->PCR[pin];
return *(port_pin_config_t *)(addr);
}
void BTN_EnablePullup(void) {
/* V2 has no pull-up on the board, need to turn on internal pull-up */
McuBtn_EnablePullResistor(btnSW2);
}
void BTN_Init(void) {
McuBtn_Config_t btnConfig;
McuBtn_GetDefaultConfig(&btnConfig);
btnConfig.isLowActive = true;
btnConfig.hw.gpio = PINS_SW2_GPIO;
btnConfig.hw.port = PINS_SW2_PORT;
btnConfig.hw.pin = PINS_SW2_PIN;
btnSW2 = McuBtn_InitButton(&btnConfig);
#if PL_IS_INTRO_ZUMO_K22_V2
/* has no pull-ups on the board, need to turn on internal pull-ups */
port_pin_config_t portConfig;
portConfig = PORT_GetPinConfig(PINS_SW2_PORT, PINS_SW2_PIN); /* get current config */
portConfig.pullSelect = kPORT_PullUp;
PORT_SetPinConfig(PINS_SW2_PORT, PINS_SW2_PIN, &portConfig);
#endif
#if !PL_LOCAL_CONFIG_USE_RESET_PIN
/* SW1: enable and turn on pull-up resistor for PTA14 (push button) */
// PORT_PDD_SetPinPullSelect(PORTA_BASE_PTR, 14, PORT_PDD_PULL_UP);
// PORT_PDD_SetPinPullEnable(PORTA_BASE_PTR, 14, PORT_PDD_PULL_ENABLE);
/* this is not implemented yet for the SDK: need to disable reset functionality and enable pull-ups */
#endif
#if PL_CONFIG_USE_KBI
PORT_SetPinInterruptConfig(PINS_SW2_PORT, PINS_SW2_PIN, kPORT_InterruptFallingEdge);
/* SW2 is on Port A */
NVIC_SetPriority(PORTA_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
EnableIRQ(PORTA_IRQn);
#elif McuLib_CONFIG_SDK_USE_FREERTOS /* use task for button polling */
if (xTaskCreate(
BtnTask, /* pointer to the task */
"Btn", /* task name for kernel awareness debugging */
500/sizeof(StackType_t), /* task stack size */
(void*)NULL, /* optional task startup argument */
tskIDLE_PRIORITY+4, /* initial priority */
(TaskHandle_t*)NULL /* optional task handle to create */
) != pdPASS)
{
for(;;){} /* error! probably out of memory */
}
#endif
#if McuLib_CONFIG_SDK_USE_FREERTOS
data.timer = xTimerCreate(
"tmrDbnc", /* name */
pdMS_TO_TICKS(TIMER_PERIOD_MS), /* period/time */
pdTRUE, /* auto reload */
(void*)2, /* timer ID */
vTimerCallbackDebounce); /* callback */
if (data.timer==NULL) {
for(;;); /* failure! */
}
#endif
}
void BTN_Deinit(void) {
#if PL_CONFIG_USE_KBI
#if TINYK22_HAT_VERSION==3
DisableIRQ(PORTB_IRQn); /* all buttons are on Port B */
#elif TINYK22_HAT_VERSION==4 || TINYK22_HAT_VERSION==5
DisableIRQ(PORTA_IRQn); /* left and right are on Port A */
DisableIRQ(PORTB_IRQn); /* up, down, push are on Port B */
#endif
#endif
btnSW2 = McuBtn_DeinitButton(btnSW2);
}
#endif /* PL_CONFIG_USE_BUTTONS */