diff --git a/bindings/python/icsneopy/bootloader/bootloader.cpp b/bindings/python/icsneopy/bootloader/bootloader.cpp index 3ab5a7d5..9cd12e4f 100644 --- a/bindings/python/icsneopy/bootloader/bootloader.cpp +++ b/bindings/python/icsneopy/bootloader/bootloader.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "icsneo/device/extensions/bootloader/api.h" #include "icsneo/device/extensions/bootloader/parser/fwloader.h" @@ -19,16 +20,21 @@ void init_bootloader(pybind11::module_& m) { pybind11::classh(bootloader, "FWLoader") .def_static("load", &Bootloader::FWLoader::Load, pybind11::arg("path"), pybind11::call_guard()); + pybind11::native_enum(bootloader, "StatusType", "enum.IntEnum") + .value("Progress", Bootloader::StatusType::Progress) + .value("Failed", Bootloader::StatusType::Failed) + .finalize(); + bootloader.def_static("update", - [](Device& device, const Bootloader::FWRepo& fw, Bootloader::Logger logger, bool alreadyInBootloader, bool forceFlash) { - if(!logger) { - logger = [](Device::OpenStatusType, const std::string&, std::optional) { return Device::OpenDirective::Continue; }; + [](Device& device, const Bootloader::FWRepo& fw, Bootloader::StatusHandler statusHandler, bool alreadyInBootloader, bool forceFlash) { + if(!statusHandler) { + statusHandler = [](Bootloader::StatusType, const std::string&, std::optional) {}; } - return Bootloader::update(device, fw, logger, alreadyInBootloader, forceFlash); + return Bootloader::update(device, fw, statusHandler, alreadyInBootloader, forceFlash); }, pybind11::arg("device"), pybind11::arg("fw"), - pybind11::arg("logger") = pybind11::none(), + pybind11::arg("statusHandler") = pybind11::none(), pybind11::arg("already_in_bootloader") = false, pybind11::arg("force_flash") = false, pybind11::call_guard()); diff --git a/bindings/python/icsneopy/device/device.cpp b/bindings/python/icsneopy/device/device.cpp index 76c29aa9..a8bd19e8 100644 --- a/bindings/python/icsneopy/device/device.cpp +++ b/bindings/python/icsneopy/device/device.cpp @@ -15,19 +15,6 @@ namespace icsneo { void init_device(pybind11::module_& m) { pybind11::classh device(m, "Device"); - pybind11::native_enum(device, "OpenDirective", "enum.IntEnum") - .value("Continue", Device::OpenDirective::Continue) - .value("Cancel", Device::OpenDirective::Cancel) - .value("Skip", Device::OpenDirective::Skip) - .finalize(); - - pybind11::native_enum(device, "OpenStatusType", "enum.IntEnum") - .value("QuestionContinueSkipCancel", Device::OpenStatusType::QuestionContinueSkipCancel) - .value("QuestionContinueCancel", Device::OpenStatusType::QuestionContinueCancel) - .value("Progress", Device::OpenStatusType::Progress) - .value("Failed", Device::OpenStatusType::Failed) - .finalize(); - device .def("__repr__", &Device::describe) .def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard()) diff --git a/device/device.cpp b/device/device.cpp index 217da0f6..cbe85b6f 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -275,7 +275,7 @@ std::vector Device::getChipVersions(bool refreshComponents) { return chipVersions; } -bool Device::open(OpenFlags flags, OpenStatusHandler handler) { +bool Device::open(OpenFlags flags) { if(!com) { report(APIEvent::Type::Unknown, APIEvent::Severity::Error); return false; @@ -287,38 +287,31 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) { startHeartbeat(); - APIEvent::Type attemptErr = attemptToBeginCommunication(); - if(attemptErr != APIEvent::Type::NoErrorFound) { - // We could not communicate with the device, let's see if an extension can - bool tryAgain = false; - forEachExtension([&tryAgain, &flags, &handler](const std::shared_ptr& ext) -> bool { - if(ext->onDeviceCommunicationDead(flags, handler)) - tryAgain = true; - return true; - }); - - if(!tryAgain) { + if((flags & OpenFlags::SkipRefreshDeviceState) == 0) { + auto refreshErr = refreshDeviceState(); + if(refreshErr != APIEvent::Type::NoErrorFound) { com->close(); - report(attemptErr, APIEvent::Severity::Error); - return false; // Extensions couldn't save us - } - attemptErr = attemptToBeginCommunication(); - if(attemptErr != APIEvent::Type::NoErrorFound) { - com->close(); - report(attemptErr, APIEvent::Severity::Error); + stopHeartbeat(); + report(refreshErr, APIEvent::Severity::Error); return false; } } - bool block = false; - forEachExtension([&block, &flags, &handler](const std::shared_ptr& ext) { - if(ext->onDeviceOpen(flags, handler)) - return true; - block = true; - return false; - }); - if(block) // Extensions say no - return false; + return true; +} + +APIEvent::Type Device::refreshDeviceState() { + if(isOnline()) { + return APIEvent::Type::DeviceCurrentlyOnline; + } + + if(!com || !com->isOpen()) { + return APIEvent::Type::Unknown; + } + APIEvent::Type attemptErr = attemptToBeginCommunication(); + if(attemptErr != APIEvent::Type::NoErrorFound) { + return attemptErr; + } refreshComponentVersions(); if(!settings->disabled) { @@ -336,7 +329,7 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) { if(supportsLiveData()) clearAllLiveData(); - return true; + return APIEvent::Type::NoErrorFound; } bool Device::reconnect(std::chrono::milliseconds timeout, std::chrono::milliseconds interval) { @@ -412,7 +405,6 @@ APIEvent::Type Device::attemptToBeginCommunication() { else versions = std::move(*maybeVersions); - // Get component versions before the extension "onDeviceOpen" hooks so that we can properly check verisons if(supportsComponentVersions()) { if(auto compVersions = com->getComponentVersionsSync()) componentVersions = std::move(*compVersions); diff --git a/device/extensions/bootloader/api.cpp b/device/extensions/bootloader/api.cpp index 0a4dff35..7ed29895 100644 --- a/device/extensions/bootloader/api.cpp +++ b/device/extensions/bootloader/api.cpp @@ -111,7 +111,7 @@ static bool runPipeline( icsneo::Device& device, const BootloaderPipeline& pipeline, const FWRepo& fw, - const Logger& logger, + const StatusHandler& statusHandler, bool alreadyInBootloader, bool forceFlash ) { @@ -167,7 +167,7 @@ static bool runPipeline( auto com = getCommunication(device, flashPhase, info); if(!withCommunication(com.get(), info, "FlashPhase", [&](Bootloader::Communication& opened) { - if(!opened.flash(fw, logger)) { + if(!opened.flash(fw, statusHandler)) { Log::Error("FlashPhase", "failed to flash " + chipString(flashPhase.chip)); return false; } @@ -257,13 +257,13 @@ static bool runPipeline( } } } - return exitBootloader(device, logger, !chipsFlashed.empty()); + return exitBootloader(device, statusHandler, !chipsFlashed.empty()); } bool Bootloader::update( icsneo::Device& device, const FWRepo& fw, - Logger logger, + StatusHandler statusHandler, bool alreadyInBootloader, bool forceFlash ) { @@ -273,7 +273,7 @@ bool Bootloader::update( return false; } - if(!runPipeline(device, pipeline, fw, logger, alreadyInBootloader, forceFlash)) { + if(!runPipeline(device, pipeline, fw, statusHandler, alreadyInBootloader, forceFlash)) { device.getEventHandler()(APIEvent::Type::FirmwareUpdateFailed, APIEvent::Severity::Error); return false; } @@ -287,19 +287,19 @@ bool Bootloader::enterBootloader(icsneo::Device& device) { return device.reconnect(std::chrono::milliseconds(30000)); } -bool Bootloader::exitBootloader(icsneo::Device& device, Logger logger, bool updatedChips) { +bool Bootloader::exitBootloader(icsneo::Device& device, StatusHandler statusHandler, bool updatedChips) { if(!updatedChips) { return true; } - logger(icsneo::Device::OpenStatusType::Progress, "Connecting to the device...", std::nullopt); - return verifyConnection(device, logger); + statusHandler(StatusType::Progress, "Connecting to the device...", std::nullopt); + return verifyConnection(device, statusHandler); } /** * Toggle network communication and wait up to 5 seconds for a reset status confirming the change. * Like icsneo::Device::goOnline(), a timeout is not an error. */ -static bool setCommunicationEnabled(icsneo::Device& device, const Logger& logger, bool enable, double progressStart) { +static bool setCommunicationEnabled(icsneo::Device& device, const StatusHandler& statusHandler, bool enable, double progressStart) { static constexpr std::chrono::seconds Timeout(5); const auto filter = std::make_shared(Message::Type::ResetStatus); @@ -329,16 +329,16 @@ static bool setCommunicationEnabled(icsneo::Device& device, const Logger& logger } // Each call covers half of the overall progress - logger(icsneo::Device::OpenStatusType::Progress, "Connecting to the device...", progressStart + (elapsedTime / Timeout) / 2.0); + statusHandler(StatusType::Progress, "Connecting to the device...", progressStart + (elapsedTime / Timeout) / 2.0); elapsedTime = std::chrono::steady_clock::now() - startTime; } - logger(icsneo::Device::OpenStatusType::Progress, "Connecting to the device...", progressStart + 0.5); + statusHandler(StatusType::Progress, "Connecting to the device...", progressStart + 0.5); return true; } -bool Bootloader::verifyConnection(icsneo::Device& device, Logger logger) { +bool Bootloader::verifyConnection(icsneo::Device& device, StatusHandler statusHandler) { // Firmware needs to confirm the update by verifying that it can enable/disable the connection on the device - return setCommunicationEnabled(device, logger, true, 0.0) && setCommunicationEnabled(device, logger, false, 0.5); + return setCommunicationEnabled(device, statusHandler, true, 0.0) && setCommunicationEnabled(device, statusHandler, false, 0.5); } bool Bootloader::isSFPChip(const icsneo::Bootloader::Chip& chip) { diff --git a/device/extensions/bootloader/communication/application.cpp b/device/extensions/bootloader/communication/application.cpp index b696c699..8d9cca38 100644 --- a/device/extensions/bootloader/communication/application.cpp +++ b/device/extensions/bootloader/communication/application.cpp @@ -38,7 +38,7 @@ bool Application::finalize() { return ok; } -bool Application::flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) { +bool Application::flash(const FWRepo& fw, const icsneo::Bootloader::StatusHandler& handler) { Log::Info(__func__, "starting flash for " + targetChip.getName()); const auto& srcVer = fw.getVersion(); @@ -55,7 +55,7 @@ bool Application::flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandle } auto currentString = "Preparing to update " + targetChip.getName() + "..."; - handler(icsneo::Device::OpenStatusType::Progress, currentString, std::nullopt); + handler(StatusType::Progress, currentString, std::nullopt); // The supplied IEF is not for this product if(ief.getVersion().prodId != static_cast(device.getProductID())) { @@ -132,10 +132,10 @@ bool Application::validateFirmware(const DeviceAppVersion& chipSrcVer) { return sendCommand(Update::CheckComponentVersion, [](double) {}, 0, {chipSrcVer.major, chipSrcVer.minor}); } -bool Application::sendSoftware(const std::vector& bin, const icsneo::Device::OpenStatusHandler& handler) { +bool Application::sendSoftware(const std::vector& bin, const icsneo::Bootloader::StatusHandler& handler) { Log::Debug(__func__, "starting for " + targetChip.getName() + " (" + std::to_string(bin.size()) + " bytes)"); auto currentString = "Preparing to update " + targetChip.getName() + "..."; - handler(icsneo::Device::OpenStatusType::Progress, currentString, std::nullopt); + handler(StatusType::Progress, currentString, std::nullopt); if(bin.empty() || bin.size() > std::numeric_limits::max()) { Log::Error(__func__, "invalid firmware size for " + targetChip.getName()); return false; @@ -144,14 +144,14 @@ bool Application::sendSoftware(const std::vector& bin, const icsneo::De Log::Debug(__func__, "erasing " + targetChip.getName()); if(!sendCommand(Update::Erase, 0, totalSize, [&](double progress) { - handler(icsneo::Device::OpenStatusType::Progress, currentString, progress); + handler(StatusType::Progress, currentString, progress); }, std::chrono::milliseconds(45000))) { Log::Error(__func__, "erase failed for " + targetChip.getName()); return false; } currentString = "Updating " + targetChip.getName() + "..."; - handler(icsneo::Device::OpenStatusType::Progress, currentString, std::nullopt); + handler(StatusType::Progress, currentString, std::nullopt); const uint32_t stepSize = std::min(totalSize, 2048); uint32_t bytesTransferred = 0; @@ -163,7 +163,7 @@ bool Application::sendSoftware(const std::vector& bin, const icsneo::De } bytesTransferred += bytesToSend; - handler(icsneo::Device::OpenStatusType::Progress, currentString, double(bytesTransferred) / totalSize); + handler(StatusType::Progress, currentString, double(bytesTransferred) / totalSize); } Log::Debug(__func__, "write complete, validating " + targetChip.getName()); if(!validateComponent()) { @@ -174,7 +174,7 @@ bool Application::sendSoftware(const std::vector& bin, const icsneo::De return true; } -bool Application::sendSoftware(const std::vector& sectorPairs, uint32_t blockSize, const icsneo::Device::OpenStatusHandler& handler) { +bool Application::sendSoftware(const std::vector& sectorPairs, uint32_t blockSize, const icsneo::Bootloader::StatusHandler& handler) { if(sectorPairs.empty()) { Log::Error(__func__, "no sectors to flash for " + targetChip.getName()); return false; @@ -182,7 +182,7 @@ bool Application::sendSoftware(const std::vector& sectorPairs, uint Log::Debug(__func__, "starting for " + targetChip.getName() + " (" + std::to_string(sectorPairs.size()) + " sectors)"); auto currentString = "Preparing to update " + targetChip.getName() + "..."; - handler(icsneo::Device::OpenStatusType::Progress, currentString, std::nullopt); + handler(StatusType::Progress, currentString, std::nullopt); uint64_t totalSize = 0; for(const auto& sector : sectorPairs) { totalSize += sector.second.size(); @@ -199,7 +199,7 @@ bool Application::sendSoftware(const std::vector& sectorPairs, uint Log::Debug(__func__, "erasing " + targetChip.getName() + " (" + std::to_string(totalSize) + " bytes)"); if(!sendCommand(Update::Erase, 0, static_cast(totalSize), [&](double progress) { - handler(icsneo::Device::OpenStatusType::Progress, currentString, progress); + handler(StatusType::Progress, currentString, progress); }, std::chrono::milliseconds(45000))) { Log::Error(__func__, "erase failed for " + targetChip.getName()); return false; @@ -212,7 +212,7 @@ bool Application::sendSoftware(const std::vector& sectorPairs, uint } currentString = "Updating " + targetChip.getName() + "..."; - handler(icsneo::Device::OpenStatusType::Progress, currentString, std::nullopt); + handler(StatusType::Progress, currentString, std::nullopt); uint32_t bytesTransferred = 0; for(const auto& pair : sectorPairs) { @@ -233,7 +233,7 @@ bool Application::sendSoftware(const std::vector& sectorPairs, uint } bytesTransferred += static_cast(rawData.size()); - handler(icsneo::Device::OpenStatusType::Progress, currentString, double(bytesTransferred) / double(totalSize)); + handler(StatusType::Progress, currentString, double(bytesTransferred) / double(totalSize)); } Log::Debug(__func__, "write complete, validating " + targetChip.getName()); bool ok = validateComponent(); @@ -264,7 +264,7 @@ bool Application::validateComponent() { * passes. Progress replies are OperationPending with a SoftwareUpdateCommandHeader whose * commandSizeOrProgress holds the progress so far, or a GenericReturn with no progress. */ -bool Application::sendCommand(Update command, uint32_t offset, uint32_t length, const StatusHandler& handler, std::chrono::milliseconds timeout, std::vector args) { +bool Application::sendCommand(Update command, uint32_t offset, uint32_t length, const CommandStatusHandler& handler, std::chrono::milliseconds timeout, std::vector args) { bool finishedResponse = false; std::condition_variable finishedResponseCV; std::mutex finishedResponseMutex; diff --git a/device/extensions/bootloader/communication/radcommunication.cpp b/device/extensions/bootloader/communication/radcommunication.cpp index 459bf5c7..2e660360 100644 --- a/device/extensions/bootloader/communication/radcommunication.cpp +++ b/device/extensions/bootloader/communication/radcommunication.cpp @@ -323,8 +323,8 @@ bool RADCommunication::sendSoftware(const std::vector& chipSoftware) { size_t remainingBytes = chipSoftware.size(); size_t currentlyReading = 0; - logger( - icsneo::Device::OpenStatusType::Progress, + statusHandler( + StatusType::Progress, "Flashing " + targetChip.getName() + "...", std::nullopt ); @@ -332,8 +332,8 @@ bool RADCommunication::sendSoftware(const std::vector& chipSoftware) { while(remainingBytes > 0) { const double progress = static_cast(currentlyReading) / static_cast(chipSoftware.size()); - logger( - icsneo::Device::OpenStatusType::Progress, + statusHandler( + StatusType::Progress, "Flashing " + targetChip.getName() + "...", progress ); @@ -407,8 +407,8 @@ bool RADCommunication::sendSoftware(const std::vector& chipSoftware) { } } - logger( - icsneo::Device::OpenStatusType::Progress, + statusHandler( + StatusType::Progress, "Flashing " + targetChip.getName() + "...", 1.0 ); @@ -431,8 +431,8 @@ bool RADCommunication::getProgrammingStatus(size_t sizeToValidate) { uint32_t status = 0; const auto beginTime = std::chrono::steady_clock::now(); - logger( - icsneo::Device::OpenStatusType::Progress, + statusHandler( + StatusType::Progress, "Programming " + targetChip.getName() + "...", std::nullopt ); @@ -440,8 +440,8 @@ bool RADCommunication::getProgrammingStatus(size_t sizeToValidate) { while(status < static_cast(sizeToValidate)) { const double progress = static_cast(status) / static_cast(sizeToValidate); - logger( - icsneo::Device::OpenStatusType::Progress, + statusHandler( + StatusType::Progress, "Programming " + targetChip.getName() + "...", progress ); @@ -457,8 +457,8 @@ bool RADCommunication::getProgrammingStatus(size_t sizeToValidate) { } } - logger( - icsneo::Device::OpenStatusType::Progress, + statusHandler( + StatusType::Progress, "Programming " + targetChip.getName() + "...", 1.0 ); @@ -510,7 +510,7 @@ bool RADCommunication::loadZips(const FWRepo& fw, std::vector& chipSoft return false; } -bool RADCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) { +bool RADCommunication::flash(const FWRepo& fw, const icsneo::Bootloader::StatusHandler& handler) { Log::Info(__func__, "starting flash for " + targetChip.getName()); auto chipSrcVer = fw.getChipVersion(targetChip.getIEFName()); if(!chipSrcVer) { @@ -524,7 +524,7 @@ bool RADCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusH return false; } - logger = handler; + statusHandler = handler; if(!validateChipVersion(*chipSrcVer)) { Log::Error(__func__, "validateChipVersion failed for " + targetChip.getName()); return false; diff --git a/device/extensions/bootloader/communication/radmultichipcommunication.cpp b/device/extensions/bootloader/communication/radmultichipcommunication.cpp index 25624ed1..a927456f 100644 --- a/device/extensions/bootloader/communication/radmultichipcommunication.cpp +++ b/device/extensions/bootloader/communication/radmultichipcommunication.cpp @@ -41,7 +41,7 @@ bool RADMultiChipCommunication::authenticate() { return true; } -bool RADMultiChipCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) { +bool RADMultiChipCommunication::flash(const FWRepo& fw, const icsneo::Bootloader::StatusHandler& handler) { Log::Info(__func__, "starting flash for " + targetChip.getName()); auto chipSrcVer = fw.getChipVersion(targetChip.getIEFName()); if(!chipSrcVer) { @@ -56,7 +56,7 @@ bool RADMultiChipCommunication::flash(const FWRepo& fw, const icsneo::Device::Op if(!standardComm->validateFirmware(*chipSrcVer)) { Log::Error(__func__, "firmware validation failed for " + targetChip.getName()); - handler(icsneo::Device::OpenStatusType::Failed, "Failed to validate firmware", std::nullopt); + handler(StatusType::Failed, "Failed to validate firmware", std::nullopt); return false; } @@ -103,7 +103,7 @@ bool RADMultiChipCommunication::flash(const FWRepo& fw, const icsneo::Device::Op return false; } Log::Debug(__func__, "finalize successful, proceeding to reboot"); - handler(icsneo::Device::OpenStatusType::Progress, "Rebooting device...", std::nullopt); + handler(StatusType::Progress, "Rebooting device...", std::nullopt); return true; } diff --git a/device/extensions/bootloader/communication/radperiphcommunication.cpp b/device/extensions/bootloader/communication/radperiphcommunication.cpp index 554c1467..85f13531 100644 --- a/device/extensions/bootloader/communication/radperiphcommunication.cpp +++ b/device/extensions/bootloader/communication/radperiphcommunication.cpp @@ -180,7 +180,7 @@ bool RADPeriphCommunication::flashSector(const IEF::Sector& sector) { return sendRequest(Request::FlashSector, std::move(args), std::chrono::milliseconds(3000)); } -bool RADPeriphCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) { +bool RADPeriphCommunication::flash(const FWRepo& fw, const icsneo::Bootloader::StatusHandler& handler) { // Validate the firmware before touching the device so a bad file can not leave it erased std::vector bin; if(!fw.getFW(targetChip.getIEFName(), bin)) { @@ -228,7 +228,7 @@ bool RADPeriphCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenS } handler( - icsneo::Device::OpenStatusType::Progress, + StatusType::Progress, "Flashing " + targetChip.getName() + "...", std::nullopt ); @@ -242,7 +242,7 @@ bool RADPeriphCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenS sizeFlashed += static_cast(sector.second.size()); handler( - icsneo::Device::OpenStatusType::Progress, + StatusType::Progress, "Flashing " + targetChip.getName() + "...", (double)sizeFlashed / (double)totalSize ); diff --git a/device/extensions/bootloader/communication/red.cpp b/device/extensions/bootloader/communication/red.cpp index a99e2d19..64ec2e8e 100644 --- a/device/extensions/bootloader/communication/red.cpp +++ b/device/extensions/bootloader/communication/red.cpp @@ -113,7 +113,7 @@ bool REDCommunication::getVersion() { return true; } -bool REDCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) { +bool REDCommunication::flash(const FWRepo& fw, const icsneo::Bootloader::StatusHandler& handler) { const auto& srcVer = fw.getVersion(); std::vector bin; @@ -152,7 +152,7 @@ bool REDCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusH } } - handler(icsneo::Device::OpenStatusType::Progress, + handler(StatusType::Progress, "Preparing to update " + targetChip.getName() + "...", std::nullopt); Log::Debug(__func__, "Erasing " + targetChip.getName()); if(!sendCommand(uint8_t(Command::Erase), std::chrono::seconds(45))) { @@ -164,7 +164,7 @@ bool REDCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusH size_t sectorsFlashed = 0; for(const auto& [id, sector] : sectorPairs) { Log::Trace(__func__, "Flashing sector " + std::to_string(id)); - handler(icsneo::Device::OpenStatusType::Progress, + handler(StatusType::Progress, "Updating " + targetChip.getName() + "...", double(sectorsFlashed++) / sectorPairs.size()); @@ -205,11 +205,11 @@ bool REDCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusH } // Tell the application that we flashed 100% - handler(icsneo::Device::OpenStatusType::Progress, + handler(StatusType::Progress, "Updating " + targetChip.getName() + "...", 1.0); - handler(icsneo::Device::OpenStatusType::Progress, "Finalizing update...", std::nullopt); + handler(StatusType::Progress, "Finalizing update...", std::nullopt); if(!sendCommand(uint8_t(Command::ValidateFirmware))) { Log::Error(__func__, "Firmware validation failed for " + targetChip.getName()); return false; diff --git a/device/extensions/bootloader/communication/redcore.cpp b/device/extensions/bootloader/communication/redcore.cpp index 64711189..1f536931 100644 --- a/device/extensions/bootloader/communication/redcore.cpp +++ b/device/extensions/bootloader/communication/redcore.cpp @@ -9,7 +9,7 @@ namespace icsneo { namespace Bootloader { -bool REDCoreCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) { +bool REDCoreCommunication::flash(const FWRepo& fw, const icsneo::Bootloader::StatusHandler& handler) { constexpr const size_t MaxSectorSize = 0x600; std::vector bin; @@ -31,7 +31,7 @@ bool REDCoreCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenSta std::vector sector; for(size_t i = 0; i < fileSize; i += MaxSectorSize) { Log::Trace(__func__, "Sending sector " + std::to_string(sectorsFlashed)); - handler(icsneo::Device::OpenStatusType::Progress, message, double(sectorsFlashed++) / sectorCount); + handler(StatusType::Progress, message, double(sectorsFlashed++) / sectorCount); sector.assign(bin.begin() + i, bin.begin() + i + std::min(MaxSectorSize, fileSize - i)); if(!sendCommand(uint8_t(Command::SendFirmware), sector)) { @@ -42,7 +42,7 @@ bool REDCoreCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenSta // Then flash it Log::Debug(__func__, "Starting core flash for " + targetChip.getName()); - handler(icsneo::Device::OpenStatusType::Progress, message, std::nullopt); + handler(StatusType::Progress, message, std::nullopt); // There is a long timeout on the StartFirmwareFlash because the bootloader may block here, // potentially for the entire duration of the flash @@ -92,7 +92,7 @@ bool REDCoreCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenSta Log::Trace(__func__, "Flashed " + std::to_string(flashed) + " of " + std::to_string(fileSize)); if(flashed != oldFlashed) - handler(icsneo::Device::OpenStatusType::Progress, message, std::min(double(flashed) / fileSize, 1.0)); + handler(StatusType::Progress, message, std::min(double(flashed) / fileSize, 1.0)); } return flashed == fileSize; diff --git a/examples/python/bootloader/update.py b/examples/python/bootloader/update.py index 477a8c03..1dc65b78 100644 --- a/examples/python/bootloader/update.py +++ b/examples/python/bootloader/update.py @@ -30,7 +30,6 @@ def update(firmware_path): print() last_status = status print(f"\r{status}" + (f" ({progress * 100:.1f}%)" if progress is not None else ""), end="", flush=True) - return icsneopy.Device.OpenDirective.Continue # force_flash updates every chip, even those already at the version in the firmware file ok = icsneopy.Bootloader.update(device, fw, logger, force_flash=True) diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index e9fc4438..52097aad 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -206,21 +206,10 @@ public: public: enum Enum { /** - * Even if the firmware does not match the current firmware version, - * the device will not be updated. - * - * Note: The device may still be flashed if the device has no firmware - * - * This has no effect if the DFU extension is not present + * Skip refreshing the device state. Instead, only open com + * and start the heartbeat thread. */ - SuppressAutoUpdate = 1 << 0, - - /** - * Force reflash the device. - * - * This has no effect if the DFU extension is not present - */ - ForceReflash = 1 << 1 + SkipRefreshDeviceState = 1 << 0, }; using EnumType = std::underlying_type::type; @@ -231,31 +220,8 @@ public: const Enum val; }; - enum class OpenDirective { - Continue, - Cancel, - Skip - }; - - enum class OpenStatusType { - QuestionContinueSkipCancel, - QuestionContinueCancel, - Progress, - Failed - }; - - /** - * @brief Alias of callback function for progress of a bootloader pipeline task - * - * The progress value passed into the callback function indicates the following: - * 1) If the value is std::nullopt, this implies the status message is for an asynchronous task or a task in which the current progress is unknown. - * 2) If the value is between 0 and 1 (i.e., 0 <= progress <= 1), this implies the actual progress of the current task as a percentage. - * 3) Values not between 0 and 1 (i.e., progress < 0 or progress > 1) are undefined. - */ - using OpenStatusHandler = std::function progress)>; - - bool open(OpenFlags flags = {}, OpenStatusHandler handler = - [](OpenStatusType, const std::string&, std::optional) { return Device::OpenDirective::Continue; }); + bool open(OpenFlags flags = {}); + APIEvent::Type refreshDeviceState(); virtual bool close(); virtual bool isOnline() const { return online; } virtual bool isOpen() const { return com->isOpen(); } diff --git a/include/icsneo/device/extensions/bootloader/api.h b/include/icsneo/device/extensions/bootloader/api.h index da43b48a..bc4e05fc 100644 --- a/include/icsneo/device/extensions/bootloader/api.h +++ b/include/icsneo/device/extensions/bootloader/api.h @@ -15,20 +15,33 @@ namespace icsneo { namespace Bootloader { -using Logger = icsneo::Device::OpenStatusHandler; +enum class StatusType { + Progress, + Failed +}; + +/** + * @brief Alias of callback function for progress of a bootloader pipeline task + * + * The progress value passed into the callback function indicates the following: + * 1) If the value is std::nullopt, this implies the status message is for an asynchronous task or a task in which the current progress is unknown. + * 2) If the value is between 0 and 1 (i.e., 0 <= progress <= 1), this implies the actual progress of the current task as a percentage. + * 3) Values not between 0 and 1 (i.e., progress < 0 or progress > 1) are undefined. + */ +using StatusHandler = std::function progress)>; bool requiresUpdate(icsneo::Device& device, const FWRepo& fw); bool update( icsneo::Device& device, const FWRepo& fw, - Logger logger = [](icsneo::Device::OpenStatusType, const std::string&, std::optional) { return icsneo::Device::OpenDirective::Continue; }, + StatusHandler statusHandler = [](StatusType, const std::string&, std::optional) {}, bool alreadyInBootloader = false, bool forceFlash = false ); bool enterBootloader(icsneo::Device& device); -bool exitBootloader(icsneo::Device& device, Logger logger, bool updatedChips); -bool verifyConnection(icsneo::Device& device, Logger logger); +bool exitBootloader(icsneo::Device& device, StatusHandler statusHandler, bool updatedChips); +bool verifyConnection(icsneo::Device& device, StatusHandler statusHandler); bool isSFPChip(const icsneo::Bootloader::Chip& chip); bool isSFPIEF(const icsneo::Bootloader::IEF& ief); diff --git a/include/icsneo/device/extensions/bootloader/communication/application.h b/include/icsneo/device/extensions/bootloader/communication/application.h index e8fa11ad..be16bed3 100644 --- a/include/icsneo/device/extensions/bootloader/communication/application.h +++ b/include/icsneo/device/extensions/bootloader/communication/application.h @@ -31,7 +31,7 @@ public: return true; } bool finalize() override; - bool flash(const FWRepo& repo, const icsneo::Device::OpenStatusHandler& handler) override; + bool flash(const FWRepo& repo, const StatusHandler& handler) override; bool open() override { return true; @@ -42,8 +42,8 @@ public: } bool authenticate(); - bool sendSoftware(const std::vector& bin, const icsneo::Device::OpenStatusHandler& handler); - bool sendSoftware(const std::vector& sectors, uint32_t blockSize, const icsneo::Device::OpenStatusHandler& handler); + bool sendSoftware(const std::vector& bin, const StatusHandler& handler); + bool sendSoftware(const std::vector& sectors, uint32_t blockSize, const StatusHandler& handler); bool validateFirmware(const DeviceAppVersion& chipSrcVer); bool validateComponent(); @@ -74,12 +74,12 @@ private: const bool doAuthChecks; const bool encrypted; - using StatusHandler = std::function; - bool sendCommand(Update command, const StatusHandler& handler, uint32_t offset = 0, + using CommandStatusHandler = std::function; + bool sendCommand(Update command, const CommandStatusHandler& handler, uint32_t offset = 0, const std::vector& args = {}, std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)) { return sendCommand(command, offset, static_cast(args.size()), handler, timeout, args); } - bool sendCommand(Update command, uint32_t offset, uint32_t length, const StatusHandler& handler, + bool sendCommand(Update command, uint32_t offset, uint32_t length, const CommandStatusHandler& handler, std::chrono::milliseconds timeout = std::chrono::milliseconds(3000), std::vector args = {}); }; diff --git a/include/icsneo/device/extensions/bootloader/communication/communication.h b/include/icsneo/device/extensions/bootloader/communication/communication.h index 40249a69..1c341cd7 100644 --- a/include/icsneo/device/extensions/bootloader/communication/communication.h +++ b/include/icsneo/device/extensions/bootloader/communication/communication.h @@ -5,6 +5,7 @@ #include "icsneo/device/extensions/bootloader/chip.h" #include "icsneo/device/device.h" +#include "icsneo/device/extensions/bootloader/api.h" #include @@ -29,7 +30,7 @@ public: virtual bool enterApplication() = 0; virtual bool hasFinalizationStep() const = 0; virtual bool finalize() = 0; - virtual bool flash(const FWRepo& repo, const icsneo::Device::OpenStatusHandler& handler) = 0; + virtual bool flash(const FWRepo& repo, const StatusHandler& handler) = 0; virtual bool open() = 0; virtual bool close() = 0; diff --git a/include/icsneo/device/extensions/bootloader/communication/radcommunication.h b/include/icsneo/device/extensions/bootloader/communication/radcommunication.h index 4fff5a33..f5b37438 100644 --- a/include/icsneo/device/extensions/bootloader/communication/radcommunication.h +++ b/include/icsneo/device/extensions/bootloader/communication/radcommunication.h @@ -69,7 +69,7 @@ protected: Response& sendRequest(const Request& request, std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)); bool sendRequestNoResponse(); - icsneo::Device::OpenStatusHandler logger; // Progress updates, set in flash() + StatusHandler statusHandler; // Progress updates, set in flash() Response lastResponse; // Last response received from sendRequest bool supportsZynqBinaryFlasher = false; // Dictates how messages are formatted, this gets set in initialize() @@ -92,7 +92,7 @@ public: bool enterApplication() override; bool finalize() override; - bool flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) override; + bool flash(const FWRepo& fw, const StatusHandler& handler) override; bool open() override; bool close() override; diff --git a/include/icsneo/device/extensions/bootloader/communication/radmultichipcommunication.h b/include/icsneo/device/extensions/bootloader/communication/radmultichipcommunication.h index 0de59206..e64ba453 100644 --- a/include/icsneo/device/extensions/bootloader/communication/radmultichipcommunication.h +++ b/include/icsneo/device/extensions/bootloader/communication/radmultichipcommunication.h @@ -22,7 +22,7 @@ private: public: RADMultiChipCommunication(icsneo::Device& dev, const ChipInfo& chipToFlash, bool auth, uint8_t slot = UINT8_MAX); - bool flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) override; + bool flash(const FWRepo& fw, const StatusHandler& handler) override; bool open() override; bool close() override; bool enterApplication() override; diff --git a/include/icsneo/device/extensions/bootloader/communication/radperiphcommunication.h b/include/icsneo/device/extensions/bootloader/communication/radperiphcommunication.h index a4d19b68..69342fa2 100644 --- a/include/icsneo/device/extensions/bootloader/communication/radperiphcommunication.h +++ b/include/icsneo/device/extensions/bootloader/communication/radperiphcommunication.h @@ -79,7 +79,7 @@ public: RADPeriphCommunication(icsneo::Device& dev, const ChipInfo& chipToFlash); ~RADPeriphCommunication(); - bool flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) override; + bool flash(const FWRepo& fw, const StatusHandler& handler) override; bool open() override; bool close() override; bool enterApplication() override; diff --git a/include/icsneo/device/extensions/bootloader/communication/red.h b/include/icsneo/device/extensions/bootloader/communication/red.h index eee5c08b..d29e7527 100644 --- a/include/icsneo/device/extensions/bootloader/communication/red.h +++ b/include/icsneo/device/extensions/bootloader/communication/red.h @@ -23,7 +23,7 @@ class REDCommunication : public REDCommunicationBase { public: REDCommunication(icsneo::Device& dev, const ChipInfo& chip, bool auth, bool encryptWithDeviceKey = true); bool enterApplication() override { return sendCommand(uint8_t(Command::EnterApplication)); } - bool flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) override; + bool flash(const FWRepo& fw, const StatusHandler& handler) override; bool open() override; private: diff --git a/include/icsneo/device/extensions/bootloader/communication/redcore.h b/include/icsneo/device/extensions/bootloader/communication/redcore.h index af8e6722..665bc397 100644 --- a/include/icsneo/device/extensions/bootloader/communication/redcore.h +++ b/include/icsneo/device/extensions/bootloader/communication/redcore.h @@ -27,7 +27,7 @@ public: using REDCommunicationBase::REDCommunicationBase; bool enterApplication() override { return false; } - bool flash(const FWRepo& fw, const icsneo::Device::OpenStatusHandler& handler) override; + bool flash(const FWRepo& fw, const StatusHandler& handler) override; private: /** * Core flasher commands are tunneled through a RED request using CoreFlasherCommand, diff --git a/include/icsneo/device/extensions/deviceextension.h b/include/icsneo/device/extensions/deviceextension.h index 244273a9..67d66564 100644 --- a/include/icsneo/device/extensions/deviceextension.h +++ b/include/icsneo/device/extensions/deviceextension.h @@ -16,12 +16,6 @@ public: virtual ~DeviceExtension() = default; virtual const char* getName() const = 0; - // Return false to block opening - virtual bool onDeviceOpen(Device::OpenFlags, const Device::OpenStatusHandler&) { return true; } - - // Return true to indicate that communication should now be back - virtual bool onDeviceCommunicationDead(Device::OpenFlags, const Device::OpenStatusHandler&) { return false; } - virtual void onGoOnline() {} virtual void onGoOffline() {} virtual void onDeviceClose() {}