Commit 140a7a17 authored by Robey Pointer's avatar Robey Pointer
Browse files

checkpoint: the refactored keyboard scan seems to work

parent a61219db
......@@ -278,6 +278,10 @@ void remote_disable_som_uart(void) {
empty_serial();
}
typedef struct MenuItem {
char* title;
int keycode;
......@@ -305,6 +309,20 @@ const MenuItem menu_items[] = {
{ "System Status s", KEY_S },
{ "KBD Power-Off p", KEY_P }
};
#include "menu.h"
const menu_item_t circle_menu[] = {
{ "Exit Menu ESC", KEY_ESCAPE, NULL },
{ "Power On 1", KEY_1, controller_turn_on_som },
{ "Power Off 0", KEY_0, controller_turn_off_som },
{ "Reset R", KEY_R, NULL },
{ "Battery Status B", KEY_B, ux_show_battery },
{ "Key Backlight - F1", KEY_F1, NULL },
{ "Key Backlight + F2", KEY_F2, NULL },
{ "Wake SPC", KEY_SPACE, NULL },
{ "System Status S", KEY_S, ux_show_status },
MENU_END
};
#endif
int current_menu_y = 0;
......@@ -410,8 +428,163 @@ int execute_meta_function(int keycode) {
return 0;
}
#define MAX_CONCURRENT_KEYS 6
#define MATRIX_ROWS 6
#define MATRIX_COLUMNS 15
#define MATRIX_BITS ((MATRIX_ROWS * MATRIX_COLUMNS + 7) >> 3)
// scan the keyboard matrix and fill in a list of (up to MAX_CONCURRENT_KEYS)
// keys that are currently pressed. returns the count of pressed keys.
static uint8_t scan_keyboard_raw(uint8_t keys[]) {
static uint8_t debounce_history[MATRIX_COLUMNS * MATRIX_ROWS] = { 0, };
static uint8_t state[MATRIX_BITS] = { 0, };
uint8_t count = 0;
// pull ROWs low one after the other
for (int y = 0; y < 6; y++) {
switch (y) {
case 0: output_low(PORTB, 6); break;
case 1: output_low(PORTB, 5); break;
case 2: output_low(PORTB, 4); break;
case 3: output_low(PORTD, 7); break;
case 4: output_low(PORTD, 6); break;
case 5: output_low(PORTD, 4); break;
}
// wait for signal to stabilize
// TODO maybe not necessary
_delay_us(10);
// check input COLs
for (int x = 0; x < 14; x++) {
uint8_t pressed = 0;
// column pins are all over the place
switch (x) {
case 0: pressed = !(PIND & (1 << 5)); break;
case 1: pressed = !(PINF & (1 << 7)); break;
case 2: pressed = !(PINE & (1 << 6)); break;
case 3: pressed = !(PINC & (1 << 7)); break;
case 4: pressed = !(PINB & (1 << 3)); break;
case 5: pressed = !(PINB & (1 << 2)); break;
case 6: pressed = !(PINB & (1 << 1)); break;
case 7: pressed = !(PINB & (1 << 0)); break;
case 8: pressed = !(PINF & (1 << 0)); break;
case 9: pressed = !(PINF & (1 << 1)); break;
case 10: pressed = !(PINF & (1 << 4)); break;
case 11: pressed = !(PINF & (1 << 5)); break;
case 12: pressed = !(PINF & (1 << 6)); break;
case 13: pressed = !(PINC & (1 << 6)); break;
}
// shift new state as bit into debounce "register"
uint8_t loc = y * 15 + x;
uint8_t pressed_byte = loc >> 3;
uint8_t pressed_bit = loc & 7;
bool now_pressed = state[pressed_byte] & (1 << pressed_bit);
debounce_history[loc] = (debounce_history[loc] << 1) | pressed;
// transition to "pressed" only on the first down event after a
// run (7) of unpressed scans. transition to "unpressed" only
// after a run (8) of unpressed scans.
if (debounce_history[loc] == 0x00 && now_pressed) {
state[pressed_byte] &= ~(1 << pressed_bit);
now_pressed = 0;
} else if (debounce_history[loc] == 0x01 && !now_pressed) {
state[pressed_byte] |= (1 << pressed_bit);
now_pressed = 1;
}
if (now_pressed && count < MAX_CONCURRENT_KEYS) {
keys[count++] = matrix[loc];
}
}
switch (y) {
case 0: output_high(PORTB, 6); break;
case 1: output_high(PORTB, 5); break;
case 2: output_high(PORTB, 4); break;
case 3: output_high(PORTD, 7); break;
case 4: output_high(PORTD, 6); break;
case 5: output_high(PORTD, 4); break;
}
}
return count;
}
// do a tight loop of scanning, to allow the debounce logic to settle.
static uint8_t scan_keyboard(uint8_t keys[]) {
uint8_t count = 0;
for (int i = 0; i < 10; i++) {
count = scan_keyboard_raw(keys);
}
return count;
}
// scan_keyboard, and handle the circle-menu
static uint8_t scan_keyboard_enhanced(uint8_t keys[]) {
static bool in_old_menu = false;
static uint8_t previous_key = 0;
uint8_t count = scan_keyboard(keys);
if (count == 1 && keys[0] == KEY_CIRCLE && !in_old_menu && !previous_key) {
current_scroll_y = 0;
current_menu_y = 0;
in_old_menu = true;
previous_key = KEY_CIRCLE;
// render menu
render_menu(current_scroll_y);
return 0;
}
// once no more keys are pressed, clear the circle-menu state and be a
// normal keyboard again.
if (count == 0) previous_key = 0;
if (in_old_menu) {
if (count == 1 && keys[0] != previous_key) {
int stay_in_menu = execute_meta_function(keys[0]);
previous_key = keys[0];
if (!stay_in_menu) in_old_menu = false;
}
return 0;
}
// still holding down a key from when we were in circle menu mode? ignore.
if (previous_key) return 0;
return count;
}
void robey_test(void) {
display_clear();
display_flush();
for (int j = 0; j < 20; j++) {
Delay_MS(500);
uint8_t keys[MAX_CONCURRENT_KEYS];
uint8_t count = scan_keyboard(keys);
if (count > 0) {
for (int i = 0; i < count; i++) {
char x[10];
sprintf(x, "%02x;", keys[i]);
display_write(x);
}
display_write(".\n");
display_flush();
}
}
display_write("*");
display_flush();
}
uint8_t last_meta_key = 0;
bool in_circle_menu = false;
void process_keyboard(char usb_report_mode, USB_KeyboardReport_Data_t* KeyboardReport) {
// how many keys are pressed this round
uint8_t total_pressed = 0;
......@@ -485,8 +658,18 @@ void process_keyboard(char usb_report_mode, USB_KeyboardReport_Data_t* KeyboardR
if (active_meta_mode) {
// not holding the same key?
if (last_meta_key!=keycode) {
if (keycode == KEY_8) {
menu_start(circle_menu);
last_meta_key = keycode;
active_meta_mode = 0;
in_circle_menu = true;
// remote_turn_on_som();
// menu_stop();
} else {
// hyper/circle/menu functions
int stay_meta = execute_meta_function(keycode);
// int stay_meta = menu_key(keycode);
// don't repeat action while key is held down
last_meta_key = keycode;
......@@ -494,6 +677,13 @@ void process_keyboard(char usb_report_mode, USB_KeyboardReport_Data_t* KeyboardR
if (!stay_meta) {
active_meta_mode = 0;
}
}
}
} else if (in_circle_menu) {
if (last_meta_key != keycode) {
int stay_meta = menu_key(keycode);
last_meta_key = keycode;
if (!stay_meta) in_circle_menu = false;
}
} else if (!last_meta_key) {
// not meta mode, regular key: report keypress via USB
......@@ -540,14 +730,34 @@ int main(void)
matrix[15*3+13]=KEY_BACKSLASH_AND_PIPE; // M3
#endif
SetupHardware();
GlobalInterruptEnable();
SetupHardware();
GlobalInterruptEnable();
// check for safe boot (holding down the circle key for 500msec)...
// this is to cover a case where the firmware is messed up enough that
// you can't even power up the laptop. hold down circle while the
// keyboard is powering up, and it will at least boot the laptop and
// allow you to reflash. :)
uint8_t keys[MAX_CONCURRENT_KEYS];
uint8_t safe_count = 0;
while (scan_keyboard(keys) == 1 && keys[0] == KEY_CIRCLE && safe_count < 50) {
safe_count++;
if (safe_count >= 50) {
display_clear();
display_write("safe boot");
display_flush();
Delay_MS(1000);
controller_turn_on_som();
break;
}
Delay_MS(10);
}
int counter = 0;
for (;;)
{
process_keyboard(0, NULL);
// process_keyboard(0, NULL);
HID_Device_USBTask(&Keyboard_HID_Interface);
USB_USBTask();
counter++;
......@@ -718,7 +928,9 @@ bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDIn
{
USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
process_keyboard(1, KeyboardReport);
uint8_t count = scan_keyboard_enhanced(KeyboardReport->KeyCode);
if (count == 0) memset(KeyboardReport->KeyCode, 0, MAX_CONCURRENT_KEYS);
// process_keyboard(1, KeyboardReport);
*ReportSize = sizeof(USB_KeyboardReport_Data_t);
return false;
......
......@@ -114,3 +114,5 @@
#define KEY_MUTE 0x7F
#define KEY_VOLUME_UP 0x80
#define KEY_VOLUME_DOWN 0x81
#define KEY_CIRCLE 0xa4
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment