firmware/main.c

Go to the documentation of this file.
00001 
00207 #define F_CPU 12000000L    
00208 
00209 #include <avr/io.h>
00210 #include <avr/interrupt.h>
00211 #include <avr/pgmspace.h>
00212 #include <avr/wdt.h>
00213 #include <util/delay.h>
00214 #include <string.h>
00215 #include <stdio.h>
00216 
00217 #include "usbdrv.h"
00218 #include "keycodes.h"
00219 
00220 /* ----------------------- hardware I/O abstraction ------------------------ */
00221 
00222 
00223 #define PORTCOLUMNS PORTB  
00224 #define PINCOLUMNS  PINB   
00225 #define DDRCOLUMNS  DDRB   
00226 #define PORTROWS1   PORTA  
00227 #define PINROWS1    PINA   
00228 #define DDRROWS1    DDRA   
00229 #define PORTROWS2   PORTC  
00230 #define PINROWS2    PINC   
00231 #define DDRROWS2    DDRC   
00232 
00233 #define PORTLEDS    PORTD  
00234 #define PINLEDS     PIND   
00235 #define DDRLEDS     DDRD   
00236 #define LEDSCROLL   PIND4  
00237 #define LEDCAPS     PIND5  
00238 #define LEDNUM      PIND6  
00239 
00240 #define PORTJUMPERS PORTD  
00241 #define PINJUMPERS  PIND   
00242 #define DDRJUMPERS  DDRD   
00243 #define JUMPER0     PD1    
00244 #define JUMPER1     PD3    
00245 #define JUMPER2     PD7    
00246 
00247 
00251 static void hardwareInit(void) {
00252     // column-port is input
00253     PORTCOLUMNS = 0xff;
00254     DDRCOLUMNS  = 0x00;
00255 
00256     // row-ports are output
00257     PORTROWS1   = 0xff;
00258     DDRROWS1    = 0x00;
00259     PORTROWS2   = 0xff;
00260     DDRROWS2    = 0x00;
00261 
00262     // port D contains USB (D0, D2),
00263     //                 LEDs (D4, D5, D6)
00264     //             and Jumpers (D1, D3, D7),
00265     // so we call it PORTD instead of PORTJUMPERS or PORTLEDS
00266     PORTD       = 0xfa; // 1000 1010: activate pull-ups except on USB- and LED-lines
00267     DDRD        = 0x75; // 0111 0101: all pins input except USB (-> USB reset) and LED-pins
00268                         // USB Reset by device only required on Watchdog Reset
00269     _delay_us(11);      // delay >10ms for USB reset
00270     DDRD        = 0x70; // 0111 0000 bin: remove USB reset condition
00271 
00272     // configure timer 0 for a rate of 12M/(1024 * 256) = 45.78Hz (~22ms)
00273     TCCR0 = 5;          // timer 0 prescaler: 1024
00274 
00275     // blink, to indicate power-on
00276     PORTLEDS &= ~((1 << LEDNUM) | (1 << LEDCAPS) | (1 << LEDSCROLL));
00277     _delay_ms(50);
00278     PORTLEDS |= ((1 << LEDNUM) | (1 << LEDCAPS) | (1 << LEDSCROLL));
00279 }
00280 
00281 /* ------------------------------------------------------------------------- */
00282 /* ----------------------------- USB interface ----------------------------- */
00283 /* ------------------------------------------------------------------------- */
00284 
00285 static uint8_t reportBuffer[8]; 
00286 static uint8_t idleRate;        
00287 static uint8_t protocolVer = 1; 
00288 uint8_t expectReport = 0;       
00289 
00290 #define LED_NUM     0x01  
00291 #define LED_CAPS    0x02  
00292 #define LED_SCROLL  0x04  
00293 #define LED_COMPOSE 0x08  
00294 #define LED_KANA    0x10  
00295 uint8_t LEDstate = 0;     
00296 
00297 
00302 char PROGMEM usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
00303     0x05, 0x01,   // USAGE_PAGE (Generic Desktop)
00304     0x09, 0x06,   // USAGE (Keyboard)
00305     0xa1, 0x01,   // COLLECTION (Application)
00306     0x05, 0x07,   //   USAGE_PAGE (Keyboard)
00307     0x19, 0xe0,   //   USAGE_MINIMUM (Keyboard LeftControl)
00308     0x29, 0xe7,   //   USAGE_MAXIMUM (Keyboard Right GUI)
00309     0x15, 0x00,   //   LOGICAL_MINIMUM (0)
00310     0x25, 0x01,   //   LOGICAL_MAXIMUM (1)
00311     0x75, 0x01,   //   REPORT_SIZE (1)
00312     0x95, 0x08,   //   REPORT_COUNT (8)
00313     0x81, 0x02,   //   INPUT (Data,Var,Abs)
00314     0x95, 0x01,   //   REPORT_COUNT (1)
00315     0x75, 0x08,   //   REPORT_SIZE (8)
00316     0x81, 0x03,   //   INPUT (Cnst,Var,Abs)
00317     0x95, 0x05,   //   REPORT_COUNT (5)
00318     0x75, 0x01,   //   REPORT_SIZE (1)
00319     0x05, 0x08,   //   USAGE_PAGE (LEDs)
00320     0x19, 0x01,   //   USAGE_MINIMUM (Num Lock)
00321     0x29, 0x05,   //   USAGE_MAXIMUM (Kana)
00322     0x91, 0x02,   //   OUTPUT (Data,Var,Abs)
00323     0x95, 0x01,   //   REPORT_COUNT (1)
00324     0x75, 0x03,   //   REPORT_SIZE (3)
00325     0x91, 0x03,   //   OUTPUT (Cnst,Var,Abs)
00326     0x95, 0x06,   //   REPORT_COUNT (6)
00327     0x75, 0x08,   //   REPORT_SIZE (8)
00328     0x15, 0x00,   //   LOGICAL_MINIMUM (0)
00329     0x25, 0x65,   //   LOGICAL_MAXIMUM (101)
00330     0x05, 0x07,   //   USAGE_PAGE (Keyboard)
00331     0x19, 0x00,   //   USAGE_MINIMUM (Reserved (no event indicated))
00332     0x29, 0x65,   //   USAGE_MAXIMUM (Keyboard Application)
00333     0x81, 0x00,   //   INPUT (Data,Ary,Abs)
00334     0xc0          // END_COLLECTION
00335 };
00336 
00343 uint8_t usbFunctionSetup(uint8_t data[8]) {
00344     usbRequest_t *rq = (void *)data;
00345     usbMsgPtr = reportBuffer;
00346     if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
00347         // class request type
00348         if (rq->bRequest == USBRQ_HID_GET_REPORT) {
00349             // wValue: ReportType (highbyte), ReportID (lowbyte)
00350             // we only have one report type, so don't look at wValue
00351             return sizeof(reportBuffer);
00352         } else if (rq->bRequest == USBRQ_HID_SET_REPORT) {
00353             if (rq->wLength.word == 1) {
00354                 // We expect one byte reports
00355                 expectReport = 1;
00356                 return 0xff; // Call usbFunctionWrite with data
00357             }
00358         } else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
00359             usbMsgPtr = &idleRate;
00360             return 1;
00361         } else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
00362             idleRate = rq->wValue.bytes[1];
00363         } else if (rq->bRequest == USBRQ_HID_GET_PROTOCOL) {
00364             if (rq->wValue.bytes[1] < 1) {
00365                 protocolVer = rq->wValue.bytes[1];
00366             }
00367         } else if(rq->bRequest == USBRQ_HID_SET_PROTOCOL) {
00368             usbMsgPtr = &protocolVer;
00369             return 1;
00370         }
00371     } else {
00372         // no vendor specific requests implemented
00373     }
00374     return 0;
00375 }
00376 
00384 uint8_t usbFunctionWrite(uchar *data, uchar len) {
00385     if (expectReport && (len == 1)) {
00386         LEDstate = data[0]; // Get the state of all 5 LEDs
00387         if (LEDstate & LED_NUM) { // light up caps lock
00388             PORTLEDS &= ~(1 << LEDNUM);
00389         } else {
00390             PORTLEDS |= (1 << LEDNUM);
00391         }
00392         if (LEDstate & LED_CAPS) { // light up caps lock
00393             PORTLEDS &= ~(1 << LEDCAPS);
00394         } else {
00395             PORTLEDS |= (1 << LEDCAPS);
00396         }
00397         if (LEDstate & LED_SCROLL) { // light up caps lock
00398             PORTLEDS &= ~(1 << LEDSCROLL);
00399         } else {
00400             PORTLEDS |= (1 << LEDSCROLL);
00401         }
00402     }
00403     expectReport = 0;
00404     return 0x01;
00405 }
00406 
00413 void usbSendReport(uint8_t mode, uint8_t key) {
00414     // buffer for HID reports. we use a private one, so nobody gets disturbed
00415     uint8_t repBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
00416     repBuffer[0] = mode;
00417     repBuffer[2] = key;
00418     while (!usbInterruptIsReady()); // wait
00419     usbSetInterrupt(repBuffer, sizeof(repBuffer)); // send
00420 }
00421 
00422 /* ------------------------------------------------------------------------- */
00423 
00424 uint8_t curmatrix[16];  
00425 
00433 const uint8_t PROGMEM keymatrix[16][8] = {
00434   // 0              1             2                  3                4               5              6               7
00435     {KEY_Reserved,  KEY_Reserved, KEY_Reserved,      KEY_Reserved,    KEY_Reserved,   KEY_Reserved,  KEY_Reserved,   KEY_Reserved   }, //  0
00436     {KEY_Reserved,  KEY_Reserved, KEY_Reserved,      KEY_Reserved,    KEY_Reserved,   KEY_Reserved,  KEY_Reserved,   KEY_Reserved   }, //  1
00437     {KEY_ESCAPE,    KEY_Tab,      KEY_grave,         KEY_1,           KEY_Q,          KEY_A,         KEY_Z,          KEY_Reserved   }, //  2
00438     {KEY_Euro,      KEY_capslock, KEY_F1,            KEY_2,           KEY_W,          KEY_S,         KEY_X,          KEY_Reserved   }, //  3
00439     {KEY_F4,        KEY_F3,       KEY_F2,            KEY_3,           KEY_E,          KEY_D,         KEY_C,          KEY_Reserved   }, //  4
00440     {KEY_G,         KEY_T,        KEY_5,             KEY_4,           KEY_R,          KEY_F,         KEY_V,          KEY_B          }, //  5
00441     {KEY_F5,        KEY_DELETE,   KEY_F9,            KEY_F10,         KEY_Reserved,   KEY_Reserved,  KEY_Return,     KEY_Spacebar   }, //  6
00442     {KEY_H,         KEY_Y,        KEY_6,             KEY_7,           KEY_U,          KEY_J,         KEY_M,          KEY_N          }, //  7
00443     {KEY_F6,        KEY_rbracket, KEY_equals,        KEY_8,           KEY_I,          KEY_K,         KEY_comma,      KEY_Reserved   }, //  8
00444     {KEY_Reserved,  KEY_F7,       KEY_F8,            KEY_9,           KEY_O,          KEY_L,         KEY_dot,        KEY_Reserved   }, //  9
00445     {KEY_apostroph, KEY_lbracket, KEY_minus,         KEY_0,           KEY_P,          KEY_semicolon, KEY_hash,       KEY_slash      }, // 10
00446     {KEY_Reserved,  KEY_KP4,      KEY_DeleteForward, KEY_F11,         KEY_KP7,        KEY_KP1,       KEY_NumLock,    KEY_DownArrow  }, // 11
00447     {KEY_KP0,       KEY_KP5,      KEY_Insert,        KEY_F12,         KEY_KP8,        KEY_KP2,       KEY_KPslash,    KEY_RightArrow }, // 12
00448     {KEY_KPcomma,   KEY_KP6,      KEY_PageUp,        KEY_PageDown,    KEY_KP9,        KEY_KP3,       KEY_KPasterisk, KEY_KPminus    }, // 13
00449     {KEY_UpArrow,   KEY_Reserved, KEY_Home,          KEY_End,         KEY_KPplus,     KEY_KPenter,   KEY_Pause,      KEY_LeftArrow  }, // 14
00450     {KEY_Reserved,  KEY_Reserved, KEY_Reserved,      KEY_PrintScreen, KEY_ScrollLock, KEY_Reserved,  KEY_Reserved,   KEY_Reserved   }, // 15
00451 };
00452 
00458 const uint8_t PROGMEM modmatrix[16][8] = { // contains positions of modifiers in the matrix
00459   // 0             1               2                 3         4         5         6                  7
00460     {MOD_NONE,     MOD_NONE,       MOD_CONTROL_LEFT, MOD_NONE, MOD_NONE, MOD_NONE, MOD_CONTROL_RIGHT, MOD_NONE     }, //  0
00461     {MOD_NONE,     MOD_SHIFT_LEFT, MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_SHIFT_RIGHT,   MOD_NONE     }, //  1
00462     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, //  2
00463     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, //  3
00464     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, //  4
00465     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, //  5
00466     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, //  6
00467     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, //  7
00468     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, //  8
00469     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, //  9
00470     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, // 10
00471     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, // 11
00472     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, // 12
00473     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, // 13
00474     {MOD_NONE,     MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_NONE     }, // 14
00475     {MOD_ALT_LEFT, MOD_NONE,       MOD_NONE,         MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE,          MOD_ALT_RIGHT}, // 15
00476 };
00477 
00482 typedef struct {
00483     uint8_t mode;
00484     uint8_t key;
00485 } Key;
00486 
00493 Key charToKey(char character) {
00494     Key key;
00495     // initialize with reserved values
00496     key.mode = MOD_NONE;
00497     key.key = KEY_Reserved;
00498     if ((character >= 'a') && (character <= 'z')) {
00499         // a..z
00500         key.key = (character - 'a') + 0x04;
00501     } else if ((character >= 'A') && (character <= 'Z')) {
00502         // A..Z
00503         key.mode = MOD_SHIFT_LEFT;
00504         key.key = (character - 'A') + 0x04;
00505     } else if ((character >= '1') && (character <= '9')) {
00506         // 1..9
00507         key.key = (character - '1') + 0x1E;
00508     }
00509     // we can't map the other characters directly, so we switch...
00510     switch (character) {
00511         case '0':
00512             key.key = KEY_0; break;
00513         case '!':
00514             key.mode = MOD_SHIFT_LEFT;
00515             key.key = KEY_1; break;
00516         /*
00517         case '@':
00518             key.mode = MOD_SHIFT_LEFT;
00519             key.key = KEY_2; break;
00520         case '#':
00521             key.mode = MOD_SHIFT_LEFT;
00522             key.key = KEY_3; break;
00523         */
00524         case '$':
00525             key.mode = MOD_SHIFT_LEFT;
00526             key.key = KEY_4; break;
00527         case '%':
00528             key.mode = MOD_SHIFT_LEFT;
00529             key.key = KEY_5; break;
00530         case '^':
00531             key.mode = MOD_SHIFT_LEFT;
00532             key.key = KEY_6; break;
00533         case '&':
00534             key.mode = MOD_SHIFT_LEFT;
00535             key.key = KEY_7; break;
00536         case '*':
00537             key.mode = MOD_SHIFT_LEFT;
00538             key.key = KEY_8; break;
00539         case '(':
00540             key.mode = MOD_SHIFT_LEFT;
00541             key.key = KEY_9; break;
00542         case ')':
00543             key.mode = MOD_SHIFT_LEFT;
00544             key.key = KEY_0; break;
00545         case ' ':
00546             key.key = KEY_Spacebar; break;
00547         case '-':
00548             key.key = KEY_minus; break;
00549         case '_':
00550             key.mode = MOD_SHIFT_LEFT;
00551             key.key = KEY_minus; break;
00552         case '=':
00553             key.key = KEY_equals; break;
00554         case '+':
00555             key.mode = MOD_SHIFT_LEFT;
00556             key.key = KEY_equals; break;
00557         case '[':
00558             key.key = KEY_lbracket; break;
00559         case '{':
00560             key.mode = MOD_SHIFT_LEFT;
00561             key.key = KEY_lbracket; break;
00562         case ']':
00563             key.key = KEY_rbracket; break;
00564         case '}':
00565             key.mode = MOD_SHIFT_LEFT;
00566             key.key = KEY_rbracket; break;
00567         case '\\':
00568             key.key = KEY_backslash; break;
00569         case '|':
00570             key.mode = MOD_SHIFT_LEFT;
00571             key.key = KEY_backslash; break;
00572         case '#':
00573             key.key = KEY_hash; break;
00574         case '@':
00575             key.mode = MOD_SHIFT_LEFT;
00576             key.key = KEY_hash; break;
00577         case ';':
00578             key.key = KEY_semicolon; break;
00579         case ':':
00580             key.mode = MOD_SHIFT_LEFT;
00581             key.key = KEY_semicolon; break;
00582         case '\'':
00583             key.key = KEY_apostroph; break;
00584         case '"':
00585             key.mode = MOD_SHIFT_LEFT;
00586             key.key = KEY_apostroph; break;
00587         case '`':
00588             key.key = KEY_grave; break;
00589         case '~':
00590             key.mode = MOD_SHIFT_LEFT;
00591             key.key = KEY_grave; break;
00592         case ',':
00593             key.key = KEY_comma; break;
00594         case '<':
00595             key.mode = MOD_SHIFT_LEFT;
00596             key.key = KEY_comma; break;
00597         case '.':
00598             key.key = KEY_dot; break;
00599         case '>':
00600             key.mode = MOD_SHIFT_LEFT;
00601             key.key = KEY_dot; break;
00602         case '/':
00603             key.key = KEY_slash; break;
00604         case '?':
00605             key.mode = MOD_SHIFT_LEFT;
00606             key.key = KEY_slash; break;
00607     }
00608     if (key.key == KEY_Reserved) {
00609         // still reserved? WTF? return question mark...
00610         key.mode = MOD_SHIFT_LEFT;
00611         key.key = KEY_slash;
00612     }
00613     return key;
00614 } 
00615 
00621 void sendKey(Key keytosend) {
00622     usbSendReport(keytosend.mode, keytosend.key);
00623     usbSendReport(0, 0);
00624 }
00625 
00631 void sendString(char* string) {
00632     for (uint8_t i = 0; i < strlen(string); i++) {
00633         Key key = charToKey(string[i]);
00634         sendKey(key);
00635     }
00636 }
00637 
00642 void printMatrix(void) {
00643     for (uint8_t i = 0; i <= 15; i++) {
00644         char buffer[10];
00645         /*
00646         sprintf(buffer, "%d%d%d%d%d%d%d%d.",
00647                 (curmatrix[i] & (1 << 0) ? 1 : 0),
00648                 (curmatrix[i] & (1 << 1) ? 1 : 0),
00649                 (curmatrix[i] & (1 << 2) ? 1 : 0),
00650                 (curmatrix[i] & (1 << 3) ? 1 : 0),
00651                 (curmatrix[i] & (1 << 4) ? 1 : 0),
00652                 (curmatrix[i] & (1 << 5) ? 1 : 0),
00653                 (curmatrix[i] & (1 << 6) ? 1 : 0),
00654                 (curmatrix[i] & (1 << 7) ? 1 : 0));
00655                 */
00656         sprintf(buffer, "%2x", curmatrix[i]);
00657         sendString(buffer);
00658         if (i == 7) {
00659             sendString(":");
00660         } else {
00661             sendString(".");
00662         }
00663     }
00664     sendString("---");
00665 }
00666 
00679 uint8_t scankeys(void) {
00680     static uint8_t debounce = 5;
00681     uint8_t retval = 0;
00682     for (uint8_t row = 0; row <= 15; row++) {
00683         if (row <= 7) {
00684             DDRROWS1  = (1 << row);
00685             PORTROWS1 = ~(1 << row);
00686             DDRROWS2  = 0x00;
00687             PORTROWS2 = 0xff;
00688         } else {
00689             DDRROWS1  = 0x00;
00690             PORTROWS1 = 0xff;
00691             // (15 - row) looks a bit weird, you would expect (row - 8) here.
00692             // This is because pins on PORTC are ordered in the other direction
00693             // than on PORTA. With (15 - row), we have the bytes in the
00694             // resulting matrix matching the pins of the keyboard connector.
00695             DDRROWS2  = (1 << (15 - row));
00696             PORTROWS2 = ~(1 << (15 - row));
00697         }
00698         _delay_us(30);
00699         uint8_t data = ~PINCOLUMNS;
00700         if (data != curmatrix[row]) {
00701             // if a change was detected
00702             debounce = 10; // activate debounce counter
00703             curmatrix[row] = data; // and store the result
00704         }
00705     }
00706     if (debounce) {
00707         // Count down, but avoid underflow
00708         debounce--;
00709     }
00710     if (debounce == 1) {
00711         // debounce counter expired, create report
00712         uint8_t reportIndex = 2; // reportBuffer[0] contains modifiers
00713         memset(reportBuffer, 0, sizeof(reportBuffer)); // clear report buffer
00714         for (uint8_t row = 0; row <= 15; row++) { // process all rows for key-codes
00715             uint8_t data = curmatrix[row]; // restore buffer
00716             if (data != 0xff) { // anything on this row? - optimization
00717                 for (uint8_t col = 0; col <= 7; col++) { // check every bit on this row
00718                     uint8_t key, modifier;
00719                     if (data & (1 << col)) {
00720                         key = pgm_read_byte(&keymatrix[row][col]);
00721                         modifier = pgm_read_byte(&modmatrix[row][col]);
00722                     } else {
00723                         key = KEY_Reserved;
00724                         modifier = MOD_NONE;
00725                     }
00726                     if (key != KEY_Reserved) { // keycode should be added to report
00727                         if (reportIndex >= sizeof(reportBuffer)) { // too many keycodes
00728                             if (!retval & 0x02) { // Only fill buffer once
00729                                 memset(reportBuffer+2, KEY_ErrorRollOver, sizeof(reportBuffer)-2);
00730                                 retval |= 0x02; // continue decoding to get modifiers
00731                             }
00732                         } else {
00733                             reportBuffer[reportIndex] = key; // set next available entry
00734                             reportIndex++;
00735                         }
00736                     }
00737                     if (modifier != MOD_NONE) { // modifier should be added to report
00738                         reportBuffer[0] |= modifier;
00739                     }
00740                 }
00741             }
00742         }
00743         retval |= 0x01; // must have been a change at some point, since debounce is done
00744     }
00745     return retval;
00746 }
00747 
00748 /* ------------------------------------------------------------------------- */
00749 
00755 int main(void) {
00756     uint8_t updateNeeded = 0;
00757     uint8_t idleCounter = 0;
00758     wdt_enable(WDTO_2S);
00759     hardwareInit();
00760     usbInit();
00761     sei();
00762 
00763     scankeys();
00764     while (1) {
00765         // main event loop
00766         wdt_reset();
00767         usbPoll();
00768 
00769         updateNeeded = scankeys(); // changes?
00770 
00771         // check timer if we need periodic reports
00772         if (TIFR & (1 << TOV0)) {
00773             TIFR = (1 << TOV0); // reset flag
00774             if (idleRate != 0) { // do we need periodic reports?
00775                 if(idleCounter > 4){ // yes, but not yet
00776                     idleCounter -= 5; // 22ms in units of 4ms
00777                 } else { // yes, it is time now
00778                     updateNeeded = 1;
00779                     idleCounter = idleRate;
00780                 }
00781             }
00782         }
00783         // if an update is needed, send the report
00784         if (updateNeeded && usbInterruptIsReady()) {
00785             updateNeeded = 0;
00786             usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
00787         }
00788     }
00789     return 0;
00790 }
00791 
00792 /* ------------------------------------------------------------------------- */

Generated on Sat Jul 12 22:27:15 2008 for Dulcimer by  doxygen 1.5.4