FreeTRX/MDUV380_firmware/application/source/io/keyboard.c
2026-07-06 08:45:33 +02:00

705 lines
18 KiB
C

/*
* Copyright (C) 2019 Kai Ludwig, DG4KLU
* Copyright (C) 2019-2020 Alex, DL4LEX
* Copyright (C) 2019-2025 Roger Clark, VK3KYY / G4KYF
* Daniel Caujolle-Bert, F1RMB
* Colin Durbridge, G4EML
*
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. Use of this source code or binary releases for commercial purposes is strictly forbidden. This includes, without limitation,
* incorporation in a commercial product or incorporation into a product or project which allows commercial use.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "io/keyboard.h"
#include "interfaces/pit.h"
#include "functions/settings.h"
#include "interfaces/gpio.h"
#include "interfaces/adc.h"
#include "io/buttons.h"
// Keyboard Keys
typedef struct
{
GPIO_TypeDef *GPIOPort;
uint16_t GPIOPin;
uint16_t Key;
} KeyboardKeySetting_t;
static char oldKeyboardCode;
static uint32_t keyDebounceScancode;
static int keyDebounceCounter;
static uint8_t keyState;
static char keypadAlphaKey;
static int keypadAlphaIndex;
volatile bool keypadAlphaEnable;
volatile bool keypadLocked = false;
#if defined(PLATFORM_MD2017)
// 360 turn is 8/9 pulses, but handling one pulse as an key event is
// a bit too reactive. Hence, increasing the pulse per event is a bit better.
// Since touching the trackball generate an unwanted event, 99% of the time is the non
// desired direction, at least (1 + trackballMotion) is considered as an event, and any
// pulse from other direction resets the pulse count.
static int32_t trackballPulsesPerEvent = TRACKBALL_FAST_MOTION;
#endif
/*
static const uint32_t keyMap[] = {
KEY_1, KEY_2, KEY_3, KEY_GREEN,
KEY_4, KEY_5, KEY_6, KEY_UP,
KEY_7, KEY_8, KEY_9, KEY_DOWN,
KEY_STAR, KEY_0, KEY_HASH, KEY_RED,
};
*/
#if defined(PLATFORM_MD2017)
volatile trackballData_t trackballData =
{
.Direction = '?',
.Count = 0
};
#else
volatile rotaryData_t rotaryData =
{
.lastB = (GPIO_PinState)(GPIO_PIN_SET + 1), // To be sure it will be different on the first run (Hackish ? Yeah !)
.Count = 0,
.Direction = 0
};
#endif
enum KEY_STATE
{
KEY_IDLE = 0,
KEY_DEBOUNCE,
KEY_PRESS,
KEY_WAITLONG,
KEY_REPEAT,
KEY_WAIT_RELEASED
};
static const char keypadAlphaMap[11][31] = {
"0 ",
"1.!,@-:?()~/[]#<>=*+$%'`&|_^{}",
"abc2ABC",
"def3DEF",
"ghi4GHI",
"jkl5JKL",
"mno6MNO",
"pqrs7PQRS",
"tuv8TUV",
"wxyz9WXYZ",
"*"
};
#define KEYBOARD_KEYS_PER_ROW 8U
static const struct
{
GPIO_TypeDef *GPIOCtrlPort;
uint16_t GPIOCtrlPin;
KeyboardKeySetting_t Rows[KEYBOARD_KEYS_PER_ROW];
} KeyboardMatrix[] =
#if defined(PLATFORM_MDUV380)
{
{
KEYPAD_ROW0_GPIO_Port,
KEYPAD_ROW0_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_1 },
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_2 },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_3 },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_4 },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_5 },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_6 },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_0 },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_STAR }
}
},
{
KEYPAD_ROW1_GPIO_Port,
KEYPAD_ROW1_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_GREEN },
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_FRONT_UP },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_FRONT_DOWN },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_7 },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_8 },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_9 },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_HASH },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_RED }
}
},
{
KEYPAD_ROW2_GPIO_Port,
KEYPAD_ROW2_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_NONE },
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_NONE },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_NONE },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_NONE },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_NONE },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_NONE },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_NONE },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_NONE }
}
}
};
#elif defined(PLATFORM_RT84_DM1701)
{
{
KEYPAD_ROW0_GPIO_Port,
KEYPAD_ROW0_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_1 },
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_4 },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_7 },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_STAR },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_FRONT_UP },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_RIGHT },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_LEFT },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_NONE }
}
},
{
KEYPAD_ROW1_GPIO_Port,
KEYPAD_ROW1_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_2 },
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_5 },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_8 },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_0 },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_FRONT_DOWN },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_RED },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_GREEN },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_NONE }
}
},
{
KEYPAD_ROW2_GPIO_Port,
KEYPAD_ROW2_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_3 },
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_6 },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_9 },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_HASH },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_NONE },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_NONE },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_NONE },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_NONE }
}
}
};
#elif defined(PLATFORM_MD2017)
{
{
KEYPAD_ROW0_GPIO_Port,
KEYPAD_ROW0_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_1 },
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_2 },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_3 },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_4 },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_5 },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_6 },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_0 },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_STAR }
}
},
{
KEYPAD_ROW1_GPIO_Port,
KEYPAD_ROW1_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_LEFT },//P1
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_GREEN },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_RED },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_7 },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_8 },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_9 },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_HASH },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_RIGHT }//P2
}
},
{
KEYPAD_ROW2_GPIO_Port,
KEYPAD_ROW2_Pin,
{
{ LCD_D0_GPIO_Port, LCD_D0_Pin, KEY_NONE },
{ LCD_D1_GPIO_Port, LCD_D1_Pin, KEY_NONE },
{ LCD_D2_GPIO_Port, LCD_D2_Pin, KEY_NONE },
{ LCD_D3_GPIO_Port, LCD_D3_Pin, KEY_NONE },
{ LCD_D4_GPIO_Port, LCD_D4_Pin, KEY_FRONT_DOWN },
{ LCD_D5_GPIO_Port, LCD_D5_Pin, KEY_NONE },
{ LCD_D6_GPIO_Port, LCD_D6_Pin, KEY_FRONT_UP },
{ LCD_D7_GPIO_Port, LCD_D7_Pin, KEY_NONE }
}
}
};
#endif
void keyboardInit(void)
{
//gpioInitKeyboard();
oldKeyboardCode = 0;
keyDebounceScancode = 0;
keyDebounceCounter = 0;
keypadAlphaEnable = false;
keypadAlphaIndex = 0;
keypadAlphaKey = 0;
keyState = KEY_IDLE;
keypadLocked = false;
#if defined(PLATFORM_MD2017)
trackballReset();
#endif
}
void keyboardReset(void)
{
oldKeyboardCode = 0;
keypadAlphaEnable = false;
keypadAlphaIndex = 0;
keypadAlphaKey = 0;
keyState = KEY_WAIT_RELEASED;
#if defined(PLATFORM_MD2017)
trackballReset();
#endif
}
uint32_t keyboardRead(void)
{
uint32_t result = KEY_NONE;
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
uint32_t portD_pins = LCD_D0_Pin | LCD_D1_Pin | LCD_D2_Pin | LCD_D3_Pin;
uint32_t portE_pins = LCD_D4_Pin | LCD_D5_Pin | LCD_D6_Pin | LCD_D7_Pin;
// VK3KYY
// Extra code added to force drive the GPIO pins low, even though the FSMC should have left them in LOW
// Possibly errata in the STM silicon when changing from FSMC to GPIO use of the ports seems to be causing a glitch on some radios
// Which is momentarily driving the GPIO input pins High prior to them being read, which causes phantom key and button presses
HAL_GPIO_WritePin(GPIOD, portD_pins, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE, portE_pins, GPIO_PIN_RESET);
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Pin = portD_pins;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = portE_pins;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
for(volatile int xx = 0; xx < 10; xx++); // arbitrary settling delay
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pin = portD_pins;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = portE_pins;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
for (size_t i = 0; i < (sizeof(KeyboardMatrix) / sizeof(KeyboardMatrix[0])); i++)
{
//Set the Row Pin as Output
GPIO_InitStruct.Pin = KeyboardMatrix[i].GPIOCtrlPin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(KeyboardMatrix[i].GPIOCtrlPort, &GPIO_InitStruct);
//Set the row pin high to select that row of keys
HAL_GPIO_WritePin(KeyboardMatrix[i].GPIOCtrlPort, KeyboardMatrix[i].GPIOCtrlPin, GPIO_PIN_SET);
for(volatile int xx = 0; xx < 100; xx++); // arbitrary settling delay
for (size_t k = 0; k < KEYBOARD_KEYS_PER_ROW; k++)
{
if((KeyboardMatrix[i].Rows[k].Key != KEY_NONE) &&
(HAL_GPIO_ReadPin(KeyboardMatrix[i].Rows[k].GPIOPort, KeyboardMatrix[i].Rows[k].GPIOPin) == GPIO_PIN_SET))
{
result = KeyboardMatrix[i].Rows[k].Key;
break;
}
}
//set the row pin back to floating. This prevents conflicts between multiple key presses.
GPIO_InitStruct.Pin = KeyboardMatrix[i].GPIOCtrlPin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(KeyboardMatrix[i].GPIOCtrlPort, &GPIO_InitStruct);
// Stop on first down key (we don't support multiple key presses).
if (result != KEY_NONE)
{
break;
}
}
return result;
}
bool keyboardKeyIsDTMFKey(char key)
{
switch (key)
{
case KEY_0 ... KEY_9:
case KEY_STAR:
case KEY_HASH:
case KEY_A:
case KEY_B:
case KEY_C:
case KEY_D:
return true;
}
return false;
}
#if defined(PLATFORM_MD2017)
void trackballReset(void)
{
trackballData.Direction = '?';
trackballData.Count = 0;
}
void trackballSetMotion(bool fast)
{
trackballPulsesPerEvent = (fast ? TRACKBALL_FAST_MOTION : TRACKBALL_SLOW_MOTION);
trackballReset();
}
void trackballISR(uint16_t pin)
{
uint8_t x = '?';
switch (pin)
{
case TRACKBALL_UP_Pin:
x = 'U';
break;
case TRACKBALL_DOWN_Pin:
x = 'D';
break;
case TRACKBALL_LEFT_Pin:
x = 'L';
break;
case TRACKBALL_RIGHT_Pin:
x = 'R';
break;
default:
trackballData.Direction = '?';
trackballData.Count = 0;
break;
}
if (x != '?')
{
if (trackballData.Direction == x)
{
trackballData.Count++;
}
else
{
trackballData.Direction = x;
trackballData.Count = 1;
}
}
}
#else
void rotaryEncoderISR(void)
{
GPIO_PinState pinA = HAL_GPIO_ReadPin(ROTARY_SW_A_GPIO_Port, ROTARY_SW_A_Pin);
GPIO_PinState pinB = HAL_GPIO_ReadPin(ROTARY_SW_B_GPIO_Port, ROTARY_SW_B_Pin);
if (pinB != rotaryData.lastB)
{
rotaryData.lastB = pinB;
rotaryData.Direction = ((pinA == pinB) ? -1 : 1);
rotaryData.Count += rotaryData.Direction;
}
}
#endif
void keyboardCheckKeyEvent(keyboardCode_t *keys, int *event)
{
uint32_t scancode = 0;
char keycode = 0;
bool validKey;
int newAlphaKey;
uint32_t tmp_timer_keypad;
uint32_t keypadTimerLong = nonVolatileSettings.keypadTimerLong * 100;
uint32_t keypadTimerRepeat = nonVolatileSettings.keypadTimerRepeat * 100;
#if defined(PLATFORM_MD2017)
bool trackballEnabled = settingsIsOptionBitSet(BIT_TRACKBALL_ENABLED);
#endif
*event = EVENT_KEY_NONE;
keys->event = 0;
keys->key = KEY_NONE;
#if defined(PLATFORM_MD2017)
if (trackballEnabled &&
(trackballData.Count > (trackballPulsesPerEvent + 1))) // Valid trackball event are started after two consecutive pulses in the same direction
{
switch (trackballData.Direction)
{
case 'U':
keys->key = KEY_UP;
break;
case 'D':
keys->key = KEY_DOWN;
break;
case 'L':
keys->key = KEY_LEFT;
break;
case 'R':
keys->key = KEY_RIGHT;
break;
}
keys->event = KEY_MOD_UP | KEY_MOD_PRESS;
*event = EVENT_KEY_CHANGE;
trackballData.Count -= trackballPulsesPerEvent; // Only decrease one event at a time.
return;
}
else
{
if (trackballEnabled == false)
{
trackballReset();
}
keycode = (char) keyboardRead();
scancode = keycode;
}
#else
if (rotaryData.Direction != 0)
{
keys->key = (rotaryData.Direction == 1) ? KEY_ROTARY_INCREMENT : KEY_ROTARY_DECREMENT;
keys->event = KEY_MOD_UP | KEY_MOD_PRESS; // Hack send both Up and Down events because the menus use KEY_MOD_PRESS but the VFO uses KEY_MOD_UP
*event = EVENT_KEY_CHANGE;
rotaryData.Direction = 0;
return;
}
else
{
keycode = (char) keyboardRead();
scancode = keycode;
}
#endif
validKey = true;
if (keyState > KEY_DEBOUNCE && !validKey)
{
keyState = KEY_WAIT_RELEASED;
}
switch (keyState)
{
case KEY_IDLE:
if (keycode != 0)
{
keyState = KEY_DEBOUNCE;
keyDebounceCounter = 0;
keyDebounceScancode = scancode;
oldKeyboardCode = 0;
}
taskENTER_CRITICAL();
tmp_timer_keypad = timer_keypad_timeout;
taskEXIT_CRITICAL();
if (tmp_timer_keypad == 0 && keypadAlphaKey != 0)
{
keys->key = keypadAlphaMap[keypadAlphaKey - 1][keypadAlphaIndex];
keys->event = KEY_MOD_PRESS;
*event = EVENT_KEY_CHANGE;
keypadAlphaKey = 0;
}
break;
case KEY_DEBOUNCE:
keyDebounceCounter++;
if (keyDebounceCounter > KEY_DEBOUNCE_COUNTER)
{
if (keyDebounceScancode == scancode)
{
oldKeyboardCode = keycode;
keyState = KEY_PRESS;
}
else
{
keyState = KEY_WAIT_RELEASED;
}
}
break;
case KEY_PRESS:
keys->key = keycode;
keys->event = KEY_MOD_DOWN | KEY_MOD_PRESS;
*event = EVENT_KEY_CHANGE;
taskENTER_CRITICAL();
timer_keypad = keypadTimerLong;
timer_keypad_timeout = 1000;
taskEXIT_CRITICAL();
keyState = KEY_WAITLONG;
if (keypadAlphaEnable)
{
newAlphaKey = 0;
if ((keycode >= '0') && (keycode <= '9'))
{
newAlphaKey = (keycode - '0') + 1;
}
else if (keycode == KEY_STAR)
{
newAlphaKey = 11;
}
if (keypadAlphaKey == 0)
{
if (newAlphaKey != 0)
{
keypadAlphaKey = newAlphaKey;
keypadAlphaIndex = 0;
}
}
else
{
if (newAlphaKey == keypadAlphaKey)
{
keypadAlphaIndex++;
if (keypadAlphaMap[keypadAlphaKey - 1][keypadAlphaIndex] == 0)
{
keypadAlphaIndex = 0;
}
}
}
if (keypadAlphaKey != 0)
{
if (newAlphaKey == keypadAlphaKey)
{
keys->key = keypadAlphaMap[keypadAlphaKey - 1][keypadAlphaIndex];
keys->event = KEY_MOD_PREVIEW;
}
else
{
keys->key = keypadAlphaMap[keypadAlphaKey - 1][keypadAlphaIndex];
keys->event = KEY_MOD_PRESS;
*event = EVENT_KEY_CHANGE;
keypadAlphaKey = newAlphaKey;
keypadAlphaIndex = -1;
keyState = KEY_PRESS;
}
}
}
break;
case KEY_WAITLONG:
if (keycode == 0)
{
keys->key = oldKeyboardCode;
keys->event = KEY_MOD_UP;
*event = EVENT_KEY_CHANGE;
keyState = KEY_IDLE;
}
else
{
taskENTER_CRITICAL();
tmp_timer_keypad = timer_keypad;
taskEXIT_CRITICAL();
if (tmp_timer_keypad == 0)
{
taskENTER_CRITICAL();
timer_keypad = keypadTimerRepeat;
taskEXIT_CRITICAL();
keys->key = keycode;
keys->event = KEY_MOD_LONG | KEY_MOD_DOWN;
*event = EVENT_KEY_CHANGE;
keyState = KEY_REPEAT;
}
}
break;
case KEY_REPEAT:
if (keycode == 0)
{
keys->key = oldKeyboardCode;
keys->event = KEY_MOD_LONG | KEY_MOD_UP;
*event = EVENT_KEY_CHANGE;
keyState = KEY_IDLE;
}
else
{
taskENTER_CRITICAL();
tmp_timer_keypad = timer_keypad;
taskEXIT_CRITICAL();
keys->key = keycode;
keys->event = KEY_MOD_LONG;
*event = EVENT_KEY_CHANGE;
if (tmp_timer_keypad == 0)
{
taskENTER_CRITICAL();
timer_keypad = keypadTimerRepeat;
taskEXIT_CRITICAL();
if ((keys->key == KEY_LEFT) || (keys->key == KEY_RIGHT)
|| (keys->key == KEY_UP) || (keys->key == KEY_DOWN) || (keys->key == KEY_FRONT_DOWN) || (keys->key == KEY_FRONT_UP))
{
keys->event = (KEY_MOD_LONG | KEY_MOD_PRESS);
}
}
}
break;
case KEY_WAIT_RELEASED:
if (scancode == 0)
{
keyState = KEY_IDLE;
}
break;
}
}
/*
void buttonsFrontPanelDump(void)
{
uint16_t keys = buttonsFrontPanelRead();
char buffer[17];
snprintf(buffer, sizeof(buffer), "K: 0x%03X %ld", keys, rotaryData.Count);
displayPrintCentered(40, buffer, FONT_SIZE_3);
}
*/