From ddd8ff21807586d2b850c8abe9fd91cca2f4cf51 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Sun, 19 Sep 2021 12:27:48 +0200 Subject: [PATCH 01/10] ptme handling wip --- bsp_q7s/core/ObjectFactory.cpp | 30 +- common/config/commonClassIds.h | 1 + common/config/commonConfig.h.in | 7 + common/config/commonObjects.h | 5 + .../tmtc}/CCSDSIPCoreBridge.cpp | 2 +- .../{obc => archive/tmtc}/CCSDSIPCoreBridge.h | 0 linux/fsfwconfig/OBSWConfig.h.in | 1 + linux/obc/CMakeLists.txt | 3 +- linux/obc/PapbVcInterface.cpp | 104 +++ linux/obc/PapbVcInterface.h | 106 +++ linux/obc/Ptme.cpp | 68 ++ linux/obc/Ptme.h | 84 +++ linux/obc/PtmeConfig.h | 26 + linux/obc/PtmeIF.h | 28 + linux/obc/VcInterfaceIF.h | 26 + mission/tmtc/CCSDSHandler.cpp | 605 ++++++++++++++++++ mission/tmtc/CCSDSHandler.h | 215 +++++++ mission/utility/TmFunnel.cpp | 7 + 18 files changed, 1312 insertions(+), 6 deletions(-) rename linux/{obc => archive/tmtc}/CCSDSIPCoreBridge.cpp (98%) rename linux/{obc => archive/tmtc}/CCSDSIPCoreBridge.h (100%) create mode 100644 linux/obc/PapbVcInterface.cpp create mode 100644 linux/obc/PapbVcInterface.h create mode 100644 linux/obc/Ptme.cpp create mode 100644 linux/obc/Ptme.h create mode 100644 linux/obc/PtmeConfig.h create mode 100644 linux/obc/PtmeIF.h create mode 100644 linux/obc/VcInterfaceIF.h create mode 100644 mission/tmtc/CCSDSHandler.cpp create mode 100644 mission/tmtc/CCSDSHandler.h diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index bdad3dac..ba98991c 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -1,3 +1,4 @@ +#include #include "ObjectFactory.h" #include "OBSWConfig.h" #include "devConf.h" @@ -23,8 +24,6 @@ #include "linux/devices/SusHandler.h" #include "linux/csp/CspCookie.h" #include "linux/csp/CspComIF.h" -#include "linux/obc/CCSDSIPCoreBridge.h" - #include "mission/core/GenericFactory.h" #include "mission/devices/PDU1Handler.h" #include "mission/devices/PDU2Handler.h" @@ -83,6 +82,9 @@ #include "linux/boardtest/LibgpiodTest.h" #endif +#include +#include + ResetArgs resetArgsGnss0; ResetArgs resetArgsGnss1; @@ -171,6 +173,26 @@ void ObjectFactory::produce(void* args){ #endif /* TE7020 != 0 */ +#if OBSW_USE_PTME_IP_CORE == 1 + GpioCookie* gpioCookiePtmeIp = new GpioCookie; + GpiodRegular* vc0PapbBusyN = new GpiodRegular(std::string("gpiochip0"), 0, std::string("PAPBBusy_N")); + gpioCookiePtmeIp->addGpio(gpioIds::PAPB_BUSY_N, papbBusyN); + GpiodRegular* vc0PapbEmpty = new GpiodRegular(st_d::string("gpiochip0"), 1, + std::string("PAPBEmpty_VC0")); + gpioCookiePtmeIp->addGpio(gpioIds::PAPB_EMPTY, papbEmpty); + gpioComIF->addGpios(gpioCookiePtmeIp); + PapbVcInterface* vc0 = new PapbVcInterface(objects::PAPB_VC0, gpioComIF, ) + Ptme* ptme = new Ptme(objects::PTME); + ptme->addVcInterface(0, vc0); + ptme->addVcInterface(1, vc1); + ptme->addVcInterface(2, vc2); + ptme->addVcInterface(3, vc3); + + new CCSDSIPCoreBridge(objects::CCSDS_IP_CORE_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR, + objects::TM_STORE, objects::TC_STORE, gpioComIF, std::string("/dev/uio0"), + gpioIds::PAPB_BUSY_N, gpioIds::PAPB_EMPTY); +#endif /* OBSW_USE_TMTC_IP_CORE_BRIDGE == 1 */ + #if OBSW_USE_TMTC_TCP_BRIDGE == 0 auto udpBridge = new UdpTmTcBridge(objects::TMTC_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR); new UdpTcPollingTask(objects::TMTC_POLLING_TASK, objects::TMTC_BRIDGE); @@ -846,10 +868,10 @@ void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) { #if BOARD_TE0720 == 1 && OBSW_TEST_CCSDS_BRIDGE == 1 GpioCookie* gpioCookieCcsdsIp = new GpioCookie; - GpiodRegular* papbBusyN = new GpiodRegular(std::string("gpiochip0"), 0, std::string("PAPBBusy_N")); + GpiodRegular* papbBusyN = new GpiodRegular(std::string("gpiochip0"), 0, std::string("PAPBBusy_VC0")); gpioCookieCcsdsIp->addGpio(gpioIds::PAPB_BUSY_N, papbBusyN); GpiodRegular* papbEmpty = new GpiodRegular(std::string("gpiochip0"), 1, - std::string("Chip Select Sus Sensor")); + std::string("PAPBEmpty_VC0")); gpioCookieCcsdsIp->addGpio(gpioIds::PAPB_EMPTY, papbEmpty); gpioComIF->addGpios(gpioCookieCcsdsIp); diff --git a/common/config/commonClassIds.h b/common/config/commonClassIds.h index 793cb1ba..71a7d312 100644 --- a/common/config/commonClassIds.h +++ b/common/config/commonClassIds.h @@ -19,6 +19,7 @@ enum commonClassIds: uint8_t { PLOC_SUPERVISOR_HANDLER, //PLSV SUS_HANDLER, //SUSS CCSDS_IP_CORE_BRIDGE, //IPCI + PTME, //PTME PLOC_UPDATER, //PLUD GOM_SPACE_HANDLER, //GOMS PLOC_MEMORY_DUMPER, //PLMEMDUMP diff --git a/common/config/commonConfig.h.in b/common/config/commonConfig.h.in index 52b5dd45..55af54e3 100644 --- a/common/config/commonConfig.h.in +++ b/common/config/commonConfig.h.in @@ -6,5 +6,12 @@ // Use TCP instead of UDP for the TMTC bridge. This allows using the TMTC client locally // because UDP packets are not allowed in the VPN #define OBSW_USE_TMTC_TCP_BRIDGE 1 +// This will cause the OBSW to initialize the TMTC bridge responsible for exchanging data with the +// CCSDS IP Cores. +#define OBSW_USE_TMTC_IP_CORE_BRIDGE 0 +// Set to 1 if all telemetry should be sent to the PTME IP Core +#define OBSW_TM_TO_PTME 0 +// Set to 1 if telecommands are received via the PDEC IP Core +#define OBSW_TC_FROM_PDEC 0 #endif /* COMMON_CONFIG_COMMONCONFIG_H_ */ diff --git a/common/config/commonObjects.h b/common/config/commonObjects.h index e44e0a1a..5fc61bd4 100644 --- a/common/config/commonObjects.h +++ b/common/config/commonObjects.h @@ -11,6 +11,11 @@ enum commonObjects: uint32_t { TMTC_BRIDGE = 0x50000300, TMTC_POLLING_TASK = 0x50000400, FILE_SYSTEM_HANDLER = 0x50000500, + PTME = 0x50000600, + PAPB_VC0 = 0x50000700, + PAPB_VC0 = 0x500007001, + PAPB_VC0 = 0x500007002, + PAPB_VC0 = 0x500007003, /* 0x43 ('C') for Controllers */ THERMAL_CONTROLLER = 0x43400001, diff --git a/linux/obc/CCSDSIPCoreBridge.cpp b/linux/archive/tmtc/CCSDSIPCoreBridge.cpp similarity index 98% rename from linux/obc/CCSDSIPCoreBridge.cpp rename to linux/archive/tmtc/CCSDSIPCoreBridge.cpp index fe5a7007..982f7fc2 100644 --- a/linux/obc/CCSDSIPCoreBridge.cpp +++ b/linux/archive/tmtc/CCSDSIPCoreBridge.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include CCSDSIPCoreBridge::CCSDSIPCoreBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId, LinuxLibgpioIF* gpioComIF, diff --git a/linux/obc/CCSDSIPCoreBridge.h b/linux/archive/tmtc/CCSDSIPCoreBridge.h similarity index 100% rename from linux/obc/CCSDSIPCoreBridge.h rename to linux/archive/tmtc/CCSDSIPCoreBridge.h diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index dc397635..83564c0c 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -96,6 +96,7 @@ namespace config { /* Add mission configuration flags here */ static constexpr uint32_t OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE = 50; static constexpr uint32_t PLOC_UPDATER_QUEUE_SIZE = 50; +static constexpr uint8_t NUMBER_OF_VIRTUAL_CHANNELS = 4; #ifdef __cplusplus } diff --git a/linux/obc/CMakeLists.txt b/linux/obc/CMakeLists.txt index 79d9ba9b..315a0d33 100644 --- a/linux/obc/CMakeLists.txt +++ b/linux/obc/CMakeLists.txt @@ -1,5 +1,6 @@ target_sources(${TARGET_NAME} PUBLIC - CCSDSIPCoreBridge.cpp + PapbVcInterface.cpp + Ptme.cpp ) diff --git a/linux/obc/PapbVcInterface.cpp b/linux/obc/PapbVcInterface.cpp new file mode 100644 index 00000000..736c8b24 --- /dev/null +++ b/linux/obc/PapbVcInterface.cpp @@ -0,0 +1,104 @@ +#include +#include "fsfw/serviceinterface/ServiceInterface.h" + +PapbVcInterface::PapbVcInterface(object_id_t objectId, LinuxLibgpioIF* gpioComIF, + gpioId_t papbBusyId, gpioId_t papbEmptyId, uint32_t vcOffset) : + SystemObject(objectId), gpioComIF(gpioComIF), uioVcInterface(uioVcInterface), papbBusyId( + papbBusyId), papbEmptyId(papbEmptyId), vcOffset(vcOffset) { +} + +PapbVcInterface::~PapbVcInterface() { +} + + +void PapbVcInterface::setRegisterAddress(uint32_t* ptmeBaseAddress) { + vcBaseReg = ptmeBaseAddress + vcOffset; +} + +ReturnValue_t PapbVcInterface::write(const uint8_t * data, size_t dataLen) { + + if(pollPapbBusySignal() == RETURN_OK) { + startPacketTransfer(); + } + + for(size_t idx = 0; idx < dataLen; idx++) { + if(pollPapbBusySignal() == RETURN_OK) { + *(vcBaseReg + DATA_REG_OFFSET) = static_cast(*(data + idx)); + } + else { + sif::warning << "PapbVcInterface::sendTm: Only written " << idx - 1 << " of " + << dataLen << " data" << std::endl; + return RETURN_FAILED; + } + } + + if(pollPapbBusySignal() == RETURN_OK) { + endPacketTransfer(); + } + return RETURN_OK; +} + +void PapbVcInterface::startPacketTransfer() { + *vcBaseReg = CONFIG_START; +} + +void PapbVcInterface::endPacketTransfer() { + *vcBaseReg = CONFIG_END; +} + +ReturnValue_t PapbVcInterface::pollPapbBusySignal() { + int papbBusyState = 0; + ReturnValue_t result = RETURN_OK; + + /** Check if PAPB interface is ready to receive data */ + result = gpioComIF->readGpio(papbBusyId, &papbBusyState); + if (result != RETURN_OK) { + sif::debug << "PapbVcInterface::pollPapbBusySignal: Failed to read papb busy signal" + << std::endl; + return RETURN_FAILED; + } + if (!papbBusyState) { + sif::debug << "PapbVcInterface::pollPapbBusySignal: PAPB busy" << std::endl; + return PAPB_BUSY; + } + + return RETURN_OK; +} + +void PapbVcInterface::isVcInterfaceBufferEmpty() { + ReturnValue_t result = RETURN_OK; + int papbEmptyState = 1; + + result = gpioComIF->readGpio(papbEmptyId, &papbEmptyState); + + if (result != RETURN_OK) { + sif::debug << "PapbVcInterface::isVcInterfaceBufferEmpty: Failed to read papb empty signal" + << std::endl; + return; + } + + if (papbEmptyState == 1) { + sif::debug << "PapbVcInterface::isVcInterfaceBufferEmpty: Buffer is empty" << std::endl; + } + else { + sif::debug << "PapbVcInterface::isVcInterfaceBufferEmpty: Buffer is not empty" << std::endl; + } + return; +} + +ReturnValue_t PapbVcInterface::sendTestFrame() { + /** Size of one complete transfer frame data field amounts to 1105 bytes */ + uint8_t testPacket[1105]; + + /** Fill one test packet */ + for(int idx = 0; idx < 1105; idx++) { + testPacket[idx] = static_cast(idx & 0xFF); + } + + ReturnValue_t result = sendTm(testPacket, 1105); + if(result != RETURN_OK) { + return result; + } + + return RETURN_OK; +} diff --git a/linux/obc/PapbVcInterface.h b/linux/obc/PapbVcInterface.h new file mode 100644 index 00000000..05947ac6 --- /dev/null +++ b/linux/obc/PapbVcInterface.h @@ -0,0 +1,106 @@ +#ifndef LINUX_OBC_PAPBVCINTERFACE_H_ +#define LINUX_OBC_PAPBVCINTERFACE_H_ + +#include "OBSWConfig.h" +#include "linux/obc/VcInterfaceIF.h" +#include +#include +#include +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +/** + * @brief This class handles the transmission of data to a virtual channel of the PTME IP Core + * via the PAPB interface. + * + * @author J. Meier + */ +class PapbVcInterface : VcInterfaceIF, HasReturnvaluesIF { +public: + /** + * @brief Constructor + * + * @param objectId + * @param papbBusyId The ID of the GPIO which is connected to the PAPBBusy_N signal of the + * VcInterface IP Core. A low logic level indicates the VcInterface is not + * ready to receive more data. + * @param papbEmptyId The ID of the GPIO which is connected to the PAPBEmpty signal of the + * VcInterface IP Core. The signal is high when there are no packets in the + * external buffer memory (BRAM). + */ + PapbVcInterface(object_id_t objectId, LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId, + gpioId_t papbEmptyId, uint32_t vcOffset); + virtual ~PapbVcInterface(); + +private: + + static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_IP_CORE_BRIDGE; + + static const ReturnValue_t PAPB_BUSY = MAKE_RETURN_CODE(0xA0); + + /** + * Configuration bits: + * bit[1:0]: Size of data (1,2,3 or 4 bytes). 1 Byte <=> b00 + * bit[2]: Set this bit to 1 to abort a transfered packet + * bit[3]: Signals to VcInterface the start of a new telemetry packet + */ + static const uint32_t CONFIG_START = 0x8; + + /** + * Writing this word to the VcInterface base address signals to the virtual channel interface + * that a complete tm packet has been transferred. + */ + static const uint32_t CONFIG_END = 0x0; + + /** + * Writing to this offset within the memory space of a virtual channel will insert data for + * encoding to the external buffer memory of the PTME IP Core. + * The address offset is 0x400 (= 4 * 256) + */ + static const int DATA_REG_OFFSET = 256; + + LinuxLibgpioIF* gpioComIF = nullptr; + + /** Pulled to low when virtual channel not ready to receive data */ + gpioId_t papbBusyId = gpio::NO_GPIO; + /** High when external buffer memory of virtual channel is empty */ + gpioId_t papbEmptyId = gpio::NO_GPIO; + + uint32_t* vcBaseReg = nullptr; + + uint32_t vcOffset = 0; + + /** + * @brief This function sends the config byte to the virtual channel of the PTME IP Core + * to initiate a packet transfer. + */ + void startPacketTransfer(); + + /** + * @brief This function sends the config byte to the virtual channel interface of the PTME + * IP Core to signal the end of a packet transfer. + */ + void endPacketTransfer(); + + /** + * @brief This function reads the papb busy signal indicating whether the virtual channel + * interface is ready to receive more data or not. PAPB is ready when + * PAPB_Busy_N == '1'. + * + * @return RETURN_OK when ready to receive data else PAPB_BUSY. + */ + ReturnValue_t pollPapbBusySignal(); + + /** + * @brief This function can be used for debugging to check whether there are packets in + * the packet buffer of the virtual channel or not. + */ + void isVcInterfaceBufferEmpty(); + + /** + * @brief This function sends a complete telemetry transfer frame data field (1105 bytes) + * to the papb interface of the PTME IP Core. Can be used to test the implementation. + */ + ReturnValue_t sendTestFrame(); +}; + +#endif /* LINUX_OBC_PAPBVCINTERFACE_H_ */ diff --git a/linux/obc/Ptme.cpp b/linux/obc/Ptme.cpp new file mode 100644 index 00000000..480b5836 --- /dev/null +++ b/linux/obc/Ptme.cpp @@ -0,0 +1,68 @@ +#include +#include + +#include +#include "fsfw/serviceinterface/ServiceInterface.h" + +Ptme::Ptme(object_id_t objectId) : + SystemObject(objectId) { +} + +Ptme::~Ptme() { +} + +ReturnValue_t Ptme::initialize() { + ReturnValue_t result = TmTcBridge::initialize(); + + fd = open(PtmeConfig::UIO_DEVICE_FILE, O_RDWR); + if (fd < 1) { + sif::warning << "Ptme::initialize: Invalid UIO device file" << std::endl; + return RETURN_FAILED; + } + + /** + * Map uio device in virtual address space + * PROT_WRITE: Map uio device in writable only mode + */ + ptmeBaseAddress = static_cast(mmap(NULL, MAP_SIZE, PROT_WRITE, + MAP_SHARED, fd, 0)); + + if (ptmeBaseAddress == MAP_FAILED) { + sif::error << "Ptme::initialize: Failed to map uio address" << std::endl; + return RETURN_FAILED; + } + + return result; +} + +ReturnValue_t Ptme::writeToVc(uint8_t vcId, const uint8_t * data, size_t dataLen) { + ReturnValue_t result = RETURN_OK; + VcInterfaceMapIter vcInterfaceMapIter = vcInterfaceMap.find(vcId); + if (vcInterfaceMapIter == vcInterfaceMap.end()) { + sif::warning << "Ptme::writeToVc: No virtual channel interface found for the virtual " + "channel with id " << static_cast(vcId) << std::endl; + return UNKNOWN_VC_ID; + } + result = vcInterfaceMapIter->second.write(data, size); + return result; +} + +void Ptme::addVcInterface(VcId_t vcId, VcInterfaceIF* vc) { + + if (vcId > config::MAX_VIRTUAL_CHANNEL_ID) { + sif::warning << "Ptme::addVcInterface: Invalid virtual channel ID" << std::endl; + return; + } + + if (vc == nullptr) { + sif::warning << "Ptme::addVcInterface: Invalid virtual channel interface" << std::endl; + return; + } + + auto status = vcInterfaceMap.emplace(vcId, vc); + if (status.second == false) { + sif::warning << "Ptme::addVcInterface: Failed to add virtual channel interface to " + "virtual channel map" << std::endl; + return; + } +} diff --git a/linux/obc/Ptme.h b/linux/obc/Ptme.h new file mode 100644 index 00000000..6ef118ab --- /dev/null +++ b/linux/obc/Ptme.h @@ -0,0 +1,84 @@ +#ifndef LINUX_OBC_PTME_H_ +#define LINUX_OBC_PTME_H_ + +#include "OBSWConfig.h" +#include "linux/obc/PtmeIF.h" +#include "linux/obc/VcInterfaceIF.h" +#include +#include +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +#include +#include + +/** + * @brief This class handles the interfacing to the telemetry (PTME) IP core responsible for the + * encoding of telemetry packets according to the CCSDS standards CCSDS 131.0-B-3 (TM Synchro- + * nization and channel coding) and CCSDS 132.0-B-2 (TM Space Data Link Protocoll). + * The IP cores are implemented on the programmable logic and are accessible through the + * linux UIO driver. + */ +class Ptme : PtmeIF, SystemObject, HasReturnvaluesIF { +public: + /** + * @brief Constructor + * + * @param objectId + */ + Ptme(object_id_t objectId); + virtual ~Ptme(); + + ReturnValue_t initialize() override; + ReturnValue_t writeToVc(uint8_t vcId, uint8_t* data, size_t size) override; + + /** + * @brief This function adds the reference to a virtual channel interface to the vcInterface + * map. + */ + void addVcInterface(VcId_t vcId, VcInterfaceIF* vc); + +private: + + static const uint8_t INTERFACE_ID = CLASS_ID::PTME; + + static const ReturnValue_t UNKNOWN_VC_ID = MAKE_RETURN_CODE(0xA0); + + + /** Size of mapped address space */ + static const int MAP_SIZE = 0x40000; + + /** + * Configuration bits: + * bit[1:0]: Size of data (1,2,3 or 4 bytes). 1 Byte <=> b00 + * bit[2]: Set this bit to 1 to abort a transfered packet + * bit[3]: Signals to PTME the start of a new telemetry packet + */ + static const uint32_t PTME_CONFIG_START = 0x8; + + /** + * Writing this word to the ptme base address signals to the PTME that a complete tm packet has + * been transferred. + */ + static const uint32_t PTME_CONFIG_END = 0x0; + + /** + * Writing to this offset within the PTME memory space will insert data for encoding to the + * PTME IP core. + * The address offset is 0x400 (= 4 * 256) + */ + static const int PTME_DATA_REG_OFFSET = 256; + + /** The file descriptor of the UIO driver */ + int fd; + + uint32_t* ptmeBaseAddress = nullptr; + + using VcId_t = uint8_t; + + using VcInterfaceMap = std::unordered_map; + using VcInterfaceMapIter = VcInterfaceMap::iterator; + + VcInterfaceMap vcInterfaceMap; +}; + +#endif /* LINUX_OBC_PTME_H_ */ diff --git a/linux/obc/PtmeConfig.h b/linux/obc/PtmeConfig.h new file mode 100644 index 00000000..34fd8876 --- /dev/null +++ b/linux/obc/PtmeConfig.h @@ -0,0 +1,26 @@ +#ifndef LINUX_OBC_PTMECONFIG_H_ +#define LINUX_OBC_PTMECONFIG_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include + + +/** + * @brief Configuration parameters derived from FPGA design and device tree. + * + * @author J. Meier + */ +namespace PtmeConfig { + /** + * Offset of virtual channels mapped into address space + * 0x10000 = (0x4000 * 4) + */ + static const uint32_t VC0_OFFSETT = 0; + static const uint32_t VC1_OFFSETT = 0x4000; + static const uint32_t VC2_OFFSETT = 0x8000; + static const uint32_t VC3_OFFSETT = 0xC000; + + static const std::string UIO_DEVICE_FILE = "/dev/uio0"; +}; + +#endif /* LINUX_OBC_PTMECONFIG_H_ */ diff --git a/linux/obc/PtmeIF.h b/linux/obc/PtmeIF.h new file mode 100644 index 00000000..c89d25f0 --- /dev/null +++ b/linux/obc/PtmeIF.h @@ -0,0 +1,28 @@ +#ifndef LINUX_OBC_PTMEIF_H_ +#define LINUX_OBC_PTMEIF_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + + +/** + * @brief Interface class for managing the PTME IP Core implemented in the programmable logic. + * + * @details PTME IP Core: https://www.esa.int/Enabling_Support/Space_Engineering_Technology/ + * Microelectronics/PTME + * @author J. Meier + */ +class PtmeIF { +public: + virtual ~PtmeIF(){}; + + /** + * @brief Implements to function to write to a specific virtual channel. + * + * @param vcId Virtual channel to write to + * @param data Pointer to buffer holding the data to write + * @param size Number of bytes to write + */ + virtual ReturnValue_t writeToVc(uint8_t vcId, uint8_t* data, size_t size) = 0; +}; + +#endif /* LINUX_OBC_PTMEIF_H_ */ diff --git a/linux/obc/VcInterfaceIF.h b/linux/obc/VcInterfaceIF.h new file mode 100644 index 00000000..ce643b48 --- /dev/null +++ b/linux/obc/VcInterfaceIF.h @@ -0,0 +1,26 @@ +#ifndef LINUX_OBC_VCINTERFACEIF_H_ +#define LINUX_OBC_VCINTERFACEIF_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +/** + * @brief Interface class for managing different virtual channels of the PTME IP core implemented + * in the programmable logic. + * + * @author J. Meier + */ +class VcInterfaceIF { +public: + virtual ~VcInterfaceIF(){}; + + /** + * @brief Implememts the functionality to write data in the virtual channel of the PTME IP + * Core. + * + * @param data Pointer to buffer holding the data to write + * @param size Number of bytes to write + */ + virtual ReturnValue_t write(uint8_t* data, size_t size) = 0; +}; + +#endif /* LINUX_OBC_VCINTERFACEIF_H_ */ diff --git a/mission/tmtc/CCSDSHandler.cpp b/mission/tmtc/CCSDSHandler.cpp new file mode 100644 index 00000000..38428c14 --- /dev/null +++ b/mission/tmtc/CCSDSHandler.cpp @@ -0,0 +1,605 @@ +/******************************* + * FLP Flight Software Framework (FSFW) + * (c) 2016 IRS, Uni Stuttgart + *******************************/ +/* + * CCSDSHandler.cpp + * + * Created on: Feb 9, 2012 + * Author: baetz + */ +#include +#include +#include +#include +#include +#include +#include +#include + +const float CCSDSHandler::DEFAULT_RATES[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD] = + { CCSDSHandler::DEFAULT_BYTES_PER_SECOND, CCSDSHandler::DEFAULT_BYTES_PER_SECOND, + CCSDSHandler::DEFAULT_BYTES_PER_SECOND, CCSDSHandler::DEFAULT_BYTES_PER_SECOND }; + +CCSDSHandler::CCSDSHandler(object_id_t setObjectId, uint8_t setSwitchId1, + uint8_t setSwitchId2, object_id_t setChannel, uint16_t setSCID, + BoardHandler::DataPoolIds setPool) : + SystemObject(setObjectId), tmPartHealth(setObjectId + 1, 0), commandQueue(), state( + STATE_IDLE), commState(SEND_WRITE), mode(MODE_OFF), submode( + SUBMODE_NONE), boardHandler((uint8_t*) frameBuffer, + sizeof(frameBuffer), setSCID, setPool), dataLinkLayer( + this->frameBuffer, boardHandler.getClcw(), 0, setSCID), frameLength( + 0), channelId(setChannel), memoryHelper(this, &commandQueue), pendingWrite( + false), pendingRead(false), modeHelper(this), healthHelper(this, + setObjectId), parameterHelper(this), powerSwitcher(setSwitchId1, + setSwitchId2), switchOffWasReported(false), fdir(setObjectId, + setChannel) { + memset(this->frameBuffer, 0, sizeof(frameBuffer)); + DataSet mySet; + PoolVector rateRatio( + datapool::DATA_RATE_ASSIGN, &mySet, PoolVariableIF::VAR_WRITE); + for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; + ++i) { + virtualChannels[i] = new VCGeneration(i, + BoardHandler::TM_PACKETS_PER_CALL_PER_CHANNEL); + rateLimitOverload[i] = 0; + rateRatio[i] = DEFAULT_RATES[i]; + } + mySet.commit(PoolVariableIF::VALID); + //Set real-time channel to high responsiveness. + virtualChannels[0]->setIdlePacketIntervalMs( + VCGeneration::IDLE_INTERVAL_RT_CHANNEL); +} + +CCSDSHandler::~CCSDSHandler() { + for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; + ++i) { + delete virtualChannels[i]; + } +} + +void CCSDSHandler::printFrameBuffer(void) { + debug << "frame_buffer contains: " << std::endl; + for (uint32_t i = 0; i < this->frameLength; ++i) { + debug << "frame_buffer[" << std::dec << i << "]: " << std::hex + << std::showbase << (uint16_t) this->frameBuffer[i] << std::dec + << std::endl; + } +} + +ReturnValue_t CCSDSHandler::packetProcessing(void) { + rateSet.read(); + const float* usedRateRatios = NULL; + if (rateSet.dataRates.isValid()) { + usedRateRatios = rateSet.dataRates.value; + } else { + usedRateRatios = DEFAULT_RATES; + } + for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; + ++i) { + //Set current cycle Limit first + uint32_t newLimit = (usedRateRatios[i]) / SENDS_PER_SECOND; + if (newLimit <= rateLimitOverload[i]) { + //Calculate new overload. + rateLimitOverload[i] -= newLimit; + //Use newLimit as current rate, VC is utilized to its current limit. + rateSet.dataRate[i] = usedRateRatios[i]; //equal to newLimit * SENDS_PER_SECOND + //Don't send anything new. + continue; + } + newLimit -= rateLimitOverload[i]; + virtualChannels[i]->tmSendLimitPerCycle = newLimit; + //Send new packets. + uint32_t tempRate = virtualChannels[i]->packetProcessing(); + if (tempRate > virtualChannels[i]->tmSendLimitPerCycle) { + rateLimitOverload[i] = tempRate - virtualChannels[i]->tmSendLimitPerCycle; + //VC is fully utilized, but not more. Overload will be accounted for in next cycles. + rateSet.dataRate[i] = virtualChannels[i]->tmSendLimitPerCycle * SENDS_PER_SECOND; + } else { + //Data rate extended to a Bytes/s range. Filtering is performed in controller. + rateSet.dataRate[i] = tempRate * SENDS_PER_SECOND; + rateLimitOverload[i] = 0; + } + } + rateSet.commit(PoolVariableIF::VALID); + return RETURN_OK; +} + +ReturnValue_t CCSDSHandler::packetProcessingCheck(void) { + ReturnValue_t status = RETURN_FAILED; + for (uint8_t vc = 0; vc < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; + ++vc) { + status = this->virtualChannels[vc]->packetProcessingCheck(); + if (status != RETURN_OK) { + error << "CCSDSHandler " << std::hex << this->getObjectId() + << " ::packetProcessingCheck: Error on VC " << (uint16_t) vc + << ". Error code: " << status << std::dec << std::endl; + } + } + return RETURN_OK; +} + +ReturnValue_t CCSDSHandler::performOperation(void) { + readCommandQueue(); + return RETURN_OK; +} + +void CCSDSHandler::searchFrame() { + frameLength = this->boardHandler.findFrame(); + while (frameLength != 0) { + ReturnValue_t frame_status = this->dataLinkLayer.processFrame( + frameLength); + if (frame_status != RETURN_OK) { + triggerEvent(DataLinkLayer::FRAME_PROCESSING_FAILED, frame_status, + 0); + } + boardHandler.resetFrameBuffer(); + frameLength = boardHandler.findFrame(); + } +} + +ReturnValue_t CCSDSHandler::initialize() { + PtmeIF *ptme = objectManager->get(ptmeId); + if (ptme == nullptr) { + return ObjectManagerIF::CHILD_INIT_FAILED; + } + status = boardHandler.initialize(channel); + if (status != RETURN_OK) { + return status; + } + status = modeHelper.initialize(); + if (status != RETURN_OK) { + return status; + } + status = healthHelper.initialize(); + if (status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + status = memoryHelper.initialize(); + if (status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + status = parameterHelper.initialize(); + if (status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + status = powerSwitcher.initialize(objects::PCDU_HANDLER); + if (status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + StorageManagerIF* tmStore = objectManager->get( + objects::TM_STORE); + status = dataLinkLayer.initialize(); + if ((tmStore != NULL) && status == RETURN_OK) { + status = RETURN_OK; + for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; + ++i) { +// this->virtualChannels[i] = objectManager->get( +// objects::CCSDS_VC_BASE + i); + if (this->virtualChannels[i] != NULL) { + this->virtualChannels[i]->setPacketStore(tmStore); + this->virtualChannels[i]->setBoardHandler(&this->boardHandler); + } else { + status = RETURN_FAILED; + } + } + } else { + status = RETURN_FAILED; + error << "CCSDSHandler " << std::hex << this->getObjectId() << std::dec + << " ::CCSDSHandler: Configuration failed." << std::endl; + } + status = fdir.initialize(); + if (status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + return status; +} + +void CCSDSHandler::readCommandQueue(void) { + CommandMessage commandMessage; + ReturnValue_t result = RETURN_FAILED; + while (commandQueue.receiveMessage(&commandMessage) == RETURN_OK) { + + result = parameterHelper.handleParameterMessage(&commandMessage); + if (result == RETURN_OK) { + return; + } + CommandMessage reply; + reply.setReplyRejected(CommandMessage::UNKNOW_COMMAND, + commandMessage.getCommand()); + commandQueue.reply(&reply); + } +} + +MessageQueueId_t CCSDSHandler::getCommandQueue() const { + return commandQueue.getId(); +} + +void CCSDSHandler::flushTmChannels() { + for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; + ++i) { + virtualChannels[i]->flush(); + } +} + +ReturnValue_t CCSDSHandler::handleMemoryLoad(uint32_t address, + const uint8_t* data, uint32_t size, uint8_t** dataPointer) { + if (size != 4) { + return INVALID_SIZE; + } + ReturnValue_t result = boardHandler.manualWriteToRegister(address, data); + if (result == RETURN_OK) { + pendingWrite = true; + return DO_IT_MYSELF; + } + return result; +} + +ReturnValue_t CCSDSHandler::handleMemoryDump(uint32_t address, uint32_t size, + uint8_t** dataPointer, uint8_t* dumpTarget) { + if (size != 4) { + return INVALID_SIZE; + } + ReturnValue_t result = boardHandler.sendRegisterReadCommand(address); + if (result == RETURN_OK) { + pendingRead = true; + return DO_IT_MYSELF; + } + return result; +} + +ReturnValue_t CCSDSHandler::checkModeCommand(Mode_t commandedMode, + Submode_t commandedSubmode, uint32_t* msToReachTheMode) { + if (state != STATE_IDLE) { + return IN_TRANSITION; + } + switch (commandedMode) { + case MODE_ON: + if ((commandedSubmode == SUBMODE_ACTIVE) + || (commandedSubmode == SUBMODE_PASSIVE)) { + return RETURN_OK; + } else { + return INVALID_SUBMODE; + } + break; + case MODE_OFF: + if (commandedSubmode == SUBMODE_NONE) { + return RETURN_OK; + } else { + return INVALID_SUBMODE; + } + default: + return INVALID_MODE; + } +} + +void CCSDSHandler::startTransition(Mode_t commandedMode, + Submode_t commandedSubmode) { + if (commandedMode == mode) { + if (mode == MODE_ON) { + state = STATE_SELECT_SUBMODE; + } else { + //Turn off switch again anyway + state = STATE_TURN_OFF; + } + } else { + switch (commandedMode) { + case MODE_ON: + state = STATE_TURN_ON; + break; + case MODE_OFF: + state = STATE_TURN_OFF; + break; + default: + //Error case. Cannot happen? + error << "CCSDSHandler::startTransition: Invalid commanded mode: " + << commandedMode << std::endl; + return; + } + } + triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); +} + +void CCSDSHandler::getMode(Mode_t* modeReturn, Submode_t* submodeReturn) { + *modeReturn = mode; + *submodeReturn = submode; +} + +void CCSDSHandler::setToExternalControl() { + healthHelper.setHealth(EXTERNAL_CONTROL); +} + +void CCSDSHandler::announceMode(bool recursive) { + triggerEvent(MODE_INFO, mode, submode); +} + +void CCSDSHandler::setParentQueue(MessageQueueId_t parentQueueId) { + modeHelper.setParentQueue(parentQueueId); + healthHelper.setParentQeueue(parentQueueId); + tmPartHealth.setParentQueue(parentQueueId); +} + +void CCSDSHandler::doStateMachine() { + ReturnValue_t status = RETURN_FAILED; + powerSwitcher.doStateMachine(); + switch (state) { + case STATE_IDLE: + //Do nothing? Do perform operation stuff? + break; + case STATE_TURN_ON: + powerSwitcher.turnOn(); + modeHelper.startTimer(powerSwitcher.getSwitchDelay()); + state = STATE_WAIT_ON; + break; + case STATE_WAIT_ON: + if (powerSwitcher.checkSwitchState() == RETURN_OK) { + modeHelper.startTimer(LINK_UP_DELAY_MS); + state = STATE_WAIT_LINK; + } + if (boardHandler.checkChannel() == RETURN_OK) { + boardHandler.startStateTranstion(); + state = STATE_INITIALIZE_BOARD; + } else { + if (modeHelper.isTimedOut()) { + triggerEvent(MODE_TRANSITION_FAILED, + PowerSwitchIF::SWITCH_TIMEOUT, state); + setMode(MODE_OFF, SUBMODE_NONE); + } + } + break; + case STATE_WAIT_LINK: + if (boardHandler.checkAndResetChannel() == RETURN_OK) { + boardHandler.startStateTranstion(); + state = STATE_INITIALIZE_BOARD; + } else { + if (modeHelper.isTimedOut()) { + triggerEvent(MODE_TRANSITION_FAILED, DeviceHandlerIF::TIMEOUT, + state); + setMode(MODE_OFF, SUBMODE_NONE); + } + } + break; + case STATE_INITIALIZE_BOARD: + status = boardHandler.initializeBoard(); + switch (status) { + case RETURN_OK: + state = STATE_SELECT_SUBMODE; + break; + case BoardHandler::IN_TRANSITION: + //cannot last forever, so just wait. + break; + default: + triggerEvent(MODE_TRANSITION_FAILED, status, state); + state = STATE_TURN_OFF; + break; + } + break; + case STATE_SELECT_SUBMODE: + boardHandler.startStateTranstion(); + if (modeHelper.commandedSubmode == SUBMODE_PASSIVE) { + state = STATE_WAIT_SUBMODE_PASSIVE; + } else { + state = STATE_WAIT_SUBMODE_ACTIVE; + } + break; + case STATE_WAIT_SUBMODE_PASSIVE: + //Just one wait cycle to get rid of pending TM. + state = STATE_DO_PASSIVATE; + break; + case STATE_DO_PASSIVATE: + status = boardHandler.tmPassivate(); + switch (status) { + case RETURN_OK: + setMode(MODE_ON, SUBMODE_PASSIVE); + break; + case BoardHandler::IN_TRANSITION: + //cannot last forever, so just wait. + break; + default: + //If it comes here and fails then, there might be something wrong with the board. + triggerEvent(MODE_TRANSITION_FAILED, status, state); + state = STATE_TURN_OFF; + break; + } + break; + case STATE_WAIT_SUBMODE_ACTIVE: + status = boardHandler.tmActivate(); + switch (status) { + case RETURN_OK: + setMode(MODE_ON, SUBMODE_ACTIVE); + break; + case BoardHandler::IN_TRANSITION: + //cannot last forever, so just wait. + break; + default: + //If it comes here and fails then, there might be something wrong with the board. + triggerEvent(MODE_TRANSITION_FAILED, status, state); + state = STATE_TURN_OFF; + break; + } + break; + case STATE_TURN_OFF: + //Passivate first. Mainly optimization for System Testbed. + boardHandler.startStateTranstion(); + state = STATE_DO_PASSIVATE_OFF; + //No break + case STATE_DO_PASSIVATE_OFF: + status = boardHandler.tmPassivate(); + switch (status) { + case RETURN_OK: + state = STATE_TURN_SWITCH_OFF; + break; + case BoardHandler::IN_TRANSITION: + //cannot last forever, so just wait. + break; + default: + //If it comes here and fails then, there might be something wrong with the board. + //Just turn it off. + state = STATE_TURN_SWITCH_OFF; + break; + } + break; + case STATE_TURN_SWITCH_OFF: + powerSwitcher.turnOff(); + modeHelper.startTimer(powerSwitcher.getSwitchDelay()); + state = STATE_WAIT_OFF; + break; + case STATE_WAIT_OFF: + if ((boardHandler.checkAndResetChannel() == RMAPChannelIF::LINK_DOWN) + || (powerSwitcher.checkSwitchState() == RETURN_OK)) { + setMode(MODE_OFF, SUBMODE_NONE); + state = STATE_IDLE; + } else { + if (modeHelper.isTimedOut()) { + triggerEvent(MODE_TRANSITION_FAILED, status, state); + setMode(mode, submode); + } + } + break; + default: + break; + } +} + +ReturnValue_t CCSDSHandler::addVirtualChannel(uint8_t virtualChannelId, + VirtualChannelReceptionIF* object) { + return this->dataLinkLayer.addVirtualChannel(virtualChannelId, object); +} + +void CCSDSHandler::setMode(Mode_t newMode, Submode_t newSubmode) { + triggerEvent(MODE_INFO, newMode, newSubmode); + if (newMode == MODE_OFF) { + boardHandler.setDataPoolVaraiblesInvalid(); + } + modeHelper.modeChanged(newMode, newSubmode); + state = STATE_IDLE; + mode = newMode; + submode = newSubmode; +} + +Mode_t CCSDSHandler::getMode() const { + return mode; +} + +Submode_t CCSDSHandler::getSubmode() const { + return submode; +} + +MessageQueueId_t CCSDSHandler::getReportReceptionQueue(uint8_t virtualChannel) { + if (virtualChannel < Ptme::NUM_OF_VIRTUAL_CHANNELS) { + return virtualChannels[virtualChannel]->getReportReceptionQueue(); + } else { + sif::debug << "CCSDSHandler::getReportReceptionQueue: Invalid virtual channel requested"; + } +} + +void CCSDSHandler::executeAllWriteCommands() { + ReturnValue_t returnValue = boardHandler.sendWriteCommands(); + if (returnValue != RETURN_OK) { + triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED, + returnValue, 0); + } + if (submode == SUBMODE_ACTIVE) { + returnValue = this->packetProcessing(); + if (returnValue != RETURN_OK) { + triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED, + returnValue, 1); + } + } +} + +void CCSDSHandler::handleAllWriteReplies() { + ReturnValue_t returnValue = boardHandler.getWriteReplys(); + if (returnValue != RETURN_OK) { + triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED, + returnValue, 0); + } + if (pendingWrite) { + memoryHelper.completeLoad(returnValue); + pendingWrite = false; + } + if (submode == SUBMODE_ACTIVE) { + returnValue = packetProcessingCheck(); + } else { + this->flushTmChannels(); + } +} + +void CCSDSHandler::executeAllReadCommands() { + ReturnValue_t returnValue = boardHandler.sendReadCommands(); + if (returnValue != RETURN_OK) { + triggerEvent(DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED, + returnValue, 0); + } +} + +void CCSDSHandler::handleAllReadReplies() { + if ((mode == MODE_ON) && (state == STATE_IDLE)) { + ReturnValue_t returnValue = boardHandler.getReadReplys(); + if (returnValue == RETURN_OK) { + searchFrame(); + } else { + triggerEvent(DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED, + returnValue, 0); + //do nothing. + } + if (pendingRead) { + uint8_t* tempBuffer; + returnValue = boardHandler.getRegisterReadReply(&tempBuffer); + memoryHelper.completeDump(returnValue, tempBuffer, + BoardHandler::REGISTER_LENGTH); + pendingRead = false; + } + } +} + +ReturnValue_t CCSDSHandler::getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, + uint16_t startAtIndex) { + ReturnValue_t result = fdir.getParameter(domainId, parameterId, + parameterWrapper, newValues, startAtIndex); + if (result != INVALID_DOMAIN_ID) { + return result; + } + if (domainId != DOMAIN_ID_BASE) { + return INVALID_DOMAIN_ID; + } + switch (parameterId) { + case 0: + parameterWrapper->set(boardHandler.tmPhysicalLayerRegisterValue); + break; + case 1: + parameterWrapper->set(boardHandler.tmCodingSublayerRegisterValue); + break; + default: + return INVALID_MATRIX_ID; + } + return RETURN_OK; +} + +ReturnValue_t CCSDSHandler::setHealth(HealthState health) { + healthHelper.setHealth(health); + return RETURN_OK; +} + +HasHealthIF::HealthState CCSDSHandler::getHealth() { + return healthHelper.getHealth(); +} + +CCSDSHandler::DataRateSet::DataRateSet() : + ControllerSet(), dataRate(datapool::VC_DATA_RATE_RAW, this, + PoolVariableIF::VAR_WRITE), dataRates( + datapool::DATA_RATE_ASSIGN, this, PoolVariableIF::VAR_READ) { +} + +CCSDSHandler::DataRateSet::~DataRateSet() { +} + +void CCSDSHandler::DataRateSet::setToDefault() { + dataRate.value = {0.0, 0.0, 0.0, 0.0}; +} + +void CCSDSHandler::triggerEvent(Event event, uint32_t parameter1, + uint32_t parameter2) { + fdir.triggerEvent(event, parameter1, parameter2); +} diff --git a/mission/tmtc/CCSDSHandler.h b/mission/tmtc/CCSDSHandler.h new file mode 100644 index 00000000..77c8b2c1 --- /dev/null +++ b/mission/tmtc/CCSDSHandler.h @@ -0,0 +1,215 @@ +#ifndef CCSDSHANDLER_H_ +#define CCSDSHANDLER_H_ + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/serviceinterface/serviceInterfaceDefintions.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/parameters/ParameterHelper.h" + +/** + * @brief This class handles the data exchange with the CCSDS IP cores implemented in the + * programmable logic of the Q7S. + * + * @author J. Meier + */ +class CCSDSHandler: public SystemObject, + public ExecutableObjectIF, + public HasModesIF, + public AcceptsTelemetryIF, + public HasReturnvaluesIF, + public ReceivesParameterMessagesIF { +public: + static const uint32_t LINK_UP_DELAY_MS = 2000; //!< The maximum time it takes to reconfigure the CCSDS Board. + static const uint32_t MAX_FRAME_SIZE = 1024; + static const Submode_t SUBMODE_ACTIVE = 1; //!< Submode where the TM part of the board is on. + static const Submode_t SUBMODE_PASSIVE = 0; //!< Submode where the TM part of the board is off. + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CCSDS_BOARD; + static const Event CCSDS_BOARD_RESET_FAILED = MAKE_EVENT(0, SEVERITY::LOW); //!> Resetting the communication channel failed. Severity LOW, par1: returnCode, par2: 0 + static const Event CCSDS_BOARD_SWITCHED = MAKE_EVENT(1, SEVERITY::INFO); //!> Switched active CCSDS-Board. Par1: objectId of now active board, Par2: objectId of now passive board. + + static const ActionId_t SET_DATA_RATE_RATIO = 1; + static const float SENDS_PER_SECOND = 2.5; + static const uint32_t MINIMUM_BYTES_PER_SECOND = + (VCGeneration::IDLE_PACKET_SIZE + / (VCGeneration::DEFAULT_IDLE_INTERVAL / 1000)) + 1; //!< +1 to be on the safe side. + static const float DEFAULT_RATES[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD]; + static const uint32_t DEFAULT_BYTES_PER_SECOND = 1300; + + HealthDevice tmPartHealth; //!< A helper device to dedicatetly set the telemetry part to not healthy. + /** + * Main Constructor of the class. + * Initializes all attributes with default values. Sets the frame buffer to zero. + * Creates all TM Virtual Channels (with \c new). Initialization of communication partners + * is done in the #initialize routine. + * @param setObjectId Object identifier of the class. + * @param setSwitchId1 Switch id of the first switch of the board. + * @param setSwitchId2 Switch id of the second switch of the board. + * @param set_channel RMAP channel identifier. This is forwarded to the #boardHandler class. + * @param set_scid Configured SpaceCraft Identifier. Is forwarded to #boardHandler and #dataLinkLayer class. + */ + CCSDSHandler(object_id_t setObjectId, uint8_t setSwitchId1, + uint8_t setSwitchId2, object_id_t setChannel, uint16_t setSCID, + BoardHandler::DataPoolIds setPool); + /** + * The destructor deletes all TM Virtual Channels. + */ + ~CCSDSHandler(); + /** + * Main executing method of the CCSDS Board handling. + * The method coordinates reading and writing of buffers and registers on the CCSDS Board + * as well as checking communication states and looking for frames. The state machine is + * executed here as well. To ensure a smooth communication without much delay, the last read + * and write calls are checked in the beginning and new requests as well as the state machine + * are issued in the end. + * @return Always returns #RETURN_OK. + */ + ReturnValue_t performOperation(void); + + ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data, + uint32_t size, uint8_t** dataPointer); + ReturnValue_t handleMemoryDump(uint32_t address, uint32_t size, + uint8_t** dataPointer, uint8_t* dumpTarget); + /** + * Initialization routine of the class. + * It initializes connections to the power unit and to the Telemetry store which is set for + * every TM Virtual Channel. + * @return + */ + ReturnValue_t initialize(); + MessageQueueId_t getCommandQueue() const; + /** + * Method to configure the TC Virtual Channels in the TC Data Link Layer. + * The call is forwarded to the #dataLinkLayer class. + * @param virtualChannelId VCID to add. + * @param object Pointer to the Virtual Channel object that is added. + * @return See the #dataLinkLayer class. + */ + ReturnValue_t addVirtualChannel(uint8_t virtualChannelId, + VirtualChannelReceptionIF* object); + + Mode_t getMode() const; + Submode_t getSubmode() const; + void setParentQueue(MessageQueueId_t parentQueueId); + MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0); + ReturnValue_t setHealth(HealthState health); + HasHealthIF::HealthState getHealth(); + ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); + void triggerEvent(Event event, uint32_t parameter1 = 0, + uint32_t parameter2 = 0); +protected: + MessageQueue commandQueue; //!< Queue to receive control commands. + VCGeneration* virtualChannels[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD];//!< An array of VCGeneration classes which each manage on TM Virtual Channel. + uint32_t rateLimitOverload[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD];//!< Used to smooth data rate in case large packets are sent. + /** + * This method reads the command queue and initializes a state transition if a command of this type was found. + */ + void readCommandQueue(void); + + /** + * This method flushes all pending messages in the TM queue by calling the \c flush method of + * all #virtualChannels. + * This is necessary to avoid doubled TM packets if the TM sender issues its messages to both the + * nominal and redundant CCSDS Board. + */ + void flushTmChannels(); + /** + * This is a helper method to print the current content of the frame buffers. + */ + void printFrameBuffer(void); + /** + * This is an important method which triggers searching for and handling found frames. + * It first calls the boardHandler method to find a frame in the received data. If a + * well-formed frame was found it calls the #dataLinkLayer class to process the frame + */ + void searchFrame(); + /** + * Calls the packet processing routine of each TM Virtual Channel. + * This triggers reception of incoming packets from the OBSW and forwarding to the CCSDS Board. + * There are different sending strategies for forwarding the packets to the board. + * @return Returns #RETURN_OK or the status of the failed virtual channel method. + */ + ReturnValue_t packetProcessing(void); + /** + * With this method the successful forwarding of Telemetry to the TM Virtual Channels is checked. + * The method calls the check routine of each virtual channel. + * @return Returns #RETURN_OK or the status of the failed virtual channel method. + */ + ReturnValue_t packetProcessingCheck(void); + + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode); + void startTransition(Mode_t mode, Submode_t submode); + void getMode(Mode_t *mode, Submode_t *submode); + void setToExternalControl(); + void announceMode(bool recursive); +private: + enum CcsdsState_t { + STATE_IDLE, + STATE_TURN_ON, + STATE_TURN_OFF, + STATE_DO_PASSIVATE_OFF, + STATE_TURN_SWITCH_OFF, + STATE_WAIT_ON, + STATE_WAIT_LINK, + STATE_WAIT_OFF, + STATE_INITIALIZE_BOARD, + STATE_SELECT_SUBMODE, + STATE_WAIT_SUBMODE_ACTIVE, + STATE_DO_PASSIVATE, + STATE_WAIT_SUBMODE_PASSIVE, + STATE_HANDLE_STARTUP, + }; + CcsdsState_t state; + enum CommState { + SEND_WRITE, GET_WRITE, SEND_READ, GET_READ + }; + CommState commState; + Mode_t mode; + Submode_t submode; + BoardHandler boardHandler;//!< The class that handles the low-level communication with the board. + DataLinkLayer dataLinkLayer;//!< The class that manages the TC Data Link Layer protocols. + uint8_t frameBuffer[MAX_FRAME_SIZE]; //!< The main buffer to store single frames in. + uint16_t frameLength; //!< Indicates the current length of the found frame. + object_id_t channelId; //!< Defines the id of the RMAP Channel to use. + MemoryHelper memoryHelper; //!< Helps handling memory messages. + + bool pendingWrite; //!< Attribute to manage remote Memory write. + + bool pendingRead; //!< Attribute to manage remote Memory read. + + ModeHelper modeHelper; //!< Helps handling mode messages. + HealthHelper healthHelper; //!< Helps setting the health information correctly. + ParameterHelper parameterHelper; + PowerSwitcher powerSwitcher; //!< Helps switching switches on and off. + + bool switchOffWasReported; //!< To avoid reporting SWITCH_WENT_OFF multiple times. + + CCSDSBoardFailureIsolation fdir; + class DataRateSet: public ControllerSet { + public: + DataRateSet(); + virtual ~DataRateSet(); + void setToDefault(); + PoolVector dataRate; + PoolVector dataRates; + }; + DataRateSet rateSet; + void setMode(Mode_t newMode, Submode_t newSubmode); //!< Method to safely setMode and inform everyone interested about it. + /** + * State machine of the Handler. + * Is responsible for handling mode transitions and for informing the modeHelper. + * In addition, it watches the SpW link and changes the Mode in case a link down or a link up is detected. + */ + void doStateMachine(); + void executeAllWriteCommands(); + void handleAllWriteReplies(); + void executeAllReadCommands(); + void handleAllReadReplies(); +}; + +#endif /* CCSDSHANDLER_H_ */ diff --git a/mission/utility/TmFunnel.cpp b/mission/utility/TmFunnel.cpp index c52fa6f9..e5de3ef7 100644 --- a/mission/utility/TmFunnel.cpp +++ b/mission/utility/TmFunnel.cpp @@ -1,3 +1,4 @@ +#include "OBSWConfig.h" #include #include #include @@ -97,7 +98,13 @@ ReturnValue_t TmFunnel::initialize() { "properly and implements AcceptsTelemetryIF" << std::endl; return ObjectManagerIF::CHILD_INIT_FAILED; } + +#if OBSW_USE_PTME_IP_CORE == 1 + // Live TM will be sent via the virtual channel 0 + tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue(0)); +#else tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue()); +#endif /* OBSW_USE_CCSDS_IP_CORES == 1 */ // Storage destination is optional. if(storageDestination == objects::NO_OBJECT) { From d54e2276d6735c3db1aadfa1ab6c230558bd9303 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Wed, 22 Sep 2021 16:54:55 +0200 Subject: [PATCH 02/10] ccsds handler wip --- bsp_q7s/boardconfig/busConf.h | 10 ++ bsp_q7s/core/ObjectFactory.cpp | 66 ++++++++---- common/config/commonConfig.h.in | 2 +- common/config/commonObjects.h | 6 +- linux/fsfwconfig/devices/gpioIds.h | 11 +- linux/obc/PapbVcInterface.cpp | 6 +- mission/tmtc/CCSDSHandler.cpp | 167 +++++++---------------------- mission/tmtc/CCSDSHandler.h | 93 ++++------------ mission/tmtc/VirtualChannel.cpp | 80 ++++++++++++++ mission/tmtc/VirtualChannel.h | 110 +++++++++++++++++++ mission/utility/TmFunnel.cpp | 10 +- mission/utility/TmFunnel.h | 2 +- 12 files changed, 327 insertions(+), 236 deletions(-) create mode 100644 mission/tmtc/VirtualChannel.cpp create mode 100644 mission/tmtc/VirtualChannel.h diff --git a/bsp_q7s/boardconfig/busConf.h b/bsp_q7s/boardconfig/busConf.h index f5b4a860..5bec55a2 100644 --- a/bsp_q7s/boardconfig/busConf.h +++ b/bsp_q7s/boardconfig/busConf.h @@ -90,6 +90,16 @@ static constexpr uint32_t SPI_MUX_BIT_5 = 17; static constexpr uint32_t SPI_MUX_BIT_6 = 9; static constexpr uint32_t EN_RW_CS = 17; +static constexpr char GPIO_VC_STATUS_SIGNALS_LABEL[] = "/amba_pl/gpio@81200000"; +static constexpr uint32_t VC0_PAPB_EMPTY_LINE = 0; +static constexpr uint32_t VC0_PAPB_BUSY_LINE = 1; +static constexpr uint32_t VC1_PAPB_EMPTY_LINE = 2; +static constexpr uint32_t VC1_PAPB_BUSY_LINE = 3; +static constexpr uint32_t VC2_PAPB_EMPTY_LINE = 4; +static constexpr uint32_t VC2_PAPB_BUSY_LINE = 5; +static constexpr uint32_t VC3_PAPB_EMPTY_LINE = 6; +static constexpr uint32_t VC3_PAPB_BUSY_LINE = 7; + } #endif /* BSP_Q7S_BOARDCONFIG_BUSCONF_H_ */ diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 024be8dd..0fcaff62 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -173,25 +173,55 @@ void ObjectFactory::produce(void* args) { #endif /* TE7020 != 0 */ -#if OBSW_USE_PTME_IP_CORE == 1 - GpioCookie* gpioCookiePtmeIp = new GpioCookie; - GpiodRegular* vc0PapbBusyN = new GpiodRegular(std::string("gpiochip0"), 0, std::string("PAPBBusy_N")); - gpioCookiePtmeIp->addGpio(gpioIds::PAPB_BUSY_N, papbBusyN); - GpiodRegular* vc0PapbEmpty = new GpiodRegular(st_d::string("gpiochip0"), 1, - std::string("PAPBEmpty_VC0")); - gpioCookiePtmeIp->addGpio(gpioIds::PAPB_EMPTY, papbEmpty); - gpioComIF->addGpios(gpioCookiePtmeIp); - PapbVcInterface* vc0 = new PapbVcInterface(objects::PAPB_VC0, gpioComIF, ) - Ptme* ptme = new Ptme(objects::PTME); - ptme->addVcInterface(0, vc0); - ptme->addVcInterface(1, vc1); - ptme->addVcInterface(2, vc2); - ptme->addVcInterface(3, vc3); +#if OBSW_USE_CCSDS_IP_CORE == 1 - new CCSDSIPCoreBridge(objects::CCSDS_IP_CORE_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR, - objects::TM_STORE, objects::TC_STORE, gpioComIF, std::string("/dev/uio0"), - gpioIds::PAPB_BUSY_N, gpioIds::PAPB_EMPTY); -#endif /* OBSW_USE_TMTC_IP_CORE_BRIDGE == 1 */ + // GPIO definitions of signals connected to the virtual channel interfaces of the PTME IP Core + GpioCookie* gpioCookiePtmeIp = new GpioCookie; + GpiodRegular* vcSignal = new GpiodRegular("PAPB VC0 Busy Signal", + q7s::GPIO_VC_STATUS_SIGNALS_LABEL, q7s::VC0_PAPB_BUSY_LINE); + gpioCookiePtmeIp->addGpio(gpioIds::VC0_PAPB_BUSY, vcSignal); + vcSignal = new GpiodRegular("PAPB VC0 Empty Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, + q7s::VC0_PAPB_EMPTY_LINE); + gpioCookiePtmeIp->addGpio(gpioIds::VC0_PAPB_EMPTY, vcSignal); + vcSignal = new GpiodRegular("PAPB VC1 Busy Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, + q7s::VC1_PAPB_BUSY_LINE); + gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_BUSY, vcSignal); + vcSignal = new GpiodRegular("PAPB VC1 Empty Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, + q7s::VC1_PAPB_EMPTY_LINE); + gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_EMPTY, vcSignal); + vcSignal = new GpiodRegular("PAPB VC2 Busy Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, + q7s::VC2_PAPB_BUSY_LINE); + gpioCookiePtmeIp->addGpio(gpioIds::VC2_PAPB_BUSY, vcSignal); + vcSignal = new GpiodRegular("PAPB VC2 Empty Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, + q7s::VC2_PAPB_EMPTY_LINE); + gpioCookiePtmeIp->addGpio(gpioIds::VC2_PAPB_EMPTY, vcSignal); + vcSignal = new GpiodRegular("PAPB VC3 Busy Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, + q7s::VC3_PAPB_BUSY_LINE); + gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_BUSY, vcSignal); + vcSignal = new GpiodRegular("PAPB VC3 Empty Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, + q7s::VC3_PAPB_EMPTY_LINE); + gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_EMPTY, vcSignal); + + gpioComIF->addGpios(gpioCookiePtmeIp); + + // Creating virtual channel interfaces + PapbVcInterface* vc = new PapbVcInterface(objects::PAPB_VC0, gpioComIF, gpioIds::VC0_PAPB_BUSY, + gpioIds::VC0_PAPB_EMPTY); + PapbVcInterface* vc = new PapbVcInterface(objects::PAPB_VC1, gpioComIF, gpioIds::VC1_PAPB_BUSY, + gpioIds::VC1_PAPB_EMPTY); + PapbVcInterface* vc = new PapbVcInterface(objects::PAPB_VC2, gpioComIF, gpioIds::VC2_PAPB_BUSY, + gpioIds::VC2_PAPB_EMPTY); + PapbVcInterface* vc = new PapbVcInterface(objects::PAPB_VC3, gpioComIF, gpioIds::VC3_PAPB_BUSY, + gpioIds::VC3_PAPB_EMPTY); + + // Creating ptme object and adding virtual channel interfaces + Ptme* ptme = new Ptme(objects::PTME); + ptme->addVcInterface(0, vc); + ptme->addVcInterface(1, vc); + ptme->addVcInterface(2, vc); + ptme->addVcInterface(3, vc); + +#endif /* OBSW_USE_CCSDS_IP_CORE == 1 */ #if OBSW_USE_TMTC_TCP_BRIDGE == 0 auto udpBridge = new UdpTmTcBridge(objects::TMTC_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR); diff --git a/common/config/commonConfig.h.in b/common/config/commonConfig.h.in index 55af54e3..c089c575 100644 --- a/common/config/commonConfig.h.in +++ b/common/config/commonConfig.h.in @@ -8,7 +8,7 @@ #define OBSW_USE_TMTC_TCP_BRIDGE 1 // This will cause the OBSW to initialize the TMTC bridge responsible for exchanging data with the // CCSDS IP Cores. -#define OBSW_USE_TMTC_IP_CORE_BRIDGE 0 +#define OBSW_USE_CCSDS_IP_CORE 1 // Set to 1 if all telemetry should be sent to the PTME IP Core #define OBSW_TM_TO_PTME 0 // Set to 1 if telecommands are received via the PDEC IP Core diff --git a/common/config/commonObjects.h b/common/config/commonObjects.h index 5fc61bd4..0a66cd9a 100644 --- a/common/config/commonObjects.h +++ b/common/config/commonObjects.h @@ -13,9 +13,9 @@ enum commonObjects: uint32_t { FILE_SYSTEM_HANDLER = 0x50000500, PTME = 0x50000600, PAPB_VC0 = 0x50000700, - PAPB_VC0 = 0x500007001, - PAPB_VC0 = 0x500007002, - PAPB_VC0 = 0x500007003, + PAPB_VC1 = 0x500007001, + PAPB_VC2 = 0x500007002, + PAPB_VC3 = 0x500007003, /* 0x43 ('C') for Controllers */ THERMAL_CONTROLLER = 0x43400001, diff --git a/linux/fsfwconfig/devices/gpioIds.h b/linux/fsfwconfig/devices/gpioIds.h index b450bf8b..2016245d 100644 --- a/linux/fsfwconfig/devices/gpioIds.h +++ b/linux/fsfwconfig/devices/gpioIds.h @@ -89,7 +89,16 @@ enum gpioId_t { EN_RW_CS, - SPI_MUX + SPI_MUX, + + VC0_PAPB_EMPTY, + VC0_PAPB_BUSY, + VC1_PAPB_EMPTY, + VC1_PAPB_BUSY, + VC2_PAPB_EMPTY, + VC2_PAPB_BUSY, + VC3_PAPB_EMPTY, + VC3_PAPB_BUSY }; } diff --git a/linux/obc/PapbVcInterface.cpp b/linux/obc/PapbVcInterface.cpp index 736c8b24..0c3c759a 100644 --- a/linux/obc/PapbVcInterface.cpp +++ b/linux/obc/PapbVcInterface.cpp @@ -53,12 +53,12 @@ ReturnValue_t PapbVcInterface::pollPapbBusySignal() { /** Check if PAPB interface is ready to receive data */ result = gpioComIF->readGpio(papbBusyId, &papbBusyState); if (result != RETURN_OK) { - sif::debug << "PapbVcInterface::pollPapbBusySignal: Failed to read papb busy signal" + sif::warning << "PapbVcInterface::pollPapbBusySignal: Failed to read papb busy signal" << std::endl; return RETURN_FAILED; } if (!papbBusyState) { - sif::debug << "PapbVcInterface::pollPapbBusySignal: PAPB busy" << std::endl; + sif::warning << "PapbVcInterface::pollPapbBusySignal: PAPB busy" << std::endl; return PAPB_BUSY; } @@ -72,7 +72,7 @@ void PapbVcInterface::isVcInterfaceBufferEmpty() { result = gpioComIF->readGpio(papbEmptyId, &papbEmptyState); if (result != RETURN_OK) { - sif::debug << "PapbVcInterface::isVcInterfaceBufferEmpty: Failed to read papb empty signal" + sif::warning << "PapbVcInterface::isVcInterfaceBufferEmpty: Failed to read papb empty signal" << std::endl; return; } diff --git a/mission/tmtc/CCSDSHandler.cpp b/mission/tmtc/CCSDSHandler.cpp index 38428c14..b17af452 100644 --- a/mission/tmtc/CCSDSHandler.cpp +++ b/mission/tmtc/CCSDSHandler.cpp @@ -1,13 +1,3 @@ -/******************************* - * FLP Flight Software Framework (FSFW) - * (c) 2016 IRS, Uni Stuttgart - *******************************/ -/* - * CCSDSHandler.cpp - * - * Created on: Feb 9, 2012 - * Author: baetz - */ #include #include #include @@ -121,9 +111,30 @@ ReturnValue_t CCSDSHandler::packetProcessingCheck(void) { ReturnValue_t CCSDSHandler::performOperation(void) { readCommandQueue(); + handleTelemetry(); + handleTelecommands(); return RETURN_OK; } +void CCSDSHandler::addVirtualChannel(VcId_t virtualChannelId, VirtualChannel* virtualChannel) { + auto status = virtualChannelMap.emplace(virtualChannelId, virtualChannel); + if (status.second == false) { + sif::warning << "CCSDSHandler::addVcInterface: Failed to add virtual channel with virtual " + << "channel id " << static_cast(virtualChannelId) << std::endl; + } +} + +void CCSDSHandler::handleTelemetry() { + VirtualChannelMapIter iter; + for (iter = virtualChannelMap.begin(); iter != VirtualChannelMap.end(); iter++) { + iter->second.virtualChannel->performOperation(); + } +} + +void CCSDSHandler::handleTelecommands() { + +} + void CCSDSHandler::searchFrame() { frameLength = this->boardHandler.findFrame(); while (frameLength != 0) { @@ -198,17 +209,18 @@ ReturnValue_t CCSDSHandler::initialize() { void CCSDSHandler::readCommandQueue(void) { CommandMessage commandMessage; ReturnValue_t result = RETURN_FAILED; - while (commandQueue.receiveMessage(&commandMessage) == RETURN_OK) { - result = parameterHelper.handleParameterMessage(&commandMessage); - if (result == RETURN_OK) { - return; - } - CommandMessage reply; - reply.setReplyRejected(CommandMessage::UNKNOW_COMMAND, - commandMessage.getCommand()); - commandQueue.reply(&reply); - } + result = commandQueue.receiveMessage(&commandMessage); + if (result == RETURN_OK) { + result = parameterHelper.handleParameterMessage(&commandMessage); + if (result == RETURN_OK) { + return; + } + CommandMessage reply; + reply.setReplyRejected(CommandMessage::UNKNOW_COMMAND, + commandMessage.getCommand()); + commandQueue.reply(&reply); + } } MessageQueueId_t CCSDSHandler::getCommandQueue() const { @@ -486,120 +498,15 @@ Submode_t CCSDSHandler::getSubmode() const { } MessageQueueId_t CCSDSHandler::getReportReceptionQueue(uint8_t virtualChannel) { - if (virtualChannel < Ptme::NUM_OF_VIRTUAL_CHANNELS) { + if (virtualChannel < config::NUMBER_OF_VIRTUAL_CHANNELS) { return virtualChannels[virtualChannel]->getReportReceptionQueue(); } else { sif::debug << "CCSDSHandler::getReportReceptionQueue: Invalid virtual channel requested"; } } -void CCSDSHandler::executeAllWriteCommands() { - ReturnValue_t returnValue = boardHandler.sendWriteCommands(); - if (returnValue != RETURN_OK) { - triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED, - returnValue, 0); - } - if (submode == SUBMODE_ACTIVE) { - returnValue = this->packetProcessing(); - if (returnValue != RETURN_OK) { - triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED, - returnValue, 1); - } - } -} - -void CCSDSHandler::handleAllWriteReplies() { - ReturnValue_t returnValue = boardHandler.getWriteReplys(); - if (returnValue != RETURN_OK) { - triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED, - returnValue, 0); - } - if (pendingWrite) { - memoryHelper.completeLoad(returnValue); - pendingWrite = false; - } - if (submode == SUBMODE_ACTIVE) { - returnValue = packetProcessingCheck(); - } else { - this->flushTmChannels(); - } -} - -void CCSDSHandler::executeAllReadCommands() { - ReturnValue_t returnValue = boardHandler.sendReadCommands(); - if (returnValue != RETURN_OK) { - triggerEvent(DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED, - returnValue, 0); - } -} - -void CCSDSHandler::handleAllReadReplies() { - if ((mode == MODE_ON) && (state == STATE_IDLE)) { - ReturnValue_t returnValue = boardHandler.getReadReplys(); - if (returnValue == RETURN_OK) { - searchFrame(); - } else { - triggerEvent(DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED, - returnValue, 0); - //do nothing. - } - if (pendingRead) { - uint8_t* tempBuffer; - returnValue = boardHandler.getRegisterReadReply(&tempBuffer); - memoryHelper.completeDump(returnValue, tempBuffer, - BoardHandler::REGISTER_LENGTH); - pendingRead = false; - } - } -} - -ReturnValue_t CCSDSHandler::getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, - uint16_t startAtIndex) { - ReturnValue_t result = fdir.getParameter(domainId, parameterId, - parameterWrapper, newValues, startAtIndex); - if (result != INVALID_DOMAIN_ID) { - return result; - } - if (domainId != DOMAIN_ID_BASE) { - return INVALID_DOMAIN_ID; - } - switch (parameterId) { - case 0: - parameterWrapper->set(boardHandler.tmPhysicalLayerRegisterValue); - break; - case 1: - parameterWrapper->set(boardHandler.tmCodingSublayerRegisterValue); - break; - default: - return INVALID_MATRIX_ID; - } - return RETURN_OK; -} - -ReturnValue_t CCSDSHandler::setHealth(HealthState health) { - healthHelper.setHealth(health); - return RETURN_OK; -} - -HasHealthIF::HealthState CCSDSHandler::getHealth() { - return healthHelper.getHealth(); -} - -CCSDSHandler::DataRateSet::DataRateSet() : - ControllerSet(), dataRate(datapool::VC_DATA_RATE_RAW, this, - PoolVariableIF::VAR_WRITE), dataRates( - datapool::DATA_RATE_ASSIGN, this, PoolVariableIF::VAR_READ) { -} - -CCSDSHandler::DataRateSet::~DataRateSet() { -} - -void CCSDSHandler::DataRateSet::setToDefault() { - dataRate.value = {0.0, 0.0, 0.0, 0.0}; -} - -void CCSDSHandler::triggerEvent(Event event, uint32_t parameter1, - uint32_t parameter2) { - fdir.triggerEvent(event, parameter1, parameter2); +ReturnValue_t CCSDSHandler::getParameter(uint8_t domainId, uint8_t uniqueIdentifier, + ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, + uint16_t startAtIndex) { + return RETURN_OK; } diff --git a/mission/tmtc/CCSDSHandler.h b/mission/tmtc/CCSDSHandler.h index 77c8b2c1..8780b4e8 100644 --- a/mission/tmtc/CCSDSHandler.h +++ b/mission/tmtc/CCSDSHandler.h @@ -16,7 +16,6 @@ */ class CCSDSHandler: public SystemObject, public ExecutableObjectIF, - public HasModesIF, public AcceptsTelemetryIF, public HasReturnvaluesIF, public ReceivesParameterMessagesIF { @@ -80,27 +79,26 @@ public: */ ReturnValue_t initialize(); MessageQueueId_t getCommandQueue() const; + /** - * Method to configure the TC Virtual Channels in the TC Data Link Layer. - * The call is forwarded to the #dataLinkLayer class. - * @param virtualChannelId VCID to add. - * @param object Pointer to the Virtual Channel object that is added. - * @return See the #dataLinkLayer class. + * @brief Function to add a virtual channel + * + * @param virtualChannelId ID of the virtual channel to add + * @param virtualChannel Pointer to virtual channel object + * + * @return RETURN_OK if successful, otherwise RETURN_FAILED */ - ReturnValue_t addVirtualChannel(uint8_t virtualChannelId, - VirtualChannelReceptionIF* object); + void addVirtualChannel(VcId_t virtualChannelId, VirtualChannel* virtualChannel); Mode_t getMode() const; Submode_t getSubmode() const; void setParentQueue(MessageQueueId_t parentQueueId); MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0); - ReturnValue_t setHealth(HealthState health); - HasHealthIF::HealthState getHealth(); - ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - void triggerEvent(Event event, uint32_t parameter1 = 0, - uint32_t parameter2 = 0); + + ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier, + ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, + uint16_t startAtIndex); + protected: MessageQueue commandQueue; //!< Queue to receive control commands. VCGeneration* virtualChannels[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD];//!< An array of VCGeneration classes which each manage on TM Virtual Channel. @@ -148,68 +146,15 @@ protected: void setToExternalControl(); void announceMode(bool recursive); private: - enum CcsdsState_t { - STATE_IDLE, - STATE_TURN_ON, - STATE_TURN_OFF, - STATE_DO_PASSIVATE_OFF, - STATE_TURN_SWITCH_OFF, - STATE_WAIT_ON, - STATE_WAIT_LINK, - STATE_WAIT_OFF, - STATE_INITIALIZE_BOARD, - STATE_SELECT_SUBMODE, - STATE_WAIT_SUBMODE_ACTIVE, - STATE_DO_PASSIVATE, - STATE_WAIT_SUBMODE_PASSIVE, - STATE_HANDLE_STARTUP, - }; - CcsdsState_t state; - enum CommState { - SEND_WRITE, GET_WRITE, SEND_READ, GET_READ - }; - CommState commState; - Mode_t mode; - Submode_t submode; - BoardHandler boardHandler;//!< The class that handles the low-level communication with the board. - DataLinkLayer dataLinkLayer;//!< The class that manages the TC Data Link Layer protocols. - uint8_t frameBuffer[MAX_FRAME_SIZE]; //!< The main buffer to store single frames in. - uint16_t frameLength; //!< Indicates the current length of the found frame. - object_id_t channelId; //!< Defines the id of the RMAP Channel to use. - MemoryHelper memoryHelper; //!< Helps handling memory messages. - bool pendingWrite; //!< Attribute to manage remote Memory write. + using VcId_t = uint8_t; + using VirtualChannelMap = std::unordered_map; + using VirtualChannelMapIter = VirtualChannelMap::iterator; - bool pendingRead; //!< Attribute to manage remote Memory read. + VirtualChannelMap virtualChannelMap; - ModeHelper modeHelper; //!< Helps handling mode messages. - HealthHelper healthHelper; //!< Helps setting the health information correctly. - ParameterHelper parameterHelper; - PowerSwitcher powerSwitcher; //!< Helps switching switches on and off. - - bool switchOffWasReported; //!< To avoid reporting SWITCH_WENT_OFF multiple times. - - CCSDSBoardFailureIsolation fdir; - class DataRateSet: public ControllerSet { - public: - DataRateSet(); - virtual ~DataRateSet(); - void setToDefault(); - PoolVector dataRate; - PoolVector dataRates; - }; - DataRateSet rateSet; - void setMode(Mode_t newMode, Submode_t newSubmode); //!< Method to safely setMode and inform everyone interested about it. - /** - * State machine of the Handler. - * Is responsible for handling mode transitions and for informing the modeHelper. - * In addition, it watches the SpW link and changes the Mode in case a link down or a link up is detected. - */ - void doStateMachine(); - void executeAllWriteCommands(); - void handleAllWriteReplies(); - void executeAllReadCommands(); - void handleAllReadReplies(); + void handleTelemetry(); + void handleTelecommands(); }; #endif /* CCSDSHANDLER_H_ */ diff --git a/mission/tmtc/VirtualChannel.cpp b/mission/tmtc/VirtualChannel.cpp new file mode 100644 index 00000000..8e106de1 --- /dev/null +++ b/mission/tmtc/VirtualChannel.cpp @@ -0,0 +1,80 @@ +#include "CCSDSHandler.h" +#include "OBSWConfig.h" + +#include "fsfw/serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/objectmanager/ObjectManager.h" + + +#include + +#include + + +VirtualChannel::VirtualChannel(uint8_t vcId, uint32_t tmQueueDepth) : + vcId(vcId) { + tmQueue = QueueFactory::instance()->createMessageQueue(tmQueueDepth, + MessageQueueMessage::MAX_MESSAGE_SIZE); +} + +ReturnValue_t VirtualChannel::initialize() { + tmStore = ObjectManager::instance()->get(objects::TM_STORE); + if(tmStore == nullptr) { + sif::error << "VirtualChannel::initialize: Failed to get tm store" << std::endl; + return RETURN_FAILED; + } +} + +ReturnValue_t VirtualChannel::performOperation() { + ReturnValue_t status = RETURN_OK; + TmTcMessage message; + + while(tmQueue->receiveMessage(&message) == RETURN_OK) { + store_address_t storeId = message.getStorageId(); + const uint8_t* data = nullptr; + size_t size = 0; + result = tmStore->getData(storeId, &data, &size); + if (result != RETURN_OK) { + sif::warning << "VirtualChannel::performOperation: Failed to read data from IPC store" + << std::endl; + tmStore->deleteData(storeId); + return result; + } + + if (linkIsUp) { + result = ptme->writeToVc(virtualChannleId, data, size); + } + + tmStore->deleteData(storeId); + + if (result != RETURN_OK) { + return result; + } + } + return result; +} + +MessageQueueId_t VirtualChannel::getReportReceptionQueue(uint8_t virtualChannel) { + return tmQueue.getId(); +} + +void VirtualChannel::setPtmeObject(PtmeIF* ptme) { + if (ptme == nullptr) { + sif::warning << "VirtualChannel::setPtmeObject: Invalid ptme object" << std::endl; + } + ptme = ptme; +} + +void VirtualChannel::setIdlePacketIntervalMs(uint32_t idlePacketIntervalMs) { + timer.timeout = idlePacketIntervalMs; +} + +ReturnValue_t VirtualChannel::flush() { + TmTcMessage message; + ReturnValue_t status = RETURN_FAILED; + for (status = tmQueue.receiveMessage(&message); status == RETURN_OK; + status = tmQueue.receiveMessage(&message)) { + packetStore->deleteData(message.getStorageId()); + } + boardHandler->resetVC(virtualChannelId); + return status; +} diff --git a/mission/tmtc/VirtualChannel.h b/mission/tmtc/VirtualChannel.h new file mode 100644 index 00000000..cba4b0b4 --- /dev/null +++ b/mission/tmtc/VirtualChannel.h @@ -0,0 +1,110 @@ +#ifndef VIRTUALCHANNEL_H_ +#define VIRTUALCHANNEL_H_ + +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief This class represents a virtual channel in the software. + * + * @author J. Meier + */ +class VirtualChannel: public AcceptsTelemetryIF, public HasReturnvaluesIF { + public: + + uint32_t tmSendLimitPerCycle; //!< Current maximum bytes per cycle. + + static const uint32_t IDLE_INTERVAL_RT_CHANNEL = 2000; //!< Real Time channel (VC 0) idle interval. + + static const uint16_t IDLE_PACKET_SIZE = 1015; //!< Size of generated idle packets. + + static const uint32_t DEFAULT_IDLE_INTERVAL = 20000; //!< Default if too lazy to set. + + /** + * @brief Constructor + * + * @param vcId The virtual channel id assigned to this object + * @param tmQueueDepth Queue depth of queue receiving telemetry from other objects + */ + VirtualChannel(uint8_t vcId, uint32_t tmQueueDepth); + + ReturnValue_t initialize(); + + /** + * One of the main public methods. + * Checks the tmQueue, calls #handlePacket if packets were found and keeps track of the number of sent bytes, + * to stop transmission before a buffer overflow occurs. If no packets were sent, an idle packet is generated. + * @return Number of sent bytes. 0 if an error occurred. + */ + uint32_t packetProcessing(void); + /** + * Another important method to check successful forwarding of packets. + * Checks how many packets have been forwarded to the CCSDS Board and tries to get as many + * RMAP write replys. The pending messages are deleted here. + * @return @c RETURN_OK on success, or one of many error codes, mainly coming from @c receiveVCAcknowledge. + */ + ReturnValue_t packetProcessingCheck(void); + /** + * Setter. + * @param setStore Sets the #packetStore used. + */ + void setPacketStore(StorageManagerIF* setStore); + MessageQueueId_t getReportReceptionQueue(); + + ReturnValue_t performOperation(); + + /** + * @brief Sets the PTME object which handles access to the PTME IP Core. + * + * @param ptme Pointer to ptme object + */ + void setPtmeObject(Ptme* ptme); + +private: + + PtmeIF* ptme = nullptr; + MessageQueueIF* tmQueue = nullptr; + uint8_t virtualChannelId; + bool linkIsUp; + StorageManagerIF* tmStore = nullptr; + + + BoardHandler* boardHandler; //!< A reference to the "hardware part" of handling the packets. + store_address_t pendingTm[BoardHandler::TM_PACKETS_PER_CALL_PER_CHANNEL]; //!< List of packets sent to the board. Is used to check if all Space Packets sent received the CCSDS Board. + uint16_t sendCount; //!< Counter to identify how many packets have been sent coming in to the board (without Idle Packets). + Countdown timer; + SpacePacket idlePacket; + uint32_t accumulatedByteCount; + + store_address_t pendingPacket; + + static const uint32_t TM_SEND_LIMIT_PER_CYCLE = 1300; //!< The maximum number of bytes to send to the CCSDS Board VC per cycle. + + /** + * Helper method to send an idle packet. + * @return @c RETURN_OK on success, @c RETURN_FAILED otherwise. + */ + ReturnValue_t sendIdlePacket(uint32_t size); + /** + * A helper method to handle incoming packets. + * Reads a packet from #packetStore and tries to forward it to the CCSDS BoardHandler class. + * Calls the hardware layer with @c writeToVc. Depending on what the "hardware" layer does, + * it stores the sent packet id's to find out if they were all received by the CCSDS Board. + * @param store_id ID of a packet in the #packetStore. + * @return @c RETURN_OK on success, the return code of @c writeToVc otherwise. + */ + ReturnValue_t handlePacket(store_address_t storeId); +}; + +#endif /* VIRTUALCHANNEL_H_ */ diff --git a/mission/utility/TmFunnel.cpp b/mission/utility/TmFunnel.cpp index e5de3ef7..d718f6cf 100644 --- a/mission/utility/TmFunnel.cpp +++ b/mission/utility/TmFunnel.cpp @@ -46,7 +46,7 @@ ReturnValue_t TmFunnel::performOperation(uint8_t operationCode) { ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) { uint8_t* packetData = nullptr; size_t size = 0; - ReturnValue_t result = tmPool->modifyData(message->getStorageId(), + ReturnValue_t result = tmStore->modifyData(message->getStorageId(), &packetData, &size); if(result != HasReturnvaluesIF::RETURN_OK){ return result; @@ -60,7 +60,7 @@ ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) { result = tmQueue->sendToDefault(message); if(result != HasReturnvaluesIF::RETURN_OK){ - tmPool->deleteData(message->getStorageId()); + tmStore->deleteData(message->getStorageId()); sif::error << "TmFunnel::handlePacket: Error sending to downlink " "handler" << std::endl; return result; @@ -69,7 +69,7 @@ ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) { if(storageDestination != objects::NO_OBJECT) { result = storageQueue->sendToDefault(message); if(result != HasReturnvaluesIF::RETURN_OK){ - tmPool->deleteData(message->getStorageId()); + tmStore->deleteData(message->getStorageId()); sif::error << "TmFunnel::handlePacket: Error sending to storage " "handler" << std::endl; return result; @@ -80,8 +80,8 @@ ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) { ReturnValue_t TmFunnel::initialize() { - tmPool = ObjectManager::instance()->get(objects::TM_STORE); - if(tmPool == nullptr) { + tmStore = ObjectManager::instance()->get(objects::TM_STORE); + if(tmStore == nullptr) { sif::error << "TmFunnel::initialize: TM store not set." << std::endl; sif::error << "Make sure the tm store is set up properly" diff --git a/mission/utility/TmFunnel.h b/mission/utility/TmFunnel.h index 2d4575a0..b85a09e0 100644 --- a/mission/utility/TmFunnel.h +++ b/mission/utility/TmFunnel.h @@ -41,7 +41,7 @@ private: MessageQueueIF* tmQueue = nullptr; MessageQueueIF* storageQueue = nullptr; - StorageManagerIF* tmPool = nullptr; + StorageManagerIF* tmStore = nullptr; uint32_t messageDepth = 0; ReturnValue_t handlePacket(TmTcMessage* message); From 5b26564058aba88f7160c9f0af19b0725b5261c5 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Sun, 26 Sep 2021 08:29:30 +0200 Subject: [PATCH 03/10] ptme ip core packet insertion --- bsp_q7s/boardconfig/busConf.h | 8 + bsp_q7s/core/ObjectFactory.cpp | 126 +++++--- bsp_q7s/core/ObjectFactory.h | 1 + common/config/ccsdsConfig.h | 15 + common/config/commonObjects.h | 7 +- linux/fsfwconfig/OBSWConfig.h.in | 5 + linux/obc/PapbVcInterface.cpp | 10 +- linux/obc/PapbVcInterface.h | 10 +- linux/obc/Ptme.cpp | 17 +- linux/obc/Ptme.h | 11 +- linux/obc/PtmeConfig.h | 2 +- linux/obc/PtmeIF.h | 2 +- linux/obc/VcInterfaceIF.h | 5 +- mission/CMakeLists.txt | 1 + mission/tmtc/CCSDSHandler.cpp | 500 ++++--------------------------- mission/tmtc/CCSDSHandler.h | 131 ++------ mission/tmtc/CMakeLists.txt | 6 + mission/tmtc/VirtualChannel.cpp | 30 +- mission/tmtc/VirtualChannel.h | 83 +---- mission/utility/TmFunnel.cpp | 4 +- 20 files changed, 252 insertions(+), 722 deletions(-) create mode 100644 common/config/ccsdsConfig.h create mode 100644 mission/tmtc/CMakeLists.txt diff --git a/bsp_q7s/boardconfig/busConf.h b/bsp_q7s/boardconfig/busConf.h index 1149a54e..4b64e775 100644 --- a/bsp_q7s/boardconfig/busConf.h +++ b/bsp_q7s/boardconfig/busConf.h @@ -52,6 +52,14 @@ namespace gpioNames { static constexpr char EN_RW_4[] = "enable_rw_4"; static constexpr char SPI_MUX_SELECT[] = "spi_mux_select"; static constexpr char RAD_SENSOR_CHIP_SELECT[] = "rad_sensor_chip_select"; + static constexpr char PAPB_BUSY_SIGNAL_VC0[] = "papb_busy_signal_vc0"; + static constexpr char PAPB_EMPTY_SIGNAL_VC0[] = "papb_empty_signal_vc0"; + static constexpr char PAPB_BUSY_SIGNAL_VC1[] = "papb_busy_signal_vc1"; + static constexpr char PAPB_EMPTY_SIGNAL_VC1[] = "papb_empty_signal_vc1"; + static constexpr char PAPB_BUSY_SIGNAL_VC2[] = "papb_busy_signal_vc2"; + static constexpr char PAPB_EMPTY_SIGNAL_VC2[] = "papb_empty_signal_vc2"; + static constexpr char PAPB_BUSY_SIGNAL_VC3[] = "papb_busy_signal_vc3"; + static constexpr char PAPB_EMPTY_SIGNAL_VC3[] = "papb_empty_signal_vc3"; } } diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index a5a76f8b..86709292 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -2,6 +2,7 @@ #include "ObjectFactory.h" #include "OBSWConfig.h" #include "devConf.h" +#include "ccsdsConfig.h" #include "busConf.h" #include "tmtc/apid.h" #include "devices/addresses.h" @@ -47,6 +48,8 @@ #include "mission/devices/devicedefinitions/RwDefinitions.h" #include "mission/devices/devicedefinitions/StarTrackerDefinitions.h" #include "mission/devices/GPSHyperionHandler.h" +#include "mission/tmtc/CCSDSHandler.h" +#include "mission/tmtc/VirtualChannel.h" #include "mission/utility/TmFunnel.h" #include "fsfw_hal/linux/uart/UartComIF.h" @@ -84,6 +87,7 @@ #include #include +#include ResetArgs resetArgsGnss0; ResetArgs resetArgsGnss1; @@ -101,7 +105,12 @@ void Factory::setStaticFrameworkObjectIds() { //DeviceHandlerBase::powerSwitcherId = objects::PCDU_HANDLER; DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; + +#if OBSW_TM_TO_PTME == 1 + TmFunnel::downlinkDestination = objects::CCSDS_HANDLER; +#else TmFunnel::downlinkDestination = objects::TMTC_BRIDGE; +#endif /* OBSW_TM_TO_PTME == 1 */ // No storage object for now. TmFunnel::storageDestination = objects::NO_OBJECT; @@ -174,53 +183,7 @@ void ObjectFactory::produce(void* args) { #endif /* TE7020 != 0 */ #if OBSW_USE_CCSDS_IP_CORE == 1 - - // GPIO definitions of signals connected to the virtual channel interfaces of the PTME IP Core - GpioCookie* gpioCookiePtmeIp = new GpioCookie; - GpiodRegular* vcSignal = new GpiodRegular("PAPB VC0 Busy Signal", - q7s::GPIO_VC_STATUS_SIGNALS_LABEL, q7s::VC0_PAPB_BUSY_LINE); - gpioCookiePtmeIp->addGpio(gpioIds::VC0_PAPB_BUSY, vcSignal); - vcSignal = new GpiodRegular("PAPB VC0 Empty Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, - q7s::VC0_PAPB_EMPTY_LINE); - gpioCookiePtmeIp->addGpio(gpioIds::VC0_PAPB_EMPTY, vcSignal); - vcSignal = new GpiodRegular("PAPB VC1 Busy Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, - q7s::VC1_PAPB_BUSY_LINE); - gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_BUSY, vcSignal); - vcSignal = new GpiodRegular("PAPB VC1 Empty Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, - q7s::VC1_PAPB_EMPTY_LINE); - gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_EMPTY, vcSignal); - vcSignal = new GpiodRegular("PAPB VC2 Busy Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, - q7s::VC2_PAPB_BUSY_LINE); - gpioCookiePtmeIp->addGpio(gpioIds::VC2_PAPB_BUSY, vcSignal); - vcSignal = new GpiodRegular("PAPB VC2 Empty Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, - q7s::VC2_PAPB_EMPTY_LINE); - gpioCookiePtmeIp->addGpio(gpioIds::VC2_PAPB_EMPTY, vcSignal); - vcSignal = new GpiodRegular("PAPB VC3 Busy Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, - q7s::VC3_PAPB_BUSY_LINE); - gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_BUSY, vcSignal); - vcSignal = new GpiodRegular("PAPB VC3 Empty Signal", q7s::GPIO_VC_STATUS_SIGNALS_LABEL, - q7s::VC3_PAPB_EMPTY_LINE); - gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_EMPTY, vcSignal); - - gpioComIF->addGpios(gpioCookiePtmeIp); - - // Creating virtual channel interfaces - PapbVcInterface* vc = new PapbVcInterface(objects::PAPB_VC0, gpioComIF, gpioIds::VC0_PAPB_BUSY, - gpioIds::VC0_PAPB_EMPTY); - PapbVcInterface* vc = new PapbVcInterface(objects::PAPB_VC1, gpioComIF, gpioIds::VC1_PAPB_BUSY, - gpioIds::VC1_PAPB_EMPTY); - PapbVcInterface* vc = new PapbVcInterface(objects::PAPB_VC2, gpioComIF, gpioIds::VC2_PAPB_BUSY, - gpioIds::VC2_PAPB_EMPTY); - PapbVcInterface* vc = new PapbVcInterface(objects::PAPB_VC3, gpioComIF, gpioIds::VC3_PAPB_BUSY, - gpioIds::VC3_PAPB_EMPTY); - - // Creating ptme object and adding virtual channel interfaces - Ptme* ptme = new Ptme(objects::PTME); - ptme->addVcInterface(0, vc); - ptme->addVcInterface(1, vc); - ptme->addVcInterface(2, vc); - ptme->addVcInterface(3, vc); - + createCcsdsComponents(gpioComIF); #endif /* OBSW_USE_CCSDS_IP_CORE == 1 */ #if OBSW_USE_TMTC_TCP_BRIDGE == 0 @@ -922,6 +885,75 @@ void ObjectFactory::createReactionWheelComponents(LinuxLibgpioIF* gpioComIF) { rw4SpiCookie->setCallbackArgs(rwHandler4); } +void ObjectFactory::createCcsdsComponents(LinuxLibgpioIF *gpioComIF) { + // GPIO definitions of signals connected to the virtual channel interfaces of the PTME IP Core + GpioCookie* gpioCookiePtmeIp = new GpioCookie; + GpiodRegularByLineName* gpio = nullptr; + std::stringstream consumer; + consumer << "0x" << std::hex << objects::PAPB_VC0; + gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_BUSY_SIGNAL_VC0, consumer.str()); + gpioCookiePtmeIp->addGpio(gpioIds::VC0_PAPB_BUSY, gpio); + consumer.str(""); + consumer << "0x" << std::hex << objects::PAPB_VC0; + gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC0, consumer.str()); + gpioCookiePtmeIp->addGpio(gpioIds::VC0_PAPB_EMPTY, gpio); + consumer.str(""); + consumer << "0x" << std::hex << objects::PAPB_VC1; + gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_BUSY_SIGNAL_VC1, consumer.str()); + gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_BUSY, gpio); + consumer.str(""); + consumer << "0x" << std::hex << objects::PAPB_VC1; + gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC1, consumer.str()); + gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_EMPTY, gpio); + consumer.str(""); + consumer << "0x" << std::hex << objects::PAPB_VC2; + gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_BUSY_SIGNAL_VC2, consumer.str()); + gpioCookiePtmeIp->addGpio(gpioIds::VC2_PAPB_BUSY, gpio); + consumer.str(""); + consumer << "0x" << std::hex << objects::PAPB_VC2; + gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC2, consumer.str()); + gpioCookiePtmeIp->addGpio(gpioIds::VC2_PAPB_EMPTY, gpio); + consumer.str(""); + consumer << "0x" << std::hex << objects::PAPB_VC3; + gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_BUSY_SIGNAL_VC3, consumer.str()); + gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_BUSY, gpio); + consumer.str(""); + consumer << "0x" << std::hex << objects::PAPB_VC3; + gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC3, consumer.str()); + gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_EMPTY, gpio); + + gpioComIF->addGpios(gpioCookiePtmeIp); + + // Creating virtual channel interfaces + VcInterfaceIF* vc0 = new PapbVcInterface(objects::PAPB_VC0, gpioComIF, gpioIds::VC0_PAPB_BUSY, + gpioIds::VC0_PAPB_EMPTY, PtmeConfig::VC0_OFFSETT); + VcInterfaceIF* vc1 = new PapbVcInterface(objects::PAPB_VC1, gpioComIF, gpioIds::VC1_PAPB_BUSY, + gpioIds::VC1_PAPB_EMPTY, PtmeConfig::VC1_OFFSETT); + VcInterfaceIF* vc2 = new PapbVcInterface(objects::PAPB_VC2, gpioComIF, gpioIds::VC2_PAPB_BUSY, + gpioIds::VC2_PAPB_EMPTY, PtmeConfig::VC2_OFFSETT); + VcInterfaceIF* vc3 = new PapbVcInterface(objects::PAPB_VC3, gpioComIF, gpioIds::VC3_PAPB_BUSY, + gpioIds::VC3_PAPB_EMPTY, PtmeConfig::VC3_OFFSETT); + + // Creating ptme object and adding virtual channel interfaces + Ptme* ptme = new Ptme(objects::PTME); + ptme->addVcInterface(ccsds::VC0, vc0); + ptme->addVcInterface(ccsds::VC1, vc1); + ptme->addVcInterface(ccsds::VC2, vc2); + ptme->addVcInterface(ccsds::VC3, vc3); + + CCSDSHandler* ccsdsHandler = new CCSDSHandler(objects::CCSDS_HANDLER, objects::PTME); + + VirtualChannel* vc = nullptr; + vc = new VirtualChannel(ccsds::VC0, config::VC0_QUEUE_SIZE); + ccsdsHandler->addVirtualChannel(ccsds::VC0, vc); + vc = new VirtualChannel(ccsds::VC1, config::VC1_QUEUE_SIZE); + ccsdsHandler->addVirtualChannel(ccsds::VC1, vc); + vc = new VirtualChannel(2, config::VC2_QUEUE_SIZE); + ccsdsHandler->addVirtualChannel(ccsds::VC2, vc); + vc = new VirtualChannel(3, config::VC3_QUEUE_SIZE); + ccsdsHandler->addVirtualChannel(ccsds::VC3, vc); +} + void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) { #if BOARD_TE0720 == 0 diff --git a/bsp_q7s/core/ObjectFactory.h b/bsp_q7s/core/ObjectFactory.h index ad9533a5..0e723142 100644 --- a/bsp_q7s/core/ObjectFactory.h +++ b/bsp_q7s/core/ObjectFactory.h @@ -22,6 +22,7 @@ void createSolarArrayDeploymentComponents(); void createSyrlinksComponents(); void createRtdComponents(LinuxLibgpioIF* gpioComIF); void createReactionWheelComponents(LinuxLibgpioIF* gpioComIF); +void createCcsdsComponents(LinuxLibgpioIF *gpioComIF); void createTestComponents(LinuxLibgpioIF* gpioComIF); }; diff --git a/common/config/ccsdsConfig.h b/common/config/ccsdsConfig.h new file mode 100644 index 00000000..8466a9fa --- /dev/null +++ b/common/config/ccsdsConfig.h @@ -0,0 +1,15 @@ +#ifndef COMMON_CONFIG_CCSDSCONFIG_H_ +#define COMMON_CONFIG_CCSDSCONFIG_H_ + +namespace ccsds { +enum { + VC0, + VC1, + VC2, + VC3 +}; +} + + + +#endif /* COMMON_CONFIG_CCSDSCONFIG_H_ */ diff --git a/common/config/commonObjects.h b/common/config/commonObjects.h index 0a66cd9a..43cd396c 100644 --- a/common/config/commonObjects.h +++ b/common/config/commonObjects.h @@ -13,9 +13,10 @@ enum commonObjects: uint32_t { FILE_SYSTEM_HANDLER = 0x50000500, PTME = 0x50000600, PAPB_VC0 = 0x50000700, - PAPB_VC1 = 0x500007001, - PAPB_VC2 = 0x500007002, - PAPB_VC3 = 0x500007003, + PAPB_VC1 = 0x50000701, + PAPB_VC2 = 0x50000702, + PAPB_VC3 = 0x50000703, + CCSDS_HANDLER = 0x50000800, /* 0x43 ('C') for Controllers */ THERMAL_CONTROLLER = 0x43400001, diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index f3d3fad6..afaed4a5 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -123,7 +123,12 @@ namespace config { /* Add mission configuration flags here */ static constexpr uint32_t OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE = 50; static constexpr uint32_t PLOC_UPDATER_QUEUE_SIZE = 50; +static constexpr uint32_t CCSDS_HANDLER_QUEUE_SIZE = 50; static constexpr uint8_t NUMBER_OF_VIRTUAL_CHANNELS = 4; +static constexpr uint8_t VC0_QUEUE_SIZE = 50; +static constexpr uint8_t VC1_QUEUE_SIZE = 50; +static constexpr uint8_t VC2_QUEUE_SIZE = 50; +static constexpr uint8_t VC3_QUEUE_SIZE = 50; #ifdef __cplusplus } diff --git a/linux/obc/PapbVcInterface.cpp b/linux/obc/PapbVcInterface.cpp index 0c3c759a..6cbd81a3 100644 --- a/linux/obc/PapbVcInterface.cpp +++ b/linux/obc/PapbVcInterface.cpp @@ -3,7 +3,7 @@ PapbVcInterface::PapbVcInterface(object_id_t objectId, LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId, gpioId_t papbEmptyId, uint32_t vcOffset) : - SystemObject(objectId), gpioComIF(gpioComIF), uioVcInterface(uioVcInterface), papbBusyId( + SystemObject(objectId), gpioComIF(gpioComIF), papbBusyId( papbBusyId), papbEmptyId(papbEmptyId), vcOffset(vcOffset) { } @@ -15,19 +15,19 @@ void PapbVcInterface::setRegisterAddress(uint32_t* ptmeBaseAddress) { vcBaseReg = ptmeBaseAddress + vcOffset; } -ReturnValue_t PapbVcInterface::write(const uint8_t * data, size_t dataLen) { +ReturnValue_t PapbVcInterface::write(const uint8_t * data, size_t size) { if(pollPapbBusySignal() == RETURN_OK) { startPacketTransfer(); } - for(size_t idx = 0; idx < dataLen; idx++) { + for(size_t idx = 0; idx < size; idx++) { if(pollPapbBusySignal() == RETURN_OK) { *(vcBaseReg + DATA_REG_OFFSET) = static_cast(*(data + idx)); } else { sif::warning << "PapbVcInterface::sendTm: Only written " << idx - 1 << " of " - << dataLen << " data" << std::endl; + << size << " data" << std::endl; return RETURN_FAILED; } } @@ -95,7 +95,7 @@ ReturnValue_t PapbVcInterface::sendTestFrame() { testPacket[idx] = static_cast(idx & 0xFF); } - ReturnValue_t result = sendTm(testPacket, 1105); + ReturnValue_t result = write(testPacket, 1105); if(result != RETURN_OK) { return result; } diff --git a/linux/obc/PapbVcInterface.h b/linux/obc/PapbVcInterface.h index 05947ac6..937f4280 100644 --- a/linux/obc/PapbVcInterface.h +++ b/linux/obc/PapbVcInterface.h @@ -5,8 +5,8 @@ #include "linux/obc/VcInterfaceIF.h" #include #include -#include #include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/objectmanager/ObjectManager.h" /** * @brief This class handles the transmission of data to a virtual channel of the PTME IP Core @@ -14,7 +14,9 @@ * * @author J. Meier */ -class PapbVcInterface : VcInterfaceIF, HasReturnvaluesIF { +class PapbVcInterface: public SystemObject, + public VcInterfaceIF, + public HasReturnvaluesIF { public: /** * @brief Constructor @@ -31,6 +33,10 @@ public: gpioId_t papbEmptyId, uint32_t vcOffset); virtual ~PapbVcInterface(); + ReturnValue_t write(const uint8_t* data, size_t size) override; + + void setRegisterAddress(uint32_t* ptmeBaseAddress) override; + private: static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_IP_CORE_BRIDGE; diff --git a/linux/obc/Ptme.cpp b/linux/obc/Ptme.cpp index 480b5836..80f9945c 100644 --- a/linux/obc/Ptme.cpp +++ b/linux/obc/Ptme.cpp @@ -3,6 +3,7 @@ #include #include "fsfw/serviceinterface/ServiceInterface.h" +#include "PtmeConfig.h" Ptme::Ptme(object_id_t objectId) : SystemObject(objectId) { @@ -12,9 +13,8 @@ Ptme::~Ptme() { } ReturnValue_t Ptme::initialize() { - ReturnValue_t result = TmTcBridge::initialize(); - fd = open(PtmeConfig::UIO_DEVICE_FILE, O_RDWR); + int fd = open(PtmeConfig::UIO_DEVICE_FILE, O_RDWR); if (fd < 1) { sif::warning << "Ptme::initialize: Invalid UIO device file" << std::endl; return RETURN_FAILED; @@ -32,10 +32,15 @@ ReturnValue_t Ptme::initialize() { return RETURN_FAILED; } - return result; + VcInterfaceMapIter iter; + for (iter = vcInterfaceMap.begin(); iter != vcInterfaceMap.end(); iter++) { + iter->second->setRegisterAddress(ptmeBaseAddress); + } + + return RETURN_OK; } -ReturnValue_t Ptme::writeToVc(uint8_t vcId, const uint8_t * data, size_t dataLen) { +ReturnValue_t Ptme::writeToVc(uint8_t vcId, const uint8_t * data, size_t size) { ReturnValue_t result = RETURN_OK; VcInterfaceMapIter vcInterfaceMapIter = vcInterfaceMap.find(vcId); if (vcInterfaceMapIter == vcInterfaceMap.end()) { @@ -43,13 +48,13 @@ ReturnValue_t Ptme::writeToVc(uint8_t vcId, const uint8_t * data, size_t dataLen "channel with id " << static_cast(vcId) << std::endl; return UNKNOWN_VC_ID; } - result = vcInterfaceMapIter->second.write(data, size); + result = vcInterfaceMapIter->second->write(data, size); return result; } void Ptme::addVcInterface(VcId_t vcId, VcInterfaceIF* vc) { - if (vcId > config::MAX_VIRTUAL_CHANNEL_ID) { + if (vcId > config::NUMBER_OF_VIRTUAL_CHANNELS) { sif::warning << "Ptme::addVcInterface: Invalid virtual channel ID" << std::endl; return; } diff --git a/linux/obc/Ptme.h b/linux/obc/Ptme.h index 6ef118ab..aa131d9e 100644 --- a/linux/obc/Ptme.h +++ b/linux/obc/Ptme.h @@ -18,8 +18,13 @@ * The IP cores are implemented on the programmable logic and are accessible through the * linux UIO driver. */ -class Ptme : PtmeIF, SystemObject, HasReturnvaluesIF { +class Ptme : public PtmeIF, + public SystemObject, + public HasReturnvaluesIF { public: + + using VcId_t = uint8_t; + /** * @brief Constructor * @@ -29,7 +34,7 @@ public: virtual ~Ptme(); ReturnValue_t initialize() override; - ReturnValue_t writeToVc(uint8_t vcId, uint8_t* data, size_t size) override; + ReturnValue_t writeToVc(uint8_t vcId, const uint8_t* data, size_t size) override; /** * @brief This function adds the reference to a virtual channel interface to the vcInterface @@ -73,8 +78,6 @@ private: uint32_t* ptmeBaseAddress = nullptr; - using VcId_t = uint8_t; - using VcInterfaceMap = std::unordered_map; using VcInterfaceMapIter = VcInterfaceMap::iterator; diff --git a/linux/obc/PtmeConfig.h b/linux/obc/PtmeConfig.h index 34fd8876..f4468570 100644 --- a/linux/obc/PtmeConfig.h +++ b/linux/obc/PtmeConfig.h @@ -20,7 +20,7 @@ namespace PtmeConfig { static const uint32_t VC2_OFFSETT = 0x8000; static const uint32_t VC3_OFFSETT = 0xC000; - static const std::string UIO_DEVICE_FILE = "/dev/uio0"; + static const char UIO_DEVICE_FILE[] = "/dev/uio0"; }; #endif /* LINUX_OBC_PTMECONFIG_H_ */ diff --git a/linux/obc/PtmeIF.h b/linux/obc/PtmeIF.h index c89d25f0..53d9498b 100644 --- a/linux/obc/PtmeIF.h +++ b/linux/obc/PtmeIF.h @@ -22,7 +22,7 @@ public: * @param data Pointer to buffer holding the data to write * @param size Number of bytes to write */ - virtual ReturnValue_t writeToVc(uint8_t vcId, uint8_t* data, size_t size) = 0; + virtual ReturnValue_t writeToVc(uint8_t vcId, const uint8_t* data, size_t size) = 0; }; #endif /* LINUX_OBC_PTMEIF_H_ */ diff --git a/linux/obc/VcInterfaceIF.h b/linux/obc/VcInterfaceIF.h index ce643b48..28b8d1f1 100644 --- a/linux/obc/VcInterfaceIF.h +++ b/linux/obc/VcInterfaceIF.h @@ -1,6 +1,7 @@ #ifndef LINUX_OBC_VCINTERFACEIF_H_ #define LINUX_OBC_VCINTERFACEIF_H_ +#include #include "fsfw/returnvalues/HasReturnvaluesIF.h" /** @@ -20,7 +21,9 @@ public: * @param data Pointer to buffer holding the data to write * @param size Number of bytes to write */ - virtual ReturnValue_t write(uint8_t* data, size_t size) = 0; + virtual ReturnValue_t write(const uint8_t* data, size_t size) = 0; + + virtual void setRegisterAddress(uint32_t* ptmeBaseAddress) = 0; }; #endif /* LINUX_OBC_VCINTERFACEIF_H_ */ diff --git a/mission/CMakeLists.txt b/mission/CMakeLists.txt index 46f562a5..876201a8 100644 --- a/mission/CMakeLists.txt +++ b/mission/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(core) add_subdirectory(devices) add_subdirectory(utility) add_subdirectory(memory) +add_subdirectory(tmtc) diff --git a/mission/tmtc/CCSDSHandler.cpp b/mission/tmtc/CCSDSHandler.cpp index b17af452..2a337d68 100644 --- a/mission/tmtc/CCSDSHandler.cpp +++ b/mission/tmtc/CCSDSHandler.cpp @@ -1,133 +1,29 @@ -#include -#include -#include -#include -#include -#include -#include -#include +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/serviceinterface/serviceInterfaceDefintions.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/ipc/QueueFactory.h" -const float CCSDSHandler::DEFAULT_RATES[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD] = - { CCSDSHandler::DEFAULT_BYTES_PER_SECOND, CCSDSHandler::DEFAULT_BYTES_PER_SECOND, - CCSDSHandler::DEFAULT_BYTES_PER_SECOND, CCSDSHandler::DEFAULT_BYTES_PER_SECOND }; +#include "CCSDSHandler.h" -CCSDSHandler::CCSDSHandler(object_id_t setObjectId, uint8_t setSwitchId1, - uint8_t setSwitchId2, object_id_t setChannel, uint16_t setSCID, - BoardHandler::DataPoolIds setPool) : - SystemObject(setObjectId), tmPartHealth(setObjectId + 1, 0), commandQueue(), state( - STATE_IDLE), commState(SEND_WRITE), mode(MODE_OFF), submode( - SUBMODE_NONE), boardHandler((uint8_t*) frameBuffer, - sizeof(frameBuffer), setSCID, setPool), dataLinkLayer( - this->frameBuffer, boardHandler.getClcw(), 0, setSCID), frameLength( - 0), channelId(setChannel), memoryHelper(this, &commandQueue), pendingWrite( - false), pendingRead(false), modeHelper(this), healthHelper(this, - setObjectId), parameterHelper(this), powerSwitcher(setSwitchId1, - setSwitchId2), switchOffWasReported(false), fdir(setObjectId, - setChannel) { - memset(this->frameBuffer, 0, sizeof(frameBuffer)); - DataSet mySet; - PoolVector rateRatio( - datapool::DATA_RATE_ASSIGN, &mySet, PoolVariableIF::VAR_WRITE); - for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; - ++i) { - virtualChannels[i] = new VCGeneration(i, - BoardHandler::TM_PACKETS_PER_CALL_PER_CHANNEL); - rateLimitOverload[i] = 0; - rateRatio[i] = DEFAULT_RATES[i]; - } - mySet.commit(PoolVariableIF::VALID); - //Set real-time channel to high responsiveness. - virtualChannels[0]->setIdlePacketIntervalMs( - VCGeneration::IDLE_INTERVAL_RT_CHANNEL); +CCSDSHandler::CCSDSHandler(object_id_t objectId, object_id_t ptmeId) : + SystemObject(objectId), ptmeId(ptmeId), parameterHelper(this) { + commandQueue = QueueFactory::instance()->createMessageQueue(QUEUE_SIZE); } CCSDSHandler::~CCSDSHandler() { - for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; - ++i) { - delete virtualChannels[i]; - } } -void CCSDSHandler::printFrameBuffer(void) { - debug << "frame_buffer contains: " << std::endl; - for (uint32_t i = 0; i < this->frameLength; ++i) { - debug << "frame_buffer[" << std::dec << i << "]: " << std::hex - << std::showbase << (uint16_t) this->frameBuffer[i] << std::dec - << std::endl; - } -} - -ReturnValue_t CCSDSHandler::packetProcessing(void) { - rateSet.read(); - const float* usedRateRatios = NULL; - if (rateSet.dataRates.isValid()) { - usedRateRatios = rateSet.dataRates.value; - } else { - usedRateRatios = DEFAULT_RATES; - } - for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; - ++i) { - //Set current cycle Limit first - uint32_t newLimit = (usedRateRatios[i]) / SENDS_PER_SECOND; - if (newLimit <= rateLimitOverload[i]) { - //Calculate new overload. - rateLimitOverload[i] -= newLimit; - //Use newLimit as current rate, VC is utilized to its current limit. - rateSet.dataRate[i] = usedRateRatios[i]; //equal to newLimit * SENDS_PER_SECOND - //Don't send anything new. - continue; - } - newLimit -= rateLimitOverload[i]; - virtualChannels[i]->tmSendLimitPerCycle = newLimit; - //Send new packets. - uint32_t tempRate = virtualChannels[i]->packetProcessing(); - if (tempRate > virtualChannels[i]->tmSendLimitPerCycle) { - rateLimitOverload[i] = tempRate - virtualChannels[i]->tmSendLimitPerCycle; - //VC is fully utilized, but not more. Overload will be accounted for in next cycles. - rateSet.dataRate[i] = virtualChannels[i]->tmSendLimitPerCycle * SENDS_PER_SECOND; - } else { - //Data rate extended to a Bytes/s range. Filtering is performed in controller. - rateSet.dataRate[i] = tempRate * SENDS_PER_SECOND; - rateLimitOverload[i] = 0; - } - } - rateSet.commit(PoolVariableIF::VALID); - return RETURN_OK; -} - -ReturnValue_t CCSDSHandler::packetProcessingCheck(void) { - ReturnValue_t status = RETURN_FAILED; - for (uint8_t vc = 0; vc < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; - ++vc) { - status = this->virtualChannels[vc]->packetProcessingCheck(); - if (status != RETURN_OK) { - error << "CCSDSHandler " << std::hex << this->getObjectId() - << " ::packetProcessingCheck: Error on VC " << (uint16_t) vc - << ". Error code: " << status << std::dec << std::endl; - } - } - return RETURN_OK; -} - -ReturnValue_t CCSDSHandler::performOperation(void) { +ReturnValue_t CCSDSHandler::performOperation(uint8_t operationCode) { readCommandQueue(); handleTelemetry(); handleTelecommands(); return RETURN_OK; } -void CCSDSHandler::addVirtualChannel(VcId_t virtualChannelId, VirtualChannel* virtualChannel) { - auto status = virtualChannelMap.emplace(virtualChannelId, virtualChannel); - if (status.second == false) { - sif::warning << "CCSDSHandler::addVcInterface: Failed to add virtual channel with virtual " - << "channel id " << static_cast(virtualChannelId) << std::endl; - } -} - void CCSDSHandler::handleTelemetry() { VirtualChannelMapIter iter; - for (iter = virtualChannelMap.begin(); iter != VirtualChannelMap.end(); iter++) { - iter->second.virtualChannel->performOperation(); + for (iter = virtualChannelMap.begin(); iter != virtualChannelMap.end(); iter++) { + iter->second->performOperation(); } } @@ -135,374 +31,78 @@ void CCSDSHandler::handleTelecommands() { } -void CCSDSHandler::searchFrame() { - frameLength = this->boardHandler.findFrame(); - while (frameLength != 0) { - ReturnValue_t frame_status = this->dataLinkLayer.processFrame( - frameLength); - if (frame_status != RETURN_OK) { - triggerEvent(DataLinkLayer::FRAME_PROCESSING_FAILED, frame_status, - 0); - } - boardHandler.resetFrameBuffer(); - frameLength = boardHandler.findFrame(); - } -} - ReturnValue_t CCSDSHandler::initialize() { - PtmeIF *ptme = objectManager->get(ptmeId); + ReturnValue_t result = RETURN_OK; + PtmeIF* ptme = ObjectManager::instance()->get(ptmeId); if (ptme == nullptr) { + sif::warning << "Invalid PTME object" << std::endl; return ObjectManagerIF::CHILD_INIT_FAILED; } - status = boardHandler.initialize(channel); - if (status != RETURN_OK) { - return status; + + result = parameterHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; } - status = modeHelper.initialize(); - if (status != RETURN_OK) { - return status; - } - status = healthHelper.initialize(); - if (status != HasReturnvaluesIF::RETURN_OK) { - return status; - } - status = memoryHelper.initialize(); - if (status != HasReturnvaluesIF::RETURN_OK) { - return status; - } - status = parameterHelper.initialize(); - if (status != HasReturnvaluesIF::RETURN_OK) { - return status; - } - status = powerSwitcher.initialize(objects::PCDU_HANDLER); - if (status != HasReturnvaluesIF::RETURN_OK) { - return status; - } - StorageManagerIF* tmStore = objectManager->get( - objects::TM_STORE); - status = dataLinkLayer.initialize(); - if ((tmStore != NULL) && status == RETURN_OK) { - status = RETURN_OK; - for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; - ++i) { -// this->virtualChannels[i] = objectManager->get( -// objects::CCSDS_VC_BASE + i); - if (this->virtualChannels[i] != NULL) { - this->virtualChannels[i]->setPacketStore(tmStore); - this->virtualChannels[i]->setBoardHandler(&this->boardHandler); - } else { - status = RETURN_FAILED; - } - } - } else { - status = RETURN_FAILED; - error << "CCSDSHandler " << std::hex << this->getObjectId() << std::dec - << " ::CCSDSHandler: Configuration failed." << std::endl; - } - status = fdir.initialize(); - if (status != HasReturnvaluesIF::RETURN_OK) { - return status; - } - return status; + return result; } void CCSDSHandler::readCommandQueue(void) { CommandMessage commandMessage; ReturnValue_t result = RETURN_FAILED; - result = commandQueue.receiveMessage(&commandMessage); + result = commandQueue->receiveMessage(&commandMessage); if (result == RETURN_OK) { result = parameterHelper.handleParameterMessage(&commandMessage); if (result == RETURN_OK) { return; } CommandMessage reply; - reply.setReplyRejected(CommandMessage::UNKNOW_COMMAND, + reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, commandMessage.getCommand()); - commandQueue.reply(&reply); + commandQueue->reply(&reply); } } MessageQueueId_t CCSDSHandler::getCommandQueue() const { - return commandQueue.getId(); + return commandQueue->getId(); } -void CCSDSHandler::flushTmChannels() { - for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD; - ++i) { - virtualChannels[i]->flush(); - } -} +void CCSDSHandler::addVirtualChannel(VcId_t vcId, VirtualChannel* virtualChannel) { + if (vcId > config::NUMBER_OF_VIRTUAL_CHANNELS) { + sif::warning << "CCSDSHandler::addVirtualChannel: Invalid virtual channel ID" << std::endl; + return; + } -ReturnValue_t CCSDSHandler::handleMemoryLoad(uint32_t address, - const uint8_t* data, uint32_t size, uint8_t** dataPointer) { - if (size != 4) { - return INVALID_SIZE; - } - ReturnValue_t result = boardHandler.manualWriteToRegister(address, data); - if (result == RETURN_OK) { - pendingWrite = true; - return DO_IT_MYSELF; - } - return result; -} + if (virtualChannel == nullptr) { + sif::warning << "CCSDSHandler::addVirtualChannel: Invalid virtual channel interface" << std::endl; + return; + } -ReturnValue_t CCSDSHandler::handleMemoryDump(uint32_t address, uint32_t size, - uint8_t** dataPointer, uint8_t* dumpTarget) { - if (size != 4) { - return INVALID_SIZE; - } - ReturnValue_t result = boardHandler.sendRegisterReadCommand(address); - if (result == RETURN_OK) { - pendingRead = true; - return DO_IT_MYSELF; - } - return result; -} - -ReturnValue_t CCSDSHandler::checkModeCommand(Mode_t commandedMode, - Submode_t commandedSubmode, uint32_t* msToReachTheMode) { - if (state != STATE_IDLE) { - return IN_TRANSITION; - } - switch (commandedMode) { - case MODE_ON: - if ((commandedSubmode == SUBMODE_ACTIVE) - || (commandedSubmode == SUBMODE_PASSIVE)) { - return RETURN_OK; - } else { - return INVALID_SUBMODE; - } - break; - case MODE_OFF: - if (commandedSubmode == SUBMODE_NONE) { - return RETURN_OK; - } else { - return INVALID_SUBMODE; - } - default: - return INVALID_MODE; - } -} - -void CCSDSHandler::startTransition(Mode_t commandedMode, - Submode_t commandedSubmode) { - if (commandedMode == mode) { - if (mode == MODE_ON) { - state = STATE_SELECT_SUBMODE; - } else { - //Turn off switch again anyway - state = STATE_TURN_OFF; - } - } else { - switch (commandedMode) { - case MODE_ON: - state = STATE_TURN_ON; - break; - case MODE_OFF: - state = STATE_TURN_OFF; - break; - default: - //Error case. Cannot happen? - error << "CCSDSHandler::startTransition: Invalid commanded mode: " - << commandedMode << std::endl; - return; - } - } - triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); -} - -void CCSDSHandler::getMode(Mode_t* modeReturn, Submode_t* submodeReturn) { - *modeReturn = mode; - *submodeReturn = submode; -} - -void CCSDSHandler::setToExternalControl() { - healthHelper.setHealth(EXTERNAL_CONTROL); -} - -void CCSDSHandler::announceMode(bool recursive) { - triggerEvent(MODE_INFO, mode, submode); -} - -void CCSDSHandler::setParentQueue(MessageQueueId_t parentQueueId) { - modeHelper.setParentQueue(parentQueueId); - healthHelper.setParentQeueue(parentQueueId); - tmPartHealth.setParentQueue(parentQueueId); -} - -void CCSDSHandler::doStateMachine() { - ReturnValue_t status = RETURN_FAILED; - powerSwitcher.doStateMachine(); - switch (state) { - case STATE_IDLE: - //Do nothing? Do perform operation stuff? - break; - case STATE_TURN_ON: - powerSwitcher.turnOn(); - modeHelper.startTimer(powerSwitcher.getSwitchDelay()); - state = STATE_WAIT_ON; - break; - case STATE_WAIT_ON: - if (powerSwitcher.checkSwitchState() == RETURN_OK) { - modeHelper.startTimer(LINK_UP_DELAY_MS); - state = STATE_WAIT_LINK; - } - if (boardHandler.checkChannel() == RETURN_OK) { - boardHandler.startStateTranstion(); - state = STATE_INITIALIZE_BOARD; - } else { - if (modeHelper.isTimedOut()) { - triggerEvent(MODE_TRANSITION_FAILED, - PowerSwitchIF::SWITCH_TIMEOUT, state); - setMode(MODE_OFF, SUBMODE_NONE); - } - } - break; - case STATE_WAIT_LINK: - if (boardHandler.checkAndResetChannel() == RETURN_OK) { - boardHandler.startStateTranstion(); - state = STATE_INITIALIZE_BOARD; - } else { - if (modeHelper.isTimedOut()) { - triggerEvent(MODE_TRANSITION_FAILED, DeviceHandlerIF::TIMEOUT, - state); - setMode(MODE_OFF, SUBMODE_NONE); - } - } - break; - case STATE_INITIALIZE_BOARD: - status = boardHandler.initializeBoard(); - switch (status) { - case RETURN_OK: - state = STATE_SELECT_SUBMODE; - break; - case BoardHandler::IN_TRANSITION: - //cannot last forever, so just wait. - break; - default: - triggerEvent(MODE_TRANSITION_FAILED, status, state); - state = STATE_TURN_OFF; - break; - } - break; - case STATE_SELECT_SUBMODE: - boardHandler.startStateTranstion(); - if (modeHelper.commandedSubmode == SUBMODE_PASSIVE) { - state = STATE_WAIT_SUBMODE_PASSIVE; - } else { - state = STATE_WAIT_SUBMODE_ACTIVE; - } - break; - case STATE_WAIT_SUBMODE_PASSIVE: - //Just one wait cycle to get rid of pending TM. - state = STATE_DO_PASSIVATE; - break; - case STATE_DO_PASSIVATE: - status = boardHandler.tmPassivate(); - switch (status) { - case RETURN_OK: - setMode(MODE_ON, SUBMODE_PASSIVE); - break; - case BoardHandler::IN_TRANSITION: - //cannot last forever, so just wait. - break; - default: - //If it comes here and fails then, there might be something wrong with the board. - triggerEvent(MODE_TRANSITION_FAILED, status, state); - state = STATE_TURN_OFF; - break; - } - break; - case STATE_WAIT_SUBMODE_ACTIVE: - status = boardHandler.tmActivate(); - switch (status) { - case RETURN_OK: - setMode(MODE_ON, SUBMODE_ACTIVE); - break; - case BoardHandler::IN_TRANSITION: - //cannot last forever, so just wait. - break; - default: - //If it comes here and fails then, there might be something wrong with the board. - triggerEvent(MODE_TRANSITION_FAILED, status, state); - state = STATE_TURN_OFF; - break; - } - break; - case STATE_TURN_OFF: - //Passivate first. Mainly optimization for System Testbed. - boardHandler.startStateTranstion(); - state = STATE_DO_PASSIVATE_OFF; - //No break - case STATE_DO_PASSIVATE_OFF: - status = boardHandler.tmPassivate(); - switch (status) { - case RETURN_OK: - state = STATE_TURN_SWITCH_OFF; - break; - case BoardHandler::IN_TRANSITION: - //cannot last forever, so just wait. - break; - default: - //If it comes here and fails then, there might be something wrong with the board. - //Just turn it off. - state = STATE_TURN_SWITCH_OFF; - break; - } - break; - case STATE_TURN_SWITCH_OFF: - powerSwitcher.turnOff(); - modeHelper.startTimer(powerSwitcher.getSwitchDelay()); - state = STATE_WAIT_OFF; - break; - case STATE_WAIT_OFF: - if ((boardHandler.checkAndResetChannel() == RMAPChannelIF::LINK_DOWN) - || (powerSwitcher.checkSwitchState() == RETURN_OK)) { - setMode(MODE_OFF, SUBMODE_NONE); - state = STATE_IDLE; - } else { - if (modeHelper.isTimedOut()) { - triggerEvent(MODE_TRANSITION_FAILED, status, state); - setMode(mode, submode); - } - } - break; - default: - break; - } -} - -ReturnValue_t CCSDSHandler::addVirtualChannel(uint8_t virtualChannelId, - VirtualChannelReceptionIF* object) { - return this->dataLinkLayer.addVirtualChannel(virtualChannelId, object); -} - -void CCSDSHandler::setMode(Mode_t newMode, Submode_t newSubmode) { - triggerEvent(MODE_INFO, newMode, newSubmode); - if (newMode == MODE_OFF) { - boardHandler.setDataPoolVaraiblesInvalid(); - } - modeHelper.modeChanged(newMode, newSubmode); - state = STATE_IDLE; - mode = newMode; - submode = newSubmode; -} - -Mode_t CCSDSHandler::getMode() const { - return mode; -} - -Submode_t CCSDSHandler::getSubmode() const { - return submode; + 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 < config::NUMBER_OF_VIRTUAL_CHANNELS) { - return virtualChannels[virtualChannel]->getReportReceptionQueue(); + VirtualChannelMapIter iter = virtualChannelMap.find(virtualChannel); + if (iter != virtualChannelMap.end()) { + return iter->second->getReportReceptionQueue(); + } + else { + sif::warning << "CCSDSHandler::getReportReceptionQueue: Virtual channel with ID " + << static_cast(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, diff --git a/mission/tmtc/CCSDSHandler.h b/mission/tmtc/CCSDSHandler.h index 8780b4e8..05693a38 100644 --- a/mission/tmtc/CCSDSHandler.h +++ b/mission/tmtc/CCSDSHandler.h @@ -1,12 +1,13 @@ #ifndef CCSDSHANDLER_H_ #define CCSDSHANDLER_H_ -#include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/serviceinterface/serviceInterfaceDefintions.h" +#include "OBSWConfig.h" #include "fsfw/objectmanager/SystemObject.h" #include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" #include "fsfw/parameters/ParameterHelper.h" +#include "VirtualChannel.h" +#include /** * @brief This class handles the data exchange with the CCSDS IP cores implemented in the @@ -20,63 +21,20 @@ class CCSDSHandler: public SystemObject, public HasReturnvaluesIF, public ReceivesParameterMessagesIF { public: - static const uint32_t LINK_UP_DELAY_MS = 2000; //!< The maximum time it takes to reconfigure the CCSDS Board. - static const uint32_t MAX_FRAME_SIZE = 1024; - static const Submode_t SUBMODE_ACTIVE = 1; //!< Submode where the TM part of the board is on. - static const Submode_t SUBMODE_PASSIVE = 0; //!< Submode where the TM part of the board is off. - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CCSDS_BOARD; - static const Event CCSDS_BOARD_RESET_FAILED = MAKE_EVENT(0, SEVERITY::LOW); //!> Resetting the communication channel failed. Severity LOW, par1: returnCode, par2: 0 - static const Event CCSDS_BOARD_SWITCHED = MAKE_EVENT(1, SEVERITY::INFO); //!> Switched active CCSDS-Board. Par1: objectId of now active board, Par2: objectId of now passive board. + using VcId_t = uint8_t; - static const ActionId_t SET_DATA_RATE_RATIO = 1; - static const float SENDS_PER_SECOND = 2.5; - static const uint32_t MINIMUM_BYTES_PER_SECOND = - (VCGeneration::IDLE_PACKET_SIZE - / (VCGeneration::DEFAULT_IDLE_INTERVAL / 1000)) + 1; //!< +1 to be on the safe side. - static const float DEFAULT_RATES[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD]; - static const uint32_t DEFAULT_BYTES_PER_SECOND = 1300; + /** + * @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. + */ + CCSDSHandler(object_id_t objectId, object_id_t ptmeId); - HealthDevice tmPartHealth; //!< A helper device to dedicatetly set the telemetry part to not healthy. - /** - * Main Constructor of the class. - * Initializes all attributes with default values. Sets the frame buffer to zero. - * Creates all TM Virtual Channels (with \c new). Initialization of communication partners - * is done in the #initialize routine. - * @param setObjectId Object identifier of the class. - * @param setSwitchId1 Switch id of the first switch of the board. - * @param setSwitchId2 Switch id of the second switch of the board. - * @param set_channel RMAP channel identifier. This is forwarded to the #boardHandler class. - * @param set_scid Configured SpaceCraft Identifier. Is forwarded to #boardHandler and #dataLinkLayer class. - */ - CCSDSHandler(object_id_t setObjectId, uint8_t setSwitchId1, - uint8_t setSwitchId2, object_id_t setChannel, uint16_t setSCID, - BoardHandler::DataPoolIds setPool); - /** - * The destructor deletes all TM Virtual Channels. - */ ~CCSDSHandler(); - /** - * Main executing method of the CCSDS Board handling. - * The method coordinates reading and writing of buffers and registers on the CCSDS Board - * as well as checking communication states and looking for frames. The state machine is - * executed here as well. To ensure a smooth communication without much delay, the last read - * and write calls are checked in the beginning and new requests as well as the state machine - * are issued in the end. - * @return Always returns #RETURN_OK. - */ - ReturnValue_t performOperation(void); - ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data, - uint32_t size, uint8_t** dataPointer); - ReturnValue_t handleMemoryDump(uint32_t address, uint32_t size, - uint8_t** dataPointer, uint8_t* dumpTarget); - /** - * Initialization routine of the class. - * It initializes connections to the power unit and to the Telemetry store which is set for - * every TM Virtual Channel. - * @return - */ + ReturnValue_t performOperation(uint8_t operationCode = 0) override; ReturnValue_t initialize(); MessageQueueId_t getCommandQueue() const; @@ -85,74 +43,31 @@ public: * * @param virtualChannelId ID of the virtual channel to add * @param virtualChannel Pointer to virtual channel object - * - * @return RETURN_OK if successful, otherwise RETURN_FAILED */ void addVirtualChannel(VcId_t virtualChannelId, VirtualChannel* virtualChannel); - Mode_t getMode() const; - Submode_t getSubmode() const; - void setParentQueue(MessageQueueId_t parentQueueId); MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0); - ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex); -protected: - MessageQueue commandQueue; //!< Queue to receive control commands. - VCGeneration* virtualChannels[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD];//!< An array of VCGeneration classes which each manage on TM Virtual Channel. - uint32_t rateLimitOverload[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD];//!< Used to smooth data rate in case large packets are sent. - /** - * This method reads the command queue and initializes a state transition if a command of this type was found. - */ - void readCommandQueue(void); - - /** - * This method flushes all pending messages in the TM queue by calling the \c flush method of - * all #virtualChannels. - * This is necessary to avoid doubled TM packets if the TM sender issues its messages to both the - * nominal and redundant CCSDS Board. - */ - void flushTmChannels(); - /** - * This is a helper method to print the current content of the frame buffers. - */ - void printFrameBuffer(void); - /** - * This is an important method which triggers searching for and handling found frames. - * It first calls the boardHandler method to find a frame in the received data. If a - * well-formed frame was found it calls the #dataLinkLayer class to process the frame - */ - void searchFrame(); - /** - * Calls the packet processing routine of each TM Virtual Channel. - * This triggers reception of incoming packets from the OBSW and forwarding to the CCSDS Board. - * There are different sending strategies for forwarding the packets to the board. - * @return Returns #RETURN_OK or the status of the failed virtual channel method. - */ - ReturnValue_t packetProcessing(void); - /** - * With this method the successful forwarding of Telemetry to the TM Virtual Channels is checked. - * The method calls the check routine of each virtual channel. - * @return Returns #RETURN_OK or the status of the failed virtual channel method. - */ - ReturnValue_t packetProcessingCheck(void); - - ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode); - void startTransition(Mode_t mode, Submode_t submode); - void getMode(Mode_t *mode, Submode_t *submode); - void setToExternalControl(); - void announceMode(bool recursive); private: - using VcId_t = uint8_t; - using VirtualChannelMap = std::unordered_map; + static const uint32_t QUEUE_SIZE = config::CCSDS_HANDLER_QUEUE_SIZE; + + using VirtualChannelMap = std::unordered_map; using VirtualChannelMapIter = VirtualChannelMap::iterator; VirtualChannelMap virtualChannelMap; + // Object ID of PTME object + object_id_t ptmeId; + + MessageQueueIF* commandQueue = nullptr; + + ParameterHelper parameterHelper; + + void readCommandQueue(void); void handleTelemetry(); void handleTelecommands(); }; diff --git a/mission/tmtc/CMakeLists.txt b/mission/tmtc/CMakeLists.txt new file mode 100644 index 00000000..7da87b6c --- /dev/null +++ b/mission/tmtc/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${TARGET_NAME} PUBLIC + CCSDSHandler.cpp + VirtualChannel.cpp +) + + diff --git a/mission/tmtc/VirtualChannel.cpp b/mission/tmtc/VirtualChannel.cpp index 8e106de1..1f8f5ffb 100644 --- a/mission/tmtc/VirtualChannel.cpp +++ b/mission/tmtc/VirtualChannel.cpp @@ -1,13 +1,11 @@ #include "CCSDSHandler.h" +#include "VirtualChannel.h" #include "OBSWConfig.h" #include "fsfw/serviceinterface/ServiceInterfaceStream.h" #include "fsfw/objectmanager/ObjectManager.h" - - -#include - -#include +#include "fsfw/tmtcservices/TmTcMessage.h" +#include "fsfw/ipc/QueueFactory.h" VirtualChannel::VirtualChannel(uint8_t vcId, uint32_t tmQueueDepth) : @@ -22,10 +20,11 @@ ReturnValue_t VirtualChannel::initialize() { sif::error << "VirtualChannel::initialize: Failed to get tm store" << std::endl; return RETURN_FAILED; } + return RETURN_OK; } ReturnValue_t VirtualChannel::performOperation() { - ReturnValue_t status = RETURN_OK; + ReturnValue_t result = RETURN_OK; TmTcMessage message; while(tmQueue->receiveMessage(&message) == RETURN_OK) { @@ -41,7 +40,7 @@ ReturnValue_t VirtualChannel::performOperation() { } if (linkIsUp) { - result = ptme->writeToVc(virtualChannleId, data, size); + result = ptme->writeToVc(vcId, data, size); } tmStore->deleteData(storeId); @@ -54,7 +53,7 @@ ReturnValue_t VirtualChannel::performOperation() { } MessageQueueId_t VirtualChannel::getReportReceptionQueue(uint8_t virtualChannel) { - return tmQueue.getId(); + return tmQueue->getId(); } void VirtualChannel::setPtmeObject(PtmeIF* ptme) { @@ -64,17 +63,6 @@ void VirtualChannel::setPtmeObject(PtmeIF* ptme) { ptme = ptme; } -void VirtualChannel::setIdlePacketIntervalMs(uint32_t idlePacketIntervalMs) { - timer.timeout = idlePacketIntervalMs; -} - -ReturnValue_t VirtualChannel::flush() { - TmTcMessage message; - ReturnValue_t status = RETURN_FAILED; - for (status = tmQueue.receiveMessage(&message); status == RETURN_OK; - status = tmQueue.receiveMessage(&message)) { - packetStore->deleteData(message.getStorageId()); - } - boardHandler->resetVC(virtualChannelId); - return status; +void VirtualChannel::setLinkState(bool linkIsUp) { + linkIsUp = linkIsUp; } diff --git a/mission/tmtc/VirtualChannel.h b/mission/tmtc/VirtualChannel.h index cba4b0b4..d897e2d6 100644 --- a/mission/tmtc/VirtualChannel.h +++ b/mission/tmtc/VirtualChannel.h @@ -4,33 +4,16 @@ #include "fsfw/tmtcservices/AcceptsTelemetryIF.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include /** - * @brief This class represents a virtual channel in the software. + * @brief This class represents a virtual channel. Sending a tm message to an object of this class + * will forward the tm packet to the respective virtual channel of the PTME IP Core. * * @author J. Meier */ class VirtualChannel: public AcceptsTelemetryIF, public HasReturnvaluesIF { public: - - uint32_t tmSendLimitPerCycle; //!< Current maximum bytes per cycle. - - static const uint32_t IDLE_INTERVAL_RT_CHANNEL = 2000; //!< Real Time channel (VC 0) idle interval. - - static const uint16_t IDLE_PACKET_SIZE = 1015; //!< Size of generated idle packets. - - static const uint32_t DEFAULT_IDLE_INTERVAL = 20000; //!< Default if too lazy to set. - /** * @brief Constructor * @@ -40,28 +23,7 @@ class VirtualChannel: public AcceptsTelemetryIF, public HasReturnvaluesIF { VirtualChannel(uint8_t vcId, uint32_t tmQueueDepth); ReturnValue_t initialize(); - - /** - * One of the main public methods. - * Checks the tmQueue, calls #handlePacket if packets were found and keeps track of the number of sent bytes, - * to stop transmission before a buffer overflow occurs. If no packets were sent, an idle packet is generated. - * @return Number of sent bytes. 0 if an error occurred. - */ - uint32_t packetProcessing(void); - /** - * Another important method to check successful forwarding of packets. - * Checks how many packets have been forwarded to the CCSDS Board and tries to get as many - * RMAP write replys. The pending messages are deleted here. - * @return @c RETURN_OK on success, or one of many error codes, mainly coming from @c receiveVCAcknowledge. - */ - ReturnValue_t packetProcessingCheck(void); - /** - * Setter. - * @param setStore Sets the #packetStore used. - */ - void setPacketStore(StorageManagerIF* setStore); - MessageQueueId_t getReportReceptionQueue(); - + MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) override; ReturnValue_t performOperation(); /** @@ -69,42 +31,21 @@ class VirtualChannel: public AcceptsTelemetryIF, public HasReturnvaluesIF { * * @param ptme Pointer to ptme object */ - void setPtmeObject(Ptme* ptme); + void setPtmeObject(PtmeIF* ptme); + + /** + * @brief Can be used by the owner to set the link state. Packets will be discarded if link + * to ground station is down. + */ + void setLinkState(bool linkIsUp); private: PtmeIF* ptme = nullptr; MessageQueueIF* tmQueue = nullptr; - uint8_t virtualChannelId; + uint8_t vcId; bool linkIsUp; StorageManagerIF* tmStore = nullptr; - - - BoardHandler* boardHandler; //!< A reference to the "hardware part" of handling the packets. - store_address_t pendingTm[BoardHandler::TM_PACKETS_PER_CALL_PER_CHANNEL]; //!< List of packets sent to the board. Is used to check if all Space Packets sent received the CCSDS Board. - uint16_t sendCount; //!< Counter to identify how many packets have been sent coming in to the board (without Idle Packets). - Countdown timer; - SpacePacket idlePacket; - uint32_t accumulatedByteCount; - - store_address_t pendingPacket; - - static const uint32_t TM_SEND_LIMIT_PER_CYCLE = 1300; //!< The maximum number of bytes to send to the CCSDS Board VC per cycle. - - /** - * Helper method to send an idle packet. - * @return @c RETURN_OK on success, @c RETURN_FAILED otherwise. - */ - ReturnValue_t sendIdlePacket(uint32_t size); - /** - * A helper method to handle incoming packets. - * Reads a packet from #packetStore and tries to forward it to the CCSDS BoardHandler class. - * Calls the hardware layer with @c writeToVc. Depending on what the "hardware" layer does, - * it stores the sent packet id's to find out if they were all received by the CCSDS Board. - * @param store_id ID of a packet in the #packetStore. - * @return @c RETURN_OK on success, the return code of @c writeToVc otherwise. - */ - ReturnValue_t handlePacket(store_address_t storeId); }; #endif /* VIRTUALCHANNEL_H_ */ diff --git a/mission/utility/TmFunnel.cpp b/mission/utility/TmFunnel.cpp index d718f6cf..5838ae75 100644 --- a/mission/utility/TmFunnel.cpp +++ b/mission/utility/TmFunnel.cpp @@ -99,12 +99,12 @@ ReturnValue_t TmFunnel::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } -#if OBSW_USE_PTME_IP_CORE == 1 +#if OBSW_TM_TO_PTME == 1 // Live TM will be sent via the virtual channel 0 tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue(0)); #else tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue()); -#endif /* OBSW_USE_CCSDS_IP_CORES == 1 */ +#endif /* OBSW_TM_TO_PTME == 1 */ // Storage destination is optional. if(storageDestination == objects::NO_OBJECT) { From 55d31d0dc259df379aa53738bb82f017ee48082b Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Wed, 29 Sep 2021 14:47:20 +0200 Subject: [PATCH 04/10] ccsds handler --- bsp_q7s/core/InitMission.cpp | 8 ++++++++ bsp_q7s/core/ObjectFactory.cpp | 4 ++-- linux/fsfwconfig/OBSWConfig.h.in | 1 + linux/obc/PapbVcInterface.cpp | 2 +- linux/obc/Ptme.h | 6 +++++- mission/tmtc/CCSDSHandler.cpp | 10 ++++++++++ mission/tmtc/VirtualChannel.cpp | 7 ++++--- mission/tmtc/VirtualChannel.h | 11 +++++++++-- tmtc | 2 +- 9 files changed, 41 insertions(+), 10 deletions(-) diff --git a/bsp_q7s/core/InitMission.cpp b/bsp_q7s/core/InitMission.cpp index e7d8779b..06cf5ca9 100644 --- a/bsp_q7s/core/InitMission.cpp +++ b/bsp_q7s/core/InitMission.cpp @@ -96,6 +96,13 @@ void initmission::initTasks() { initmission::printAddObjectError("UDP_POLLING", objects::TMTC_POLLING_TASK); } + PeriodicTaskIF* ccsdsHandlerTask = factory->createPeriodicTask( + "UDP_POLLING", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc); + result = ccsdsHandlerTask->addComponent(objects::CCSDS_HANDLER); + if(result != HasReturnvaluesIF::RETURN_OK) { + initmission::printAddObjectError("CCSDS Handler", objects::CCSDS_HANDLER); + } + # if BOARD_TE0720 == 0 // FS task, task interval does not matter because it runs in permanent loop, priority low // because it is a non-essential background task @@ -141,6 +148,7 @@ void initmission::initTasks() { tmTcDistributor->startTask(); tmtcBridgeTask->startTask(); tmtcPollingTask->startTask(); + ccsdsHandlerTask->startTask(); #if BOARD_TE0720 == 0 coreController->startTask(); #endif diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 86709292..c36d05e1 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -948,9 +948,9 @@ void ObjectFactory::createCcsdsComponents(LinuxLibgpioIF *gpioComIF) { ccsdsHandler->addVirtualChannel(ccsds::VC0, vc); vc = new VirtualChannel(ccsds::VC1, config::VC1_QUEUE_SIZE); ccsdsHandler->addVirtualChannel(ccsds::VC1, vc); - vc = new VirtualChannel(2, config::VC2_QUEUE_SIZE); + vc = new VirtualChannel(ccsds::VC2, config::VC2_QUEUE_SIZE); ccsdsHandler->addVirtualChannel(ccsds::VC2, vc); - vc = new VirtualChannel(3, config::VC3_QUEUE_SIZE); + vc = new VirtualChannel(ccsds::VC3, config::VC3_QUEUE_SIZE); ccsdsHandler->addVirtualChannel(ccsds::VC3, vc); } diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index afaed4a5..d54ab39a 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -86,6 +86,7 @@ debugging. */ #define OBSW_TEST_TE7020_HEATER 0 #define OBSW_TEST_GPIO_OPEN_BY_LABEL 0 #define OBSW_TEST_GPIO_OPEN_BY_LINE_NAME 0 +#define OBSW_LINK_IS_UP 0 #define OBSW_DEBUG_P60DOCK 0 #define OBSW_DEBUG_PDU1 0 diff --git a/linux/obc/PapbVcInterface.cpp b/linux/obc/PapbVcInterface.cpp index 6cbd81a3..5bb72066 100644 --- a/linux/obc/PapbVcInterface.cpp +++ b/linux/obc/PapbVcInterface.cpp @@ -26,7 +26,7 @@ ReturnValue_t PapbVcInterface::write(const uint8_t * data, size_t size) { *(vcBaseReg + DATA_REG_OFFSET) = static_cast(*(data + idx)); } else { - sif::warning << "PapbVcInterface::sendTm: Only written " << idx - 1 << " of " + sif::warning << "PapbVcInterface::write: Only written " << idx << " of " << size << " data" << std::endl; return RETURN_FAILED; } diff --git a/linux/obc/Ptme.h b/linux/obc/Ptme.h index aa131d9e..753cc08f 100644 --- a/linux/obc/Ptme.h +++ b/linux/obc/Ptme.h @@ -48,9 +48,13 @@ private: static const ReturnValue_t UNKNOWN_VC_ID = MAKE_RETURN_CODE(0xA0); - +#if BOARD_TE0720 == 1 + /** Size of mapped address space */ + static const int MAP_SIZE = 0x1000; +#else /** Size of mapped address space */ static const int MAP_SIZE = 0x40000; +#endif /* BOARD_TE0720 == 1 */ /** * Configuration bits: diff --git a/mission/tmtc/CCSDSHandler.cpp b/mission/tmtc/CCSDSHandler.cpp index 2a337d68..95d557ee 100644 --- a/mission/tmtc/CCSDSHandler.cpp +++ b/mission/tmtc/CCSDSHandler.cpp @@ -43,6 +43,16 @@ ReturnValue_t CCSDSHandler::initialize() { if (result != HasReturnvaluesIF::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); + } + return result; } diff --git a/mission/tmtc/VirtualChannel.cpp b/mission/tmtc/VirtualChannel.cpp index 1f8f5ffb..3423692b 100644 --- a/mission/tmtc/VirtualChannel.cpp +++ b/mission/tmtc/VirtualChannel.cpp @@ -56,11 +56,12 @@ MessageQueueId_t VirtualChannel::getReportReceptionQueue(uint8_t virtualChannel) return tmQueue->getId(); } -void VirtualChannel::setPtmeObject(PtmeIF* ptme) { - if (ptme == nullptr) { +void VirtualChannel::setPtmeObject(PtmeIF* ptme_) { + if (ptme_ == nullptr) { sif::warning << "VirtualChannel::setPtmeObject: Invalid ptme object" << std::endl; + return; } - ptme = ptme; + ptme = ptme_; } void VirtualChannel::setLinkState(bool linkIsUp) { diff --git a/mission/tmtc/VirtualChannel.h b/mission/tmtc/VirtualChannel.h index d897e2d6..d7d95cb7 100644 --- a/mission/tmtc/VirtualChannel.h +++ b/mission/tmtc/VirtualChannel.h @@ -1,6 +1,7 @@ #ifndef VIRTUALCHANNEL_H_ #define VIRTUALCHANNEL_H_ +#include "OBSWConfig.h" #include "fsfw/tmtcservices/AcceptsTelemetryIF.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" #include @@ -31,7 +32,7 @@ class VirtualChannel: public AcceptsTelemetryIF, public HasReturnvaluesIF { * * @param ptme Pointer to ptme object */ - void setPtmeObject(PtmeIF* ptme); + void setPtmeObject(PtmeIF* ptme_); /** * @brief Can be used by the owner to set the link state. Packets will be discarded if link @@ -44,7 +45,13 @@ private: PtmeIF* ptme = nullptr; MessageQueueIF* tmQueue = nullptr; uint8_t vcId; - bool linkIsUp; + +#if OBSW_LINK_IS_UP == 1 + bool linkIsUp = true; +#else + bool linkIsUp = false; +#endif /* OBSW_LINK_IS_UP == 1 */ + StorageManagerIF* tmStore = nullptr; }; diff --git a/tmtc b/tmtc index 53bf6508..bad6a42a 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 53bf65083889af10f77c3899972b1153ea835f3c +Subproject commit bad6a42af715f62ddc2a593a5f1ce344fde96da7 From 3ca18a42adeac8721f8f1c312dba2de5c9fd801b Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Thu, 30 Sep 2021 09:34:01 +0200 Subject: [PATCH 05/10] live tm variable --- linux/fsfwconfig/OBSWConfig.h.in | 2 ++ linux/obc/Ptme.h | 2 +- mission/utility/TmFunnel.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index d54ab39a..a714e850 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -131,6 +131,8 @@ static constexpr uint8_t VC1_QUEUE_SIZE = 50; static constexpr uint8_t VC2_QUEUE_SIZE = 50; static constexpr uint8_t VC3_QUEUE_SIZE = 50; +static constexpr uint8_t LIVE_TM = 0; + #ifdef __cplusplus } #endif diff --git a/linux/obc/Ptme.h b/linux/obc/Ptme.h index 753cc08f..be687e17 100644 --- a/linux/obc/Ptme.h +++ b/linux/obc/Ptme.h @@ -50,7 +50,7 @@ private: #if BOARD_TE0720 == 1 /** Size of mapped address space */ - static const int MAP_SIZE = 0x1000; + static const int MAP_SIZE = 0x40000; #else /** Size of mapped address space */ static const int MAP_SIZE = 0x40000; diff --git a/mission/utility/TmFunnel.cpp b/mission/utility/TmFunnel.cpp index 5838ae75..4b9eebdf 100644 --- a/mission/utility/TmFunnel.cpp +++ b/mission/utility/TmFunnel.cpp @@ -101,7 +101,7 @@ ReturnValue_t TmFunnel::initialize() { #if OBSW_TM_TO_PTME == 1 // Live TM will be sent via the virtual channel 0 - tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue(0)); + tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue(config::LIVE_TM)); #else tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue()); #endif /* OBSW_TM_TO_PTME == 1 */ From 7ae02d43a7759ad71f83f92fc2ec5274ea5021a1 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Mon, 4 Oct 2021 14:47:32 +0200 Subject: [PATCH 06/10] added preprocessor defines to exclude CCSDS Handler --- bsp_q7s/core/InitMission.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bsp_q7s/core/InitMission.cpp b/bsp_q7s/core/InitMission.cpp index 06cf5ca9..e6e1e48f 100644 --- a/bsp_q7s/core/InitMission.cpp +++ b/bsp_q7s/core/InitMission.cpp @@ -96,12 +96,14 @@ void initmission::initTasks() { initmission::printAddObjectError("UDP_POLLING", objects::TMTC_POLLING_TASK); } +#if OBSW_USE_CCSDS_IP_CORE == 1 PeriodicTaskIF* ccsdsHandlerTask = factory->createPeriodicTask( "UDP_POLLING", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc); result = ccsdsHandlerTask->addComponent(objects::CCSDS_HANDLER); if(result != HasReturnvaluesIF::RETURN_OK) { initmission::printAddObjectError("CCSDS Handler", objects::CCSDS_HANDLER); } +#endif /* OBSW_USE_CCSDS_IP_CORE == 1 */ # if BOARD_TE0720 == 0 // FS task, task interval does not matter because it runs in permanent loop, priority low @@ -148,7 +150,11 @@ void initmission::initTasks() { tmTcDistributor->startTask(); tmtcBridgeTask->startTask(); tmtcPollingTask->startTask(); + +#if OBSW_USE_CCSDS_IP_CORE == 1 ccsdsHandlerTask->startTask(); +#endif /* OBSW_USE_CCSDS_IP_CORE == 1 */ + #if BOARD_TE0720 == 0 coreController->startTask(); #endif From 1463bcae5242707d1de7777dfd5a2031a1f1e132 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Thu, 7 Oct 2021 10:14:35 +0200 Subject: [PATCH 07/10] update fsfw and tmtc --- fsfw | 2 +- tmtc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fsfw b/fsfw index a84c770d..2844c512 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit a84c770dfb8447325c263da42d5cecd99b38d1f0 +Subproject commit 2844c512b69a2a0089ee4b0f4fd57a75a42a3cb3 diff --git a/tmtc b/tmtc index bad6a42a..1a176582 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit bad6a42af715f62ddc2a593a5f1ce344fde96da7 +Subproject commit 1a176582883aed989870819e5e57e0ce0a78ecda From 18f7d3e3c96686d4581acfd384883031d4c7321a Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Thu, 7 Oct 2021 17:23:41 +0200 Subject: [PATCH 08/10] tm now sent over PTME --- common/config/commonConfig.h.in | 2 +- linux/fsfwconfig/OBSWConfig.h.in | 2 +- scripts/q7s-port.sh | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/config/commonConfig.h.in b/common/config/commonConfig.h.in index c089c575..88e25877 100644 --- a/common/config/commonConfig.h.in +++ b/common/config/commonConfig.h.in @@ -10,7 +10,7 @@ // CCSDS IP Cores. #define OBSW_USE_CCSDS_IP_CORE 1 // Set to 1 if all telemetry should be sent to the PTME IP Core -#define OBSW_TM_TO_PTME 0 +#define OBSW_TM_TO_PTME 1 // Set to 1 if telecommands are received via the PDEC IP Core #define OBSW_TC_FROM_PDEC 0 diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index a714e850..924026af 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -86,7 +86,7 @@ debugging. */ #define OBSW_TEST_TE7020_HEATER 0 #define OBSW_TEST_GPIO_OPEN_BY_LABEL 0 #define OBSW_TEST_GPIO_OPEN_BY_LINE_NAME 0 -#define OBSW_LINK_IS_UP 0 +#define OBSW_LINK_IS_UP 1 #define OBSW_DEBUG_P60DOCK 0 #define OBSW_DEBUG_PDU1 0 diff --git a/scripts/q7s-port.sh b/scripts/q7s-port.sh index e475e8b7..a4d2e718 100755 --- a/scripts/q7s-port.sh +++ b/scripts/q7s-port.sh @@ -7,5 +7,6 @@ echo "-L 1536:192.168.133.10:7301 for TMTC commanding" ssh -L 1534:192.168.133.10:1534 \ -L 1535:192.168.133.10:22 \ -L 1536:192.168.133.10:7301 \ + -L 1537:192.168.133.10:7100 \ eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 \ -t 'CONSOLE_PREFIX="[Q7S Tunnel]" /bin/bash' From 5da2a458817ca88ed30221691964cbdfa437d694 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 8 Oct 2021 14:15:33 +0200 Subject: [PATCH 09/10] gpios to enable rs485 tx clock and tx data --- bsp_q7s/boardconfig/busConf.h | 2 ++ bsp_q7s/core/ObjectFactory.cpp | 10 ++++++++++ fsfw | 2 +- linux/fsfwconfig/devices/gpioIds.h | 6 +++++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/bsp_q7s/boardconfig/busConf.h b/bsp_q7s/boardconfig/busConf.h index 4b64e775..8905a125 100644 --- a/bsp_q7s/boardconfig/busConf.h +++ b/bsp_q7s/boardconfig/busConf.h @@ -60,6 +60,8 @@ namespace gpioNames { static constexpr char PAPB_EMPTY_SIGNAL_VC2[] = "papb_empty_signal_vc2"; static constexpr char PAPB_BUSY_SIGNAL_VC3[] = "papb_busy_signal_vc3"; static constexpr char PAPB_EMPTY_SIGNAL_VC3[] = "papb_empty_signal_vc3"; + static constexpr char RS485_EN_TX_CLOCK[] = "tx_clock_enable_ltc2872"; + static constexpr char RS485_EN_TX_DATA[] = "tx_data_enable_ltc2872"; } } diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index e36bf12c..47b26a2a 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -943,6 +943,16 @@ void ObjectFactory::createCcsdsComponents(LinuxLibgpioIF *gpioComIF) { ccsdsHandler->addVirtualChannel(ccsds::VC2, vc); vc = new VirtualChannel(ccsds::VC3, config::VC3_QUEUE_SIZE); ccsdsHandler->addVirtualChannel(ccsds::VC3, vc); + + GpioCookie* gpioRS485Chip = new GpioCookie; + gpio = new GpiodRegularByLineName(q7s::gpioNames::RS485_EN_TX_CLOCK, "RS485 Transceiver", + gpio::Direction::OUT, gpio::HIGH); + gpioRS485Chip->addGpio(gpioIds::RS485_EN_TX_CLOCK, gpio); + gpio = new GpiodRegularByLineName(q7s::gpioNames::RS485_EN_TX_DATA, "RS485 Transceiver", + gpio::Direction::OUT, gpio::HIGH); + gpioRS485Chip->addGpio(gpioIds::RS485_EN_TX_DATA, gpio); + + gpioComIF->addGpios(gpioRS485Chip); } void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) { diff --git a/fsfw b/fsfw index 2844c512..a578f039 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 2844c512b69a2a0089ee4b0f4fd57a75a42a3cb3 +Subproject commit a578f0390bce6c0a3d1d1e8d59764072f1075867 diff --git a/linux/fsfwconfig/devices/gpioIds.h b/linux/fsfwconfig/devices/gpioIds.h index 2016245d..5f09e5f6 100644 --- a/linux/fsfwconfig/devices/gpioIds.h +++ b/linux/fsfwconfig/devices/gpioIds.h @@ -98,7 +98,11 @@ enum gpioId_t { VC2_PAPB_EMPTY, VC2_PAPB_BUSY, VC3_PAPB_EMPTY, - VC3_PAPB_BUSY + VC3_PAPB_BUSY, + + + RS485_EN_TX_DATA, + RS485_EN_TX_CLOCK }; } From 2b609a413df7bb37c3bff90e424c07227dd5de82 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Fri, 8 Oct 2021 14:39:53 +0200 Subject: [PATCH 10/10] readme update --- README.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b6a18947..f117535d 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,14 @@ 4. [Useful and Common Host Commands](#host-commands) 5. [Setting up Prerequisites](#set-up-prereq) 6. [Remote Debugging](#remote-debugging) -7. [Direct Debugging](#direct-debugging) -8. [Transfering Files to the Q7S](#file-transfer) -9. [Q7S OBC](#q7s) -10. [Static Code Analysis](#static-code-analysis) -11. [Eclipse](#eclipse) -12. [Running the OBSW on a Raspberry Pi](#rpi) -13. [FSFW](#fsfw) +7. [TMTC testing](#tmtc-testing) +8. [Direct Debugging](#direct-debugging) +9. [Transfering Files to the Q7S](#file-transfer) +10. [Q7S OBC](#q7s) +11. [Static Code Analysis](#static-code-analysis) +12. [Eclipse](#eclipse) +13. [Running the OBSW on a Raspberry Pi](#rpi) +14. [FSFW](#fsfw) # General information @@ -574,6 +575,13 @@ alias or shell script to do this quickly. Note: When now setting up a debug session in the Xilinx SDK or Eclipse, the host must be set to localhost instead of the IP address of the Q7S. +# TMTC testing +The OBSW supports sending PUS TM packets via TCP or the PDEC IP Core which transmits the data as CADU frames. To make the CADU frames receivabel by the [TMTC porgram](https://egit.irs.uni-stuttgart.de/eive/eive-tmtc), a python script is running as systemd service on the flatsat PC which forwards TCP commands to the TCP server of the OBC and reads CADU frames from a serial interface. The PUS packets transported with the CADU frames are extracted and forwared to the TMTC program's TCP client. The code of the TMTC bridge can be found [here](https://egit.irs.uni-stuttgart.de/eive/tmtc-bridge). To connect the TMTC program to the TMTC-bridge a port forwarding from a host must be set up with the following command: +```` +ssh -L 1537:127.0.0.1:7100 eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 -t bash +```` +Note: The encoding of the TM packets and conversion of CADU frames takes some time. Thus the replies are received with a larger delay compared to a direct TCP connection. + # Direct Debugging 1. Assign static IP address to Q7S