diff --git a/bsp_q7s/InitMission.cpp b/bsp_q7s/InitMission.cpp index 797c5e71..85249099 100644 --- a/bsp_q7s/InitMission.cpp +++ b/bsp_q7s/InitMission.cpp @@ -83,6 +83,15 @@ void initmission::initTasks() { initmission::printAddObjectError("UDP_POLLING", objects::UDP_POLLING_TASK); } +#if TEST_CCSDS_BRIDGE == 1 + PeriodicTaskIF* ptmeTestTask = factory->createPeriodicTask( + "PTME_TEST", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc); + result = ptmeTestTask->addComponent(objects::CCSDS_IP_CORE_BRIDGE); + if(result != HasReturnvaluesIF::RETURN_OK) { + initmission::printAddObjectError("PTME_TEST", objects::CCSDS_IP_CORE_BRIDGE); + } +#endif + /* PUS Services */ PeriodicTaskIF* pusVerification = factory->createPeriodicTask( "PUS_VERIF", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc); @@ -210,5 +219,9 @@ void initmission::initTasks() { #if OBSW_ADD_TEST_CODE == 1 testTask->startTask(); #endif + +#if TEST_CCSDS_BRIDGE == 1 + ptmeTestTask->startTask(); +#endif sif::info << "Tasks started.." << std::endl; } diff --git a/bsp_q7s/ObjectFactory.cpp b/bsp_q7s/ObjectFactory.cpp index 4d1a413e..71e758b1 100644 --- a/bsp_q7s/ObjectFactory.cpp +++ b/bsp_q7s/ObjectFactory.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -577,9 +578,22 @@ void ObjectFactory::produce(){ SpiCookie* spiCookieSus = new SpiCookie(addresses::SUS_1, std::string("/dev/spidev1.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::DEFAULT_MAX_1227_SPEED); - SusHandler* sus1 = new SusHandler(objects::SUS_1, objects::SPI_COM_IF, spiCookieSus, gpioComIF, + new SusHandler(objects::SUS_1, objects::SPI_COM_IF, spiCookieSus, gpioComIF, gpioIds::CS_SUS_1); - sus1->setStartUpImmediately(); +#endif + +#if TE0720 == 1 && TEST_CCSDS_BRIDGE == 1 + GpioCookie* gpioCookieCcsdsIp = new GpioCookie; + GpiodRegular* papbBusyN = new GpiodRegular(std::string("gpiochip0"), 0, std::string("PAPBBusy_N")); + gpioCookieCcsdsIp->addGpio(gpioIds::PAPB_BUSY_N, papbBusyN); + GpiodRegular* papbEmpty = new GpiodRegular(std::string("gpiochip0"), 1, + std::string("Chip Select Sus Sensor")); + gpioCookieCcsdsIp->addGpio(gpioIds::PAPB_EMPTY, papbEmpty); + gpioComIF->addGpios(gpioCookieCcsdsIp); + + 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 #if TE0720 == 1 && TEST_RADIATION_SENSOR_HANDLER == 1 diff --git a/fsfw_hal b/fsfw_hal index a0f698ff..6341da22 160000 --- a/fsfw_hal +++ b/fsfw_hal @@ -1 +1 @@ -Subproject commit a0f698fffa4dd5c9f86337c5d6170f9321cb8de7 +Subproject commit 6341da22123166ac5fafdbc09e823d7464f769e5 diff --git a/fsfwconfig/OBSWConfig.h b/fsfwconfig/OBSWConfig.h index 9426d01b..efc8bcc2 100644 --- a/fsfwconfig/OBSWConfig.h +++ b/fsfwconfig/OBSWConfig.h @@ -20,11 +20,12 @@ debugging. */ #define OBSW_PRINT_MISSED_DEADLINES 1 #define OBSW_ADD_TEST_CODE 1 #define TEST_LIBGPIOD 0 -#define TEST_RADIATION_SENSOR_HANDLER 1 +#define TEST_RADIATION_SENSOR_HANDLER 0 #define TEST_SUS_HANDLER 1 #define TEST_PLOC_HANDLER 0 +#define TEST_CCSDS_BRIDGE 1 -#define TE0720 0 +#define TE0720 1 #define TE0720_HEATER_TEST 0 #define P60DOCK_DEBUG 0 diff --git a/fsfwconfig/devices/gpioIds.h b/fsfwconfig/devices/gpioIds.h index 3221c613..102b04b9 100644 --- a/fsfwconfig/devices/gpioIds.h +++ b/fsfwconfig/devices/gpioIds.h @@ -65,7 +65,10 @@ namespace gpioIds { SPI_MUX_BIT_5, SPI_MUX_BIT_6, - CS_RAD_SENSOR + CS_RAD_SENSOR, + + PAPB_BUSY_N, + PAPB_EMPTY }; } diff --git a/fsfwconfig/objects/systemObjectList.h b/fsfwconfig/objects/systemObjectList.h index 746e83cf..0d20bd3d 100644 --- a/fsfwconfig/objects/systemObjectList.h +++ b/fsfwconfig/objects/systemObjectList.h @@ -16,6 +16,7 @@ namespace objects { PUS_PACKET_DISTRIBUTOR = 0x50000200, UDP_BRIDGE = 0x50000300, UDP_POLLING_TASK = 0x50000400, + CCSDS_IP_CORE_BRIDGE = 0x50000500, PUS_SERVICE_3 = 0x51000300, PUS_SERVICE_5 = 0x51000400, diff --git a/fsfwconfig/returnvalues/classIds.h b/fsfwconfig/returnvalues/classIds.h index 50bb3cea..f3f50592 100644 --- a/fsfwconfig/returnvalues/classIds.h +++ b/fsfwconfig/returnvalues/classIds.h @@ -21,7 +21,8 @@ enum { SYRLINKS_HANDLER, IMTQ_HANDLER, PLOC_HANDLER, - SUS_HANDLER + SUS_HANDLER, + CCSDS_IP_CORE_BRIDGE }; } diff --git a/mission/CMakeLists.txt b/mission/CMakeLists.txt index 9cb18749..8a18094c 100644 --- a/mission/CMakeLists.txt +++ b/mission/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(core) add_subdirectory(devices) +add_subdirectory(obc) add_subdirectory(utility) diff --git a/mission/obc/CCSDSIPCoreBridge.cpp b/mission/obc/CCSDSIPCoreBridge.cpp new file mode 100644 index 00000000..f92244ce --- /dev/null +++ b/mission/obc/CCSDSIPCoreBridge.cpp @@ -0,0 +1,104 @@ +#include +#include + +#include + +CCSDSIPCoreBridge::CCSDSIPCoreBridge(object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId, object_id_t tcStoreId, LinuxLibgpioIF* gpioComIF, + std::string uioPtme, gpioId_t papbBusyId, gpioId_t papbEmptyId) : + TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId), gpioComIF(gpioComIF), uioPtme( + uioPtme), papbBusyId(papbBusyId), papbEmptyId(papbEmptyId) { +} + +CCSDSIPCoreBridge::~CCSDSIPCoreBridge() { +} + +ReturnValue_t CCSDSIPCoreBridge::initialize() { + ReturnValue_t result = TmTcBridge::initialize(); + + fd = open("/dev/uio0", O_RDWR); + if (fd < 1) { + sif::debug << "CCSDSIPCoreBridge::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 << "CCSDSIPCoreBridge::initialize: Failed to map uio address" << std::endl; + return RETURN_FAILED; + } + + return result; +} + +ReturnValue_t CCSDSIPCoreBridge::handleTm() { + + /** 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; +} + +ReturnValue_t CCSDSIPCoreBridge::sendTm(const uint8_t * data, size_t dataLen) { + + if(pollPapbSignal() == RETURN_OK) { + startPacketTransfer(); + } + + for(size_t idx = 0; idx < dataLen; idx++) { + if(pollPapbSignal() == RETURN_OK) { + *(ptmeBaseAddress + PTME_DATA_REG_OFFSET) = static_cast(*(data + idx)); + } + else { + sif::debug << "CCSDSIPCoreBridge::sendTm: Only written " << idx - 1 << " of " << dataLen + << " data" << std::endl; + return RETURN_FAILED; + } + } + + if(pollPapbSignal() == RETURN_OK) { + endPacketTransfer(); + } + return RETURN_OK; +} + +void CCSDSIPCoreBridge::startPacketTransfer() { + *(ptmeBaseAddress) = PTME_CONFIG_START; +} + +void CCSDSIPCoreBridge::endPacketTransfer() { + *(ptmeBaseAddress) = PTME_CONFIG_END; +} + +ReturnValue_t CCSDSIPCoreBridge::pollPapbSignal() { + 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 << "CCSDSIPCoreBridge::pollPapbSignal: Failed to read papb busy signal" + << std::endl; + return RETURN_FAILED; + } + if (!papbBusyState) { + sif::debug << "CCSDSIPCoreBridge::pollPapbSignal: PAPB busy" << std::endl; + return PAPB_BUSY; + } + + return RETURN_OK; +} diff --git a/mission/obc/CCSDSIPCoreBridge.h b/mission/obc/CCSDSIPCoreBridge.h new file mode 100644 index 00000000..ee73cbc3 --- /dev/null +++ b/mission/obc/CCSDSIPCoreBridge.h @@ -0,0 +1,116 @@ +#ifndef MISSION_OBC_CCSDSIPCOREBRIDGE_H_ +#define MISSION_OBC_CCSDSIPCOREBRIDGE_H_ + +#include +#include +#include +#include + +/** + * @brief This class handles the interfacing to the telemetry (PTME) and telecommand (PDEC) IP + * cores responsible for the CCSDS encoding and decoding. The IP cores are implemented + * on the programmable logic and are accessible through the linux UIO driver. + */ +class CCSDSIPCoreBridge: public TmTcBridge { +public: + /** + * @brief Constructor + * + * @param objectId + * @param tcDestination + * @param tmStoreId + * @param tcStoreId + * @param uioPtme Name of the uio device file which provides access to the PTME IP Core. + * @param papbBusyId The ID of the GPIO which is connected to the PAPBBusy_N signal of the + * PTME IP Core. A low logic level indicates the PTME is not ready to + * receive more data. + * @param papbEmptyId The ID of the GPIO which is connected to the PAPBEmpty signal of the + * PTME IP Core. The signal is high when there are no packets in the + * external buffer memory (BRAM). + */ + CCSDSIPCoreBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, + object_id_t tcStoreId, LinuxLibgpioIF* gpioComIF, std::string uioPtme, + gpioId_t papbBusyId, gpioId_t papbEmptyId); + virtual ~CCSDSIPCoreBridge(); + + ReturnValue_t initialize() override; + +protected: + + /** + * Overwriting this function for testing purpose. Function is periodically called in + * performOperation. + */ + virtual ReturnValue_t handleTm() override; + + virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; + +private: + + static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_IP_CORE_BRIDGE; + + static const ReturnValue_t PAPB_BUSY = MAKE_RETURN_CODE(0xA0); + + + /** Size of mapped address space. 4k (minimal size of pl device) */ + static const int MAP_SIZE = 0xFA0; + + /** + * 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. + */ + static const int PTME_DATA_REG_OFFSET = 0x400; + + LinuxLibgpioIF* gpioComIF = nullptr; + + /** The uio device file related to the PTME IP Core */ + std::string uioPtme; + + /** Pulled to low when PTME not ready to receive data */ + gpioId_t papbBusyId = gpio::NO_GPIO; + + /** High when externally buffer memory of PTME is empty */ + gpioId_t papbEmptyId = gpio::NO_GPIO; + + /** The file descriptor of the UIO driver */ + int fd; + + /** PTME base address */ + uint32_t* ptmeBaseAddress = nullptr; + + /** + * @brief This function sends the config byte to the PTME IP Core to initiate a packet + * transfer. + */ + void startPacketTransfer(); + + /** + * @brief This function sends the config byte to 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 PAPB 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 pollPapbSignal(); +}; + +#endif /* MISSION_OBC_CCSDSIPCOREBRIDGE_H_ */ diff --git a/mission/obc/CMakeLists.txt b/mission/obc/CMakeLists.txt new file mode 100644 index 00000000..79d9ba9b --- /dev/null +++ b/mission/obc/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${TARGET_NAME} PUBLIC + CCSDSIPCoreBridge.cpp +) + +