mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-11-04 21:09:06 +01:00
Compare commits
3
Commits
dffb0bcefb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f747df692 | ||
|
|
ee6b846acc | ||
|
|
645549193d |
@@ -431,6 +431,30 @@ icsneoc2_error_t icsneoc2_message_lin_props_set(icsneoc2_message_t* message,
|
|||||||
return icsneoc2_error_success;
|
return icsneoc2_error_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icsneoc2_error_t icsneoc2_message_lin_wakeup_width_get(const icsneoc2_message_t* message, uint16_t* width_us) {
|
||||||
|
if(!message || !width_us) {
|
||||||
|
return icsneoc2_error_invalid_parameters;
|
||||||
|
}
|
||||||
|
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
|
||||||
|
if(!lin_msg) {
|
||||||
|
return icsneoc2_error_invalid_type;
|
||||||
|
}
|
||||||
|
*width_us = lin_msg->wakeupPulseWidthUs;
|
||||||
|
return icsneoc2_error_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
icsneoc2_error_t icsneoc2_message_lin_wakeup_width_set(icsneoc2_message_t* message, uint16_t width_us) {
|
||||||
|
if(!message) {
|
||||||
|
return icsneoc2_error_invalid_parameters;
|
||||||
|
}
|
||||||
|
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
|
||||||
|
if(!lin_msg) {
|
||||||
|
return icsneoc2_error_invalid_type;
|
||||||
|
}
|
||||||
|
lin_msg->wakeupPulseWidthUs = width_us;
|
||||||
|
return icsneoc2_error_success;
|
||||||
|
}
|
||||||
|
|
||||||
icsneoc2_error_t icsneoc2_message_lin_err_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_err_flags_t* err_flags) {
|
icsneoc2_error_t icsneoc2_message_lin_err_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_err_flags_t* err_flags) {
|
||||||
if(!message || !err_flags) {
|
if(!message || !err_flags) {
|
||||||
return icsneoc2_error_invalid_parameters;
|
return icsneoc2_error_invalid_parameters;
|
||||||
|
|||||||
@@ -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>());
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ void init_linmessage(pybind11::module_& m) {
|
|||||||
.def_readwrite("checksum", &LINMessage::checksum)
|
.def_readwrite("checksum", &LINMessage::checksum)
|
||||||
.def_readwrite("linMsgType", &LINMessage::linMsgType)
|
.def_readwrite("linMsgType", &LINMessage::linMsgType)
|
||||||
.def_readwrite("isEnhancedChecksum", &LINMessage::isEnhancedChecksum)
|
.def_readwrite("isEnhancedChecksum", &LINMessage::isEnhancedChecksum)
|
||||||
|
.def_readwrite("wakeupPulseWidthUs", &LINMessage::wakeupPulseWidthUs)
|
||||||
.def_readwrite("errFlags", &LINMessage::errFlags)
|
.def_readwrite("errFlags", &LINMessage::errFlags)
|
||||||
.def_readwrite("statusFlags", &LINMessage::statusFlags);
|
.def_readwrite("statusFlags", &LINMessage::statusFlags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>())
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -27,4 +27,11 @@ uint8_t LINMessage::calcProtectedID(uint8_t& id) {
|
|||||||
return protID;
|
return protID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LINMessage::wakeupPulseWidthSteps(const LINMessage& message) {
|
||||||
|
const uint16_t widthUs = message.wakeupPulseWidthUs;
|
||||||
|
if(widthUs < 250 || widthUs > 5000)
|
||||||
|
return 0;
|
||||||
|
return (widthUs + 25) / 50;
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace icsneo
|
} //namespace icsneo
|
||||||
@@ -140,6 +140,10 @@ static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> frame, c
|
|||||||
linpacket->CoreMiniBitsLIN.TXCommander = 1;
|
linpacket->CoreMiniBitsLIN.TXCommander = 1;
|
||||||
linpacket->CoreMiniBitsLIN.BreakOnly = 1;
|
linpacket->CoreMiniBitsLIN.BreakOnly = 1;
|
||||||
break;
|
break;
|
||||||
|
case LINMessage::Type::LIN_WAKEUP_REQUEST:
|
||||||
|
linpacket->CoreMiniBitsLIN.TXCommander = 1;
|
||||||
|
linpacket->CoreMiniBitsLIN.WakeupRequest = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -165,6 +169,18 @@ static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> frame, c
|
|||||||
linpacket->CoreMiniBitsLIN.len = 0;
|
linpacket->CoreMiniBitsLIN.len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(linmsg->linMsgType == LINMessage::Type::LIN_WAKEUP_REQUEST) {
|
||||||
|
const int steps = LINMessage::wakeupPulseWidthSteps(*linmsg);
|
||||||
|
if(!steps) {
|
||||||
|
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// data[0] is the pulse width in 50 us steps
|
||||||
|
// data[1] to data[7]: future bits reserved for more LIN wake features
|
||||||
|
linpacket->CoreMiniBitsLIN.len = 1;
|
||||||
|
linpacket->data[0] = static_cast<uint8_t>(steps);
|
||||||
|
}
|
||||||
|
|
||||||
// Description/stats and network
|
// Description/stats and network
|
||||||
linpacket->stats = linmsg->description;
|
linpacket->stats = linmsg->description;
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,16 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
|
|||||||
size |= 0x80u | 0x20u;
|
size |= 0x80u | 0x20u;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LINMessage::Type::LIN_WAKEUP_REQUEST:
|
||||||
|
{
|
||||||
|
if(!LINMessage::wakeupPulseWidthSteps(message)) {
|
||||||
|
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// wakeup pulse only, one data byte for the pulse width
|
||||||
|
size = 0x04u | 0x80u | 0x10u;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LINMessage::Type::NOT_SET:
|
case LINMessage::Type::NOT_SET:
|
||||||
{
|
{
|
||||||
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||||
@@ -145,6 +155,13 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
|
|||||||
bytestream.push_back(message.checksum);
|
bytestream.push_back(message.checksum);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case(LINMessage::Type::LIN_WAKEUP_REQUEST):
|
||||||
|
{
|
||||||
|
// data byte 0 is the pulse width in 50 us steps
|
||||||
|
// data bytes 1 to 7: future bits reserved for more LIN wake features
|
||||||
|
bytestream.push_back(static_cast<uint8_t>(LINMessage::wakeupPulseWidthSteps(message)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-32
@@ -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();
|
||||||
|
|
||||||
|
if((flags & OpenFlags::SkipRefreshDeviceState) == 0) {
|
||||||
|
auto refreshErr = refreshDeviceState();
|
||||||
|
if(refreshErr != APIEvent::Type::NoErrorFound) {
|
||||||
|
com->close();
|
||||||
|
stopHeartbeat();
|
||||||
|
report(refreshErr, APIEvent::Severity::Error);
|
||||||
|
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();
|
APIEvent::Type attemptErr = attemptToBeginCommunication();
|
||||||
if(attemptErr != APIEvent::Type::NoErrorFound) {
|
if(attemptErr != APIEvent::Type::NoErrorFound) {
|
||||||
// We could not communicate with the device, let's see if an extension can
|
return attemptErr;
|
||||||
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();
|
|
||||||
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);
|
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -47,11 +47,14 @@ public:
|
|||||||
LIN_SYNC_ONLY = icsneoc2_lin_msg_type_sync_only,
|
LIN_SYNC_ONLY = icsneoc2_lin_msg_type_sync_only,
|
||||||
LIN_UPDATE_RESPONDER = icsneoc2_lin_msg_type_update_responder,
|
LIN_UPDATE_RESPONDER = icsneoc2_lin_msg_type_update_responder,
|
||||||
LIN_ERROR = icsneoc2_lin_msg_type_error,
|
LIN_ERROR = icsneoc2_lin_msg_type_error,
|
||||||
|
// needs firmware with LIN wakeup transmit; older firmware sends a commander header (break, sync, ID) instead
|
||||||
LIN_WAKEUP_REQUEST = icsneoc2_lin_msg_type_wakeup_request
|
LIN_WAKEUP_REQUEST = icsneoc2_lin_msg_type_wakeup_request
|
||||||
};
|
};
|
||||||
|
|
||||||
static void calcChecksum(LINMessage& message);
|
static void calcChecksum(LINMessage& message);
|
||||||
uint8_t calcProtectedID(uint8_t& id);
|
uint8_t calcProtectedID(uint8_t& id);
|
||||||
|
// wakeupPulseWidthUs in 50 us steps, 0 if it is outside 250 to 5000 us
|
||||||
|
static int wakeupPulseWidthSteps(const LINMessage& message);
|
||||||
|
|
||||||
LINMessage() {};
|
LINMessage() {};
|
||||||
LINMessage(uint8_t id) : ID(id & 0x3Fu), protectedID(calcProtectedID(ID)) {};
|
LINMessage(uint8_t id) : ID(id & 0x3Fu), protectedID(calcProtectedID(ID)) {};
|
||||||
@@ -61,6 +64,9 @@ public:
|
|||||||
uint8_t checksum = 0;
|
uint8_t checksum = 0;
|
||||||
LINMessage::Type linMsgType = Type::NOT_SET;
|
LINMessage::Type linMsgType = Type::NOT_SET;
|
||||||
bool isEnhancedChecksum = false;
|
bool isEnhancedChecksum = false;
|
||||||
|
// LIN_WAKEUP_REQUEST only, the same as the Vehicle Spy LIN Send Wake Width property: 250 to 5000 us,
|
||||||
|
// rounded to the nearest 50 us. Outside that range the transmit fails.
|
||||||
|
uint16_t wakeupPulseWidthUs = 300;
|
||||||
LINErrorFlags errFlags;
|
LINErrorFlags errFlags;
|
||||||
LINStatusFlags statusFlags;
|
LINStatusFlags statusFlags;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
+1
-1
@@ -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() {}
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ typedef enum _icsneoc2_lin_msg_type_t {
|
|||||||
icsneoc2_lin_msg_type_sync_only = 4,
|
icsneoc2_lin_msg_type_sync_only = 4,
|
||||||
icsneoc2_lin_msg_type_update_responder = 5,
|
icsneoc2_lin_msg_type_update_responder = 5,
|
||||||
icsneoc2_lin_msg_type_error = 6,
|
icsneoc2_lin_msg_type_error = 6,
|
||||||
|
// needs firmware with LIN wakeup transmit; older firmware sends a commander header (break, sync, ID) instead
|
||||||
icsneoc2_lin_msg_type_wakeup_request = 7,
|
icsneoc2_lin_msg_type_wakeup_request = 7,
|
||||||
} _icsneoc2_lin_msg_type_t;
|
} _icsneoc2_lin_msg_type_t;
|
||||||
|
|
||||||
@@ -461,6 +462,29 @@ icsneoc2_error_t icsneoc2_message_lin_props_set(icsneoc2_message_t* message,
|
|||||||
const uint8_t* id, const uint8_t* checksum,
|
const uint8_t* id, const uint8_t* checksum,
|
||||||
const icsneoc2_lin_msg_type_t* msg_type, const bool* is_enhanced_checksum);
|
const icsneoc2_lin_msg_type_t* msg_type, const bool* is_enhanced_checksum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the wakeup pulse width of a LIN message.
|
||||||
|
*
|
||||||
|
* @param[in] message The message to query (must be a LIN message).
|
||||||
|
* @param[out] width_us Pointer to receive the pulse width in microseconds. The default is 300 us.
|
||||||
|
*
|
||||||
|
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if not a LIN message.
|
||||||
|
*/
|
||||||
|
icsneoc2_error_t icsneoc2_message_lin_wakeup_width_get(const icsneoc2_message_t* message, uint16_t* width_us);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the wakeup pulse width of a LIN message. Only used by icsneoc2_lin_msg_type_wakeup_request.
|
||||||
|
*
|
||||||
|
* The same as the Vehicle Spy LIN Send Wake Width property: 250 to 5000 us, rounded to the nearest 50 us.
|
||||||
|
* Outside that range the transmit fails.
|
||||||
|
*
|
||||||
|
* @param[in] message The message to modify (must be a LIN message).
|
||||||
|
* @param[in] width_us The pulse width in microseconds.
|
||||||
|
*
|
||||||
|
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if not a LIN message.
|
||||||
|
*/
|
||||||
|
icsneoc2_error_t icsneoc2_message_lin_wakeup_width_set(icsneoc2_message_t* message, uint16_t width_us);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the LIN error flags of a message.
|
* Get the LIN error flags of a message.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -208,6 +208,8 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
|
|||||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_create(NULL, 0));
|
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_create(NULL, 0));
|
||||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_props_get(NULL, NULL, NULL, NULL, NULL, NULL));
|
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_props_get(NULL, NULL, NULL, NULL, NULL, NULL));
|
||||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_props_set(NULL, NULL, NULL, NULL, NULL));
|
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_props_set(NULL, NULL, NULL, NULL, NULL));
|
||||||
|
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_wakeup_width_get(NULL, NULL));
|
||||||
|
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_wakeup_width_set(NULL, 0));
|
||||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_err_flags_get(NULL, NULL));
|
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_err_flags_get(NULL, NULL));
|
||||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_status_flags_get(NULL, NULL));
|
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_status_flags_get(NULL, NULL));
|
||||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_calc_checksum(NULL));
|
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_calc_checksum(NULL));
|
||||||
@@ -1768,6 +1770,28 @@ TEST(icsneoc2, test_lin_message_props_set)
|
|||||||
icsneoc2_message_free(msg);
|
icsneoc2_message_free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(icsneoc2, test_lin_message_wakeup_width)
|
||||||
|
{
|
||||||
|
icsneoc2_message_t* msg = nullptr;
|
||||||
|
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_create(&msg, 0x00));
|
||||||
|
|
||||||
|
uint16_t width_us = 0;
|
||||||
|
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_wakeup_width_get(msg, &width_us));
|
||||||
|
ASSERT_EQ(width_us, 300);
|
||||||
|
|
||||||
|
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_wakeup_width_set(msg, 2500));
|
||||||
|
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_wakeup_width_get(msg, &width_us));
|
||||||
|
ASSERT_EQ(width_us, 2500);
|
||||||
|
|
||||||
|
icsneoc2_message_t* can_msg = nullptr;
|
||||||
|
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_create(&can_msg));
|
||||||
|
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_lin_wakeup_width_set(can_msg, 300));
|
||||||
|
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_lin_wakeup_width_get(can_msg, &width_us));
|
||||||
|
icsneoc2_message_free(can_msg);
|
||||||
|
|
||||||
|
icsneoc2_message_free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(icsneoc2, test_lin_message_data_and_netid)
|
TEST(icsneoc2, test_lin_message_data_and_netid)
|
||||||
{
|
{
|
||||||
icsneoc2_message_t* msg = nullptr;
|
icsneoc2_message_t* msg = nullptr;
|
||||||
|
|||||||
@@ -67,6 +67,24 @@ protected:
|
|||||||
0x00, 0x00,
|
0x00, 0x00,
|
||||||
0x80, 0x41};
|
0x80, 0x41};
|
||||||
|
|
||||||
|
// Wakeup LIN 1: commander (0x80) | wakeup (0x10) | len 3 => 0x93, description 0x1234
|
||||||
|
std::vector<uint8_t> testControllerWakeup =
|
||||||
|
{0xaa, 0x0c,
|
||||||
|
0x0d, 0x00,
|
||||||
|
0x10, 0x00,
|
||||||
|
0x00, 0x94,
|
||||||
|
0x12, 0x34,
|
||||||
|
0x80, 0x06};
|
||||||
|
|
||||||
|
// Wakeup LIN 1 with a 5000 us pulse: len 4 => 0x94, data byte 0 is 100 steps of 50 us
|
||||||
|
std::vector<uint8_t> testControllerWakeupWidth =
|
||||||
|
{0xaa, 0x0c,
|
||||||
|
0x0d, 0x00,
|
||||||
|
0x10, 0x00,
|
||||||
|
0x00, 0x94,
|
||||||
|
0x12, 0x34,
|
||||||
|
0x80, 0x64};
|
||||||
|
|
||||||
std::vector<uint8_t> recvBytes =
|
std::vector<uint8_t> recvBytes =
|
||||||
{0xaa, 0x0c, 0x22, 0x00,
|
{0xaa, 0x0c, 0x22, 0x00,
|
||||||
0x10, 0x00, 0x88, 0x03,
|
0x10, 0x00, 0x88, 0x03,
|
||||||
@@ -174,6 +192,97 @@ TEST_F(LINEncoderDecoderTest, TransmitMessageBreakOnlySetsCommander) {
|
|||||||
EXPECT_EQ(lin->CoreMiniBitsLIN.BreakOnly, 1);
|
EXPECT_EQ(lin->CoreMiniBitsLIN.BreakOnly, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerWakeupTest) {
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x00u));
|
||||||
|
message->network = icsneo::Network::NetID::LIN_01;
|
||||||
|
message->linMsgType = icsneo::LINMessage::Type::LIN_WAKEUP_REQUEST;
|
||||||
|
message->isEnhancedChecksum = false;
|
||||||
|
message->description = 0x1234;
|
||||||
|
message->data = {0x55}; // ignored, a wakeup never carries data
|
||||||
|
packetEncoder->encode(*packetizer, bytestream, message);
|
||||||
|
EXPECT_EQ(bytestream, testControllerWakeup);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, TransmitMessageWakeupSetsCommander) {
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x00u));
|
||||||
|
message->network = icsneo::Network::NetID::LIN_01;
|
||||||
|
message->linMsgType = icsneo::LINMessage::Type::LIN_WAKEUP_REQUEST;
|
||||||
|
message->description = 0x1234;
|
||||||
|
message->data = {0x55};
|
||||||
|
auto bytes = TransmitMessage::EncodeFromMessage(message, 1, report);
|
||||||
|
ASSERT_FALSE(bytes.empty());
|
||||||
|
ASSERT_GE(bytes.size(), sizeof(TransmitMessage));
|
||||||
|
auto* tx = reinterpret_cast<TransmitMessage*>(bytes.data());
|
||||||
|
auto* lin = reinterpret_cast<HardwareLINPacket*>(tx->commonHeader);
|
||||||
|
EXPECT_EQ(lin->CoreMiniBitsLIN.TXCommander, 1);
|
||||||
|
EXPECT_EQ(lin->CoreMiniBitsLIN.WakeupRequest, 1);
|
||||||
|
EXPECT_EQ(lin->CoreMiniBitsLIN.BreakOnly, 0);
|
||||||
|
EXPECT_EQ(lin->CoreMiniBitsLIN.len, 1);
|
||||||
|
EXPECT_EQ(lin->data[0], 6); // default 300 us
|
||||||
|
EXPECT_EQ(lin->stats, 0x1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerWakeupWidthTest) {
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x00u));
|
||||||
|
message->network = icsneo::Network::NetID::LIN_01;
|
||||||
|
message->linMsgType = icsneo::LINMessage::Type::LIN_WAKEUP_REQUEST;
|
||||||
|
message->description = 0x1234;
|
||||||
|
message->wakeupPulseWidthUs = 5000;
|
||||||
|
packetEncoder->encode(*packetizer, bytestream, message);
|
||||||
|
EXPECT_EQ(bytestream, testControllerWakeupWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, TransmitMessageWakeupWidth) {
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x00u));
|
||||||
|
message->network = icsneo::Network::NetID::LIN_01;
|
||||||
|
message->linMsgType = icsneo::LINMessage::Type::LIN_WAKEUP_REQUEST;
|
||||||
|
message->wakeupPulseWidthUs = 250;
|
||||||
|
auto bytes = TransmitMessage::EncodeFromMessage(message, 1, report);
|
||||||
|
ASSERT_GE(bytes.size(), sizeof(TransmitMessage));
|
||||||
|
auto* tx = reinterpret_cast<TransmitMessage*>(bytes.data());
|
||||||
|
auto* lin = reinterpret_cast<HardwareLINPacket*>(tx->commonHeader);
|
||||||
|
EXPECT_EQ(lin->CoreMiniBitsLIN.WakeupRequest, 1);
|
||||||
|
EXPECT_EQ(lin->CoreMiniBitsLIN.len, 1);
|
||||||
|
EXPECT_EQ(lin->data[0], 5);
|
||||||
|
EXPECT_EQ(lin->data[1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, WakeupWidthRounds) {
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x00u));
|
||||||
|
message->network = icsneo::Network::NetID::LIN_01;
|
||||||
|
message->linMsgType = icsneo::LINMessage::Type::LIN_WAKEUP_REQUEST;
|
||||||
|
const std::pair<uint16_t, uint8_t> widths[] = {
|
||||||
|
{250, 5}, {274, 5}, {275, 6}, {326, 7}, {4975, 100}, {5000, 100}};
|
||||||
|
for(const auto& [widthUs, steps] : widths) {
|
||||||
|
message->wakeupPulseWidthUs = widthUs;
|
||||||
|
auto bytes = TransmitMessage::EncodeFromMessage(message, 1, report);
|
||||||
|
ASSERT_GE(bytes.size(), sizeof(TransmitMessage));
|
||||||
|
auto* tx = reinterpret_cast<TransmitMessage*>(bytes.data());
|
||||||
|
auto* lin = reinterpret_cast<HardwareLINPacket*>(tx->commonHeader);
|
||||||
|
EXPECT_EQ(lin->data[0], steps) << widthUs << " us";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LINEncoderDecoderTest, WakeupWidthOutOfRangeIsRejected) {
|
||||||
|
int errors = 0;
|
||||||
|
report = [&errors](APIEvent::Type type, APIEvent::Severity) {
|
||||||
|
EXPECT_EQ(type, APIEvent::Type::ParameterOutOfRange);
|
||||||
|
++errors;
|
||||||
|
};
|
||||||
|
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x00u));
|
||||||
|
message->network = icsneo::Network::NetID::LIN_01;
|
||||||
|
message->linMsgType = icsneo::LINMessage::Type::LIN_WAKEUP_REQUEST;
|
||||||
|
for(uint16_t widthUs : {uint16_t(0), uint16_t(1), uint16_t(249), uint16_t(5001), uint16_t(60000)}) {
|
||||||
|
message->wakeupPulseWidthUs = widthUs;
|
||||||
|
std::vector<uint8_t> bytestream;
|
||||||
|
EXPECT_FALSE(packetEncoder->encode(*packetizer, bytestream, message));
|
||||||
|
EXPECT_TRUE(TransmitMessage::EncodeFromMessage(message, 1, report).empty());
|
||||||
|
}
|
||||||
|
EXPECT_EQ(errors, 10);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(LINEncoderDecoderTest, TransmitMessageCalculatesChecksum) {
|
TEST_F(LINEncoderDecoderTest, TransmitMessageCalculatesChecksum) {
|
||||||
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
|
||||||
message->network = icsneo::Network::NetID::LIN_02;
|
message->network = icsneo::Network::NetID::LIN_02;
|
||||||
|
|||||||
Reference in New Issue
Block a user