295 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * \file firmware/modelsuntype5.c
 | |
|  * \brief Hardware specific part for IBM Model M keyboard
 | |
|  * \author Ronald Schaten <ronald@schatenseite.de>
 | |
|  * \version $Id: main.c,v 1.6 2008/07/15 05:16:41 rschaten Exp $
 | |
|  *
 | |
|  * License: GNU GPL v2 (see License.txt)
 | |
|  */
 | |
| 
 | |
| #include <avr/io.h>
 | |
| #include <avr/pgmspace.h>
 | |
| #include <util/delay.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #include "keycodes.h"
 | |
| #include "tools.h"
 | |
| #include "modelinterface.h"
 | |
| #include "usbdrv.h"
 | |
| 
 | |
| /* ----------------------- hardware I/O abstraction ------------------------ */
 | |
| 
 | |
| #define PORTLEDS    PORTB  ///< port on which the LEDs are connected
 | |
| #define PINLEDS     PINB   ///< port on which the LEDs are connected
 | |
| #define DDRLEDS     DDRB   ///< port on which the LEDs are connected
 | |
| #define LEDSCROLL   PINB7  ///< address of the scroll-lock LED
 | |
| #define LEDNUM      PINB6  ///< address of the num-lock LED
 | |
| #define LEDCOMP     PINB5  ///< address of the compose LED
 | |
| #define LEDCAPS     PINB4  ///< address of the caps-lock LED
 | |
| 
 | |
| #define SRCLOCKON    PORTC |= (1 << PC5)
 | |
| #define SRCLOCKOFF   PORTC &= ~(1 << PC5)
 | |
| #define SRDATAON     PORTC |= (1 << PC6)
 | |
| #define SRDATAOFF    PORTC &= ~(1 << PC6)
 | |
| #define SRSTROBEON   PORTC |= (1 << PC7)
 | |
| #define SRSTROBEOFF  PORTC &= ~(1 << PC7)
 | |
| 
 | |
| uint16_t curmatrix[22];  ///< contains current state of the keyboard
 | |
| uint16_t oldmatrix[22];  ///< contains old state of the keyboard
 | |
| uint16_t ghostmatrix[22]; ///< contains pressed keys that belong to a ghost-key situation
 | |
| 
 | |
| void hardwareInit(void) { 
 | |
|     // configure ports
 | |
|     DDRA = 0x00;
 | |
|     PORTA = 0xff;
 | |
|     DDRB = (1 << PB4) |(1 << PB5) | (1 << PB6) | (1 << PB7);
 | |
|     PORTB = (1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3);
 | |
|     DDRC = (1 << PC5) | (1 << PC6) | (1 << PC7);
 | |
|     PORTC = (1 << PC0) | (1 << PC1) | (1 << PC2) | (1 << PC3) | (1 << PC4);
 | |
|     DDRD &= ~((1 << PD4) | (1 << PD5) | (1 << PD6) | (1 << PD7));
 | |
|     PORTD |= (1 << PD4) | (1 << PD5) | (1 << PD6) | (1 << PD7);
 | |
| 
 | |
|     DDRD |= (1 << PD0) | (1 << PD2); // needed for USB reset
 | |
|     _delay_us(11);      // delay >10ms for USB reset
 | |
|     DDRD &= ~((1 << PD0) | (1 << PD2)); // remove USB reset condition
 | |
| 
 | |
|     // configure timer 0 for a rate of 12M/(1024 * 256) = 45.78Hz (~22ms)
 | |
|     TCCR0 = 5;          // timer 0 prescaler: 1024
 | |
| 
 | |
|     // blink, to indicate power-on
 | |
|     PORTLEDS &= ~((1 << LEDNUM) | (1 << LEDCAPS) | (1 << LEDSCROLL) | (1 << LEDCOMP));
 | |
|     _delay_ms(50);
 | |
|     PORTLEDS |= ((1 << LEDNUM) | (1 << LEDCAPS) | (1 << LEDSCROLL) | (1 << LEDCOMP));
 | |
| 
 | |
|     // clean shift registers -- set all row lines to 1, except for KEYROW
 | |
|     SRDATAON;
 | |
|     SRSTROBEOFF;
 | |
|     for (uint8_t i = 0; i < 21; i++) {
 | |
|         SRCLOCKON; SRCLOCKOFF;
 | |
|     }
 | |
|     SRSTROBEON; SRSTROBEOFF;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Print the current state of the keyboard in a readable form. This function
 | |
|  * is used for debug-purposes only.
 | |
|  */
 | |
| void printMatrix(void) {
 | |
|     for (uint8_t i = 0; i < 22; i++) {
 | |
|         char buffer[10];
 | |
|         sprintf(buffer, "%4x", ~(curmatrix[i] | 0xe000));
 | |
|         for(int j= 0; j < strlen(buffer); j++) {
 | |
|             if(buffer[j] == '0')
 | |
|                 buffer[j]= ' ';
 | |
|         }
 | |
|         sendString(buffer);
 | |
|         if (i == 11) {
 | |
|             sendString(":");
 | |
|         } else {
 | |
|             sendString(".");
 | |
|         }
 | |
|     }
 | |
|     sendString("\n");
 | |
| }
 | |
| 
 | |
| void setLeds(uint8_t LEDstate) {
 | |
|     if (LEDstate & LED_NUM) { // light up caps lock
 | |
|         PORTLEDS &= ~(1 << LEDNUM);
 | |
|     } else {
 | |
|         PORTLEDS |= (1 << LEDNUM);
 | |
|     }
 | |
|     if (LEDstate & LED_CAPS) { // light up caps lock
 | |
|         PORTLEDS &= ~(1 << LEDCAPS);
 | |
|     } else {
 | |
|         PORTLEDS |= (1 << LEDCAPS);
 | |
|     }
 | |
|     if (LEDstate & LED_SCROLL) { // light up caps lock
 | |
|         PORTLEDS &= ~(1 << LEDSCROLL);
 | |
|     } else {
 | |
|         PORTLEDS |= (1 << LEDSCROLL);
 | |
|     }
 | |
|     if (LEDstate & LED_COMPOSE) { // light up compose
 | |
|         PORTLEDS &= ~(1 << LEDCOMP);
 | |
|     } else {
 | |
|         PORTLEDS |= (1 << LEDCOMP);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * The keymatrix-array contains positions of keys in the matrix. Here you can
 | |
|  * see which row is connected to which column when a key is pressed. This array
 | |
|  * probably has to be modified if this firmware is ported to a different
 | |
|  * keyboard.
 | |
|  * \sa modmatrix
 | |
|  */
 | |
| const uint8_t PROGMEM keymatrix[22][13] = {
 | |
|   // 0             1             2             3             4                      5                         6               7                      8                       9                       10                      11             12
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_dot,                  KEY_F8,         KEY_F10,               KEY_Reserved,           KEY_9,                  KEY_minus,              KEY_P,         KEY_K},                  //  0
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_slash,                KEY_equals,     KEY_F11,               KEY_Reserved,           KEY_0,                  KEY_lbracket,           KEY_semicolon, KEY_L},                  //  1
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_LeftArrow,         KEY_DownArrow,            KEY_grave,      KEY_F12,               KEY_Reserved,           KEY_Euro,               KEY_DELETE,             KEY_rbracket,  KEY_apostroph},          //  2
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_RightArrow,        KEY_UpArrow,              KEY_Insert,     KEY_PrintScreen,       KEY_Reserved,           KEY_NumLock,            KEY_DeleteForward,      KEY_Return,    KEY_KP4},                //  3
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_KP2,               KEY_KP5,                  KEY_ScrollLock, KEY_Reserved /*mute*/, KEY_Reserved,           KEY_KPslash,            KEY_Home,               KEY_End,       KEY_KP7},                //  4
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_KP3,               KEY_KP6,                  KEY_Pause,      KEY_Reserved /*vol-*/, KEY_Reserved,           KEY_KPasterisk,         KEY_PageUp,             KEY_PageDown,  KEY_KP8},                //  5
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_KPcomma,           KEY_KP0,                  KEY_KPminus,    KEY_Reserved /*vol+*/, KEY_Reserved,           KEY_KP9,                KEY_KPplus,             KEY_KPenter,   KEY_KP1},                //  6
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_Reserved,             KEY_Reserved,   KEY_Reserved,          KEY_Reserved,           KEY_Reserved,           KEY_Reserved,           KEY_Reserved,  KEY_Reserved},           //  7
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_Reserved /*compose*/, KEY_Reserved,   KEY_Reserved,          KEY_Reserved,           KEY_Reserved,           KEY_Reserved,           KEY_Reserved,  KEY_Reserved},           //  8
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_Reserved,             KEY_Reserved,   KEY_Reserved,          KEY_Reserved /*power*/, KEY_Reserved,           KEY_Reserved,           KEY_Reserved,  KEY_Reserved},           //  9
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_Reserved,             KEY_Reserved,   KEY_Reserved,          KEY_Reserved,           KEY_Reserved,           KEY_Reserved,           KEY_Reserved,  KEY_Reserved},           //  10
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_Reserved,             KEY_Reserved,   KEY_Reserved,          KEY_Reserved,           KEY_Reserved,           KEY_Reserved,           KEY_Reserved,  KEY_Reserved},           //  11
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_capslock,          KEY_Reserved,             KEY_Reserved,   KEY_Reserved,          KEY_Reserved,           KEY_Reserved,           KEY_Reserved,           KEY_Reserved,  KEY_Reserved},           //  12
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved /*find*/, KEY_Reserved /*open*/,    KEY_ESCAPE,     KEY_Reserved /*help*/, KEY_Reserved,           KEY_Reserved /*stop*/,  KEY_Reserved /*props*/, KEY_Tab,       KEY_Reserved /*front*/}, //  13
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_Reserved,             KEY_Reserved,   KEY_Reserved,          KEY_Reserved,           KEY_Reserved,           KEY_Reserved,           KEY_Reserved,  KEY_Reserved},           //  14
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved /*cut*/,  KEY_Reserved /*paste*/,   KEY_1,          KEY_Reserved /*any*/,  KEY_Reserved,           KEY_Reserved /*again*/, KEY_Reserved /*undo*/ , KEY_Q,         KEY_Reserved /*copy*/},  //  15
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_Z,                    KEY_2,          KEY_F1,                KEY_Reserved,           KEY_3,                  KEY_E,                  KEY_W,         KEY_D},                  //  16
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_C,                 KEY_X,                    KEY_4,          KEY_F2,                KEY_Reserved,           KEY_5,                  KEY_R,                  KEY_F,         KEY_A},                  //  17
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_V,                 KEY_N,                    KEY_F3,         KEY_F5,                KEY_Reserved,           KEY_6,                  KEY_T,                  KEY_G,         KEY_S},                  //  18
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_B,                 KEY_M,                    KEY_F4,         KEY_F6,                KEY_Reserved,           KEY_7,                  KEY_U,                  KEY_Y,         KEY_H},                  //  19
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved,          KEY_Reserved,             KEY_Reserved,   KEY_Reserved,          KEY_Reserved,           KEY_Reserved,           KEY_Reserved,           KEY_Reserved,  KEY_Reserved},           //  20
 | |
|     {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Spacebar,          KEY_comma,                KEY_F7,         KEY_F9,                KEY_Reserved,           KEY_8,                  KEY_O,                  KEY_I,         KEY_J},                  //  21
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * The modmatrix-array contains positions of the modifier-keys in the matrix.
 | |
|  * It is built in the same way as the keymatrix-array.
 | |
|  * \sa keymatrix
 | |
|  */
 | |
| const uint8_t PROGMEM modmatrix[22][13] = { // contains positions of modifiers in the matrix
 | |
|   // 0                1              2             3               4             5         6         7         8         9         10        11        12
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  0
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  1
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  2
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  3
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  4
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  5
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  6
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_ALT_RIGHT, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  7
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  8
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  9
 | |
|     {MOD_NONE,        MOD_GUI_RIGHT, MOD_GUI_LEFT, MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  10
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_ALT_LEFT, MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  11
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  12
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  13
 | |
|     {MOD_SHIFT_RIGHT, MOD_NONE,      MOD_NONE,     MOD_SHIFT_LEFT, MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  14
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  15
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  16
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  17
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  18
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  19
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_CONTROL_LEFT}, //  20
 | |
|     {MOD_NONE,        MOD_NONE,      MOD_NONE,     MOD_NONE,       MOD_NONE,     MOD_NONE,      MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE},         //  21
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Checks if more than one bit in data is set.
 | |
|  * \param data value to check
 | |
|  * \return true if more than one bit is set
 | |
|  */
 | |
| static uint8_t bitcount2(uint16_t data) {
 | |
|     data &= (data - 1);
 | |
|     return data != 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * check if reportBuffer contains the key
 | |
|  * \param buffer buffer to check
 | |
|  * \param key key to search
 | |
|  * \return 1 if buffer contains key, 0 otherwise
 | |
|  */
 | |
| static uint8_t bufferContains(uint8_t* buffer, uint8_t key) {
 | |
|     for (uint8_t i = 2; i < sizeof(buffer); i++) {
 | |
|         if (buffer[i] == key) {
 | |
|             return 1;
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Scan and debounce keypresses. This is the main worker function for normal
 | |
|  * keyboard operation, the code contains lot of comments. Basically, it first
 | |
|  * scans the keyboard state. If a change is detected, it initializes a counter
 | |
|  * that is decreased each time this function is called. If the counter reaches
 | |
|  * 1, that means that the same scan result has been scanned ten times in a row,
 | |
|  * so we can be pretty sure that the keys are in a certain state (as in: not
 | |
|  * bouncing). Then, the codes for keys and modifiers are searched from the two
 | |
|  * arrays, the USB-message to send the state is prepared. The return value of
 | |
|  * this function indicates if the message has to be sent.
 | |
|  * \return flag to indicate whether something has changed
 | |
|  */
 | |
| uint8_t scankeys(uint8_t* reportBuffer, uint8_t* oldReportBuffer, uint8_t sizeOfReportBuffer) {
 | |
|     static uint8_t debounce = 5;
 | |
|     uint8_t retval = 0;
 | |
|     SRDATAOFF; // mark first bit as the active one
 | |
|     SRCLOCKON; SRCLOCKOFF; // trigger clock to shift first bit into the register
 | |
|     SRDATAON; // all further bits will be inactive
 | |
|     for (uint8_t row = 0; row < 22; row++) {
 | |
|         SRSTROBEON; SRSTROBEOFF; // copy current register values to output
 | |
|         _delay_us(30);
 | |
|         uint16_t data = ((PINC & 0x1f) << 8) | PINA; // we need the lower five bits of PINC and PINA
 | |
|         if (data != curmatrix[row]) {
 | |
|             // if a change was detected
 | |
|             debounce = 10; // activate debounce counter
 | |
|             curmatrix[row] = data; // and store the result
 | |
|             ghostmatrix[row] = 0;
 | |
|         }
 | |
|         SRCLOCKON; SRCLOCKOFF; // trigger clock to shift register values
 | |
|     }
 | |
|     if (debounce) {
 | |
|         // Count down, but avoid underflow
 | |
|         debounce--;
 | |
|     }
 | |
|     if (debounce == 1) {
 | |
|         if (memcmp(oldmatrix, curmatrix, sizeof(curmatrix)) != 0) {
 | |
|          //   printMatrix();
 | |
|             memcpy(oldmatrix, curmatrix, sizeof(curmatrix));
 | |
|         }
 | |
|         // debounce counter expired, create report
 | |
|         uint8_t reportIndex = 2; // reportBuffer[0] contains modifiers
 | |
|         memset(reportBuffer, 0, sizeOfReportBuffer); // clear report buffer
 | |
|         for (uint8_t row = 0; row < 22; row++) { // process all rows for key-codes
 | |
|             uint16_t data = curmatrix[row]; // restore buffer
 | |
|             if (data != 0x1fff) { // anything on this row? - optimization
 | |
|                 for (uint8_t col = 0; col < 13; col++) { // check every bit on this row
 | |
|                     uint8_t key, modifier, isghostkey;
 | |
|                     if (!(data & (1 << col))) {
 | |
|                         key = pgm_read_byte(&keymatrix[row][col]);
 | |
|                         modifier = pgm_read_byte(&modmatrix[row][col]);
 | |
|                         isghostkey = ghostmatrix[row] & (1 << col);
 | |
|                     } else {
 | |
|                         key = KEY_Reserved;
 | |
|                         modifier = MOD_NONE;
 | |
|                         isghostkey = 0x00;
 | |
|                     }
 | |
|                     if (key != KEY_Reserved) { // keycode should be added to report
 | |
|                         if (reportIndex >= sizeOfReportBuffer) { // too many keycodes
 | |
|                             if (!retval & 0x02) { // Only fill buffer once
 | |
|                                 memset(reportBuffer+2, KEY_ErrorRollOver, sizeOfReportBuffer-2);
 | |
|                                 retval |= 0x02; // continue decoding to get modifiers
 | |
|                             }
 | |
|                         } else {
 | |
|                             if (isghostkey) {
 | |
|                                 // we're in a ghost-key situation
 | |
|                                 if (bufferContains(oldReportBuffer, key)) {
 | |
|                                     // this key has been pressed before, so we still send it
 | |
|                                     reportBuffer[reportIndex] = key; // set next available entry
 | |
|                                     reportIndex++;
 | |
|                                 }
 | |
|                             } else {
 | |
|                                 reportBuffer[reportIndex] = key; // set next available entry
 | |
|                                 reportIndex++;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     if (modifier != MOD_NONE) { // modifier should be added to report
 | |
|                         reportBuffer[0] |= modifier;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         retval |= 0x01; // must have been a change at some point, since debounce is done
 | |
|     }
 | |
|     return retval;
 | |
| }
 | |
| 
 |