mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-11-04 04:49:07 +01:00
Device: Allow skipping of device state refreshing on call to open
This commit is contained in:
committed by
Kyle Schwarz
parent
dffb0bcefb
commit
645549193d
@@ -1,6 +1,7 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/functional.h>
|
||||
#include <pybind11/native_enum.h>
|
||||
|
||||
#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>(bootloader, "FWLoader")
|
||||
.def_static("load", &Bootloader::FWLoader::Load, pybind11::arg("path"), pybind11::call_guard<pybind11::gil_scoped_release>());
|
||||
|
||||
pybind11::native_enum<Bootloader::StatusType>(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<double>) { 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<double>) {};
|
||||
}
|
||||
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<pybind11::gil_scoped_release>());
|
||||
|
||||
@@ -15,19 +15,6 @@ namespace icsneo {
|
||||
void init_device(pybind11::module_& m) {
|
||||
pybind11::classh<Device> device(m, "Device");
|
||||
|
||||
pybind11::native_enum<Device::OpenDirective>(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>(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<pybind11::gil_scoped_release>())
|
||||
|
||||
+22
-30
@@ -275,7 +275,7 @@ std::vector<VersionReport> 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<DeviceExtension>& 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<DeviceExtension>& 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);
|
||||
|
||||
@@ -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<MessageFilter>(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) {
|
||||
|
||||
@@ -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<uint8_t>(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<uint8_t>& bin, const icsneo::Device::OpenStatusHandler& handler) {
|
||||
bool Application::sendSoftware(const std::vector<uint8_t>& 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<uint32_t>::max()) {
|
||||
Log::Error(__func__, "invalid firmware size for " + targetChip.getName());
|
||||
return false;
|
||||
@@ -144,14 +144,14 @@ bool Application::sendSoftware(const std::vector<uint8_t>& 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<uint32_t>(totalSize, 2048);
|
||||
uint32_t bytesTransferred = 0;
|
||||
@@ -163,7 +163,7 @@ bool Application::sendSoftware(const std::vector<uint8_t>& 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<uint8_t>& bin, const icsneo::De
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::sendSoftware(const std::vector<IEF::Sector>& sectorPairs, uint32_t blockSize, const icsneo::Device::OpenStatusHandler& handler) {
|
||||
bool Application::sendSoftware(const std::vector<IEF::Sector>& 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<IEF::Sector>& 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<IEF::Sector>& sectorPairs, uint
|
||||
|
||||
Log::Debug(__func__, "erasing " + targetChip.getName() + " (" + std::to_string(totalSize) + " bytes)");
|
||||
if(!sendCommand(Update::Erase, 0, static_cast<uint32_t>(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<IEF::Sector>& 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<IEF::Sector>& sectorPairs, uint
|
||||
}
|
||||
|
||||
bytesTransferred += static_cast<uint32_t>(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<uint8_t> args) {
|
||||
bool Application::sendCommand(Update command, uint32_t offset, uint32_t length, const CommandStatusHandler& handler, std::chrono::milliseconds timeout, std::vector<uint8_t> args) {
|
||||
bool finishedResponse = false;
|
||||
std::condition_variable finishedResponseCV;
|
||||
std::mutex finishedResponseMutex;
|
||||
|
||||
@@ -323,8 +323,8 @@ bool RADCommunication::sendSoftware(const std::vector<uint8_t>& 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<uint8_t>& chipSoftware) {
|
||||
while(remainingBytes > 0) {
|
||||
const double progress = static_cast<double>(currentlyReading) / static_cast<double>(chipSoftware.size());
|
||||
|
||||
logger(
|
||||
icsneo::Device::OpenStatusType::Progress,
|
||||
statusHandler(
|
||||
StatusType::Progress,
|
||||
"Flashing " + targetChip.getName() + "...",
|
||||
progress
|
||||
);
|
||||
@@ -407,8 +407,8 @@ bool RADCommunication::sendSoftware(const std::vector<uint8_t>& 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<uint32_t>(sizeToValidate)) {
|
||||
const double progress = static_cast<double>(status) / static_cast<double>(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<uint8_t>& 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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<uint8_t> 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<uint32_t>(sector.second.size());
|
||||
handler(
|
||||
icsneo::Device::OpenStatusType::Progress,
|
||||
StatusType::Progress,
|
||||
"Flashing " + targetChip.getName() + "...",
|
||||
(double)sizeFlashed / (double)totalSize
|
||||
);
|
||||
|
||||
@@ -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<uint8_t> 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;
|
||||
|
||||
@@ -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<uint8_t> bin;
|
||||
@@ -31,7 +31,7 @@ bool REDCoreCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenSta
|
||||
std::vector<uint8_t> 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<size_t>(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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<Enum>::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<Device::OpenDirective(OpenStatusType type, const std::string& status, std::optional<double> progress)>;
|
||||
|
||||
bool open(OpenFlags flags = {}, OpenStatusHandler handler =
|
||||
[](OpenStatusType, const std::string&, std::optional<double>) { 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(); }
|
||||
|
||||
@@ -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<void(StatusType type, const std::string& status, std::optional<double> 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<double>) { return icsneo::Device::OpenDirective::Continue; },
|
||||
StatusHandler statusHandler = [](StatusType, const std::string&, std::optional<double>) {},
|
||||
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);
|
||||
|
||||
@@ -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<uint8_t>& bin, const icsneo::Device::OpenStatusHandler& handler);
|
||||
bool sendSoftware(const std::vector<IEF::Sector>& sectors, uint32_t blockSize, const icsneo::Device::OpenStatusHandler& handler);
|
||||
bool sendSoftware(const std::vector<uint8_t>& bin, const StatusHandler& handler);
|
||||
bool sendSoftware(const std::vector<IEF::Sector>& 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<void(double progress)>;
|
||||
bool sendCommand(Update command, const StatusHandler& handler, uint32_t offset = 0,
|
||||
using CommandStatusHandler = std::function<void(double progress)>;
|
||||
bool sendCommand(Update command, const CommandStatusHandler& handler, uint32_t offset = 0,
|
||||
const std::vector<uint8_t>& args = {}, std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)) {
|
||||
return sendCommand(command, offset, static_cast<uint32_t>(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<uint8_t> args = {});
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "icsneo/device/extensions/bootloader/chip.h"
|
||||
#include "icsneo/device/device.h"
|
||||
#include "icsneo/device/extensions/bootloader/api.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
Reference in New Issue
Block a user