5 Commits
23 changed files with 141 additions and 169 deletions
+10 -2
View File
@@ -329,9 +329,10 @@ deploy python/pypi:
image: python:3.13 image: python:3.13
rules: rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
script: script:
- python3 -m pip install -U twine - python3 -m pip install -U twine
- twine upload wheelhouse/* - twine upload --verbose wheelhouse/*
dependencies: dependencies:
- build python/linux/amd64 - build python/linux/amd64
- build python/linux/arm64 - build python/linux/arm64
@@ -353,10 +354,17 @@ push github:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: delayed when: delayed
start_in: 10 minutes start_in: 10 minutes
variables:
REFSPEC: HEAD:master
- if: $CI_COMMIT_TAG
when: delayed
start_in: 10 minutes
variables:
REFSPEC: $CI_COMMIT_TAG
dependencies: dependencies:
- deploy python/pypi - deploy python/pypi
needs: needs:
- deploy python/pypi - deploy python/pypi
script: script:
- apk add git - apk add git
- git push https://$LIBICSNEO_GITHUB_USERNAME:$LIBICSNEO_GITHUB_TOKEN@github.com/intrepidcs/libicsneo.git HEAD:master - git push https://$LIBICSNEO_GITHUB_USERNAME:$LIBICSNEO_GITHUB_TOKEN@github.com/intrepidcs/libicsneo.git $REFSPEC
@@ -1,6 +1,7 @@
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include <pybind11/functional.h> #include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/device/extensions/bootloader/api.h" #include "icsneo/device/extensions/bootloader/api.h"
#include "icsneo/device/extensions/bootloader/parser/fwloader.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") pybind11::classh<Bootloader::FWLoader>(bootloader, "FWLoader")
.def_static("load", &Bootloader::FWLoader::Load, pybind11::arg("path"), pybind11::call_guard<pybind11::gil_scoped_release>()); .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", bootloader.def_static("update",
[](Device& device, const Bootloader::FWRepo& fw, Bootloader::Logger logger, bool alreadyInBootloader, bool forceFlash) { [](Device& device, const Bootloader::FWRepo& fw, Bootloader::StatusHandler statusHandler, bool alreadyInBootloader, bool forceFlash) {
if(!logger) { if(!statusHandler) {
logger = [](Device::OpenStatusType, const std::string&, std::optional<double>) { return Device::OpenDirective::Continue; }; 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("device"),
pybind11::arg("fw"), pybind11::arg("fw"),
pybind11::arg("logger") = pybind11::none(), pybind11::arg("statusHandler") = pybind11::none(),
pybind11::arg("already_in_bootloader") = false, pybind11::arg("already_in_bootloader") = false,
pybind11::arg("force_flash") = false, pybind11::arg("force_flash") = false,
pybind11::call_guard<pybind11::gil_scoped_release>()); pybind11::call_guard<pybind11::gil_scoped_release>());
@@ -15,19 +15,6 @@ namespace icsneo {
void init_device(pybind11::module_& m) { void init_device(pybind11::module_& m) {
pybind11::classh<Device> device(m, "Device"); 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 device
.def("__repr__", &Device::describe) .def("__repr__", &Device::describe)
.def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
+7 -1
View File
@@ -9,7 +9,13 @@
using namespace icsneo; using namespace icsneo;
bool Driver::pushRx(const uint8_t* buf, size_t numReceived) { bool Driver::pushRx(const uint8_t* buf, size_t numReceived) {
bool ret = readBuffer.write(buf, numReceived); bool ret;
{
// Write under the lock waitForRx checks its predicate with, or a notify between that check and
// the wait is lost and the reader sleeps the full timeout (1s for the read task) with data ready
std::lock_guard<std::mutex> lk(rxWaitMutex);
ret = readBuffer.write(buf, numReceived);
}
rxWaitCv.notify_all(); rxWaitCv.notify_all();
+22 -30
View File
@@ -275,7 +275,7 @@ std::vector<VersionReport> Device::getChipVersions(bool refreshComponents) {
return chipVersions; return chipVersions;
} }
bool Device::open(OpenFlags flags, OpenStatusHandler handler) { bool Device::open(OpenFlags flags) {
if(!com) { if(!com) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error); report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false; return false;
@@ -287,38 +287,31 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
startHeartbeat(); startHeartbeat();
APIEvent::Type attemptErr = attemptToBeginCommunication(); if((flags & OpenFlags::SkipRefreshDeviceState) == 0) {
if(attemptErr != APIEvent::Type::NoErrorFound) { auto refreshErr = refreshDeviceState();
// We could not communicate with the device, let's see if an extension can if(refreshErr != APIEvent::Type::NoErrorFound) {
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) {
com->close(); com->close();
report(attemptErr, APIEvent::Severity::Error); stopHeartbeat();
return false; // Extensions couldn't save us report(refreshErr, APIEvent::Severity::Error);
}
attemptErr = attemptToBeginCommunication();
if(attemptErr != APIEvent::Type::NoErrorFound) {
com->close();
report(attemptErr, APIEvent::Severity::Error);
return false; return false;
} }
} }
bool block = false; return true;
forEachExtension([&block, &flags, &handler](const std::shared_ptr<DeviceExtension>& ext) { }
if(ext->onDeviceOpen(flags, handler))
return true; APIEvent::Type Device::refreshDeviceState() {
block = true; if(isOnline()) {
return false; return APIEvent::Type::DeviceCurrentlyOnline;
}); }
if(block) // Extensions say no
return false; if(!com || !com->isOpen()) {
return APIEvent::Type::Unknown;
}
APIEvent::Type attemptErr = attemptToBeginCommunication();
if(attemptErr != APIEvent::Type::NoErrorFound) {
return attemptErr;
}
refreshComponentVersions(); refreshComponentVersions();
if(!settings->disabled) { if(!settings->disabled) {
@@ -336,7 +329,7 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
if(supportsLiveData()) if(supportsLiveData())
clearAllLiveData(); clearAllLiveData();
return true; return APIEvent::Type::NoErrorFound;
} }
bool Device::reconnect(std::chrono::milliseconds timeout, std::chrono::milliseconds interval) { bool Device::reconnect(std::chrono::milliseconds timeout, std::chrono::milliseconds interval) {
@@ -412,7 +405,6 @@ APIEvent::Type Device::attemptToBeginCommunication() {
else else
versions = std::move(*maybeVersions); versions = std::move(*maybeVersions);
// Get component versions before the extension "onDeviceOpen" hooks so that we can properly check verisons
if(supportsComponentVersions()) { if(supportsComponentVersions()) {
if(auto compVersions = com->getComponentVersionsSync()) if(auto compVersions = com->getComponentVersionsSync())
componentVersions = std::move(*compVersions); componentVersions = std::move(*compVersions);
+13 -13
View File
@@ -111,7 +111,7 @@ static bool runPipeline(
icsneo::Device& device, icsneo::Device& device,
const BootloaderPipeline& pipeline, const BootloaderPipeline& pipeline,
const FWRepo& fw, const FWRepo& fw,
const Logger& logger, const StatusHandler& statusHandler,
bool alreadyInBootloader, bool alreadyInBootloader,
bool forceFlash bool forceFlash
) { ) {
@@ -167,7 +167,7 @@ static bool runPipeline(
auto com = getCommunication(device, flashPhase, info); auto com = getCommunication(device, flashPhase, info);
if(!withCommunication(com.get(), info, "FlashPhase", [&](Bootloader::Communication& opened) { 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)); Log::Error("FlashPhase", "failed to flash " + chipString(flashPhase.chip));
return false; return false;
} }
@@ -257,13 +257,13 @@ static bool runPipeline(
} }
} }
} }
return exitBootloader(device, logger, !chipsFlashed.empty()); return exitBootloader(device, statusHandler, !chipsFlashed.empty());
} }
bool Bootloader::update( bool Bootloader::update(
icsneo::Device& device, icsneo::Device& device,
const FWRepo& fw, const FWRepo& fw,
Logger logger, StatusHandler statusHandler,
bool alreadyInBootloader, bool alreadyInBootloader,
bool forceFlash bool forceFlash
) { ) {
@@ -273,7 +273,7 @@ bool Bootloader::update(
return false; 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); device.getEventHandler()(APIEvent::Type::FirmwareUpdateFailed, APIEvent::Severity::Error);
return false; return false;
} }
@@ -287,19 +287,19 @@ bool Bootloader::enterBootloader(icsneo::Device& device) {
return device.reconnect(std::chrono::milliseconds(30000)); 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) { if(!updatedChips) {
return true; return true;
} }
logger(icsneo::Device::OpenStatusType::Progress, "Connecting to the device...", std::nullopt); statusHandler(StatusType::Progress, "Connecting to the device...", std::nullopt);
return verifyConnection(device, logger); return verifyConnection(device, statusHandler);
} }
/** /**
* Toggle network communication and wait up to 5 seconds for a reset status confirming the change. * 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. * 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); static constexpr std::chrono::seconds Timeout(5);
const auto filter = std::make_shared<MessageFilter>(Message::Type::ResetStatus); 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 // 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; 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; 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 // 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) { bool Bootloader::isSFPChip(const icsneo::Bootloader::Chip& chip) {
@@ -38,7 +38,7 @@ bool Application::finalize() {
return ok; 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()); Log::Info(__func__, "starting flash for " + targetChip.getName());
const auto& srcVer = fw.getVersion(); 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() + "..."; 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 // The supplied IEF is not for this product
if(ief.getVersion().prodId != static_cast<uint8_t>(device.getProductID())) { 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}); 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)"); Log::Debug(__func__, "starting for " + targetChip.getName() + " (" + std::to_string(bin.size()) + " bytes)");
auto currentString = "Preparing to update " + targetChip.getName() + "..."; 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()) { if(bin.empty() || bin.size() > std::numeric_limits<uint32_t>::max()) {
Log::Error(__func__, "invalid firmware size for " + targetChip.getName()); Log::Error(__func__, "invalid firmware size for " + targetChip.getName());
return false; return false;
@@ -144,14 +144,14 @@ bool Application::sendSoftware(const std::vector<uint8_t>& bin, const icsneo::De
Log::Debug(__func__, "erasing " + targetChip.getName()); Log::Debug(__func__, "erasing " + targetChip.getName());
if(!sendCommand(Update::Erase, 0, totalSize, [&](double progress) { if(!sendCommand(Update::Erase, 0, totalSize, [&](double progress) {
handler(icsneo::Device::OpenStatusType::Progress, currentString, progress); handler(StatusType::Progress, currentString, progress);
}, std::chrono::milliseconds(45000))) { }, std::chrono::milliseconds(45000))) {
Log::Error(__func__, "erase failed for " + targetChip.getName()); Log::Error(__func__, "erase failed for " + targetChip.getName());
return false; return false;
} }
currentString = "Updating " + targetChip.getName() + "..."; 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); const uint32_t stepSize = std::min<uint32_t>(totalSize, 2048);
uint32_t bytesTransferred = 0; uint32_t bytesTransferred = 0;
@@ -163,7 +163,7 @@ bool Application::sendSoftware(const std::vector<uint8_t>& bin, const icsneo::De
} }
bytesTransferred += bytesToSend; 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()); Log::Debug(__func__, "write complete, validating " + targetChip.getName());
if(!validateComponent()) { if(!validateComponent()) {
@@ -174,7 +174,7 @@ bool Application::sendSoftware(const std::vector<uint8_t>& bin, const icsneo::De
return true; 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()) { if(sectorPairs.empty()) {
Log::Error(__func__, "no sectors to flash for " + targetChip.getName()); Log::Error(__func__, "no sectors to flash for " + targetChip.getName());
return false; 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)"); Log::Debug(__func__, "starting for " + targetChip.getName() + " (" + std::to_string(sectorPairs.size()) + " sectors)");
auto currentString = "Preparing to update " + targetChip.getName() + "..."; 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; uint64_t totalSize = 0;
for(const auto& sector : sectorPairs) { for(const auto& sector : sectorPairs) {
totalSize += sector.second.size(); 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)"); Log::Debug(__func__, "erasing " + targetChip.getName() + " (" + std::to_string(totalSize) + " bytes)");
if(!sendCommand(Update::Erase, 0, static_cast<uint32_t>(totalSize), [&](double progress) { 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))) { }, std::chrono::milliseconds(45000))) {
Log::Error(__func__, "erase failed for " + targetChip.getName()); Log::Error(__func__, "erase failed for " + targetChip.getName());
return false; return false;
@@ -212,7 +212,7 @@ bool Application::sendSoftware(const std::vector<IEF::Sector>& sectorPairs, uint
} }
currentString = "Updating " + targetChip.getName() + "..."; currentString = "Updating " + targetChip.getName() + "...";
handler(icsneo::Device::OpenStatusType::Progress, currentString, std::nullopt); handler(StatusType::Progress, currentString, std::nullopt);
uint32_t bytesTransferred = 0; uint32_t bytesTransferred = 0;
for(const auto& pair : sectorPairs) { 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()); 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()); Log::Debug(__func__, "write complete, validating " + targetChip.getName());
bool ok = validateComponent(); bool ok = validateComponent();
@@ -264,7 +264,7 @@ bool Application::validateComponent() {
* passes. Progress replies are OperationPending with a SoftwareUpdateCommandHeader whose * passes. Progress replies are OperationPending with a SoftwareUpdateCommandHeader whose
* commandSizeOrProgress holds the progress so far, or a GenericReturn with no progress. * 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; bool finishedResponse = false;
std::condition_variable finishedResponseCV; std::condition_variable finishedResponseCV;
std::mutex finishedResponseMutex; std::mutex finishedResponseMutex;
@@ -323,8 +323,8 @@ bool RADCommunication::sendSoftware(const std::vector<uint8_t>& chipSoftware) {
size_t remainingBytes = chipSoftware.size(); size_t remainingBytes = chipSoftware.size();
size_t currentlyReading = 0; size_t currentlyReading = 0;
logger( statusHandler(
icsneo::Device::OpenStatusType::Progress, StatusType::Progress,
"Flashing " + targetChip.getName() + "...", "Flashing " + targetChip.getName() + "...",
std::nullopt std::nullopt
); );
@@ -332,8 +332,8 @@ bool RADCommunication::sendSoftware(const std::vector<uint8_t>& chipSoftware) {
while(remainingBytes > 0) { while(remainingBytes > 0) {
const double progress = static_cast<double>(currentlyReading) / static_cast<double>(chipSoftware.size()); const double progress = static_cast<double>(currentlyReading) / static_cast<double>(chipSoftware.size());
logger( statusHandler(
icsneo::Device::OpenStatusType::Progress, StatusType::Progress,
"Flashing " + targetChip.getName() + "...", "Flashing " + targetChip.getName() + "...",
progress progress
); );
@@ -407,8 +407,8 @@ bool RADCommunication::sendSoftware(const std::vector<uint8_t>& chipSoftware) {
} }
} }
logger( statusHandler(
icsneo::Device::OpenStatusType::Progress, StatusType::Progress,
"Flashing " + targetChip.getName() + "...", "Flashing " + targetChip.getName() + "...",
1.0 1.0
); );
@@ -431,8 +431,8 @@ bool RADCommunication::getProgrammingStatus(size_t sizeToValidate) {
uint32_t status = 0; uint32_t status = 0;
const auto beginTime = std::chrono::steady_clock::now(); const auto beginTime = std::chrono::steady_clock::now();
logger( statusHandler(
icsneo::Device::OpenStatusType::Progress, StatusType::Progress,
"Programming " + targetChip.getName() + "...", "Programming " + targetChip.getName() + "...",
std::nullopt std::nullopt
); );
@@ -440,8 +440,8 @@ bool RADCommunication::getProgrammingStatus(size_t sizeToValidate) {
while(status < static_cast<uint32_t>(sizeToValidate)) { while(status < static_cast<uint32_t>(sizeToValidate)) {
const double progress = static_cast<double>(status) / static_cast<double>(sizeToValidate); const double progress = static_cast<double>(status) / static_cast<double>(sizeToValidate);
logger( statusHandler(
icsneo::Device::OpenStatusType::Progress, StatusType::Progress,
"Programming " + targetChip.getName() + "...", "Programming " + targetChip.getName() + "...",
progress progress
); );
@@ -457,8 +457,8 @@ bool RADCommunication::getProgrammingStatus(size_t sizeToValidate) {
} }
} }
logger( statusHandler(
icsneo::Device::OpenStatusType::Progress, StatusType::Progress,
"Programming " + targetChip.getName() + "...", "Programming " + targetChip.getName() + "...",
1.0 1.0
); );
@@ -510,7 +510,7 @@ bool RADCommunication::loadZips(const FWRepo& fw, std::vector<uint8_t>& chipSoft
return false; 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()); Log::Info(__func__, "starting flash for " + targetChip.getName());
auto chipSrcVer = fw.getChipVersion(targetChip.getIEFName()); auto chipSrcVer = fw.getChipVersion(targetChip.getIEFName());
if(!chipSrcVer) { if(!chipSrcVer) {
@@ -524,7 +524,7 @@ bool RADCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenStatusH
return false; return false;
} }
logger = handler; statusHandler = handler;
if(!validateChipVersion(*chipSrcVer)) { if(!validateChipVersion(*chipSrcVer)) {
Log::Error(__func__, "validateChipVersion failed for " + targetChip.getName()); Log::Error(__func__, "validateChipVersion failed for " + targetChip.getName());
return false; return false;
@@ -41,7 +41,7 @@ bool RADMultiChipCommunication::authenticate() {
return true; 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()); Log::Info(__func__, "starting flash for " + targetChip.getName());
auto chipSrcVer = fw.getChipVersion(targetChip.getIEFName()); auto chipSrcVer = fw.getChipVersion(targetChip.getIEFName());
if(!chipSrcVer) { if(!chipSrcVer) {
@@ -56,7 +56,7 @@ bool RADMultiChipCommunication::flash(const FWRepo& fw, const icsneo::Device::Op
if(!standardComm->validateFirmware(*chipSrcVer)) { if(!standardComm->validateFirmware(*chipSrcVer)) {
Log::Error(__func__, "firmware validation failed for " + targetChip.getName()); 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; return false;
} }
@@ -103,7 +103,7 @@ bool RADMultiChipCommunication::flash(const FWRepo& fw, const icsneo::Device::Op
return false; return false;
} }
Log::Debug(__func__, "finalize successful, proceeding to reboot"); 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; return true;
} }
@@ -180,7 +180,7 @@ bool RADPeriphCommunication::flashSector(const IEF::Sector& sector) {
return sendRequest(Request::FlashSector, std::move(args), std::chrono::milliseconds(3000)); 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 // Validate the firmware before touching the device so a bad file can not leave it erased
std::vector<uint8_t> bin; std::vector<uint8_t> bin;
if(!fw.getFW(targetChip.getIEFName(), bin)) { if(!fw.getFW(targetChip.getIEFName(), bin)) {
@@ -228,7 +228,7 @@ bool RADPeriphCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenS
} }
handler( handler(
icsneo::Device::OpenStatusType::Progress, StatusType::Progress,
"Flashing " + targetChip.getName() + "...", "Flashing " + targetChip.getName() + "...",
std::nullopt std::nullopt
); );
@@ -242,7 +242,7 @@ bool RADPeriphCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenS
sizeFlashed += static_cast<uint32_t>(sector.second.size()); sizeFlashed += static_cast<uint32_t>(sector.second.size());
handler( handler(
icsneo::Device::OpenStatusType::Progress, StatusType::Progress,
"Flashing " + targetChip.getName() + "...", "Flashing " + targetChip.getName() + "...",
(double)sizeFlashed / (double)totalSize (double)sizeFlashed / (double)totalSize
); );
@@ -113,7 +113,7 @@ bool REDCommunication::getVersion() {
return true; 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(); const auto& srcVer = fw.getVersion();
std::vector<uint8_t> bin; 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); "Preparing to update " + targetChip.getName() + "...", std::nullopt);
Log::Debug(__func__, "Erasing " + targetChip.getName()); Log::Debug(__func__, "Erasing " + targetChip.getName());
if(!sendCommand(uint8_t(Command::Erase), std::chrono::seconds(45))) { 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; size_t sectorsFlashed = 0;
for(const auto& [id, sector] : sectorPairs) { for(const auto& [id, sector] : sectorPairs) {
Log::Trace(__func__, "Flashing sector " + std::to_string(id)); Log::Trace(__func__, "Flashing sector " + std::to_string(id));
handler(icsneo::Device::OpenStatusType::Progress, handler(StatusType::Progress,
"Updating " + targetChip.getName() + "...", "Updating " + targetChip.getName() + "...",
double(sectorsFlashed++) / sectorPairs.size()); 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% // Tell the application that we flashed 100%
handler(icsneo::Device::OpenStatusType::Progress, handler(StatusType::Progress,
"Updating " + targetChip.getName() + "...", "Updating " + targetChip.getName() + "...",
1.0); 1.0);
handler(icsneo::Device::OpenStatusType::Progress, "Finalizing update...", std::nullopt); handler(StatusType::Progress, "Finalizing update...", std::nullopt);
if(!sendCommand(uint8_t(Command::ValidateFirmware))) { if(!sendCommand(uint8_t(Command::ValidateFirmware))) {
Log::Error(__func__, "Firmware validation failed for " + targetChip.getName()); Log::Error(__func__, "Firmware validation failed for " + targetChip.getName());
return false; return false;
@@ -9,7 +9,7 @@ namespace icsneo {
namespace Bootloader { 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; constexpr const size_t MaxSectorSize = 0x600;
std::vector<uint8_t> bin; std::vector<uint8_t> bin;
@@ -31,7 +31,7 @@ bool REDCoreCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenSta
std::vector<uint8_t> sector; std::vector<uint8_t> sector;
for(size_t i = 0; i < fileSize; i += MaxSectorSize) { for(size_t i = 0; i < fileSize; i += MaxSectorSize) {
Log::Trace(__func__, "Sending sector " + std::to_string(sectorsFlashed)); 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)); sector.assign(bin.begin() + i, bin.begin() + i + std::min<size_t>(MaxSectorSize, fileSize - i));
if(!sendCommand(uint8_t(Command::SendFirmware), sector)) { if(!sendCommand(uint8_t(Command::SendFirmware), sector)) {
@@ -42,7 +42,7 @@ bool REDCoreCommunication::flash(const FWRepo& fw, const icsneo::Device::OpenSta
// Then flash it // Then flash it
Log::Debug(__func__, "Starting core flash for " + targetChip.getName()); 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, // There is a long timeout on the StartFirmwareFlash because the bootloader may block here,
// potentially for the entire duration of the flash // 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)); Log::Trace(__func__, "Flashed " + std::to_string(flashed) + " of " + std::to_string(fileSize));
if(flashed != oldFlashed) 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; return flashed == fileSize;
-1
View File
@@ -30,7 +30,6 @@ def update(firmware_path):
print() print()
last_status = status last_status = status
print(f"\r{status}" + (f" ({progress * 100:.1f}%)" if progress is not None else ""), end="", flush=True) 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 # 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) ok = icsneopy.Bootloader.update(device, fw, logger, force_flash=True)
+5 -39
View File
@@ -206,21 +206,10 @@ public:
public: public:
enum Enum { enum Enum {
/** /**
* Even if the firmware does not match the current firmware version, * Skip refreshing the device state. Instead, only open com
* the device will not be updated. * and start the heartbeat thread.
*
* Note: The device may still be flashed if the device has no firmware
*
* This has no effect if the DFU extension is not present
*/ */
SuppressAutoUpdate = 1 << 0, SkipRefreshDeviceState = 1 << 0,
/**
* Force reflash the device.
*
* This has no effect if the DFU extension is not present
*/
ForceReflash = 1 << 1
}; };
using EnumType = std::underlying_type<Enum>::type; using EnumType = std::underlying_type<Enum>::type;
@@ -231,31 +220,8 @@ public:
const Enum val; const Enum val;
}; };
enum class OpenDirective { bool open(OpenFlags flags = {});
Continue, APIEvent::Type refreshDeviceState();
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; });
virtual bool close(); virtual bool close();
virtual bool isOnline() const { return online; } virtual bool isOnline() const { return online; }
virtual bool isOpen() const { return com->isOpen(); } virtual bool isOpen() const { return com->isOpen(); }
@@ -15,20 +15,33 @@ namespace icsneo {
namespace Bootloader { 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 requiresUpdate(icsneo::Device& device, const FWRepo& fw);
bool update( bool update(
icsneo::Device& device, icsneo::Device& device,
const FWRepo& fw, 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 alreadyInBootloader = false,
bool forceFlash = false bool forceFlash = false
); );
bool enterBootloader(icsneo::Device& device); bool enterBootloader(icsneo::Device& device);
bool exitBootloader(icsneo::Device& device, Logger logger, bool updatedChips); bool exitBootloader(icsneo::Device& device, StatusHandler statusHandler, bool updatedChips);
bool verifyConnection(icsneo::Device& device, Logger logger); bool verifyConnection(icsneo::Device& device, StatusHandler statusHandler);
bool isSFPChip(const icsneo::Bootloader::Chip& chip); bool isSFPChip(const icsneo::Bootloader::Chip& chip);
bool isSFPIEF(const icsneo::Bootloader::IEF& ief); bool isSFPIEF(const icsneo::Bootloader::IEF& ief);
@@ -31,7 +31,7 @@ public:
return true; return true;
} }
bool finalize() override; 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 { bool open() override {
return true; return true;
@@ -42,8 +42,8 @@ public:
} }
bool authenticate(); bool authenticate();
bool sendSoftware(const std::vector<uint8_t>& bin, 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 icsneo::Device::OpenStatusHandler& handler); bool sendSoftware(const std::vector<IEF::Sector>& sectors, uint32_t blockSize, const StatusHandler& handler);
bool validateFirmware(const DeviceAppVersion& chipSrcVer); bool validateFirmware(const DeviceAppVersion& chipSrcVer);
bool validateComponent(); bool validateComponent();
@@ -74,12 +74,12 @@ private:
const bool doAuthChecks; const bool doAuthChecks;
const bool encrypted; const bool encrypted;
using StatusHandler = std::function<void(double progress)>; using CommandStatusHandler = std::function<void(double progress)>;
bool sendCommand(Update command, const StatusHandler& handler, uint32_t offset = 0, 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)) { 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); 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 = {}); 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/extensions/bootloader/chip.h"
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/extensions/bootloader/api.h"
#include <cstdint> #include <cstdint>
@@ -29,7 +30,7 @@ public:
virtual bool enterApplication() = 0; virtual bool enterApplication() = 0;
virtual bool hasFinalizationStep() const = 0; virtual bool hasFinalizationStep() const = 0;
virtual bool finalize() = 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 open() = 0;
virtual bool close() = 0; virtual bool close() = 0;
@@ -69,7 +69,7 @@ protected:
Response& sendRequest(const Request& request, std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)); Response& sendRequest(const Request& request, std::chrono::milliseconds timeout = std::chrono::milliseconds(2000));
bool sendRequestNoResponse(); 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 Response lastResponse; // Last response received from sendRequest
bool supportsZynqBinaryFlasher = false; // Dictates how messages are formatted, this gets set in initialize() bool supportsZynqBinaryFlasher = false; // Dictates how messages are formatted, this gets set in initialize()
@@ -92,7 +92,7 @@ public:
bool enterApplication() override; bool enterApplication() override;
bool finalize() 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 open() override;
bool close() override; bool close() override;
@@ -22,7 +22,7 @@ private:
public: public:
RADMultiChipCommunication(icsneo::Device& dev, const ChipInfo& chipToFlash, bool auth, uint8_t slot = UINT8_MAX); 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 open() override;
bool close() override; bool close() override;
bool enterApplication() override; bool enterApplication() override;
@@ -79,7 +79,7 @@ public:
RADPeriphCommunication(icsneo::Device& dev, const ChipInfo& chipToFlash); RADPeriphCommunication(icsneo::Device& dev, const ChipInfo& chipToFlash);
~RADPeriphCommunication(); ~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 open() override;
bool close() override; bool close() override;
bool enterApplication() override; bool enterApplication() override;
@@ -23,7 +23,7 @@ class REDCommunication : public REDCommunicationBase {
public: public:
REDCommunication(icsneo::Device& dev, const ChipInfo& chip, bool auth, bool encryptWithDeviceKey = true); REDCommunication(icsneo::Device& dev, const ChipInfo& chip, bool auth, bool encryptWithDeviceKey = true);
bool enterApplication() override { return sendCommand(uint8_t(Command::EnterApplication)); } 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; bool open() override;
private: private:
@@ -27,7 +27,7 @@ public:
using REDCommunicationBase::REDCommunicationBase; using REDCommunicationBase::REDCommunicationBase;
bool enterApplication() override { return false; } 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: private:
/** /**
* Core flasher commands are tunneled through a RED request using CoreFlasherCommand, * Core flasher commands are tunneled through a RED request using CoreFlasherCommand,
@@ -16,12 +16,6 @@ public:
virtual ~DeviceExtension() = default; virtual ~DeviceExtension() = default;
virtual const char* getName() const = 0; 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 onGoOnline() {}
virtual void onGoOffline() {} virtual void onGoOffline() {}
virtual void onDeviceClose() {} virtual void onDeviceClose() {}