/*
* Author: Pawel Jablonski
* E-mail: pj@xirx.net
* WWW: xirx.net
* GIT: git.xirx.net
*
* License: You can use this code however you like
* but leave information about the original author.
* Code is free for non-commercial and commercial use.
*/
#include <stm32f0xx.h>
#include <stm32f0xx_hal.h>
#include <stm32f0xx_hal_gpio.h>
#include <stm32f0xx_hal_rcc.h>
#include <system_stm32f0xx.h>
#include "type.h"
#include "led.h"
#include "keyboard.h"
#define KEYBOARD_COLUMN_QUANTITY 15 //!< Quantity of key columns of keyboard
#define KEYBOARD_ROW_QUANTITY 5 //!< Quantity of key rows of keyboard
#define KEYBOARD_STATUS_RETRY 5 //!< How many times read status of all keys
#define KEYBOARD_STATUS_MIN 4 //!< How many statuses must be high to count a key as clicked
#define KEYBOARD_BUFFER_SIZE 16 //!< Global input buffer size
#define KEYBOARD_LOCAL_BUFFER_SIZE 8 //!< Local input buffer size for the read function
#define KEYBOARD_KEY_ESC 0x1b //!< Escape key code
#define KEYBOARD_KEY_BACKSPACE 0x08 //!< Backspace key code
#define KEYBOARD_KEY_TAB 0x09 //!< Tab key code
#define KEYBOARD_KEY_ENTER 0x0d //!< Enter key code
#define KEYBOARD_KEY_DELETE 0x7f //!< Delete key code
#define KEYBOARD_KEY_UP 0x11 //!< Up arrow key code
#define KEYBOARD_KEY_DOWN 0x12 //!< Down arrow key code
#define KEYBOARD_KEY_LEFT 0x13 //!< Left arrow key code
#define KEYBOARD_KEY_RIGHT 0x14 //!< Right arrow key code
#define KEYBOARD_CTRL_MASK 0x80 //!< Mask used to check if the control key is pressed too
#define KEYBOARD_CTRL_MIN_CODE 0x20 //!< Minimum key code where the control mask can be set
#define KEYBOARD_POS_SHIFT_LEFT_COLUMN 14 //!< Left shift key column position in the key statuses matrix
#define KEYBOARD_POS_SHIFT_LEFT_ROW 1 //!< Left shift key row position in the key statuses matrix
#define KEYBOARD_POS_SHIFT_RIGHT_COLUMN 3 //!< Right shift key column position in the key statuses matrix
#define KEYBOARD_POS_SHIFT_RIGHT_ROW 1 //!< Right shift key row position in the key statuses matrix
#define KEYBOARD_POS_CAPSLOCK_COLUMN 14 //!< Capslock key column position in the key statuses matrix
#define KEYBOARD_POS_CAPSLOCK_ROW 2 //!< Capslock key row position in the key statuses matrix
#define KEYBOARD_POS_CTRL_COLUMN 14 //!< Control key column position in the key statuses matrix
#define KEYBOARD_POS_CTRL_ROW 0 //!< Control key row position in the key statuses matrix
//! Keyboard matrix with data for every key for down and upper case
static const unsigned char keyCode[2][KEYBOARD_ROW_QUANTITY][KEYBOARD_COLUMN_QUANTITY] = {
{
{ 0x00, KEYBOARD_KEY_RIGHT, KEYBOARD_KEY_DOWN, KEYBOARD_KEY_LEFT, 0x00, 0x00, 0x00, 0x00, 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0xff },
{ 0x00, KEYBOARD_KEY_DELETE, KEYBOARD_KEY_UP, 0xff, '/', '.', ',', 'm', 'n', 'b', 'v', 'c', 'x', 'z', 0xff },
{ 0x00, KEYBOARD_KEY_ENTER, 0x00, '\'', ';', 'l', 'k', 'j', 'h', 'g', 'f', 'd', 's', 'a', 0xff },
{ 0x00, '\\', ']', '[', 'p', 'o', 'i', 'u', 'y', 't', 'r', 'e', 'w', 'q', KEYBOARD_KEY_TAB },
{ KEYBOARD_KEY_BACKSPACE, '`', '+', '-', '0', '9', '8', '7', '6', '5', '4', '3', '2', '1', KEYBOARD_KEY_ESC }
},
{
{ 0x00, KEYBOARD_KEY_RIGHT, KEYBOARD_KEY_DOWN, KEYBOARD_KEY_LEFT, 0x00, 0x00, 0x00, 0x00, 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0xff },
{ 0x00, KEYBOARD_KEY_DELETE, KEYBOARD_KEY_UP, 0xff, '?', '>', '<', 'M', 'N', 'B', 'V', 'C', 'X', 'Z', 0xff },
{ 0x00, KEYBOARD_KEY_ENTER, 0x00, '"', ':', 'L', 'K', 'J', 'H', 'G', 'F', 'D', 'S', 'A', 0xff },
{ 0x00, '|', '}', '{', 'P', 'O', 'I', 'U', 'Y', 'T', 'R', 'E', 'W', 'Q', KEYBOARD_KEY_TAB },
{ KEYBOARD_KEY_BACKSPACE, '~', '+', '_', ')', '(', '*', '&', '^', '%', '$', '#', '@', '!', KEYBOARD_KEY_ESC },
}
};
static bool keyLastStatus[KEYBOARD_ROW_QUANTITY][KEYBOARD_COLUMN_QUANTITY]; //!< Last key statuses matrix
static bool capslock = 0; //!< Capslock key status
static unsigned char buffer[KEYBOARD_BUFFER_SIZE]; //!< Circular keyboard input buffer
static volatile unsigned int bufferStart = 0; //!< Data start position
static volatile unsigned int bufferEnd = 0; //!< Data end position
//! Init keyboard and set up the pin outs and inputs
void keyboardInit(void)
{
GPIO_InitTypeDef gpioInit = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
gpioInit.Pin = (GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
gpioInit.Mode = GPIO_MODE_OUTPUT_PP;
gpioInit.Pull = GPIO_NOPULL;
gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &gpioInit);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);
__HAL_RCC_GPIOA_CLK_ENABLE();
gpioInit.Pin = (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
gpioInit.Mode = GPIO_MODE_OUTPUT_PP;
gpioInit.Pull = GPIO_NOPULL;
gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &gpioInit);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
__HAL_RCC_GPIOD_CLK_ENABLE();
gpioInit.Pin = GPIO_PIN_2;
gpioInit.Mode = GPIO_MODE_INPUT;
gpioInit.Pull = GPIO_PULLDOWN;
gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOD, &gpioInit);
for(int i = 0; i < KEYBOARD_ROW_QUANTITY; i++)
{
for(int j = 0; j < KEYBOARD_COLUMN_QUANTITY; j++)
{
keyLastStatus[i][j] = FALSE;
}
}
}
//! Process the keyboard fire event. It reads current keyboard status and adds new data to the input buffer.
void keyboardFire(void)
{
static unsigned char keyStatus[KEYBOARD_ROW_QUANTITY][KEYBOARD_COLUMN_QUANTITY];
bool shift = FALSE;
bool ctrl = FALSE;
unsigned char localBuffer[KEYBOARD_LOCAL_BUFFER_SIZE];
unsigned char localBufferEnd = 0;
for(int i = 0; i < KEYBOARD_ROW_QUANTITY; i++)
{
for(int j = 0; j < KEYBOARD_COLUMN_QUANTITY; j++)
{
keyStatus[i][j] = 0;
}
}
for(int retry = 0; retry < KEYBOARD_STATUS_RETRY; retry++)
{
for(int i = 0; i < KEYBOARD_ROW_QUANTITY; i++)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, ((i & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET));
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, ((i & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET));
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, ((i & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET));
for(int j = 0; j < KEYBOARD_COLUMN_QUANTITY; j++)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, ((j & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET));
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, ((j & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET));
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, ((j & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET));
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, ((j & 0x08) ? GPIO_PIN_SET : GPIO_PIN_RESET));
// wait
{
volatile int w = 15;
while(w--);
}
if(HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_2) == GPIO_PIN_SET)
{
keyStatus[i][j]++;
}
}
}
}
if(keyStatus[KEYBOARD_POS_SHIFT_LEFT_ROW][KEYBOARD_POS_SHIFT_LEFT_COLUMN] >= KEYBOARD_STATUS_MIN)
{
shift = TRUE;
}
else if(keyStatus[KEYBOARD_POS_SHIFT_RIGHT_ROW][KEYBOARD_POS_SHIFT_RIGHT_COLUMN] >= KEYBOARD_STATUS_MIN)
{
shift = TRUE;
}
if(keyStatus[KEYBOARD_POS_CAPSLOCK_ROW][KEYBOARD_POS_CAPSLOCK_COLUMN] >= KEYBOARD_STATUS_MIN)
{
if(!(keyLastStatus[KEYBOARD_POS_CAPSLOCK_ROW][KEYBOARD_POS_CAPSLOCK_COLUMN]))
{
if(capslock)
{
ledSetCapslock(FALSE);
capslock = FALSE;
}
else
{
ledSetCapslock(TRUE);
capslock = TRUE;
}
keyLastStatus[KEYBOARD_POS_CAPSLOCK_ROW][KEYBOARD_POS_CAPSLOCK_COLUMN] = TRUE;
}
}
else
{
keyLastStatus[KEYBOARD_POS_CAPSLOCK_ROW][KEYBOARD_POS_CAPSLOCK_COLUMN] = FALSE;
}
if(keyStatus[KEYBOARD_POS_CTRL_ROW][KEYBOARD_POS_CTRL_COLUMN] >= KEYBOARD_STATUS_MIN)
{
ctrl = TRUE;
}
for(int i = 0; i < KEYBOARD_ROW_QUANTITY; i++)
{
for(int j = 0; j < KEYBOARD_COLUMN_QUANTITY; j++)
{
if((keyCode[0][i][j] > 0x00) && (keyCode[0][i][j] < 0xff))
{
if(keyStatus[i][j] >= KEYBOARD_STATUS_MIN)
{
if(!(keyLastStatus[i][j]))
{
unsigned char key;
if(((!capslock) && shift) || (capslock && (!shift)))
{
key = keyCode[1][i][j];
}
else
{
key = keyCode[0][i][j];
}
if(ctrl && (key >= KEYBOARD_CTRL_MIN_CODE))
{
key |= KEYBOARD_CTRL_MASK;
}
if(localBufferEnd < KEYBOARD_LOCAL_BUFFER_SIZE)
{
localBuffer[localBufferEnd] = key;
localBufferEnd++;
}
keyLastStatus[i][j] = TRUE;
}
}
else
{
keyLastStatus[i][j] = FALSE;
}
}
}
}
for(int i = 0; i < localBufferEnd; i++)
{
__disable_irq();
{
if(bufferStart == ((bufferEnd + 1) % KEYBOARD_BUFFER_SIZE))
{
__enable_irq();
break;
}
buffer[bufferEnd] = localBuffer[i];
bufferEnd = ((bufferEnd + 1) % KEYBOARD_BUFFER_SIZE);
}
__enable_irq();
}
}
/**
* Read a next char from input buffer
*
* @return Next char from the input buffer
*/
unsigned char keyboardGetKey(void)
{
__disable_irq();
if(bufferStart == bufferEnd)
{
__enable_irq();
return(0x00);
}
else
{
unsigned int first = bufferStart;
bufferStart = ((first + 1) % KEYBOARD_BUFFER_SIZE);
unsigned char val = buffer[first];
__enable_irq();
return(val);
}
}
/**
* Check if is a new data in the input buffer
*
* @return Status of waiting data in the input buffer
*/
bool keyboardIsData(void)
{
__disable_irq();
if(bufferStart == bufferEnd)
{
__enable_irq();
return(FALSE);
}
else
{
__enable_irq();
return(TRUE);
}
}