#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_PLOCMPSOCDEFINITIONS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_PLOCMPSOCDEFINITIONS_H_ #include "MPSoCReturnValuesIF.h" #include "OBSWConfig.h" #include "eive/definitions.h" #include "fsfw/globalfunctions/CRC.h" #include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/tmtcpacket/SpacePacket.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 DeviceCommandId_t TC_FLASHDELETE = 10; static const DeviceCommandId_t TC_REPLAY_START = 11; static const DeviceCommandId_t TC_REPLAY_STOP = 12; static const DeviceCommandId_t TC_REPLAY_WRITE_SEQUENCE = 13; static const DeviceCommandId_t TC_DOWNLINK_PWR_ON = 14; static const DeviceCommandId_t TC_DOWNLINK_PWR_OFF = 15; static const DeviceCommandId_t TC_MODE_REPLAY = 16; // Will reset the sequence count of the OBSW static const DeviceCommandId_t OBSW_RESET_SEQ_COUNT = 50; 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_REPLAY_START = 0x110; static const uint16_t TC_REPLAY_STOP = 0x111; static const uint16_t TC_REPLAY_WRITE_SEQUENCE = 0x112; static const uint16_t TC_DOWNLINK_PWR_ON = 0x113; 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 TC_FLASHDELETE = 0x11C; static const uint16_t TC_MODE_REPLAY = 0x11F; static const uint16_t TC_DOWNLINK_PWR_OFF = 0x124; 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; } // namespace apid /** 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; static const char NULL_TERMINATOR = '\0'; /** * 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; /** * The replay write sequence command has a maximum delay for the execution report which amounts to * 30 seconds. (80 cycles * 0.5 seconds = 40 seconds). */ static const uint16_t TC_WRITE_SEQ_EXECUTION_DELAY = 80; // Requires approx. 2 seconds for execution. 8 => 4 seconds static const uint16_t TC_DOWNLINK_PWR_ON_EXECUTION_DELAY = 8; /** * @brief Abstract base class for TC space packet of MPSoC. */ class TcBase : public SpacePacket, public MPSoCReturnValuesIF { public: // Initial length field of space packet. Will always be updated when packet is created. static const uint16_t INIT_LENGTH = 1; /** * @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 = HasReturnvaluesIF::RETURN_OK; result = initPacket(commandData, commandDataLen); if (result != HasReturnvaluesIF::HasReturnvaluesIF::RETURN_OK) { return result; } result = addCrc(); if (result != HasReturnvaluesIF::HasReturnvaluesIF::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 HasReturnvaluesIF::RETURN_OK; } /** * @brief Calculates and adds the CRC */ ReturnValue_t addCrc() { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; size_t serializedSize = 0; uint32_t full_size = getFullSize(); uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); result = SerializeAdapter::serialize( &crc, this->localData.byteStream + full_size - CRC_SIZE, &serializedSize, sizeof(crc), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::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 MPSoCReturnValuesIF { public: /** * @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() - CRC_SIZE); if (recalculatedCrc != receivedCrc) { return CRC_FAILURE; } return HasReturnvaluesIF::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 = HasReturnvaluesIF::RETURN_OK; result = lengthCheck(commandDataLen); if (result != HasReturnvaluesIF::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 != HasReturnvaluesIF::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 HasReturnvaluesIF::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 = HasReturnvaluesIF::RETURN_OK; result = lengthCheck(commandDataLen); if (result != HasReturnvaluesIF::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) { sif::warning << "TcMemWrite: Command has invalid length " << commandDataLen << std::endl; return INVALID_LENGTH; } return HasReturnvaluesIF::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_) { accessMode = accessMode_; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; size_t nameSize = filename.size(); std::memcpy(this->getPacketData(), filename.c_str(), nameSize); *(this->getPacketData() + nameSize) = NULL_TERMINATOR; std::memcpy(this->getPacketData() + nameSize + sizeof(NULL_TERMINATOR), &accessMode, sizeof(accessMode)); this->setPacketDataLength(nameSize + sizeof(NULL_TERMINATOR) + sizeof(accessMode) + CRC_SIZE - 1); result = addCrc(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } return result; } private: char accessMode = APPEND; }; /** * @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 = HasReturnvaluesIF::RETURN_OK; size_t nameSize = filename.size(); std::memcpy(this->getPacketData(), filename.c_str(), nameSize); *(this->getPacketData() + nameSize) = NULL_TERMINATOR; this->setPacketDataLength(nameSize + sizeof(NULL_TERMINATOR) + CRC_SIZE - 1); result = addCrc(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } return result; } }; /** * @brief Class to build flash write space packet. */ class TcFlashWrite : public TcBase { public: TcFlashWrite(uint16_t sequenceCount) : TcBase(apid::TC_FLASHWRITE, sequenceCount) {} ReturnValue_t createPacket(const uint8_t* writeData, uint32_t writeLen_) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; writeLen = writeLen_; if (writeLen > MAX_DATA_SIZE) { sif::debug << "FlashWrite::createPacket: Command data too big" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } size_t serializedSize = 0; result = SerializeAdapter::serialize(&writeLen, this->getPacketData(), &serializedSize, sizeof(writeLen), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } std::memcpy(this->getPacketData() + sizeof(writeLen), writeData, writeLen); this->setPacketDataLength(static_cast(writeLen + CRC_SIZE - 1)); result = addCrc(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } return HasReturnvaluesIF::RETURN_OK; } private: uint32_t writeLen = 0; }; /** * @brief Class to help creation of flash delete command. */ class TcFlashDelete : public TcBase { public: TcFlashDelete(uint16_t sequenceCount) : TcBase(apid::TC_FLASHDELETE, sequenceCount) {} ReturnValue_t createPacket(std::string filename) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; size_t nameSize = filename.size(); std::memcpy(this->getPacketData(), filename.c_str(), nameSize); *(this->getPacketData() + nameSize) = NULL_TERMINATOR; this->setPacketDataLength(nameSize + sizeof(NULL_TERMINATOR) + CRC_SIZE - 1); result = addCrc(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } return result; } }; /** * @brief Class to build replay stop space packet. */ class TcReplayStop : public TcBase { public: TcReplayStop(uint16_t sequenceCount) : TcBase(apid::TC_REPLAY_STOP, sequenceCount) {} ReturnValue_t createPacket() { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; result = addCrc(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } this->setPacketDataLength(static_cast(CRC_SIZE - 1)); return HasReturnvaluesIF::RETURN_OK; } }; /** * @brief This class helps to build the replay start command. */ class TcReplayStart : public TcBase { public: /** * @brief Constructor */ TcReplayStart(uint16_t sequenceCount) : TcBase(apid::TC_REPLAY_START, sequenceCount) {} protected: ReturnValue_t initPacket(const uint8_t* commandData, size_t commandDataLen) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; result = lengthCheck(commandDataLen); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } result = checkData(*commandData); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } std::memcpy(this->localData.fields.buffer, commandData, commandDataLen); this->setPacketDataLength(commandDataLen + CRC_SIZE - 1); return result; } private: static const size_t COMMAND_DATA_LENGTH = 1; static const uint8_t REPEATING = 0; static const uint8_t ONCE = 1; ReturnValue_t lengthCheck(size_t commandDataLen) { if (commandDataLen != COMMAND_DATA_LENGTH) { sif::warning << "TcReplayStart: Command has invalid length " << commandDataLen << std::endl; return INVALID_LENGTH; } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t checkData(uint8_t replay) { if (replay != REPEATING && replay != ONCE) { sif::warning << "TcReplayStart::checkData: Invalid replay value" << std::endl; return INVALID_PARAMETER; } return HasReturnvaluesIF::RETURN_OK; } }; /** * @brief This class helps to build downlink power on command. */ class TcDownlinkPwrOn : public TcBase { public: /** * @brief Constructor */ TcDownlinkPwrOn(uint16_t sequenceCount) : TcBase(apid::TC_DOWNLINK_PWR_ON, sequenceCount) {} protected: ReturnValue_t initPacket(const uint8_t* commandData, size_t commandDataLen) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; result = lengthCheck(commandDataLen); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } result = modeCheck(*commandData); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } result = laneRateCheck(*(commandData + 1)); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } std::memcpy(this->localData.fields.buffer, commandData, commandDataLen); std::memcpy(this->localData.fields.buffer + commandDataLen, &MAX_AMPLITUDE, sizeof(MAX_AMPLITUDE)); this->setPacketDataLength(commandDataLen + sizeof(MAX_AMPLITUDE) + CRC_SIZE - 1); return result; } private: static const uint8_t INTERFACE_ID = CLASS_ID::DWLPWRON_CMD; //! [EXPORT] : [COMMENT] Received command has invalid JESD mode (valid modes are 0 - 5) static const ReturnValue_t INVALID_MODE = MAKE_RETURN_CODE(0xE0); //! [EXPORT] : [COMMENT] Received command has invalid lane rate (valid lane rate are 0 - 9) static const ReturnValue_t INVALID_LANE_RATE = MAKE_RETURN_CODE(0xE1); static const size_t COMMAND_DATA_LENGTH = 2; static const uint8_t MAX_MODE = 5; static const uint8_t MAX_LANE_RATE = 9; static const uint16_t MAX_AMPLITUDE = 0; ReturnValue_t lengthCheck(size_t commandDataLen) { if (commandDataLen != COMMAND_DATA_LENGTH) { sif::warning << "TcDownlinkPwrOn: Command has invalid length " << commandDataLen << std::endl; return INVALID_LENGTH; } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t modeCheck(uint8_t mode) { if (mode > MAX_MODE) { sif::warning << "TcDwonlinkPwrOn::modeCheck: Invalid JESD mode" << std::endl; return INVALID_MODE; } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t laneRateCheck(uint8_t laneRate) { if (laneRate > MAX_LANE_RATE) { sif::warning << "TcReplayStart::laneRateCheck: Invalid lane rate" << std::endl; return INVALID_LANE_RATE; } return HasReturnvaluesIF::RETURN_OK; } }; /** * @brief Class to build replay stop space packet. */ class TcDownlinkPwrOff : public TcBase { public: TcDownlinkPwrOff(uint16_t sequenceCount) : TcBase(apid::TC_DOWNLINK_PWR_OFF, sequenceCount) {} ReturnValue_t createPacket() { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; result = addCrc(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } this->setPacketDataLength(static_cast(CRC_SIZE - 1)); return HasReturnvaluesIF::RETURN_OK; } }; /** * @brief This class helps to build the replay start command. */ class TcReplayWriteSeq : public TcBase { public: /** * @brief Constructor */ TcReplayWriteSeq(uint16_t sequenceCount) : TcBase(apid::TC_REPLAY_WRITE_SEQUENCE, sequenceCount) {} protected: ReturnValue_t initPacket(const uint8_t* commandData, size_t commandDataLen) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; result = lengthCheck(commandDataLen); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } std::memcpy(this->localData.fields.buffer, commandData, commandDataLen); *(this->localData.fields.buffer + commandDataLen) = NULL_TERMINATOR; this->setPacketDataLength(commandDataLen + sizeof(NULL_TERMINATOR) + CRC_SIZE - 1); return result; } private: static const size_t USE_DECODING_LENGTH = 1; ReturnValue_t lengthCheck(size_t commandDataLen) { if (commandDataLen > USE_DECODING_LENGTH + MAX_FILENAME_SIZE) { sif::warning << "TcReplayWriteSeq: Command has invalid length " << commandDataLen << std::endl; return INVALID_LENGTH; } return HasReturnvaluesIF::RETURN_OK; } }; /** * @brief Helps to extract the fields of the flash write command from the PUS packet. */ class FlashWritePusCmd : public MPSoCReturnValuesIF { public: FlashWritePusCmd(){}; ReturnValue_t extractFields(const uint8_t* commandData, size_t commandDataLen) { if (commandDataLen > (config::MAX_PATH_SIZE + config::MAX_FILENAME_SIZE + MAX_FILENAME_SIZE)) { return INVALID_LENGTH; } obcFile = std::string(reinterpret_cast(commandData)); if (obcFile.size() > (config::MAX_PATH_SIZE + config::MAX_FILENAME_SIZE)) { return FILENAME_TOO_LONG; } mpsocFile = std::string( reinterpret_cast(commandData + obcFile.size() + SIZE_NULL_TERMINATOR)); if (mpsocFile.size() > MAX_FILENAME_SIZE) { return MPSOC_FILENAME_TOO_LONG; } return HasReturnvaluesIF::RETURN_OK; } std::string getObcFile() { return obcFile; } std::string getMPSoCFile() { return mpsocFile; } private: static const size_t SIZE_NULL_TERMINATOR = 1; std::string obcFile = ""; std::string mpsocFile = ""; }; /** * @brief Class to build replay stop space packet. */ class TcModeReplay : public TcBase { public: TcModeReplay(uint16_t sequenceCount) : TcBase(apid::TC_MODE_REPLAY, sequenceCount) {} ReturnValue_t createPacket() { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; result = addCrc(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } this->setPacketDataLength(static_cast(CRC_SIZE - 1)); return HasReturnvaluesIF::RETURN_OK; } }; } // namespace mpsoc #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_PLOCMPSOCDEFINITIONS_H_ */