eive-obsw/linux/ipcore/PdecHandler.cpp

680 lines
24 KiB
C++
Raw Normal View History

2022-01-26 17:59:31 +01:00
#include "PdecHandler.h"
2021-11-01 12:41:20 +01:00
#include <fcntl.h>
2023-02-20 18:12:33 +01:00
#include <fsfw/tasks/TaskFactory.h>
2022-10-27 10:49:52 +02:00
#include <poll.h>
2022-01-17 15:58:27 +01:00
#include <sys/mman.h>
2022-10-27 10:49:52 +02:00
#include <unistd.h>
2022-01-26 17:59:31 +01:00
2022-01-17 15:58:27 +01:00
#include <cstring>
#include <sstream>
2022-01-26 17:59:31 +01:00
2022-05-29 17:52:13 +02:00
#include "OBSWConfig.h"
2022-01-17 15:58:27 +01:00
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
2021-11-01 12:41:20 +01:00
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
#include "fsfw_hal/linux/uio/UioMapper.h"
2022-10-27 10:49:52 +02:00
#include "pdec.h"
using namespace pdec;
// If this is ever shared, protect it with a mutex!
uint32_t PdecHandler::CURRENT_FAR = 0;
2021-11-01 12:41:20 +01:00
2021-11-02 11:11:38 +01:00
PdecHandler::PdecHandler(object_id_t objectId, object_id_t tcDestinationId,
2022-10-27 10:49:52 +02:00
LinuxLibgpioIF* gpioComIF, gpioId_t pdecReset, UioNames names)
2022-01-17 15:58:27 +01:00
: SystemObject(objectId),
tcDestinationId(tcDestinationId),
gpioComIF(gpioComIF),
pdecReset(pdecReset),
2022-10-27 10:49:52 +02:00
actionHelper(this, nullptr),
uioNames(names) {
2022-03-22 11:57:48 +01:00
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
PdecHandler::~PdecHandler() {}
2021-11-01 12:41:20 +01:00
ReturnValue_t PdecHandler::initialize() {
2022-01-17 15:58:27 +01:00
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;
}
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
tcDestination = ObjectManager::instance()->get<AcceptsTelecommandsIF>(tcDestinationId);
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
if (tcDestination == nullptr) {
sif::error << "PdecHandler::initialize: Invalid tc destination specified" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
2021-11-01 12:41:20 +01:00
2022-08-24 17:27:47 +02:00
ReturnValue_t result = returnvalue::OK;
2021-11-01 12:41:20 +01:00
2022-10-27 10:49:52 +02:00
UioMapper regMapper(uioNames.registers);
result = regMapper.getMappedAdress(&registerBaseAddress, UioMapper::Permissions::READ_WRITE);
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
return ObjectManagerIF::CHILD_INIT_FAILED;
}
2022-10-27 10:49:52 +02:00
UioMapper configMemMapper(uioNames.configMemory);
result = configMemMapper.getMappedAdress(&memoryBaseAddress, UioMapper::Permissions::READ_WRITE);
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
return ObjectManagerIF::CHILD_INIT_FAILED;
}
2022-10-27 10:49:52 +02:00
UioMapper ramMapper(uioNames.ramMemory);
result = ramMapper.getMappedAdress(&ramBaseAddress, UioMapper::Permissions::READ_WRITE);
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
return ObjectManagerIF::CHILD_INIT_FAILED;
}
2021-11-03 18:19:36 +01:00
2022-10-27 10:49:52 +02:00
if (OP_MODE == Modes::IRQ and uioNames.irq == nullptr) {
sif::error << "Can not use IRQ mode if IRQ UIO name is invalid" << std::endl;
return returnvalue::FAILED;
}
2022-11-02 18:58:29 +01:00
PdecConfig pdecConfig;
writePdecConfigDuringReset(pdecConfig);
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
result = releasePdec();
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
return ObjectManagerIF::CHILD_INIT_FAILED;
}
2021-11-01 12:41:20 +01:00
2022-11-02 18:58:29 +01:00
// This configuration must be done while the PDEC is not held in reset.
if (OP_MODE == Modes::IRQ) {
// Configure interrupt mask register to enable interrupts
*(registerBaseAddress + PDEC_IMR_OFFSET) = pdecConfig.getImrReg();
}
2022-01-17 15:58:27 +01:00
result = actionHelper.initialize(commandQueue);
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
return result;
}
2021-11-22 10:38:32 +01:00
2022-08-24 17:27:47 +02:00
return returnvalue::OK;
2021-11-01 12:41:20 +01:00
}
2022-10-26 14:35:47 +02:00
ReturnValue_t PdecHandler::performOperation(uint8_t operationCode) {
if (OP_MODE == Modes::POLLED) {
2022-10-27 08:34:45 +02:00
return polledOperation();
2022-10-26 14:35:47 +02:00
} else if (OP_MODE == Modes::IRQ) {
2022-10-27 08:34:45 +02:00
return irqOperation();
2022-10-26 14:35:47 +02:00
}
2023-02-14 10:36:53 +01:00
return returnvalue::FAILED;
2022-10-26 14:35:47 +02:00
}
ReturnValue_t PdecHandler::polledOperation() {
2022-10-27 08:34:45 +02:00
ReturnValue_t result = returnvalue::OK;
2022-10-26 14:35:47 +02:00
readCommandQueue();
switch (state) {
case State::INIT:
resetFarStatFlag();
if (result != returnvalue::OK) {
// Requires reconfiguration and reinitialization of PDEC
triggerEvent(INVALID_FAR);
state = State::WAIT_FOR_RECOVERY;
2023-02-20 18:12:33 +01:00
break;
2022-10-26 14:35:47 +02:00
}
state = State::RUNNING;
break;
case State::RUNNING:
if (newTcReceived()) {
handleNewTc();
}
checkLocks();
break;
case State::WAIT_FOR_RECOVERY:
break;
default:
2022-10-27 10:49:52 +02:00
sif::error << "PdecHandler::performOperation: Invalid state" << std::endl;
2022-10-26 14:35:47 +02:00
break;
}
return returnvalue::OK;
}
2023-02-08 20:01:56 +01:00
// See https://yurovsky.github.io/2014/10/10/linux-uio-gpio-interrupt.html for more information.
2022-10-26 14:35:47 +02:00
ReturnValue_t PdecHandler::irqOperation() {
2022-10-27 10:49:52 +02:00
ReturnValue_t result = returnvalue::OK;
int fd = open(uioNames.irq, O_RDWR);
if (fd < 0) {
sif::error << "PdecHandler::irqOperation: Opening UIO IRQ file" << uioNames.irq << " failed"
<< std::endl;
return returnvalue::FAILED;
}
// Used to unmask IRQ
uint32_t info = 1;
2023-02-20 18:12:33 +01:00
interruptWindowCd.resetTimer();
2023-02-08 20:01:56 +01:00
// Clear interrupts with dummy read before unmasking the interrupt. Use a volatile to prevent
// read being optimized away.
volatile uint32_t dummy = *(registerBaseAddress + PDEC_PIR_OFFSET);
2022-10-27 10:49:52 +02:00
2022-10-26 14:35:47 +02:00
while (true) {
2023-02-08 20:01:56 +01:00
// Default value to unmask IRQ on the write call.
info = 1;
2022-10-26 14:35:47 +02:00
readCommandQueue();
2022-10-27 10:49:52 +02:00
switch (state) {
case State::INIT:
2023-02-20 18:12:33 +01:00
result = resetFarStatFlag();
2022-10-27 10:49:52 +02:00
if (result != returnvalue::OK) {
// Requires reconfiguration and reinitialization of PDEC
triggerEvent(INVALID_FAR);
state = State::WAIT_FOR_RECOVERY;
return result;
}
state = State::RUNNING;
break;
case State::RUNNING: {
2023-02-20 18:53:56 +01:00
checkAndHandleIrqs(fd, info);
2022-10-27 10:49:52 +02:00
break;
}
case State::WAIT_FOR_RECOVERY:
2023-02-20 18:12:33 +01:00
TaskFactory::delayTask(400);
2022-10-27 10:49:52 +02:00
break;
default:
2023-02-20 18:12:33 +01:00
// Should never happen.
2022-10-27 10:49:52 +02:00
sif::error << "PdecHandler::performOperation: Invalid state" << std::endl;
2023-02-20 18:12:33 +01:00
TaskFactory::delayTask(400);
2022-10-27 10:49:52 +02:00
break;
}
2022-10-26 14:35:47 +02:00
}
2023-02-08 20:01:56 +01:00
// To avoid compiler warning
static_cast<void>(dummy);
2022-10-26 14:35:47 +02:00
return returnvalue::OK;
}
2023-02-20 18:53:56 +01:00
ReturnValue_t PdecHandler::checkAndHandleIrqs(int fd, uint32_t& info) {
ssize_t nb = write(fd, &info, sizeof(info));
if (nb != static_cast<ssize_t>(sizeof(info))) {
sif::error << "PdecHandler::irqOperation: Unmasking IRQ failed" << std::endl;
triggerEvent(WRITE_SYSCALL_ERROR_PDEC, errno);
close(fd);
state = State::INIT;
return returnvalue::FAILED;
}
struct pollfd fds = {.fd = fd, .events = POLLIN, .revents = 0};
int ret = poll(&fds, 1, IRQ_TIMEOUT_MS);
if (ret == 0) {
// No TCs for timeout period
checkLocks();
genericCheckCd.resetTimer();
resetIrqLimiters();
} else if (ret >= 1) {
// Interrupt handling.
nb = read(fd, &info, sizeof(info));
interruptCounter++;
if (nb == static_cast<ssize_t>(sizeof(info))) {
uint32_t pisr = *(registerBaseAddress + PDEC_PISR_OFFSET);
if ((pisr & TC_NEW_MASK) == TC_NEW_MASK) {
// handle TC
handleNewTc();
}
if ((pisr & TC_ABORT_MASK) == TC_ABORT_MASK) {
tcAbortCounter += 1;
}
if ((pisr & NEW_FAR_MASK) == NEW_FAR_MASK) {
// Read FAR here
CURRENT_FAR = readFar();
checkFrameAna(CURRENT_FAR);
}
// Clear interrupts with dummy read. Volatile is important here to prevent
// compiler opitmizations in release builds!
volatile uint32_t dummy = *(registerBaseAddress + PDEC_PIR_OFFSET);
static_cast<void>(dummy);
if (genericCheckCd.hasTimedOut()) {
checkLocks();
genericCheckCd.resetTimer();
if (interruptWindowCd.hasTimedOut()) {
if (interruptCounter >= MAX_ALLOWED_IRQS_PER_WINDOW) {
sif::error << "PdecHandler::irqOperation: Possible IRQ storm" << std::endl;
triggerEvent(TOO_MANY_IRQS, MAX_ALLOWED_IRQS_PER_WINDOW);
resetIrqLimiters();
TaskFactory::delayTask(400);
return returnvalue::FAILED;
}
resetIrqLimiters();
}
}
}
} else {
sif::error << "PdecHandler::irqOperation: Poll error with errno " << errno << ": "
<< strerror(errno) << std::endl;
triggerEvent(POLL_SYSCALL_ERROR_PDEC, errno);
close(fd);
state = State::INIT;
return returnvalue::FAILED;
}
return returnvalue::OK;
}
2022-10-26 14:35:47 +02:00
void PdecHandler::readCommandQueue(void) {
CommandMessage commandMessage;
ReturnValue_t result = returnvalue::FAILED;
result = commandQueue->receiveMessage(&commandMessage);
if (result == returnvalue::OK) {
result = actionHelper.handleActionMessage(&commandMessage);
if (result == returnvalue::OK) {
return;
}
CommandMessage reply;
reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, commandMessage.getCommand());
commandQueue->reply(&reply);
return;
}
}
2022-01-17 15:58:27 +01:00
MessageQueueId_t PdecHandler::getCommandQueue() const { return commandQueue->getId(); }
2021-11-22 10:38:32 +01:00
2022-11-02 18:58:29 +01:00
void PdecHandler::writePdecConfigDuringReset(PdecConfig& pdecConfig) {
2022-01-17 15:58:27 +01:00
*(memoryBaseAddress + FRAME_HEADER_OFFSET) = pdecConfig.getConfigWord(0);
*(memoryBaseAddress + FRAME_HEADER_OFFSET + 1) = pdecConfig.getConfigWord(1);
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
// Configure all MAP IDs as invalid
for (int idx = 0; idx <= MAX_MAP_ADDR; idx += 4) {
*(memoryBaseAddress + MAP_ADDR_LUT_OFFSET + idx / 4) =
2022-01-17 15:58:27 +01:00
NO_DESTINATION << 24 | NO_DESTINATION << 16 | NO_DESTINATION << 8 | NO_DESTINATION;
}
2021-11-03 18:19:36 +01:00
2022-01-17 15:58:27 +01:00
// 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 + MAP_ADDR_LUT_OFFSET + 1) =
(NO_DESTINATION << 24) | (NO_DESTINATION << 16) | (NO_DESTINATION << 8) | routeToPm;
2021-11-03 18:19:36 +01:00
2022-01-17 15:58:27 +01:00
// Write map id clock frequencies
for (int idx = 0; idx <= MAX_MAP_ADDR; idx += 4) {
*(memoryBaseAddress + MAP_CLK_FREQ_OFFSET + idx / 4) =
MAP_CLK_FREQ << 24 | MAP_CLK_FREQ << 16 | MAP_CLK_FREQ << 8 | MAP_CLK_FREQ;
}
2021-11-01 12:41:20 +01:00
}
ReturnValue_t PdecHandler::resetFarStatFlag() {
2022-10-27 10:49:52 +02:00
uint32_t pdecFar = readFar();
2022-11-03 10:40:59 +01:00
if ((pdecFar & FAR_STAT_MASK) != 0) {
sif::warning << "PdecHandler::resetFarStatFlag: FAR register stat bit is not 0."
<< " Read value for FAR: 0x" << std::hex << static_cast<unsigned int>(pdecFar)
2022-01-17 15:58:27 +01:00
<< std::endl;
2022-10-27 10:49:52 +02:00
CURRENT_FAR = pdecFar;
2022-08-24 17:27:47 +02:00
return returnvalue::FAILED;
2022-01-17 15:58:27 +01:00
}
2021-11-01 12:41:20 +01:00
#if OBSW_DEBUG_PDEC_HANDLER == 1
2022-01-17 15:58:27 +01:00
sif::debug << "PdecHandler::resetFarStatFlag: read FAR with value: 0x" << std::hex << pdecFar
<< std::endl;
2021-11-01 12:41:20 +01:00
#endif /* OBSW_DEBUG_PDEC_HANDLER == 1 */
2022-10-27 10:49:52 +02:00
CURRENT_FAR = pdecFar;
2022-08-24 17:27:47 +02:00
return returnvalue::OK;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
ReturnValue_t PdecHandler::releasePdec() {
2022-08-24 17:27:47 +02:00
ReturnValue_t result = returnvalue::OK;
2022-01-17 15:58:27 +01:00
result = gpioComIF->pullHigh(pdecReset);
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
sif::error << "PdecHandler::releasePdec: Failed to release PDEC reset signal" << std::endl;
}
return result;
2021-11-01 12:41:20 +01:00
}
bool PdecHandler::newTcReceived() {
2022-10-27 10:49:52 +02:00
uint32_t pdecFar = readFar();
2022-01-17 15:58:27 +01:00
if (pdecFar >> STAT_POSITION != NEW_FAR_RECEIVED) {
2022-10-27 10:49:52 +02:00
CURRENT_FAR = pdecFar;
2022-01-17 15:58:27 +01:00
return false;
}
if (!checkFrameAna(pdecFar)) {
2022-10-27 10:49:52 +02:00
CURRENT_FAR = pdecFar;
2022-01-17 15:58:27 +01:00
return false;
}
return true;
2021-11-01 12:41:20 +01:00
}
2021-11-22 18:01:16 +01:00
void PdecHandler::checkLocks() {
2022-01-17 15:58:27 +01:00
uint32_t clcw = getClcw();
if (not(clcw & NO_RF_MASK) && not carrierLock) {
2022-01-17 15:58:27 +01:00
triggerEvent(CARRIER_LOCK);
carrierLock = true;
} else if ((clcw & NO_RF_MASK) && carrierLock) {
carrierLock = false;
triggerEvent(LOST_CARRIER_LOCK_PDEC);
2022-01-17 15:58:27 +01:00
}
if (not(clcw & NO_BITLOCK_MASK) && not bitLock) {
2022-01-17 15:58:27 +01:00
triggerEvent(BIT_LOCK_PDEC);
bitLock = true;
} else if ((clcw & NO_BITLOCK_MASK) && bitLock) {
bitLock = false;
triggerEvent(LOST_BIT_LOCK_PDEC);
2022-01-17 15:58:27 +01:00
}
2021-11-22 18:01:16 +01:00
}
2021-11-01 12:41:20 +01:00
bool PdecHandler::checkFrameAna(uint32_t pdecFar) {
2022-01-17 15:58:27 +01:00
bool frameValid = false;
FrameAna_t frameAna = static_cast<FrameAna_t>((pdecFar & FRAME_ANA_MASK) >> FRAME_ANA_POSITION);
switch (frameAna) {
case (FrameAna_t::ABANDONED_CLTU): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, ABANDONED_CLTU_RETVAL);
2022-01-17 15:58:27 +01:00
sif::warning << "PdecHandler::checkFrameAna: Abondoned CLTU" << std::endl;
break;
}
case (FrameAna_t::FRAME_DIRTY): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, FRAME_DIRTY_RETVAL);
2022-01-17 15:58:27 +01:00
sif::warning << "PdecHandler::checkFrameAna: Frame dirty" << std::endl;
break;
}
case (FrameAna_t::FRAME_ILLEGAL): {
sif::warning << "PdecHandler::checkFrameAna: Frame illegal for one reason" << std::endl;
handleIReason(pdecFar, FRAME_ILLEGAL_ONE_REASON);
break;
}
case (FrameAna_t::FRAME_ILLEGAL_MULTI_REASON): {
sif::warning << "PdecHandler::checkFrameAna: Frame illegal for multiple reasons" << std::endl;
handleIReason(pdecFar, FRAME_ILLEGAL_MULTIPLE_REASONS);
break;
}
case (FrameAna_t::AD_DISCARDED_LOCKOUT): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, AD_DISCARDED_LOCKOUT_RETVAL);
2022-01-17 15:58:27 +01:00
sif::warning << "PdecHandler::checkFrameAna: AD frame discarded because of lockout"
<< std::endl;
break;
}
case (FrameAna_t::AD_DISCARDED_WAIT): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, AD_DISCARDED_LOCKOUT_RETVAL);
2022-01-17 15:58:27 +01:00
sif::warning << "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::warning << "PdecHandler::checkFrameAna: AD frame discarded because N(S) or V(R)"
<< std::endl;
break;
}
case (FrameAna_t::FRAME_ACCEPTED): {
2021-11-30 14:40:35 +01:00
#if OBSW_DEBUG_PDEC_HANDLER == 1
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::checkFrameAna: Accepted TC frame" << std::endl;
2021-11-30 14:40:35 +01:00
#endif
2022-01-17 15:58:27 +01:00
frameValid = true;
break;
2021-11-01 12:41:20 +01:00
}
default: {
2022-01-17 15:58:27 +01:00
sif::debug << "PdecHandler::checkFrameAna: Invalid frame analysis report" << std::endl;
break;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
}
return frameValid;
2021-11-01 12:41:20 +01:00
}
void PdecHandler::handleIReason(uint32_t pdecFar, ReturnValue_t parameter1) {
2022-01-17 15:58:27 +01:00
IReason_t ireason = static_cast<IReason_t>((pdecFar & IREASON_MASK) >> IREASON_POSITION);
switch (ireason) {
case (IReason_t::NO_REPORT): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, parameter1, NO_REPORT_RETVAL);
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::handleIReason: No illegal report" << std::endl;
break;
}
case (IReason_t::ERROR_VERSION_NUMBER): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, parameter1, ERROR_VERSION_NUMBER_RETVAL);
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::handleIReason: Error in version number and reserved A and B "
2021-11-01 12:41:20 +01:00
<< "fields" << std::endl;
2022-01-17 15:58:27 +01:00
break;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
case (IReason_t::ILLEGAL_COMBINATION): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, parameter1, ILLEGAL_COMBINATION_RETVAL);
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::handleIReason: Illegal combination (AC) of bypass and control "
2021-11-01 12:41:20 +01:00
<< "command flags" << std::endl;
2022-01-17 15:58:27 +01:00
break;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
case (IReason_t::INVALID_SC_ID): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_SC_ID_RETVAL);
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::handleIReason: Invalid spacecraft identifier " << std::endl;
break;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
case (IReason_t::INVALID_VC_ID_MSB): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_VC_ID_MSB_RETVAL);
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::handleIReason: VC identifier bit 0 to 4 did not match "
2021-11-01 12:41:20 +01:00
<< std::endl;
2022-01-17 15:58:27 +01:00
break;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
case (IReason_t::INVALID_VC_ID_LSB): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_VC_ID_LSB_RETVAL);
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::handleIReason: VC identifier bit 5 did not match " << std::endl;
break;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
case (IReason_t::NS_NOT_ZERO): {
2023-02-17 12:19:53 +01:00
triggerEvent(INVALID_TC_FRAME, parameter1, NS_NOT_ZERO_RETVAL);
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::handleIReason: N(S) of BC or BD frame not set to all zeros"
2021-11-01 12:41:20 +01:00
<< std::endl;
2022-01-17 15:58:27 +01:00
break;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
case (IReason_t::INCORRECT_BC_CC): {
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_BC_CC);
sif::info << "PdecHandler::handleIReason: Invalid BC control command format" << std::endl;
break;
2021-11-01 12:41:20 +01:00
}
default: {
2022-01-17 15:58:27 +01:00
sif::info << "PdecHandler::handleIReason: Invalid reason id" << std::endl;
break;
2021-11-01 12:41:20 +01:00
}
2022-01-17 15:58:27 +01:00
}
2021-11-01 12:41:20 +01:00
}
void PdecHandler::handleNewTc() {
2022-08-24 17:27:47 +02:00
ReturnValue_t result = returnvalue::OK;
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
uint32_t tcLength = 0;
result = readTc(tcLength);
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
return;
}
2021-11-03 18:19:36 +01:00
#if OBSW_DEBUG_PDEC_HANDLER == 1
2022-01-17 15:58:27 +01:00
unsigned int mapId = tcSegment[0] & MAP_ID_MASK;
sif::info << "PdecHandler::handleNewTc: Received TC segment with map ID " << mapId << std::endl;
printTC(tcLength);
2021-11-03 18:19:36 +01:00
#endif /* OBSW_DEBUG_PDEC_HANDLER */
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
store_address_t storeId;
result = tcStore->addData(&storeId, tcSegment + 1, tcLength - 1);
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
sif::warning << "PdecHandler::handleNewTc: Failed to add received space packet to store"
<< std::endl;
return;
}
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
TmTcMessage message(storeId);
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
result = MessageQueueSenderIF::sendMessage(tcDestination->getRequestQueue(), &message);
2022-08-24 17:27:47 +02:00
if (result != returnvalue::OK) {
2022-01-17 15:58:27 +01:00
sif::warning << "PdecHandler::handleNewTc: Failed to send message to TC destination"
<< std::endl;
tcStore->deleteData(storeId);
2021-11-01 12:41:20 +01:00
return;
2022-01-17 15:58:27 +01:00
}
return;
2021-11-01 12:41:20 +01:00
}
ReturnValue_t PdecHandler::readTc(uint32_t& tcLength) {
2022-01-17 15:58:27 +01:00
uint32_t tcOffset = (*(registerBaseAddress + PDEC_BPTR_OFFSET) - PHYSICAL_RAM_BASE_ADDRESS) / 4;
2021-11-01 12:41:20 +01:00
2021-11-03 18:19:36 +01:00
#if OBSW_DEBUG_PDEC_HANDLER == 1
2022-01-17 15:58:27 +01:00
sif::debug << "PdecHandler::readTc: TC offset: 0x" << std::hex << tcOffset << std::endl;
2021-11-03 18:19:36 +01:00
#endif /* OBSW_DEBUG_PDEC_HANDLER */
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
tcLength = *(registerBaseAddress + PDEC_SLEN_OFFSET);
2021-11-01 12:41:20 +01:00
2021-11-03 18:19:36 +01:00
#if OBSW_DEBUG_PDEC_HANDLER == 1
2022-01-17 15:58:27 +01:00
sif::debug << "PdecHandler::readTc: TC segment length: " << std::dec << tcLength << std::endl;
2021-11-03 18:19:36 +01:00
#endif /* OBSW_DEBUG_PDEC_HANDLER */
2021-11-01 12:41:20 +01:00
2022-01-17 15:58:27 +01:00
if (tcLength > MAX_TC_SEGMENT_SIZE) {
sif::warning << "PdecHandler::handleNewTc: Read invalid TC length from PDEC register"
<< std::endl;
2022-08-24 17:27:47 +02:00
return returnvalue::FAILED;
2022-01-17 15:58:27 +01:00
}
uint32_t idx = 0;
uint32_t tcData = 0;
for (idx = 0; idx <= tcLength; idx = idx + 4) {
tcData = *(ramBaseAddress + tcOffset + idx / 4);
if (idx == 0) {
tcSegment[idx] = static_cast<uint8_t>((tcData >> 16) & 0xFF);
tcSegment[idx + 1] = static_cast<uint8_t>((tcData >> 8) & 0xFF);
tcSegment[idx + 2] = static_cast<uint8_t>(tcData & 0xFF);
} else if (tcLength - idx + 1 == 3) {
tcSegment[idx - 1] = static_cast<uint8_t>((tcData >> 24) & 0xFF);
tcSegment[idx] = static_cast<uint8_t>((tcData >> 16) & 0xFF);
tcSegment[idx + 1] = static_cast<uint8_t>((tcData >> 8) & 0xFF);
} else if (tcLength - idx + 1 == 2) {
tcSegment[idx - 1] = static_cast<uint8_t>((tcData >> 24) & 0xFF);
tcSegment[idx] = static_cast<uint8_t>((tcData >> 16) & 0xFF);
} else if (tcLength - idx + 1 == 1) {
tcSegment[idx - 1] = static_cast<uint8_t>((tcData >> 24) & 0xFF);
} else {
tcSegment[idx - 1] = static_cast<uint8_t>((tcData >> 24) & 0xFF);
tcSegment[idx] = static_cast<uint8_t>((tcData >> 16) & 0xFF);
tcSegment[idx + 1] = static_cast<uint8_t>((tcData >> 8) & 0xFF);
tcSegment[idx + 2] = static_cast<uint8_t>(tcData & 0xFF);
}
}
// Backend buffer is handled back to PDEC3
*(registerBaseAddress + PDEC_BFREE_OFFSET) = 0;
2022-08-24 17:27:47 +02:00
return returnvalue::OK;
2021-11-01 12:41:20 +01:00
}
2021-11-03 18:19:36 +01:00
void PdecHandler::printTC(uint32_t tcLength) {
2022-01-17 15:58:27 +01:00
std::stringstream tcSegmentStream;
tcSegmentStream << "TC segment data: 0x";
for (uint32_t idx = 0; idx < tcLength; idx++) {
tcSegmentStream << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<unsigned int>(tcSegment[idx]);
}
sif::info << tcSegmentStream.str() << std::endl;
2021-11-03 18:19:36 +01:00
}
2021-11-01 12:41:20 +01:00
uint8_t PdecHandler::calcMapAddrEntry(uint8_t moduleId) {
2022-01-17 15:58:27 +01:00
uint8_t lutEntry = 0;
uint8_t parity = getOddParity(moduleId | (1 << VALID_POSITION));
lutEntry = (parity << PARITY_POSITION) | (1 << VALID_POSITION) | moduleId;
return lutEntry;
2021-11-01 12:41:20 +01:00
}
uint8_t PdecHandler::getOddParity(uint8_t number) {
2022-01-17 15:58:27 +01:00
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;
2021-11-01 12:41:20 +01:00
}
2021-11-03 19:49:41 +01:00
2022-01-17 15:58:27 +01:00
uint32_t PdecHandler::getClcw() { return *(registerBaseAddress + PDEC_CLCW_OFFSET); }
2021-11-03 19:49:41 +01:00
2022-01-17 15:58:27 +01:00
uint32_t PdecHandler::getPdecMon() { return *(registerBaseAddress + PDEC_MON_OFFSET); }
2021-12-02 11:51:22 +01:00
2021-11-22 10:38:32 +01:00
void PdecHandler::printClcw() {
2022-01-17 15:58:27 +01:00
uint32_t clcw = getClcw();
uint8_t type = static_cast<uint8_t>((clcw >> 31) & 0x1);
uint8_t versionNo = static_cast<uint8_t>((clcw >> 29) & 0x3);
uint8_t status = static_cast<uint8_t>((clcw >> 26) & 0x7);
uint8_t cop = static_cast<uint8_t>((clcw >> 24) & 0x3);
uint8_t vcId = static_cast<uint8_t>((clcw >> 18) & 0x3F);
uint8_t noRf = static_cast<uint8_t>((clcw >> 15) & 0x1);
uint8_t noBitLock = static_cast<uint8_t>((clcw >> 14) & 0x1);
uint8_t lockoutFlag = static_cast<uint8_t>((clcw >> 13) & 0x1);
uint8_t waitFlag = static_cast<uint8_t>((clcw >> 12) & 0x1);
uint8_t retransmitFlag = static_cast<uint8_t>((clcw >> 11) & 0x1);
uint8_t farmBcnt = static_cast<uint8_t>((clcw >> 9) & 0x3);
// Expected frame sequence number in te next AD frame
uint8_t repValue = static_cast<uint8_t>(clcw & 0xFF);
sif::info << std::setw(30) << std::left << "CLCW type: " << std::hex << "0x"
<< static_cast<unsigned int>(type) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW version no: " << std::hex << "0x"
<< static_cast<unsigned int>(versionNo) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW status: " << std::hex << "0x"
<< static_cast<unsigned int>(status) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW COP: " << std::hex << "0x"
<< static_cast<unsigned int>(cop) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW virtual channel ID: " << std::hex << "0x"
<< static_cast<unsigned int>(vcId) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW no RF: " << std::hex << "0x"
<< static_cast<unsigned int>(noRf) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW no bit lock: " << std::hex << "0x"
<< static_cast<unsigned int>(noBitLock) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW lockout flag: " << std::hex << "0x"
<< static_cast<unsigned int>(lockoutFlag) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW wait flag: " << std::hex << "0x"
<< static_cast<unsigned int>(waitFlag) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW retransmit flag: " << std::hex << "0x"
<< static_cast<unsigned int>(retransmitFlag) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW FARM B count: " << std::hex << "0x"
<< static_cast<unsigned int>(farmBcnt) << std::endl;
sif::info << std::setw(30) << std::left << "CLCW rep value: " << std::hex << "0x"
<< static_cast<unsigned int>(repValue) << std::endl;
2021-11-03 19:49:41 +01:00
}
2021-11-22 10:38:32 +01:00
2021-12-02 11:51:22 +01:00
void PdecHandler::printPdecMon() {
2022-01-17 15:58:27 +01:00
uint32_t pdecMon = getPdecMon();
uint32_t tc0ChannelStatus = (pdecMon & TC0_STATUS_MASK) >> TC0_STATUS_POS;
uint32_t tc1ChannelStatus = (pdecMon & TC1_STATUS_MASK) >> TC1_STATUS_POS;
uint32_t tc2ChannelStatus = (pdecMon & TC2_STATUS_MASK) >> TC2_STATUS_POS;
uint32_t tc3ChannelStatus = (pdecMon & TC3_STATUS_MASK) >> TC3_STATUS_POS;
uint32_t tc4ChannelStatus = (pdecMon & TC4_STATUS_MASK) >> TC4_STATUS_POS;
uint32_t tc5ChannelStatus = (pdecMon & TC5_STATUS_MASK) >> TC5_STATUS_POS;
uint32_t lock = (pdecMon & LOCK_MASK) >> LOCK_POS;
sif::info << std::setw(30) << std::left << "TC0 status: " << getMonStatusString(tc0ChannelStatus)
<< std::endl;
sif::info << std::setw(30) << std::left << "TC1 status: " << getMonStatusString(tc1ChannelStatus)
<< std::endl;
sif::info << std::setw(30) << std::left << "TC2 status: " << getMonStatusString(tc2ChannelStatus)
<< std::endl;
sif::info << std::setw(30) << std::left << "TC3 status: " << getMonStatusString(tc3ChannelStatus)
<< std::endl;
sif::info << std::setw(30) << std::left << "TC4 status: " << getMonStatusString(tc4ChannelStatus)
<< std::endl;
sif::info << std::setw(30) << std::left << "TC5 status: " << getMonStatusString(tc5ChannelStatus)
<< std::endl;
sif::info << std::setw(30) << std::left << "Start sequence lock: " << lock << std::endl;
2021-12-02 11:51:22 +01:00
}
2022-10-27 10:49:52 +02:00
uint32_t PdecHandler::readFar() { return *(registerBaseAddress + PDEC_FAR_OFFSET); }
2023-02-20 18:41:26 +01:00
void PdecHandler::resetIrqLimiters() {
interruptWindowCd.resetTimer();
interruptCounter = 0;
}
2021-12-02 11:51:22 +01:00
std::string PdecHandler::getMonStatusString(uint32_t status) {
2022-01-17 15:58:27 +01:00
switch (status) {
case TC_CHANNEL_INACTIVE:
return std::string("inactive");
case TC_CHANNEL_ACTIVE:
return std::string("active");
case TC_CHANNEL_TIMEDOUT:
return std::string("timed out");
default:
sif::warning << "PdecHandler::getMonStatusString: Invalid status" << std::endl;
return std::string();
break;
}
2021-12-02 11:51:22 +01:00
}
2022-01-17 15:58:27 +01:00
ReturnValue_t PdecHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
switch (actionId) {
2021-11-22 10:38:32 +01:00
case PRINT_CLCW:
2022-01-17 15:58:27 +01:00
printClcw();
return EXECUTION_FINISHED;
2021-12-02 11:51:22 +01:00
case PRINT_PDEC_MON:
2022-01-17 15:58:27 +01:00
printPdecMon();
return EXECUTION_FINISHED;
2021-11-22 10:38:32 +01:00
default:
2022-01-17 15:58:27 +01:00
return COMMAND_NOT_IMPLEMENTED;
}
2021-11-22 10:38:32 +01:00
}