132 lines
2.6 KiB
C++
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];
|
|
}
|