From 345ccf5392385a7f64f14cc89669cbe29bfd5a28 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Mon, 22 Nov 2021 18:01:16 +0100 Subject: [PATCH] transmit enable and timeout --- bsp_q7s/core/InitMission.cpp | 2 +- bsp_q7s/core/ObjectFactory.cpp | 3 +- generators/bsp_q7s_objects.csv | 1 + linux/fsfwconfig/OBSWConfig.h.in | 2 +- linux/obc/PdecHandler.cpp | 14 ++++ linux/obc/PdecHandler.h | 34 ++++++-- mission/tmtc/CCSDSHandler.cpp | 137 ++++++++++++++++++++++++++++++- mission/tmtc/CCSDSHandler.h | 58 ++++++++++++- 8 files changed, 234 insertions(+), 17 deletions(-) diff --git a/bsp_q7s/core/InitMission.cpp b/bsp_q7s/core/InitMission.cpp index eab396c6..bd70c1c0 100644 --- a/bsp_q7s/core/InitMission.cpp +++ b/bsp_q7s/core/InitMission.cpp @@ -110,7 +110,7 @@ void initmission::initTasks() { // If a command has not been read before the next one arrives, the old command will be // overwritten by the PDEC. PeriodicTaskIF* pdecHandlerTask = factory->createPeriodicTask( - "PDEC_HANDLER", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.6, missedDeadlineFunc); + "PDEC_HANDLER", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1, missedDeadlineFunc); result = pdecHandlerTask->addComponent(objects::PDEC_HANDLER); if(result != HasReturnvaluesIF::RETURN_OK) { initmission::printAddObjectError("PDEC Handler", objects::PDEC_HANDLER); diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index c7738679..ec0c085f 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -951,7 +951,8 @@ void ObjectFactory::createCcsdsComponents(LinuxLibgpioIF *gpioComIF) { TxRateSetterIF* txRateSetterIF = new PtmeRateSetter(gpioIds::BIT_RATE_SEL, gpioComIF); CCSDSHandler* ccsdsHandler = new CCSDSHandler(objects::CCSDS_HANDLER, objects::PTME, - objects::CCSDS_PACKET_DISTRIBUTOR, txRateSetterIF); + objects::CCSDS_PACKET_DISTRIBUTOR, txRateSetterIF, gpioComIF, + gpioIds::RS485_EN_TX_CLOCK, gpioIds::RS485_EN_TX_DATA); VirtualChannel* vc = nullptr; vc = new VirtualChannel(ccsds::VC0, common::VC0_QUEUE_SIZE); diff --git a/generators/bsp_q7s_objects.csv b/generators/bsp_q7s_objects.csv index 3d8a4d40..fded183b 100644 --- a/generators/bsp_q7s_objects.csv +++ b/generators/bsp_q7s_objects.csv @@ -78,6 +78,7 @@ 0x50000701;PAPB_VC1 0x50000702;PAPB_VC2 0x50000703;PAPB_VC3 +0x50000704;PDEC_HANDLER 0x50000800;CCSDS_HANDLER 0x51000500;PUS_SERVICE_6 0x53000000;FSFW_OBJECTS_START diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index 9dbc5428..3e3bf5c3 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -37,7 +37,7 @@ debugging. */ // Set to 1 if all telemetry should be sent to the PTME IP Core #define OBSW_TM_TO_PTME 1 // Set to 1 if telecommands are received via the PDEC IP Core -#define OBSW_TC_FROM_PDEC 0 +#define OBSW_TC_FROM_PDEC 1 #define OBSW_ENABLE_TIMERS 1 #define OBSW_ADD_STAR_TRACKER 0 diff --git a/linux/obc/PdecHandler.cpp b/linux/obc/PdecHandler.cpp index d68f79a4..f99a1a30 100644 --- a/linux/obc/PdecHandler.cpp +++ b/linux/obc/PdecHandler.cpp @@ -196,6 +196,7 @@ ReturnValue_t PdecHandler::performOperation(uint8_t operationCode) { if (newTcReceived()) { handleNewTc(); } + checkLocks(); break; case State::WAIT_FOR_RECOVERY: break; @@ -237,6 +238,19 @@ bool PdecHandler::newTcReceived() { return true; } +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 + triggerEvent(BIT_LOCK); + } + lastClcw = clcw; +} + bool PdecHandler::checkFrameAna(uint32_t pdecFar) { bool frameValid = false; FrameAna_t frameAna = static_cast((pdecFar & FRAME_ANA_MASK) >> FRAME_ANA_POSITION); diff --git a/linux/obc/PdecHandler.h b/linux/obc/PdecHandler.h index d7c7d236..83e4a253 100644 --- a/linux/obc/PdecHandler.h +++ b/linux/obc/PdecHandler.h @@ -71,6 +71,19 @@ public: */ void printClcw(); + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PDEC_HANDLER; + + //! [EXPORT] : [COMMENT] Frame acceptance report signals an invalid frame + //! P1: The frame analysis information (FrameAna field of PDEC_FAR register) + //! P2: When frame declared illegal this parameter this parameter gives information about the reason (IReason field of the PDEC_FAR register) + static const Event INVALID_TC_FRAME = MAKE_EVENT(1, severity::HIGH); + //! [EXPORT] : [COMMENT] Read invalid FAR from PDEC after startup + static const Event INVALID_FAR = MAKE_EVENT(2, severity::HIGH); + //! [EXPORT] : [COMMENT] Carrier lock detected + static const Event CARRIER_LOCK = MAKE_EVENT(3, severity::INFO); + //! [EXPORT] : [COMMENT] Bit lock detected (data valid) + static const Event BIT_LOCK = MAKE_EVENT(4, severity::INFO); + private: static const uint8_t INTERFACE_ID = CLASS_ID::PDEC_HANDLER; @@ -102,15 +115,6 @@ private: //! 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 uint32_t QUEUE_SIZE = common::CCSDS_HANDLER_QUEUE_SIZE; // Action IDs @@ -172,6 +176,9 @@ private: static const uint32_t TC_SEGMENT_LEN = 1017; + static const uint32_t NO_RF_MASK = 0x8000; + static const uint32_t NO_BITLOCK_MASK = 0x4000; + /** * TCs with map addresses (also know as Map IDs) assigned to this channel will be stored in * the PDEC memory. @@ -260,6 +267,12 @@ private: */ bool newTcReceived(); + /** + * @brief Checks if carrier lock or bit lock has been detected and triggers appropriate + * event. + */ + void checkLocks(); + /** * @brief Analyzes the FramAna field (frame analysis data) of a FAR report. * @@ -362,6 +375,9 @@ private: uint32_t pdecFar = 0; uint8_t tcSegment[TC_SEGMENT_LEN]; + + // Used to check carrier and bit lock changes (default set to no rf and no bitlock) + uint32_t lastClcw = 0xC000; }; #endif /* LINUX_OBC_PDECHANDLER_H_ */ diff --git a/mission/tmtc/CCSDSHandler.cpp b/mission/tmtc/CCSDSHandler.cpp index caf99515..a9c6df27 100644 --- a/mission/tmtc/CCSDSHandler.cpp +++ b/mission/tmtc/CCSDSHandler.cpp @@ -1,24 +1,32 @@ +#include "OBSWConfig.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/serviceInterfaceDefintions.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/ipc/QueueFactory.h" +#include "fsfw/events/EventManagerIF.h" + +#include #include "CCSDSHandler.h" CCSDSHandler::CCSDSHandler(object_id_t objectId, object_id_t ptmeId, object_id_t tcDestination, - TxRateSetterIF* txRateSetterIF) : + TxRateSetterIF* txRateSetterIF, GpioIF* gpioIF, gpioId_t enTxClock, gpioId_t enTxData) : SystemObject(objectId), ptmeId(ptmeId), tcDestination(tcDestination), parameterHelper(this), actionHelper( - this, nullptr), txRateSetterIF(txRateSetterIF) { + this, nullptr), txRateSetterIF(txRateSetterIF), gpioIF(gpioIF), enTxClock( + enTxClock), enTxData(enTxData) { commandQueue = QueueFactory::instance()->createMessageQueue(QUEUE_SIZE); + eventQueue = QueueFactory::instance()->createMessageQueue(EventMessage::EVENT_MESSAGE_SIZE * 2); } CCSDSHandler::~CCSDSHandler() { } ReturnValue_t CCSDSHandler::performOperation(uint8_t operationCode) { + checkEvents(); readCommandQueue(); handleTelemetry(); handleTelecommands(); + checkTxTimer(); return RETURN_OK; } @@ -71,6 +79,27 @@ ReturnValue_t CCSDSHandler::initialize() { iter->second->setPtmeObject(ptme); } + EventManagerIF* manager = ObjectManager::instance()->get( + objects::EVENT_MANAGER); + if (manager == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "CCSDSHandler::initialize: Invalid event manager" << std::endl; +#endif + return RETURN_FAILED; + } + result = manager->registerListener(eventQueue->getId()); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = manager->subscribeToEventRange(eventQueue->getId(), + event::getEventId(PdecHandler::CARRIER_LOCK), event::getEventId(PdecHandler::BIT_LOCK)); + 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; + } return result; } @@ -157,13 +186,113 @@ ReturnValue_t CCSDSHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { switch(actionId) { - case SET_LOW_RATE: + case SET_LOW_RATE: { txRateSetterIF->setRate(BitRates::RATE_400KHZ); return EXECUTION_FINISHED; - case SET_HIGH_RATE: + } + case SET_HIGH_RATE: { txRateSetterIF->setRate(BitRates::RATE_2000KHZ); return EXECUTION_FINISHED; + } + case EN_TRANSMITTER: { + enableTransmit(); + return EXECUTION_FINISHED; + } + case DIS_TRANSMITTER: { + disableTransmit(); + return EXECUTION_FINISHED; + } default: return COMMAND_NOT_IMPLEMENTED; } } + +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: { + 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); +#if BOARD_TE0720 == 0 + gpioIF->pullLow(enTxClock); + gpioIF->pullLow(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() { +#if BOARD_TE0720 == 0 + gpioIF->pullHigh(enTxClock); + gpioIF->pullHigh(enTxData); +#endif /* BOARD_TE0720 == 0 */ + linkState = DOWN; + forwardLinkstate(); +} diff --git a/mission/tmtc/CCSDSHandler.h b/mission/tmtc/CCSDSHandler.h index 6ed5abbe..cdab72e0 100644 --- a/mission/tmtc/CCSDSHandler.h +++ b/mission/tmtc/CCSDSHandler.h @@ -10,7 +10,11 @@ #include "fsfw/parameters/ParameterHelper.h" #include "fsfw/action/ActionHelper.h" #include "fsfw/action/HasActionsIF.h" +#include "fsfw/timemanager/Countdown.h" +#include "fsfw/events/EventMessage.h" #include "linux/obc/TxRateSetterIF.h" +#include "fsfw_hal/common/gpio/gpioDefinitions.h" +#include "fsfw_hal/common/gpio/GpioIF.h" #include "VirtualChannel.h" #include @@ -39,9 +43,12 @@ public: * @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, - TxRateSetterIF* txRateSetterIF); + TxRateSetterIF* txRateSetterIF, GpioIF* gpioIF, gpioId_t enTxClock, gpioId_t enTxData); ~CCSDSHandler(); @@ -76,10 +83,19 @@ private: 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 DIS_TRANSMITTER = 3; //! [EXPORT] : [COMMENT] Received action message with unknown action id static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xA0); + // syrlinks must not be transmitting more than 15 minutes (according to datasheet) +// static const uint32_t TRANSMITTER_TIMEOUT = 900000; //900000 ms = 15 min + static const uint32_t TRANSMITTER_TIMEOUT = 10000; //900000 ms = 15 min + + static const bool UP = true; + static const bool DOWN = false; + using VirtualChannelMap = std::unordered_map; using VirtualChannelMapIter = VirtualChannelMap::iterator; @@ -91,6 +107,7 @@ private: object_id_t tcDestination; MessageQueueIF* commandQueue = nullptr; + MessageQueueIF* eventQueue = nullptr; ParameterHelper parameterHelper; @@ -100,9 +117,48 @@ private: TxRateSetterIF* txRateSetterIF = nullptr; + GpioIF* gpioIF = nullptr; + gpioId_t enTxClock = gpio::NO_GPIO; + gpioId_t enTxData = gpio::NO_GPIO; + + // 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_ */