build configuration for trenz te0720-1cfa

This commit is contained in:
Jakob Meier
2022-03-17 14:28:32 +01:00
parent b0b2854d44
commit 9dc124004d
41 changed files with 557 additions and 29 deletions

View File

@ -339,6 +339,8 @@ void SpiTestClass::performMax1227Test() {
std::string deviceName = "";
#elif defined(EGSE)
std::string deviceName = "";
#elif defined(TE0720_1CFA)
std::string deviceName = "";
#endif
int fd = 0;
UnixFileGuard fileHelper(deviceName, &fd, O_RDWR, "SpiComIF::initializeInterface");

View File

@ -4,4 +4,5 @@ if(EIVE_BUILD_GPSD_GPS_HANDLER)
)
endif()
add_subdirectory(ploc)
add_subdirectory(startracker)

View File

@ -0,0 +1,338 @@
#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_PLOCMPSOCDEFINITIONS_H_
#define MISSION_DEVICES_DEVICEDEFINITIONS_PLOCMPSOCDEFINITIONS_H_
#include <fsfw/tmtcpacket/SpacePacket.h>
#include <fsfw/globalfunctions/CRC.h>
#include <fsfw/serialize/SerializeAdapter.h>
namespace mpsoc {
static const DeviceCommandId_t NONE = 0;
static const DeviceCommandId_t TC_MEM_WRITE = 1;
static const DeviceCommandId_t TC_MEM_READ = 2;
static const DeviceCommandId_t ACK_REPORT = 3;
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;
static const uint16_t SIZE_TM_MEM_READ_REPORT = 18;
/**
* SpacePacket apids of PLOC telecommands and telemetry.
*/
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;
static const uint16_t ACK_SUCCESS = 0x400;
static const uint16_t ACK_FAILURE = 0x401;
static const uint16_t EXE_SUCCESS = 0x402;
static const uint16_t EXE_FAILURE = 0x403;
}
/** Offset from first byte in space packet to first byte of data field */
static const uint8_t DATA_FIELD_OFFSET = 6;
static const size_t MEM_READ_RPT_LEN_OFFSET = 10;
/**
* The size of payload data which will be forwarded to the requesting object. e.g. PUS Service
* 8.
*/
static const uint8_t SIZE_MEM_READ_RPT_FIX = 6;
static const size_t MAX_FILENAME_SIZE = 256;
/**
* PLOC space packet length for fixed size packets. This is the size of the whole packet data
* field. For the length field in the space packet this size will be substracted by one.
*/
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 = SpacePacket::PACKET_MAX_SIZE * 3;
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.
*/
class TcBase : public SpacePacket, public HasReturnvaluesIF {
public:
// Initial length field of space packet. Will always be updated when packet is created.
static const uint16_t INIT_LENGTH = 1;
static const uint8_t INTERFACE_ID = CLASS_ID::MPSOC_CMD;
//! [EXPORT] : [COMMENT] Received command with invalid length
static const ReturnValue_t INVALID_LENGTH = MAKE_RETURN_CODE(0xC0);
/**
* @brief Constructor
*
* @param sequenceCount Sequence count of space packet which will be incremented with each
* sent and received packets.
*/
TcBase(uint16_t apid, uint16_t sequenceCount) :
SpacePacket(INIT_LENGTH, true, apid, sequenceCount) {
}
/**
* @brief Function to initialize the space packet
*
* @param commandData Pointer to command specific data
* @param commandDataLen Length of command data
*
* @return RETURN_OK if packet creation was successful, otherwise error return value
*/
virtual ReturnValue_t createPacket(const uint8_t* commandData, size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
result = initPacket(commandData, commandDataLen);
if (result != RETURN_OK) {
return result;
}
result = addCrc();
if (result != RETURN_OK) {
return result;
}
return result;
}
protected:
/**
* @brief Must be overwritten by the child class to define the command specific parameters
*
* @param commandData Pointer to received command data
* @param commandDataLen Length of received command data
*/
virtual ReturnValue_t initPacket(const uint8_t* commandData, size_t commandDataLen) {
return RETURN_OK;
}
/**
* @brief Calculates and adds the CRC
*/
ReturnValue_t addCrc() {
ReturnValue_t result = RETURN_OK;
size_t serializedSize = 0;
uint32_t full_size = getFullSize();
uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE);
result = SerializeAdapter::serialize<uint16_t>(&crc,
this->localData.byteStream + full_size - CRC_SIZE, &serializedSize, sizeof(crc),
SerializeIF::Endianness::BIG);
if (result != RETURN_OK) {
sif::debug << "TcBase::addCrc: Failed to serialize crc field" << std::endl;
}
return result;
}
};
/**
* @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 != receivedCrc) {
return CRC_FAILURE;
}
return RETURN_OK;
}
};
/**
* @brief This class helps to build the memory read command for the PLOC.
*/
class TcMemRead: public TcBase {
public:
/**
* @brief Constructor
*/
TcMemRead(uint16_t sequenceCount) :
TcBase(apid::TC_MEM_READ, sequenceCount) {
this->setPacketDataLength(PACKET_LENGTH);
}
uint16_t getMemLen() const {
return memLen;
}
protected:
ReturnValue_t initPacket(const uint8_t* commandData, size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
result = lengthCheck(commandDataLen);
if (result != RETURN_OK) {
return result;
}
std::memcpy(this->localData.fields.buffer, commandData, MEM_ADDRESS_SIZE);
std::memcpy(this->localData.fields.buffer + MEM_ADDRESS_SIZE,
commandData + MEM_ADDRESS_SIZE, MEM_LEN_SIZE);
size_t size = sizeof(memLen);
const uint8_t* memLenPtr = commandData + MEM_ADDRESS_SIZE;
result = SerializeAdapter::deSerialize(&memLen, &memLenPtr, &size,
SerializeIF::Endianness::BIG);
if(result != RETURN_OK) {
return result;
}
return result;
}
private:
static const size_t COMMAND_LENGTH = 6;
static const size_t MEM_ADDRESS_SIZE = 4;
static const size_t MEM_LEN_SIZE = 2;
static const uint16_t PACKET_LENGTH = 7;
uint16_t memLen = 0;
ReturnValue_t lengthCheck(size_t commandDataLen) {
if (commandDataLen != COMMAND_LENGTH){
return INVALID_LENGTH;
}
return RETURN_OK;
}
};
/**
* @brief This class helps to generate the space packet to write data to a memory address within
* the PLOC.
*/
class TcMemWrite: public TcBase {
public:
/**
* @brief Constructor
*/
TcMemWrite(uint16_t sequenceCount) : TcBase(apid::TC_MEM_WRITE, sequenceCount) {
}
protected:
ReturnValue_t initPacket(const uint8_t* commandData, size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
result = lengthCheck(commandDataLen);
if (result != RETURN_OK) {
return result;
}
std::memcpy(this->localData.fields.buffer, commandData, commandDataLen);
uint16_t memLen = *(commandData + MEM_ADDRESS_SIZE) << 8
| *(commandData + MEM_ADDRESS_SIZE + 1);
this->setPacketDataLength(memLen * 4 + FIX_LENGTH - 1);
return result;
}
private:
// Min length consists of 4 byte address, 2 byte mem length field, 4 byte data (1 word)
static const size_t MIN_COMMAND_DATA_LENGTH = 10;
static const size_t MEM_ADDRESS_SIZE = 4;
static const size_t FIX_LENGTH = 8;
ReturnValue_t lengthCheck(size_t commandDataLen) {
if (commandDataLen < MIN_COMMAND_DATA_LENGTH) {
return INVALID_LENGTH;
}
return RETURN_OK;
}
};
/**
* @brief Class to help creation of flash fopen command.
*/
class FlashFopen : public TcBase {
public:
FlashFopen(uint16_t sequenceCount) :
TcBase(apid::TC_FLASHFOPEN, sequenceCount) {
}
static const char APPEND = 'a';
static const char WRITE = 'w';
static const char READ = 'r';
ReturnValue_t createPacket(std::string filename, char accessMode) {
ReturnValue_t result = RETURN_OK;
size_t nameSize = filename.size();
std::memcpy(this->getPacketData(), filename.c_str(),
nameSize);
std::memcpy(this->getPacketData() + nameSize, &accessMode,
sizeof(accessMode));
result = addCrc();
if (result != RETURN_OK) {
return result;
}
this->setPacketDataLength(nameSize + CRC_SIZE - 1);
return result;
}
};
/**
* @brief Class to help creation of flash fclose command.
*/
class FlashFclose: public TcBase {
public:
FlashFclose(uint16_t sequenceCount) :
TcBase(apid::TC_FLASHFCLOSE, sequenceCount) {
}
ReturnValue_t createPacket(std::string filename) {
ReturnValue_t result = RETURN_OK;
size_t nameSize = filename.size();
std::memcpy(this->getPacketData(), filename.c_str(), nameSize);
result = addCrc();
if (result != RETURN_OK) {
return result;
}
this->setPacketDataLength(nameSize + CRC_SIZE - 1);
return result;
}
};
/**
* @brief Class to build flash write space packet.
*/
class FlashWrite : public TcBase {
public:
FlashWrite(uint16_t sequenceCount) :
TcBase(apid::TC_FLASHWRITE, sequenceCount) {
}
ReturnValue_t createPacket(uint8_t* writeData, uint32_t writeLen) {
if (writeLen > MAX_DATA_SIZE) {
sif::debug << "FlashWrite::createPacket: Command data too big" << std::endl;
return RETURN_FAILED;
}
std::memcpy(this->getPacketData(), writeData, writeLen);
this->setPacketDataLength(static_cast<uint16_t>(writeLen + CRC_SIZE - 1));
return RETURN_OK;
}
};
}
#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_PLOCMPSOCDEFINITIONS_H_ */

View File

@ -0,0 +1,28 @@
#ifndef BSP_Q7S_DEVICES_DEVICEDEFINITIONS_PLOCMEMDUMPDEFINITIONS_H_
#define BSP_Q7S_DEVICES_DEVICEDEFINITIONS_PLOCMEMDUMPDEFINITIONS_H_
#include <fsfw/src/fsfw/serialize/SerialLinkedListAdapter.h>
class MemoryParams : public SerialLinkedListAdapter<SerializeIF> {
public:
/**
* @brief Constructor
* @param startAddress Start of address range to dump
* @param endAddress End of address range to dump
*/
MemoryParams(uint32_t startAddress, uint32_t endAddress)
: startAddress(startAddress), endAddress(endAddress) {
setLinks();
}
private:
void setLinks() {
setStart(&startAddress);
startAddress.setNext(&endAddress);
}
SerializeElement<uint32_t> startAddress;
SerializeElement<uint32_t> endAddress;
};
#endif /* BSP_Q7S_DEVICES_DEVICEDEFINITIONS_PLOCMEMDUMPDEFINITIONS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
target_sources(${OBSW_NAME} PRIVATE
PlocSupervisorHandler.cpp
PlocUpdater.cpp
PlocMemoryDumper.cpp
PlocMPSoCHandler.cpp
PlocMPSoCHelper.cpp
)

View File

@ -0,0 +1,589 @@
#include "OBSWConfig.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, PlocMPSoCHelper* plocMPSoCHelper) :
DeviceHandlerBase(objectId, uartComIFid, comCookie), plocMPSoCHelper(plocMPSoCHelper) {
if (comCookie == NULL) {
sif::error << "PlocMPSoCHandler: Invalid com cookie" << std::endl;
}
eventQueue = QueueFactory::instance()->createMessageQueue(EventMessage::EVENT_MESSAGE_SIZE * 5);
}
PlocMPSoCHandler::~PlocMPSoCHandler() {
}
ReturnValue_t PlocMPSoCHandler::initialize() {
ReturnValue_t result = RETURN_OK;
result = DeviceHandlerBase::initialize();
if (result != RETURN_OK) {
return result;
}
uartComIf = dynamic_cast<UartComIF*>(communicationInterface);
if (uartComIf == nullptr) {
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::MPSOC_FLASH_WRITE_FAILED),
event::getEventId(PlocMPSoCHelper::MPSOC_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;
}
void PlocMPSoCHandler::performOperationHook() {
EventMessage event;
for (ReturnValue_t result = eventQueue->receiveMessage(&event);
result == RETURN_OK; result = eventQueue->receiveMessage(&event)) {
switch (event.getMessageId()) {
case EventMessage::EVENT_MESSAGE:
handleEvent(&event);
break;
default:
sif::debug << "PlocMPSoCHandler::performOperationHook: Did not subscribe to this event"
<< " message" << std::endl;
break;
}
}
}
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_FILENAME_SIZE) {
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(){
#if OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP == 1
setMode(MODE_NORMAL);
#else
setMode(_MODE_TO_ON);
#endif
}
void PlocMPSoCHandler::doShutDown(){
setMode(_MODE_POWER_DOWN);
}
ReturnValue_t PlocMPSoCHandler::buildNormalDeviceCommand(
DeviceCommandId_t * id) {
return NOTHING_TO_SEND;
}
ReturnValue_t PlocMPSoCHandler::buildTransitionDeviceCommand(
DeviceCommandId_t * id){
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PlocMPSoCHandler::buildCommandFromCommand(
DeviceCommandId_t deviceCommand, const uint8_t * commandData,
size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
switch(deviceCommand) {
case(mpsoc::TC_MEM_WRITE): {
result = prepareTcMemWriteCommand(commandData, commandDataLen);
break;
}
case(mpsoc::TC_MEM_READ): {
result = prepareTcMemReadCommand(commandData, commandDataLen);
break;
}
default:
sif::debug << "PlocMPSoCHandler::buildCommandFromCommand: Command not implemented" << std::endl;
result = DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
break;
}
if (result == RETURN_OK) {
/**
* Flushing the receive buffer to make sure there are no data left from a faulty reply.
*/
uartComIf->flushUartRxBuffer(comCookie);
}
return result;
}
void PlocMPSoCHandler::fillCommandAndReplyMap() {
this->insertInCommandMap(mpsoc::TC_MEM_WRITE);
this->insertInCommandMap(mpsoc::TC_MEM_READ);
this->insertInReplyMap(mpsoc::ACK_REPORT, 1, nullptr, mpsoc::SIZE_ACK_REPORT);
this->insertInReplyMap(mpsoc::EXE_REPORT, 3, nullptr, mpsoc::SIZE_EXE_REPORT);
this->insertInReplyMap(mpsoc::TM_MEMORY_READ_REPORT, 2, nullptr, mpsoc::SIZE_TM_MEM_READ_REPORT);
}
ReturnValue_t PlocMPSoCHandler::scanForReply(const uint8_t *start,
size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) {
ReturnValue_t result = RETURN_OK;
uint16_t apid = (*(start) << 8 | *(start + 1)) & APID_MASK;
switch(apid) {
case(mpsoc::apid::ACK_SUCCESS):
*foundLen = mpsoc::SIZE_ACK_REPORT;
*foundId = mpsoc::ACK_REPORT;
break;
case(mpsoc::apid::ACK_FAILURE):
*foundLen = mpsoc::SIZE_ACK_REPORT;
*foundId = mpsoc::ACK_REPORT;
break;
case(mpsoc::apid::TM_MEMORY_READ_REPORT):
*foundLen = tmMemReadReport.rememberRequestedSize;
*foundId = mpsoc::TM_MEMORY_READ_REPORT;
break;
case(mpsoc::apid::EXE_SUCCESS):
*foundLen = mpsoc::SIZE_EXE_REPORT;
*foundId = mpsoc::EXE_REPORT;
break;
case(mpsoc::apid::EXE_FAILURE):
*foundLen = mpsoc::SIZE_EXE_REPORT;
*foundId = mpsoc::EXE_REPORT;
break;
default: {
sif::debug << "PlocMPSoCHandler::scanForReply: Reply has invalid apid" << std::endl;
*foundLen = remainingSize;
return INVALID_APID;
}
}
sequenceCount++;
uint16_t recvSeqCnt = (*(start + 2) << 8 | *(start + 3)) & PACKET_SEQUENCE_COUNT_MASK;
if (recvSeqCnt != sequenceCount) {
triggerEvent(MPSOC_HANDLER_SEQ_CNT_MISMATCH, sequenceCount, recvSeqCnt);
sequenceCount = recvSeqCnt;
}
return result;
}
ReturnValue_t PlocMPSoCHandler::interpretDeviceReply(DeviceCommandId_t id,
const uint8_t *packet) {
ReturnValue_t result = RETURN_OK;
switch (id) {
case mpsoc::ACK_REPORT: {
result = handleAckReport(packet);
break;
}
case (mpsoc::TM_MEMORY_READ_REPORT): {
result = handleMemoryReadReport(packet);
break;
}
case (mpsoc::EXE_REPORT): {
result = handleExecutionReport(packet);
break;
}
default: {
sif::debug << "PlocMPSoCHandler::interpretDeviceReply: Unknown device reply id" << std::endl;
return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY;
}
}
return result;
}
void PlocMPSoCHandler::setNormalDatapoolEntriesInvalid(){
}
uint32_t PlocMPSoCHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo){
return 500;
}
ReturnValue_t PlocMPSoCHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) {
return HasReturnvaluesIF::RETURN_OK;
}
void PlocMPSoCHandler::handleEvent(EventMessage* eventMessage) {
object_id_t objectId = eventMessage->getReporter();
switch(objectId){
case objects::PLOC_MPSOC_HELPER: {
plocMPSoCHelperExecuting = false;
break;
}
default:
sif::debug << "PlocMPSoCHandler::handleEvent: Did not subscribe to this event"
<< std::endl;
break;
}
}
ReturnValue_t PlocMPSoCHandler::prepareTcMemWriteCommand(const uint8_t * commandData,
size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
sequenceCount++;
mpsoc::TcMemWrite tcMemWrite(sequenceCount);
result = tcMemWrite.createPacket(commandData, commandDataLen);
if (result != RETURN_OK) {
return result;
}
copyToCommandBuffer(&tcMemWrite);
return RETURN_OK;
}
ReturnValue_t PlocMPSoCHandler::prepareTcMemReadCommand(const uint8_t * commandData,
size_t commandDataLen) {
ReturnValue_t result = RETURN_OK;
sequenceCount++;
mpsoc::TcMemRead tcMemRead(sequenceCount);
result = tcMemRead.createPacket(commandData, commandDataLen);
if (result != RETURN_OK) {
return result;
}
copyToCommandBuffer(&tcMemRead);
tmMemReadReport.rememberRequestedSize = tcMemRead.getMemLen() * 4 + TmMemReadReport::FIX_SIZE;
return RETURN_OK;
}
void PlocMPSoCHandler::copyToCommandBuffer(mpsoc::TcBase* tc) {
if (tc == nullptr) {
sif::debug << "PlocMPSoCHandler::copyToCommandBuffer: Invalid TC" << std::endl;
}
memcpy(commandBuffer, tc->getWholeData(), tc->getFullSize());
rawPacket = commandBuffer;
rawPacketLen = tc->getFullSize();
nextReplyId = mpsoc::ACK_REPORT;
}
ReturnValue_t PlocMPSoCHandler::verifyPacket(const uint8_t* start, size_t foundLen) {
uint16_t receivedCrc = *(start + foundLen - 2) << 8 | *(start + foundLen - 1);
uint16_t recalculatedCrc = CRC::crc16ccitt(start, foundLen - 2);
if (receivedCrc != recalculatedCrc) {
return CRC_FAILURE;
}
return RETURN_OK;
}
ReturnValue_t PlocMPSoCHandler::handleAckReport(const uint8_t* data) {
ReturnValue_t result = RETURN_OK;
result = verifyPacket(data, mpsoc::SIZE_ACK_REPORT);
if(result == CRC_FAILURE) {
sif::error << "PlocMPSoCHandler::handleAckReport: CRC failure" << std::endl;
nextReplyId = mpsoc::NONE;
replyRawReplyIfnotWiretapped(data, mpsoc::SIZE_ACK_REPORT);
triggerEvent(MPSOC_HANDLER_CRC_FAILURE);
sendFailureReport(mpsoc::ACK_REPORT, CRC_FAILURE);
disableAllReplies();
return IGNORE_REPLY_DATA;
}
uint16_t apid = (*(data) << 8 | *(data + 1)) & APID_MASK;
switch(apid) {
case mpsoc::apid::ACK_FAILURE: {
//TODO: Interpretation of status field in acknowledgment report
sif::debug << "PlocMPSoCHandler::handleAckReport: Received Ack failure report" << std::endl;
DeviceCommandId_t commandId = getPendingCommand();
if (commandId != DeviceHandlerIF::NO_COMMAND_ID) {
triggerEvent(ACK_FAILURE, commandId);
}
sendFailureReport(mpsoc::ACK_REPORT, RECEIVED_ACK_FAILURE);
disableAllReplies();
nextReplyId = mpsoc::NONE;
result = IGNORE_REPLY_DATA;
break;
}
case mpsoc::apid::ACK_SUCCESS: {
setNextReplyId();
break;
}
default: {
sif::debug << "PlocMPSoCHandler::handleAckReport: Invalid APID in Ack report" << std::endl;
result = RETURN_FAILED;
break;
}
}
return result;
}
ReturnValue_t PlocMPSoCHandler::handleExecutionReport(const uint8_t* data) {
ReturnValue_t result = RETURN_OK;
result = verifyPacket(data, mpsoc::SIZE_EXE_REPORT);
if(result == CRC_FAILURE) {
sif::error << "PlocMPSoCHandler::handleExecutionReport: CRC failure" << std::endl;
nextReplyId = mpsoc::NONE;
return result;
}
uint16_t apid = (*(data) << 8 | *(data + 1)) & APID_MASK;
switch (apid) {
case (mpsoc::apid::EXE_SUCCESS): {
break;
}
case (mpsoc::apid::EXE_FAILURE): {
//TODO: Interpretation of status field in execution report
sif::error << "PlocMPSoCHandler::handleExecutionReport: Received execution failure report"
<< std::endl;
DeviceCommandId_t commandId = getPendingCommand();
if (commandId != DeviceHandlerIF::NO_COMMAND_ID) {
triggerEvent(EXE_FAILURE, commandId);
}
else {
sif::debug << "PlocMPSoCHandler::handleExecutionReport: Unknown command id" << std::endl;
}
sendFailureReport(mpsoc::EXE_REPORT, RECEIVED_EXE_FAILURE);
disableExeReportReply();
result = IGNORE_REPLY_DATA;
break;
}
default: {
sif::error << "PlocMPSoCHandler::handleExecutionReport: Unknown APID" << std::endl;
result = RETURN_FAILED;
break;
}
}
nextReplyId = mpsoc::NONE;
return result;
}
ReturnValue_t PlocMPSoCHandler::handleMemoryReadReport(const uint8_t* data) {
ReturnValue_t result = RETURN_OK;
result = verifyPacket(data, tmMemReadReport.rememberRequestedSize);
if(result == CRC_FAILURE) {
sif::error << "PlocMPSoCHandler::handleMemoryReadReport: Memory read report has invalid crc"
<< std::endl;
}
uint16_t memLen = *(data + mpsoc::MEM_READ_RPT_LEN_OFFSET) << 8
| *(data + mpsoc::MEM_READ_RPT_LEN_OFFSET + 1);
/** Send data to commanding queue */
handleDeviceTM(data + mpsoc::DATA_FIELD_OFFSET, mpsoc::SIZE_MEM_READ_RPT_FIX + memLen * 4,
mpsoc::TM_MEMORY_READ_REPORT);
nextReplyId = mpsoc::EXE_REPORT;
return result;
}
ReturnValue_t PlocMPSoCHandler::enableReplyInReplyMap(DeviceCommandMap::iterator command,
uint8_t expectedReplies, bool useAlternateId,
DeviceCommandId_t alternateReplyID) {
ReturnValue_t result = RETURN_OK;
uint8_t enabledReplies = 0;
switch (command->first) {
case mpsoc::TC_MEM_WRITE:
enabledReplies = 2;
break;
case mpsoc::TC_MEM_READ: {
enabledReplies = 3;
result = DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true,
mpsoc::TM_MEMORY_READ_REPORT);
if (result != RETURN_OK) {
sif::debug << "PlocMPSoCHandler::enableReplyInReplyMap: Reply with id "
<< mpsoc::TM_MEMORY_READ_REPORT << " not in replyMap" << std::endl;
}
break;
}
default:
sif::debug << "PlocMPSoCHandler::enableReplyInReplyMap: Unknown command id" << std::endl;
break;
}
/**
* Every command causes at least one acknowledgment and one execution report. Therefore both
* replies will be enabled here.
*/
result = DeviceHandlerBase::enableReplyInReplyMap(command,
enabledReplies, true, mpsoc::ACK_REPORT);
if (result != RETURN_OK) {
sif::debug << "PlocMPSoCHandler::enableReplyInReplyMap: Reply with id " << mpsoc::ACK_REPORT
<< " not in replyMap" << std::endl;
}
result = DeviceHandlerBase::enableReplyInReplyMap(command,
enabledReplies, true, mpsoc::EXE_REPORT);
if (result != RETURN_OK) {
sif::debug << "PlocMPSoCHandler::enableReplyInReplyMap: Reply with id " << mpsoc::EXE_REPORT
<< " not in replyMap" << std::endl;
}
return RETURN_OK;
}
void PlocMPSoCHandler::setNextReplyId() {
switch(getPendingCommand()) {
case mpsoc::TC_MEM_READ:
nextReplyId = mpsoc::TM_MEMORY_READ_REPORT;
break;
default:
/* If no telemetry is expected the next reply is always the execution report */
nextReplyId = mpsoc::EXE_REPORT;
break;
}
}
size_t PlocMPSoCHandler::getNextReplyLength(DeviceCommandId_t commandId){
size_t replyLen = 0;
if (nextReplyId == mpsoc::NONE) {
return replyLen;
}
DeviceReplyIter iter = deviceReplyMap.find(nextReplyId);
if (iter != deviceReplyMap.end()) {
if (iter->second.delayCycles == 0) {
/* Reply inactive */
return replyLen;
}
switch(nextReplyId) {
case mpsoc::TM_MEMORY_READ_REPORT: {
replyLen = tmMemReadReport.rememberRequestedSize;
break;
}
default: {
replyLen = iter->second.replyLen;
break;
}
}
}
else {
sif::debug << "PlocMPSoCHandler::getNextReplyLength: No entry for reply with reply id "
<< std::hex << nextReplyId << " in deviceReplyMap" << std::endl;
}
return replyLen;
}
void PlocMPSoCHandler::handleDeviceTM(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId) {
ReturnValue_t result = RETURN_OK;
if (wiretappingMode == RAW) {
/* Data already sent in doGetRead() */
return;
}
DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId);
if (iter == deviceReplyMap.end()) {
sif::debug << "PlocMPSoCHandler::handleDeviceTM: Unknown reply id" << std::endl;
return;
}
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
if (queueId == NO_COMMANDER) {
return;
}
result = actionHelper.reportData(queueId, replyId, data, dataSize);
if (result != RETURN_OK) {
sif::debug << "PlocMPSoCHandler::handleDeviceTM: Failed to report data" << std::endl;
}
}
void PlocMPSoCHandler::disableAllReplies() {
DeviceReplyMap::iterator iter;
/* Disable ack reply */
iter = deviceReplyMap.find(mpsoc::ACK_REPORT);
DeviceReplyInfo *info = &(iter->second);
info->delayCycles = 0;
info->command = deviceCommandMap.end();
DeviceCommandId_t commandId = getPendingCommand();
/* If the command expects a telemetry packet the appropriate tm reply will be disabled here */
switch (commandId) {
case mpsoc::TC_MEM_WRITE:
break;
case mpsoc::TC_MEM_READ: {
iter = deviceReplyMap.find(mpsoc::TM_MEMORY_READ_REPORT);
info = &(iter->second);
info->delayCycles = 0;
info->command = deviceCommandMap.end();
break;
}
default: {
sif::debug << "PlocMPSoCHandler::disableAllReplies: Unknown command id" << commandId
<< std::endl;
break;
}
}
/* We must always disable the execution report reply here */
disableExeReportReply();
}
void PlocMPSoCHandler::sendFailureReport(DeviceCommandId_t replyId, ReturnValue_t status) {
DeviceReplyIter iter = deviceReplyMap.find(replyId);
if (iter == deviceReplyMap.end()) {
sif::debug << "PlocMPSoCHandler::sendFailureReport: Reply not in reply map" << std::endl;
return;
}
DeviceCommandInfo* info = &(iter->second.command->second);
if (info == nullptr) {
sif::debug << "PlocMPSoCHandler::sendFailureReport: Reply has no active command" << std::endl;
return;
}
if (info->sendReplyTo != NO_COMMANDER) {
actionHelper.finish(false, info->sendReplyTo, iter->first, status);
}
info->isExecuting = false;
}
void PlocMPSoCHandler::disableExeReportReply() {
DeviceReplyIter iter = deviceReplyMap.find(mpsoc::EXE_REPORT);
DeviceReplyInfo *info = &(iter->second);
info->delayCycles = 0;
info->command = deviceCommandMap.end();
/* Expected replies is set to one here. The value will set to 0 in replyToReply() */
info->command->second.expectedReplies = 0;
}

View File

@ -0,0 +1,213 @@
#ifndef BSP_Q7S_DEVICES_PLOC_PLOCMPSOCHANDLER_H_
#define BSP_Q7S_DEVICES_PLOC_PLOCMPSOCHANDLER_H_
#include <string>
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "fsfw_hal/linux/uart/UartComIF.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/tmtcservices/SourceSequenceCounter.h"
#include "linux/devices/devicedefinitions/PlocMPSoCDefinitions.h"
#include "PlocMPSoCHelper.h"
/**
* @brief This is the device handler for the MPSoC of the payload computer.
*
* @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_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 {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::PLOC_MPSOC_HANDLER;
//! [EXPORT] : [COMMENT] Space Packet received from PLOC has invalid CRC
static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA0);
//! [EXPORT] : [COMMENT] Received ACK failure reply from PLOC
static const ReturnValue_t RECEIVED_ACK_FAILURE = MAKE_RETURN_CODE(0xA1);
//! [EXPORT] : [COMMENT] Received execution failure reply from PLOC
static const ReturnValue_t RECEIVED_EXE_FAILURE = MAKE_RETURN_CODE(0xA2);
//! [EXPORT] : [COMMENT] Received space packet with invalid APID from PLOC
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,
PlocMPSoCHelper* plocMPSoCHelper);
virtual ~PlocMPSoCHandler();
virtual ReturnValue_t initialize() override;
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) override;
void performOperationHook() override;
protected:
void doStartUp() override;
void doShutDown() override;
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) override;
ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) override;
void fillCommandAndReplyMap() override;
ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand,
const uint8_t * commandData,size_t commandDataLen) override;
ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize,
DeviceCommandId_t *foundId, size_t *foundLen) override;
ReturnValue_t interpretDeviceReply(DeviceCommandId_t id,
const uint8_t *packet) override;
void setNormalDatapoolEntriesInvalid() override;
uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator command,
uint8_t expectedReplies = 1, bool useAlternateId = false,
DeviceCommandId_t alternateReplyID = 0) override;
size_t getNextReplyLength(DeviceCommandId_t deviceCommand) override;
private:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_MPSOC_HANDLER;
//! [EXPORT] : [COMMENT] PLOC crc failure in telemetry packet
static const Event MEMORY_READ_RPT_CRC_FAILURE = MAKE_EVENT(1, severity::LOW);
//! [EXPORT] : [COMMENT] PLOC receive acknowledgment failure report
static const Event ACK_FAILURE = MAKE_EVENT(2, severity::LOW);
//! [EXPORT] : [COMMENT] PLOC receive execution failure report
static const Event EXE_FAILURE = MAKE_EVENT(3, severity::LOW);
//! [EXPORT] : [COMMENT] PLOC reply has invalid crc
static const Event MPSOC_HANDLER_CRC_FAILURE = MAKE_EVENT(4, severity::LOW);
//! [EXPORT] : [COMMENT] Packet sequence count in received space packet does not match expected count
//! P1: Expected sequence count
//! P2: Received sequence count
static const Event MPSOC_HANDLER_SEQ_CNT_MISMATCH = MAKE_EVENT(5, severity::LOW);
static const uint16_t APID_MASK = 0x7FF;
static const uint16_t PACKET_SEQUENCE_COUNT_MASK = 0x3FFF;
MessageQueueIF* eventQueue = nullptr;
SourceSequenceCounter sequenceCount;
uint8_t commandBuffer[mpsoc::MAX_COMMAND_SIZE];
/**
* 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
* report.
*/
DeviceCommandId_t nextReplyId = mpsoc::NONE;
UartComIF* uartComIf = nullptr;
PlocMPSoCHelper* plocMPSoCHelper = nullptr;
// Used to block incoming commands when MPSoC helper class is currently executing a command
bool plocMPSoCHelperExecuting = false;
class TmMemReadReport {
public:
static const uint8_t FIX_SIZE = 14;
size_t rememberRequestedSize = 0;
};
TmMemReadReport tmMemReadReport;
/**
* @brief Handles events received from the PLOC MPSoC helper
*/
void handleEvent(EventMessage* eventMessage);
ReturnValue_t prepareTcMemWriteCommand(const uint8_t * commandData, size_t commandDataLen);
ReturnValue_t prepareTcMemReadCommand(const uint8_t * commandData, size_t commandDataLen);
/**
* @brief Copies space packet into command buffer
*/
void copyToCommandBuffer(mpsoc::TcBase* tc);
/**
* @brief This function checks the crc of the received PLOC reply.
*
* @param start Pointer to the first byte of the reply.
* @param foundLen Pointer to the length of the whole packet.
*
* @return RETURN_OK if CRC is ok, otherwise CRC_FAILURE.
*/
ReturnValue_t verifyPacket(const uint8_t* start, size_t foundLen);
/**
* @brief This function handles the acknowledgment report.
*
* @param data Pointer to the data holding the acknowledgment report.
*
* @return RETURN_OK if successful, otherwise an error code.
*/
ReturnValue_t handleAckReport(const uint8_t* data);
/**
* @brief This function handles the data of a execution report.
*
* @param data Pointer to the received data packet.
*
* @return RETURN_OK if successful, otherwise an error code.
*/
ReturnValue_t handleExecutionReport(const uint8_t* data);
/**
* @brief This function handles the memory read report.
*
* @param data Pointer to the data buffer holding the memory read report.
*
* @return RETURN_OK if successful, otherwise an error code.
*/
ReturnValue_t handleMemoryReadReport(const uint8_t* data);
/**
* @brief Depending on the current active command, this function sets the reply id of the
* next reply after a successful acknowledgment report has been received. This is
* required by the function getNextReplyLength() to identify the length of the next
* reply to read.
*/
void setNextReplyId();
/**
* @brief This function handles action message replies in case the telemetry has been
* requested by another object.
*
* @param data Pointer to the telemetry data.
* @param dataSize Size of telemetry in bytes.
* @param replyId Id of the reply. This will be added to the ActionMessage.
*/
void handleDeviceTM(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId);
/**
* @brief In case an acknowledgment failure reply has been received this function disables
* all previously enabled commands and resets the exepected replies variable of an
* active command.
*/
void disableAllReplies();
/**
* @brief This function sends a failure report if the active action was commanded by an other
* object.
*
* @param replyId The id of the reply which signals a failure.
* @param status A status byte which gives information about the failure type.
*/
void sendFailureReport(DeviceCommandId_t replyId, ReturnValue_t status);
/**
* @brief This function disables the execution report reply. Within this function also the
* the variable expectedReplies of an active command will be set to 0.
*/
void disableExeReportReply();
};
#endif /* BSP_Q7S_DEVICES_PLOC_PLOCMPSOCHANDLER_H_ */

View File

@ -0,0 +1,277 @@
#include "PlocMPSoCHelper.h"
#include <filesystem>
#include <fstream>
#ifdef XIPHOS_Q7S
#include "bsp_q7s/memory/FileSystemHelper.h"
#endif
#include "mission/utility/Timestamp.h"
PlocMPSoCHelper::PlocMPSoCHelper(object_id_t objectId) : SystemObject(objectId) {}
PlocMPSoCHelper::~PlocMPSoCHelper() {}
ReturnValue_t PlocMPSoCHelper::initialize() {
#ifdef XIPHOS_Q7S
sdcMan = SdCardManager::instance();
if (sdcMan == nullptr) {
sif::warning << "PlocMPSoCHelper::initialize: Invalid SD Card Manager" << std::endl;
return RETURN_FAILED;
}
#endif
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(MPSOC_FLASH_WRITE_SUCCESSFUL);
} else {
triggerEvent(MPSOC_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(SourceSequenceCounter* sequenceCount_) {
sequenceCount = sequenceCount_;
}
ReturnValue_t PlocMPSoCHelper::startFlashWrite(std::string file) {
#ifdef XIPHOS_Q7S
ReturnValue_t result = FilesystemHelper::checkPath(file);
if (result != RETURN_OK) {
return result;
}
result = FilesystemHelper::fileExists(file);
if (result != RETURN_OK) {
return result;
}
#endif
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;
result = flashfopen();
if (result != RETURN_OK) {
return result;
}
uint8_t tempData[mpsoc::MAX_DATA_SIZE];
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
size_t remainingSize = file.tellg();
size_t dataLength = 0;
while (remainingSize > 0) {
if (terminate) {
return RETURN_OK;
}
if (remainingSize > mpsoc::MAX_DATA_SIZE) {
dataLength = mpsoc::MAX_DATA_SIZE;
} else {
dataLength = remainingSize;
}
file.read(reinterpret_cast<char*>(tempData), dataLength);
(*sequenceCount)++;
mpsoc::FlashWrite tc(*sequenceCount);
tc.createPacket(tempData, dataLength);
result = sendCommand(&tc);
if (result != RETURN_OK) {
return result;
}
result = handleAck();
if (result != RETURN_OK) {
return result;
}
result = handleExe();
if (result != RETURN_OK) {
return result;
}
}
result = flashfclose();
if (result != RETURN_OK) {
return result;
}
return result;
}
ReturnValue_t PlocMPSoCHelper::flashfopen() {
ReturnValue_t result = RETURN_OK;
(*sequenceCount)++;
mpsoc::FlashFopen flashFopen(*sequenceCount);
result = flashFopen.createPacket(flashWrite.file, mpsoc::FlashFopen::APPEND);
if (result != RETURN_OK) {
return result;
}
result = sendCommand(&flashFopen);
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}
ReturnValue_t PlocMPSoCHelper::flashfclose() {
ReturnValue_t result = RETURN_OK;
(*sequenceCount)++;
mpsoc::FlashFclose flashFclose(*sequenceCount);
result = flashFclose.createPacket(flashWrite.file);
if (result != RETURN_OK) {
return result;
}
result = sendCommand(&flashFclose);
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}
ReturnValue_t PlocMPSoCHelper::sendCommand(mpsoc::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, static_cast<uint32_t>(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, static_cast<uint32_t>(internalState));
sif::warning << "PlocMPSoCHelper::handleAckApidFailure: Received acknowledgement failure "
<< "report" << std::endl;
} else {
triggerEvent(ACK_INVALID_APID, apid, static_cast<uint32_t>(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, static_cast<uint32_t>(internalState));
sif::warning << "PlocMPSoCHelper::handleExeApidFailure: Received execution failure "
<< "report" << std::endl;
} else {
triggerEvent(EXE_INVALID_APID, apid, static_cast<uint32_t>(internalState));
sif::warning << "PlocMPSoCHelper::handleAckApidFailure: Expected execution report "
<< "but received space packet with apid " << std::hex << apid << std::endl;
}
}
ReturnValue_t PlocMPSoCHelper::handleTmReception(mpsoc::TmPacket* tmPacket, size_t remainingBytes) {
ReturnValue_t result = RETURN_OK;
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, static_cast<uint32_t>(internalState));
return RETURN_FAILED;
}
result = tmPacket->checkCrc();
if (result != RETURN_OK) {
sif::warning << "PlocMPSoCHelper::handleTmReception: CRC check failed" << std::endl;
return result;
}
uint16_t recvSeqCnt = tmPacket->getPacketSequenceCount();
if (recvSeqCnt != *sequenceCount) {
triggerEvent(MPSOC_HELPER_SEQ_CNT_MISMATCH, *sequenceCount, recvSeqCnt);
*sequenceCount = recvSeqCnt;
return result;
}
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,
static_cast<uint32_t>(static_cast<uint32_t>(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, static_cast<uint32_t>(internalState));
return RETURN_FAILED;
}
return result;
}

View File

@ -0,0 +1,150 @@
#ifndef BSP_Q7S_DEVICES_PLOCMPSOCHELPER_H_
#define BSP_Q7S_DEVICES_PLOCMPSOCHELPER_H_
#include <string>
#include "fsfw/osal/linux/BinarySemaphore.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 "fsfw/tmtcservices/SourceSequenceCounter.h"
#include "linux/devices/devicedefinitions/PlocMPSoCDefinitions.h"
#ifdef XIPHOS_Q7S
#include "bsp_q7s/memory/SdCardManager.h"
#endif
/**
* @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 MPSOC_FLASH_WRITE_FAILED = MAKE_EVENT(0, severity::LOW);
//! [EXPORT] : [COMMENT] Flash write successful
static const Event MPSOC_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_READING_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);
//! [EXPORT] : [COMMENT] Received sequence count does not match expected sequence count
//!P1: Expected sequence count
//!P2: Received sequence count
static const Event MPSOC_HELPER_SEQ_CNT_MISMATCH = MAKE_EVENT(11, 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(SourceSequenceCounter* 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;
struct FlashWrite {
std::string file;
};
struct FlashWrite flashWrite;
enum class InternalState {
IDLE,
FLASH_WRITE,
FLASH_READ
};
InternalState internalState = InternalState::IDLE;
BinarySemaphore semaphore;
#ifdef XIPHOS_Q7S
SdCardManager* sdcMan = nullptr;
#endif
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
SourceSequenceCounter* sequenceCount;
ReturnValue_t performFlashWrite();
ReturnValue_t flashfopen();
ReturnValue_t flashfclose();
ReturnValue_t sendCommand(mpsoc::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(mpsoc::TmPacket* tmPacket, size_t remainingBytes);
};
#endif /* BSP_Q7S_DEVICES_PLOCMPSOCHELPER_H_ */

View File

@ -0,0 +1,194 @@
#include "PlocMemoryDumper.h"
#include <fsfw/src/fsfw/serialize/SerializeAdapter.h>
#include <filesystem>
#include <fstream>
#include <string>
#include "fsfw/ipc/QueueFactory.h"
PlocMemoryDumper::PlocMemoryDumper(object_id_t objectId)
: SystemObject(objectId), commandActionHelper(this), actionHelper(this, nullptr) {
auto mqArgs = MqArgs(this->getObjectId());
commandQueue = QueueFactory::instance()->createMessageQueue(
QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
PlocMemoryDumper::~PlocMemoryDumper() {}
ReturnValue_t PlocMemoryDumper::initialize() {
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 PlocMemoryDumper::performOperation(uint8_t operationCode) {
readCommandQueue();
doStateMachine();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PlocMemoryDumper::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
if (state != State::IDLE) {
return IS_BUSY;
}
switch (actionId) {
case DUMP_MRAM: {
size_t deserializeSize = sizeof(mram.startAddress) + sizeof(mram.endAddress);
SerializeAdapter::deSerialize(&mram.startAddress, &data, &deserializeSize,
SerializeIF::Endianness::BIG);
SerializeAdapter::deSerialize(&mram.endAddress, &data, &deserializeSize,
SerializeIF::Endianness::BIG);
if (mram.endAddress > MAX_MRAM_ADDRESS) {
return MRAM_ADDRESS_TOO_HIGH;
}
if (mram.endAddress <= mram.startAddress) {
return MRAM_INVALID_ADDRESS_COMBINATION;
}
state = State::COMMAND_FIRST_MRAM_DUMP;
break;
}
default: {
sif::warning << "PlocMemoryDumper::executeAction: Received command with invalid action id"
<< std::endl;
return INVALID_ACTION_ID;
}
}
return EXECUTION_FINISHED;
}
MessageQueueId_t PlocMemoryDumper::getCommandQueue() const { return commandQueue->getId(); }
MessageQueueIF* PlocMemoryDumper::getCommandQueuePtr() { return commandQueue; }
void PlocMemoryDumper::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 << "PlocMemoryDumper::readCommandQueue: Received message with invalid format"
<< std::endl;
}
}
void PlocMemoryDumper::doStateMachine() {
switch (state) {
case State::IDLE:
break;
case State::COMMAND_FIRST_MRAM_DUMP:
commandNextMramDump(PLOC_SPV::FIRST_MRAM_DUMP);
break;
case State::COMMAND_CONSECUTIVE_MRAM_DUMP:
commandNextMramDump(PLOC_SPV::CONSECUTIVE_MRAM_DUMP);
break;
case State::EXECUTING_MRAM_DUMP:
break;
default:
sif::debug << "PlocMemoryDumper::doStateMachine: Invalid state" << std::endl;
break;
}
}
void PlocMemoryDumper::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {}
void PlocMemoryDumper::stepFailedReceived(ActionId_t actionId, uint8_t step,
ReturnValue_t returnCode) {}
void PlocMemoryDumper::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) {}
void PlocMemoryDumper::completionSuccessfulReceived(ActionId_t actionId) {
switch (pendingCommand) {
case (PLOC_SPV::FIRST_MRAM_DUMP):
case (PLOC_SPV::CONSECUTIVE_MRAM_DUMP):
if (mram.endAddress == mram.startAddress) {
triggerEvent(MRAM_DUMP_FINISHED);
state = State::IDLE;
} else {
state = State::COMMAND_CONSECUTIVE_MRAM_DUMP;
}
break;
default:
sif::debug << "PlocMemoryDumper::completionSuccessfulReceived: Invalid pending command"
<< std::endl;
state = State::IDLE;
break;
}
}
void PlocMemoryDumper::completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) {
switch (pendingCommand) {
case (PLOC_SPV::FIRST_MRAM_DUMP):
case (PLOC_SPV::CONSECUTIVE_MRAM_DUMP):
triggerEvent(MRAM_DUMP_FAILED, mram.lastStartAddress);
break;
default:
sif::debug << "PlocMemoryDumper::completionFailedReceived: Invalid pending command "
<< std::endl;
break;
}
state = State::IDLE;
}
void PlocMemoryDumper::commandNextMramDump(ActionId_t dumpCommand) {
ReturnValue_t result = RETURN_OK;
uint32_t tempStartAddress = 0;
uint32_t tempEndAddress = 0;
if (mram.endAddress - mram.startAddress > MAX_MRAM_DUMP_SIZE) {
tempStartAddress = mram.startAddress;
tempEndAddress = mram.startAddress + MAX_MRAM_DUMP_SIZE;
mram.startAddress += MAX_MRAM_DUMP_SIZE;
mram.lastStartAddress = tempStartAddress;
} else {
tempStartAddress = mram.startAddress;
tempEndAddress = mram.endAddress;
mram.startAddress = mram.endAddress;
}
MemoryParams params(tempStartAddress, tempEndAddress);
result =
commandActionHelper.commandAction(objects::PLOC_SUPERVISOR_HANDLER, dumpCommand, &params);
if (result != RETURN_OK) {
sif::warning << "PlocMemoryDumper::commandNextMramDump: Failed to send mram dump command "
<< "with start address " << tempStartAddress << " and end address "
<< tempEndAddress << std::endl;
triggerEvent(SEND_MRAM_DUMP_FAILED, result, tempStartAddress);
state = State::IDLE;
pendingCommand = NONE;
return;
}
state = State::EXECUTING_MRAM_DUMP;
pendingCommand = dumpCommand;
return;
}

View File

@ -0,0 +1,114 @@
#ifndef MISSION_DEVICES_PLOCMEMORYDUMPER_H_
#define MISSION_DEVICES_PLOCMEMORYDUMPER_H_
#include <linux/devices/devicedefinitions/PlocMemDumpDefinitions.h>
#include <linux/devices/devicedefinitions/PlocSupervisorDefinitions.h>
#include "OBSWConfig.h"
#include "bsp_q7s/memory/SdCardManager.h"
#include "fsfw/action/ActionHelper.h"
#include "fsfw/action/CommandActionHelper.h"
#include "fsfw/action/CommandsActionsIF.h"
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tmtcpacket/SpacePacket.h"
#include "linux/fsfwconfig/objects/systemObjectList.h"
/**
* @brief Because the buffer of the linux tty driver is limited to 2 x 65535 bytes, this class is
* created to perform large dumps of PLOC memories.
*
* @details Currently the PLOC supervisor only implements the functionality to dump the MRAM.
*
* @author J. Meier
*/
class PlocMemoryDumper : public SystemObject,
public HasActionsIF,
public ExecutableObjectIF,
public HasReturnvaluesIF,
public CommandsActionsIF {
public:
static const ActionId_t NONE = 0;
static const ActionId_t DUMP_MRAM = 1;
PlocMemoryDumper(object_id_t objectId);
virtual ~PlocMemoryDumper();
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size);
MessageQueueId_t getCommandQueue() const;
ReturnValue_t initialize() override;
MessageQueueIF* getCommandQueuePtr() override;
void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) override;
void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) override;
void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) override;
void completionSuccessfulReceived(ActionId_t actionId) override;
void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) override;
private:
static const uint32_t QUEUE_SIZE = 10;
static const uint8_t INTERFACE_ID = CLASS_ID::PLOC_MEMORY_DUMPER;
//! [EXPORT] : [COMMENT] The capacity of the MRAM amounts to 512 kB. Thus the maximum address must
//! not be higher than 0x7d000.
static const ReturnValue_t MRAM_ADDRESS_TOO_HIGH = MAKE_RETURN_CODE(0xA0);
//! [EXPORT] : [COMMENT] The specified end address is lower than the start address
static const ReturnValue_t MRAM_INVALID_ADDRESS_COMBINATION = MAKE_RETURN_CODE(0xA1);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_MEMORY_DUMPER;
//! [EXPORT] : [COMMENT] Failed to send mram dump command to supervisor handler
//! P1: Return value of commandAction function
//! P2: Start address of MRAM to dump with this command
static const Event SEND_MRAM_DUMP_FAILED = MAKE_EVENT(0, severity::LOW);
//! [EXPORT] : [COMMENT] Received completion failure report form PLOC supervisor handler
//! P1: MRAM start address of failing dump command
static const Event MRAM_DUMP_FAILED = MAKE_EVENT(1, severity::LOW);
//! [EXPORT] : [COMMENT] MRAM dump finished successfully
static const Event MRAM_DUMP_FINISHED = MAKE_EVENT(2, severity::LOW);
// Maximum size of mram dump which can be retrieved with one command
static const uint32_t MAX_MRAM_DUMP_SIZE = 100000;
static const uint32_t MAX_MRAM_ADDRESS = 0x7d000;
MessageQueueIF* commandQueue = nullptr;
CommandActionHelper commandActionHelper;
ActionHelper actionHelper;
enum class State : uint8_t {
IDLE,
COMMAND_FIRST_MRAM_DUMP,
COMMAND_CONSECUTIVE_MRAM_DUMP,
EXECUTING_MRAM_DUMP
};
State state = State::IDLE;
ActionId_t pendingCommand = NONE;
typedef struct MemoryInfo {
// Stores the start address of the next memory range to dump
uint32_t startAddress;
uint32_t endAddress;
// Stores the start address of the last sent dump command
uint32_t lastStartAddress;
} MemoryInfo_t;
MemoryInfo_t mram = {0, 0, 0};
void readCommandQueue();
void doStateMachine();
/**
* @brief Sends the next mram dump command to the PLOC supervisor handler.
*/
void commandNextMramDump(ActionId_t dumpCommand);
};
#endif /* MISSION_DEVICES_PLOCMEMORYDUMPER_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,340 @@
#ifndef MISSION_DEVICES_PLOCSUPERVISORHANDLER_H_
#define MISSION_DEVICES_PLOCSUPERVISORHANDLER_H_
#include "OBSWconfig.h"
#include <linux/devices/devicedefinitions/PlocSupervisorDefinitions.h>
#include <bsp_q7s/memory/SdCardManager.h>
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include <fsfw_hal/linux/uart/UartComIF.h>
/**
* @brief This is the device handler for the supervisor of the PLOC which is programmed by
* Thales.
*
* @details The PLOC uses the space packet protocol for communication. To 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
* @author J. Meier
*/
class PlocSupervisorHandler: public DeviceHandlerBase {
public:
PlocSupervisorHandler(object_id_t objectId, object_id_t uartComIFid, CookieIF * comCookie);
virtual ~PlocSupervisorHandler();
virtual ReturnValue_t initialize() override;
protected:
void doStartUp() override;
void doShutDown() override;
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) override;
ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) override;
void fillCommandAndReplyMap() override;
ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand,
const uint8_t * commandData,size_t commandDataLen) override;
ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize,
DeviceCommandId_t *foundId, size_t *foundLen) override;
ReturnValue_t interpretDeviceReply(DeviceCommandId_t id,
const uint8_t *packet) override;
void setNormalDatapoolEntriesInvalid() override;
uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator command,
uint8_t expectedReplies = 1, bool useAlternateId = false,
DeviceCommandId_t alternateReplyID = 0) override;
size_t getNextReplyLength(DeviceCommandId_t deviceCommand) override;
private:
static const uint8_t INTERFACE_ID = CLASS_ID::PLOC_SUPERVISOR_HANDLER;
//! [EXPORT] : [COMMENT] Space Packet received from PLOC supervisor has invalid CRC
static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA0);
//! [EXPORT] : [COMMENT] Received ACK failure reply from PLOC supervisor
static const ReturnValue_t RECEIVED_ACK_FAILURE = MAKE_RETURN_CODE(0xA1);
//! [EXPORT] : [COMMENT] Received execution failure reply from PLOC supervisor
static const ReturnValue_t RECEIVED_EXE_FAILURE = MAKE_RETURN_CODE(0xA2);
//! [EXPORT] : [COMMENT] Received space packet with invalid APID from PLOC supervisor
static const ReturnValue_t INVALID_APID = MAKE_RETURN_CODE(0xA3);
//! [EXPORT] : [COMMENT] Failed to read current system time
static const ReturnValue_t GET_TIME_FAILURE = MAKE_RETURN_CODE(0xA4);
//! [EXPORT] : [COMMENT] Received command with invalid watchdog parameter. Valid watchdogs are 0 for PS, 1 for PL and 2 for INT
static const ReturnValue_t INVALID_WATCHDOG = MAKE_RETURN_CODE(0xA5);
//! [EXPORT] : [COMMENT] Received watchdog timeout config command with invalid timeout. Valid timeouts must be in the range between 1000 and 360000 ms.
static const ReturnValue_t INVALID_WATCHDOG_TIMEOUT = MAKE_RETURN_CODE(0xA6);
//! [EXPORT] : [COMMENT] Received latchup config command with invalid latchup ID
static const ReturnValue_t INVALID_LATCHUP_ID = MAKE_RETURN_CODE(0xA7);
//! [EXPORT] : [COMMENT] Received set adc sweep period command with invalid sweep period. Must be larger than 21.
static const ReturnValue_t SWEEP_PERIOD_TOO_SMALL = MAKE_RETURN_CODE(0xA8);
//! [EXPORT] : [COMMENT] Receive auto EM test command with invalid test param. Valid params are 1 and 2.
static const ReturnValue_t INVALID_TEST_PARAM = MAKE_RETURN_CODE(0xA9);
//! [EXPORT] : [COMMENT] Returned when scanning for MRAM dump packets failed.
static const ReturnValue_t MRAM_PACKET_PARSING_FAILURE = MAKE_RETURN_CODE(0xAA);
//! [EXPORT] : [COMMENT] Returned when the start and stop addresses of the MRAM dump or MRAM wipe commands are invalid (e.g. start address bigger than stop address)
static const ReturnValue_t INVALID_MRAM_ADDRESSES = MAKE_RETURN_CODE(0xAB);
//! [EXPORT] : [COMMENT] Expect reception of an MRAM dump packet but received space packet with other apid.
static const ReturnValue_t NO_MRAM_PACKET = MAKE_RETURN_CODE(0xAC);
//! [EXPORT] : [COMMENT] Path to PLOC directory on SD card does not exist
static const ReturnValue_t PATH_DOES_NOT_EXIST = MAKE_RETURN_CODE(0xAD);
//! [EXPORT] : [COMMENT] MRAM dump file does not exists. The file should actually already have been created with the reception of the first dump packet.
static const ReturnValue_t MRAM_FILE_NOT_EXISTS = MAKE_RETURN_CODE(0xAE);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_SUPERVISOR_HANDLER;
//! [EXPORT] : [COMMENT] PLOC supervisor crc failure in telemetry packet
static const Event SUPV_MEMORY_READ_RPT_CRC_FAILURE = MAKE_EVENT(1, severity::LOW);
//! [EXPORT] : [COMMENT] PLOC supervisor received acknowledgment failure report
static const Event SUPV_ACK_FAILURE = MAKE_EVENT(2, severity::LOW);
//! [EXPORT] : [COMMENT] PLOC received execution failure report
static const Event SUPV_EXE_FAILURE = MAKE_EVENT(3, severity::LOW);
//! [EXPORT] : [COMMENT] PLOC supervisor reply has invalid crc
static const Event SUPV_CRC_FAILURE_EVENT = MAKE_EVENT(4, severity::LOW);
static const uint16_t APID_MASK = 0x7FF;
static const uint16_t PACKET_SEQUENCE_COUNT_MASK = 0x3FFF;
uint8_t commandBuffer[PLOC_SPV::MAX_COMMAND_SIZE];
/**
* 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
* report.
*/
DeviceCommandId_t nextReplyId = PLOC_SPV::NONE;
UartComIF* uartComIf = nullptr;
PLOC_SPV::HkSet hkset;
PLOC_SPV::BootStatusReport bootStatusReport;
PLOC_SPV::LatchupStatusReport latchupStatusReport;
/** Number of expected replies following the MRAM dump command */
uint32_t expectedMramDumpPackets = 0;
uint32_t receivedMramDumpPackets = 0;
/** Set to true as soon as a complete space packet is present in the spacePacketBuffer */
bool packetInBuffer = false;
/** Points to the next free position in the space packet buffer */
uint16_t bufferTop = 0;
/** This buffer is used to concatenate space packets received in two different read steps */
uint8_t spacePacketBuffer[PLOC_SPV::MAX_PACKET_SIZE];
#if BOARD_TE0720 == 0
SdCardManager* sdcMan = nullptr;
#endif /* BOARD_TE0720 == 0 */
/** Path to PLOC specific files on SD card */
std::string plocFilePath = "ploc";
std::string activeMramFile;
/** Setting this variable to true will enable direct downlink of MRAM packets */
bool downlinkMramDump = false;
/**
* @brief This function checks the crc of the received PLOC reply.
*
* @param start Pointer to the first byte of the reply.
* @param foundLen Pointer to the length of the whole packet.
*
* @return RETURN_OK if CRC is ok, otherwise CRC_FAILURE.
*/
ReturnValue_t verifyPacket(const uint8_t* start, size_t foundLen);
/**
* @brief This function handles the acknowledgment report.
*
* @param data Pointer to the data holding the acknowledgment report.
*
* @return RETURN_OK if successful, otherwise an error code.
*/
ReturnValue_t handleAckReport(const uint8_t* data);
/**
* @brief This function handles the data of a execution report.
*
* @param data Pointer to the received data packet.
*
* @return RETURN_OK if successful, otherwise an error code.
*/
ReturnValue_t handleExecutionReport(const uint8_t* data);
/**
* @brief This function handles the housekeeping report. This means verifying the CRC of the
* reply and filling the appropriate dataset.
*
* @param data Pointer to the data buffer holding the housekeeping read report.
*
* @return RETURN_OK if successful, otherwise an error code.
*/
ReturnValue_t handleHkReport(const uint8_t* data);
/**
* @brief This function calls the function to check the CRC of the received boot status report
* and fills the associated dataset with the boot status information.
*/
ReturnValue_t handleBootStatusReport(const uint8_t* data);
ReturnValue_t handleLatchupStatusReport(const uint8_t* data);
/**
* @brief Depending on the current active command, this function sets the reply id of the
* next reply after a successful acknowledgment report has been received. This is
* required by the function getNextReplyLength() to identify the length of the next
* reply to read.
*/
void setNextReplyId();
/**
* @brief This function handles action message replies in case the telemetry has been
* requested by another object.
*
* @param data Pointer to the telemetry data.
* @param dataSize Size of telemetry in bytes.
* @param replyId Id of the reply. This will be added to the ActionMessage.
*/
void handleDeviceTM(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId);
/**
* @brief This function prepares a space packet which does not transport any data in the
* packet data field apart from the crc.
*/
void prepareEmptyCmd(uint16_t apid);
/**
* @brief This function initializes the space packet to select the boot image of the MPSoC.
*/
void prepareSelBootImageCmd(const uint8_t * commandData);
void prepareDisableHk();
/**
* @brief This function fills the commandBuffer with the data to update the time of the
* PLOC supervisor.
*/
ReturnValue_t prepareSetTimeRefCmd();
/**
* @brief This function fills the commandBuffer with the data to change the boot timeout
* value in the PLOC supervisor.
*/
void prepareSetBootTimeoutCmd(const uint8_t * commandData);
void prepareRestartTriesCmd(const uint8_t * commandData);
/**
* @brief This function fills the command buffer with the packet to enable or disable the
* watchdogs on the PLOC.
*/
void prepareWatchdogsEnableCmd(const uint8_t * commandData);
/**
* @brief This function fills the command buffer with the packet to set the watchdog timer
* of one of the three watchdogs (PS, PL, INT).
*/
ReturnValue_t prepareWatchdogsConfigTimeoutCmd(const uint8_t * commandData);
ReturnValue_t prepareLatchupConfigCmd(const uint8_t* commandData,
DeviceCommandId_t deviceCommand);
ReturnValue_t prepareAutoCalibrateAlertCmd(const uint8_t* commandData);
ReturnValue_t prepareSetAlertLimitCmd(const uint8_t* commandData);
ReturnValue_t prepareSetAlertIrqFilterCmd(const uint8_t* commandData);
ReturnValue_t prepareSetAdcSweetPeriodCmd(const uint8_t* commandData);
void prepareSetAdcEnabledChannelsCmd(const uint8_t* commandData);
void prepareSetAdcWindowAndStrideCmd(const uint8_t* commandData);
void prepareSetAdcThresholdCmd(const uint8_t* commandData);
void prepareEnableNvmsCmd(const uint8_t* commandData);
void prepareSelectNvmCmd(const uint8_t* commandData);
ReturnValue_t prepareRunAutoEmTest(const uint8_t* commandData);
ReturnValue_t prepareWipeMramCmd(const uint8_t* commandData);
ReturnValue_t prepareDumpMramCmd(const uint8_t* commandData);
void preparePrintCpuStatsCmd(const uint8_t* commandData);
void prepareSetDbgVerbosityCmd(const uint8_t* commandData);
void prepareSetGpioCmd(const uint8_t* commandData);
void prepareReadGpioCmd(const uint8_t* commandData);
/**
* @brief Copies the content of a space packet to the command buffer.
*/
void packetToOutBuffer(uint8_t* packetData, size_t fullSize);
/**
* @brief In case an acknowledgment failure reply has been received this function disables
* all previously enabled commands and resets the exepected replies variable of an
* active command.
*/
void disableAllReplies();
/**
* @brief This function sends a failure report if the active action was commanded by an other
* object.
*
* @param replyId The id of the reply which signals a failure.
* @param status A status byte which gives information about the failure type.
*/
void sendFailureReport(DeviceCommandId_t replyId, ReturnValue_t status);
/**
* @brief This function disables the execution report reply. Within this function also the
* the variable expectedReplies of an active command will be set to 0.
*/
void disableExeReportReply();
/**
* @brief Function is called in scanForReply and fills the spacePacketBuffer with the read
* data until a full packet has been received.
*/
ReturnValue_t parseMramPackets(const uint8_t *packet, size_t remainingSize, size_t* foundlen);
/**
* @brief This function generates the Service 8 packets for the MRAM dump data.
*/
ReturnValue_t handleMramDumpPacket(DeviceCommandId_t id);
/**
* @brief With this function the number of expected replies following an MRAM dump command
* will be increased. This is necessary to release the command in case not all replies
* have been received.
*/
void increaseExpectedMramReplies(DeviceCommandId_t id);
/**
* @brief Function checks if the packet written to the space packet buffer is really a
* MRAM dump packet.
*/
ReturnValue_t checkMramPacketApid();
/**
* @brief Writes the data of the MRAM dump to a file. The file will be created when receiving
* the first packet.
*/
ReturnValue_t handleMramDumpFile(DeviceCommandId_t id);
/**
* @brief Extracts the length field of a spacePacket referenced by the spacePacket pointer.
*
* @param spacePacket Pointer to the buffer holding the space packet.
*
* @return The value stored in the length field of the data field.
*/
uint16_t readSpacePacketLength(uint8_t* spacePacket);
/**
* @brief Extracts the sequence flags from a space packet referenced by the spacePacket
* pointer.
*
* @param spacePacket Pointer to the buffer holding the space packet.
*
* @return uint8_t where the two least significant bits hold the sequence flags.
*/
uint8_t readSequenceFlags(uint8_t* spacePacket);
ReturnValue_t createMramDumpFile();
ReturnValue_t getTimeStampString(std::string& timeStamp);
};
#endif /* MISSION_DEVICES_PLOCSUPERVISORHANDLER_H_ */

View File

@ -0,0 +1,395 @@
#include "PlocUpdater.h"
#include <filesystem>
#include <fstream>
#include <string>
#include "fsfw/ipc/QueueFactory.h"
PlocUpdater::PlocUpdater(object_id_t objectId)
: SystemObject(objectId), commandActionHelper(this), actionHelper(this, nullptr) {
auto mqArgs = MqArgs(this->getObjectId());
commandQueue = QueueFactory::instance()->createMessageQueue(
QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
PlocUpdater::~PlocUpdater() {}
ReturnValue_t PlocUpdater::initialize() {
#if BOARD_TE0720 == 0
sdcMan = SdCardManager::instance();
#endif
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_A_UBOOT:
image = Image::A;
partition = Partition::UBOOT;
break;
case UPDATE_A_BITSTREAM:
image = Image::A;
partition = Partition::BITSTREAM;
break;
case UPDATE_A_LINUX:
image = Image::A;
partition = Partition::LINUX_OS;
break;
case UPDATE_A_APP_SW:
image = Image::A;
partition = Partition::APP_SW;
break;
case UPDATE_B_UBOOT:
image = Image::B;
partition = Partition::UBOOT;
break;
case UPDATE_B_BITSTREAM:
image = Image::B;
partition = Partition::BITSTREAM;
break;
case UPDATE_B_LINUX:
image = Image::B;
partition = Partition::LINUX_OS;
break;
case UPDATE_B_APP_SW:
image = Image::B;
partition = Partition::APP_SW;
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;
}
#if BOARD_TE0720 == 0
// 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 */
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;
}
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;
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;
}
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 > 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;
}
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>(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;
return;
}
state = State::COMMAND_EXECUTING;
pendingCommand = PLOC_SPV::UPDATE_VERIFY;
return;
}
void PlocUpdater::calcImageCrc() {
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);
}
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));
}
}

View File

@ -0,0 +1,172 @@
#ifndef MISSION_DEVICES_PLOCUPDATER_H_
#define MISSION_DEVICES_PLOCUPDATER_H_
#include "OBSWConfig.h"
#include <linux/devices/devicedefinitions/PlocSupervisorDefinitions.h>
#include "fsfw/action/CommandActionHelper.h"
#include "bsp_q7s/memory/SdCardManager.h"
#include "fsfw/action/ActionHelper.h"
#include "fsfw/action/CommandActionHelper.h"
#include "fsfw/action/CommandsActionsIF.h"
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tmtcpacket/SpacePacket.h"
#include "linux/fsfwconfig/objects/systemObjectList.h"
/**
* @brief An object of this class can be used to perform the software updates of the PLOC. The
* software update will be read from one of the SD cards, split into multiple space
* packets and sent to the PlocSupervisorHandler.
*
* @details The MPSoC has two boot memories (NVM0 and NVM1) where each stores two images (Partition
* A and Partition B)
*
* @author J. Meier
*/
class PlocUpdater : public SystemObject,
public HasActionsIF,
public ExecutableObjectIF,
public HasReturnvaluesIF,
public CommandsActionsIF {
public:
static const ActionId_t UPDATE_A_UBOOT = 0;
static const ActionId_t UPDATE_A_BITSTREAM = 1;
static const ActionId_t UPDATE_A_LINUX = 2;
static const ActionId_t UPDATE_A_APP_SW = 3;
static const ActionId_t UPDATE_B_UBOOT = 4;
static const ActionId_t UPDATE_B_BITSTREAM = 5;
static const ActionId_t UPDATE_B_LINUX = 6;
static const ActionId_t UPDATE_B_APP_SW = 7;
PlocUpdater(object_id_t objectId);
virtual ~PlocUpdater();
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size);
MessageQueueId_t getCommandQueue() const;
ReturnValue_t initialize() override;
MessageQueueIF* getCommandQueuePtr() override;
void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) override;
void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) override;
void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) override;
void completionSuccessfulReceived(ActionId_t actionId) override;
void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) override;
private:
static const uint8_t INTERFACE_ID = CLASS_ID::PLOC_UPDATER;
//! [EXPORT] : [COMMENT] Updater is already performing an update
static const ReturnValue_t UPDATER_BUSY = MAKE_RETURN_CODE(0xA0);
//! [EXPORT] : [COMMENT] Received update command with invalid path string (too long).
static const ReturnValue_t NAME_TOO_LONG = MAKE_RETURN_CODE(0xA1);
//! [EXPORT] : [COMMENT] Received command to initiate update but SD card with update image not
//! mounted.
static const ReturnValue_t SD_NOT_MOUNTED = MAKE_RETURN_CODE(0xA2);
//! [EXPORT] : [COMMENT] Update file received with update command does not exist.
static const ReturnValue_t FILE_NOT_EXISTS = MAKE_RETURN_CODE(0xA3);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_UPDATER;
//! [EXPORT] : [COMMENT] Try to read update file but the file does not exist.
//! P1: Indicates in which state the file read fails
//! P2: During the update transfer the second parameter gives information about the number of
//! already sent packets
static const Event UPDATE_FILE_NOT_EXISTS = MAKE_EVENT(0, severity::LOW);
//! [EXPORT] : [COMMENT] Failed to send command to supervisor handler
//! P1: Return value of CommandActionHelper::commandAction
//! P2: Action ID of command to send
static const Event ACTION_COMMANDING_FAILED = MAKE_EVENT(1, severity::LOW);
//! [EXPORT] : [COMMENT] Supervisor handler replied action message indicating a command execution
//! failure of the update available command
static const Event UPDATE_AVAILABLE_FAILED = MAKE_EVENT(2, severity::LOW);
//! [EXPORT] : [COMMENT] Supervisor handler failed to transfer an update space packet.
//! P1: Parameter holds the number of update packets already sent (inclusive the failed packet)
static const Event UPDATE_TRANSFER_FAILED = MAKE_EVENT(3, severity::LOW);
//! [EXPORT] : [COMMENT] Supervisor failed to execute the update verify command.
static const Event UPDATE_VERIFY_FAILED = MAKE_EVENT(4, severity::LOW);
//! [EXPORT] : [COMMENT] MPSoC update successful completed
static const Event UPDATE_FINISHED = MAKE_EVENT(5, severity::INFO);
static const uint32_t QUEUE_SIZE = config::PLOC_UPDATER_QUEUE_SIZE;
static const size_t MAX_PLOC_UPDATE_PATH = 50;
static const size_t SD_PREFIX_LENGTH = 8;
// Maximum size of update payload data per space packet (max size of space packet is 1024 bytes)
static const size_t MAX_SP_DATA = 1016;
static const uint32_t TOPBIT_32 = (1 << 31);
static const uint32_t POLYNOMIAL_32 = 0x04C11DB7;
static const uint32_t INITIAL_REMAINDER_32 = 0xFFFFFFFF;
static const uint32_t FINAL_XOR_VALUE_32 = 0xFFFFFFFF;
MessageQueueIF* commandQueue = nullptr;
#if BOARD_TE0720 == 0
SdCardManager* sdcMan = nullptr;
#endif
CommandActionHelper commandActionHelper;
ActionHelper actionHelper;
enum class State : uint8_t {
IDLE,
UPDATE_AVAILABLE,
UPDATE_TRANSFER,
UPDATE_VERIFY,
COMMAND_EXECUTING
};
State state = State::IDLE;
ActionId_t pendingCommand = PLOC_SPV::NONE;
enum class Image : uint8_t { NONE, A, B };
Image image = Image::NONE;
enum class Partition : uint8_t { NONE, UBOOT, BITSTREAM, LINUX_OS, APP_SW };
Partition partition = Partition::NONE;
uint32_t packetsSent = 0;
uint32_t remainingPackets = 0;
// Number of packets required to transfer the update image
uint32_t numOfUpdatePackets = 0;
std::string updateFile;
uint32_t imageSize = 0;
uint32_t imageCrc = 0;
void readCommandQueue();
void doStateMachine();
/**
* @brief Extracts the path and name of the update image from the service 8 command data.
*/
ReturnValue_t getImageLocation(const uint8_t* data, size_t size);
ReturnValue_t checkNameLength(size_t size);
/**
* @brief Prepares and sends update available command to PLOC supervisor handler.
*/
void commandUpdateAvailable();
/**
* @brief Prepares and sends and update packet to the PLOC supervisor handler.
*/
void commandUpdatePacket();
/**
* @brief Prepares and sends the update verification packet to the PLOC supervisor handler.
*/
void commandUpdateVerify();
void calcImageCrc();
void adjustSequenceFlags(PLOC_SPV::UpdatePacket& packet);
};
#endif /* MISSION_DEVICES_PLOCUPDATER_H_ */

View File

@ -10,6 +10,7 @@
#cmakedefine XIPHOS_Q7S
#cmakedefine BEAGLEBONEBLACK
#cmakedefine EGSE
#cmakedefine TE0720_1CFA
#ifdef RASPBERRY_PI
#include "rpiConfig.h"
@ -36,11 +37,11 @@ debugging. */
#define Q7S_EM 0
#define OBSW_USE_CCSDS_IP_CORE 1
#define OBSW_USE_CCSDS_IP_CORE 0
// Set to 1 if all telemetry should be sent to the PTME IP Core
#define OBSW_TM_TO_PTME 1
#define OBSW_TM_TO_PTME 0
// Set to 1 if telecommands are received via the PDEC IP Core
#define OBSW_TC_FROM_PDEC 1
#define OBSW_TC_FROM_PDEC 0
#define OBSW_ENABLE_TIMERS 1
#define OBSW_ADD_MGT 1
@ -69,6 +70,36 @@ debugging. */
#define OBSW_ADD_STAR_TRACKER 1
#endif
#ifdef TE0720_1CFA
#define OBSW_USE_CCSDS_IP_CORE 0
// Set to 1 if all telemetry should be sent to the PTME IP Core
#define OBSW_TM_TO_PTME 0
// Set to 1 if telecommands are received via the PDEC IP Core
#define OBSW_TC_FROM_PDEC 0
#define OBSW_ENABLE_TIMERS 1
#define OBSW_ADD_MGT 0
#define OBSW_ADD_BPX_BATTERY_HANDLER 0
#define OBSW_ADD_STAR_TRACKER 0
#define OBSW_ADD_PLOC_SUPERVISOR 0
#define OBSW_ADD_PLOC_MPSOC 1
#define OBSW_ADD_SUN_SENSORS 0
#define OBSW_ADD_ACS_BOARD 1
#define OBSW_ADD_ACS_HANDLERS 0
#define OBSW_ADD_RW 0
#define OBSW_ADD_RTD_DEVICES 0
#define OBSW_ADD_TMP_DEVICES 0
#define OBSW_ADD_RAD_SENSORS 0
#define OBSW_ADD_PL_PCDU 0
#define OBSW_ADD_SYRLINKS 0
#define OBSW_ENABLE_SYRLINKS_TRANSMIT_TIMEOUT 0
#define OBSW_SYRLINKS_SIMULATED 1
#define OBSW_STAR_TRACKER_GROUND_CONFIG 1
#define OBSW_ENABLE_PERIODIC_HK 0
#define OBSW_PRINT_CORE_HK 0
#endif
/*******************************************************************/
/** All of the following flags should be disabled for mission code */
/*******************************************************************/

View File

@ -524,6 +524,7 @@ ReturnValue_t pst::pstUart(FixedTimeslotTaskIF *thisSequence) {
ReturnValue_t pst::pstGompaceCan(FixedTimeslotTaskIF *thisSequence) {
uint32_t length = thisSequence->getPeriodMs();
#ifndef TE0720_1CFA
#if Q7S_EM != 1
// PCDU handlers receives two messages and both must be handled
thisSequence->addSlot(objects::PCDU_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION);
@ -558,6 +559,7 @@ ReturnValue_t pst::pstGompaceCan(FixedTimeslotTaskIF *thisSequence) {
return HasReturnvaluesIF::RETURN_FAILED;
}
#endif /* Q7S_EM == 0 */
#endif
static_cast<void>(length);
return HasReturnvaluesIF::RETURN_OK;
}