Merge branch 'mueller/master' of https://egit.irs.uni-stuttgart.de/eive/eive-obsw into mueller/master

This commit is contained in:
Robin Müller 2021-10-11 17:08:33 +02:00
commit c51d9b437e
31 changed files with 1029 additions and 23 deletions

View File

@ -11,13 +11,14 @@
4. [Useful and Common Host Commands](#host-commands) 4. [Useful and Common Host Commands](#host-commands)
5. [Setting up Prerequisites](#set-up-prereq) 5. [Setting up Prerequisites](#set-up-prereq)
6. [Remote Debugging](#remote-debugging) 6. [Remote Debugging](#remote-debugging)
7. [Direct Debugging](#direct-debugging) 7. [TMTC testing](#tmtc-testing)
8. [Transfering Files to the Q7S](#file-transfer) 8. [Direct Debugging](#direct-debugging)
9. [Q7S OBC](#q7s) 9. [Transfering Files to the Q7S](#file-transfer)
10. [Static Code Analysis](#static-code-analysis) 10. [Q7S OBC](#q7s)
11. [Eclipse](#eclipse) 11. [Static Code Analysis](#static-code-analysis)
12. [Running the OBSW on a Raspberry Pi](#rpi) 12. [Eclipse](#eclipse)
13. [FSFW](#fsfw) 13. [Running the OBSW on a Raspberry Pi](#rpi)
14. [FSFW](#fsfw)
# <a id="general"></a> General information # <a id="general"></a> General information
@ -574,6 +575,40 @@ 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 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. to localhost instead of the IP address of the Q7S.
# <a id="tmtc-testing"></a> 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 named `tmtc_bridge` on the flatsat PC which forwards TCP commands to the TCP
server of the OBC and reads CADU frames from a serial interface.
You can check whether the service is running the following command on the flatsat PC
```sh
systemctl status tmtc_bridge
```
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:
```sh
ssh -L 1537:127.0.0.1:7100 eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 -t bash
```
You can print the output of the `systemd` service with
```sh
journalctl -u tmtc_bridge
```
This can be helpful to determine whether any TCs arrive or TMs are coming back.
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.
# <a id="direct-debugging"></a> Direct Debugging # <a id="direct-debugging"></a> Direct Debugging
1. Assign static IP address to Q7S 1. Assign static IP address to Q7S

View File

@ -52,6 +52,16 @@ namespace gpioNames {
static constexpr char EN_RW_4[] = "enable_rw_4"; static constexpr char EN_RW_4[] = "enable_rw_4";
static constexpr char SPI_MUX_SELECT[] = "spi_mux_select"; static constexpr char SPI_MUX_SELECT[] = "spi_mux_select";
static constexpr char RAD_SENSOR_CHIP_SELECT[] = "rad_sensor_chip_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";
static constexpr char RS485_EN_TX_CLOCK[] = "tx_clock_enable_ltc2872";
static constexpr char RS485_EN_TX_DATA[] = "tx_data_enable_ltc2872";
} }
} }

View File

@ -98,6 +98,15 @@ void initmission::initTasks() {
} }
#endif #endif
#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 # if BOARD_TE0720 == 0
// FS task, task interval does not matter because it runs in permanent loop, priority low // FS task, task interval does not matter because it runs in permanent loop, priority low
// because it is a non-essential background task // because it is a non-essential background task
@ -147,6 +156,10 @@ void initmission::initTasks() {
tmtcPollingTask->startTask(); tmtcPollingTask->startTask();
#endif #endif
#if OBSW_USE_CCSDS_IP_CORE == 1
ccsdsHandlerTask->startTask();
#endif /* OBSW_USE_CCSDS_IP_CORE == 1 */
#if BOARD_TE0720 == 0 #if BOARD_TE0720 == 0
coreController->startTask(); coreController->startTask();
#endif #endif

View File

@ -1,8 +1,8 @@
#include <sstream> #include <sstream>
#include "ObjectFactory.h" #include "ObjectFactory.h"
#include "OBSWConfig.h" #include "OBSWConfig.h"
#include "devConf.h" #include "devConf.h"
#include "ccsdsConfig.h"
#include "busConf.h" #include "busConf.h"
#include "tmtc/apid.h" #include "tmtc/apid.h"
#include "devices/addresses.h" #include "devices/addresses.h"
@ -25,8 +25,6 @@
#include "linux/devices/SusHandler.h" #include "linux/devices/SusHandler.h"
#include "linux/csp/CspCookie.h" #include "linux/csp/CspCookie.h"
#include "linux/csp/CspComIF.h" #include "linux/csp/CspComIF.h"
#include "linux/obc/CCSDSIPCoreBridge.h"
#include "mission/core/GenericFactory.h" #include "mission/core/GenericFactory.h"
#include "mission/devices/PDU1Handler.h" #include "mission/devices/PDU1Handler.h"
#include "mission/devices/PDU2Handler.h" #include "mission/devices/PDU2Handler.h"
@ -50,6 +48,8 @@
#include "mission/devices/devicedefinitions/RwDefinitions.h" #include "mission/devices/devicedefinitions/RwDefinitions.h"
#include "mission/devices/devicedefinitions/StarTrackerDefinitions.h" #include "mission/devices/devicedefinitions/StarTrackerDefinitions.h"
#include "mission/devices/GPSHyperionHandler.h" #include "mission/devices/GPSHyperionHandler.h"
#include "mission/tmtc/CCSDSHandler.h"
#include "mission/tmtc/VirtualChannel.h"
#include "mission/utility/TmFunnel.h" #include "mission/utility/TmFunnel.h"
#include "fsfw_hal/linux/uart/UartComIF.h" #include "fsfw_hal/linux/uart/UartComIF.h"
@ -75,6 +75,10 @@
#include "linux/boardtest/LibgpiodTest.h" #include "linux/boardtest/LibgpiodTest.h"
#endif #endif
#include <linux/obc/Ptme.h>
#include <linux/obc/PapbVcInterface.h>
#include <linux/obc/PtmeConfig.h>
ResetArgs resetArgsGnss0; ResetArgs resetArgsGnss0;
ResetArgs resetArgsGnss1; ResetArgs resetArgsGnss1;
@ -91,7 +95,12 @@ void Factory::setStaticFrameworkObjectIds() {
//DeviceHandlerBase::powerSwitcherId = objects::PCDU_HANDLER; //DeviceHandlerBase::powerSwitcherId = objects::PCDU_HANDLER;
DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
#if OBSW_TM_TO_PTME == 1
TmFunnel::downlinkDestination = objects::CCSDS_HANDLER;
#else
TmFunnel::downlinkDestination = objects::TMTC_BRIDGE; TmFunnel::downlinkDestination = objects::TMTC_BRIDGE;
#endif /* OBSW_TM_TO_PTME == 1 */
// No storage object for now. // No storage object for now.
TmFunnel::storageDestination = objects::NO_OBJECT; TmFunnel::storageDestination = objects::NO_OBJECT;
@ -164,6 +173,10 @@ void ObjectFactory::produce(void* args) {
#endif /* TE7020 != 0 */ #endif /* TE7020 != 0 */
#if OBSW_USE_CCSDS_IP_CORE == 1
createCcsdsComponents(gpioComIF);
#endif /* OBSW_USE_CCSDS_IP_CORE == 1 */
/* Test Task */ /* Test Task */
#if OBSW_ADD_TEST_CODE == 1 #if OBSW_ADD_TEST_CODE == 1
createTestComponents(gpioComIF); createTestComponents(gpioComIF);
@ -863,6 +876,85 @@ void ObjectFactory::createReactionWheelComponents(LinuxLibgpioIF* gpioComIF) {
rw4SpiCookie->setCallbackArgs(rwHandler4); 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(ccsds::VC2, config::VC2_QUEUE_SIZE);
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) { void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) {
#if BOARD_TE0720 == 0 #if BOARD_TE0720 == 0
@ -901,10 +993,10 @@ void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) {
#if BOARD_TE0720 == 1 && OBSW_TEST_CCSDS_BRIDGE == 1 #if BOARD_TE0720 == 1 && OBSW_TEST_CCSDS_BRIDGE == 1
GpioCookie* gpioCookieCcsdsIp = new GpioCookie; 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); gpioCookieCcsdsIp->addGpio(gpioIds::PAPB_BUSY_N, papbBusyN);
GpiodRegular* papbEmpty = new GpiodRegular(std::string("gpiochip0"), 1, GpiodRegular* papbEmpty = new GpiodRegular(std::string("gpiochip0"), 1,
std::string("Chip Select Sus Sensor")); std::string("PAPBEmpty_VC0"));
gpioCookieCcsdsIp->addGpio(gpioIds::PAPB_EMPTY, papbEmpty); gpioCookieCcsdsIp->addGpio(gpioIds::PAPB_EMPTY, papbEmpty);
gpioComIF->addGpios(gpioCookieCcsdsIp); gpioComIF->addGpios(gpioCookieCcsdsIp);

View File

@ -22,6 +22,7 @@ void createSolarArrayDeploymentComponents();
void createSyrlinksComponents(); void createSyrlinksComponents();
void createRtdComponents(LinuxLibgpioIF* gpioComIF); void createRtdComponents(LinuxLibgpioIF* gpioComIF);
void createReactionWheelComponents(LinuxLibgpioIF* gpioComIF); void createReactionWheelComponents(LinuxLibgpioIF* gpioComIF);
void createCcsdsComponents(LinuxLibgpioIF *gpioComIF);
void createTestComponents(LinuxLibgpioIF* gpioComIF); void createTestComponents(LinuxLibgpioIF* gpioComIF);
}; };

View File

@ -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_ */

View File

@ -17,6 +17,7 @@ enum commonClassIds: uint8_t {
PLOC_SUPERVISOR_HANDLER, //PLSV PLOC_SUPERVISOR_HANDLER, //PLSV
SUS_HANDLER, //SUSS SUS_HANDLER, //SUSS
CCSDS_IP_CORE_BRIDGE, //IPCI CCSDS_IP_CORE_BRIDGE, //IPCI
PTME, //PTME
PLOC_UPDATER, //PLUD PLOC_UPDATER, //PLUD
GOM_SPACE_HANDLER, //GOMS GOM_SPACE_HANDLER, //GOMS
PLOC_MEMORY_DUMPER, //PLMEMDUMP PLOC_MEMORY_DUMPER, //PLMEMDUMP

View File

@ -9,6 +9,13 @@
#define OBSW_ADD_TCPIP_BRIDGE 1 #define OBSW_ADD_TCPIP_BRIDGE 1
// Use TCP instead of UDP for the TMTC bridge. This allows using the TMTC client locally // 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 // because UDP packets are not allowed in the VPN
// This will cause the OBSW to initialize the TMTC bridge responsible for exchanging data with the
// 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 1
// Set to 1 if telecommands are received via the PDEC IP Core
#define OBSW_TC_FROM_PDEC 0
#define OBSW_USE_TCP_BRIDGE 1 #define OBSW_USE_TCP_BRIDGE 1
namespace common { namespace common {

View File

@ -11,6 +11,12 @@ enum commonObjects: uint32_t {
TMTC_BRIDGE = 0x50000300, TMTC_BRIDGE = 0x50000300,
TMTC_POLLING_TASK = 0x50000400, TMTC_POLLING_TASK = 0x50000400,
FILE_SYSTEM_HANDLER = 0x50000500, FILE_SYSTEM_HANDLER = 0x50000500,
PTME = 0x50000600,
PAPB_VC0 = 0x50000700,
PAPB_VC1 = 0x50000701,
PAPB_VC2 = 0x50000702,
PAPB_VC3 = 0x50000703,
CCSDS_HANDLER = 0x50000800,
/* 0x43 ('C') for Controllers */ /* 0x43 ('C') for Controllers */
THERMAL_CONTROLLER = 0x43400001, THERMAL_CONTROLLER = 0x43400001,

View File

@ -1,7 +1,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <fcntl.h> #include <fcntl.h>
#include <linux/obc/CCSDSIPCoreBridge.h> #include <linux/obc/Ptme.h>
CCSDSIPCoreBridge::CCSDSIPCoreBridge(object_id_t objectId, object_id_t tcDestination, CCSDSIPCoreBridge::CCSDSIPCoreBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, LinuxLibgpioIF* gpioComIF, object_id_t tmStoreId, object_id_t tcStoreId, LinuxLibgpioIF* gpioComIF,

View File

@ -86,6 +86,7 @@ debugging. */
#define OBSW_TEST_TE7020_HEATER 0 #define OBSW_TEST_TE7020_HEATER 0
#define OBSW_TEST_GPIO_OPEN_BY_LABEL 0 #define OBSW_TEST_GPIO_OPEN_BY_LABEL 0
#define OBSW_TEST_GPIO_OPEN_BY_LINE_NAME 0 #define OBSW_TEST_GPIO_OPEN_BY_LINE_NAME 0
#define OBSW_LINK_IS_UP 1
#define OBSW_DEBUG_P60DOCK 0 #define OBSW_DEBUG_P60DOCK 0
#define OBSW_DEBUG_PDU1 0 #define OBSW_DEBUG_PDU1 0
@ -123,6 +124,14 @@ namespace config {
/* Add mission configuration flags here */ /* Add mission configuration flags here */
static constexpr uint32_t OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE = 50; static constexpr uint32_t OBSW_FILESYSTEM_HANDLER_QUEUE_SIZE = 50;
static constexpr uint32_t PLOC_UPDATER_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;
static constexpr uint8_t LIVE_TM = 0;
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -89,7 +89,20 @@ enum gpioId_t {
EN_RW_CS, 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,
RS485_EN_TX_DATA,
RS485_EN_TX_CLOCK
}; };
} }

View File

@ -1,5 +1,6 @@
target_sources(${TARGET_NAME} PUBLIC target_sources(${TARGET_NAME} PUBLIC
CCSDSIPCoreBridge.cpp PapbVcInterface.cpp
Ptme.cpp
) )

View File

@ -0,0 +1,104 @@
#include <linux/obc/PapbVcInterface.h>
#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), 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 size) {
if(pollPapbBusySignal() == RETURN_OK) {
startPacketTransfer();
}
for(size_t idx = 0; idx < size; idx++) {
if(pollPapbBusySignal() == RETURN_OK) {
*(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(*(data + idx));
}
else {
sif::warning << "PapbVcInterface::write: Only written " << idx << " of "
<< size << " 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::warning << "PapbVcInterface::pollPapbBusySignal: Failed to read papb busy signal"
<< std::endl;
return RETURN_FAILED;
}
if (!papbBusyState) {
sif::warning << "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::warning << "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<uint8_t>(idx & 0xFF);
}
ReturnValue_t result = write(testPacket, 1105);
if(result != RETURN_OK) {
return result;
}
return RETURN_OK;
}

112
linux/obc/PapbVcInterface.h Normal file
View File

@ -0,0 +1,112 @@
#ifndef LINUX_OBC_PAPBVCINTERFACE_H_
#define LINUX_OBC_PAPBVCINTERFACE_H_
#include "OBSWConfig.h"
#include "linux/obc/VcInterfaceIF.h"
#include <fsfw_hal/common/gpio/gpioDefinitions.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
#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
* via the PAPB interface.
*
* @author J. Meier
*/
class PapbVcInterface: public SystemObject,
public VcInterfaceIF,
public 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();
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;
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_ */

73
linux/obc/Ptme.cpp Normal file
View File

@ -0,0 +1,73 @@
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/obc/Ptme.h>
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "PtmeConfig.h"
Ptme::Ptme(object_id_t objectId) :
SystemObject(objectId) {
}
Ptme::~Ptme() {
}
ReturnValue_t Ptme::initialize() {
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;
}
/**
* Map uio device in virtual address space
* PROT_WRITE: Map uio device in writable only mode
*/
ptmeBaseAddress = static_cast<uint32_t*>(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;
}
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 size) {
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<unsigned int>(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::NUMBER_OF_VIRTUAL_CHANNELS) {
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;
}
}

91
linux/obc/Ptme.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef LINUX_OBC_PTME_H_
#define LINUX_OBC_PTME_H_
#include "OBSWConfig.h"
#include "linux/obc/PtmeIF.h"
#include "linux/obc/VcInterfaceIF.h"
#include <fsfw_hal/common/gpio/gpioDefinitions.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include <cstring>
#include <unordered_map>
/**
* @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 : public PtmeIF,
public SystemObject,
public HasReturnvaluesIF {
public:
using VcId_t = uint8_t;
/**
* @brief Constructor
*
* @param objectId
*/
Ptme(object_id_t objectId);
virtual ~Ptme();
ReturnValue_t initialize() 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
* 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);
#if BOARD_TE0720 == 1
/** Size of mapped address space */
static const int MAP_SIZE = 0x40000;
#else
/** Size of mapped address space */
static const int MAP_SIZE = 0x40000;
#endif /* BOARD_TE0720 == 1 */
/**
* 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 VcInterfaceMap = std::unordered_map<VcId_t, VcInterfaceIF*>;
using VcInterfaceMapIter = VcInterfaceMap::iterator;
VcInterfaceMap vcInterfaceMap;
};
#endif /* LINUX_OBC_PTME_H_ */

26
linux/obc/PtmeConfig.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef LINUX_OBC_PTMECONFIG_H_
#define LINUX_OBC_PTMECONFIG_H_
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include <cstring>
/**
* @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 char UIO_DEVICE_FILE[] = "/dev/uio0";
};
#endif /* LINUX_OBC_PTMECONFIG_H_ */

28
linux/obc/PtmeIF.h Normal file
View File

@ -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, const uint8_t* data, size_t size) = 0;
};
#endif /* LINUX_OBC_PTMEIF_H_ */

29
linux/obc/VcInterfaceIF.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef LINUX_OBC_VCINTERFACEIF_H_
#define LINUX_OBC_VCINTERFACEIF_H_
#include <stddef.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(const uint8_t* data, size_t size) = 0;
virtual void setRegisterAddress(uint32_t* ptmeBaseAddress) = 0;
};
#endif /* LINUX_OBC_VCINTERFACEIF_H_ */

View File

@ -2,3 +2,4 @@ add_subdirectory(core)
add_subdirectory(devices) add_subdirectory(devices)
add_subdirectory(utility) add_subdirectory(utility)
add_subdirectory(memory) add_subdirectory(memory)
add_subdirectory(tmtc)

View File

@ -0,0 +1,122 @@
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/ipc/QueueFactory.h"
#include "CCSDSHandler.h"
CCSDSHandler::CCSDSHandler(object_id_t objectId, object_id_t ptmeId) :
SystemObject(objectId), ptmeId(ptmeId), parameterHelper(this) {
commandQueue = QueueFactory::instance()->createMessageQueue(QUEUE_SIZE);
}
CCSDSHandler::~CCSDSHandler() {
}
ReturnValue_t CCSDSHandler::performOperation(uint8_t operationCode) {
readCommandQueue();
handleTelemetry();
handleTelecommands();
return RETURN_OK;
}
void CCSDSHandler::handleTelemetry() {
VirtualChannelMapIter iter;
for (iter = virtualChannelMap.begin(); iter != virtualChannelMap.end(); iter++) {
iter->second->performOperation();
}
}
void CCSDSHandler::handleTelecommands() {
}
ReturnValue_t CCSDSHandler::initialize() {
ReturnValue_t result = RETURN_OK;
PtmeIF* ptme = ObjectManager::instance()->get<PtmeIF>(ptmeId);
if (ptme == nullptr) {
sif::warning << "Invalid PTME object" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
result = parameterHelper.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;
}
void CCSDSHandler::readCommandQueue(void) {
CommandMessage commandMessage;
ReturnValue_t result = RETURN_FAILED;
result = commandQueue->receiveMessage(&commandMessage);
if (result == RETURN_OK) {
result = parameterHelper.handleParameterMessage(&commandMessage);
if (result == RETURN_OK) {
return;
}
CommandMessage reply;
reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND,
commandMessage.getCommand());
commandQueue->reply(&reply);
}
}
MessageQueueId_t CCSDSHandler::getCommandQueue() const {
return commandQueue->getId();
}
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;
}
if (virtualChannel == nullptr) {
sif::warning << "CCSDSHandler::addVirtualChannel: Invalid virtual channel interface" << std::endl;
return;
}
auto status = virtualChannelMap.emplace(vcId, virtualChannel);
if (status.second == false) {
sif::warning << "CCSDSHandler::addVirtualChannel: Failed to add virtual channel to "
"virtual channel map" << std::endl;
return;
}
}
MessageQueueId_t CCSDSHandler::getReportReceptionQueue(uint8_t virtualChannel) {
if (virtualChannel < config::NUMBER_OF_VIRTUAL_CHANNELS) {
VirtualChannelMapIter iter = virtualChannelMap.find(virtualChannel);
if (iter != virtualChannelMap.end()) {
return iter->second->getReportReceptionQueue();
}
else {
sif::warning << "CCSDSHandler::getReportReceptionQueue: Virtual channel with ID "
<< static_cast<unsigned int>(virtualChannel) << " not in virtual channel map"
<< std::endl;
return MessageQueueIF::NO_QUEUE;
}
} else {
sif::debug << "CCSDSHandler::getReportReceptionQueue: Invalid virtual channel requested";
}
return MessageQueueIF::NO_QUEUE;
}
ReturnValue_t CCSDSHandler::getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
uint16_t startAtIndex) {
return RETURN_OK;
}

View File

@ -0,0 +1,75 @@
#ifndef CCSDSHANDLER_H_
#define CCSDSHANDLER_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 <unordered_map>
/**
* @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 AcceptsTelemetryIF,
public HasReturnvaluesIF,
public ReceivesParameterMessagesIF {
public:
using VcId_t = uint8_t;
/**
* @brief Constructor
*
* @param objectId Object ID of the CCSDS handler
* @param ptmeId Object ID of the PTME object providing access to the PTME IP Core.
*/
CCSDSHandler(object_id_t objectId, object_id_t ptmeId);
~CCSDSHandler();
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
ReturnValue_t initialize();
MessageQueueId_t getCommandQueue() const;
/**
* @brief Function to add a virtual channel
*
* @param virtualChannelId ID of the virtual channel to add
* @param virtualChannel Pointer to virtual channel object
*/
void addVirtualChannel(VcId_t virtualChannelId, VirtualChannel* virtualChannel);
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0);
ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
uint16_t startAtIndex);
private:
static const uint32_t QUEUE_SIZE = config::CCSDS_HANDLER_QUEUE_SIZE;
using VirtualChannelMap = std::unordered_map<VcId_t, VirtualChannel*>;
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();
};
#endif /* CCSDSHANDLER_H_ */

View File

@ -0,0 +1,6 @@
target_sources(${TARGET_NAME} PUBLIC
CCSDSHandler.cpp
VirtualChannel.cpp
)

View File

@ -0,0 +1,69 @@
#include "CCSDSHandler.h"
#include "VirtualChannel.h"
#include "OBSWConfig.h"
#include "fsfw/serviceinterface/ServiceInterfaceStream.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
#include "fsfw/ipc/QueueFactory.h"
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<StorageManagerIF>(objects::TM_STORE);
if(tmStore == nullptr) {
sif::error << "VirtualChannel::initialize: Failed to get tm store" << std::endl;
return RETURN_FAILED;
}
return RETURN_OK;
}
ReturnValue_t VirtualChannel::performOperation() {
ReturnValue_t result = 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(vcId, 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;
return;
}
ptme = ptme_;
}
void VirtualChannel::setLinkState(bool linkIsUp) {
linkIsUp = linkIsUp;
}

View File

@ -0,0 +1,58 @@
#ifndef VIRTUALCHANNEL_H_
#define VIRTUALCHANNEL_H_
#include "OBSWConfig.h"
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include <fsfw/ipc/MessageQueueIF.h>
#include <linux/obc/PtmeIF.h>
/**
* @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:
/**
* @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();
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) override;
ReturnValue_t performOperation();
/**
* @brief Sets the PTME object which handles access to the PTME IP Core.
*
* @param ptme Pointer to ptme object
*/
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 vcId;
#if OBSW_LINK_IS_UP == 1
bool linkIsUp = true;
#else
bool linkIsUp = false;
#endif /* OBSW_LINK_IS_UP == 1 */
StorageManagerIF* tmStore = nullptr;
};
#endif /* VIRTUALCHANNEL_H_ */

View File

@ -1,3 +1,4 @@
#include "OBSWConfig.h"
#include <fsfw/ipc/QueueFactory.h> #include <fsfw/ipc/QueueFactory.h>
#include <fsfw/tmtcpacket/pus/tm.h> #include <fsfw/tmtcpacket/pus/tm.h>
#include <fsfw/objectmanager/ObjectManager.h> #include <fsfw/objectmanager/ObjectManager.h>
@ -45,7 +46,7 @@ ReturnValue_t TmFunnel::performOperation(uint8_t operationCode) {
ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) { ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) {
uint8_t* packetData = nullptr; uint8_t* packetData = nullptr;
size_t size = 0; size_t size = 0;
ReturnValue_t result = tmPool->modifyData(message->getStorageId(), ReturnValue_t result = tmStore->modifyData(message->getStorageId(),
&packetData, &size); &packetData, &size);
if(result != HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK){
return result; return result;
@ -59,7 +60,7 @@ ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) {
result = tmQueue->sendToDefault(message); result = tmQueue->sendToDefault(message);
if(result != HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK){
tmPool->deleteData(message->getStorageId()); tmStore->deleteData(message->getStorageId());
sif::error << "TmFunnel::handlePacket: Error sending to downlink " sif::error << "TmFunnel::handlePacket: Error sending to downlink "
"handler" << std::endl; "handler" << std::endl;
return result; return result;
@ -68,7 +69,7 @@ ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) {
if(storageDestination != objects::NO_OBJECT) { if(storageDestination != objects::NO_OBJECT) {
result = storageQueue->sendToDefault(message); result = storageQueue->sendToDefault(message);
if(result != HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK){
tmPool->deleteData(message->getStorageId()); tmStore->deleteData(message->getStorageId());
sif::error << "TmFunnel::handlePacket: Error sending to storage " sif::error << "TmFunnel::handlePacket: Error sending to storage "
"handler" << std::endl; "handler" << std::endl;
return result; return result;
@ -79,8 +80,8 @@ ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) {
ReturnValue_t TmFunnel::initialize() { ReturnValue_t TmFunnel::initialize() {
tmPool = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE); tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
if(tmPool == nullptr) { if(tmStore == nullptr) {
sif::error << "TmFunnel::initialize: TM store not set." sif::error << "TmFunnel::initialize: TM store not set."
<< std::endl; << std::endl;
sif::error << "Make sure the tm store is set up properly" sif::error << "Make sure the tm store is set up properly"
@ -97,7 +98,13 @@ ReturnValue_t TmFunnel::initialize() {
"properly and implements AcceptsTelemetryIF" << std::endl; "properly and implements AcceptsTelemetryIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
#if OBSW_TM_TO_PTME == 1
// Live TM will be sent via the virtual channel 0
tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue(config::LIVE_TM));
#else
tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue()); tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue());
#endif /* OBSW_TM_TO_PTME == 1 */
// Storage destination is optional. // Storage destination is optional.
if(storageDestination == objects::NO_OBJECT) { if(storageDestination == objects::NO_OBJECT) {

View File

@ -41,7 +41,7 @@ private:
MessageQueueIF* tmQueue = nullptr; MessageQueueIF* tmQueue = nullptr;
MessageQueueIF* storageQueue = nullptr; MessageQueueIF* storageQueue = nullptr;
StorageManagerIF* tmPool = nullptr; StorageManagerIF* tmStore = nullptr;
uint32_t messageDepth = 0; uint32_t messageDepth = 0;
ReturnValue_t handlePacket(TmTcMessage* message); ReturnValue_t handlePacket(TmTcMessage* message);

View File

@ -2,10 +2,12 @@
echo "Setting up all Q7S ports" echo "Setting up all Q7S ports"
echo "-L 1534:192.168.133.10:1534 for connection to TCF agent" echo "-L 1534:192.168.133.10:1534 for connection to TCF agent"
echo "-L 1535:192.168.133.10:22 for file transfers" echo "-L 1535:192.168.133.10:22 for file transfers"
echo "-L 1536:192.168.133.10:7301 for TMTC commanding" echo "-L 1536:192.168.133.10:7301 for TMTC commanding using the TCP/IP IF"
echo "-L 1537:127.0.0.1:7100 for TMTC commanding using the CCSDS IF"
ssh -L 1534:192.168.133.10:1534 \ ssh -L 1534:192.168.133.10:1534 \
-L 1535:192.168.133.10:22 \ -L 1535:192.168.133.10:22 \
-L 1536:192.168.133.10:7301 \ -L 1536:192.168.133.10:7301 \
-L 1537:127.0.0.1:7100 \
eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 \ eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 \
-t 'CONSOLE_PREFIX="[Q7S Tunnel]" /bin/bash' -t 'CONSOLE_PREFIX="[Q7S Tunnel]" /bin/bash'

2
tmtc

@ -1 +1 @@
Subproject commit 56717935e6d90e8a501894f44cd250aec8d12d03 Subproject commit 7b49babb1febb3959f0f817aa4b4ce4c32d6d21c