398 lines
12 KiB
C++
398 lines
12 KiB
C++
|
#include "fsfw/ipc/QueueFactory.h"
|
||
|
#include "PlocUpdater.h"
|
||
|
|
||
|
#include <fstream>
|
||
|
#include <filesystem>
|
||
|
#include <string>
|
||
|
|
||
|
PlocUpdater::PlocUpdater(object_id_t objectId) :
|
||
|
SystemObject(objectId), commandActionHelper(this), actionHelper(this, nullptr) {
|
||
|
commandQueue = QueueFactory::instance()->createMessageQueue(QUEUE_SIZE);
|
||
|
}
|
||
|
|
||
|
PlocUpdater::~PlocUpdater() {
|
||
|
}
|
||
|
|
||
|
ReturnValue_t PlocUpdater::initialize() {
|
||
|
sdcMan = SdCardManager::instance();
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
ReturnValue_t PlocUpdater::performOperation(uint8_t operationCode) {
|
||
|
readCommandQueue();
|
||
|
doStateMachine();
|
||
|
return HasReturnvaluesIF::RETURN_OK;
|
||
|
}
|
||
|
|
||
|
ReturnValue_t PlocUpdater::executeAction(ActionId_t actionId,
|
||
|
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) {
|
||
|
ReturnValue_t result = RETURN_FAILED;
|
||
|
|
||
|
if (state != State::IDLE) {
|
||
|
return IS_BUSY;
|
||
|
}
|
||
|
|
||
|
if (size > MAX_PLOC_UPDATE_PATH) {
|
||
|
return NAME_TOO_LONG;
|
||
|
}
|
||
|
|
||
|
switch (actionId) {
|
||
|
case UPDATE_NVM0_A:
|
||
|
updatePartition = Partition::A;
|
||
|
updateMemory = Memory::NVM0;
|
||
|
break;
|
||
|
case UPDATE_NVM0_B:
|
||
|
updatePartition = Partition::B;
|
||
|
updateMemory = Memory::NVM0;
|
||
|
break;
|
||
|
case UPDATE_NVM1_A:
|
||
|
updatePartition = Partition::A;
|
||
|
updateMemory = Memory::NVM1;
|
||
|
break;
|
||
|
case UPDATE_NVM1_B:
|
||
|
updatePartition = Partition::B;
|
||
|
updateMemory = Memory::NVM1;
|
||
|
break;
|
||
|
default:
|
||
|
return INVALID_ACTION_ID;
|
||
|
}
|
||
|
|
||
|
result = getImageLocation(data, size);
|
||
|
|
||
|
if (result != RETURN_OK) {
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
state = State::UPDATE_AVAILABLE;
|
||
|
|
||
|
return EXECUTION_FINISHED;
|
||
|
}
|
||
|
|
||
|
MessageQueueId_t PlocUpdater::getCommandQueue() const {
|
||
|
return commandQueue->getId();
|
||
|
}
|
||
|
|
||
|
MessageQueueIF* PlocUpdater::getCommandQueuePtr() {
|
||
|
return commandQueue;
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::readCommandQueue() {
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
result = commandActionHelper.handleReply(&message);
|
||
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
sif::debug << "PlocUpdater::readCommandQueue: Received message with invalid format"
|
||
|
<< std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::doStateMachine() {
|
||
|
switch (state) {
|
||
|
case State::IDLE:
|
||
|
break;
|
||
|
case State::UPDATE_AVAILABLE:
|
||
|
commandUpdateAvailable();
|
||
|
break;
|
||
|
case State::UPDATE_TRANSFER:
|
||
|
commandUpdatePacket();
|
||
|
break;
|
||
|
case State::UPDATE_VERIFY:
|
||
|
commandUpdateVerify();
|
||
|
break;
|
||
|
case State::COMMAND_EXECUTING:
|
||
|
break;
|
||
|
default:
|
||
|
sif::debug << "PlocUpdater::doStateMachine: Invalid state" << std::endl;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ReturnValue_t PlocUpdater::checkNameLength(size_t size) {
|
||
|
if (size > MAX_PLOC_UPDATE_PATH) {
|
||
|
return NAME_TOO_LONG;
|
||
|
}
|
||
|
return RETURN_OK;
|
||
|
}
|
||
|
|
||
|
ReturnValue_t PlocUpdater::getImageLocation(const uint8_t* data, size_t size) {
|
||
|
ReturnValue_t result = checkNameLength(size);
|
||
|
if (result != RETURN_OK) {
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// 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 (!isSdCardMounted(sd::SLOT_0)) {
|
||
|
sif::warning << "PlocUpdater::prepareNvm0AUpdate: 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 (!isSdCardMounted(sd::SLOT_0)) {
|
||
|
sif::warning << "PlocUpdater::prepareNvm0AUpdate: SD card 1 not mounted" << std::endl;
|
||
|
return SD_NOT_MOUNTED;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
//update image not stored on SD card
|
||
|
}
|
||
|
|
||
|
updateFile = std::string(reinterpret_cast<const char*>(data), size);
|
||
|
|
||
|
// Check if file exists
|
||
|
if(not std::filesystem::exists(updateFile)) {
|
||
|
return FILE_NOT_EXISTS;
|
||
|
}
|
||
|
return RETURN_OK;
|
||
|
}
|
||
|
|
||
|
bool PlocUpdater::isSdCardMounted(sd::SdCard sdCard) {
|
||
|
SdCardManager::SdStatePair active;
|
||
|
ReturnValue_t result = sdcMan->getSdCardActiveStatus(active);
|
||
|
if (result != RETURN_OK) {
|
||
|
sif::debug << "PlocUpdater::isSdCardMounted: Failed to get SD card active state";
|
||
|
return false;
|
||
|
}
|
||
|
if (sdCard == sd::SLOT_0) {
|
||
|
if (active.first == sd::MOUNTED) {
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
else if (sdCard == sd::SLOT_1) {
|
||
|
if (active.second == sd::MOUNTED) {
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
sif::debug << "PlocUpdater::isSdCardMounted: Unknown SD card specified" << std::endl;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::stepSuccessfulReceived(ActionId_t actionId,
|
||
|
uint8_t step) {
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::stepFailedReceived(ActionId_t actionId, uint8_t step,
|
||
|
ReturnValue_t returnCode) {
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) {
|
||
|
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::completionSuccessfulReceived(ActionId_t actionId) {
|
||
|
switch (pendingCommand) {
|
||
|
case (PLOC_SPV::UPDATE_AVAILABLE):
|
||
|
state = State::UPDATE_TRANSFER;
|
||
|
break;
|
||
|
case (PLOC_SPV::UPDATE_IMAGE_DATA):
|
||
|
if (remainingPackets == 0) {
|
||
|
packetsSent = 0; // Reset packets sent variable for next update sequence
|
||
|
state = State::UPDATE_VERIFY;
|
||
|
}
|
||
|
else {
|
||
|
state = State::UPDATE_TRANSFER;
|
||
|
}
|
||
|
break;
|
||
|
case (PLOC_SPV::UPDATE_VERIFY):
|
||
|
triggerEvent(UPDATE_FINISHED);
|
||
|
state = State::IDLE;
|
||
|
pendingCommand = PLOC_SPV::NONE;
|
||
|
break;
|
||
|
default:
|
||
|
sif::debug << "PlocUpdater::completionSuccessfulReceived: Invalid pending command"
|
||
|
<< std::endl;
|
||
|
state = State::IDLE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::completionFailedReceived(ActionId_t actionId,
|
||
|
ReturnValue_t returnCode) {
|
||
|
switch(pendingCommand) {
|
||
|
case(PLOC_SPV::UPDATE_AVAILABLE): {
|
||
|
triggerEvent(UPDATE_AVAILABLE_FAILED);
|
||
|
break;
|
||
|
}
|
||
|
case(PLOC_SPV::UPDATE_IMAGE_DATA): {
|
||
|
triggerEvent(UPDATE_TRANSFER_FAILED, packetsSent);
|
||
|
break;
|
||
|
}
|
||
|
case(PLOC_SPV::UPDATE_VERIFY): {
|
||
|
triggerEvent(UPDATE_VERIFY_FAILED);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
sif::debug << "PlocUpdater::completionFailedReceived: Invalid pending command "
|
||
|
<< std::endl;
|
||
|
break;
|
||
|
}
|
||
|
state = State::IDLE;
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::commandUpdateAvailable() {
|
||
|
ReturnValue_t result = RETURN_OK;
|
||
|
|
||
|
if (not std::filesystem::exists(updateFile)) {
|
||
|
triggerEvent(UPDATE_FILE_NOT_EXISTS, static_cast<uint8_t>(state));
|
||
|
state = State::IDLE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
|
||
|
uint32_t imageCrc = makeCrc();
|
||
|
|
||
|
PLOC_SPV::UpdateInfo packet(PLOC_SPV::APID_UPDATE_AVAILABLE, static_cast<uint8_t>(updateMemory),
|
||
|
static_cast<uint8_t>(updatePartition), 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;
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::commandUpdatePacket() {
|
||
|
ReturnValue_t result = RETURN_OK;
|
||
|
uint16_t payloadLength = 0;
|
||
|
|
||
|
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 > 0) {
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
remainingPackets--;
|
||
|
packetsSent++;
|
||
|
|
||
|
pendingCommand = PLOC_SPV::UPDATE_IMAGE_DATA;
|
||
|
state = State::COMMAND_EXECUTING;
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::commandUpdateVerify() {
|
||
|
ReturnValue_t result = RETURN_OK;
|
||
|
|
||
|
PLOC_SPV::UpdateInfo packet(PLOC_SPV::APID_UPDATE_VERIFY, static_cast<uint8_t>(updateMemory),
|
||
|
static_cast<uint8_t>(updatePartition), 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;
|
||
|
return;
|
||
|
}
|
||
|
state = State::COMMAND_EXECUTING;
|
||
|
pendingCommand = PLOC_SPV::UPDATE_VERIFY;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ReturnValue_t PlocUpdater::makeCrc() {
|
||
|
//TODO: Waiting on input from TAS about the CRC to use
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void PlocUpdater::adjustSequenceFlags(PLOC_SPV::UpdatePacket& packet) {
|
||
|
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));
|
||
|
}
|
||
|
}
|
||
|
|