v1.10.0 #220

Merged
meierj merged 592 commits from develop into main 2022-04-22 07:42:20 +02:00
18 changed files with 733 additions and 109 deletions
Showing only changes of commit 996a8a226e - Show all commits

View File

@ -16,6 +16,7 @@ static const DeviceCommandId_t EXE_REPORT = 5;
static const DeviceCommandId_t TM_MEMORY_READ_REPORT = 6;
static const DeviceCommandId_t TC_FLASHFOPEN = 7;
static const DeviceCommandId_t TC_FLASHFCLOSE = 8;
static const DeviceCommandId_t TC_FLASHWRITE = 9;
static const uint16_t SIZE_ACK_REPORT = 14;
static const uint16_t SIZE_EXE_REPORT = 14;
@ -27,6 +28,7 @@ static const uint16_t SIZE_TM_MEM_READ_REPORT = 18;
namespace apid {
static const uint16_t TC_MEM_WRITE = 0x114;
static const uint16_t TC_MEM_READ = 0x115;
static const uint16_t TC_FLASHWRITE = 0x117;
static const uint16_t TC_FLASHFOPEN = 0x119;
static const uint16_t TC_FLASHFCLOSE = 0x11A;
static const uint16_t TM_MEMORY_READ_REPORT = 0x404;
@ -54,8 +56,9 @@ static const size_t MAX_FILENAME_SIZE = 256;
static const uint16_t LENGTH_TC_MEM_WRITE = 12;
static const uint16_t LENGTH_TC_MEM_READ = 8;
static const size_t MAX_REPLY_SIZE = SIZE_TM_MEM_READ_REPORT;
static const size_t MAX_COMMAND_SIZE = 18;
static const size_t MAX_REPLY_SIZE = SpacePacket::PACKET_MAX_SIZE;
static const size_t MAX_COMMAND_SIZE = SpacePacket::PACKET_MAX_SIZE;
static const size_t MAX_DATA_SIZE = 1016;
/**
* @breif Abstract base class for TC space packet of MPSoC.
@ -130,6 +133,33 @@ private:
}
};
/**
* @brief Class for handling tm replies of the PLOC MPSoC.
*/
class TmPacket : public SpacePacket, public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::MPSOC_CMD;
//! [EXPORT] : [COMMENT] CRC check of received packet failed
static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA0);
/**
* @brief Constructor creates idle packet and sets length field to maximum allowed size.
*/
TmPacket() : SpacePacket(PACKET_MAX_SIZE) {
}
ReturnValue_t checkCrc() {
uint8_t crcPtr = this->getPacketData() + this->getPacketDataLength() - 1;
uint16_t receivedCrc = *(crcPtr) << 8 | *(crcPtr + 1);
uint16_t recalculatedCrc = CRC::crc16ccitt(this->localData.byteStream, this->getFullSize());
if (recalculatedCrc != this->ge) {
return CRC_FAILURE;
}
return RETURN_OK;
}
};
/**
* @brief This class helps to build the memory read command for the PLOC.
*/
@ -291,6 +321,29 @@ private:
}
};
/**
* @brief Class to build flash write space packet.
*/
class FlashWrite : public TcBase {
public:
FlashWrite(uint16_t sequenceCount) :
TcBase(apid::TC_FLASHWRITE, sequenceCount) {
}
protected:
ReturnValue_t initPacket(const uint8_t* commandData, size_t commandDataLen) {
if (commandDataLen > MAX_DATA_SIZE) {
sif::debug << "FlashWrite::initPacket: Command data too big" << std::endl;
return RETURN_FAILED;
}
std::memcpy(this->getPacketData(), commandData, commandDataLen);
this->setPacketDataLength(static_cast<uint16_t>(commandDataLen + CRC_SIZE - 1));
return RETURN_OK;
}
};
}
#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_PLOCMPSOCDEFINITIONS_H_ */

View File

@ -3,4 +3,5 @@ target_sources(${TARGET_NAME} PRIVATE
PlocUpdater.cpp
PlocMemoryDumper.cpp
PlocMPSoCHandler.cpp
PlocMPSoCHelper.cpp
)

View File

@ -0,0 +1,56 @@
#include "MPSoCSequenceCount.h"
MPSoCSequenceCount::MPSoCSequenceCount() {
}
MPSoCSequenceCount::~MPSoCSequenceCount() {
}
MPSoCSequenceCount::increment() {
ReturnValue_t result = RETURN_OK;
result = spiMutex->lockMutex(timeoutType, timeoutMs);
if (result != RETURN_OK) {
sif::warning << "MPSoCSequenceCount::increment: Failed to lock mutex" << std::endl;
return result;
}
sequenceCount = (sequenceCount + 1) & SEQUENCE_COUNT_MASK;
result = spiMutex->unlockMutex(timeoutType, timeoutMs);
if (result != RETURN_OK) {
sif::warning << "MPSoCSequenceCount::increment: Failed to unlock mutex" << std::endl;
return result;
}
}
MPSoCSequenceCount::set(uint16_t sequenceCount_) {
ReturnValue_t result = RETURN_OK;
result = spiMutex->lockMutex(timeoutType, timeoutMs);
if (result != RETURN_OK) {
sif::warning << "MPSoCSequenceCount::set: Failed to lock mutex" << std::endl;
return result;
}
sequenceCount = sequenceCount_;
result = spiMutex->unlockMutex(timeoutType, timeoutMs);
if (result != RETURN_OK) {
sif::warning << "MPSoCSequenceCount::set: Failed to unlock mutex" << std::endl;
return result;
}
}
MPSoCSequenceCount::reset() {
ReturnValue_t result = RETURN_OK;
result = spiMutex->lockMutex(timeoutType, timeoutMs);
if (result != RETURN_OK) {
sif::warning << "MPSoCSequenceCount::reset: Failed to lock mutex" << std::endl;
return result;
}
sequenceCount = 0;
result = spiMutex->unlockMutex(timeoutType, timeoutMs);
if (result != RETURN_OK) {
sif::warning << "MPSoCSequenceCount::reset: Failed to unlock mutex" << std::endl;
return result;
}
}
uint16_t MPSoCSequenceCount::get() {
return sequenceCount;
}

View File

@ -0,0 +1,48 @@
#ifndef BSP_Q7S_DEVICES_PLOC_MPSOCSEQUENCECOUNT_H_
#define BSP_Q7S_DEVICES_PLOC_MPSOCSEQUENCECOUNT_H_
/**
* @brief Manages incrementing, resetting and harmonization of the sequence count in the space
* packet based communication between MPSoC and OBC.
*
* @author J. Meier
*/
class MPSoCSequenceCount {
public:
MPSoCSequenceCount();
virtual ~MPSoCSequenceCount();
/**
* @brief Increments the sequence count.
*/
void increment();
/**
* @brief Sets the value of the sequence count
*
* @param sequenceCount The sequence count to set
*/
void set(uint16_t sequenceCount_);
/**
* @brief Resets the sequence count to zero
*/
void reset();
/**
* @brief Returns the current value sequence count
*/
uint16_t get();
private:
MutexIF* spiMutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20;
static const uint16_t SEQUENCE_COUNT_MASK = 0x3FFF;
uint16_t sequenceCount = 0x3FFF;
};
#endif /* BSP_Q7S_DEVICES_PLOC_MPSOCSEQUENCECOUNT_H_ */

View File

@ -1,13 +1,11 @@
#include "../../bsp_q7s/devices/ploc/PlocMPSoCHandler.h"
#include "OBSWConfig.h"
#include <fsfw/globalfunctions/CRC.h>
#include <fsfw/datapool/PoolReadGuard.h>
#include "PlocMPSoCHandler.h"
#include "fsfw/globalfunctions/CRC.h"
#include "fsfw/datapool/PoolReadGuard.h"
PlocMPSoCHandler::PlocMPSoCHandler(object_id_t objectId, object_id_t uartComIFid,
CookieIF * comCookie) :
DeviceHandlerBase(objectId, uartComIFid, comCookie) {
CookieIF * comCookie, PlocMPSoCHelper* plocMPSoCHelper) :
DeviceHandlerBase(objectId, uartComIFid, comCookie), plocMPSoCHelper(plocMPSoCHelper) {
if (comCookie == NULL) {
sif::error << "PlocMPSoCHandler: Invalid com cookie" << std::endl;
}
@ -27,8 +25,65 @@ ReturnValue_t PlocMPSoCHandler::initialize() {
sif::warning << "PlocMPSoCHandler::initialize: Invalid uart com if" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(
objects::EVENT_MANAGER);
if (manager == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PlocMPSoCHandler::initialize: Invalid event manager" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;;
}
result = manager->registerListener(eventQueue->getId());
if (result != RETURN_OK) {
return result;
}
result = manager->subscribeToEventRange(eventQueue->getId(),
event::getEventId(PlocMPSoCHelper::FLASH_WRITE_FAILED),
event::getEventId(PlocMPSoCHelper::FLASH_WRITE_SUCCESSFUL));
if (result != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "PlocMPSoCHandler::initialize: Failed to subscribe to events from "
" ploc mpsoc helper" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
result = plocMPSoCHelper->setComIF(communicationInterface);
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
plocMPSoCHelper->setComCookie(comCookie);
plocMPSoCHelper->setSequenceCount(&sequenceCount);
return result;
}
ReturnValue_t PlocMPSoCHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
ReturnValue_t result = RETURN_OK;
if (plocMPSoCHelperExecuting) {
return MPSOC_HELPER_EXECUTING;
}
switch(actionId) {
case mpsoc::TC_FLASHWRITE: {
if (size > config::MAX_PATH_SIZE + config::MAX_FILE_NAME) {
return FILENAME_TOO_LONG;
}
result = plocMPSoCHelper->startFlashWrite(
std::string(reinterpret_cast<const char*>(data), size));
if (result != RETURN_OK) {
return result;
}
plocMPSoCHelperExecuting = true;
break;
}
default:
break;
}
return DeviceHandlerBase::executeAction(actionId, commandedBy, data, size);
}
void PlocMPSoCHandler::doStartUp(){
@ -179,15 +234,11 @@ ReturnValue_t PlocMPSoCHandler::initializeLocalDataPool(localpool::DataPool& loc
return HasReturnvaluesIF::RETURN_OK;
}
void PlocMPSoCHandler::setModeNormal() {
mode = MODE_NORMAL;
}
ReturnValue_t PlocMPSoCHandler::prepareTcMemWriteCommand(const uint8_t * commandData,
size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
packetSequenceCount = (packetSequenceCount + 1) & PACKET_SEQUENCE_COUNT_MASK;
mpsoc::TcMemWrite tcMemWrite(packetSequenceCount);
sequenceCount.increment();
mpsoc::TcMemWrite tcMemWrite(sequenceCount.get());
result = tcMemWrite.createPacket(commandData, commandDataLen);
if (result != RETURN_OK) {
return result;
@ -199,8 +250,8 @@ ReturnValue_t PlocMPSoCHandler::prepareTcMemWriteCommand(const uint8_t * command
ReturnValue_t PlocMPSoCHandler::prepareTcMemReadCommand(const uint8_t * commandData,
size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
packetSequenceCount = (packetSequenceCount + 1) & PACKET_SEQUENCE_COUNT_MASK;
mpsoc::TcMemRead tcMemRead(packetSequenceCount);
sequenceCount.increment();
mpsoc::TcMemRead tcMemRead(sequenceCount.get());
result = tcMemRead.createPacket(commandData, commandDataLen);
if (result != RETURN_OK) {
return result;
@ -212,8 +263,8 @@ ReturnValue_t PlocMPSoCHandler::prepareTcMemReadCommand(const uint8_t * commandD
ReturnValue_t PlocMPSoCHandler::prepareFlashFopenCmd(const uint8_t * commandData,
size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
packetSequenceCount = (packetSequenceCount + 1) & PACKET_SEQUENCE_COUNT_MASK;
mpsoc::FlashFopen flashFopen(packetSequenceCount);
sequenceCount.increment();
mpsoc::FlashFopen flashFopen(sequenceCount.get());
result = flashFopen.createPacket(commandData, commandDataLen);
if (result != RETURN_OK) {
return result;
@ -225,8 +276,8 @@ ReturnValue_t PlocMPSoCHandler::prepareFlashFopenCmd(const uint8_t * commandData
ReturnValue_t PlocMPSoCHandler::prepareFlashFcloseCmd(const uint8_t * commandData,
size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
packetSequenceCount = (packetSequenceCount + 1) & PACKET_SEQUENCE_COUNT_MASK;
mpsoc::FlashFclose flashFclose(packetSequenceCount);
sequenceCount.increment();
mpsoc::FlashFclose flashFclose(sequenceCount.get());
result = flashFclose.createPacket(commandData, commandDataLen);
if (result != RETURN_OK) {
return result;
@ -534,13 +585,13 @@ void PlocMPSoCHandler::disableExeReportReply() {
ReturnValue_t PlocMPSoCHandler::checkPacketSequenceCount(const uint8_t* data) {
uint16_t receivedSeqCnt = (*(data + 2) << 8 | *(data + 3)) & PACKET_SEQUENCE_COUNT_MASK;
uint16_t expectedSeqCnt = ((packetSequenceCount + 1) & PACKET_SEQUENCE_COUNT_MASK);
uint16_t expectedSeqCnt = sequenceCount.get();
if (receivedSeqCnt != expectedSeqCnt) {
sif::warning << "PlocMPSoCHandler::checkPacketSequenceCount: Packet sequence count "
"mismatch. Received: " << receivedSeqCnt << ", Expected: "
<< expectedSeqCnt << std::endl;
triggerEvent(SEQ_CNT_MISMATCH, expectedSeqCnt, receivedSeqCnt);
}
packetSequenceCount = receivedSeqCnt;
sequenceCount.set(receivedSeqCnt);
return RETURN_OK;
}

View File

@ -1,22 +1,24 @@
#ifndef BSP_Q7S_DEVICES_PLOC_PLOCMPSOCHANDLER_H_
#define BSP_Q7S_DEVICES_PLOC_PLOCMPSOCHANDLER_H_
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include <bsp_q7s/devices/devicedefinitions/PlocMPSoCDefinitions.h>
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "devicedefinitions/PlocMPSoCDefinitions.h"
#include "fsfw_hal/linux/uart/UartComIF.h"
#include "MPSoCSequenceCount.h"
#include "PlocMPSoCHelper.h"
#include <cstring>
#include <fsfw_hal/linux/uart/UartComIF.h>
/**
* @brief This is the device handler for the MPSoC which is programmed by the ILH of the
* university of stuttgart.
* @brief This is the device handler for the MPSoC of the payload computer.
*
* @details
* The PLOC uses the space packet protocol for communication. To each command the PLOC
* @details The PLOC uses the space packet protocol for communication. On each command the PLOC
* answers with at least one acknowledgment and one execution report.
* Flight manual:
* https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/PLOC_Commands
* ILH ICD: https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/
* Arbeitsdaten/08_Used%20Components/PLOC&fileid=940960
* Flight manual: https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/PLOC_MPSoC
* ICD: https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_TAS-ILH-IRS/ICD-PLOC/ILH&fileid=1030263
*
* @note The sequence count in the space packets must be incremented with each received and sent
* packet.
*
* @author J. Meier
*/
class PlocMPSoCHandler: public DeviceHandlerBase {
@ -34,15 +36,17 @@ public:
static const ReturnValue_t INVALID_APID = MAKE_RETURN_CODE(0xA3);
//! [EXPORT] : [COMMENT] Received command with invalid length
static const ReturnValue_t INVALID_LENGTH = MAKE_RETURN_CODE(0xA4);
//! [EXPORT] : [COMMENT] Received command with invalid filename
static const ReturnValue_t FILENAME_TOO_LONG = MAKE_RETURN_CODE(0xA5);
//! [EXPORT] : [COMMENT] MPSoC helper is currently executing a command
static const ReturnValue_t MPSOC_HELPER_EXECUTING = MAKE_RETURN_CODE(0xA6);
PlocMPSoCHandler(object_id_t objectId, object_id_t uartComIFid, CookieIF * comCookie);
PlocMPSoCHandler(object_id_t objectId, object_id_t uartComIFid, CookieIF * comCookie,
PlocMPSoCHelper* plocMPSoCHelper);
virtual ~PlocMPSoCHandler();
virtual ReturnValue_t initialize() override;
/**
* @brief Sets mode to MODE_NORMAL. Can be used for debugging.
*/
void setModeNormal();
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) override;
protected:
void doStartUp() override;
@ -83,22 +87,11 @@ private:
static const Event SEQ_CNT_MISMATCH = MAKE_EVENT(5, severity::LOW);
static const uint16_t APID_MASK = 0x7FF;
static const uint16_t PACKET_SEQUENCE_COUNT_MASK = 0x3FFF;
MPSoCSequenceCount sequenceCount;
uint8_t commandBuffer[mpsoc::MAX_COMMAND_SIZE];
/**
* @brief This object is incremented each time a packet is sent or received. By checking the
* packet sequence count of a received packet, no packets can be lost without noticing
* it. Only the least significant 14 bits represent the packet sequence count in a
* space packet. Thus the maximum value amounts to 16383 (0x3FFF).
* @note Normally this should never happen because the PLOC replies are always sent in a
* fixed order. However, the PLOC software checks this value and will return an ACK
* failure report in case the sequence count is not incremented with each transferred
* space packet.
*/
uint16_t packetSequenceCount = 0x3FFF;
/**
* This variable is used to store the id of the next reply to receive. This is necessary
* because the PLOC sends as reply to each command at least one acknowledgment and execution
@ -108,6 +101,11 @@ private:
UartComIF* uartComIf = nullptr;
PlocMPSoCHelper* plocMPSoCHelper = nullptr;
// Used to block incoming commands when MPSoC helper class is currently executing a command
bool plocMPSoCHelperExecuting = false;
ReturnValue_t prepareTcMemWriteCommand(const uint8_t * commandData, size_t commandDataLen);
ReturnValue_t prepareTcMemReadCommand(const uint8_t * commandData, size_t commandDataLen);
ReturnValue_t prepareFlashFopenCmd(const uint8_t * commandData, size_t commandDataLen);

View File

@ -0,0 +1,215 @@
#include "PlocMPSoCHelper.h"
#include "mission/utility/Timestamp.h"
#include <fstream>
#include <filesystem>
PlocMPSoCHelper::PlocMPSoCHelper(object_id_t objectId) : SystemObject(objectId){
}
PlocMPSoCHelper::~PlocMPSoCHelper() {
}
ReturnValue_t PlocMPSoCHelper::initialize() {
sdcMan = SdCardManager::instance();
if (sdcMan == nullptr) {
sif::warning << "PlocMPSoCHelper::initialize: Invalid SD Card Manager" << std::endl;
return RETURN_FAILED;
}
return RETURN_OK;
}
ReturnValue_t PlocMPSoCHelper::performOperation(uint8_t operationCode) {
ReturnValue_t result = RETURN_OK;
semaphore.acquire();
while(true) {
switch(internalState) {
case InternalState::IDLE: {
semaphore.acquire();
break;
}
case InternalState::FLASH_WRITE: {
result = performFlashWrite();
if (result == RETURN_OK){
triggerEvent(FLASH_WRITE_SUCCESSFUL);
}
else {
triggerEvent(FLASH_WRITE_FAILED);
}
internalState = InternalState::IDLE;
break;
}
default:
sif::debug << "PlocMPSoCHelper::performOperation: Invalid state" << std::endl;
break;
}
}
}
ReturnValue_t PlocMPSoCHelper::setComIF(DeviceCommunicationIF* communicationInterface_) {
uartComIF = dynamic_cast<UartComIF*>(communicationInterface_);
if (uartComIF == nullptr) {
sif::warning << "PlocMPSoCHelper::initialize: Invalid uart com if" << std::endl;
return RETURN_FAILED;
}
return RETURN_OK;
}
void PlocMPSoCHelper::setComCookie(CookieIF* comCookie_) {
comCookie = comCookie_;
}
void PlocMPSoCHelper::setSequenceCount(MPSoCSequenceCount* sequenceCount_) {
sequenceCount = sequenceCount_;
}
ReturnValue_t PlocMPSoCHelper::startFlashWrite(std::string file) {
ReturnValue_t result = FilesystemHelper::checkPath(file);
if (result != RETURN_OK) {
return result;
}
result = FilesystemHelper::fileExists(file);
if (result != RETURN_OK) {
return result;
}
flashWrite.file = file;
internalState = InternalState::FLASH_WRITE;
semaphore.release();
terminate = false;
return RETURN_OK;
}
void PlocMPSoCHelper::stopProcess() {
terminate = true;
}
ReturnValue_t PlocMPSoCHelper::performFlashWrite() {
ReturnValue_t result = RETURN_OK;
std::ifstream file(flashWrite.file, std::ifstream::binary);
// Set position of next character to end of file input stream
file.seekg(0, file.end);
// tellg returns position of character in input stream
imageSize = file.tellg();
sequenceCount->increment();
mpsoc::FlashWrite tc(sequenceCount->get());
result = sendCommand(tc);
if (result != REUTRN_OK) {
return result;
}
result = handleAck();
if (result != RETURN_OK) {
return result;
}
result = handleExe();
if (result != RETURN_OK) {
return result;
}
return result;
}
ReturnValue_t PlocMPSoCHelper::sendCommand(TcBase* tc) {
ReturnValue_t result = RETURN_OK;
result = uartComIF->sendMessage(comCookie, tc->getWholeData(), tc->getFullSize());
if (result != RETURN_OK) {
sif::warning << "PlocMPSoCHelper::sendCommand: Failed to send command" << std::endl;
triggerEvent(SENDING_COMMAND_FAILED, result, internalState);
return result;
}
return result;
}
ReturnValue_t PlocMPSoCHelper::handleAck() {
ReturnValue_t result = RETURN_OK;
mpsoc::TmPacket tmPacket;
result = handleTmReception(tmPacket, mpsoc::SIZE_ACK_REPORT);
if (result != RETURN_OK) {
return result;
}
uint16_t apid = tmPacket.getAPID();
if (apid != mpsoc::apid::ACK_SUCCESS) {
handleAckApidFailure(apid);
return RETURN_FAILED;
}
return RETURN_OK;
}
void PlocMPSoCHelper::handleAckApidFailure(uint16_t apid) {
if (apid == mpsoc::apid::ACK_FAILURE) {
triggerEvent(ACK_FAILURE_REPORT, internalState);
sif::warning << "PlocMPSoCHelper::handleAckApidFailure: Received acknowledgement failure "
<< "report" << std::endl;
}
else {
triggerEvent(ACK_INVALID_APID, apid, internalState);
sif::warning << "PlocMPSoCHelper::handleAckApidFailure: Expected acknowledgement report "
<< "but received space packet with apid " << std::hex << apid << std::endl;
}
}
ReturnValue_t PlocMPSoCHelper::handleExe() {
ReturnValue_t result = RETURN_OK;
mpsoc::TmPacket tmPacket;
result = handleTmReception(tmPacket, mpsoc::SIZE_EXE_REPORT);
if (result != RETURN_OK) {
return result;
}
uint16_t apid = tmPacket.getAPID();
if (apid != mpsoc::apid::EXE_SUCCESS) {
handleExeApidFailure(apid);
return RETURN_FAILED;
}
return RETURN_OK;
}
void PlocMPSoCHelper::handleExeApidFailure(uint16_t apid) {
if (apid == mpsoc::apid::EXE_FAILURE) {
triggerEvent(EXE_FAILURE_REPORT, internalState);
sif::warning << "PlocMPSoCHelper::handleExeApidFailure: Received execution failure "
<< "report" << std::endl;
}
else {
triggerEvent(EXE_INVALID_APID, apid, internalState);
sif::warning << "PlocMPSoCHelper::handleAckApidFailure: Expected execution report "
<< "but received space packet with apid " << std::hex << apid << std::endl;
}
}
ReturnValue_t PlocMPSoCHelper::handleTmReception(TmPacket* tmPacket, size_t remainingBytes) {
size_t readBytes = 0;
for(int retries = 0; retries < RETRIES; retries++) {
result = receive(tmPacket->getWholeData(), readBytes, remainingBytes);
if (result != RETURN_OK) {
return result;
}
remainingBytes = remainingBytes - readBytes;
if (remainingBytes == 0) {
break;
}
}
if (remainingBytes != 0) {
sif::warning << "PlocMPSoCHelper::handleTmReception: Failed to receive reply" << std::endl;
triggerEvent(MISSING_EXE, remainingBytes, internalState);
return RETURN_FAILED;
}
result = tmPacket->checkCrc();
if (result != RETURN_OK) {
sif::warning << "PlocMPSoCHelper::handleTmReception: CRC check failed" << std::endl;
return result;
}
}
ReturnValue_t PlocMPSoCHelper::receive(uint8_t* data, size_t* readBytes, size_t requestBytes) {
ReturnValue_t result = RETURN_OK;
result = uartComIF->requestReceiveMessage(comCookie, requestBytes);
if (result != RETURN_OK) {
sif::warning << "PlocMPSoCHelper::receive: Failed to request reply" << std::endl;
triggerEvent(MPSOC_HELPER_REQUESTING_REPLY_FAILED, result, internalState);
return RETURN_FAILED;
}
result = uartComIF->readReceivedMessage(comCookie, &data, readBytes);
if (result != RETURN_OK) {
sif::warning << "PlocMPSoCHelper::receive: Failed to read received message" << std::endl;
triggerEvent(MPSOC_HELPER_READING_REPLY_FAILED, result, internalState);
return RETURN_FAILED;
}
}

View File

@ -0,0 +1,143 @@
#ifndef BSP_Q7S_DEVICES_PLOCMPSOCHELPER_H_
#define BSP_Q7S_DEVICES_PLOCMPSOCHELPER_H_
#include <string>
#include "fsfw/osal/linux/BinarySemaphore.h"
#include "bsp_q7s/memory/SdCardManager.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw_hal/linux/uart/UartComIF.h"
#include "fsfw/devicehandlers/CookieIF.h"
#include "bsp_q7s/devices/devicedefinitions/PlocMPSoCDefinitions.h"
#include "MPSoCSequenceCount.h"
/**
* @brief Helper class for MPSoC of PLOC intended to accelerate large data transfers between
* MPSoC and OBC.
* @author J. Meier
*/
class PlocMPSoCHelper: public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF {
public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_MPSOC_HELPER;
//! [EXPORT] : [COMMENT] Flash write fails
static const Event FLASH_WRITE_FAILED = MAKE_EVENT(0, severity::LOW);
//! [EXPORT] : [COMMENT] Flash write successful
static const Event FLASH_WRITE_SUCCESSFUL = MAKE_EVENT(1, severity::LOW);
//! [EXPORT] : [COMMENT] Communication interface returned failure when trying to send the command ot the PLOC
//!P1: Return value returned by the communication interface sendMessage function
//!P2: Internal state of MPSoC helper
static const Event SENDING_COMMAND_FAILED = MAKE_EVENT(2, severity::LOW);
//! [EXPORT] : [COMMENT] Request receive message of communication interface failed
//!P1: Return value returned by the communication interface requestReceiveMessage function
//!P2: Internal state of MPSoC helper
static const Event MPSOC_HELPER_REQUESTING_REPLY_FAILED = MAKE_EVENT(3, severity::LOW);
//! [EXPORT] : [COMMENT] Reading receive message of communication interface failed
//!P1: Return value returned by the communication interface readingReceivedMessage function
//!P2: Internal state of MPSoC helper
static const Event MPSOC_HELPER_REQUESTING_REPLY_FAILED = MAKE_EVENT(4, severity::LOW);
//! [EXPORT] : [COMMENT] Did not receive acknowledgement report
//!P1: Number of bytes missing
//!P2: Internal state of MPSoC helper
static const Event MISSING_ACK = MAKE_EVENT(5, severity::LOW);
//! [EXPORT] : [COMMENT] Did not receive execution report
//!P1: Number of bytes missing
//!P2: Internal state of MPSoC helper
static const Event MISSING_EXE = MAKE_EVENT(6, severity::LOW);
//! [EXPORT] : [COMMENT] Received acknowledgement failure report
//!P1: Internal state of MPSoC
static const Event ACK_FAILURE_REPORT = MAKE_EVENT(7, severity::LOW);
//! [EXPORT] : [COMMENT] Received execution failure report
//!P1: Internal state of MPSoC
static const Event EXE_FAILURE_REPORT = MAKE_EVENT(8, severity::LOW);
//! [EXPORT] : [COMMENT] Expected acknowledgement report but received space packet with other apid
//!P1: Apid of received space packet
//!P2: Internal state of MPSoC
static const Event ACK_INVALID_APID = MAKE_EVENT(9, severity::LOW);
//! [EXPORT] : [COMMENT] Expected execution report but received space packet with other apid
//!P1: Apid of received space packet
//!P2: Internal state of MPSoC
static const Event EXE_INVALID_APID = MAKE_EVENT(10, severity::LOW);
PlocMPSoCHelper(object_id_t objectId);
virtual ~PlocMPSoCHelper();
ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
ReturnValue_t setComIF(DeviceCommunicationIF* communicationInterface_);
void setComCookie(CookieIF* comCookie_);
/**
* @brief Starts flash write sequence
*
* @param file File with data to write
*
* @return RETURN_OK if successful, otherwise error return value
*/
ReturnValue_t startFlashWrite(std::string file);
/**
* @brief Can be used to interrupt a running data transfer.
*/
void stopProcess();
/**
* @brief Sets the sequence count object responsible for the sequence count handling
*/
void setSequenceCount(MPSoCSequenceCount* sequenceCount_);
private:
static const uint8_t INTERFACE_ID = CLASS_ID::PLOC_MPSOC_HELPER;
// Maximum number of times the communication interface retries polling data from the reply
// buffer
static const int RETRIES = 3;
class FlashWrite {
public:
static const std::string file;
};
FlashWrite flashWrite;
enum class InternalState {
IDLE,
FLASH_WRITE,
FLASH_READ
};
InternalState internalState = InternalState::IDLE;
BinarySemaphore semaphore;
SdCardManager* sdcMan = nullptr;
uint8_t commandBuffer[mpsoc::MAX_COMMAND_SIZE];
bool terminate = false;
/**
* Communication interface of MPSoC responsible for low level access. Must be set by the
* MPSoC Handler.
*/
UartComIF* uartComIF = nullptr;
// Communication cookie. Must be set by the MPSoC Handler
CookieIF* comCookie = nullptr;
// Sequence count, must be set by Ploc MPSoC Handler
MPSoCSequenceCount* sequenceCount;
ReturnValue_t performFlashWrite();
ReturnValue_t sendCommand(TcBase* tc);
ReturnValue_t receive(uint8_t* data, size_t* readBytes, size_t requestBytes);
ReturnValue_t handleAck();
ReturnValue_t handleExe();
void handleAckApidFailure(uint16_t apid);
void handleExeApidFailure(uint16_t apid);
ReturnValue_t handleTmReception(TmPacket* tmPacket, size_t remainingBytes);
};
#endif /* BSP_Q7S_DEVICES_PLOCMPSOCHELPER_H_ */

View File

@ -81,7 +81,7 @@ ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueu
return EXECUTION_FINISHED;
}
case(StarTracker::SET_JSON_FILE_NAME): {
if (size > MAX_PATH_SIZE) {
if (size > config::MAX_PATH_SIZE) {
return FILE_PATH_TOO_LONG;
}
paramJsonFile = std::string(reinterpret_cast<const char*>(data), size);
@ -91,8 +91,8 @@ ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueu
break;
}
if (strHelperExecuting == true) {
return IMAGE_LOADER_EXECUTING;
if (strHelperExecuting) {
return STR_HELPER_EXECUTING;
}
result = checkMode(actionId);
@ -107,7 +107,7 @@ ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueu
if (result != RETURN_OK) {
return result;
}
if (size > MAX_PATH_SIZE + MAX_FILE_NAME) {
if (size > config::MAX_PATH_SIZE + config::MAX_FILENAME_SIZE) {
return FILE_PATH_TOO_LONG;
}
result = strHelper->startImageUpload(
@ -123,7 +123,7 @@ ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueu
if (result != RETURN_OK) {
return result;
}
if (size > MAX_PATH_SIZE) {
if (size > config::MAX_PATH_SIZE) {
return FILE_PATH_TOO_LONG;
}
result = strHelper->startImageDownload(
@ -160,7 +160,7 @@ ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueu
return EXECUTION_FINISHED;
}
case(StarTracker::CHANGE_DOWNLOAD_FILE): {
if (size > MAX_FILE_NAME) {
if (size > config::MAX_FILENAME_SIZE) {
return FILENAME_TOO_LONG;
}
strHelper->setDownloadImageName(
@ -168,14 +168,14 @@ ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueu
return EXECUTION_FINISHED;
}
case(StarTracker::CHANGE_FPGA_DOWNLOAD_FILE): {
if (size > MAX_FILE_NAME) {
if (size > config::MAX_FILENAME_SIZE) {
return FILENAME_TOO_LONG;
}
strHelper->setDownloadFpgaImage(std::string(reinterpret_cast<const char*>(data), size));
return EXECUTION_FINISHED;
}
case(StarTracker::SET_READ_FILENAME): {
if (size > MAX_FILE_NAME) {
if (size > config::MAX_FILENAME_SIZE) {
return FILENAME_TOO_LONG;
}
strHelper->setDownloadImageName(
@ -187,7 +187,7 @@ ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueu
if (result != RETURN_OK) {
return result;
}
if (size > MAX_PATH_SIZE) {
if (size > config::MAX_PATH_SIZE) {
return FILE_PATH_TOO_LONG;
}
result = executeFpgaDownloadCommand(data, size);
@ -202,7 +202,7 @@ ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueu
if (result != RETURN_OK) {
return result;
}
if (size > MAX_PATH_SIZE + MAX_FILE_NAME) {
if (size > config::MAX_PATH_SIZE + config::MAX_FILENAME_SIZE) {
return FILE_PATH_TOO_LONG;
}
result = strHelper->startFpgaUpload(std::string(reinterpret_cast<const char*>(data), size));
@ -1170,7 +1170,7 @@ ReturnValue_t StarTrackerHandler::executeWriteCommand(const uint8_t* commandData
<< std::endl;
return result;
}
if (commandDataLen - sizeof(address) - sizeof(region) > MAX_PATH_SIZE) {
if (commandDataLen - sizeof(address) - sizeof(region) > config::MAX_PATH_SIZE) {
sif::warning << "StarTrackerHandler::executeWriteCommand: Received command with invalid"
<< " path and filename" << std::endl;
return FILE_PATH_TOO_LONG;
@ -1211,7 +1211,7 @@ ReturnValue_t StarTrackerHandler::executeFpgaDownloadCommand(const uint8_t* comm
<< std::endl;
return result;
}
if (commandDataLen - sizeof(position) - sizeof(length) > MAX_PATH_SIZE) {
if (commandDataLen - sizeof(position) - sizeof(length) > config::MAX_PATH_SIZE) {
sif::warning << "StarTrackerHandler::executeFpgaDownloadCommand: Received command with "
" invalid path and filename" << std::endl;
return FILE_PATH_TOO_LONG;
@ -1253,7 +1253,7 @@ ReturnValue_t StarTrackerHandler::executeReadCommand(const uint8_t* commandData,
<< std::endl;
return result;
}
if (commandDataLen - sizeof(address) - sizeof(region) - sizeof(length) > MAX_PATH_SIZE) {
if (commandDataLen - sizeof(address) - sizeof(region) - sizeof(length) > config::MAX_PATH_SIZE) {
sif::warning << "StarTrackerHandler::executeReadCommand: Received command with invalid"
<< " path and filename" << std::endl;
return FILE_PATH_TOO_LONG;
@ -1397,7 +1397,7 @@ ReturnValue_t StarTrackerHandler::prepareDownloadCentroidCommand(const uint8_t*
ReturnValue_t StarTrackerHandler::prepareUploadCentroidCommand(const uint8_t* commandData,
size_t commandDataLen) {
if (commandDataLen > MAX_PATH_SIZE) {
if (commandDataLen > config::MAX_PATH_SIZE) {
return FILE_PATH_TOO_LONG;
}
ReturnValue_t result = RETURN_OK;
@ -1616,7 +1616,7 @@ void StarTrackerHandler::prepareErrorResetRequest() {
ReturnValue_t StarTrackerHandler::prepareParamCommand(const uint8_t* commandData,
size_t commandDataLen, ArcsecJsonParamBase& paramSet) {
ReturnValue_t result = RETURN_OK;
if (commandDataLen > MAX_PATH_SIZE) {
if (commandDataLen > config::MAX_PATH_SIZE) {
return FILE_PATH_TOO_LONG;
}
std::string fullName(reinterpret_cast<const char*>(commandData), commandDataLen);

View File

@ -78,8 +78,8 @@ private:
static const ReturnValue_t REPLY_TOO_SHORT = MAKE_RETURN_CODE(0xB0);
//! [EXPORT] : [COMMENT] Received reply with invalid CRC
static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xB1);
//! [EXPORT] : [COMMENT] Image loader executing
static const ReturnValue_t IMAGE_LOADER_EXECUTING = MAKE_RETURN_CODE(0xB2);
//! [EXPORT] : [COMMENT] Star tracker helper class currently executing a command
static const ReturnValue_t STR_HELPER_EXECUTING = MAKE_RETURN_CODE(0xB2);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::STR_HANDLER;

View File

@ -1,7 +1,6 @@
#include "StrHelper.h"
#include "mission/utility/Timestamp.h"
#include "bsp_q7s/memory/FilesystemHelper.h"
#include <fstream>
#include <filesystem>
@ -117,7 +116,7 @@ void StrHelper::setComCookie(CookieIF* comCookie_) {
}
ReturnValue_t StrHelper::startImageUpload(std::string fullname) {
ReturnValue_t result = checkPath(fullname);
ReturnValue_t result = FilesystemHelper::checkPath(fullname);
if (result != RETURN_OK) {
return result;
}
@ -132,7 +131,7 @@ ReturnValue_t StrHelper::startImageUpload(std::string fullname) {
}
ReturnValue_t StrHelper::startImageDownload(std::string path) {
ReturnValue_t result = checkPath(path);
ReturnValue_t result = FilesystemHelper::checkPath(path);
if (result != RETURN_OK) {
return result;
}
@ -164,7 +163,7 @@ void StrHelper::setDownloadFpgaImage(std::string filename) {
ReturnValue_t StrHelper::startFlashWrite(std::string fullname, uint8_t region,
uint32_t address) {
ReturnValue_t result = checkPath(fullname);
ReturnValue_t result = FilesystemHelper::checkPath(fullname);
if (result != RETURN_OK) {
return result;
}
@ -182,7 +181,7 @@ ReturnValue_t StrHelper::startFlashWrite(std::string fullname, uint8_t region,
ReturnValue_t StrHelper::startFlashRead(std::string path, uint8_t region,
uint32_t address, uint32_t length) {
ReturnValue_t result = checkPath(path);
ReturnValue_t result = FilesystemHelper::checkPath(path);
if (result != RETURN_OK) {
return result;
}
@ -683,20 +682,3 @@ ReturnValue_t StrHelper::checkFpgaActionReply(uint32_t expectedPosition,
}
return result;
}
ReturnValue_t StrHelper::checkPath(std::string name) {
if (name.substr(0, sizeof(SdCardManager::SD_0_MOUNT_POINT))
== std::string(SdCardManager::SD_0_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
sif::warning << "StrHelper::checkPath: SD card 0 not mounted" << std::endl;
return SD_NOT_MOUNTED;
}
} else if (name.substr(0, sizeof(SdCardManager::SD_1_MOUNT_POINT))
== std::string(SdCardManager::SD_1_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
sif::warning << "StrHelper::checkPath: SD card 1 not mounted" << std::endl;
return SD_NOT_MOUNTED;
}
}
return RETURN_OK;
}

View File

@ -60,8 +60,8 @@ public:
//!P1: Position of upload or download packet for which no reply was sent
static const Event STR_HELPER_NO_REPLY = MAKE_EVENT(14, severity::LOW);
//! [EXPORT] : [COMMENT] Error during decoding of received reply occurred
//P1: Return value of decoding function
//P2: Position of upload/download packet, or address of flash write/read request
//!P1: Return value of decoding function
//!P2: Position of upload/download packet, or address of flash write/read request
static const Event STR_HELPER_DEC_ERROR = MAKE_EVENT(15, severity::LOW);
//! [EXPORT] : [COMMENT] Position mismatch
//!P1: The expected position and thus the position for which the image upload/download failed
@ -163,8 +163,6 @@ private:
static const uint8_t INTERFACE_ID = CLASS_ID::STR_HELPER;
//! [EXPORT] : [COMMENT] SD card specified in path string not mounted
static const ReturnValue_t SD_NOT_MOUNTED = MAKE_RETURN_CODE(0xA0);
//! [EXPORT] : [COMMENT] Specified file does not exist on filesystem
static const ReturnValue_t FILE_NOT_EXISTS = MAKE_RETURN_CODE(0xA1);
//! [EXPORT] : [COMMENT] Specified path does not exist
@ -382,13 +380,6 @@ private:
* @param expectedLength The expected length field in the reply
*/
ReturnValue_t checkFpgaActionReply(uint32_t expectedPosition, uint32_t expectedLength);
/**
* @brief Checks if a path points to an sd card and whether the SD card is monuted.
*
* @return SD_NOT_MOUNTED id SD card is not mounted, otherwise RETURN_OK
*/
ReturnValue_t checkPath(std::string name);
};
#endif /* BSP_Q7S_DEVICES_STRHELPER_H_ */

View File

@ -0,0 +1,34 @@
#include "FilesystemHelper.h"
#include "bsp_q7s/memory/SdCardManager.h"
FilesystemHelper::FilesystemHelper() {
}
FilesystemHelper::~FilesystemHelper() {
}
ReturnValue_t FilesystemHelper::checkPath(std::string path) {
SdCardManager sdcMan = SdCardManager::instance();
if (sdcMan == nullptr) {
sif::warning << "FilesystemHelper::checkPath: Invalid SD card manager" << std::endl;
return RETURN_FAILED;
}
if (path.substr(0, sizeof(SdCardManager::SD_0_MOUNT_POINT))
== std::string(SdCardManager::SD_0_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
sif::warning << "FilesystemHelper::checkPath: SD card 0 not mounted" << std::endl;
return SD_NOT_MOUNTED;
}
} else if (path.substr(0, sizeof(SdCardManager::SD_1_MOUNT_POINT))
== std::string(SdCardManager::SD_1_MOUNT_POINT)) {
if (!sdcMan->isSdCardMounted(sd::SLOT_0)) {
sif::warning << "FilesystemHelper::checkPath: SD card 1 not mounted" << std::endl;
return SD_NOT_MOUNTED;
}
}
return RETURN_OK;
}
ReturnValue_t FilesystemHelper::fileExists(std::string file) {
}

View File

@ -0,0 +1,47 @@
#ifndef BSP_Q7S_MEMORY_FILESYSTEMHELPER_H_
#define BSP_Q7S_MEMORY_FILESYSTEMHELPER_H_
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
/**
* @brief This class implements often used functions concerning the file system management.
*
* @author J. Meier
*/
class FilesystemHelper : public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FILE_SYSTEM_HELPER;
//! [EXPORT] : [COMMENT] SD card specified with path string not mounted
static const ReturnValue_t SD_NOT_MOUNTED = MAKE_RETURN_CODE(0xA0);
//! [EXPORT] : [COMMENT] Specified file does not exist on filesystem
static const ReturnValue_t FILE_NOT_EXISTS = MAKE_RETURN_CODE(0xA1);
FilesystemHelper();
virtual ~FilesystemHelper();
/**
* @brief In case the path points to a directory on the sd card the function checks if the
* appropriate SD card is mounted.
*
* @param path Path to check
*
* @return RETURN_OK if path points to SD card and the appropriate SD card is mounted or if
* path does not point to SD card.
* Return error code if path points to SD card and the corresponding SD card is not
* mounted.
*/
static const ReturnValue_t checkPath(std::string path);
/**
* @brief Checks if the file exists on the filesystem.
*
* param file File to check
*
* @return RETURN_OK if fiel exists, otherwise return error code.
*/
static const ReturnValue_t fileExists(std::string file);
};
#endif /* BSP_Q7S_MEMORY_FILESYSTEMHELPER_H_ */

View File

@ -15,6 +15,7 @@ enum commonClassIds: uint8_t {
STR_HANDLER, //STRH
PLOC_MPSOC_HANDLER, //PLMP
MPSOC_CMD, //MPCMD
MPSOC_TM, //MPTM
PLOC_SUPERVISOR_HANDLER, //PLSV
SUS_HANDLER, //SUSS
CCSDS_IP_CORE_BRIDGE, //IPCI
@ -27,6 +28,8 @@ enum commonClassIds: uint8_t {
CCSDS_HANDLER, //CCSDS
ARCSEC_JSON_BASE, //JSONBASE
NVM_PARAM_BASE, //NVMB
FILE_SYSTEM_HELPER, //FSHLP
PLOC_MPSOC_HELPER, // PLMPHLP
COMMON_CLASS_ID_END // [EXPORT] : [END]
};

View File

@ -19,6 +19,7 @@ enum: uint8_t {
PLOC_MEMORY_DUMPER = 118,
PDEC_HANDLER = 119,
STR_HELPER = 120,
PLOC_MPSOC_HELPER = 121,
COMMON_SUBSYSTEM_ID_END
};
}

View File

@ -131,8 +131,9 @@ namespace config {
/* Add mission configuration flags here */
static constexpr uint32_t OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE = 50;
static constexpr uint32_t PLOC_UPDATER_QUEUE_SIZE = 50;
static constexpr uint32_t STR_IMG_HELPER_QUEUE_SIZE = 50;
/* Global config values to check validity of received file path strings and filenames */
static constexpr uint32_t MAX_PATH_SIZE = 100;
static constexpr uint32_t MAX_FILENAME_SIZE = 50;
static constexpr uint8_t LIVE_TM = 0;
#ifdef __cplusplus

2
tmtc

@ -1 +1 @@
Subproject commit 734dc5aef88d9fef4ad59817b6ea315db954205c
Subproject commit 5816f05ccf8971f3cf2dd1d603dd3f5a33f6f504