103 lines
3.7 KiB
C++
103 lines
3.7 KiB
C++
//=============================================================================
|
|
// iR Hackpad Demo Firmware
|
|
// Compile for Arduino Leonardo
|
|
//=============================================================================
|
|
|
|
// The Arduino Keyboard library creates a HID keyboard interface to send keyboard scancodes to the host.
|
|
// For convenience, the class takes ASCII characters via Keyboard::write(), which are automatically
|
|
// converted to the corresponding keboard scan-codes according to the keyboard layout passed to
|
|
// Keyboard::begin(). On the host side, the scan-codes are again converted to characters by the OS.
|
|
#include "Keyboard.h"
|
|
|
|
//=============================================================================
|
|
// Our key matrix (see schematics)
|
|
const int N_rows = 5;
|
|
const int N_cols = 4;
|
|
const int gpio_rows[N_rows] = { 6, 7, 8, 9, 5 };
|
|
const int gpio_cols[N_cols] = { 15, 14, 16, 10 };
|
|
|
|
// Key function assignment: ASCII characters or special function codes (see Keyboard.h)
|
|
const int key_matrix[N_rows][N_cols] = {
|
|
{'a', 'b', 'c', 'd'}, // 4x4 keypad
|
|
{'e', 'f', 'g', 'h'},
|
|
{'i', 'j', 'k', 'l'},
|
|
{'m', 'n', 'o', 'p'},
|
|
{'_', '_', '_', 'x'} // rotery encoder button
|
|
};
|
|
|
|
// Key state
|
|
struct {
|
|
bool last; // Last debounced state
|
|
bool inhibit; // State change inhibited during debounce period
|
|
uint32_t since_ms; // Inhibited since timestamp
|
|
} key_state[N_rows][N_cols];
|
|
|
|
const uint32_t KEY_DEBOUNCE_MS = 50; // Key Debounce period
|
|
const uint32_t KEY_SCAN_DELAY_US = 200; // Delay between row scans
|
|
|
|
//=============================================================================
|
|
|
|
void setup()
|
|
{
|
|
for (int col=0; col<N_cols; col++) {
|
|
pinMode(gpio_cols[col], INPUT_PULLUP); // Key matrix columns as inputs
|
|
}
|
|
for (int row=0; row<N_rows; row++) {
|
|
digitalWrite(gpio_rows[row], HIGH);
|
|
pinMode(gpio_rows[row], OUTPUT); // Key matrix rows as outputs
|
|
}
|
|
|
|
memset( &key_state, 0, sizeof(key_state) ); // Clear key state
|
|
|
|
Keyboard.begin(KeyboardLayout_de_DE);
|
|
Serial.begin(9600); // Open serial port to host, so the IDE can reset the device for reprogramming
|
|
}
|
|
|
|
//=============================================================================
|
|
// Key debouncing:
|
|
// React immediately to rising edge (pressed == 1 and last_pressed == 0)
|
|
// After that, inhibit further state changes for KEY_DEBOUNCE_MS milliseconds.
|
|
|
|
void eval_key( int row, int col, bool pressed )
|
|
{
|
|
// Remove inhibit after debounce period
|
|
if (key_state[row][col].inhibit &&
|
|
((millis() - key_state[row][col].since_ms) > KEY_DEBOUNCE_MS)) {
|
|
key_state[row][col].inhibit = 0;
|
|
}
|
|
|
|
if (pressed == true) { // Key is pressed?
|
|
if (key_state[row][col].last == false) { // Rising edge: Key has just been pressed?
|
|
key_state[row][col].last = true;
|
|
key_state[row][col].inhibit = true;
|
|
key_state[row][col].since_ms = millis();
|
|
Keyboard.press(key_matrix[row][col]);
|
|
}
|
|
|
|
// TODO: Repeat delay, repeat rate
|
|
|
|
}
|
|
else { // Pressed == false
|
|
if (!key_state[row][col].inhibit)
|
|
key_state[row][col].last = false;
|
|
Keyboard.release(key_matrix[row][col]);
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
void loop()
|
|
{
|
|
for (int row=0; row<N_rows; row++) {
|
|
digitalWrite(gpio_rows[row], LOW);
|
|
for (int col=0; col<N_cols; col++) {
|
|
const bool pressed = (digitalRead(gpio_cols[col]) == LOW); // Input level low: Key is pressed
|
|
eval_key( row, col, pressed );
|
|
}
|
|
digitalWrite(gpio_rows[row], HIGH);
|
|
delayMicroseconds(KEY_SCAN_DELAY_US); // Give the column inputs time to reach HIGH state (slow recharge via weak pullups)
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|