eive-obsw/bsp_q7s/devices/PlocUpdater.cpp

394 lines
12 KiB
C++
Raw Normal View History

2021-08-09 16:30:59 +02:00
#include "PlocUpdater.h"
#include <filesystem>
2022-01-18 11:41:19 +01:00
#include <fstream>
2021-08-09 16:30:59 +02:00
#include <string>
2022-01-18 11:41:19 +01:00
#include "fsfw/ipc/QueueFactory.h"
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
PlocUpdater::PlocUpdater(object_id_t objectId)
: SystemObject(objectId), commandActionHelper(this), actionHelper(this, nullptr) {
commandQueue = QueueFactory::instance()->createMessageQueue(QUEUE_SIZE);
2021-08-09 16:30:59 +02:00
}
2022-01-18 11:41:19 +01:00
PlocUpdater::~PlocUpdater() {}
2021-08-09 16:30:59 +02:00
ReturnValue_t PlocUpdater::initialize() {
#if BOARD_TE0720 == 0
2022-01-18 11:41:19 +01:00
sdcMan = SdCardManager::instance();
#endif
2022-01-18 11:41:19 +01:00
ReturnValue_t result = SystemObject::initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = commandActionHelper.initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = actionHelper.initialize(commandQueue);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
2021-08-09 16:30:59 +02:00
}
ReturnValue_t PlocUpdater::performOperation(uint8_t operationCode) {
2022-01-18 11:41:19 +01:00
readCommandQueue();
doStateMachine();
return HasReturnvaluesIF::RETURN_OK;
2021-08-09 16:30:59 +02:00
}
2022-01-18 11:41:19 +01:00
ReturnValue_t PlocUpdater::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
ReturnValue_t result = RETURN_FAILED;
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
if (state != State::IDLE) {
return IS_BUSY;
}
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
if (size > MAX_PLOC_UPDATE_PATH) {
return NAME_TOO_LONG;
}
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
switch (actionId) {
2021-08-20 06:56:29 +02:00
case UPDATE_A_UBOOT:
2022-01-18 11:41:19 +01:00
image = Image::A;
partition = Partition::UBOOT;
break;
2021-08-20 06:56:29 +02:00
case UPDATE_A_BITSTREAM:
2022-01-18 11:41:19 +01:00
image = Image::A;
partition = Partition::BITSTREAM;
break;
2021-08-20 06:56:29 +02:00
case UPDATE_A_LINUX:
2022-01-18 11:41:19 +01:00
image = Image::A;
partition = Partition::LINUX_OS;
break;
2021-08-20 06:56:29 +02:00
case UPDATE_A_APP_SW:
2022-01-18 11:41:19 +01:00
image = Image::A;
partition = Partition::APP_SW;
break;
2021-08-20 06:56:29 +02:00
case UPDATE_B_UBOOT:
2022-01-18 11:41:19 +01:00
image = Image::B;
partition = Partition::UBOOT;
break;
2021-08-20 06:56:29 +02:00
case UPDATE_B_BITSTREAM:
2022-01-18 11:41:19 +01:00
image = Image::B;
partition = Partition::BITSTREAM;
break;
2021-08-20 06:56:29 +02:00
case UPDATE_B_LINUX:
2022-01-18 11:41:19 +01:00
image = Image::B;
partition = Partition::LINUX_OS;
break;
2021-08-20 06:56:29 +02:00
case UPDATE_B_APP_SW:
2022-01-18 11:41:19 +01:00
image = Image::B;
partition = Partition::APP_SW;
break;
2021-08-09 16:30:59 +02:00
default:
2022-01-18 11:41:19 +01:00
return INVALID_ACTION_ID;
}
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
result = getImageLocation(data, size);
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
if (result != RETURN_OK) {
return result;
}
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
state = State::UPDATE_AVAILABLE;
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
return EXECUTION_FINISHED;
2021-08-09 16:30:59 +02:00
}
2022-01-18 11:41:19 +01:00
MessageQueueId_t PlocUpdater::getCommandQueue() const { return commandQueue->getId(); }
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
MessageQueueIF* PlocUpdater::getCommandQueuePtr() { return commandQueue; }
2021-08-09 16:30:59 +02:00
void PlocUpdater::readCommandQueue() {
2022-01-18 11:41:19 +01:00
CommandMessage message;
ReturnValue_t result;
for (result = commandQueue->receiveMessage(&message); result == HasReturnvaluesIF::RETURN_OK;
result = commandQueue->receiveMessage(&message)) {
if (result != RETURN_OK) {
continue;
}
result = actionHelper.handleActionMessage(&message);
if (result == HasReturnvaluesIF::RETURN_OK) {
continue;
2021-08-09 16:30:59 +02:00
}
2022-01-18 11:41:19 +01:00
result = commandActionHelper.handleReply(&message);
if (result == HasReturnvaluesIF::RETURN_OK) {
continue;
}
sif::debug << "PlocUpdater::readCommandQueue: Received message with invalid format"
<< std::endl;
}
2021-08-09 16:30:59 +02:00
}
void PlocUpdater::doStateMachine() {
2022-01-18 11:41:19 +01:00
switch (state) {
2021-08-09 16:30:59 +02:00
case State::IDLE:
2022-01-18 11:41:19 +01:00
break;
2021-08-09 16:30:59 +02:00
case State::UPDATE_AVAILABLE:
2022-01-18 11:41:19 +01:00
commandUpdateAvailable();
break;
2021-08-09 16:30:59 +02:00
case State::UPDATE_TRANSFER:
2022-01-18 11:41:19 +01:00
commandUpdatePacket();
break;
2021-08-09 16:30:59 +02:00
case State::UPDATE_VERIFY:
2022-01-18 11:41:19 +01:00
commandUpdateVerify();
break;
2021-08-09 16:30:59 +02:00
case State::COMMAND_EXECUTING:
2022-01-18 11:41:19 +01:00
break;
2021-08-09 16:30:59 +02:00
default:
2022-01-18 11:41:19 +01:00
sif::debug << "PlocUpdater::doStateMachine: Invalid state" << std::endl;
break;
}
2021-08-09 16:30:59 +02:00
}
ReturnValue_t PlocUpdater::checkNameLength(size_t size) {
2022-01-18 11:41:19 +01:00
if (size > MAX_PLOC_UPDATE_PATH) {
return NAME_TOO_LONG;
}
return RETURN_OK;
2021-08-09 16:30:59 +02:00
}
ReturnValue_t PlocUpdater::getImageLocation(const uint8_t* data, size_t size) {
2022-01-18 11:41:19 +01:00
ReturnValue_t result = checkNameLength(size);
if (result != RETURN_OK) {
return result;
}
2021-08-09 16:30:59 +02:00
#if BOARD_TE0720 == 0
2022-01-18 11:41:19 +01:00
// Check if file is stored on SD card and if associated SD card is mounted
if (std::string(reinterpret_cast<const char*>(data), SD_PREFIX_LENGTH) ==
std::string(SdCardManager::SD_0_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
sif::warning << "PlocUpdater::getImageLocation: SD card 0 not mounted" << std::endl;
return SD_NOT_MOUNTED;
}
} else if (std::string(reinterpret_cast<const char*>(data), SD_PREFIX_LENGTH) ==
std::string(SdCardManager::SD_1_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
sif::warning << "PlocUpdater::getImageLocation: SD card 1 not mounted" << std::endl;
return SD_NOT_MOUNTED;
}
} else {
// update image not stored on SD card
}
#endif /* BOARD_TE0720 == 0 */
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
updateFile = std::string(reinterpret_cast<const char*>(data), size);
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
// Check if file exists
if (not std::filesystem::exists(updateFile)) {
return FILE_NOT_EXISTS;
}
return RETURN_OK;
2021-08-09 16:30:59 +02:00
}
2022-01-18 11:41:19 +01:00
void PlocUpdater::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {}
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
void PlocUpdater::stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) {}
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
void PlocUpdater::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) {}
2021-08-09 16:30:59 +02:00
void PlocUpdater::completionSuccessfulReceived(ActionId_t actionId) {
2022-01-18 11:41:19 +01:00
switch (pendingCommand) {
2021-08-09 16:30:59 +02:00
case (PLOC_SPV::UPDATE_AVAILABLE):
2022-01-18 11:41:19 +01:00
state = State::UPDATE_TRANSFER;
break;
2021-08-09 16:30:59 +02:00
case (PLOC_SPV::UPDATE_IMAGE_DATA):
2022-01-18 11:41:19 +01:00
if (remainingPackets == 0) {
packetsSent = 0; // Reset packets sent variable for next update sequence
state = State::UPDATE_VERIFY;
} else {
state = State::UPDATE_TRANSFER;
}
break;
2021-08-09 16:30:59 +02:00
case (PLOC_SPV::UPDATE_VERIFY):
2022-01-18 11:41:19 +01:00
triggerEvent(UPDATE_FINISHED);
state = State::IDLE;
pendingCommand = PLOC_SPV::NONE;
break;
2021-08-09 16:30:59 +02:00
default:
2022-01-18 11:41:19 +01:00
sif::debug << "PlocUpdater::completionSuccessfulReceived: Invalid pending command"
<< std::endl;
state = State::IDLE;
break;
}
2021-08-09 16:30:59 +02:00
}
2022-01-18 11:41:19 +01:00
void PlocUpdater::completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) {
switch (pendingCommand) {
case (PLOC_SPV::UPDATE_AVAILABLE): {
triggerEvent(UPDATE_AVAILABLE_FAILED);
break;
2021-08-09 16:30:59 +02:00
}
2022-01-18 11:41:19 +01:00
case (PLOC_SPV::UPDATE_IMAGE_DATA): {
triggerEvent(UPDATE_TRANSFER_FAILED, packetsSent);
break;
2021-08-09 16:30:59 +02:00
}
2022-01-18 11:41:19 +01:00
case (PLOC_SPV::UPDATE_VERIFY): {
triggerEvent(UPDATE_VERIFY_FAILED);
break;
2021-08-09 16:30:59 +02:00
}
default:
2022-01-18 11:41:19 +01:00
sif::debug << "PlocUpdater::completionFailedReceived: Invalid pending command " << std::endl;
break;
}
state = State::IDLE;
2021-08-09 16:30:59 +02:00
}
void PlocUpdater::commandUpdateAvailable() {
2022-01-18 11:41:19 +01:00
ReturnValue_t result = RETURN_OK;
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
if (not std::filesystem::exists(updateFile)) {
triggerEvent(UPDATE_FILE_NOT_EXISTS, static_cast<uint8_t>(state));
state = State::IDLE;
2021-08-09 16:30:59 +02:00
return;
2022-01-18 11:41:19 +01:00
}
std::ifstream file(updateFile, std::ifstream::binary);
file.seekg(0, file.end);
imageSize = static_cast<size_t>(file.tellg());
file.close();
numOfUpdatePackets = imageSize / MAX_SP_DATA;
if (imageSize % MAX_SP_DATA) {
numOfUpdatePackets++;
}
remainingPackets = numOfUpdatePackets;
packetsSent = 0;
calcImageCrc();
PLOC_SPV::UpdateInfo packet(PLOC_SPV::APID_UPDATE_AVAILABLE, static_cast<uint8_t>(image),
static_cast<uint8_t>(partition), imageSize, imageCrc,
numOfUpdatePackets);
result = commandActionHelper.commandAction(objects::PLOC_SUPERVISOR_HANDLER,
PLOC_SPV::UPDATE_AVAILABLE, packet.getWholeData(),
packet.getFullSize());
if (result != RETURN_OK) {
sif::warning << "PlocUpdater::commandUpdateAvailable: Failed to send update available"
<< " packet to supervisor handler" << std::endl;
triggerEvent(ACTION_COMMANDING_FAILED, result, PLOC_SPV::UPDATE_AVAILABLE);
state = State::IDLE;
pendingCommand = PLOC_SPV::NONE;
return;
}
pendingCommand = PLOC_SPV::UPDATE_AVAILABLE;
state = State::COMMAND_EXECUTING;
return;
2021-08-09 16:30:59 +02:00
}
void PlocUpdater::commandUpdatePacket() {
2022-01-18 11:41:19 +01:00
ReturnValue_t result = RETURN_OK;
uint16_t payloadLength = 0;
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
if (not std::filesystem::exists(updateFile)) {
triggerEvent(UPDATE_FILE_NOT_EXISTS, static_cast<uint8_t>(state), packetsSent);
state = State::IDLE;
return;
}
std::ifstream file(updateFile, std::ifstream::binary);
file.seekg(packetsSent * MAX_SP_DATA, file.beg);
if (remainingPackets == 1) {
payloadLength = imageSize - static_cast<uint16_t>(file.tellg());
} else {
payloadLength = MAX_SP_DATA;
}
PLOC_SPV::UpdatePacket packet(payloadLength);
file.read(reinterpret_cast<char*>(packet.getDataFieldPointer()), payloadLength);
file.close();
// sequence count of first packet is 1
packet.setPacketSequenceCount((packetsSent + 1) & PLOC_SPV::SEQUENCE_COUNT_MASK);
if (numOfUpdatePackets > 1) {
adjustSequenceFlags(packet);
}
packet.makeCrc();
result = commandActionHelper.commandAction(objects::PLOC_SUPERVISOR_HANDLER,
PLOC_SPV::UPDATE_IMAGE_DATA, packet.getWholeData(),
packet.getFullSize());
if (result != RETURN_OK) {
sif::warning << "PlocUpdater::commandUpdateAvailable: Failed to send update"
<< " packet to supervisor handler" << std::endl;
triggerEvent(ACTION_COMMANDING_FAILED, result, PLOC_SPV::UPDATE_IMAGE_DATA);
state = State::IDLE;
pendingCommand = PLOC_SPV::NONE;
return;
}
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
remainingPackets--;
packetsSent++;
2021-08-09 16:30:59 +02:00
2022-01-18 11:41:19 +01:00
pendingCommand = PLOC_SPV::UPDATE_IMAGE_DATA;
state = State::COMMAND_EXECUTING;
2021-08-09 16:30:59 +02:00
}
void PlocUpdater::commandUpdateVerify() {
2022-01-18 11:41:19 +01:00
ReturnValue_t result = RETURN_OK;
PLOC_SPV::UpdateInfo packet(PLOC_SPV::APID_UPDATE_VERIFY, static_cast<uint8_t>(image),
static_cast<uint8_t>(partition), imageSize, imageCrc,
numOfUpdatePackets);
result =
commandActionHelper.commandAction(objects::PLOC_SUPERVISOR_HANDLER, PLOC_SPV::UPDATE_VERIFY,
packet.getWholeData(), packet.getFullSize());
if (result != RETURN_OK) {
sif::warning << "PlocUpdater::commandUpdateAvailable: Failed to send update available"
<< " packet to supervisor handler" << std::endl;
triggerEvent(ACTION_COMMANDING_FAILED, result, PLOC_SPV::UPDATE_VERIFY);
state = State::IDLE;
pendingCommand = PLOC_SPV::NONE;
2021-08-09 16:30:59 +02:00
return;
2022-01-18 11:41:19 +01:00
}
state = State::COMMAND_EXECUTING;
pendingCommand = PLOC_SPV::UPDATE_VERIFY;
return;
2021-08-09 16:30:59 +02:00
}
2021-08-18 08:26:31 +02:00
void PlocUpdater::calcImageCrc() {
2022-01-18 11:41:19 +01:00
std::ifstream file(updateFile, std::ifstream::binary);
file.seekg(0, file.end);
uint32_t count;
uint32_t bit;
uint32_t remainder = INITIAL_REMAINDER_32;
char input;
for (count = 0; count < imageSize; count++) {
file.seekg(count, file.beg);
file.read(&input, 1);
remainder ^= (input << 16);
for (bit = 8; bit > 0; --bit) {
if (remainder & TOPBIT_32) {
remainder = (remainder << 1) ^ POLYNOMIAL_32;
} else {
remainder = (remainder << 1);
}
}
}
file.close();
imageCrc = (remainder ^ FINAL_XOR_VALUE_32);
2021-08-09 16:30:59 +02:00
}
void PlocUpdater::adjustSequenceFlags(PLOC_SPV::UpdatePacket& packet) {
2022-01-18 11:41:19 +01:00
if (packetsSent == 0) {
packet.setSequenceFlags(static_cast<uint8_t>(PLOC_SPV::SequenceFlags::FIRST_PKT));
} else if (remainingPackets == 1) {
packet.setSequenceFlags(static_cast<uint8_t>(PLOC_SPV::SequenceFlags::LAST_PKT));
} else {
packet.setSequenceFlags(static_cast<uint8_t>(PLOC_SPV::SequenceFlags::CONTINUED_PKT));
}
2021-08-09 16:30:59 +02:00
}