X-Git-Url: https://git.cryptolib.org/?p=labortage2013badge.git;a=blobdiff_plain;f=firmware%2Fmain.c;h=a266a59a8ec61ba3b9c6a4fb9d764495fc9ad9ee;hp=b9fa41f155ff38867e599c86806637d865782df7;hb=b5f34edfe75543109080c5557b20a5dea8446f27;hpb=2da43c43d4818a4f2e3af7e8ec138c1f98019d9e diff --git a/firmware/main.c b/firmware/main.c index b9fa41f..a266a59 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -25,6 +25,7 @@ different port or bit, change the macros below: #include #include +#include #include #include @@ -43,35 +44,40 @@ void update_pwm(void); /* ------------------------------------------------------------------------- */ /* ----------------------------- USB interface ----------------------------- */ /* ------------------------------------------------------------------------- */ -const PROGMEM char usbHidReportDescriptor[35] = { /* USB report descriptor */ +PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) - 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x05, 0x07, // USAGE_PAGE (Keyboard)(Key Codes) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)(224) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)(231) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) ; Modifier byte + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) ; Reserved byte + 0x95, 0x05, // REPORT_COUNT (5) 0x75, 0x01, // REPORT_SIZE (1) - 0x95, 0x08, // REPORT_COUNT (8) - 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) ; LED report 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) ; LED report padding + 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x65, // LOGICAL_MAXIMUM (101) - 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard)(Key Codes) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))(0) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)(101) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0 // END_COLLECTION }; -/* We use a simplifed keyboard report descriptor which does not support the - * boot protocol. We don't allow setting status LEDs and we only allow one - * simultaneous key press (except modifiers). We can therefore use short - * 2 byte input reports. - * The report descriptor has been created with usb.org's "HID Descriptor Tool" - * which can be downloaded from http://www.usb.org/developers/hidpage/. - * Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted - * for the second INPUT item. - */ /* Keyboard usage values, see usb.org's HID-usage-tables document, chapter * 10 Keyboard/Keypad Page for more codes. @@ -135,17 +141,15 @@ const PROGMEM char usbHidReportDescriptor[35] = { /* USB report descriptor */ #define KEY_F11 68 #define KEY_F12 69 -union { - struct { - uint16_t red; - uint16_t green; - uint16_t blue; - } name; - uint16_t idx[3]; -} color; +#define NUM_LOCK 1 +#define CAPS_LOCK 2 +#define SCROLL_LOCK 4 + #define UNI_BUFFER_SIZE 16 +static uint8_t dbg_buffer[8]; + static union { uint8_t w8[UNI_BUFFER_SIZE]; uint16_t w16[UNI_BUFFER_SIZE/2]; @@ -155,13 +159,36 @@ static union { static uint8_t uni_buffer_fill; static uint8_t current_command; + +typedef struct { + uint8_t modifier; + uint8_t reserved; + uint8_t keycode[6]; +} keyboard_report_t; + +#define STATE_WAIT 0 +#define STATE_SEND_KEY 1 +#define STATE_RELEASE_KEY 2 + + +static keyboard_report_t keyboard_report; // sent to PC +static uchar idleRate; /* in 4 ms units */ +static uchar key_state = STATE_WAIT; +volatile static uchar LED_state = 0xff; // received from PC /* ------------------------------------------------------------------------- */ +void buildReport(uchar send_key) { + keyboard_report.modifier = 0; + + if(send_key >= 'a' && send_key <= 'z') + keyboard_report.keycode[0] = 4 + (send_key - 'a'); + else + keyboard_report.keycode[0] = 0; +} uint8_t read_button(void){ - uint8_t t,u,v=0; + uint8_t t,v=0; t = DDRB; - u = PORTB; DDRB &= ~(1<bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR) - { + if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) { /* class request type */ + switch(rq->bRequest) { + case USBRQ_HID_GET_REPORT: // send "no keys pressed" if asked here + // wValue: ReportType (highbyte), ReportID (lowbyte) + usbMsgPtr = (void *)&keyboard_report; // we only have this one + keyboard_report.modifier = 0; + keyboard_report.keycode[0] = 0; + return sizeof(keyboard_report); + case USBRQ_HID_SET_REPORT: // if wLength == 1, should be LED state + if (rq->wLength.word == 1) { + current_command = LED_WRITE; + return USB_NO_MSG; + } + return 0; + case USBRQ_HID_GET_IDLE: // send idle rate to PC as required by spec + usbMsgPtr = &idleRate; + return 1; + case USBRQ_HID_SET_IDLE: // save idle rate as required by spec + idleRate = rq->wValue.bytes[1]; + return 0; + } + } + if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR) { current_command = rq->bRequest; switch(rq->bRequest) { - case CUSTOM_RQ_SET_RED: - color.name.red = rq->wValue.bytes[0]; - break; - case CUSTOM_RQ_SET_GREEN: - color.name.green = rq->wValue.bytes[0]; - break; - case CUSTOM_RQ_SET_BLUE: - color.name.blue = rq->wValue.bytes[0]; - break; - case CUSTOM_RQ_SET_RGB: + case CUSTOM_RQ_PRESS_BUTTON: + key_state = STATE_SEND_KEY; + return 0; + case CUSTOM_RQ_CLR_DBG: + memset(dbg_buffer, 0, sizeof(dbg_buffer)); + return 0; + case CUSTOM_RQ_SET_DBG: return USB_NO_MSG; - case CUSTOM_RQ_GET_RGB:{ - usbMsgLen_t len=6; - if(len>rq->wLength.word){ + case CUSTOM_RQ_GET_DBG:{ + usbMsgLen_t len = 8; + if(len > rq->wLength.word){ len = rq->wLength.word; } - usbMsgPtr = (uchar*)color.idx; + usbMsgPtr = dbg_buffer; return len; } case CUSTOM_RQ_READ_MEM: @@ -235,37 +279,37 @@ usbMsgLen_t usbFunctionSetup(uchar data[8]) usbMsgPtr = uni_buffer.w8; return 1; case CUSTOM_RQ_READ_TMPSENS: - uni_buffer.w16[0] = read_tmpsensor(); + uni_buffer.w16[0] = read_temperture_sensor(); usbMsgPtr = uni_buffer.w8; return 2; } } - else - { - /* calls requests USBRQ_HID_GET_REPORT and USBRQ_HID_SET_REPORT are - * not implemented since we never call them. The operating system - * won't call them either because our descriptor defines no meaning. - */ - } + return 0; /* default for not implemented requests: return no data back to host */ } + uchar usbFunctionWrite(uchar *data, uchar len) { switch(current_command){ - case CUSTOM_RQ_SET_RGB: - if(len!=6){ - return 1; + + case LED_WRITE: + if (data[0] != LED_state) + LED_state = data[0]; + return 1; // Data read, not expecting more + case CUSTOM_RQ_SET_DBG: + if(len > sizeof(dbg_buffer)){ + len = sizeof(dbg_buffer); } - memcpy(color.idx, data, 6); + memcpy(dbg_buffer, data, len); return 1; case CUSTOM_RQ_WRITE_MEM: memcpy(uni_buffer.ptr[0], data, len); uni_buffer.w16[0] += len; return !(uni_buffer.w16[1] -= len); case CUSTOM_RQ_EXEC_SPM: - if(uni_buffer_fill<8){ - uint8_t l = 8-uni_buffer_fill; + if(uni_buffer_fill < 8){ + uint8_t l = 8 - uni_buffer_fill; if(len8){ + if (uni_buffer.w16[1] > 8) { memcpy(uni_buffer.ptr[0], data, len); uni_buffer.w16[0] += len; return 0; - }else{ + } else { memcpy(&(uni_buffer.w8[uni_buffer_fill]), data, len); exec_spm(uni_buffer.w16[2], uni_buffer.w16[3], uni_buffer.ptr[0], data, len); return 1; @@ -289,7 +333,7 @@ uchar usbFunctionWrite(uchar *data, uchar len) return 0; } uchar usbFunctionRead(uchar *data, uchar len){ - uchar ret=len; + uchar ret = len; switch(current_command){ case CUSTOM_RQ_READ_FLASH: while(len--){ @@ -309,22 +353,22 @@ uchar trialValue = 0, optimumValue; int x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5); /* do a binary search: */ - do{ + do { OSCCAL = trialValue + step; x = usbMeasureFrameLength(); // proportional to current real frequency if(x < targetValue) // frequency still too low trialValue += step; step >>= 1; - }while(step > 0); + } while(step > 0); /* We have a precision of +/- 1 for optimum OSCCAL here */ /* now do a neighborhood search for optimum value */ optimumValue = trialValue; optimumDev = x; // this is certainly far away from optimum - for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){ + for (OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){ x = usbMeasureFrameLength() - targetValue; - if(x < 0) + if (x < 0) x = -x; - if(x < optimumDev){ + if (x < optimumDev) { optimumDev = x; optimumValue = OSCCAL; } @@ -357,24 +401,44 @@ int main(void) * additional hardware initialization. */ - init_tmpsensor(); + memset(&keyboard_report, 0, sizeof(keyboard_report)); + + init_temperature_sensor(); usbInit(); usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ i = 0; - while(--i){ /* fake USB disconnect for > 250 ms */ + while(--i){ /* fake USB disconnect for ~512 ms */ wdt_reset(); - _delay_ms(1); + _delay_ms(2); } usbDeviceConnect(); LED_PORT_DDR |= _BV(R_BIT) | _BV(G_BIT) | _BV(B_BIT); /* make the LED bit an output */ + sei(); for(;;){ /* main event loop */ - update_pwm(); + // update_pwm(); wdt_reset(); usbPoll(); + + if(usbInterruptIsReady() && key_state != STATE_WAIT){ + switch(key_state) { + case STATE_SEND_KEY: + buildReport('x'); + key_state = STATE_RELEASE_KEY; // release next + break; + case STATE_RELEASE_KEY: + buildReport(0); + default: + key_state = STATE_WAIT; // should not happen + } + // start sending + usbSetInterrupt((void *)&keyboard_report, sizeof(keyboard_report)); + + } + } return 0; }