usbMsgLen_t usbFunctionSetup(uint8_t data[8]) { usbRequest_t *rq = (void *)data; usbMsgPtr = usbOutputBuffer; if (rq->bRequest == REQ_TEST_PROGRAMMER) { usbOutputBuffer[0] = ERROR_OK; usbOutputBuffer[1] = MAJOR_VERSION; usbOutputBuffer[2] = MINOR_VERSION; usbOutputBuffer[3] = rq->wValue.bytes[0]; usbOutputBuffer[4] = rq->wValue.bytes[1]; usbOutputBuffer[5] = rq->wIndex.bytes[0]; usbOutputBuffer[6] = rq->wIndex.bytes[1]; return 7; } else if (rq->bRequest == REQ_TURN_PROG_ON) { return turnProgOn(); } else if (rq->bRequest == REQ_TURN_PROG_OFF) { return turnProgOff(); } else if (rq->bRequest == REQ_TEST_NRF) { return nrfTest(); } else if (rq->bRequest == REQ_PROGRAM_PAGE) { return programPage(rq->wValue.word, rq->wIndex.word); } else if(rq->bRequest == REQ_READ) { return readMemory(rq->wValue.word, rq->wIndex.word); } else if(rq->bRequest == REQ_ERASE_PAGE) { return erasePage(rq->wValue.word); } return 0; }
void avrisp() { static uint16_t address = 0; uint8_t ch = getch(); switch (ch) { case '0': // signon _error = 0; reply(); break; case '1': if (receiveEop()) { Serial.print("AVR ISP"); Serial.write(STK_OK); } break; case 'A': replyVersion(getch()); break; case 'B': fill(20); setParameters(); reply(); break; case 'E': // extended parameters - ignore for now fill(5); reply(); break; case 'P': _programming ? pulse(LED_ERROR, 3) : beginProgramming(); reply(); break; case 'U': // set address (word) address = getch() | (getch() << 8); reply(); break; case 0x60: //STK_PROG_FLASH getch(); getch(); reply(); break; case 0x61: //STK_PROG_DATA getch(); reply(); break; case 0x64: //STK_PROG_PAGE programPage(address); break; case 0x74: //STK_READ_PAGE 't' readPage(address); break; case 'V': //0x56 universal(); break; case 'Q': //0x51 _error = 0; endProgramming(); reply(); break; case 0x75: //STK_READ_SIGN 'u' readSignature(); break; // expecting a command, not CRC_EOP // this is how we can get back in sync case CRC_EOP: _error = true; Serial.write(STK_NOSYNC); break; default: // anything else we will return STK_UNKNOWN _error = true; if (receiveEop()) Serial.write(STK_UNKNOWN); break; } }
// main start int main(void) { asm volatile ("clr __zero_reg__"); // reset MCU status register MCUSR = 0; // enable watchdog to avoid deadlock watchdogConfig(WATCHDOG_8S); // initialize SPI SPIinit(); // initialize RF module RFinit(); // Read node config from EEPROM, i.e. nodeId, parent nodeId, distance eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(struct NodeConfig)); // Read firmware config from EEPROM, i.e. type, version, CRC, blocks eeprom_read_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); // find nearest node during reboot: invalidate parent node settings, since we have to re-discover them for every single reboot configuredParentID = nc.parentNodeId; // nc.parentNodeId = 0xFF; nc.distance = 0xFF; // prepare for I_FIND_PARENTS outMsg.sender = nc.nodeId; outMsg.last = nc.nodeId; outMsg.sensor = 0xFF; outMsg.destination = BROADCAST_ADDRESS; // set header mSetVersion(outMsg, PROTOCOL_VERSION); mSetLength(outMsg, 0); mSetCommand(outMsg, C_INTERNAL); mSetAck(outMsg,false); mSetPayloadType(outMsg, P_STRING); // set reading & writing pipe address setAddress(nc.nodeId); // network up? get neighbors, else startup if (!sendAndWait(I_FIND_PARENT, I_FIND_PARENT_RESPONSE)) { startup(); } // all messages to gateway outMsg.destination = GATEWAY_ADDRESS; // if no node id assigned, request new id if (nc.nodeId == AUTO) { // listen to broadcast openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(BROADCAST_ADDRESS)); if (sendAndWait(I_ID_REQUEST, I_ID_RESPONSE)) { // save id to eeprom eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, atoi(inMsg.data)); } // we could go on and set everything right here, but rebooting will take care of that - and saves some bytes :) reboot(); } // wuff watchdogReset(); // prepare for FW config request RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)outMsg.data; mSetLength(outMsg, sizeof(RequestFirmwareConfig)); mSetCommand(outMsg, C_STREAM); mSetPayloadType(outMsg,P_CUSTOM); // copy node settings to reqFWConfig memcpy(reqFWConfig,&fc,sizeof(NodeFirmwareConfig)); // add bootloader information reqFWConfig->BLVersion = MYSBOOTLOADER_VERSION; // send node config and request FW config from controller if (!sendAndWait(ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE)) { startup(); } NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)inMsg.data; // bootloader commands if (firmwareConfigResponse->blocks == 0) { // verify flag if (firmwareConfigResponse->crc == 0xDA7A){ // cmd 0x01 clear eeprom if(firmwareConfigResponse->bl_command == 0x01) { for(uint16_t i = 0; i < EEPROM_SIZE; i++) eeprom_update_byte((uint8_t *)i,0xFF); } else // cmd 0x02 set id if(firmwareConfigResponse->bl_command == 0x02) { eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, (uint8_t)firmwareConfigResponse->bl_data); } } // final step reboot(); } // compare with current node configuration, if equal startup if (!memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { startup(); } // *********** from here on we will fetch new FW // invalidate current CRC fc.crc = 0xFFFF; // write fetched type and version in case OTA fails (BL will reboot and re-request FW with stored settings) eeprom_update_block(&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,sizeof(NodeFirmwareConfig)); // copy new FW config memcpy(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); RequestFWBlock *firmwareRequest = (RequestFWBlock *)outMsg.data; mSetLength(outMsg, sizeof(RequestFWBlock)); firmwareRequest->type = fc.type; firmwareRequest->version = fc.version; // request FW from controller, load FW counting backwards uint16_t block = fc.blocks; do { firmwareRequest->block = block - 1; // request FW block if (!sendAndWait(ST_FIRMWARE_REQUEST, ST_FIRMWARE_RESPONSE)) { reboot(); } ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)inMsg.data; // did we receive requested block? if (!memcmp(firmwareRequest,firmwareResponse,sizeof(RequestFWBlock))) { // calculate page offset uint8_t offset = ((block - 1) * FIRMWARE_BLOCK_SIZE) % SPM_PAGESIZE; // write to buffer memcpy(progBuf + offset, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); // program if page full if (offset == 0) { programPage(((block - 1) * FIRMWARE_BLOCK_SIZE), progBuf); } block--; } } while (block); // wuff watchdogReset(); // all blocks transmitted, calc CRC and write to eeprom if valid if (IsFirmwareValid()) { // if FW is valid, write settings to eeprom eeprom_update_block(&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); } // final step reboot(); }