#ifndef LINUX_OBC_PDECHANDLER_H_ #define LINUX_OBC_PDECHANDLER_H_ #include #include "OBSWConfig.h" #include "PdecConfig.h" #include "eive/definitions.h" #include "fsfw/action/ActionHelper.h" #include "fsfw/action/HasActionsIF.h" #include "fsfw/objectmanager/SystemObject.h" #include "fsfw/returnvalues/returnvalue.h" #include "fsfw/storagemanager/StorageManagerIF.h" #include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" #include "fsfw_hal/common/gpio/gpioDefinitions.h" #include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h" struct UioNames { const char* configMemory; const char* ramMemory; const char* registers; const char* irq; }; /** * @brief This class controls the PDEC IP Core implemented in the programmable logic of the * Zynq-7020. All registers and memories of the PDEC IP Core are accessed via UIO * drivers. * * @details The PDEC IP Core is responsible for processing data received in form of CLTUs from the * S-Band transceiver. This comprises the BCH decoding of the CLTUs and reconstruction of * telecommand transfer frames. Finally the PDEC stores the TC segment transported with * the TC transfer frame in a register. As soon as a new TC has been received a new * frame acceptance report (FAR) will be generated. If the FAR confirms the validity of * a received TC segment, the data can be read out from the associated register. * Currently, the ground software only supports transmissions of CLTUs containing one * space packet. * Link to datasheet of PDEC IP Core: https://eive-cloud.irs.uni-stuttgart.de/index.php/ * apps/files/?dir=/EIVE_IRS/Arbeitsdaten/08_Used%20Components/CCSDS_IP_Cores&fileid=1108967 * * @author J. Meier */ class PdecHandler : public SystemObject, public ExecutableObjectIF, public HasActionsIF { public: static constexpr dur_millis_t IRQ_TIMEOUT_MS = 500; enum class Modes { POLLED, IRQ }; /** * @brief Constructor * @param objectId Object ID of PDEC handler system object * @param tcDestinationId Object ID of object responsible for processing TCs. * @param gpioComIF Pointer to GPIO interace responsible for driving GPIOs. * @param pdecReset GPIO ID of GPIO connected to the reset signal of the PDEC. * @param uioConfigMemory String of uio device file same mapped to the PDEC memory space * @param uioregsiters String of uio device file same mapped to the PDEC register space */ PdecHandler(object_id_t objectId, object_id_t tcDestinationId, LinuxLibgpioIF* gpioComIF, gpioId_t pdecReset, UioNames names); virtual ~PdecHandler(); ReturnValue_t performOperation(uint8_t operationCode = 0); ReturnValue_t initialize() override; MessageQueueId_t getCommandQueue() const; ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size) override; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PDEC_HANDLER; //! [EXPORT] : [COMMENT] Frame acceptance report signals an invalid frame //! P1: The frame analysis information (FrameAna field of PDEC_FAR register) //! P2: When frame declared illegal this parameter this parameter gives information about the //! reason (IReason field of the PDEC_FAR register) static const Event INVALID_TC_FRAME = MAKE_EVENT(1, severity::HIGH); //! [EXPORT] : [COMMENT] Read invalid FAR from PDEC after startup static const Event INVALID_FAR = MAKE_EVENT(2, severity::HIGH); //! [EXPORT] : [COMMENT] Carrier lock detected static const Event CARRIER_LOCK = MAKE_EVENT(3, severity::INFO); //! [EXPORT] : [COMMENT] Bit lock detected (data valid) static const Event BIT_LOCK_PDEC = MAKE_EVENT(4, severity::INFO); //! [EXPORT] : [COMMENT] Lost carrier lock static const Event LOST_CARRIER_LOCK_PDEC = MAKE_EVENT(5, severity::INFO); //! [EXPORT] : [COMMENT] Lost bit lock static const Event LOST_BIT_LOCK_PDEC = MAKE_EVENT(6, severity::INFO); //! [EXPORT] : [COMMENT] Too many IRQs over the time window of one second. P1: Allowed TCs static constexpr Event TOO_MANY_IRQS = MAKE_EVENT(7, severity::MEDIUM); static constexpr Event POLL_SYSCALL_ERROR_PDEC = event::makeEvent(SUBSYSTEM_ID, 8, severity::MEDIUM); static constexpr Event WRITE_SYSCALL_ERROR_PDEC = event::makeEvent(SUBSYSTEM_ID, 9, severity::MEDIUM); private: static const uint8_t INTERFACE_ID = CLASS_ID::PDEC_HANDLER; static constexpr Modes OP_MODE = Modes::IRQ; static const ReturnValue_t ABANDONED_CLTU_RETVAL = MAKE_RETURN_CODE(0xA0); static const ReturnValue_t FRAME_DIRTY_RETVAL = MAKE_RETURN_CODE(0xA1); static const ReturnValue_t FRAME_ILLEGAL_ONE_REASON = MAKE_RETURN_CODE(0xA2); static const ReturnValue_t FRAME_ILLEGAL_MULTIPLE_REASONS = MAKE_RETURN_CODE(0xA2); static const ReturnValue_t AD_DISCARDED_LOCKOUT_RETVAL = MAKE_RETURN_CODE(0xA3); static const ReturnValue_t AD_DISCARDED_WAIT_RETVAL = MAKE_RETURN_CODE(0xA4); static const ReturnValue_t AD_DISCARDED_NS_VS = MAKE_RETURN_CODE(0xA5); //! [EXPORT] : [COMMENT] Received action message with unknown action id static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xB0); static const ReturnValue_t NO_REPORT_RETVAL = MAKE_RETURN_CODE(0xA6); //! Error in version number and reserved A and B fields static const ReturnValue_t ERROR_VERSION_NUMBER_RETVAL = MAKE_RETURN_CODE(0xA7); //! Illegal combination of bypass and control command flag static const ReturnValue_t ILLEGAL_COMBINATION_RETVAL = MAKE_RETURN_CODE(0xA8); //! Spacecraft identifier did not match static const ReturnValue_t INVALID_SC_ID_RETVAL = MAKE_RETURN_CODE(0xA9); //! VC identifier bits 0 to 4 did not match static const ReturnValue_t INVALID_VC_ID_MSB_RETVAL = MAKE_RETURN_CODE(0xAA); //! VC identifier bit 5 did not match static const ReturnValue_t INVALID_VC_ID_LSB_RETVAL = MAKE_RETURN_CODE(0xAB); //! N(S) of BC or BD frame not set to all zeros static const ReturnValue_t NS_NOT_ZERO_RETVAL = MAKE_RETURN_CODE(0xAC); //! Invalid BC control command static const ReturnValue_t INVALID_BC_CC = MAKE_RETURN_CODE(0xAE); static const uint32_t QUEUE_SIZE = config::CCSDS_HANDLER_QUEUE_SIZE; // Action IDs static const ActionId_t PRINT_CLCW = 0; // Print PDEC monitor register static const ActionId_t PRINT_PDEC_MON = 1; #ifdef TE0720_1CFA static const int CONFIG_MEMORY_MAP_SIZE = 0x400; static const int RAM_MAP_SIZE = 0x4000; static const int REGISTER_MAP_SIZE = 0x10000; #else static const int CONFIG_MEMORY_MAP_SIZE = 0x400; static const int RAM_MAP_SIZE = 0x4000; static const int REGISTER_MAP_SIZE = 0x4000; #endif /* BOARD_TE0720 == 1 */ // 0x200 / 4 = 0x80 static const uint32_t FRAME_HEADER_OFFSET = 0x80; static const size_t MAX_TC_SEGMENT_SIZE = 1017; static const uint8_t MAP_ID_MASK = 0x3F; #ifdef TE0720_1CFA static const uint32_t PHYSICAL_RAM_BASE_ADDRESS = 0x32000000; #else static const uint32_t PHYSICAL_RAM_BASE_ADDRESS = 0x26000000; #endif static const uint32_t MAP_ADDR_LUT_OFFSET = 0xA0; static const uint32_t MAP_CLK_FREQ_OFFSET = 0x90; static const uint8_t MAX_MAP_ADDR = 63; // Writing this to the map address in the look up table will invalidate a MAP ID. static const uint8_t NO_DESTINATION = 0; static const uint8_t VALID_POSITION = 6; static const uint8_t PARITY_POSITION = 7; // Expected value stored in FAR register after reset static const uint32_t FAR_RESET = 0x7FE0; static const uint32_t TC_SEGMENT_LEN = 1017; static const uint32_t NO_RF_MASK = 0x8000; static const uint32_t NO_BITLOCK_MASK = 0x4000; /** * TCs with map addresses (also know as Map IDs) assigned to this channel will be stored in * the PDEC memory. */ static const uint8_t PM_BUFFER = 7; // MAP clock frequency. Must be a value between 1 and 13 otherwise the TC segment will be // discarded static const uint8_t MAP_CLK_FREQ = 2; static constexpr uint32_t MAX_ALLOWED_IRQS_PER_WINDOW = 800; enum class FrameAna_t : uint8_t { ABANDONED_CLTU, FRAME_DIRTY, FRAME_ILLEGAL, FRAME_ILLEGAL_MULTI_REASON, AD_DISCARDED_LOCKOUT, AD_DISCARDED_WAIT, AD_DISCARDED_NS_VR, FRAME_ACCEPTED }; enum class IReason_t : uint8_t { NO_REPORT, ERROR_VERSION_NUMBER, ILLEGAL_COMBINATION, INVALID_SC_ID, INVALID_VC_ID_LSB, INVALID_VC_ID_MSB, NS_NOT_ZERO, INCORRECT_BC_CC }; enum class State : uint8_t { INIT, RUNNING, WAIT_FOR_RECOVERY }; static uint32_t CURRENT_FAR; Countdown genericCheckCd = Countdown(IRQ_TIMEOUT_MS); object_id_t tcDestinationId; AcceptsTelecommandsIF* tcDestination = nullptr; LinuxLibgpioIF* gpioComIF = nullptr; uint32_t interruptCounter = 0; Countdown interruptWindowCd = Countdown(1000); /** * Reset signal is required to hold PDEC in reset state until the configuration has been * written to the appropriate memory space. * Can also be used to reboot PDEC in case of erros. */ gpioId_t pdecReset = gpio::NO_GPIO; uint32_t tcAbortCounter = 0; ActionHelper actionHelper; StorageManagerIF* tcStore = nullptr; MessageQueueIF* commandQueue = nullptr; State state = State::INIT; /** * Pointer pointing to base address of the PDEC memory space. * This address is equivalent with the base address of the section named configuration area in * the PDEC datasheet. */ uint32_t* memoryBaseAddress = nullptr; uint32_t* ramBaseAddress = nullptr; // Pointer pointing to base address of register space uint32_t* registerBaseAddress = nullptr; uint8_t tcSegment[TC_SEGMENT_LEN]; // Used to check carrier and bit lock changes (default set to no rf and no bitlock) uint32_t lastClcw = 0xC000; bool carrierLock = false; bool bitLock = false; UioNames uioNames; /** * @brief Reads and handles messages stored in the commandQueue */ void readCommandQueue(void); ReturnValue_t polledOperation(); ReturnValue_t irqOperation(); ReturnValue_t checkAndHandleIrqs(int fd, uint32_t& info); uint32_t readFar(); /** * @brief This functions writes the configuration parameters to the configuration * section of the PDEC. */ void writePdecConfigDuringReset(PdecConfig& config); /** * @brief Reading the FAR resets the set stat flag which signals a new TC. Without clearing * this flag no new TC will be excepted. After start up the flag is set and needs * to be reset. * Stat flag 0 - new TC received * Stat flag 1 - old TC (ready to receive next TC) */ ReturnValue_t resetFarStatFlag(); /** * @brief Releases the PDEC from reset state. PDEC will start with loading the written * configuration parameters. */ ReturnValue_t releasePdec(); /** * @brief Reads the FAR register and checks if a new TC has been received. */ bool newTcReceived(); /** * @brief Checks if carrier lock or bit lock has been detected and triggers appropriate * event. */ void checkLocks(); void resetIrqLimiters(); /** * @brief Analyzes the FramAna field (frame analysis data) of a FAR report. * * @return True if frame valid, otherwise false. */ bool checkFrameAna(uint32_t pdecFar); /** * @brief This function handles the IReason field of the frame analysis report. * * @details In case frame as been declared illegal for multiple reasons, the reason with the * lowest value will be shown. */ void handleIReason(uint32_t pdecFar, ReturnValue_t parameter1); /** * @brief Handles the reception of new TCs. Reads the pointer to the storage location of the * new TC segment, extracts the PUS packet and forwards the data to the object * responsible for processing the TC. */ void handleNewTc(); /** * @brief Function reads the last received TC segment from the PDEC memory and copies * the data to the tcSegement array. * * @param tcLength The length of the received TC. * */ ReturnValue_t readTc(uint32_t& tcLength); /** * @brief Prints the tc segment data */ void printTC(uint32_t tcLength); /** * @brief This function calculates the entry for the configuration of the MAP ID routing. * * @param mapAddr The MAP ID to configure * @param moduleId The destination module where all TCs with the map id mapAddr will be routed * to. * * @details The PDEC has different modules where the TCs can be routed to. A lookup table is * used which links the MAP ID field to the destination module. The entry for this * lookup table is created by this function and must be stored in the configuration * memory region of the PDEC. The entry has a specific format */ uint8_t calcMapAddrEntry(uint8_t moduleId); /** * @brief This functions calculates the odd parity of the bits in number. * * @param number The number from which to calculate the odd parity. */ uint8_t getOddParity(uint8_t number); /** * brief Returns the 32-bit wide communication link control word (CLCW) */ uint32_t getClcw(); /** * @brief Returns the PDEC monitor register content * */ uint32_t getPdecMon(); /** * @brief Reads and prints the CLCW. Can be useful for debugging. */ void printClcw(); /** * @brief Prints monitor register information to debug console. */ void printPdecMon(); std::string getMonStatusString(uint32_t status); }; #endif /* LINUX_OBC_PDECHANDLER_H_ */