/** * The write function is called when LEDs should be set. Normally, we get only * one byte that contains info about the LED states. * \param data pointer to received data * \param len number ob bytes received * \return 0x01 */ uint8_t usbFunctionWrite(uchar *data, uchar len) { // DBG1(0xBB, (uchar *)&len, 1); if (expectReport == 1 && (len == 1)) { // change LEDs of indicator delegateLedUsb(data[0]); expectReport = 0; }else if (expectReport == 2){ // options DBG1(0xEE, data, len); // start bootloader if(data[1] == OPTION_INDEX_BOOTLOADER && len == 8){ if(data[2] == 0xFF){ eeprom_write_byte((uint8_t *)EEPROM_BOOTLOADER_START, 0x00); } delegateGotoBootloader(); /* TODO * 이전 버전과 호환을 위해 남겨둠 */ #ifdef ENABLE_BOOTMAPPER }else if(data[1] == OPTION_INDEX_BOOTMAPPER){ if(data[2] == OPTION_VALUE_BOOTMAPPER_START){ setToBootMapper(true); }else{ setToBootMapper(false); } #endif /* }else if(data[1] == OPTION_INDEX_READY){ stopPwmForUsbReport(true); }else if(data[1] == OPTION_INDEX_ACTION){ stopPwmForUsbReport(false);*/ }else{ setOptions((uint8_t *)data); } }else if (expectReport == 4){ // rainbow color setting setOptions((uint8_t *)data); }else if (expectReport == 5){ // write quick macro; updateQuickMacro((uint8_t *)data, len); } return 0x01; }
/** * This function is called whenever we receive a setup request via USB. * \param data[8] eight bytes of data we received * \return number of bytes to use, or 0xff if usbFunctionWrite() should be * called */ usbMsgLen_t usbFunctionSetup(uint8_t data[8]) { delegateInterfaceReadyUsb(); static uint8_t readyForNext = 0; usbRequest_t *rq = (void *)data; // DBG1(0xCC, data, 8); if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) { // class request type if (rq->bRequest == USBRQ_HID_GET_REPORT) { if (rq->wValue.word == HID_REPORT_KEBOARD) { // wValue: ReportType (highbyte), ReportID (lowbyte) usbMsgPtr = (usbMsgPtr_t)&reportKeyboard; return sizeof(reportKeyboard); }else if(rq->wValue.word == HID_REPORT_BOOT){ if(rq->wLength.word == OPTION_GET_REPORT_LENGTH_RAINBOW){ // ready for rainbow color setting; readyForNext = NEXT_RAINBOW; }else if(rq->wLength.word >= OPTION_GET_REPORT_LENGTH_QUICK_MACRO1 && rq->wLength.word <= OPTION_GET_REPORT_LENGTH_QUICK_MACRO12){ readyForNext = rq->wLength.word; } }else if(rq->wValue.word == HID_REPORT_OPTION){ // length : rq->wLength.word 필요한 리포트를 length로 구분한다. if(rq->wLength.word == OPTION_GET_REPORT_LENGTH_INFO){ // report led2 info static option_info_t optionsBuffer; getOptions(&optionsBuffer); usbMsgPtr = (usbMsgPtr_t)&optionsBuffer; return sizeof(optionsBuffer); //OPTION_GET_REPORT_LENGTH_INFO; }else if(rq->wLength.word == OPTION_GET_REPORT_LENGTH_TOGGLE_BOOTMAPPER){ static bool gIsBootloader; if(isBootMapper()){ setToBootMapper(false); gIsBootloader = false; }else{ setToBootMapper(true); gIsBootloader = true; } usbMsgPtr = (usbMsgPtr_t)&gIsBootloader; return 1; #if HAS_OPTIONS }else if(rq->wLength.word >= OPTION_GET_REPORT_LENGTH_KEYMAP_LAYER1 && rq->wLength.word <= OPTION_GET_REPORT_LENGTH_KEYMAP_LAYER4){ // keymap usbMsgFlags = USB_FLG_MSGPTR_IS_ROM; usbMsgPtr = (usbMsgPtr_t)(KEYMAP_ADDRESS + (ROWS * COLUMNS * (rq->wLength.word - OPTION_GET_REPORT_LENGTH_KEYMAP_LAYER1))); return OPTION_GET_REPORT_LENGTH_KEYMAP; }else if(rq->wLength.word >= OPTION_GET_REPORT_LENGTH_MACRO1 && rq->wLength.word <= OPTION_GET_REPORT_LENGTH_MACRO12){ // cst macro usbMsgFlags = USB_FLG_MSGPTR_IS_ROM; usbMsgPtr = (usbMsgPtr_t)(CUSTOM_MACRO_ADDRESS+(CUSTOM_MACRO_SIZE_MAX * (rq->wLength.word - OPTION_GET_REPORT_LENGTH_MACRO1))); return CUSTOM_MACRO_SIZE_MAX; }else if(rq->wLength.word == OPTION_GET_OPTION_INDEX_DUALACTION){ // dual action usbMsgFlags = USB_FLG_MSGPTR_IS_ROM; usbMsgPtr = (usbMsgPtr_t)(DUALACTION_ADDRESS); return DUALACTION_BYTES; }else if(rq->wLength.word >= OPTION_GET_REPORT_LENGTH_QUICK_MACRO1 && rq->wLength.word <= OPTION_GET_REPORT_LENGTH_QUICK_MACRO12){ usbMsgFlags = USB_FLG_USE_USER_RW; usbMsgPtr = (usbMsgPtr_t)(EEPROM_MACRO+(MACRO_SIZE_MAX * (rq->wLength.word - OPTION_GET_REPORT_LENGTH_QUICK_MACRO1))); return MACRO_SIZE_MAX; #else }else if(rq->wLength.word >= OPTION_GET_REPORT_LENGTH_KEYMAP_LAYER1 && rq->wLength.word <= OPTION_GET_REPORT_LENGTH_KEYMAP_LAYER4){ // keymap usbMsgFlags = USB_FLG_MSGPTR_IS_ROM; usbMsgPtr = (usbMsgPtr_t)(KEYMAP_ADDRESS + (ROWS * COLUMNS * (rq->wLength.word - OPTION_GET_REPORT_LENGTH_KEYMAP_LAYER1))); return OPTION_GET_REPORT_LENGTH_KEYMAP; }else if(rq->wLength.word >= OPTION_GET_REPORT_LENGTH_MACRO1 && rq->wLength.word <= OPTION_GET_REPORT_LENGTH_MACRO12){ // cst macro usbMsgFlags = USB_FLG_MSGPTR_IS_ROM; usbMsgPtr = (usbMsgPtr_t)(CUSTOM_MACRO_ADDRESS+(CUSTOM_MACRO_SIZE_MAX * (rq->wLength.word - OPTION_GET_REPORT_LENGTH_MACRO1))); return CUSTOM_MACRO_SIZE_MAX; }else if(rq->wLength.word == OPTION_GET_OPTION_INDEX_DUALACTION){ // dual action usbMsgFlags = USB_FLG_MSGPTR_IS_ROM; usbMsgPtr = (usbMsgPtr_t)(DUALACTION_ADDRESS); return DUALACTION_BYTES; }else if(rq->wLength.word >= OPTION_GET_REPORT_LENGTH_QUICK_MACRO1 && rq->wLength.word <= OPTION_GET_REPORT_LENGTH_QUICK_MACRO12){ usbMsgFlags = USB_FLG_USE_USER_RW; usbMsgPtr = (usbMsgPtr_t)(EEPROM_MACRO+(MACRO_SIZE_MAX * (rq->wLength.word - OPTION_GET_REPORT_LENGTH_QUICK_MACRO1))); return MACRO_SIZE_MAX; #endif }else { return rq->wLength.word; } } } else if (rq->bRequest == USBRQ_HID_SET_REPORT) { // DBG1(0xAA, (uchar *)&rq->wValue.word, 2); // 02 03 : Report Type: 0x03, ReportID: 0x02 // 01 03 : Report Type: 0x03, ReportID: 0x01 // Report Type: 0x02(Out)/ReportID: 0x00(none) && Interface: 0(keyboard) if (rq->wValue.word == HID_REPORT_KEBOARD && rq->wIndex.word == 0) { // We expect one byte reports expectReport = 1; return USB_NO_MSG; // Call usbFunctionWrite with data }else if(rq->wValue.word == HID_REPORT_BOOT){ // boot // isStart = 1; if(readyForNext == NEXT_RAINBOW){ data[1] = OPTION_INDEX_COLOR_RAINBOW_INIT; // init setting; setOptions((uint8_t *)data); expectReport = 4; }else if(readyForNext >= OPTION_GET_REPORT_LENGTH_QUICK_MACRO1 && readyForNext <= OPTION_GET_REPORT_LENGTH_QUICK_MACRO12){ // write quick macro IsAddressHead = true; quickMacroAddress = EEPROM_MACRO + (MACRO_SIZE_MAX * (readyForNext - OPTION_GET_REPORT_LENGTH_QUICK_MACRO1)); expectReport = 5; } readyForNext = 0; return USB_NO_MSG; // Call usbFunctionWrite with data }else if(rq->wValue.word == HID_REPORT_OPTION){ // options expectReport = 2; return USB_NO_MSG; // Call usbFunctionWrite with data } } else if (rq->bRequest == USBRQ_HID_GET_IDLE) { usbMsgPtr = idleRate; // DBG1(0x71, (uchar *)&idleRate, 1); return 1; } else if (rq->bRequest == USBRQ_HID_SET_IDLE) { delegateInitInterfaceUsb(); idleRate = rq->wValue.bytes[1]; // DBG1(0x70, (uchar *)&idleRate, 1); } else if (rq->bRequest == USBRQ_HID_GET_PROTOCOL) { if (rq->wValue.bytes[1] < 1) { protocolVer = rq->wValue.bytes[1]; } } else if(rq->bRequest == USBRQ_HID_SET_PROTOCOL) { usbMsgPtr = protocolVer; return 1; } } else { // no vendor specific requests implemented } return 0; }
/** * The write function is called when LEDs should be set. Normally, we get only * one byte that contains info about the LED states. * \param data pointer to received data * \param len number ob bytes received * \return 0x01 */ uint8_t usbFunctionWrite(uchar *data, uchar len) { DBG1(0xBB, (uchar *)&len, 1); if (expectReport == 1 && (len == 1)) { delegateLedUsb(data[0]); expectReport = 0; }else if (expectReport == 2){ // options DBG1(0xEE, data, len); // start bootloader if(data[1] == OPTION_INDEX_BOOTLOADER && len == 8){ if(data[2] == 0xFF){ eeprom_write_byte((uint8_t *)EEPROM_BOOTLOADER_START, 0x00); } delegateGotoBootloader(); #ifdef ENABLE_BOOTMAPPER }else if(data[1] == OPTION_INDEX_BOOTMAPPER){ if(data[2] == OPTION_VALUE_BOOTMAPPER_START){ setToBootMapper(true); }else{ setToBootMapper(false); } #endif }else if(data[1] == OPTION_INDEX_READY){ //stop timer // stop timer1 stopFullLed(); }else if(data[1] == OPTION_INDEX_ACTION){ // start timer1 startFullLed(); }else{ setLed2((uint8_t *)data); } // expectReport = 0; }else if (expectReport == 4){ // rainbow color setting DBG1(0x44, data, len); setLed2((uint8_t *)data); }else if (expectReport == 3){ // HID_REPORT_BOOT DBG1(0xDD, data, len); /* * 44: 02 10 00 00 00 00 00 00 44: ff 00 ff 00 ff 00 00 00 44: 00 00 00 00 00 00 00 00 44: 00 00 00 00 00 00 00 00 44: 00 00 00 */ // uchar isLast; // static uchar offset; // if(isStart == 1){ // isStart = 0; // offset = 0; // len -= 4; // } // offset += len; // isLast = offset & 0x80; /* != 0 if last block received */ // DBG1(0xDE, (void *)&isLast, 1); // return isLast; /* uint8_t gRet; gRet = writeFlash(data, len, isStart); if(isStart == 1){ isStart = 0; } DBG1(0xDF, (uchar *)&gRet, 1); return gRet;*/ /* * * * 여기까지 제대로 실행이 되지만, '커뮤니케이션 에러'가 발생하면서 다음 page로 진행이 되지 않는다. * - 일단 page는 저장이 된 상태 * * USB_CFG_SUPPRESS_INTR_CODE 와 USB_CFG_INTR_POLL_INTERVAL 값을 변경해야 통신이 원활히 된다. * (아마도 다른 인터럽트를 허용하지 않고 해당 통신만 전담하는 세팅인것 같다.) * * USB_CFG_INTR_POLL_INTERVAL를 높히면 매크로 출력시 속도가 느리고, * USB_CFG_SUPPRESS_INTR_CODE를 1로 설정하면 키보드로 작동을 안한다. * * 이 둘을 최적화 했다 치더라도, 통신 중(페이지 단위로 쓰기 위해서 8바이트씩 전송되는 데이터를 조합하고 이 페이지를 5개 받는다)에 * 플래시를 쓰면 커뮤니케이션 에러가 발생하고, * * 이를 방지하기 위해서 모든 페이지를 메모리에 저장 후 쓰려고 하면, 작동은하지만 메모리가 부족한 현상이 있다. * * * * * */ } return 0x01; }