cewkomator/firmware/src/keyboard.cpp

132 lines
2.6 KiB
C++

#include <PCF8574.h>
#include <Wire.h>
#include "constants.h"
#include "debug.h"
#include "buzzer.h"
#include "keyboard.h"
PCF8574 kbd(KBD_I2C_ADDR, &Wire);
/*
Keyboard layout:
row/col 0 1 2 3
0 1 2 3 A
1 4 5 6 B
2 7 8 9 C
3 * 0 # D
*/
const char *allKeys = "123A456B789C*0#D";
const uint8_t digits[16] =
{ 1, 2, 3, KEY_NONE,
4, 5, 6, KEY_NONE,
7, 8, 9, KEY_NONE,
KEY_NONE, 0, KEY_NONE, KEY_NONE};
bool setupKeyboard() {
if (!kbd.begin()) {
Serial.println("Could not initialize keyboard");
return false;
}
if (!kbd.isConnected()) {
Serial.println("Keyboard not connected");
return false;
}
return true;
}
Key previousKey = KEY_NONE;
unsigned long lastPressedAt = 0;
Key getPressedKey();
Key handleKeyboard() {
auto key = getPressedKey();
// only handle change
if (key == previousKey) {
return KEY_NONE;
}
// debounce
auto now = millis();
if (now - lastPressedAt < DEBOUNCE_MS) {
return KEY_NONE;
}
// save state
previousKey = key;
lastPressedAt = now;
// return event
return key;
}
#define KBD_COL_MASK 0b11110000
#define KBD_ROW_MASK 0b00001111
/**
* Returns pressed key or KEY_NONE if no key is pressed
*
* NOTE: Only one key can be pressed at a time;
* if multiple keys are pressed, the result is undefined
*/
Key getPressedKey() {
// check pressed column
// first 4 bits are columns, low when pressed
kbd.write8(KBD_COL_MASK);
uint8_t cols = kbd.read8();
if (cols == KBD_COL_MASK) {
return KEY_NONE;
}
uint8_t colState = ~(cols >> 4);
uint8_t colPressed = 0;
if (colState & 0b1000) colPressed = 0;
else if (colState & 0b0100) colPressed = 1;
else if (colState & 0b0010) colPressed = 2;
else if (colState & 0b0001) colPressed = 3;
else {
Serial.print("Invalid kbd column state: ");
Serial.println(cols, BIN);
sadBuzz();
return KEY_NONE;
}
// check pressed row
// last 4 bits are rows, low when pressed
kbd.write8(KBD_ROW_MASK);
uint8_t rows = kbd.read8();
if (rows == KBD_ROW_MASK) {
// between col and row read, a key could be released
return KEY_NONE;
}
uint8_t rowState = ~rows;
uint8_t rowPressed = 0;
if (rowState & 0b1000) rowPressed = 0;
else if (rowState & 0b0100) rowPressed = 1;
else if (rowState & 0b0010) rowPressed = 2;
else if (rowState & 0b0001) rowPressed = 3;
else {
Serial.print("Invalid kbd row state: ");
Serial.println(rowState, BIN);
sadBuzz();
return KEY_NONE;
}
// return key
return (rowPressed * 4) + colPressed;
}
uint8_t getPressedDigit(Key key) {
if (key == KEY_NONE) return KEY_NONE;
return digits[key];
}