restructured tmtc modules a bit, added comDefinitions file
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good

This commit is contained in:
2022-04-28 16:38:06 +02:00
parent 9c0a89bbdc
commit 699bc520f0
18 changed files with 56 additions and 15 deletions

342
linux/tmtc/CCSDSHandler.cpp Normal file
View File

@ -0,0 +1,342 @@
#include "CCSDSHandler.h"
#include <linux/obc/PdecHandler.h>
#include <linux/obc/PtmeConfig.h>
#include "fsfw/events/EventManagerIF.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
CCSDSHandler::CCSDSHandler(object_id_t objectId, object_id_t ptmeId, object_id_t tcDestination,
PtmeConfig* ptmeConfig, GpioIF* gpioIF, gpioId_t enTxClock,
gpioId_t enTxData, uint32_t transmitterTimeout)
: SystemObject(objectId),
ptmeId(ptmeId),
tcDestination(tcDestination),
parameterHelper(this),
actionHelper(this, nullptr),
ptmeConfig(ptmeConfig),
gpioIF(gpioIF),
enTxClock(enTxClock),
enTxData(enTxData),
TRANSMITTER_TIMEOUT(transmitterTimeout) {
commandQueue = QueueFactory::instance()->createMessageQueue(QUEUE_SIZE);
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
eventQueue =
QueueFactory::instance()->createMessageQueue(10, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
}
CCSDSHandler::~CCSDSHandler() {}
ReturnValue_t CCSDSHandler::performOperation(uint8_t operationCode) {
checkEvents();
readCommandQueue();
handleTelemetry();
handleTelecommands();
checkTxTimer();
return RETURN_OK;
}
void CCSDSHandler::handleTelemetry() {
VirtualChannelMapIter iter;
for (iter = virtualChannelMap.begin(); iter != virtualChannelMap.end(); iter++) {
iter->second->performOperation();
}
}
void CCSDSHandler::handleTelecommands() {}
ReturnValue_t CCSDSHandler::initialize() {
ReturnValue_t result = RETURN_OK;
PtmeIF* ptme = ObjectManager::instance()->get<PtmeIF>(ptmeId);
if (ptme == nullptr) {
sif::warning << "Invalid PTME object" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
AcceptsTelecommandsIF* tcDistributor =
ObjectManager::instance()->get<AcceptsTelecommandsIF>(tcDestination);
if (tcDistributor == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CCSDSHandler::initialize: Invalid TC Distributor object" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tcDistributorQueueId = tcDistributor->getRequestQueue();
result = parameterHelper.initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = actionHelper.initialize(commandQueue);
if (result != RETURN_OK) {
return result;
}
VirtualChannelMapIter iter;
for (iter = virtualChannelMap.begin(); iter != virtualChannelMap.end(); iter++) {
result = iter->second->initialize();
if (result != RETURN_OK) {
return result;
}
iter->second->setPtmeObject(ptme);
}
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
if (manager == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CCSDSHandler::initialize: Invalid event manager" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
result = manager->registerListener(eventQueue->getId());
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CCSDSHandler::initialize: Failed to register CCSDS handler as event "
"listener"
<< std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
;
}
result = manager->subscribeToEventRange(eventQueue->getId(),
event::getEventId(PdecHandler::CARRIER_LOCK),
event::getEventId(PdecHandler::BIT_LOCK_PDEC));
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CCSDSHandler::initialize: Failed to subscribe to events from PDEC "
"handler"
<< std::endl;
#endif
return result;
}
result = ptmeConfig->initialize();
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
#if OBSW_SYRLINKS_SIMULATED == 1
ptmeConfig->invertTxClock(true);
#endif /* OBSW_SYRLINKS_SIMULATED == 1*/
return result;
}
void CCSDSHandler::readCommandQueue(void) {
CommandMessage commandMessage;
ReturnValue_t result = RETURN_FAILED;
result = commandQueue->receiveMessage(&commandMessage);
if (result == RETURN_OK) {
result = parameterHelper.handleParameterMessage(&commandMessage);
if (result == RETURN_OK) {
return;
}
result = actionHelper.handleActionMessage(&commandMessage);
if (result == RETURN_OK) {
return;
}
CommandMessage reply;
reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, commandMessage.getCommand());
commandQueue->reply(&reply);
return;
}
}
MessageQueueId_t CCSDSHandler::getCommandQueue() const { return commandQueue->getId(); }
void CCSDSHandler::addVirtualChannel(VcId_t vcId, VirtualChannel* virtualChannel) {
if (vcId > common::NUMBER_OF_VIRTUAL_CHANNELS) {
sif::warning << "CCSDSHandler::addVirtualChannel: Invalid virtual channel ID" << std::endl;
return;
}
if (virtualChannel == nullptr) {
sif::warning << "CCSDSHandler::addVirtualChannel: Invalid virtual channel interface"
<< std::endl;
return;
}
auto status = virtualChannelMap.emplace(vcId, virtualChannel);
if (status.second == false) {
sif::warning << "CCSDSHandler::addVirtualChannel: Failed to add virtual channel to "
"virtual channel map"
<< std::endl;
return;
}
}
MessageQueueId_t CCSDSHandler::getReportReceptionQueue(uint8_t virtualChannel) {
if (virtualChannel < common::NUMBER_OF_VIRTUAL_CHANNELS) {
VirtualChannelMapIter iter = virtualChannelMap.find(virtualChannel);
if (iter != virtualChannelMap.end()) {
return iter->second->getReportReceptionQueue();
} else {
sif::warning << "CCSDSHandler::getReportReceptionQueue: Virtual channel with ID "
<< static_cast<unsigned int>(virtualChannel) << " not in virtual channel map"
<< std::endl;
return MessageQueueIF::NO_QUEUE;
}
} else {
sif::debug << "CCSDSHandler::getReportReceptionQueue: Invalid virtual channel requested";
}
return MessageQueueIF::NO_QUEUE;
}
ReturnValue_t CCSDSHandler::getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues, uint16_t startAtIndex) {
return RETURN_OK;
}
uint16_t CCSDSHandler::getIdentifier() { return 0; }
MessageQueueId_t CCSDSHandler::getRequestQueue() {
// Forward packets directly to TC distributor
return tcDistributorQueueId;
}
ReturnValue_t CCSDSHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
ReturnValue_t result = RETURN_OK;
switch (actionId) {
case SET_LOW_RATE: {
result = ptmeConfig->setRate(RATE_100KBPS);
break;
}
case SET_HIGH_RATE: {
result = ptmeConfig->setRate(RATE_500KBPS);
break;
}
case ARBITRARY_RATE: {
uint32_t bitrate = 0;
SerializeAdapter::deSerialize(&bitrate, &data, &size, SerializeIF::Endianness::BIG);
result = ptmeConfig->setRate(bitrate);
break;
}
case EN_TRANSMITTER: {
enableTransmit();
return EXECUTION_FINISHED;
}
case DISABLE_TRANSMITTER: {
disableTransmit();
return EXECUTION_FINISHED;
}
case ENABLE_TX_CLK_MANIPULATOR: {
result = ptmeConfig->configTxManipulator(true);
break;
}
case DISABLE_TX_CLK_MANIPULATOR: {
result = ptmeConfig->configTxManipulator(false);
break;
}
case UPDATE_ON_RISING_EDGE: {
result = ptmeConfig->invertTxClock(false);
break;
}
case UPDATE_ON_FALLING_EDGE: {
result = ptmeConfig->invertTxClock(true);
break;
}
default:
return COMMAND_NOT_IMPLEMENTED;
}
if (result != RETURN_OK) {
return result;
}
return EXECUTION_FINISHED;
}
void CCSDSHandler::checkEvents() {
EventMessage event;
for (ReturnValue_t result = eventQueue->receiveMessage(&event); result == RETURN_OK;
result = eventQueue->receiveMessage(&event)) {
switch (event.getMessageId()) {
case EventMessage::EVENT_MESSAGE:
handleEvent(&event);
break;
default:
sif::debug << "CCSDSHandler::checkEvents: Did not subscribe to this event message"
<< std::endl;
break;
}
}
}
void CCSDSHandler::handleEvent(EventMessage* eventMessage) {
Event event = eventMessage->getEvent();
switch (event) {
case PdecHandler::BIT_LOCK_PDEC: {
handleBitLockEvent();
break;
}
case PdecHandler::CARRIER_LOCK: {
handleCarrierLockEvent();
break;
}
default:
sif::debug << "CCSDSHandler::handleEvent: Did not subscribe to this event" << std::endl;
break;
}
}
void CCSDSHandler::handleBitLockEvent() {
if (transmitterCountdown.isBusy()) {
// Transmitter already enabled
return;
}
enableTransmit();
}
void CCSDSHandler::handleCarrierLockEvent() {
if (!enableTxWhenCarrierLock) {
return;
}
enableTransmit();
}
void CCSDSHandler::forwardLinkstate() {
VirtualChannelMapIter iter;
for (iter = virtualChannelMap.begin(); iter != virtualChannelMap.end(); iter++) {
iter->second->setLinkState(linkState);
}
}
void CCSDSHandler::enableTransmit() {
if (transmitterCountdown.isBusy()) {
// Transmitter already enabled
return;
}
transmitterCountdown.setTimeout(TRANSMITTER_TIMEOUT);
#ifndef TE0720_1CFA
gpioIF->pullHigh(enTxClock);
gpioIF->pullHigh(enTxData);
#endif /* BOARD_TE0720 == 0 */
linkState = UP;
// Set link state of all virtual channels to link up
forwardLinkstate();
}
void CCSDSHandler::checkTxTimer() {
if (linkState == DOWN) {
return;
}
if (transmitterCountdown.hasTimedOut()) {
disableTransmit();
}
}
void CCSDSHandler::disableTransmit() {
#ifdef TE0720_1CFA
gpioIF->pullLow(enTxClock);
gpioIF->pullLow(enTxData);
#endif /* BOARD_TE0720 == 0 */
linkState = DOWN;
forwardLinkstate();
transmitterCountdown.setTimeout(0);
}

180
linux/tmtc/CCSDSHandler.h Normal file
View File

@ -0,0 +1,180 @@
#ifndef CCSDSHANDLER_H_
#define CCSDSHANDLER_H_
#include <unordered_map>
#include "OBSWConfig.h"
#include "fsfw/action/ActionHelper.h"
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/events/EventMessage.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/parameters/ParameterHelper.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/timemanager/Countdown.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
#include "fsfw_hal/common/gpio/GpioIF.h"
#include "fsfw_hal/common/gpio/gpioDefinitions.h"
#include "linux/obc/PtmeConfig.h"
#include "mission/tmtc/VirtualChannel.h"
/**
* @brief This class handles the data exchange with the CCSDS IP cores implemented in the
* programmable logic of the Q7S.
*
* @details After reboot default CADU bitrate is always set to 100 kbps (results in downlink rate
* of 200 kbps due to convolutional code added by syrlinks transceiver)
*
* @author J. Meier
*/
class CCSDSHandler : public SystemObject,
public ExecutableObjectIF,
public AcceptsTelemetryIF,
public AcceptsTelecommandsIF,
public HasReturnvaluesIF,
public ReceivesParameterMessagesIF,
public HasActionsIF {
public:
using VcId_t = uint8_t;
/**
* @brief Constructor
*
* @param objectId Object ID of the CCSDS handler
* @param ptmeId Object ID of the PTME object providing access to the PTME IP Core.
* @param tcDestination Object ID of object handling received TC space packets
* @param txRateSetter Object providing the functionality to switch the input bitrate of
* the S-Band transceiver.
* @param gpioIF Required to enable TX data and TX clock RS485 transceiver chips.
* @param enTxClock GPIO ID of RS485 tx clock enable
* @param enTxData GPIO ID of RS485 tx data enable
*/
CCSDSHandler(object_id_t objectId, object_id_t ptmeId, object_id_t tcDestination,
PtmeConfig* ptmeConfig, GpioIF* gpioIF, gpioId_t enTxClock, gpioId_t enTxData,
uint32_t transmitterTimeout = 900000);
~CCSDSHandler();
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
ReturnValue_t initialize();
MessageQueueId_t getCommandQueue() const;
/**
* @brief Function to add a virtual channel
*
* @param virtualChannelId ID of the virtual channel to add
* @param virtualChannel Pointer to virtual channel object
*/
void addVirtualChannel(VcId_t virtualChannelId, VirtualChannel* virtualChannel);
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0);
ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues,
uint16_t startAtIndex);
uint16_t getIdentifier() override;
MessageQueueId_t getRequestQueue() override;
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size);
private:
static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_HANDLER;
static const uint32_t QUEUE_SIZE = common::CCSDS_HANDLER_QUEUE_SIZE;
static const ActionId_t SET_LOW_RATE = 0;
static const ActionId_t SET_HIGH_RATE = 1;
static const ActionId_t EN_TRANSMITTER = 2;
static const ActionId_t DISABLE_TRANSMITTER = 3;
static const ActionId_t ARBITRARY_RATE = 4;
static const ActionId_t ENABLE_TX_CLK_MANIPULATOR = 5;
static const ActionId_t DISABLE_TX_CLK_MANIPULATOR = 6;
// Will update data with respect to tx clock signal of cadu bitstream on rising edge
static const ActionId_t UPDATE_ON_RISING_EDGE = 7;
// Will update data with respect to tx clock signal of cadu bitstream on falling edge
static const ActionId_t UPDATE_ON_FALLING_EDGE = 8;
// Syrlinks supports two bitrates (200 kbps and 1000 kbps)
// Due to convolutional code added by the syrlinks the input frequency must be half the
// target frequency
static const uint32_t RATE_100KBPS = 100000;
static const uint32_t RATE_500KBPS = 500000;
//! [EXPORT] : [COMMENT] Received action message with unknown action id
static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xA0);
static const bool UP = true;
static const bool DOWN = false;
using VirtualChannelMap = std::unordered_map<VcId_t, VirtualChannel*>;
using VirtualChannelMapIter = VirtualChannelMap::iterator;
VirtualChannelMap virtualChannelMap;
// Object ID of PTME object
object_id_t ptmeId;
object_id_t tcDestination;
MessageQueueIF* commandQueue = nullptr;
MessageQueueIF* eventQueue = nullptr;
ParameterHelper parameterHelper;
ActionHelper actionHelper;
MessageQueueId_t tcDistributorQueueId = MessageQueueIF::NO_QUEUE;
PtmeConfig* ptmeConfig = nullptr;
GpioIF* gpioIF = nullptr;
gpioId_t enTxClock = gpio::NO_GPIO;
gpioId_t enTxData = gpio::NO_GPIO;
// syrlinks must not be transmitting more than 15 minutes (according to datasheet)
// Value can be configured via CTOR argument to allow test setups
const uint32_t TRANSMITTER_TIMEOUT = 900000; // 900000 ms = 15 min
// Countdown to disable transmitter after 15 minutes
Countdown transmitterCountdown;
// When true transmitting is started as soon as carrier lock has been detected
bool enableTxWhenCarrierLock = false;
bool linkState = DOWN;
void readCommandQueue(void);
void handleTelemetry();
void handleTelecommands();
void checkEvents();
void handleEvent(EventMessage* eventMessage);
void handleBitLockEvent();
void handleCarrierLockEvent();
/**
* @brief Forward link state to virtual channels.
*/
void forwardLinkstate();
/**
* @brief Starts transmit timer and enables transmitter.
*/
void enableTransmit();
/**
* @brief Checks Tx timer for timeout and disables RS485 tx clock and tx data in case
* timer has expired.
*/
void checkTxTimer();
/**
* @brief Disables the transmitter by pulling the enable tx clock and tx data pin of the
* RS485 transceiver chips to high.
*/
void disableTransmit();
};
#endif /* CCSDSHANDLER_H_ */

View File

@ -0,0 +1,5 @@
target_sources(${OBSW_NAME} PUBLIC
CCSDSHandler.cpp
)