509 lines
16 KiB
C++
509 lines
16 KiB
C++
#include "PlocSupvHelper.h"
|
|
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
|
|
#include "OBSWConfig.h"
|
|
#ifdef XIPHOS_Q7S
|
|
#include "bsp_q7s/memory/FilesystemHelper.h"
|
|
#include "bsp_q7s/memory/SDCardManager.h"
|
|
#endif
|
|
|
|
#include "fsfw/globalfunctions/CRC.h"
|
|
#include "fsfw/timemanager/Countdown.h"
|
|
#include "mission/utility/Filenaming.h"
|
|
#include "mission/utility/ProgressPrinter.h"
|
|
#include "mission/utility/Timestamp.h"
|
|
|
|
PlocSupvHelper::PlocSupvHelper(object_id_t objectId) : SystemObject(objectId) {}
|
|
|
|
PlocSupvHelper::~PlocSupvHelper() {}
|
|
|
|
ReturnValue_t PlocSupvHelper::initialize() {
|
|
#ifdef XIPHOS_Q7S
|
|
sdcMan = SdCardManager::instance();
|
|
if (sdcMan == nullptr) {
|
|
sif::warning << "PlocSupvHelper::initialize: Invalid SD Card Manager" << std::endl;
|
|
return RETURN_FAILED;
|
|
}
|
|
#endif
|
|
return RETURN_OK;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::performOperation(uint8_t operationCode) {
|
|
ReturnValue_t result = RETURN_OK;
|
|
semaphore.acquire();
|
|
while (true) {
|
|
switch (internalState) {
|
|
case InternalState::IDLE: {
|
|
semaphore.acquire();
|
|
break;
|
|
}
|
|
case InternalState::UPDATE: {
|
|
result = performUpdate();
|
|
if (result == RETURN_OK) {
|
|
triggerEvent(SUPV_UPDATE_SUCCESSFUL, result);
|
|
} else if (result == PROCESS_TERMINATED) {
|
|
// Event already triggered
|
|
} else {
|
|
triggerEvent(SUPV_UPDATE_FAILED, result);
|
|
}
|
|
internalState = InternalState::IDLE;
|
|
break;
|
|
}
|
|
case InternalState::REQUEST_EVENT_BUFFER: {
|
|
result = performEventBufferRequest();
|
|
if (result == RETURN_OK) {
|
|
triggerEvent(SUPV_EVENT_BUFFER_REQUEST_SUCCESSFUL, result);
|
|
} else if (result == PROCESS_TERMINATED) {
|
|
// Event already triggered
|
|
break;
|
|
} else {
|
|
triggerEvent(SUPV_EVENT_BUFFER_REQUEST_FAILED, result);
|
|
}
|
|
internalState = InternalState::IDLE;
|
|
break;
|
|
}
|
|
default:
|
|
sif::debug << "PlocSupvHelper::performOperation: Invalid state" << std::endl;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::setComIF(UartComIF* uartComIF_) {
|
|
if (uartComIF_ == nullptr) {
|
|
sif::warning << "PlocSupvHelper::initialize: Provided invalid uart com if" << std::endl;
|
|
return RETURN_FAILED;
|
|
}
|
|
uartComIF = uartComIF_;
|
|
return RETURN_OK;
|
|
}
|
|
|
|
void PlocSupvHelper::setComCookie(CookieIF* comCookie_) { comCookie = comCookie_; }
|
|
|
|
ReturnValue_t PlocSupvHelper::startUpdate(std::string file, uint8_t memoryId,
|
|
uint32_t startAddress) {
|
|
ReturnValue_t result = RETURN_OK;
|
|
#ifdef XIPHOS_Q7S
|
|
result = FilesystemHelper::checkPath(file);
|
|
if (result != RETURN_OK) {
|
|
sif::warning << "PlocSupvHelper::startUpdate: File " << file << " does not exist" << std::endl;
|
|
return result;
|
|
}
|
|
result = FilesystemHelper::fileExists(file);
|
|
if (result != RETURN_OK) {
|
|
sif::warning << "PlocSupvHelper::startUpdate: The file " << file << " does not exist"
|
|
<< std::endl;
|
|
return result;
|
|
}
|
|
#endif
|
|
#ifdef TE0720_1CFA
|
|
if (not std::filesystem::exists(file)) {
|
|
sif::warning << "PlocSupvHelper::startUpdate: The file " << file << " does not exist"
|
|
<< std::endl;
|
|
return RETURN_FAILED;
|
|
}
|
|
#endif
|
|
update.file = file;
|
|
update.length = getFileSize(update.file);
|
|
update.memoryId = memoryId;
|
|
update.startAddress = startAddress;
|
|
internalState = InternalState::UPDATE;
|
|
uartComIF->flushUartTxAndRxBuf(comCookie);
|
|
semaphore.release();
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::startEventbBufferRequest(std::string path) {
|
|
#ifdef XIPHOS_Q7S
|
|
ReturnValue_t result = FilesystemHelper::checkPath(path);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
#endif
|
|
if (not std::filesystem::exists(path)) {
|
|
return PATH_NOT_EXISTS;
|
|
}
|
|
eventBufferReq.path = path;
|
|
internalState = InternalState::REQUEST_EVENT_BUFFER;
|
|
uartComIF->flushUartTxAndRxBuf(comCookie);
|
|
semaphore.release();
|
|
return RETURN_OK;
|
|
}
|
|
|
|
void PlocSupvHelper::stopProcess() { terminate = true; }
|
|
|
|
ReturnValue_t PlocSupvHelper::performUpdate() {
|
|
ReturnValue_t result = RETURN_OK;
|
|
result = calcImageCrc();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = prepareUpdate();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = eraseMemory();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
#if OBSW_DEBUG_PLOC_SUPERVISOR == 1
|
|
ProgressPrinter progressPrinter("Supervisor update", update.length, ProgressPrinter::ONE_PERCENT);
|
|
#endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */
|
|
uint8_t tempData[supv::WriteMemory::CHUNK_MAX];
|
|
std::ifstream file(update.file, std::ifstream::binary);
|
|
size_t remainingSize = update.length;
|
|
uint16_t dataLength = 0;
|
|
size_t bytesWritten = 0;
|
|
uint16_t sequenceCount = 1;
|
|
supv::SequenceFlags seqFlags = supv::SequenceFlags::FIRST_PKT;
|
|
while (remainingSize > 0) {
|
|
if (terminate) {
|
|
return PROCESS_TERMINATED;
|
|
}
|
|
if (remainingSize > supv::WriteMemory::CHUNK_MAX) {
|
|
dataLength = supv::WriteMemory::CHUNK_MAX;
|
|
} else {
|
|
dataLength = static_cast<uint16_t>(remainingSize);
|
|
}
|
|
if (file.is_open()) {
|
|
file.seekg(bytesWritten, file.beg);
|
|
file.read(reinterpret_cast<char*>(tempData), dataLength);
|
|
if (!file) {
|
|
sif::warning << "PlocSupvHelper::performUpdate: Read only " << file.gcount() << " of "
|
|
<< dataLength << " bytes" << std::endl;
|
|
sif::info << "PlocSupvHelper::performUpdate: Failed when trying to read byte "
|
|
<< bytesWritten << std::endl;
|
|
}
|
|
remainingSize -= dataLength;
|
|
} else {
|
|
return FILE_CLOSED_ACCIDENTALLY;
|
|
}
|
|
if (bytesWritten == 0) {
|
|
seqFlags = supv::SequenceFlags::FIRST_PKT;
|
|
} else if (remainingSize == 0) {
|
|
seqFlags = supv::SequenceFlags::LAST_PKT;
|
|
} else {
|
|
seqFlags = supv::SequenceFlags::CONTINUED_PKT;
|
|
}
|
|
supv::WriteMemory packet(seqFlags, sequenceCount++, update.memoryId,
|
|
update.startAddress + bytesWritten, dataLength, tempData);
|
|
result = handlePacketTransmission(packet);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
bytesWritten += dataLength;
|
|
#if OBSW_DEBUG_PLOC_SUPERVISOR == 1
|
|
progressPrinter.print(bytesWritten);
|
|
#endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */
|
|
}
|
|
result = handleCheckMemoryCommand();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::performEventBufferRequest() {
|
|
using namespace supv;
|
|
ReturnValue_t result = RETURN_OK;
|
|
RequestLoggingData packet(RequestLoggingData::Sa::REQUEST_EVENT_BUFFERS);
|
|
result = sendCommand(packet);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = handleAck();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = handleEventBufferReception();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = handleExe();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::prepareUpdate() {
|
|
ReturnValue_t result = RETURN_OK;
|
|
supv::ApidOnlyPacket packet(supv::APID_PREPARE_UPDATE);
|
|
result = handlePacketTransmission(packet);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
return RETURN_OK;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::eraseMemory() {
|
|
ReturnValue_t result = RETURN_OK;
|
|
supv::EraseMemory eraseMemory(update.memoryId, update.startAddress, update.length);
|
|
result = handlePacketTransmission(eraseMemory, supv::recv_timeout::ERASE_MEMORY);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
return RETURN_OK;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::handlePacketTransmission(SpacePacket& packet,
|
|
uint32_t timeoutExecutionReport) {
|
|
ReturnValue_t result = RETURN_OK;
|
|
result = sendCommand(packet);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = handleAck();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = handleExe(timeoutExecutionReport);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
return RETURN_OK;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::sendCommand(SpacePacket& packet) {
|
|
ReturnValue_t result = RETURN_OK;
|
|
rememberApid = packet.getAPID();
|
|
result = uartComIF->sendMessage(comCookie, packet.getWholeData(), packet.getFullSize());
|
|
if (result != RETURN_OK) {
|
|
sif::warning << "PlocSupvHelper::sendCommand: Failed to send command" << std::endl;
|
|
triggerEvent(SUPV_SENDING_COMMAND_FAILED, result, static_cast<uint32_t>(internalState));
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::handleAck() {
|
|
ReturnValue_t result = RETURN_OK;
|
|
supv::TmPacket tmPacket;
|
|
result = handleTmReception(&tmPacket, supv::SIZE_ACK_REPORT);
|
|
if (result != RETURN_OK) {
|
|
triggerEvent(ACK_RECEPTION_FAILURE, result, static_cast<uint32_t>(rememberApid));
|
|
sif::warning << "PlocSupvHelper::handleAck: Error in reception of acknowledgment report"
|
|
<< std::endl;
|
|
return result;
|
|
}
|
|
uint16_t apid = tmPacket.getAPID();
|
|
if (apid != supv::APID_ACK_SUCCESS) {
|
|
handleAckApidFailure(apid);
|
|
return RETURN_FAILED;
|
|
}
|
|
return RETURN_OK;
|
|
}
|
|
|
|
void PlocSupvHelper::handleAckApidFailure(uint16_t apid) {
|
|
if (apid == supv::APID_ACK_FAILURE) {
|
|
triggerEvent(SUPV_ACK_FAILURE_REPORT, static_cast<uint32_t>(internalState));
|
|
sif::warning << "PlocSupvHelper::handleAckApidFailure: Received acknowledgement failure "
|
|
<< "report" << std::endl;
|
|
} else {
|
|
triggerEvent(SUPV_ACK_INVALID_APID, apid, static_cast<uint32_t>(internalState));
|
|
sif::warning << "PlocSupvHelper::handleAckApidFailure: Expected acknowledgement report "
|
|
<< "but received space packet with apid " << std::hex << apid << std::endl;
|
|
}
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::handleExe(uint32_t timeout) {
|
|
ReturnValue_t result = RETURN_OK;
|
|
supv::TmPacket tmPacket;
|
|
result = handleTmReception(&tmPacket, supv::SIZE_EXE_REPORT, timeout);
|
|
if (result != RETURN_OK) {
|
|
triggerEvent(EXE_RECEPTION_FAILURE, result, static_cast<uint32_t>(rememberApid));
|
|
sif::warning << "PlocSupvHelper::handleExe: Error in reception of execution report"
|
|
<< std::endl;
|
|
return result;
|
|
}
|
|
uint16_t apid = tmPacket.getAPID();
|
|
if (apid != supv::APID_EXE_SUCCESS) {
|
|
handleExeApidFailure(apid);
|
|
return RETURN_FAILED;
|
|
}
|
|
return RETURN_OK;
|
|
}
|
|
|
|
void PlocSupvHelper::handleExeApidFailure(uint16_t apid) {
|
|
if (apid == supv::APID_EXE_FAILURE) {
|
|
triggerEvent(SUPV_EXE_FAILURE_REPORT, static_cast<uint32_t>(internalState));
|
|
sif::warning << "PlocSupvHelper::handleExeApidFailure: Received execution failure "
|
|
<< "report" << std::endl;
|
|
} else {
|
|
triggerEvent(SUPV_EXE_INVALID_APID, apid, static_cast<uint32_t>(internalState));
|
|
sif::warning << "PlocSupvHelper::handleExeApidFailure: Expected execution report "
|
|
<< "but received space packet with apid " << std::hex << apid << std::endl;
|
|
}
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::handleTmReception(supv::TmPacket* tmPacket, size_t remainingBytes,
|
|
uint32_t timeout) {
|
|
ReturnValue_t result = RETURN_OK;
|
|
size_t readBytes = 0;
|
|
size_t currentBytes = 0;
|
|
Countdown countdown(timeout);
|
|
while (!countdown.hasTimedOut()) {
|
|
result = receive(tmPacket->getWholeData() + readBytes, ¤tBytes, remainingBytes);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
readBytes += currentBytes;
|
|
remainingBytes = remainingBytes - currentBytes;
|
|
if (remainingBytes == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (remainingBytes != 0) {
|
|
sif::warning << "PlocSupvHelper::handleTmReception: Failed to read " << remainingBytes
|
|
<< " bytes" << std::endl;
|
|
return RETURN_FAILED;
|
|
}
|
|
result = tmPacket->checkCrc();
|
|
if (result != RETURN_OK) {
|
|
sif::warning << "PlocSupvHelper::handleTmReception: CRC check failed" << std::endl;
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::receive(uint8_t* data, size_t* readBytes, size_t requestBytes) {
|
|
ReturnValue_t result = RETURN_OK;
|
|
uint8_t* buffer = nullptr;
|
|
result = uartComIF->requestReceiveMessage(comCookie, requestBytes);
|
|
if (result != RETURN_OK) {
|
|
sif::warning << "PlocSupvHelper::receive: Failed to request reply" << std::endl;
|
|
triggerEvent(SUPV_HELPER_REQUESTING_REPLY_FAILED, result,
|
|
static_cast<uint32_t>(static_cast<uint32_t>(internalState)));
|
|
return RETURN_FAILED;
|
|
}
|
|
result = uartComIF->readReceivedMessage(comCookie, &buffer, readBytes);
|
|
if (result != RETURN_OK) {
|
|
sif::warning << "PlocSupvHelper::receive: Failed to read received message" << std::endl;
|
|
triggerEvent(SUPV_HELPER_READING_REPLY_FAILED, result, static_cast<uint32_t>(internalState));
|
|
return RETURN_FAILED;
|
|
}
|
|
if (*readBytes > 0) {
|
|
std::memcpy(data, buffer, *readBytes);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::calcImageCrc() {
|
|
ReturnValue_t result = RETURN_OK;
|
|
#ifdef XIPHOS_Q7S
|
|
result = FilesystemHelper::checkPath(update.file);
|
|
#endif
|
|
if (result != RETURN_OK) {
|
|
sif::warning << "PlocSupvHelper::calcImageCrc: File " << update.file << " does not exist"
|
|
<< std::endl;
|
|
return result;
|
|
}
|
|
std::ifstream file(update.file, std::ifstream::binary);
|
|
uint16_t remainder = CRC16_INIT;
|
|
uint8_t input;
|
|
#if OBSW_DEBUG_PLOC_SUPERVISOR == 1
|
|
ProgressPrinter progress("Supervisor update crc calculation", update.length);
|
|
#endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */
|
|
uint32_t byteCount = 0;
|
|
for (byteCount = 0; byteCount < update.length; byteCount++) {
|
|
file.seekg(byteCount, file.beg);
|
|
file.read(reinterpret_cast<char*>(&input), 1);
|
|
remainder = CRC::crc16ccitt(&input, sizeof(input), remainder);
|
|
#if OBSW_DEBUG_PLOC_SUPERVISOR == 1
|
|
progress.print(byteCount);
|
|
#endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */
|
|
}
|
|
#if OBSW_DEBUG_PLOC_SUPERVISOR == 1
|
|
progress.print(byteCount);
|
|
#endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */
|
|
file.close();
|
|
update.crc = remainder;
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::handleCheckMemoryCommand() {
|
|
ReturnValue_t result = RETURN_OK;
|
|
// Verification of update write procedure
|
|
supv::CheckMemory packet(update.memoryId, update.startAddress, update.length);
|
|
result = sendCommand(packet);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = handleAck();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
supv::UpdateStatusReport updateStatusReport;
|
|
result = handleTmReception(&updateStatusReport,
|
|
static_cast<size_t>(updateStatusReport.getNominalSize()),
|
|
supv::recv_timeout::UPDATE_STATUS_REPORT);
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = handleExe();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = updateStatusReport.parseDataField();
|
|
if (result != RETURN_OK) {
|
|
return result;
|
|
}
|
|
result = updateStatusReport.verifycrc(update.crc);
|
|
if (result != RETURN_OK) {
|
|
sif::warning << "PlocSupvHelper::performUpdate: CRC failure. Expected CRC 0x" << std::hex
|
|
<< update.crc << " but received CRC 0x" << updateStatusReport.getCrc()
|
|
<< std::endl;
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
uint32_t PlocSupvHelper::getFileSize(std::string filename) {
|
|
std::ifstream file(filename, std::ifstream::binary);
|
|
file.seekg(0, file.end);
|
|
uint32_t size = file.tellg();
|
|
file.close();
|
|
return size;
|
|
}
|
|
|
|
ReturnValue_t PlocSupvHelper::handleEventBufferReception() {
|
|
ReturnValue_t result = RETURN_OK;
|
|
std::string filename = Filenaming::generateAbsoluteFilename(
|
|
eventBufferReq.path, eventBufferReq.filename, timestamping);
|
|
std::ofstream file(filename, std::ios_base::app | std::ios_base::out);
|
|
uint32_t packetsRead = 0;
|
|
size_t requestLen = 0;
|
|
supv::TmPacket tmPacket;
|
|
for (packetsRead = 0; packetsRead < NUM_EVENT_BUFFER_PACKETS; packetsRead++) {
|
|
if (terminate) {
|
|
triggerEvent(SUPV_EVENT_BUFFER_REQUEST_TERMINATED, packetsRead - 1);
|
|
file.close();
|
|
return PROCESS_TERMINATED;
|
|
}
|
|
if (packetsRead == NUM_EVENT_BUFFER_PACKETS - 1) {
|
|
requestLen = SIZE_EVENT_BUFFER_LAST_PACKET;
|
|
} else {
|
|
requestLen = SIZE_EVENT_BUFFER_FULL_PACKET;
|
|
}
|
|
result = handleTmReception(&tmPacket, requestLen);
|
|
if (result != RETURN_OK) {
|
|
sif::debug << "PlocSupvHelper::handleEventBufferReception: Failed while trying to read packet"
|
|
<< " " << packetsRead + 1 << std::endl;
|
|
file.close();
|
|
return result;
|
|
}
|
|
uint16_t apid = tmPacket.getAPID();
|
|
if (apid != supv::APID_MRAM_DUMP_TM) {
|
|
sif::warning << "PlocSupvHelper::handleEventBufferReception: Did not expect space packet "
|
|
<< "with APID 0x" << std::hex << apid << std::endl;
|
|
file.close();
|
|
return EVENT_BUFFER_REPLY_INVALID_APID;
|
|
}
|
|
file.write(reinterpret_cast<const char*>(tmPacket.getPacketData()),
|
|
tmPacket.getPayloadDataLength());
|
|
}
|
|
return result;
|
|
}
|