/****************************************************************************** * This function waits for commands over UART *****************************************************************************/ void commandLoop(void) { uint8_t command = 0; sendWelcomeMessage(); while(1) { /* Wait for command */ command = BLUART_receive(); switch(command) { case 'h': sendWelcomeMessage(); break; case 'u': enterDownloadMode(); break; case 'v': BLUART_sendString("Verifying firmware..."); if ( verifyActiveFirmware() ) { BLUART_sendString("OK\r\n"); } else { BLUART_sendString("INVALID\r\n"); } break; case 'l': BLUART_sendString("Locking debug access...\r\n"); enableDebugLock(); break; case 'r': BLUART_sendString("Reset\r\n"); NVIC_SystemReset(); break; } } }
/**************************************************************************//** * @brief Starts a XMODEM download. *****************************************************************************/ RAMFUNC bool XMODEM_download(void) { XMODEM_packet *pkt; uint32_t i; uint32_t byte; uint32_t sequenceNumber = 1; uint32_t writeAddress, endAddress; uint8_t *decryptedBuffer; if ( USE_TEMP_STORAGE ) { writeAddress = TEMP_START_ADDRESS; endAddress = TEMP_END_ADDRESS; } else { writeAddress = FIRMWARE_START_ADDRESS; endAddress = FIRMWARE_END_ADDRESS; } /* Initialize AES for decryption */ startDecryptCBC256(); /* Send one start transmission packet. Wait for a response. If there is no * response, we resend the start transmission packet. */ while (1) { BLUART_send(XMODEM_NCG); i = 10000000; /* Wait until we receive a packet */ while ( !(UART->STATUS & USART_STATUS_RXDATAV) ) { /* Time out */ if ( --i == 0 ) break; } /* We have received a packet */ if ( UART->STATUS & USART_STATUS_RXDATAV ) { break; } } /* Start receiving XMODEM packets */ while (1) { /* Swap buffer for packet buffer */ pkt = (XMODEM_packet *) rawPacket[sequenceNumber & 1]; decryptedBuffer = rawBuffer[sequenceNumber & 1]; /* Fetch the first byte of the packet explicitly, as it defines the * rest of the packet */ pkt->header = BLUART_receive(); /* Check for end of transfer */ if (pkt->header == XMODEM_EOT) { /* Acknowledge End of transfer */ BLUART_send(XMODEM_ACK); break; } /* If header is cancel message, then cancel the transfer */ if (pkt->header == XMODEM_CAN) { return false; } /* If the header is not a start of header (SOH), then cancel * * the transfer. */ if (pkt->header != XMODEM_SOH) { BLUART_send(XMODEM_CAN); return false; } /* If the received file is larger than the allocated memory * for the firmware, cancel the transfer. */ if ( writeAddress > endAddress ) { BLUART_send(XMODEM_CAN); return false; } /* Fill the remaining bytes packet */ /* Byte 0 is padding, byte 1 is header */ for (byte = 2; byte < sizeof(XMODEM_packet); byte++) { *((uint8_t *)pkt + byte) = BLUART_receive(); } /* Verify that the packet is valid */ if (XMODEM_verifyPacketChecksum(pkt, sequenceNumber) != 0) { /* On a malformed packet, send a NAK and start over */ BLUART_send(XMODEM_NAK); continue; } /* If we have reached a new page, first erase it */ if ( writeAddress % FLASH_PAGE_SIZE == 0 ) { FLASH_erasePage(writeAddress); } /* Decrypt one XMODEM packet(32 words) */ for ( i=0; i<XMODEM_DATA_SIZE/AES_BLOCKSIZE; i++ ) { /* Decrypt one AES block (4 words) */ decryptBlockCBC256(&(pkt->data[i * AES_BLOCKSIZE]), &(decryptedBuffer[i * AES_BLOCKSIZE])); } /* Check if this is the header packet */ if ( sequenceNumber == 1 ) { /* Get the header */ FirmwareHeader *header = (FirmwareHeader *)decryptedBuffer; /* Set the state to not verified initially */ header->verified = FW_NOT_VERIFIED; /* Write the header to flash */ FLASH_write((uint32_t *)writeAddress, (uint32_t *)header, sizeof(FirmwareHeader) / 4); /* Start at the boot address for the next packet */ writeAddress = writeAddress + FIRMWARE_HEADER_SIZE; } else { /* Write decrypted packet to flash */ FLASH_write((uint32_t *)writeAddress, (uint32_t *)decryptedBuffer, XMODEM_DATA_SIZE / 4); writeAddress += XMODEM_DATA_SIZE; } sequenceNumber++; /* Send ACK */ BLUART_send(XMODEM_ACK); } endDecryptCBC256(); /* Wait for the last DMA transfer to finish. */ while (DMA->CHENS & DMA_CHENS_CH0ENS) ; /* Return success */ return true; }