[usb | recovery] Improve code quality

This commit is contained in:
Laury
2021-11-21 21:48:51 +01:00
parent e8a1bc6149
commit 9afb42716d
32 changed files with 1024 additions and 912 deletions

View File

@@ -29,7 +29,7 @@ void initMPU() {
// 1.1 Memory barrier
Cache::dmb();
// 1.2 Disable fault exceptions
// 1.2 Enable fault exceptions
CORTEX.SHCRS()->setMEMFAULTENA(true);
CORTEX.SHCRS()->setBUSFAULTENA(true);
CORTEX.SHCRS()->setUSGFAULTENA(true);

View File

@@ -8,11 +8,12 @@ extern "C" {
void bf_abort();
void uf_abort();
void nmi_abort();
// Here and below, we mean init the abort handler, not the opposite
void abort_init();
void abort_core(const char *);
void abort_screen(const char *);
void abort_sleeping();
void abort_economy();
void abort_screen(const char *);
void start();
void abort();
void isr_systick();

View File

@@ -1,3 +1,4 @@
#include "isr.h"
#include <drivers/battery.h>
#include <drivers/cache.h>
#include <drivers/external_flash.h>
@@ -27,13 +28,13 @@
typedef void (*cxx_constructor)();
extern "C" {
extern char _data_section_start_flash;
extern char _data_section_start_ram;
extern char _data_section_end_ram;
extern char _bss_section_start_ram;
extern char _bss_section_end_ram;
extern cxx_constructor _init_array_start;
extern cxx_constructor _init_array_end;
extern char _data_section_start_flash;
extern char _data_section_start_ram;
extern char _data_section_end_ram;
extern char _bss_section_start_ram;
extern char _bss_section_end_ram;
extern cxx_constructor _init_array_start;
extern cxx_constructor _init_array_end;
}
/* In order to ensure that this method is execute from the external flash, we
@@ -45,8 +46,8 @@ static void __attribute__((noinline)) external_flash_start() {
* happening during the on boarding app. The backlight will be initialized
* after the Power-On Self-Test if there is one or before switching to the
* home app otherwise. */
Ion::Device::Board::initPeripherals(false);
return ion_main(0, nullptr);
Ion::Device::Board::initPeripherals(false);
return ion_main(0, nullptr);
}
/* This additional function call 'jump_to_external_flash' serves two purposes:
@@ -219,6 +220,154 @@ void __attribute__((noinline)) uf_abort() {
abort_core("USAGEFAULT");
}
void __attribute__((noinline)) abort_init() {
Ion::Device::Board::shutdownPeripherals(true);
Ion::Device::Board::initPeripherals(false);
Ion::Timing::msleep(100);
Ion::Backlight::init();
Ion::LED::setColor(KDColorRed);
Ion::Backlight::setBrightness(180);
}
void __attribute__((noinline)) abort_economy() {
int brightness = Ion::Backlight::brightness();
bool plugged = Ion::USB::isPlugged();
while (brightness > 0) {
brightness--;
Ion::Backlight::setBrightness(brightness);
Ion::Timing::msleep(50);
if(plugged || (!plugged && Ion::USB::isPlugged())){
Ion::Backlight::setBrightness(180);
return;
}
}
Ion::Backlight::shutdown();
while (1) {
Ion::Device::Power::sleepConfiguration();
Ion::Device::WakeUp::onUSBPlugging();
Ion::Device::WakeUp::onChargingEvent();
Ion::Device::Power::internalFlashSuspend(true);
if (!plugged && Ion::USB::isPlugged()) {
break;
}
plugged = Ion::USB::isPlugged();
};
Ion::Device::Board::setStandardFrequency(Ion::Device::Board::Frequency::High);
Ion::Backlight::init();
Ion::Backlight::setBrightness(180);
}
void __attribute__((noinline)) abort_sleeping() {
if (Ion::Battery::level() != Ion::Battery::Charge::EMPTY) {
return;
}
// We don't use Ion::Power::suspend because we don't want to move the exam buffer into the internal
Ion::Device::Board::shutdownPeripherals(true);
bool plugged = Ion::USB::isPlugged();
while (true) {
Ion::Device::Battery::initGPIO();
Ion::Device::USB::initGPIO();
Ion::Device::LED::init();
Ion::Device::Power::sleepConfiguration();
Ion::Device::Board::shutdownPeripherals(true);
Ion::Device::WakeUp::onUSBPlugging();
Ion::Device::WakeUp::onChargingEvent();
Ion::Device::Power::internalFlashSuspend(true);
Ion::Device::USB::initGPIO();
if (!plugged && Ion::USB::isPlugged()) {
break;
}
plugged = Ion::USB::isPlugged();
}
Ion::Device::Board::setStandardFrequency(Ion::Device::Board::Frequency::High);
abort_init();
}
void __attribute__((noinline)) abort_core(const char * text) {
Ion::Timing::msleep(100);
int counting;
while (true) {
counting = 0;
if (Ion::Battery::level() == Ion::Battery::Charge::EMPTY) {
abort_sleeping();
abort_screen(text);
}
Ion::USB::enable();
Ion::Battery::Charge previous_state = Ion::Battery::level();
while (!Ion::USB::isEnumerated()) {
if (Ion::Battery::level() == Ion::Battery::Charge::LOW) {
if (previous_state != Ion::Battery::Charge::LOW) {
previous_state = Ion::Battery::Charge::LOW;
counting = 0;
}
Ion::Timing::msleep(500);
if (counting >= 20) {
abort_sleeping();
abort_screen(text);
counting = -1;
}
counting++;
} else {
if (previous_state == Ion::Battery::Charge::LOW) {
previous_state = Ion::Battery::level();
counting = 0;
}
Ion::Timing::msleep(100);
if (counting >= 300) {
abort_economy();
counting = -1;
}
counting++;
}
}
Ion::USB::DFU(false, false, 0);
}
}
void __attribute__((noinline)) abort_screen(const char * text){
KDRect screen = KDRect(0, 0, Ion::Display::Width, Ion::Display::Height);
Ion::Display::pushRectUniform(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), KDColor::RGB24(0xffffff));
KDContext* ctx = KDIonContext::sharedContext();
ctx->setOrigin(KDPointZero);
ctx->setClippingRect(screen);
ctx->drawString("UPSILON CRASH", KDPoint(90, 10), KDFont::LargeFont, KDColorRed, KDColor::RGB24(0xffffff));
ctx->drawString("An error occurred", KDPoint(10, 30), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString("If you have some important data, please", KDPoint(10, 45), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString("use bit.ly/upsiBackup to backup them.", KDPoint(10, 60), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString("YOU WILL LOSE ALL YOUR DATA", KDPoint(10, 85), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString("→ You can try to reboot by presssing the", KDPoint(10, 110), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString("reset button at the back of the calculator", KDPoint(10, 125), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString("→ If Upsilon keeps crashing, you can connect", KDPoint(10, 140), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString("the calculator to a computer or a phone", KDPoint(10, 160), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString("and try to reinstall Upsilon", KDPoint(10, 175), KDFont::SmallFont, KDColorBlack, KDColor::RGB24(0xffffff));
ctx->drawString(text, KDPoint(220, 200), KDFont::SmallFont, KDColorRed, KDColor::RGB24(0xffffff));
}
void __attribute__((noinline)) abort() {
abort_init();
abort_screen("HARDFAULT");
abort_core("HARDFAULT");
}
void __attribute__((noinline)) nmi_abort() {
abort_init();
abort_screen("NMIFAULT");
abort_core("NMIFAULT");
}
void __attribute__((noinline)) bf_abort() {
abort_init();
abort_screen("BUSFAULT");
abort_core("BUSFAULT");
}
void __attribute__((noinline)) uf_abort() {
abort_init();
abort_screen("USAGEFAULT");
abort_core("USAGEFAULT");
}
/* When 'start' is executed, the external flash is supposed to be shutdown. We
* thus forbid inlining to prevent executing this code from external flash
* (just in case 'start' was to be called from the external flash). */
@@ -252,9 +401,9 @@ void __attribute__((noinline)) start() {
* call the pointed function. */
#define SUPPORT_CPP_GLOBAL_CONSTRUCTORS 0
#if SUPPORT_CPP_GLOBAL_CONSTRUCTORS
for (cxx_constructor* c = &_init_array_start; c < &_init_array_end; c++) {
(*c)();
}
for (cxx_constructor* c = &_init_array_start; c < &_init_array_end; c++) {
(*c)();
}
#else
/* In practice, static initialized objects are a terrible idea. Since the init
* order is not specified, most often than not this yields the dreaded static

View File

@@ -12,7 +12,6 @@ void Calculator::PollAndReset(bool exitWithKeyboard, bool unlock, int level) {
Ion::Device::SerialNumber::copy(serialNumber);
Calculator c(serialNumber);
/* Leave DFU mode if the Back key is pressed, the calculator unplugged or the
* USB core soft-disconnected. */
Ion::Keyboard::Key exitKey = Ion::Keyboard::Key::Back;

View File

@@ -17,500 +17,500 @@ namespace USB {
static inline uint32_t minUint32T(uint32_t x, uint32_t y) { return x < y ? x : y; }
void DFUInterface::StatusData::push(Channel *c) const {
c->push(m_bStatus);
c->push(m_bwPollTimeout[2]);
c->push(m_bwPollTimeout[1]);
c->push(m_bwPollTimeout[0]);
c->push(m_bState);
c->push(m_iString);
c->push(m_bStatus);
c->push(m_bwPollTimeout[2]);
c->push(m_bwPollTimeout[1]);
c->push(m_bwPollTimeout[0]);
c->push(m_bState);
c->push(m_iString);
}
void DFUInterface::StateData::push(Channel *c) const {
c->push(m_bState);
c->push(m_bState);
}
void DFUInterface::wholeDataReceivedCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) {
if (request->bRequest() == (uint8_t)DFURequest::Download) {
// Handle a download request
if (request->wValue() == 0) {
// The request is a special command
switch (transferBuffer[0]) {
case (uint8_t)DFUDownloadCommand::SetAddressPointer:
setAddressPointerCommand(request, transferBuffer, *transferBufferLength);
return;
case (uint8_t)DFUDownloadCommand::Erase:
eraseCommand(transferBuffer, *transferBufferLength);
return;
default:
m_state = State::dfuERROR;
m_status = Status::errSTALLEDPKT;
return;
}
}
if (request->wValue() == 1) {
m_ep0->stallTransaction();
return;
}
if (request->wLength() > 0) {
// The request is a "real" download. Compute the writing address.
m_writeAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer;
// Store the received data until we copy it on the flash.
memcpy(m_largeBuffer, transferBuffer, *transferBufferLength);
m_largeBufferLength = *transferBufferLength;
m_state = State::dfuDNLOADSYNC;
}
if (request->bRequest() == (uint8_t)DFURequest::Download) {
// Handle a download request
if (request->wValue() == 0) {
// The request is a special command
switch (transferBuffer[0]) {
case (uint8_t)DFUDownloadCommand::SetAddressPointer:
setAddressPointerCommand(request, transferBuffer, *transferBufferLength);
return;
case (uint8_t)DFUDownloadCommand::Erase:
eraseCommand(transferBuffer, *transferBufferLength);
return;
default:
m_state = State::dfuERROR;
m_status = Status::errSTALLEDPKT;
return;
}
}
if (request->wValue() == 1) {
m_ep0->stallTransaction();
return;
}
if (request->wLength() > 0) {
// The request is a "real" download. Compute the writing address.
m_writeAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer;
// Store the received data until we copy it on the flash.
memcpy(m_largeBuffer, transferBuffer, *transferBufferLength);
m_largeBufferLength = *transferBufferLength;
m_state = State::dfuDNLOADSYNC;
}
}
}
void DFUInterface::wholeDataSentCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) {
if (request->bRequest() == (uint8_t)DFURequest::GetStatus) {
// Do any needed action after the GetStatus request.
if (m_state == State::dfuMANIFEST) {
if (m_dfuLevel == 1 && m_isFirstExternalFlash && !m_isInternalLocked) {
return;
}
/* If we leave the DFU and reset immediately, dfu-util outputs an error:
* "File downloaded successfully
* dfu-util: Error during download get_status"
* If we sleep 1us here, there is no error. We put 1ms for security.
* This error might be due to the USB connection being cut too soon after
* the last USB exchange, so the host does not have time to process the
* answer received for the last GetStatus request. */
Ion::Timing::msleep(1);
// Leave DFU routine: Leave DFU, reset device, jump to application code
leaveDFUAndReset();
} else if (m_state == State::dfuDNBUSY) {
m_state = State::dfuDNBUSY;
if (m_largeBufferLength != 0) {
// Here, copy the data from the transfer buffer to the flash memory
writeOnMemory();
}
changeAddressPointerIfNeeded();
eraseMemoryIfNeeded();
m_state = State::dfuDNLOADIDLE;
}
if (request->bRequest() == (uint8_t)DFURequest::GetStatus) {
// Do any needed action after the GetStatus request.
if (m_state == State::dfuMANIFEST) {
if (m_dfuLevel == 1 && m_isFirstExternalFlash && !m_isInternalLocked) {
return;
}
/* If we leave the DFU and reset immediately, dfu-util outputs an error:
* "File downloaded successfully
* dfu-util: Error during download get_status"
* If we sleep 1us here, there is no error. We put 1ms for security.
* This error might be due to the USB connection being cut too soon after
* the last USB exchange, so the host does not have time to process the
* answer received for the last GetStatus request. */
Ion::Timing::msleep(1);
// Leave DFU routine: Leave DFU, reset device, jump to application code
leaveDFUAndReset();
} else if (m_state == State::dfuDNBUSY) {
m_state = State::dfuDNBUSY;
if (m_largeBufferLength != 0) {
// Here, copy the data from the transfer buffer to the flash memory
writeOnMemory();
}
changeAddressPointerIfNeeded();
eraseMemoryIfNeeded();
m_state = State::dfuDNLOADIDLE;
}
}
}
bool DFUInterface::processSetupInRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) {
if (Interface::processSetupInRequest(request, transferBuffer, transferBufferLength, transferBufferMaxLength)) {
return true;
}
switch (request->bRequest()) {
case (uint8_t)DFURequest::Detach:
m_device->detach();
return true;
case (uint8_t)DFURequest::Download:
return processDownloadRequest(request->wLength(), transferBufferLength);
case (uint8_t)DFURequest::Upload:
return processUploadRequest(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
case (uint8_t)DFURequest::GetStatus:
return getStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
case (uint8_t)DFURequest::ClearStatus:
return clearStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
case (uint8_t)DFURequest::GetState:
return getState(transferBuffer, transferBufferLength, transferBufferMaxLength);
case (uint8_t)DFURequest::Abort:
return dfuAbort(transferBufferLength);
}
return false;
if (Interface::processSetupInRequest(request, transferBuffer, transferBufferLength, transferBufferMaxLength)) {
return true;
}
switch (request->bRequest()) {
case (uint8_t)DFURequest::Detach:
m_device->detach();
return true;
case (uint8_t)DFURequest::Download:
return processDownloadRequest(request->wLength(), transferBufferLength);
case (uint8_t)DFURequest::Upload:
return processUploadRequest(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
case (uint8_t)DFURequest::GetStatus:
return getStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
case (uint8_t)DFURequest::ClearStatus:
return clearStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
case (uint8_t)DFURequest::GetState:
return getState(transferBuffer, transferBufferLength, transferBufferMaxLength);
case (uint8_t)DFURequest::Abort:
return dfuAbort(transferBufferLength);
}
return false;
}
bool DFUInterface::processDownloadRequest(uint16_t wLength, uint16_t *transferBufferLength) {
if (m_state != State::dfuIDLE && m_state != State::dfuDNLOADIDLE) {
m_state = State::dfuERROR;
m_status = Status::errNOTDONE;
m_ep0->stallTransaction();
return false;
}
if (wLength == 0) {
// Leave DFU routine: Reset the device and jump to application code
m_state = State::dfuMANIFESTSYNC;
} else {
// Prepare to receive the download data
m_ep0->clearForOutTransactions(wLength);
m_state = State::dfuDNLOADSYNC;
}
return true;
if (m_state != State::dfuIDLE && m_state != State::dfuDNLOADIDLE) {
m_state = State::dfuERROR;
m_status = Status::errNOTDONE;
m_ep0->stallTransaction();
return false;
}
if (wLength == 0) {
// Leave DFU routine: Reset the device and jump to application code
m_state = State::dfuMANIFESTSYNC;
} else {
// Prepare to receive the download data
m_ep0->clearForOutTransactions(wLength);
m_state = State::dfuDNLOADSYNC;
}
return true;
}
bool DFUInterface::processUploadRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) {
if (m_state != State::dfuIDLE && m_state != State::dfuUPLOADIDLE) {
m_ep0->stallTransaction();
return false;
}
if (request->wValue() == 0) {
/* The host requests to read the commands supported by the bootloader. After
* receiving this command, the device should returns N bytes representing
* the command codes for :
* Get command / Set Address Pointer / Erase / Read Unprotect
* We no not need it for now. */
return false;
} else if (request->wValue() == 1) {
m_ep0->stallTransaction();
return false;
} else {
/* We decided to never protect Read operation. Else we would have to check
* here it is not protected before reading. */
if (m_state != State::dfuIDLE && m_state != State::dfuUPLOADIDLE) {
m_ep0->stallTransaction();
return false;
}
if (request->wValue() == 0) {
/* The host requests to read the commands supported by the bootloader. After
* receiving this command, the device should returns N bytes representing
* the command codes for :
* Get command / Set Address Pointer / Erase / Read Unprotect
* We no not need it for now. */
return false;
} else if (request->wValue() == 1) {
m_ep0->stallTransaction();
return false;
} else {
/* We decided to never protect Read operation. Else we would have to check
* here it is not protected before reading. */
// Compute the reading address
uint32_t readAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer;
// Copy the requested memory zone into the transfer buffer.
uint16_t copySize = minUint32T(transferBufferMaxLength, request->wLength());
memcpy(transferBuffer, (void *)readAddress, copySize);
*transferBufferLength = copySize;
}
m_state = State::dfuUPLOADIDLE;
return true;
// Compute the reading address
uint32_t readAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer;
// Copy the requested memory zone into the transfer buffer.
uint16_t copySize = minUint32T(transferBufferMaxLength, request->wLength());
memcpy(transferBuffer, (void *)readAddress, copySize);
*transferBufferLength = copySize;
}
m_state = State::dfuUPLOADIDLE;
return true;
}
void DFUInterface::setAddressPointerCommand(SetupPacket *request, uint8_t *transferBuffer, uint16_t transferBufferLength) {
assert(transferBufferLength == 5);
// Compute the new address but change it after the next getStatus request.
m_potentialNewAddressPointer = transferBuffer[1] + (transferBuffer[2] << 8) + (transferBuffer[3] << 16) + (transferBuffer[4] << 24);
m_state = State::dfuDNLOADSYNC;
assert(transferBufferLength == 5);
// Compute the new address but change it after the next getStatus request.
m_potentialNewAddressPointer = transferBuffer[1] + (transferBuffer[2] << 8) + (transferBuffer[3] << 16) + (transferBuffer[4] << 24);
m_state = State::dfuDNLOADSYNC;
}
void DFUInterface::changeAddressPointerIfNeeded() {
if (m_potentialNewAddressPointer == 0) {
// There was no address change waiting.
return;
}
// If there is a new address pointer waiting, change the pointer address.
m_addressPointer = m_potentialNewAddressPointer;
m_potentialNewAddressPointer = 0;
m_state = State::dfuDNLOADIDLE;
m_status = Status::OK;
if (m_potentialNewAddressPointer == 0) {
// There was no address change waiting.
return;
}
// If there is a new address pointer waiting, change the pointer address.
m_addressPointer = m_potentialNewAddressPointer;
m_potentialNewAddressPointer = 0;
m_state = State::dfuDNLOADIDLE;
m_status = Status::OK;
}
void DFUInterface::eraseCommand(uint8_t *transferBuffer, uint16_t transferBufferLength) {
/* We determine whether the commands asks for a mass erase or which sector to
/* We determine whether the commands asks for a mass erase or which sector to
* erase. The erase must be done after the next getStatus request. */
m_state = State::dfuDNLOADSYNC;
m_state = State::dfuDNLOADSYNC;
if (transferBufferLength == 1) {
// Mass erase
m_erasePage = Flash::TotalNumberOfSectors();
return;
}
if (transferBufferLength == 1) {
// Mass erase
m_erasePage = Flash::TotalNumberOfSectors();
return;
}
// Sector erase
assert(transferBufferLength == 5);
// Sector erase
assert(transferBufferLength == 5);
m_eraseAddress = transferBuffer[1] + (transferBuffer[2] << 8) + (transferBuffer[3] << 16) + (transferBuffer[4] << 24);
m_eraseAddress = transferBuffer[1] + (transferBuffer[2] << 8) + (transferBuffer[3] << 16) + (transferBuffer[4] << 24);
m_erasePage = Flash::SectorAtAddress(m_eraseAddress);
if (m_erasePage < 0) {
// Unrecognized sector
m_state = State::dfuERROR;
m_status = Status::errTARGET;
}
m_erasePage = Flash::SectorAtAddress(m_eraseAddress);
if (m_erasePage < 0) {
// Unrecognized sector
m_state = State::dfuERROR;
m_status = Status::errTARGET;
}
}
void DFUInterface::eraseMemoryIfNeeded() {
if (m_erasePage < 0) {
return;
}
willErase();
if ((m_eraseAddress >= k_ExternalBorderAddress && m_eraseAddress < ExternalFlash::Config::EndAddress) || m_dfuUnlocked) {
int32_t order = Flash::SectorAtAddress(m_eraseAddress);
Flash::EraseSector(order);
}
m_state = State::dfuDNLOADIDLE;
m_status = Status::OK;
m_erasePage = -1;
if (m_erasePage < 0) {
return;
}
willErase();
if ((m_eraseAddress >= k_ExternalBorderAddress && m_eraseAddress < ExternalFlash::Config::EndAddress) || m_dfuUnlocked) {
int32_t order = Flash::SectorAtAddress(m_eraseAddress);
Flash::EraseSector(order);
}
m_state = State::dfuDNLOADIDLE;
m_status = Status::OK;
m_erasePage = -1;
}
void DFUInterface::writeOnMemory() {
if (m_writeAddress >= k_sramStartAddress && m_writeAddress <= k_sramEndAddress) {
// Write on SRAM
// FIXME We should check that we are not overriding the current instructions.
memcpy((void *)m_writeAddress, m_largeBuffer, m_largeBufferLength);
reset_custom_vars(); // On reset les vars car la ram n'a pas de secteur à effacer
} else if (Flash::SectorAtAddress(m_writeAddress) >= 0) {
if (m_dfuLevel == 2) {
m_largeBufferLength = 0;
m_state = State::dfuERROR;
m_status = Status::errWRITE;
return;
}
if (m_writeAddress >= k_sramStartAddress && m_writeAddress <= k_sramEndAddress) {
// Write on SRAM
// FIXME We should check that we are not overriding the current instructions.
memcpy((void *)m_writeAddress, m_largeBuffer, m_largeBufferLength);
reset_custom_vars(); // On reset les vars car la ram n'a pas de secteur à effacer
} else if (Flash::SectorAtAddress(m_writeAddress) >= 0) {
if (m_dfuLevel == 2) {
m_largeBufferLength = 0;
m_state = State::dfuERROR;
m_status = Status::errWRITE;
return;
}
int current_memory_flashed;
if (m_writeAddress >= InternalFlash::Config::StartAddress && m_writeAddress <= InternalFlash::Config::EndAddress) {
if (m_isInternalLocked && !m_dfuUnlocked) // On vérifie si l'external a été flash
{
m_largeBufferLength = 0;
m_state = State::dfuERROR;
m_status = Status::errTARGET;
leaveDFUAndReset(false); // Numworks flash l'internal avant donc on exit pour afficher le message
return;
}
current_memory_flashed = 0;
//on écrit dans la mémoire interne
if (m_isFirstInternalFlash && !m_dfuUnlocked) {
m_temp_is_valid = true;
for (int i = 0; i < 4; i++) {
if (magik[i] != m_largeBuffer[magik_adrs + i]) {
m_temp_is_valid = false;
break;
}
}
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
m_state = State::dfuERROR;
m_status = Status::errVERIFY;
//leaveDFUAndReset(); On ne leave plus sinon on fait crash la calc si il n'y a que la partie ext.
return;
} else {
m_isFirstInternalFlash = false;
}
}
} else {
current_memory_flashed = 1;
// Nous écrivons la partie external os
if (m_writeAddress < k_ExternalBorderAddress && m_isFirstExternalFlash && !m_dfuUnlocked) // On vérifie si on installe des apps ext
{
// if (m_dfuLevel == 1 && m_isInternalLocked) {
// m_largeBufferLength = 0;
// m_state = State::dfuERROR;
// m_status = Status::errTARGET;
// return;
// }
if (m_dfuLevel == 0) {
// Partie moche du code parce que je n'arrivais pas à compil avec 3 boucles for sous msys
int adress_magik = magik_ext_adrs[0];
m_temp_is_valid = external_magik[0] == m_largeBuffer[adress_magik];
m_largeBuffer[adress_magik] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[1] == m_largeBuffer[adress_magik + 1];
m_largeBuffer[adress_magik + 1] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[2] == m_largeBuffer[adress_magik + 2];
m_largeBuffer[adress_magik + 2] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[3] == m_largeBuffer[adress_magik + 3];
m_largeBuffer[adress_magik + 3] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
adress_magik = magik_ext_adrs[1];
m_temp_is_valid = external_magik[5] == m_largeBuffer[adress_magik];
m_largeBuffer[adress_magik] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[6] == m_largeBuffer[adress_magik + 1];
m_largeBuffer[adress_magik + 1] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[7] == m_largeBuffer[adress_magik + 2];
m_largeBuffer[adress_magik + 2] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[8] == m_largeBuffer[adress_magik + 3];
m_largeBuffer[adress_magik + 3] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
adress_magik = magik_ext_adrs[2];
m_temp_is_valid = true;
m_temp_is_valid = external_magik[0] == m_largeBuffer[adress_magik];
m_largeBuffer[adress_magik] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[1] == m_largeBuffer[adress_magik + 1];
m_largeBuffer[adress_magik + 1] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[2] == m_largeBuffer[adress_magik + 2];
m_largeBuffer[adress_magik + 2] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[3] == m_largeBuffer[adress_magik + 3];
m_largeBuffer[adress_magik + 3] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[4] == m_largeBuffer[adress_magik + 4];
m_largeBuffer[adress_magik + 4] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[5] == m_largeBuffer[adress_magik + 5];
m_largeBuffer[adress_magik + 5] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[6] == m_largeBuffer[adress_magik + 6];
m_largeBuffer[adress_magik + 6] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[7] == m_largeBuffer[adress_magik + 7];
m_largeBuffer[adress_magik + 7] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[8] == m_largeBuffer[adress_magik + 8];
m_largeBuffer[adress_magik + 8] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
} else {
m_isFirstExternalFlash = false;
m_isInternalLocked = false;
}
} else {
m_isFirstExternalFlash = false;
m_isInternalLocked = false;
}
}
}
if (m_last_memoryFlashed >= 0 && current_memory_flashed != m_last_memoryFlashed) {
m_last_memoryFlashed = -1;
}
m_erasePage = Flash::SectorAtAddress(m_writeAddress);
//On vérifie qu'on a pas déjà effacé le secteur et si ce n'est pas un secteur external déjà effacé
if ((m_last_memoryFlashed < 0 || m_erasePage != m_lastPageErased) && m_writeAddress < k_ExternalBorderAddress && !m_dfuUnlocked) {
Flash::EraseSector(m_erasePage);
m_last_memoryFlashed = current_memory_flashed;
}
m_lastPageErased = m_erasePage;
m_erasePage = -1;
Ion::Timing::msleep(1);
Flash::WriteMemory(reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBuffer, m_largeBufferLength);
} else {
// Invalid write address
int current_memory_flashed;
if (m_writeAddress >= InternalFlash::Config::StartAddress && m_writeAddress <= InternalFlash::Config::EndAddress) {
if (m_isInternalLocked && !m_dfuUnlocked) // On vérifie si l'external a été flash
{
m_largeBufferLength = 0;
m_state = State::dfuERROR;
m_status = Status::errTARGET;
leaveDFUAndReset(false); // Numworks flash l'internal avant donc on exit pour afficher le message
return;
}
current_memory_flashed = 0;
//on écrit dans la mémoire interne
if (m_isFirstInternalFlash && !m_dfuUnlocked) {
m_temp_is_valid = true;
for (int i = 0; i < 4; i++) {
if (magik[i] != m_largeBuffer[magik_adrs + i]) {
m_temp_is_valid = false;
break;
}
}
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
m_state = State::dfuERROR;
m_status = Status::errVERIFY;
//leaveDFUAndReset(); On ne leave plus sinon on fait crash la calc si il n'y a que la partie ext.
return;
} else {
m_isFirstInternalFlash = false;
}
}
} else {
current_memory_flashed = 1;
// Nous écrivons la partie external os
if (m_writeAddress < k_ExternalBorderAddress && m_isFirstExternalFlash && !m_dfuUnlocked) // On vérifie si on installe des apps ext
{
// if (m_dfuLevel == 1 && m_isInternalLocked) {
// m_largeBufferLength = 0;
// m_state = State::dfuERROR;
// m_status = Status::errTARGET;
// return;
// }
if (m_dfuLevel == 0) {
// Partie moche du code parce que je n'arrivais pas à compil avec 3 boucles for sous msys
int adress_magik = magik_ext_adrs[0];
m_temp_is_valid = external_magik[0] == m_largeBuffer[adress_magik];
m_largeBuffer[adress_magik] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[1] == m_largeBuffer[adress_magik + 1];
m_largeBuffer[adress_magik + 1] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[2] == m_largeBuffer[adress_magik + 2];
m_largeBuffer[adress_magik + 2] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[3] == m_largeBuffer[adress_magik + 3];
m_largeBuffer[adress_magik + 3] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
adress_magik = magik_ext_adrs[1];
m_temp_is_valid = external_magik[5] == m_largeBuffer[adress_magik];
m_largeBuffer[adress_magik] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[6] == m_largeBuffer[adress_magik + 1];
m_largeBuffer[adress_magik + 1] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[7] == m_largeBuffer[adress_magik + 2];
m_largeBuffer[adress_magik + 2] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[8] == m_largeBuffer[adress_magik + 3];
m_largeBuffer[adress_magik + 3] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
adress_magik = magik_ext_adrs[2];
m_temp_is_valid = true;
m_temp_is_valid = external_magik[0] == m_largeBuffer[adress_magik];
m_largeBuffer[adress_magik] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[1] == m_largeBuffer[adress_magik + 1];
m_largeBuffer[adress_magik + 1] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[2] == m_largeBuffer[adress_magik + 2];
m_largeBuffer[adress_magik + 2] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[3] == m_largeBuffer[adress_magik + 3];
m_largeBuffer[adress_magik + 3] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[4] == m_largeBuffer[adress_magik + 4];
m_largeBuffer[adress_magik + 4] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[5] == m_largeBuffer[adress_magik + 5];
m_largeBuffer[adress_magik + 5] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[6] == m_largeBuffer[adress_magik + 6];
m_largeBuffer[adress_magik + 6] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[7] == m_largeBuffer[adress_magik + 7];
m_largeBuffer[adress_magik + 7] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
}
m_temp_is_valid = external_magik[8] == m_largeBuffer[adress_magik + 8];
m_largeBuffer[adress_magik + 8] = 0xff;
if (!m_temp_is_valid) {
m_largeBufferLength = 0;
leaveDFUAndReset(false);
return;
} else {
m_isFirstExternalFlash = false;
m_isInternalLocked = false;
}
} else {
m_isFirstExternalFlash = false;
m_isInternalLocked = false;
}
}
}
// Reset the buffer length
if (m_last_memoryFlashed >= 0 && current_memory_flashed != m_last_memoryFlashed) {
m_last_memoryFlashed = -1;
}
m_erasePage = Flash::SectorAtAddress(m_writeAddress);
//On vérifie qu'on a pas déjà effacé le secteur et si ce n'est pas un secteur external déjà effacé
if ((m_last_memoryFlashed < 0 || m_erasePage != m_lastPageErased) && m_writeAddress < k_ExternalBorderAddress && !m_dfuUnlocked) {
Flash::EraseSector(m_erasePage);
m_last_memoryFlashed = current_memory_flashed;
}
m_lastPageErased = m_erasePage;
m_erasePage = -1;
Ion::Timing::msleep(1);
Flash::WriteMemory(reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBuffer, m_largeBufferLength);
} else {
// Invalid write address
m_largeBufferLength = 0;
// Change the interface state and status
m_state = State::dfuDNLOADIDLE;
m_status = Status::OK;
m_state = State::dfuERROR;
m_status = Status::errTARGET;
return;
}
// Reset the buffer length
m_largeBufferLength = 0;
// Change the interface state and status
m_state = State::dfuDNLOADIDLE;
m_status = Status::OK;
}
bool DFUInterface::getStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) {
// Change the status if needed
if (m_state == State::dfuMANIFESTSYNC) {
m_state = State::dfuMANIFEST;
} else if (m_state == State::dfuDNLOADSYNC) {
m_state = State::dfuDNBUSY;
}
// Copy the status on the TxFifo
*transferBufferLength = StatusData(m_status, m_state).copy(transferBuffer, transferBufferMaxLength);
return true;
// Change the status if needed
if (m_state == State::dfuMANIFESTSYNC) {
m_state = State::dfuMANIFEST;
} else if (m_state == State::dfuDNLOADSYNC) {
m_state = State::dfuDNBUSY;
}
// Copy the status on the TxFifo
*transferBufferLength = StatusData(m_status, m_state).copy(transferBuffer, transferBufferMaxLength);
return true;
}
bool DFUInterface::clearStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) {
m_status = Status::OK;
m_state = State::dfuIDLE;
return getStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
m_status = Status::OK;
m_state = State::dfuIDLE;
return getStatus(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
}
bool DFUInterface::getState(uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t maxSize) {
*transferBufferLength = StateData(m_state).copy(transferBuffer, maxSize);
return true;
*transferBufferLength = StateData(m_state).copy(transferBuffer, maxSize);
return true;
}
bool DFUInterface::dfuAbort(uint16_t *transferBufferLength) {
m_status = Status::OK;
m_state = State::dfuIDLE;
*transferBufferLength = 0;
return true;
m_status = Status::OK;
m_state = State::dfuIDLE;
*transferBufferLength = 0;
return true;
}
void DFUInterface::leaveDFUAndReset(bool do_reset) {
reset_custom_vars();
m_isInternalLocked = true;
m_isFirstInternalFlash = true;
m_isFirstExternalFlash = true;
m_device->setResetOnDisconnect(do_reset);
m_device->detach();
reset_custom_vars();
m_isInternalLocked = true;
m_isFirstInternalFlash = true;
m_isFirstExternalFlash = true;
m_device->setResetOnDisconnect(do_reset);
m_device->detach();
}
} // namespace USB

View File

@@ -13,212 +13,197 @@
namespace Ion
{
namespace Device
namespace Device
{
namespace USB
{
class DFUInterface : public Interface {
public:
DFUInterface(Device *device, Endpoint0 *ep0, uint8_t bInterfaceAlternateSetting):
Interface(ep0),
m_device(device),
m_status(Status::OK),
m_state(State::dfuIDLE),
m_addressPointer(0),
m_potentialNewAddressPointer(0),
m_erasePage(-1),
m_largeBuffer{0},
m_largeBufferLength(0),
m_writeAddress(0),
m_eraseAddress(0),
m_bInterfaceAlternateSetting(bInterfaceAlternateSetting),
m_lastErasedPage(-1),
m_isErasingAndWriting(false),
m_isTemporaryUnlocked(false),
m_haveAlreadyFlashedExternal(false),
m_dfuUnlocked(false),
m_dfuLevel(0)
{
namespace USB
}
uint32_t addressPointer() const { return m_addressPointer; }
void wholeDataReceivedCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) override;
void wholeDataSentCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) override;
bool isErasingAndWriting() const { return m_isErasingAndWriting; }
void unlockDfu() { m_dfuUnlocked = true; };
void setLevel(uint8_t lvl) { m_dfuLevel = lvl; }
protected:
void setActiveInterfaceAlternative(uint8_t interfaceAlternativeIndex) override {
assert(interfaceAlternativeIndex == m_bInterfaceAlternateSetting);
}
uint8_t getActiveInterfaceAlternative() override {
return m_bInterfaceAlternateSetting;
}
bool processSetupInRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) override;
private:
// DFU Request Codes
enum class DFURequest {
Detach = 0,
Download = 1,
Upload = 2,
GetStatus = 3,
ClearStatus = 4,
GetState = 5,
Abort = 6
};
// DFU Download Commmand Codes
enum class DFUDownloadCommand {
GetCommand = 0x00,
SetAddressPointer = 0x21,
Erase = 0x41,
ReadUnprotect = 0x92
};
enum class Status : uint8_t {
OK = 0x00,
errTARGET = 0x01,
errFILE = 0x02,
errWRITE = 0x03,
errERASE = 0x04,
errCHECK_ERASED = 0x05,
errPROG = 0x06,
errVERIFY = 0x07,
errADDRESS = 0x08,
errNOTDONE = 0x09,
errFIRMWARE = 0x0A,
errVENDOR = 0x0B,
errUSBR = 0x0C,
errPOR = 0x0D,
errUNKNOWN = 0x0E,
errSTALLEDPKT = 0x0F
};
enum class State : uint8_t {
appIDLE = 0,
appDETACH = 1,
dfuIDLE = 2,
dfuDNLOADSYNC = 3,
dfuDNBUSY = 4,
dfuDNLOADIDLE = 5,
dfuMANIFESTSYNC = 6,
dfuMANIFEST = 7,
dfuMANIFESTWAITRESET = 8,
dfuUPLOADIDLE = 9,
dfuERROR = 10
};
class StatusData : public Streamable {
public:
StatusData(Status status, State state, uint32_t pollTimeout = 10):
/* We put a default pollTimeout value of 1ms: if the device is busy, the
* host has to wait 1ms before sending a getStatus Request. */
m_bStatus((uint8_t)status),
m_bwPollTimeout{uint8_t((pollTimeout >> 16) & 0xFF), uint8_t((pollTimeout >> 8) & 0xFF), uint8_t(pollTimeout & 0xFF)},
m_bState((uint8_t)state),
m_iString(0)
{
}
protected:
void push(Channel * c) const override;
private:
uint8_t m_bStatus; // Status resulting from the execution of the most recent request
uint8_t m_bwPollTimeout[3]; // m_bwPollTimeout is 24 bits
uint8_t m_bState; // State of the device immediately following transmission of this response
uint8_t m_iString;
};
class DFUInterface : public Interface
{
class StateData : public Streamable
{
public:
StateData(State state) : m_bState((uint8_t)state) {}
protected:
void push(Channel *c) const override;
private:
uint8_t m_bState; // Current state of the device
};
public:
DFUInterface(Device *device, Endpoint0 *ep0, uint8_t bInterfaceAlternateSetting) : Interface(ep0),
m_device(device),
m_status(Status::OK),
m_state(State::dfuIDLE),
m_addressPointer(0),
m_potentialNewAddressPointer(0),
m_erasePage(-1),
m_largeBuffer{0},
m_largeBufferLength(0),
m_writeAddress(0),
m_eraseAddress(0),
m_bInterfaceAlternateSetting(bInterfaceAlternateSetting),
m_isErasingAndWriting(false),
m_isFirstInternalFlash(true),
m_temp_is_valid(false),
m_isInternalLocked(true),
m_isFirstExternalFlash(true),
m_last_memoryFlashed(-1),
m_lastPageErased(-1),
m_dfuUnlocked(false),
m_dfuLevel(0)
{
}
uint32_t addressPointer() const { return m_addressPointer; }
void wholeDataReceivedCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) override;
void wholeDataSentCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) override;
bool isErasingAndWriting() const { return m_isErasingAndWriting; }
void unlockDfu() {m_dfuUnlocked = true;};
void setLevel(int lvl) {m_dfuLevel = lvl; }
protected:
void setActiveInterfaceAlternative(uint8_t interfaceAlternativeIndex) override
{
assert(interfaceAlternativeIndex == m_bInterfaceAlternateSetting);
}
uint8_t getActiveInterfaceAlternative() override
{
return m_bInterfaceAlternateSetting;
}
bool processSetupInRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength) override;
private:
// DFU Request Codes
enum class DFURequest
{
Detach = 0,
Download = 1,
Upload = 2,
GetStatus = 3,
ClearStatus = 4,
GetState = 5,
Abort = 6
};
// DFU Download Commmand Codes
enum class DFUDownloadCommand
{
GetCommand = 0x00,
SetAddressPointer = 0x21,
Erase = 0x41,
ReadUnprotect = 0x92
};
enum class Status : uint8_t
{
OK = 0x00,
errTARGET = 0x01,
errFILE = 0x02,
errWRITE = 0x03,
errERASE = 0x04,
errCHECK_ERASED = 0x05,
errPROG = 0x06,
errVERIFY = 0x07,
errADDRESS = 0x08,
errNOTDONE = 0x09,
errFIRMWARE = 0x0A,
errVENDOR = 0x0B,
errUSBR = 0x0C,
errPOR = 0x0D,
errUNKNOWN = 0x0E,
errSTALLEDPKT = 0x0F
};
enum class State : uint8_t
{
appIDLE = 0,
appDETACH = 1,
dfuIDLE = 2,
dfuDNLOADSYNC = 3,
dfuDNBUSY = 4,
dfuDNLOADIDLE = 5,
dfuMANIFESTSYNC = 6,
dfuMANIFEST = 7,
dfuMANIFESTWAITRESET = 8,
dfuUPLOADIDLE = 9,
dfuERROR = 10
};
class StatusData : public Streamable
{
public:
StatusData(Status status, State state, uint32_t pollTimeout = 10) : /* We put a default pollTimeout value of 1ms: if the device is busy, the
* host has to wait 1ms before sending a getStatus Request. */
m_bStatus((uint8_t)status),
m_bwPollTimeout{uint8_t((pollTimeout >> 16) & 0xFF), uint8_t((pollTimeout >> 8) & 0xFF), uint8_t(pollTimeout & 0xFF)},
m_bState((uint8_t)state),
m_iString(0)
{
}
protected:
void push(Channel *c) const override;
private:
uint8_t m_bStatus; // Status resulting from the execution of the most recent request
uint8_t m_bwPollTimeout[3]; // m_bwPollTimeout is 24 bits
uint8_t m_bState; // State of the device immediately following transmission of this response
uint8_t m_iString;
};
class StateData : public Streamable
{
public:
StateData(State state) : m_bState((uint8_t)state) {}
protected:
void push(Channel *c) const override;
private:
uint8_t m_bState; // Current state of the device
};
/* The Flash and SRAM addresses are in flash.ld. However, dfu_interface is
/* The Flash and SRAM addresses are in flash.ld. However, dfu_interface is
* linked with dfu.ld, so we cannot access the values. */
constexpr static uint32_t k_sramStartAddress = 0x20000000;
constexpr static uint32_t k_sramEndAddress = 0x20040000;
constexpr static uint32_t k_ExternalBorderAddress = 0x90200000;
constexpr static uint32_t k_sramStartAddress = 0x20000000;
constexpr static uint32_t k_sramEndAddress = 0x20040000;
constexpr static uint32_t k_externalAppsBorderAddress = 0x90200000;
const static int magik_adrs = 0x1C4;
constexpr static int magik_ext_adrs[3] = {0x03, 0xb, 0x44f};
constexpr static uint8_t magik[4] = {0xF0, 0x0D, 0xC0, 0xDE};
constexpr static uint8_t external_magik[9] = {0x64, 0x6c, 0x31, 0x31, 0x23, 0x39, 0x38, 0x33, 0x35};
const static int k_internalMagikPointer = 0x1C4;
constexpr static int k_externalMagikPointer = 0x44F;
constexpr static uint8_t k_internalMagik[4] = {0xF0, 0x0D, 0xC0, 0xDE};
constexpr static uint8_t k_externalMagik[9] = {0x64, 0x6c, 0x31, 0x31, 0x23, 0x39, 0x38, 0x33, 0x35};
// Download and upload
bool processDownloadRequest(uint16_t wLength, uint16_t *transferBufferLength);
bool processUploadRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength);
// Address pointer
void setAddressPointerCommand(SetupPacket *request, uint8_t *transferBuffer, uint16_t transferBufferLength);
void changeAddressPointerIfNeeded();
// Access memory
void eraseCommand(uint8_t *transferBuffer, uint16_t transferBufferLength);
void eraseMemoryIfNeeded();
void eraseMemoryIfNeededWithoutErasingAtAll();
void writeOnMemory();
void unlockFlashMemory();
void lockFlashMemoryAndPurgeCaches();
// Status
bool getStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength);
bool clearStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength);
// State
bool getState(uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t maxSize);
// Abort
bool dfuAbort(uint16_t *transferBufferLength);
// Leave DFU
void leaveDFUAndReset(bool do_reset=true);
/* Erase and Write state. After starting the erase of flash memory, the user
// Download and upload
bool processDownloadRequest(uint16_t wLength, uint16_t *transferBufferLength);
bool processUploadRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength);
// Address pointer
void setAddressPointerCommand(SetupPacket *request, uint8_t *transferBuffer, uint16_t transferBufferLength);
void changeAddressPointerIfNeeded();
// Access memory
void eraseCommand(uint8_t *transferBuffer, uint16_t transferBufferLength);
void eraseMemoryIfNeeded();
void eraseMemoryIfNeededWithoutErasingAtAll();
void writeOnMemory();
void unlockFlashMemory();
void lockFlashMemoryAndPurgeCaches();
// Status
bool getStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength);
bool clearStatus(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength);
// State
bool getState(uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t maxSize);
// Abort
bool dfuAbort(uint16_t *transferBufferLength);
// Leave DFU
void leaveDFUAndReset(bool do_reset=true);
/* Erase and Write state. After starting the erase of flash memory, the user
* can no longer leave DFU mode by pressing the Back key of the keyboard. This
* way, we prevent the user from interrupting a software download. After every
* software download, the calculator resets, which unlocks the "exit on
* pressing back". */
void willErase() { m_isErasingAndWriting = true; }
void reset_custom_vars() {m_temp_is_valid = true; m_last_memoryFlashed = -1; m_lastPageErased = -1;}
void willErase() { m_isErasingAndWriting = true; }
void resetProtectionVariables() { m_lastErasedPage = -1; m_isTemporaryUnlocked = false; m_haveAlreadyFlashedExternal = false; }
Device *m_device;
Status m_status;
State m_state;
uint32_t m_addressPointer;
uint32_t m_potentialNewAddressPointer;
int32_t m_erasePage;
uint8_t m_largeBuffer[Endpoint0::MaxTransferSize];
uint16_t m_largeBufferLength;
uint32_t m_writeAddress;
uint32_t m_eraseAddress;
uint8_t m_bInterfaceAlternateSetting;
bool m_isErasingAndWriting;
bool m_isFirstInternalFlash;
bool m_temp_is_valid;
bool m_isInternalLocked;
bool m_isFirstExternalFlash;
int m_last_memoryFlashed; // -1: aucune; 0: internal; 1: external
int m_lastPageErased; // -1 par défaut
bool m_dfuUnlocked;
int m_dfuLevel;
};
Device *m_device;
Status m_status;
State m_state;
uint32_t m_addressPointer;
uint32_t m_potentialNewAddressPointer;
int32_t m_erasePage;
uint8_t m_largeBuffer[Endpoint0::MaxTransferSize];
uint16_t m_largeBufferLength;
uint32_t m_writeAddress;
uint32_t m_eraseAddress;
uint8_t m_bInterfaceAlternateSetting;
uint8_t m_lastErasedPage;
bool m_isErasingAndWriting;
bool m_isTemporaryUnlocked;
bool m_haveAlreadyFlashedExternal;
bool m_dfuUnlocked;
uint8_t m_dfuLevel; // 0: Upsilon only, 1: Omega-forked only, 2: No update
};
}
}
}
}
}
#endif