reform

MNT Reform: Open Source Portable Computer
Log (Feed) | Files | Refs (Tags) | README

keyboard.c (17762B)


      1 /*
      2   MNT Reform 2.0 Keyboard Firmware
      3   Copyright 2019-2021  Lukas F. Hartmann / MNT Research GmbH, Berlin (lukas@mntre.com)
      4   And Contributors:
      5   Chartreuse
      6   V Körbes
      7   Robey Pointer (robey@lag.net)
      8 
      9   Based on code from LUFA Library (lufa-lib.org):
     10   Copyright 2018 Dean Camera (dean [at] fourwalledcubicle [dot] com)
     11 
     12   SPDX-License-Identifier: MIT
     13 */
     14 
     15 #include <stdlib.h>
     16 #include <avr/io.h>
     17 #include "backlight.h"
     18 // Important: version and variant info moved here
     19 #include "constants.h"
     20 #include "hid_report.h"
     21 #include "keyboard.h"
     22 #include "menu.h"
     23 #include "oled.h"
     24 #include "powersave.h"
     25 #include "remote.h"
     26 #include "scancodes.h"
     27 
     28 #ifdef KBD_VARIANT_ANRI
     29 #include "matrix_anri.h"
     30 #else
     31 #ifdef KBD_VARIANT_3
     32 #include "matrix_3.h"
     33 #else
     34 #ifdef KBD_VARIANT_V
     35 #include "matrix_v.h"
     36 #else
     37 #include "matrix.h"
     38 #endif
     39 #endif
     40 #endif
     41 
     42 /** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */
     43 static uint8_t PrevKeyboardHIDReportBuffer[sizeof(USB_KeyboardReport_Data_t)];
     44 static uint8_t PrevMediaControlHIDReportBuffer[sizeof(USB_MediaReport_Data_t)];
     45 
     46 /** LUFA HID Class driver interface configuration and state information. This structure is
     47  *  passed to all HID Class driver functions, so that multiple instances of the same class
     48  *  within a device can be differentiated from one another.
     49  */
     50 USB_ClassInfo_HID_Device_t Keyboard_HID_Interface =
     51   {
     52     .Config =
     53       {
     54         .InterfaceNumber              = INTERFACE_ID_Keyboard,
     55         .ReportINEndpoint             =
     56           {
     57             .Address              = KEYBOARD_EPADDR,
     58             .Size                 = HID_EPSIZE,
     59             .Banks                = 1,
     60           },
     61         .PrevReportINBuffer           = PrevKeyboardHIDReportBuffer,
     62         .PrevReportINBufferSize       = sizeof(PrevKeyboardHIDReportBuffer),
     63       },
     64   };
     65 
     66 /** LUFA HID Class driver interface configuration and state information for the Media Controller */
     67 USB_ClassInfo_HID_Device_t MediaControl_HID_Interface =
     68   {
     69     .Config =
     70       {
     71         .InterfaceNumber              = INTERFACE_ID_MediaControl,
     72         .ReportINEndpoint             =
     73           {
     74             .Address              = MEDIACONTROL_EPADDR,
     75             .Size                 = HID_EPSIZE,
     76             .Banks                = 1,
     77           },
     78         .PrevReportINBuffer           = PrevMediaControlHIDReportBuffer,
     79         .PrevReportINBufferSize       = sizeof(PrevMediaControlHIDReportBuffer),
     80       },
     81   };
     82 
     83 enum keymods {
     84     SHIFT = 1,
     85   CONTROL = 2,
     86     AGR = 4,
     87     ALT = 8,
     88   SUPER = 16,
     89 };
     90 
     91 uint8_t matrix_debounce[KBD_COLS*KBD_ROWS];
     92 uint8_t matrix_state[KBD_COLS*KBD_ROWS];
     93 
     94 int active_meta_mode = 0;
     95 uint8_t last_meta_key = 0;
     96 
     97 uint8_t* active_matrix = matrix;
     98 int active_keymods = 0;
     99 bool media_toggle = 0;
    100 bool fn_key = 0; // Am I holding FN?
    101 bool circle = 0; // Am I holding circle?
    102 bool help_display = 0; // Is the Hyper help screen displayed?
    103 bool should_run_fade_anim = false;
    104 
    105 int led_brightness;
    106 int led_dimmed = 0;
    107 uint32_t led_idle_counter = 0;
    108 
    109 // enter the menu
    110 void enter_meta_mode(void) {
    111   active_meta_mode = 1;
    112   reset_and_render_menu();
    113 }
    114 
    115 void reset_keyboard_state(void) {
    116   for (int i = 0; i < KBD_COLS*KBD_ROWS; i++) {
    117     matrix_debounce[i] = 0;
    118     matrix_state[i] = 0;
    119   }
    120   last_meta_key = 0;
    121   reset_menu();
    122 }
    123 
    124 inline bool is_media_key(uint8_t keycode) {
    125   return (keycode>=HID_KEYBOARD_SC_MEDIA_PLAY);
    126 }
    127 
    128 void get_media_keys(uint8_t keycode, USB_MediaReport_Data_t* mcr) {
    129   switch (keycode) {
    130   case HID_KEYBOARD_SC_MEDIA_BRIGHTNESS_DOWN: mcr->BrightnessDown = 1; break;
    131   case HID_KEYBOARD_SC_MEDIA_BRIGHTNESS_UP: mcr->BrightnessUp = 1; break;
    132   case HID_KEYBOARD_SC_MEDIA_PREVIOUS_TRACK: mcr->PreviousTrack = 1; break;
    133   case HID_KEYBOARD_SC_MEDIA_PLAY: mcr->PlayPause = 1; break;
    134   case HID_KEYBOARD_SC_MEDIA_NEXT_TRACK: mcr->NextTrack = 1; break;
    135   case HID_KEYBOARD_SC_MEDIA_MUTE: mcr->Mute = 1; break;
    136   case HID_KEYBOARD_SC_MEDIA_VOLUME_DOWN: mcr->VolumeDown = 1; break;
    137   case HID_KEYBOARD_SC_MEDIA_VOLUME_UP: mcr->VolumeUp = 1; break;
    138   }
    139 }
    140 
    141 #define MAX_SCANCODES 6
    142 static uint8_t pressed_scancodes[MAX_SCANCODES] = {0,0,0,0,0,0};
    143 
    144 // number of cycles a key has to remain pressed to register a keypress
    145 // is at least 1 but at most 8
    146 #define DEBOUNCE_BITS 1
    147 
    148 // usb_report_mode: if you pass 0, you can leave KeyboardReport NULL
    149 int process_keyboard(uint8_t* resulting_scancodes) {
    150   // how many keys are pressed this round
    151   uint8_t total_pressed = 0;
    152   uint8_t used_key_codes = 0;
    153 
    154   // create a bitmask with the lowest DEBOUNCE_BITS number of bits set to 1
    155   // 1 -> 0b00000001
    156   // 2 -> 0b00000011
    157   // ...
    158   // 8 -> 0b11111111
    159   uint8_t debounce_bitmask = (1<<DEBOUNCE_BITS)-1;
    160 
    161   int old_keymods = active_keymods;
    162   bool left_ctrl_pressed = 1;
    163   bool left_shift_pressed = 1;
    164   // pull ROWs low one after the other
    165   for (int y = 0; y < KBD_ROWS; y++) {
    166     switch (y) {
    167     case 0: output_low(PORTB, 6); break;
    168     case 1: output_low(PORTB, 5); break;
    169     case 2: output_low(PORTB, 4); break;
    170     case 3: output_low(PORTD, 7); break;
    171     case 4: output_low(PORTD, 6); break;
    172     case 5: output_low(PORTD, 4); break;
    173     }
    174 
    175     // wait for signal to stabilize
    176     // TODO maybe not necessary
    177     //_delay_us(10);
    178 
    179     // check input COLs
    180     for (int x=0; x<14; x++) {
    181       uint16_t keycode;
    182       uint16_t loc = y*KBD_COLS+x;
    183       keycode = active_matrix[loc];
    184       uint8_t  pressed = 0;
    185       uint8_t  debounced_pressed = 0;
    186 
    187       // column pins are all over the place
    188       switch (x) {
    189       case 0:  pressed = !(PIND&(1<<5)); break;
    190       case 1:  pressed = !(PINF&(1<<7)); break;
    191       case 2:  pressed = !(PINE&(1<<6)); break;
    192       case 3:  pressed = !(PINC&(1<<7)); break;
    193       case 4:  pressed = !(PINB&(1<<3)); break;
    194       case 5:  pressed = !(PINB&(1<<2)); break;
    195       case 6:  pressed = !(PINB&(1<<1)); break;
    196       case 7:  pressed = !(PINB&(1<<0)); break;
    197       case 8:  pressed = !(PINF&(1<<0)); break;
    198       case 9:  pressed = !(PINF&(1<<1)); break;
    199       case 10: pressed = !(PINF&(1<<4)); break;
    200       case 11: pressed = !(PINF&(1<<5)); break;
    201       case 12: pressed = !(PINF&(1<<6)); break;
    202       case 13: pressed = !(PINC&(1<<6)); break;
    203       }
    204 
    205       // shift new state as bit into debounce "register"
    206       matrix_debounce[loc] = (matrix_debounce[loc]<<1)|pressed;
    207 
    208       // if unclear state, we need to keep the last state of the key
    209       if (matrix_debounce[loc] == 0x00) {
    210         matrix_state[loc] = 0;
    211       } else if (matrix_debounce[loc] == debounce_bitmask) {
    212         // the key has been pressed for the last DEBOUNCE_BITS number of
    213         // cycles -> register key press
    214         matrix_state[loc] = 1;
    215       }
    216       debounced_pressed = matrix_state[loc];
    217 
    218       if (debounced_pressed) {
    219         total_pressed++;
    220         // set active keymod for OLED display
    221         if (keycode == HID_KEYBOARD_SC_LEFT_CONTROL || keycode == HID_KEYBOARD_SC_RIGHT_CONTROL) {
    222           active_keymods |= CONTROL;
    223         } else if (keycode == HID_KEYBOARD_SC_LEFT_SHIFT || keycode == HID_KEYBOARD_SC_RIGHT_SHIFT) {
    224           active_keymods |= SHIFT;
    225         } else if (keycode == HID_KEYBOARD_SC_RIGHT_ALT) {
    226           active_keymods |= AGR;
    227         } else if (keycode == HID_KEYBOARD_SC_LEFT_ALT) {
    228           active_keymods |= ALT;
    229         } else if (keycode == HID_KEYBOARD_SC_LEFT_GUI) {
    230           active_keymods |= SUPER;
    231         }
    232         // Is circle key pressed?
    233         if (keycode == KEY_CIRCLE) {
    234           if (fn_key) {
    235             circle = 1;
    236           } else {
    237             if (!active_meta_mode && !last_meta_key) {
    238               enter_meta_mode();
    239             }
    240           }
    241         } else if (keycode == HID_KEYBOARD_SC_EXECUTE) {
    242           fn_key = 1;
    243           active_matrix = matrix_fn;
    244           if (!help_display) {
    245             render_help();
    246             help_display = 1;
    247           }
    248         } else {
    249           if (active_meta_mode) {
    250             // not holding the same key?
    251             if (last_meta_key != keycode) {
    252               // hyper/circle/menu functions
    253               int stay_meta = execute_meta_function(keycode);
    254               // don't repeat action while key is held down
    255               last_meta_key = keycode;
    256 
    257               // exit meta mode
    258               if (!stay_meta) {
    259                 active_meta_mode = 0;
    260               }
    261 
    262               // after wake-up from sleep mode, skip further keymap processing
    263               if (stay_meta == 2) {
    264                 reset_keyboard_state();
    265                 enter_meta_mode();
    266                 return 0;
    267               }
    268             }
    269           } else if (!last_meta_key) {
    270             // not meta mode, regular key: report keypress via USB
    271             // 6 keys is the limit in the HID descriptor
    272             if (used_key_codes < MAX_SCANCODES && resulting_scancodes) {
    273               resulting_scancodes[used_key_codes++] = keycode;
    274             }
    275           }
    276         }
    277       } else {
    278         // key not pressed
    279         if (keycode == HID_KEYBOARD_SC_EXECUTE) {
    280           fn_key = 0;
    281           if (help_display) {
    282             clear_display();
    283             help_display = 0;
    284           }
    285           if (media_toggle) {
    286             active_matrix = matrix_fn_toggled;
    287           } else {
    288             active_matrix = matrix;
    289           }
    290         } else if (keycode == KEY_CIRCLE) {
    291           if (fn_key && circle) {
    292             if (!media_toggle) {
    293               media_toggle = 1;
    294               active_matrix = matrix_fn_toggled;
    295             } else {
    296               media_toggle = 0;
    297               active_matrix = matrix_fn;
    298             }
    299           }
    300           circle = 0;
    301         } 
    302         // disable active keymod for OLED display
    303         if (active_keymods) {
    304           if (keycode == HID_KEYBOARD_SC_LEFT_CONTROL) {
    305             left_ctrl_pressed = 0;
    306           } else if (keycode == HID_KEYBOARD_SC_LEFT_SHIFT) {
    307             left_shift_pressed = 0;
    308           } else if (!left_ctrl_pressed && keycode == HID_KEYBOARD_SC_RIGHT_CONTROL) {
    309             active_keymods &= ~ CONTROL;
    310           } else if (!left_shift_pressed && keycode == HID_KEYBOARD_SC_RIGHT_SHIFT) {
    311             active_keymods &= ~ SHIFT;
    312           } else if (keycode == HID_KEYBOARD_SC_RIGHT_ALT) {
    313             active_keymods &= ~ AGR;
    314           } else if (keycode == HID_KEYBOARD_SC_LEFT_ALT) {
    315             active_keymods &= ~ ALT;
    316           } else if (keycode == HID_KEYBOARD_SC_LEFT_GUI) {
    317             active_keymods &= ~ SUPER;
    318           }
    319         }
    320       }
    321     }
    322 
    323     switch (y) {
    324     case 0: output_high(PORTB, 6); break;
    325     case 1: output_high(PORTB, 5); break;
    326     case 2: output_high(PORTB, 4); break;
    327     case 3: output_high(PORTD, 7); break;
    328     case 4: output_high(PORTD, 6); break;
    329     case 5: output_high(PORTD, 4); break;
    330     }
    331   }
    332 
    333   if (old_keymods != active_keymods) {
    334     render_keymods(active_keymods);
    335   }
    336   // if no more keys are held down, allow a new meta command
    337   if (total_pressed < 1) {
    338     last_meta_key = 0;
    339     if (led_dimmed < 2) {
    340       led_idle_counter++;
    341       if (led_dimmed == 0 && led_idle_counter > 500000) {
    342         led_dimmed = 1;
    343         led_brightness = kbd_brightness_get();
    344       } else if (led_dimmed == 1) {
    345         if (led_idle_counter % 1000 == 0) {
    346           kbd_brightness_dec();
    347         }
    348         if (kbd_brightness_get() == 0) {
    349           led_dimmed = 2;
    350         }
    351       }
    352     }
    353   }
    354   // If a key is held down, and the backlight is dimmed, brighten it and reset the timer
    355   else {
    356     led_idle_counter = 0;
    357     if (led_dimmed > 0) {
    358       kbd_brightness_set(led_brightness);
    359       led_dimmed = 0;
    360     }
    361   }
    362 
    363   return used_key_codes;
    364 }
    365 
    366 int main(void)
    367 {
    368 #ifdef KBD_VARIANT_QWERTY_US
    369   matrix[KBD_COLS*4+1]=KEY_DELETE;
    370   matrix_fn[KBD_COLS*4+1]=KEY_DELETE;
    371   matrix_fn_toggled[KBD_COLS*4+1]=KEY_DELETE;
    372 #endif
    373 
    374 #ifdef KBD_VARIANT_NEO2
    375   matrix[KBD_COLS*2+13]=KEY_ENTER;
    376   matrix[KBD_COLS*3+0]=HID_KEYBOARD_SC_CAPS_LOCK; // left M3
    377   matrix[KBD_COLS*3+13]=KEY_BACKSLASH_AND_PIPE; // M3
    378   #ifdef KBD_VARIANT_3
    379     matrix[KBD_COLS*3+12]=KEY_BACKSLASH_AND_PIPE; // M3
    380     matrix[KBD_COLS*5+2]=HID_KEYBOARD_SC_RIGHT_CONTROL;
    381     matrix[KBD_COLS*5+7]=HID_KEYBOARD_SC_LEFT_ALT;
    382     matrix[KBD_COLS*5+8]=HID_KEYBOARD_SC_RIGHT_ALT;
    383   #endif
    384 #endif
    385 
    386   setup_hardware();
    387   GlobalInterruptEnable();
    388   anim_hello();
    389 
    390   int counter = 0;
    391 
    392   for (;;)
    393   {
    394     process_keyboard(NULL);
    395     HID_Device_USBTask(&Keyboard_HID_Interface);
    396     HID_Device_USBTask(&MediaControl_HID_Interface);
    397     USB_USBTask();
    398     counter++;
    399 
    400     if (counter%2048 == 0) {
    401       refresh_menu_page();
    402     }
    403 
    404 #ifndef KBD_MODE_STANDALONE
    405       if (counter>=100000) {
    406         remote_check_for_low_battery();
    407         counter = 0;
    408       }
    409       if (counter%750 == 0) {
    410         remote_process_alerts();
    411       }
    412       if (should_run_fade_anim) {
    413         anim_kbd_hello();
    414         should_run_fade_anim = false;
    415       }
    416 #endif
    417   }
    418 }
    419 
    420 void setup_hardware(void)
    421 {
    422   // Disable watchdog if enabled by bootloader/fuses
    423   MCUSR &= ~(1 << WDRF);
    424   wdt_disable();
    425 
    426   // Disable clock division
    427   clock_prescale_set(clock_div_1);
    428 
    429   // declare port pins as inputs (0) and outputs (1)
    430   DDRB  = 0b11110000;
    431   DDRC  = 0b00000000;
    432   DDRD  = 0b11011001;
    433   DDRE  = 0b00000000;
    434   DDRF  = 0b00000000;
    435 
    436   // initial pin states
    437   PORTB = 0b10001111;
    438   PORTC = 0b11000000;
    439   PORTD = 0b00100000;
    440   PORTE = 0b01000000;
    441   PORTF = 0b11111111;
    442 
    443   // disable JTAG
    444   MCUCR |=(1<<JTD);
    445   MCUCR |=(1<<JTD);
    446 
    447   kbd_brightness_init();
    448   gfx_init(false);
    449   remote_init();
    450   USB_Init();
    451 }
    452 
    453 ISR(WDT_vect)
    454 {
    455   // WDT interrupt enable and flag cleared on entry
    456   Delay_MS(1);
    457 }
    458 
    459 /** Event handler for the library USB Connection event. */
    460 void EVENT_USB_Device_Connect(void)
    461 {
    462   should_run_fade_anim = true;
    463 }
    464 
    465 /** Event handler for the library USB Disconnection event. */
    466 void EVENT_USB_Device_Disconnect(void)
    467 {
    468 }
    469 
    470 /** Event handler for the library USB Configuration Changed event. */
    471 void EVENT_USB_Device_ConfigurationChanged(void)
    472 {
    473   bool ConfigSuccess = true;
    474 
    475   ConfigSuccess &= HID_Device_ConfigureEndpoints(&Keyboard_HID_Interface);
    476   ConfigSuccess &= HID_Device_ConfigureEndpoints(&MediaControl_HID_Interface);
    477 
    478   USB_Device_EnableSOFEvents();
    479 }
    480 
    481 /** Event handler for the library USB Control Request reception event. */
    482 void EVENT_USB_Device_ControlRequest(void)
    483 {
    484   HID_Device_ProcessControlRequest(&Keyboard_HID_Interface);
    485   HID_Device_ProcessControlRequest(&MediaControl_HID_Interface);
    486 }
    487 
    488 /** Event handler for the USB device Start Of Frame event. */
    489 void EVENT_USB_Device_StartOfFrame(void)
    490 {
    491   HID_Device_MillisecondElapsed(&Keyboard_HID_Interface);
    492   HID_Device_MillisecondElapsed(&MediaControl_HID_Interface);
    493 }
    494 
    495 /** HID class driver callback function for the creation of HID reports to the host.
    496  *
    497  *  \param[in]     HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
    498  *  \param[in,out] ReportID    Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
    499  *  \param[in]     ReportType  Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature
    500  *  \param[out]    ReportData  Pointer to a buffer where the created report should be stored
    501  *  \param[out]    ReportSize  Number of bytes written in the report (or zero if no report is to be sent)
    502  *
    503  *  \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent
    504  */
    505 
    506 bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
    507                                          uint8_t* const ReportID,
    508                                          const uint8_t ReportType,
    509                                          void* ReportData,
    510                                          uint16_t* const ReportSize)
    511 {
    512   int num_keys = process_keyboard(pressed_scancodes);
    513   if (num_keys > MAX_SCANCODES) num_keys = MAX_SCANCODES;
    514 
    515   if (HIDInterfaceInfo == &Keyboard_HID_Interface) {
    516     // host asks for a keyboard report
    517     USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
    518     *ReportSize = sizeof(USB_KeyboardReport_Data_t);
    519     for (int i=0; i<num_keys; i++) {
    520       uint8_t sc = pressed_scancodes[i];
    521       if (!is_media_key(sc)) {
    522         KeyboardReport->KeyCode[i] = sc;
    523       }
    524     }
    525   } else if (HIDInterfaceInfo == &MediaControl_HID_Interface) {
    526     // host asks for a media control report
    527     USB_MediaReport_Data_t* MediaControlReport = (USB_MediaReport_Data_t*)ReportData;
    528     *ReportSize = sizeof(USB_MediaReport_Data_t);
    529     for (int i=0; i<num_keys; i++) {
    530       uint8_t sc = pressed_scancodes[i];
    531       if (is_media_key(sc)) {
    532         get_media_keys(sc, MediaControlReport);
    533       }
    534     }
    535   }
    536   return false;
    537 }
    538 
    539 /** HID class driver callback function for the processing of HID reports from the host.
    540  *
    541  *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
    542  *  \param[in] ReportID    Report ID of the received report from the host
    543  *  \param[in] ReportType  The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature
    544  *  \param[in] ReportData  Pointer to a buffer where the received report has been stored
    545  *  \param[in] ReportSize  Size in bytes of the received HID report
    546  */
    547 void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
    548                                           const uint8_t ReportID,
    549                                           const uint8_t ReportType,
    550                                           const void* ReportData,
    551                                           const uint16_t ReportSize)
    552 {
    553   uint8_t* data = (uint8_t*)ReportData;
    554   if (ReportSize<4) return;
    555 
    556   hid_report_cmd(data);
    557 }
    558 /* vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab */