2021-11-01 12:41:20 +01:00
|
|
|
#include <cstring>
|
2021-11-03 18:19:36 +01:00
|
|
|
#include <sstream>
|
2021-11-01 12:41:20 +01:00
|
|
|
|
|
|
|
#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"
|
2021-11-22 10:38:32 +01:00
|
|
|
#include "fsfw/ipc/QueueFactory.h"
|
|
|
|
|
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,
|
2021-11-03 18:19:36 +01:00
|
|
|
LinuxLibgpioIF* gpioComIF, gpioId_t pdecReset, std::string uioConfigMemory,
|
|
|
|
std::string uioRamMemory, std::string uioRegisters) :
|
2021-11-01 12:41:20 +01:00
|
|
|
SystemObject(objectId), tcDestinationId(tcDestinationId), gpioComIF(gpioComIF), pdecReset(
|
2021-11-03 18:19:36 +01:00
|
|
|
pdecReset), uioConfigMemory(uioConfigMemory), uioRamMemory(uioRamMemory), uioRegisters(
|
2021-11-22 10:38:32 +01:00
|
|
|
uioRegisters), actionHelper(this, nullptr) {
|
|
|
|
commandQueue = QueueFactory::instance()->createMessageQueue(QUEUE_SIZE);
|
2021-11-01 12:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-11-03 18:19:36 +01:00
|
|
|
result = getConfigMemoryBaseAddress();
|
|
|
|
if (result != RETURN_OK) {
|
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = getRamBaseAddress();
|
2021-11-01 12:41:20 +01:00
|
|
|
if (result != RETURN_OK) {
|
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
writePdecConfig();
|
|
|
|
|
|
|
|
result = releasePdec();
|
|
|
|
if (result != RETURN_OK) {
|
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
|
|
}
|
|
|
|
|
2021-11-22 10:38:32 +01:00
|
|
|
result = actionHelper.initialize(commandQueue);
|
|
|
|
if (result != RETURN_OK) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-11-01 12:41:20 +01:00
|
|
|
return RETURN_OK;
|
|
|
|
}
|
|
|
|
|
2021-11-22 10:38:32 +01:00
|
|
|
MessageQueueId_t PdecHandler::getCommandQueue() const {
|
|
|
|
return commandQueue->getId();
|
|
|
|
}
|
|
|
|
|
2021-11-01 12:41:20 +01:00
|
|
|
ReturnValue_t PdecHandler::getRegisterAddress() {
|
2021-11-02 11:11:38 +01:00
|
|
|
int fd = open(uioRegisters.c_str(), O_RDWR);
|
2021-11-01 12:41:20 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-11-03 18:19:36 +01:00
|
|
|
ReturnValue_t PdecHandler::getConfigMemoryBaseAddress() {
|
|
|
|
int fd = open(uioConfigMemory.c_str(), O_RDWR);
|
2021-11-01 12:41:20 +01:00
|
|
|
if (fd < 1) {
|
2021-11-03 18:19:36 +01:00
|
|
|
sif::warning << "PdecHandler::getConfigMemoryBaseAddress: Invalid UIO device file" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
return RETURN_FAILED;
|
|
|
|
}
|
|
|
|
|
2021-11-03 18:19:36 +01:00
|
|
|
memoryBaseAddress = static_cast<uint32_t*>(mmap(NULL, CONFIG_MEMORY_MAP_SIZE, PROT_WRITE | PROT_READ,
|
2021-11-01 12:41:20 +01:00
|
|
|
MAP_SHARED, fd, 0));
|
|
|
|
|
|
|
|
if (memoryBaseAddress == MAP_FAILED) {
|
2021-11-03 18:19:36 +01:00
|
|
|
sif::error << "PdecHandler::getConfigMemoryBaseAddress: Failed to map uio address" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
return RETURN_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RETURN_OK;
|
|
|
|
}
|
|
|
|
|
2021-11-03 18:19:36 +01:00
|
|
|
ReturnValue_t PdecHandler::getRamBaseAddress() {
|
|
|
|
int fd = open(uioRamMemory.c_str(), O_RDWR);
|
|
|
|
|
|
|
|
ramBaseAddress = static_cast<uint32_t*>(mmap(NULL, RAM_MAP_SIZE, PROT_WRITE | PROT_READ,
|
|
|
|
MAP_SHARED, fd, 0));
|
|
|
|
|
|
|
|
if (ramBaseAddress == MAP_FAILED) {
|
|
|
|
sif::error << "PdecHandler::getRamBaseAddress: Failed to map RAM base address" << std::endl;
|
|
|
|
return RETURN_FAILED;
|
|
|
|
}
|
|
|
|
return RETURN_OK;
|
|
|
|
}
|
|
|
|
|
2021-11-01 12:41:20 +01:00
|
|
|
void PdecHandler::writePdecConfig() {
|
2021-11-02 11:11:38 +01:00
|
|
|
|
|
|
|
PdecConfig pdecConfig;
|
|
|
|
|
2021-11-03 18:19:36 +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
|
|
|
|
|
|
|
// Configure all MAP IDs as invalid
|
|
|
|
for (int idx = 0; idx <= MAX_MAP_ADDR; idx += 4) {
|
2021-11-03 18:19:36 +01:00
|
|
|
*(memoryBaseAddress + MAP_ADDR_LUT_OFFSET + idx + 1 / 4) = NO_DESTINATION << 24
|
2021-11-01 12:41:20 +01:00
|
|
|
| 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);
|
2021-11-03 18:19:36 +01:00
|
|
|
*(memoryBaseAddress + MAP_ADDR_LUT_OFFSET + 1) = (NO_DESTINATION << 24) | (NO_DESTINATION << 16) | (NO_DESTINATION << 8)
|
2021-11-01 12:41:20 +01:00
|
|
|
| routeToPm;
|
2021-11-03 18:19:36 +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() {
|
|
|
|
uint32_t pdecFar = *(registerBaseAddress + PDEC_FAR_OFFSET);
|
|
|
|
if (pdecFar != FAR_RESET) {
|
|
|
|
sif::warning << "PdecHandler::resetFarStatFlag: FAR register did not match expected value."
|
2021-11-01 18:11:29 +01:00
|
|
|
<< " Read value: 0x" << std::hex << static_cast<unsigned int>(pdecFar) << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
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;
|
|
|
|
|
2021-11-22 10:38:32 +01:00
|
|
|
readCommandQueue();
|
|
|
|
|
2021-11-01 12:41:20 +01:00
|
|
|
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();
|
|
|
|
}
|
2021-11-22 18:01:16 +01:00
|
|
|
checkLocks();
|
2021-11-01 12:41:20 +01:00
|
|
|
break;
|
|
|
|
case State::WAIT_FOR_RECOVERY:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sif::debug << "PdecHandler::performOperation: Invalid state" << std::endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RETURN_OK;
|
|
|
|
}
|
|
|
|
|
2021-11-22 10:38:32 +01:00
|
|
|
void PdecHandler::readCommandQueue(void) {
|
|
|
|
CommandMessage commandMessage;
|
|
|
|
ReturnValue_t result = RETURN_FAILED;
|
|
|
|
|
|
|
|
result = commandQueue->receiveMessage(&commandMessage);
|
|
|
|
if (result == RETURN_OK) {
|
|
|
|
result = actionHelper.handleActionMessage(&commandMessage);
|
|
|
|
if (result == RETURN_OK) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CommandMessage reply;
|
|
|
|
reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND,
|
|
|
|
commandMessage.getCommand());
|
|
|
|
commandQueue->reply(&reply);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-01 12:41:20 +01:00
|
|
|
bool PdecHandler::newTcReceived() {
|
|
|
|
uint32_t pdecFar = *(registerBaseAddress + PDEC_FAR_OFFSET);
|
2021-11-01 18:11:29 +01:00
|
|
|
|
2021-11-01 12:41:20 +01:00
|
|
|
if (pdecFar >> STAT_POSITION != NEW_FAR_RECEIVED) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!checkFrameAna(pdecFar)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-22 18:01:16 +01:00
|
|
|
void PdecHandler::checkLocks() {
|
|
|
|
uint32_t clcw = getClcw();
|
|
|
|
if (!(clcw & NO_RF_MASK) && (lastClcw & NO_RF_MASK)) {
|
|
|
|
// Rf available changed from 0 to 1
|
|
|
|
triggerEvent(CARRIER_LOCK);
|
|
|
|
}
|
|
|
|
if (!(clcw & NO_BITLOCK_MASK) && (lastClcw & NO_BITLOCK_MASK)) {
|
|
|
|
// Bit lock changed from 0 to 1
|
2021-11-25 14:09:06 +01:00
|
|
|
triggerEvent(BIT_LOCK_PDEC);
|
2021-11-22 18:01:16 +01:00
|
|
|
}
|
|
|
|
lastClcw = clcw;
|
|
|
|
}
|
|
|
|
|
2021-11-01 12:41:20 +01:00
|
|
|
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);
|
2021-11-30 14:41:42 +01:00
|
|
|
sif::warning << "PdecHandler::checkFrameAna: Abondoned CLTU" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(FrameAna_t::FRAME_DIRTY): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, FRAME_DIRTY);
|
2021-12-06 19:36:21 +01:00
|
|
|
sif::warning << "PdecHandler::checkFrameAna: Frame dirty" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(FrameAna_t::FRAME_ILLEGAL): {
|
2021-11-30 14:41:42 +01:00
|
|
|
sif::warning << "PdecHandler::checkFrameAna: Frame illegal for one reason" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
handleIReason(pdecFar, FRAME_ILLEGAL_ONE_REASON);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(FrameAna_t::FRAME_ILLEGAL_MULTI_REASON): {
|
2021-11-30 14:41:42 +01:00
|
|
|
sif::warning << "PdecHandler::checkFrameAna: Frame illegal for multiple reasons"
|
2021-11-01 12:41:20 +01:00
|
|
|
<< std::endl;
|
|
|
|
handleIReason(pdecFar, FRAME_ILLEGAL_MULTIPLE_REASONS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(FrameAna_t::AD_DISCARDED_LOCKOUT): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, AD_DISCARDED_LOCKOUT);
|
2021-11-30 14:41:42 +01:00
|
|
|
sif::warning << "PdecHandler::checkFrameAna: AD frame discarded because of lockout"
|
2021-11-01 12:41:20 +01:00
|
|
|
<< std::endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(FrameAna_t::AD_DISCARDED_WAIT): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, AD_DISCARDED_LOCKOUT);
|
2021-11-30 14:41:42 +01:00
|
|
|
sif::warning << "PdecHandler::checkFrameAna: AD frame discarded because of wait"
|
2021-11-01 12:41:20 +01:00
|
|
|
<< std::endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(FrameAna_t::AD_DISCARDED_NS_VR): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, AD_DISCARDED_NS_VS);
|
2021-11-30 14:41:42 +01:00
|
|
|
sif::warning << "PdecHandler::checkFrameAna: AD frame discarded because N(S) or V(R)"
|
2021-11-01 12:41:20 +01:00
|
|
|
<< std::endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(FrameAna_t::FRAME_ACCEPTED): {
|
2021-11-30 14:40:35 +01:00
|
|
|
#if OBSW_DEBUG_PDEC_HANDLER == 1
|
|
|
|
sif::info << "PdecHandler::checkFrameAna: Accepted TC frame" << std::endl;
|
|
|
|
#endif
|
2021-11-01 12:41:20 +01:00
|
|
|
frameValid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
2021-11-06 20:28:33 +01:00
|
|
|
sif::debug << "PdecHandler::checkFrameAna: Invalid frame analysis report" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
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);
|
2021-12-06 19:36:21 +01:00
|
|
|
sif::info << "PdecHandler::handleIReason: No illegal report" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(IReason_t::ERROR_VERSION_NUMBER): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, parameter1, ERROR_VERSION_NUMBER);
|
2021-12-06 19:36:21 +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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(IReason_t::ILLEGAL_COMBINATION): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, parameter1, ILLEGAL_COMBINATION);
|
2021-12-06 19:36:21 +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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(IReason_t::INVALID_SC_ID): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_SC_ID);
|
2021-12-06 19:36:21 +01:00
|
|
|
sif::info << "PdecHandler::handleIReason: Invalid spacecraft identifier " << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(IReason_t::INVALID_VC_ID_MSB): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_VC_ID_MSB);
|
2021-12-06 19:36:21 +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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(IReason_t::INVALID_VC_ID_LSB): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_VC_ID_LSB);
|
2021-12-06 19:36:21 +01:00
|
|
|
sif::info << "PdecHandler::handleIReason: VC identifier bit 5 did not match " << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(IReason_t::NS_NOT_ZERO): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, parameter1, NS_NOT_ZERO);
|
2021-12-06 19:36:21 +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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(IReason_t::INCORRECT_BC_CC): {
|
|
|
|
triggerEvent(INVALID_TC_FRAME, parameter1, INVALID_BC_CC);
|
2021-12-06 19:36:21 +01:00
|
|
|
sif::info << "PdecHandler::handleIReason: Invalid BC control command format" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
2021-12-06 19:36:21 +01:00
|
|
|
sif::info << "PdecHandler::handleIReason: Invalid reason id" << std::endl;
|
2021-11-01 12:41:20 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PdecHandler::handleNewTc() {
|
|
|
|
ReturnValue_t result = RETURN_OK;
|
|
|
|
|
|
|
|
uint32_t tcLength = 0;
|
|
|
|
result = readTc(tcLength);
|
|
|
|
if (result != RETURN_OK) {
|
|
|
|
return;
|
|
|
|
}
|
2021-11-03 18:19:36 +01:00
|
|
|
#if OBSW_DEBUG_PDEC_HANDLER == 1
|
2021-11-01 12:41:20 +01:00
|
|
|
unsigned int mapId = tcSegment[0] & MAP_ID_MASK;
|
2021-12-06 19:36:21 +01:00
|
|
|
sif::info << "PdecHandler::handleNewTc: Received TC segment with map ID " << mapId
|
2021-11-01 12:41:20 +01:00
|
|
|
<< std::endl;
|
2021-11-03 18:19:36 +01:00
|
|
|
printTC(tcLength);
|
|
|
|
#endif /* OBSW_DEBUG_PDEC_HANDLER */
|
2021-11-01 12:41:20 +01:00
|
|
|
|
|
|
|
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) {
|
2021-11-03 18:19:36 +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
|
|
|
|
sif::debug << "PdecHandler::readTc: TC offset: 0x" << std::hex << tcOffset << std::endl;
|
|
|
|
#endif /* OBSW_DEBUG_PDEC_HANDLER */
|
2021-11-01 12:41:20 +01:00
|
|
|
|
|
|
|
tcLength = *(registerBaseAddress + PDEC_SLEN_OFFSET);
|
|
|
|
|
2021-11-03 18:19:36 +01:00
|
|
|
#if OBSW_DEBUG_PDEC_HANDLER == 1
|
|
|
|
sif::debug << "PdecHandler::readTc: TC segment length: " << std::dec << tcLength << std::endl;
|
|
|
|
#endif /* OBSW_DEBUG_PDEC_HANDLER */
|
2021-11-01 12:41:20 +01:00
|
|
|
|
|
|
|
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;
|
2021-11-03 18:19:36 +01:00
|
|
|
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) {
|
2021-11-06 20:28:33 +01:00
|
|
|
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);
|
2021-11-03 18:19:36 +01:00
|
|
|
}
|
|
|
|
else if (tcLength - idx + 1 == 2) {
|
2021-11-06 20:28:33 +01:00
|
|
|
tcSegment[idx - 1] = static_cast<uint8_t>((tcData >> 24) & 0xFF);
|
|
|
|
tcSegment[idx] = static_cast<uint8_t>((tcData >> 16) & 0xFF);
|
2021-11-03 18:19:36 +01:00
|
|
|
}
|
|
|
|
else if (tcLength - idx + 1 == 1) {
|
2021-11-06 20:28:33 +01:00
|
|
|
tcSegment[idx - 1] = static_cast<uint8_t>((tcData >> 24) & 0xFF);
|
2021-11-03 18:19:36 +01:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
2021-11-01 12:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Backend buffer is handled back to PDEC3
|
|
|
|
*(registerBaseAddress + PDEC_BFREE_OFFSET) = 0;
|
|
|
|
|
|
|
|
return RETURN_OK;
|
|
|
|
}
|
|
|
|
|
2021-11-03 18:19:36 +01:00
|
|
|
void PdecHandler::printTC(uint32_t tcLength) {
|
|
|
|
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]);
|
|
|
|
}
|
2021-12-06 19:36:21 +01:00
|
|
|
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) {
|
|
|
|
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;
|
|
|
|
}
|
2021-11-03 19:49:41 +01:00
|
|
|
|
2021-11-22 10:38:32 +01:00
|
|
|
uint32_t PdecHandler::getClcw() {
|
|
|
|
return *(registerBaseAddress + PDEC_CLCW_OFFSET);
|
2021-11-03 19:49:41 +01:00
|
|
|
}
|
|
|
|
|
2021-12-02 11:51:22 +01:00
|
|
|
uint32_t PdecHandler::getPdecMon() {
|
|
|
|
return *(registerBaseAddress + PDEC_MON_OFFSET);
|
|
|
|
}
|
|
|
|
|
2021-11-22 10:38:32 +01:00
|
|
|
void PdecHandler::printClcw() {
|
|
|
|
uint32_t clcw = getClcw();
|
2021-11-03 19:49:41 +01:00
|
|
|
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-22 10:38:32 +01:00
|
|
|
|
2021-12-02 11:51:22 +01:00
|
|
|
void PdecHandler::printPdecMon() {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string PdecHandler::getMonStatusString(uint32_t status) {
|
|
|
|
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-11-22 10:38:32 +01:00
|
|
|
|
|
|
|
ReturnValue_t PdecHandler::executeAction(ActionId_t actionId,
|
|
|
|
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) {
|
|
|
|
switch(actionId) {
|
|
|
|
case PRINT_CLCW:
|
|
|
|
printClcw();
|
|
|
|
return EXECUTION_FINISHED;
|
2021-12-02 11:51:22 +01:00
|
|
|
case PRINT_PDEC_MON:
|
|
|
|
printPdecMon();
|
|
|
|
return EXECUTION_FINISHED;
|
2021-11-22 10:38:32 +01:00
|
|
|
default:
|
|
|
|
return COMMAND_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
}
|