eive-obsw/linux/obc/PdecHandler.h

416 lines
15 KiB
C
Raw Normal View History

2021-11-01 12:41:20 +01:00
#ifndef LINUX_OBC_PDECHANDLER_H_
#define LINUX_OBC_PDECHANDLER_H_
2021-11-08 12:25:12 +01:00
#include "OBSWConfig.h"
2021-11-01 12:41:20 +01:00
#include "PdecConfig.h"
2022-01-17 15:58:27 +01:00
#include "fsfw/action/ActionHelper.h"
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/objectmanager/SystemObject.h"
2021-11-01 12:41:20 +01:00
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
2022-01-17 15:58:27 +01:00
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
#include "fsfw_hal/common/gpio/gpioDefinitions.h"
#include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h"
2021-11-01 12:41:20 +01:00
/**
* @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
*/
2021-11-22 10:38:32 +01:00
class PdecHandler : public SystemObject,
public ExecutableObjectIF,
public HasReturnvaluesIF,
public HasActionsIF {
2022-01-17 15:58:27 +01:00
public:
/**
* @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, std::string uioConfigMemory, std::string uioRamMemory,
std::string uioRegisters);
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);
private:
static const uint8_t INTERFACE_ID = CLASS_ID::PDEC_HANDLER;
static const ReturnValue_t ABANDONED_CLTU = MAKE_RETURN_CODE(0xA0);
static const ReturnValue_t FRAME_DIRTY = 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 = MAKE_RETURN_CODE(0xA3);
static const ReturnValue_t AD_DISCARDED_WAIT = 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 = MAKE_RETURN_CODE(0xA6);
//! Error in version number and reserved A and B fields
static const ReturnValue_t ERROR_VERSION_NUMBER = MAKE_RETURN_CODE(0xA7);
//! Illegal combination of bypass and control command flag
static const ReturnValue_t ILLEGAL_COMBINATION = MAKE_RETURN_CODE(0xA8);
//! Spacecraft identifier did not match
static const ReturnValue_t INVALID_SC_ID = MAKE_RETURN_CODE(0xA9);
//! VC identifier bits 0 to 4 did not match
static const ReturnValue_t INVALID_VC_ID_MSB = MAKE_RETURN_CODE(0xAA);
//! VC identifier bit 5 did not match
static const ReturnValue_t INVALID_VC_ID_LSB = MAKE_RETURN_CODE(0xAB);
//! N(S) of BC or BD frame not set to all zeros
static const ReturnValue_t NS_NOT_ZERO = 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 = common::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;
static const uint8_t STAT_POSITION = 31;
static const uint8_t FRAME_ANA_POSITION = 28;
static const uint8_t IREASON_POSITION = 25;
static const uint8_t NEW_FAR_RECEIVED = 0;
static const uint32_t FRAME_ANA_MASK = 0x70000000;
static const uint32_t IREASON_MASK = 0x0E000000;
static const uint32_t TC_CHANNEL_INACTIVE = 0x0;
static const uint32_t TC_CHANNEL_ACTIVE = 0x1;
static const uint32_t TC_CHANNEL_TIMEDOUT = 0x2;
static const uint32_t TC0_STATUS_MASK = 0x3;
static const uint32_t TC1_STATUS_MASK = 0xC;
static const uint32_t TC2_STATUS_MASK = 0x300;
static const uint32_t TC3_STATUS_MASK = 0xC00;
static const uint32_t TC4_STATUS_MASK = 0x30000;
static const uint32_t TC5_STATUS_MASK = 0xc00000;
// Lock register set to 1 when start sequence has been found (CLTU is beeing processed)
static const uint32_t LOCK_MASK = 0xc00000;
static const uint32_t TC0_STATUS_POS = 0;
static const uint32_t TC1_STATUS_POS = 2;
static const uint32_t TC2_STATUS_POS = 4;
static const uint32_t TC3_STATUS_POS = 6;
static const uint32_t TC4_STATUS_POS = 8;
static const uint32_t TC5_STATUS_POS = 10;
// Lock register set to 1 when start sequence has been found (CLTU is beeing processed)
static const uint32_t LOCK_POS = 12;
/**
* UIO is 4 byte aligned. Thus offset is calculated with "true offset" / 4
* Example: PDEC_FAR = 0x2840 => Offset in virtual address space is 0xA10
*/
static const uint32_t PDEC_FAR_OFFSET = 0xA10;
static const uint32_t PDEC_CLCW_OFFSET = 0xA12;
static const uint32_t PDEC_BFREE_OFFSET = 0xA24;
static const uint32_t PDEC_BPTR_OFFSET = 0xA25;
static const uint32_t PDEC_SLEN_OFFSET = 0xA26;
static const uint32_t PDEC_MON_OFFSET = 0xA27;
2021-11-01 12:41:20 +01:00
2021-11-08 12:25:12 +01:00
#if BOARD_TE0720 == 1
2022-01-17 15:58:27 +01:00
static const int CONFIG_MEMORY_MAP_SIZE = 0x400;
static const int RAM_MAP_SIZE = 0x4000;
static const int REGISTER_MAP_SIZE = 0x10000;
2021-11-08 12:25:12 +01:00
#else
2022-01-17 15:58:27 +01:00
static const int CONFIG_MEMORY_MAP_SIZE = 0x400;
static const int RAM_MAP_SIZE = 0x4000;
static const int REGISTER_MAP_SIZE = 0x4000;
2021-11-08 12:25:12 +01:00
#endif /* BOARD_TE0720 == 1 */
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
// 0x200 / 4 = 0x80
static const uint32_t FRAME_HEADER_OFFSET = 0x80;
2021-11-03 18:19:36 +01:00
2022-01-17 15:58:27 +01:00
static const size_t MAX_TC_SEGMENT_SIZE = 1017;
static const uint8_t MAP_ID_MASK = 0x3F;
2021-11-01 12:41:20 +01:00
2021-11-21 13:58:05 +01:00
#if BOARD_TE0720 == 1
2022-01-17 15:58:27 +01:00
static const uint32_t PHYSICAL_RAM_BASE_ADDRESS = 0x32000000;
2021-11-21 13:58:05 +01:00
#else
2022-01-17 15:58:27 +01:00
static const uint32_t PHYSICAL_RAM_BASE_ADDRESS = 0x26000000;
2021-11-21 13:58:05 +01:00
#endif
2022-01-17 15:58:27 +01:00
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;
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 };
/**
* @brief Reads and handles messages stored in the commandQueue
*/
void readCommandQueue(void);
/**
* @brief Opens UIO device assigned to AXI to AHB converter giving access to the PDEC
* registers. The register base address will be mapped into the virtual address space.
*/
ReturnValue_t getRegisterAddress();
/**
* @brief Opens UIO device assigned to the base address of the PDEC memory space and maps the
* physical address into the virtual address space.
*/
ReturnValue_t getConfigMemoryBaseAddress();
/**
* @brief Opens UIO device assigned to the RAM section of the PDEC IP core memory map.
*
* @details A received TC segment will be written to this memory area.
*/
ReturnValue_t getRamBaseAddress();
/**
* @brief This functions writes the configuration parameters to the configuration
* section of the PDEC.
*/
void writePdecConfig();
/**
* @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();
/**
* @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);
object_id_t tcDestinationId;
AcceptsTelecommandsIF* tcDestination = nullptr;
LinuxLibgpioIF* gpioComIF = nullptr;
/**
* 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;
// UIO device file giving access to the PDEC configuration memory section
std::string uioConfigMemory;
// UIO device file giving access to the PDEC RAM section
std::string uioRamMemory;
// UIO device file giving access to the PDEC register space
std::string uioRegisters;
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;
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
uint32_t pdecFar = 0;
uint8_t tcSegment[TC_SEGMENT_LEN];
2021-11-22 18:01:16 +01:00
2022-01-17 15:58:27 +01:00
// Used to check carrier and bit lock changes (default set to no rf and no bitlock)
uint32_t lastClcw = 0xC000;
2021-11-01 12:41:20 +01:00
};
#endif /* LINUX_OBC_PDECHANDLER_H_ */