pdec handler
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
target_sources(${TARGET_NAME} PUBLIC
|
||||
PapbVcInterface.cpp
|
||||
Ptme.cpp
|
||||
PdecHandler.cpp
|
||||
)
|
||||
|
||||
|
||||
|
31
linux/obc/PdecConfig.h
Normal file
31
linux/obc/PdecConfig.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef LINUX_OBC_PDECCONFIG_H_
|
||||
#define LINUX_OBC_PDECCONFIG_H_
|
||||
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include <cstring>
|
||||
|
||||
/**
|
||||
* @brief PDEC specific configuration parameters.
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
namespace PdecConfig {
|
||||
|
||||
// Access to register space of PDEC via the AXI to AHB bridge
|
||||
static const char UIO_PDEC_REGISTERS[] = "/dev/uio0";
|
||||
// Direct access to memory area in DDR assigned to PDEC
|
||||
static const char UIO_PDEC_MEMORY[] = "/dev/uio2";
|
||||
|
||||
// TC transfer frame configuration parameters
|
||||
static const uint8_t VERSION_ID = 0;
|
||||
static const uint8_t BYPASS_FLAG = 1;
|
||||
static const uint8_t CONTROL_COMMAND_FLAG = 1;
|
||||
static const uint8_t VIRTUAL_CHANNEL = 0;
|
||||
static const uint8_t RESERVED_FIELD_A = 0;
|
||||
static const uint16_t SPACECRAFT_ID = 0x274;
|
||||
// Parameters to control the FARM for AD frames
|
||||
static const uint8_t POSITIVE_WINDOW = 10;
|
||||
static const uint8_t NEGATIVE_WINDOW = 151;
|
||||
};
|
||||
|
||||
#endif /* LINUX_OBC_PDECCONFIG_H_ */
|
379
linux/obc/PdecHandler.cpp
Normal file
379
linux/obc/PdecHandler.cpp
Normal file
@ -0,0 +1,379 @@
|
||||
#include <cstring>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "PdecHandler.h"
|
||||
#include "OBSWConfig.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
|
||||
PdecHandler::PdecHandler(object_id_t objectId, object_id_t tcDestinationId, LinuxLibgpioIF* gpioComIF,
|
||||
gpioId_t pdecReset) :
|
||||
SystemObject(objectId), tcDestinationId(tcDestinationId), gpioComIF(gpioComIF), pdecReset(
|
||||
pdecReset) {
|
||||
|
||||
}
|
||||
|
||||
PdecHandler::~PdecHandler() {
|
||||
}
|
||||
|
||||
ReturnValue_t PdecHandler::initialize() {
|
||||
|
||||
tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (tcStore == nullptr) {
|
||||
sif::error << "PdecHandler::initialize: Invalid TC store" << std::endl;
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
tcDestination = ObjectManager::instance()->get<AcceptsTelecommandsIF>(
|
||||
tcDestinationId);
|
||||
|
||||
if (tcDestination == nullptr) {
|
||||
sif::error << "PdecHandler::initialize: Invalid tc destination specified" << std::endl;
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
|
||||
result = getRegisterAddress();
|
||||
if (result != RETURN_OK) {
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
result = getMemoryBaseAddress();
|
||||
if (result != RETURN_OK) {
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
writePdecConfig();
|
||||
|
||||
result = releasePdec();
|
||||
if (result != RETURN_OK) {
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PdecHandler::getRegisterAddress() {
|
||||
int fd = open(PdecConfig::UIO_PDEC_REGISTERS, O_RDWR);
|
||||
if (fd < 1) {
|
||||
sif::warning << "PdecHandler::getRegisterAddress: Invalid UIO device file" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
registerBaseAddress = static_cast<uint32_t*>(mmap(NULL, REGISTER_MAP_SIZE,
|
||||
PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0));
|
||||
|
||||
if (registerBaseAddress == MAP_FAILED) {
|
||||
sif::error << "PdecHandler::getRegisterAddress: Failed to map uio address" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PdecHandler::getMemoryBaseAddress() {
|
||||
int fd = open(PdecConfig::UIO_PDEC_MEMORY, O_RDWR);
|
||||
if (fd < 1) {
|
||||
sif::warning << "PdecHandler::getMemoryBaseAddress: Invalid UIO device file" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
memoryBaseAddress = static_cast<uint32_t*>(mmap(NULL, MEMORY_MAP_SIZE, PROT_WRITE | PROT_READ,
|
||||
MAP_SHARED, fd, 0));
|
||||
|
||||
if (memoryBaseAddress == MAP_FAILED) {
|
||||
sif::error << "PdecHandler::getMemoryBaseAddress: Failed to map uio address" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void PdecHandler::writePdecConfig() {
|
||||
PdecParams_t pdecParams;
|
||||
pdecParams.versionId = 0;
|
||||
pdecParams.bypassFlag = PdecConfig::BYPASS_FLAG;
|
||||
pdecParams.controlCommandFlag = PdecConfig::CONTROL_COMMAND_FLAG;
|
||||
pdecParams.reservedFieldA = 0;
|
||||
pdecParams.spacecraftId = PdecConfig::SPACECRAFT_ID;
|
||||
pdecParams.virtualChannelId = PdecConfig::VIRTUAL_CHANNEL;
|
||||
pdecParams.dummy = 0;
|
||||
pdecParams.positiveWindow = PdecConfig::POSITIVE_WINDOW;
|
||||
pdecParams.negativeWindow = PdecConfig::NEGATIVE_WINDOW;
|
||||
std::memcpy(memoryBaseAddress, &pdecParams, sizeof(pdecParams));
|
||||
|
||||
// Configure all MAP IDs as invalid
|
||||
for (int idx = 0; idx <= MAX_MAP_ADDR; idx += 4) {
|
||||
*(memoryBaseAddress + MAP_ADDR_LUT_OFFSET + idx / 4) = NO_DESTINATION << 24
|
||||
| NO_DESTINATION << 16 | NO_DESTINATION << 8 | NO_DESTINATION;
|
||||
|
||||
}
|
||||
|
||||
// All TCs with MAP ID 7 will be routed to the PM module (can then be read from memory)
|
||||
uint8_t routeToPm = calcMapAddrEntry(PM_BUFFER);
|
||||
*(memoryBaseAddress + 1) = NO_DESTINATION << 24 | NO_DESTINATION << 16 | NO_DESTINATION << 8
|
||||
| routeToPm;
|
||||
}
|
||||
|
||||
ReturnValue_t PdecHandler::resetFarStatFlag() {
|
||||
uint32_t pdecFar = *(registerBaseAddress + PDEC_FAR_OFFSET);
|
||||
if (pdecFar != FAR_RESET) {
|
||||
sif::warning << "PdecHandler::resetFarStatFlag: FAR register did not match expected value."
|
||||
<< " Read value:" << static_cast<unsigned int>(pdecFar) << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
#if OBSW_DEBUG_PDEC_HANDLER == 1
|
||||
sif::debug << "PdecHandler::resetFarStatFlag: read FAR with value: 0x" << std::hex << pdecFar
|
||||
<< std::endl;
|
||||
#endif /* OBSW_DEBUG_PDEC_HANDLER == 1 */
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PdecHandler::releasePdec() {
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
result = gpioComIF->pullHigh(pdecReset);
|
||||
if (result != RETURN_OK) {
|
||||
sif::error << "PdecHandler::releasePdec: Failed to release PDEC reset signal" << std::endl;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t PdecHandler::performOperation(uint8_t operationCode) {
|
||||
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
|
||||
switch(state) {
|
||||
case State::INIT:
|
||||
resetFarStatFlag();
|
||||
if (result != RETURN_OK) {
|
||||
// Requires reconfiguration and reinitialization of PDEC
|
||||
triggerEvent(INVALID_FAR);
|
||||
state = State::WAIT_FOR_RECOVERY;
|
||||
return result;
|
||||
}
|
||||
state = State::RUNNING;
|
||||
break;
|
||||
case State::RUNNING:
|
||||
if (newTcReceived()) {
|
||||
handleNewTc();
|
||||
}
|
||||
break;
|
||||
case State::WAIT_FOR_RECOVERY:
|
||||
break;
|
||||
default:
|
||||
sif::debug << "PdecHandler::performOperation: Invalid state" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
bool PdecHandler::newTcReceived() {
|
||||
uint32_t pdecFar = *(registerBaseAddress + PDEC_FAR_OFFSET);
|
||||
if (pdecFar >> STAT_POSITION != NEW_FAR_RECEIVED) {
|
||||
return false;
|
||||
}
|
||||
if (!checkFrameAna(pdecFar)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PdecHandler::checkFrameAna(uint32_t pdecFar) {
|
||||
bool frameValid = false;
|
||||
FrameAna_t frameAna = static_cast<FrameAna_t>((pdecFar & FRAME_ANA_MASK) >> FRAME_ANA_POSITION);
|
||||
switch(frameAna) {
|
||||
case(FrameAna_t::ABANDONED_CLTU): {
|
||||
triggerEvent(INVALID_TC_FRAME, ABANDONED_CLTU);
|
||||
sif::debug << "PdecHandler::checkFrameAna: Abondoned CLTU" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(FrameAna_t::FRAME_DIRTY): {
|
||||
triggerEvent(INVALID_TC_FRAME, FRAME_DIRTY);
|
||||
sif::debug << "PdecHandler::checkFrameAna: Frame dirty" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(FrameAna_t::FRAME_ILLEGAL): {
|
||||
sif::debug << "PdecHandler::checkFrameAna: Frame illegal for one reason" << std::endl;
|
||||
handleIReason(pdecFar, FRAME_ILLEGAL_ONE_REASON);
|
||||
break;
|
||||
}
|
||||
case(FrameAna_t::FRAME_ILLEGAL_MULTI_REASON): {
|
||||
sif::debug << "PdecHandler::checkFrameAna: Frame illegal for multiple reasons"
|
||||
<< std::endl;
|
||||
handleIReason(pdecFar, FRAME_ILLEGAL_MULTIPLE_REASONS);
|
||||
break;
|
||||
}
|
||||
case(FrameAna_t::AD_DISCARDED_LOCKOUT): {
|
||||
triggerEvent(INVALID_TC_FRAME, AD_DISCARDED_LOCKOUT);
|
||||
sif::debug << "PdecHandler::checkFrameAna: AD frame discarded because of lockout"
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
case(FrameAna_t::AD_DISCARDED_WAIT): {
|
||||
triggerEvent(INVALID_TC_FRAME, AD_DISCARDED_LOCKOUT);
|
||||
sif::debug << "PdecHandler::checkFrameAna: AD frame discarded because of wait"
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
case(FrameAna_t::AD_DISCARDED_NS_VR): {
|
||||
triggerEvent(INVALID_TC_FRAME, AD_DISCARDED_NS_VS);
|
||||
sif::debug << "PdecHandler::checkFrameAna: AD frame discarded because N(S) or V(R)"
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
case(FrameAna_t::FRAME_ACCEPTED): {
|
||||
sif::debug << "PdecHandler::checkFrameAna: Accepted TC frame" << std::endl;
|
||||
frameValid = true;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sif::debug << "PdecHandler::checkFrameAna: Invaid frame analysis report" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return frameValid;
|
||||
}
|
||||
|
||||
void PdecHandler::handleIReason(uint32_t pdecFar, ReturnValue_t parameter1) {
|
||||
IReason_t ireason = static_cast<IReason_t>((pdecFar & IREASON_MASK) >> IREASON_POSITION);
|
||||
switch(ireason) {
|
||||
case(IReason_t::NO_REPORT): {
|
||||
triggerEvent(INVALID_TC_FRAME, parameter1, NO_REPORT);
|
||||
sif::debug << "PdecHandler::handleIReason: No illegal report" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(IReason_t::ERROR_VERSION_NUMBER): {
|
||||
triggerEvent(INVALID_TC_FRAME, parameter1, ERROR_VERSION_NUMBER);
|
||||
sif::debug << "PdecHandler::handleIReason: Error in version number and reserved A and B "
|
||||
<< "fields" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(IReason_t::ILLEGAL_COMBINATION): {
|
||||
triggerEvent(INVALID_TC_FRAME, parameter1, ILLEGAL_COMBINATION);
|
||||
sif::debug << "PdecHandler::handleIReason: Illegal combination (AC) of bypass and control "
|
||||
<< "command flags" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(IReason_t::INVALID_SC_ID): {
|
||||
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_SC_ID);
|
||||
sif::debug << "PdecHandler::handleIReason: Invalid spacecraft identifier " << std::endl;
|
||||
break;
|
||||
}
|
||||
case(IReason_t::INVALID_VC_ID_MSB): {
|
||||
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_VC_ID_MSB);
|
||||
sif::debug << "PdecHandler::handleIReason: VC identifier bit 0 to 4 did not match "
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
case(IReason_t::INVALID_VC_ID_LSB): {
|
||||
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_VC_ID_LSB);
|
||||
sif::debug << "PdecHandler::handleIReason: VC identifier bit 5 did not match " << std::endl;
|
||||
break;
|
||||
}
|
||||
case(IReason_t::NS_NOT_ZERO): {
|
||||
triggerEvent(INVALID_TC_FRAME, parameter1, NS_NOT_ZERO);
|
||||
sif::debug << "PdecHandler::handleIReason: N(S) of BC or BD frame not set to all zeros"
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
case(IReason_t::INCORRECT_BC_CC): {
|
||||
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_BC_CC);
|
||||
sif::debug << "PdecHandler::handleIReason: Invalid BC control command format" << std::endl;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sif::debug << "PdecHandler::handleIReason: Invaid reason id" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PdecHandler::handleNewTc() {
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
|
||||
uint32_t tcLength = 0;
|
||||
result = readTc(tcLength);
|
||||
if (result != RETURN_OK) {
|
||||
return;
|
||||
}
|
||||
#if OBSW_DEBUG_PDEC == 1
|
||||
unsigned int mapId = tcSegment[0] & MAP_ID_MASK;
|
||||
sif::debug << "PdecHandler::handleNewTc: Received TC segment with map ID" << mapId
|
||||
<< std::endl;
|
||||
#endif /* OBSW_DEBUG_PDEC */
|
||||
|
||||
store_address_t storeId;
|
||||
result = tcStore->addData(&storeId, tcSegment + 1, tcLength - 1);
|
||||
if (result != RETURN_OK) {
|
||||
sif::warning << "PdecHandler::handleNewTc: Failed to add received space packet to store"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
TmTcMessage message(storeId);
|
||||
|
||||
result = MessageQueueSenderIF::sendMessage(tcDestination->getRequestQueue(), &message);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
sif::warning << "PdecHandler::handleNewTc: Failed to send message to TC destination"
|
||||
<< std::endl;
|
||||
tcStore->deleteData(storeId);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ReturnValue_t PdecHandler::readTc(uint32_t& tcLength) {
|
||||
uint32_t tcOffset = *(registerBaseAddress + PDEC_BPTR_OFFSET) - PHYSICAL_BASE_ADDRESS;
|
||||
|
||||
#if OBSW_DEBUG_PDEC == 1
|
||||
sif::debug << "PdecHandler::readTc: TC offset: " << std::hex << tcOffset << std::endl;
|
||||
#endif /* OBSW_DEBUG_PDEC */
|
||||
|
||||
uint32_t* tcPtr = reinterpret_cast<uint32_t*>(*(registerBaseAddress + tcOffset) / 4);
|
||||
tcLength = *(registerBaseAddress + PDEC_SLEN_OFFSET);
|
||||
|
||||
#if OBSW_DEBUG_PDEC == 1
|
||||
sif::debug << "PdecHandler::readTc: TC length: " << tcLength << std::endl;
|
||||
#endif /* OBSW_DEBUG_PDEC */
|
||||
|
||||
if (tcLength > MAX_TC_SEGMENT_SIZE) {
|
||||
sif::warning << "PdecHandler::handleNewTc: Read invalid TC length from PDEC register"
|
||||
<< std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
uint32_t idx = 0;
|
||||
uint32_t tcData = 0;
|
||||
for (idx = 0; idx < tcLength; idx = idx + 4) {
|
||||
tcData = *(tcPtr + idx);
|
||||
std::memcpy(tcSegment + idx, &tcData, sizeof(tcData));
|
||||
}
|
||||
|
||||
// Backend buffer is handled back to PDEC3
|
||||
*(registerBaseAddress + PDEC_BFREE_OFFSET) = 0;
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
uint8_t PdecHandler::calcMapAddrEntry(uint8_t moduleId) {
|
||||
uint8_t lutEntry = 0;
|
||||
uint8_t parity = getOddParity(moduleId | (1 << VALID_POSITION));
|
||||
lutEntry = (parity << PARITY_POSITION) | (1 << VALID_POSITION) | moduleId;
|
||||
return lutEntry;
|
||||
}
|
||||
|
||||
uint8_t PdecHandler::getOddParity(uint8_t number) {
|
||||
uint8_t parityBit = 0;
|
||||
uint8_t countBits = 0;
|
||||
for (unsigned int idx = 0; idx < sizeof(number) * 8; idx++) {
|
||||
countBits += (number >> idx) & 0x1;
|
||||
}
|
||||
parityBit = ~(countBits & 0x1) & 0x1;
|
||||
return parityBit;
|
||||
}
|
298
linux/obc/PdecHandler.h
Normal file
298
linux/obc/PdecHandler.h
Normal file
@ -0,0 +1,298 @@
|
||||
#ifndef LINUX_OBC_PDECHANDLER_H_
|
||||
#define LINUX_OBC_PDECHANDLER_H_
|
||||
|
||||
#include "PdecConfig.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include "fsfw_hal/common/gpio/gpioDefinitions.h"
|
||||
#include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
|
||||
/**
|
||||
* @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 HasReturnvaluesIF {
|
||||
|
||||
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.
|
||||
*/
|
||||
PdecHandler(object_id_t objectId, object_id_t tcDestinationId, LinuxLibgpioIF* gpioComIF,
|
||||
gpioId_t pdecReset);
|
||||
|
||||
virtual ~PdecHandler();
|
||||
|
||||
ReturnValue_t performOperation(uint8_t operationCode = 0);
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
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);
|
||||
|
||||
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 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);
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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_BFREE_OFFSET = 0xA24;
|
||||
static const uint32_t PDEC_BPTR_OFFSET = 0xA25;
|
||||
static const uint32_t PDEC_SLEN_OFFSET = 0xA26;
|
||||
|
||||
static const int MEMORY_MAP_SIZE = 0xF42400;
|
||||
static const int REGISTER_MAP_SIZE = 0x10000;
|
||||
|
||||
static const size_t MAX_TC_SEGMENT_SIZE = 1017;
|
||||
static const uint8_t MAP_ID_MASK = 0x3F;
|
||||
|
||||
static const uint32_t PHYSICAL_BASE_ADDRESS = 0x30000000;
|
||||
static const uint32_t MAP_ADDR_LUT_OFFSET = 0xA0;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* TCs with map addresses (also know as Map IDs) assigned to this channel will be stored in
|
||||
* the PDEC memory.
|
||||
*/
|
||||
static const uint32_t PM_BUFFER = 7;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
typedef struct PdecParams {
|
||||
uint8_t versionId : 2 ;
|
||||
uint8_t bypassFlag : 1;
|
||||
uint8_t controlCommandFlag : 1;
|
||||
uint8_t reservedFieldA : 2;
|
||||
uint16_t spacecraftId : 10;
|
||||
uint8_t virtualChannelId : 6;
|
||||
uint8_t dummy : 2;
|
||||
uint8_t positiveWindow;
|
||||
uint8_t negativeWindow;
|
||||
//Authentication unit not used for EIVE
|
||||
uint8_t auMapIdPointer = 0;
|
||||
// De-randomizing enabled
|
||||
uint8_t derandomiserConfig = 1;
|
||||
// Only used when AU is enabled. Enables the use of an external recovery lac counter.
|
||||
// The AU requires a lac counter to generate the signature.
|
||||
uint8_t recoveryLacConfig = 0;
|
||||
} PdecParams_t;
|
||||
|
||||
enum class State: uint8_t {
|
||||
INIT,
|
||||
RUNNING,
|
||||
WAIT_FOR_RECOVERY
|
||||
};
|
||||
|
||||
/**
|
||||
* @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 getMemoryBaseAddress();
|
||||
|
||||
/**
|
||||
* @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 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 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);
|
||||
|
||||
object_id_t tcDestinationId;
|
||||
|
||||
AcceptsTelecommandsIF* tcDestination = nullptr;
|
||||
|
||||
LinuxLibgpioIF* gpioComIF = nullptr;
|
||||
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
|
||||
State state = State::INIT;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// Pointer pointing to base address of register space
|
||||
uint32_t* registerBaseAddress = nullptr;
|
||||
|
||||
uint32_t pdecFar = 0;
|
||||
|
||||
uint8_t tcSegment[1017];
|
||||
};
|
||||
|
||||
#endif /* LINUX_OBC_PDECHANDLER_H_ */
|
@ -3,10 +3,10 @@
|
||||
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "OBSWConfig.h"
|
||||
|
||||
/**
|
||||
* @brief Configuration parameters derived from FPGA design and device tree.
|
||||
* @brief PTME specific configuration parameters derived from FPGA design and device tree.
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
@ -19,8 +19,12 @@ namespace PtmeConfig {
|
||||
static const uint32_t VC1_OFFSETT = 0x4000;
|
||||
static const uint32_t VC2_OFFSETT = 0x8000;
|
||||
static const uint32_t VC3_OFFSETT = 0xC000;
|
||||
|
||||
#if BOARD_TE0720 == 0
|
||||
static const char UIO_DEVICE_FILE[] = "/dev/uio0";
|
||||
#else
|
||||
static const char UIO_DEVICE_FILE[] = "/dev/uio1";
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif /* LINUX_OBC_PTMECONFIG_H_ */
|
||||
|
Reference in New Issue
Block a user