diff --git a/README.md b/README.md
index 6ad16a87..7d27b092 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
13. [Eclipse](#eclipse)
14. [Running the OBSW on a Raspberry Pi](#rpi)
15. [FSFW](#fsfw)
+16. [Coding Style](#coding-style)
# General information
@@ -1151,3 +1152,15 @@ git merge upstream/master
Alternatively, changes from other upstreams (forks) and branches can be merged like that
in the same way.
+
+# Coding Style
+* the formatting is based on the clang-format tools
+## Setting up eclipse auto-fromatter with clang-format
+1. Help → Install New Software → Add
+2. In location insert the link http://www.cppstyle.com/luna
+3. The software package CppStyle should now be available for installation
+4. On windows download the clang-formatting tools from https://llvm.org/builds/. On linux clang-format can be installed with the package manager.
+5. Navigate to Preferences → C/C++ → CppStyle
+6. Insert the path to the clang-format executable
+7. Under C/C++ → Code Style → Formatter, change the formatter to CppStyle (clang-format)
+8. Code can now be formatted with the clang tool by using the key combination Ctrl + Shift + f
\ No newline at end of file
diff --git a/apply-clang-format.sh b/apply-clang-format.sh
deleted file mode 100755
index 6d77c6e9..00000000
--- a/apply-clang-format.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-if [[ ! -f README.md ]]; then
- cd ..
-fi
-
-find ./mission -iname *.h o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
-find ./linux -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
-find ./bsp_q7s -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
-find ./bsp_linux_board -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
-find ./bsp_hosted -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
-find ./test -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
diff --git a/bsp_q7s/boardconfig/busConf.h b/bsp_q7s/boardconfig/busConf.h
index e41ed093..2083ac6b 100644
--- a/bsp_q7s/boardconfig/busConf.h
+++ b/bsp_q7s/boardconfig/busConf.h
@@ -3,20 +3,30 @@
namespace q7s {
-static constexpr char SPI_DEFAULT_DEV[] = "/dev/spidev2.0";
-static constexpr char SPI_RW_DEV[] = "/dev/spidev3.0";
+static constexpr char SPI_DEFAULT_DEV[] = "/dev/spi-main";
+static constexpr char SPI_RW_DEV[] = "/dev/spi-rw";
-static constexpr char I2C_DEFAULT_DEV[] = "/dev/i2c-1";
+static constexpr char I2C_DEFAULT_DEV[] = "/dev/i2c-eive";
-static constexpr char UART_GNSS_DEV[] = "/dev/ttyUL0";
-static constexpr char UART_PLOC_MPSOC_DEV[] = "/dev/ttyUL2";
-static constexpr char UART_PLOC_SUPERVSIOR_DEV[] = "/dev/ttyUL3";
-static constexpr char UART_SYRLINKS_DEV[] = "/dev/ttyUL4";
-static constexpr char UART_STAR_TRACKER_DEV[] = "/dev/ttyUL7";
+static constexpr char UART_GNSS_DEV[] = "/dev/ul-gps";
+static constexpr char UART_PLOC_MPSOC_DEV[] = "/dev/ul-plmpsoc";
+static constexpr char UART_PLOC_SUPERVSIOR_DEV[] = "/dev/ul-plsv";
+static constexpr char UART_SYRLINKS_DEV[] = "/dev/ul-syrlinks";
+static constexpr char UART_STAR_TRACKER_DEV[] = "/dev/ul-str";
static constexpr char UIO_PDEC_REGISTERS[] = "/dev/uio0";
static constexpr char UIO_PDEC_CONFIG_MEMORY[] = "/dev/uio2";
static constexpr char UIO_PDEC_RAM[] = "/dev/uio3";
+static constexpr char UIO_PTME[] = "/dev/uio1";
+static constexpr int MAP_ID_PTME_CONFIG = 3;
+
+namespace uiomapids {
+static const int PTME_VC0 = 0;
+static const int PTME_VC1 = 1;
+static const int PTME_VC2 = 2;
+static const int PTME_VC3 = 3;
+static const int PTME_CONFIG = 4;
+} // namespace uiomapids
namespace gpioNames {
static constexpr char GYRO_0_ADIS_CS[] = "gyro_0_adis_chip_select";
@@ -33,6 +43,7 @@ static constexpr char GNSS_0_ENABLE[] = "enable_gnss_0";
static constexpr char GNSS_1_ENABLE[] = "enable_gnss_1";
static constexpr char GYRO_0_ENABLE[] = "enable_gyro_0";
static constexpr char GYRO_2_ENABLE[] = "enable_gyro_2";
+static constexpr char GNSS_SELECT[] = "gnss_mux_select";
static constexpr char HEATER_0[] = "heater0";
static constexpr char HEATER_1[] = "heater1";
static constexpr char HEATER_2[] = "heater2";
@@ -69,7 +80,6 @@ static constexpr char RS485_EN_TX_DATA[] = "tx_data_enable_ltc2872";
static constexpr char RS485_EN_RX_CLOCK[] = "rx_clock_enable_ltc2872";
static constexpr char RS485_EN_RX_DATA[] = "rx_data_enable_ltc2872";
static constexpr char PDEC_RESET[] = "pdec_reset";
-static constexpr char BIT_RATE_SEL[] = "bit_rate_sel";
} // namespace gpioNames
} // namespace q7s
diff --git a/bsp_q7s/callbacks/CMakeLists.txt b/bsp_q7s/callbacks/CMakeLists.txt
index 8c83e26f..a85bf6fb 100644
--- a/bsp_q7s/callbacks/CMakeLists.txt
+++ b/bsp_q7s/callbacks/CMakeLists.txt
@@ -1,4 +1,5 @@
target_sources(${TARGET_NAME} PRIVATE
rwSpiCallback.cpp
gnssCallback.cpp
+ pcduSwitchCb.cpp
)
diff --git a/bsp_q7s/callbacks/pcduSwitchCb.cpp b/bsp_q7s/callbacks/pcduSwitchCb.cpp
new file mode 100644
index 00000000..ec5f4dc5
--- /dev/null
+++ b/bsp_q7s/callbacks/pcduSwitchCb.cpp
@@ -0,0 +1,32 @@
+#include "pcduSwitchCb.h"
+
+#include
+
+#include "devices/gpioIds.h"
+
+void pcdu::switchCallback(GOMSPACE::Pdu pdu, uint8_t channel, bool state, void* args) {
+ LinuxLibgpioIF* gpioComIF = reinterpret_cast(args);
+ if (gpioComIF == nullptr) {
+ return;
+ }
+ if (pdu == GOMSPACE::Pdu::PDU1) {
+ PDU1::SwitchChannels typedChannel = static_cast(channel);
+ if (typedChannel == PDU1::SwitchChannels::ACS_A_SIDE) {
+ if (state) {
+ gpioComIF->pullHigh(gpioIds::GNSS_0_NRESET);
+ } else {
+ gpioComIF->pullLow(gpioIds::GNSS_0_NRESET);
+ }
+ }
+
+ } else if (pdu == GOMSPACE::Pdu::PDU2) {
+ PDU2::SwitchChannels typedChannel = static_cast(channel);
+ if (typedChannel == PDU2::SwitchChannels::ACS_B_SIDE) {
+ if (state) {
+ gpioComIF->pullHigh(gpioIds::GNSS_1_NRESET);
+ } else {
+ gpioComIF->pullLow(gpioIds::GNSS_1_NRESET);
+ }
+ }
+ }
+}
diff --git a/bsp_q7s/callbacks/pcduSwitchCb.h b/bsp_q7s/callbacks/pcduSwitchCb.h
new file mode 100644
index 00000000..d0f2b748
--- /dev/null
+++ b/bsp_q7s/callbacks/pcduSwitchCb.h
@@ -0,0 +1,14 @@
+#ifndef BSP_Q7S_CALLBACKS_PCDUSWITCHCB_H_
+#define BSP_Q7S_CALLBACKS_PCDUSWITCHCB_H_
+
+#include
+
+#include "mission/devices/devicedefinitions/GomspaceDefinitions.h"
+
+namespace pcdu {
+
+void switchCallback(GOMSPACE::Pdu pdu, uint8_t channel, bool state, void* args);
+
+}
+
+#endif /* BSP_Q7S_CALLBACKS_PCDUSWITCHCB_H_ */
diff --git a/bsp_q7s/core/InitMission.cpp b/bsp_q7s/core/InitMission.cpp
index a5b2b548..cb01496c 100644
--- a/bsp_q7s/core/InitMission.cpp
+++ b/bsp_q7s/core/InitMission.cpp
@@ -115,12 +115,14 @@ void initmission::initTasks() {
}
#endif /* OBSW_USE_CCSDS_IP_CORE == 1 */
+#if OBSW_ADD_ACS_HANDLERS == 1
PeriodicTaskIF* acsCtrl = factory->createPeriodicTask(
- "ACS_CTRL", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.4, missedDeadlineFunc);
+ "ACS_CTRL", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.4, missedDeadlineFunc);
result = acsCtrl->addComponent(objects::GPS_CONTROLLER);
if (result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("ACS_CTRL", objects::GPS_CONTROLLER);
}
+#endif /* OBSW_ADD_ACS_HANDLERS */
#if BOARD_TE0720 == 0
// FS task, task interval does not matter because it runs in permanent loop, priority low
@@ -134,10 +136,10 @@ void initmission::initTasks() {
#if OBSW_ADD_STAR_TRACKER == 1
PeriodicTaskIF* strImgLoaderTask = factory->createPeriodicTask(
- "FILE_SYSTEM_TASK", 20, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
+ "STR_HELPER", 20, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
result = strImgLoaderTask->addComponent(objects::STR_HELPER);
if (result != HasReturnvaluesIF::RETURN_OK) {
- initmission::printAddObjectError("FILE_SYSTEM_TASK", objects::STR_HELPER);
+ initmission::printAddObjectError("STR_HELPER", objects::STR_HELPER);
}
#endif /* OBSW_ADD_STAR_TRACKER == 1 */
@@ -206,7 +208,9 @@ void initmission::initTasks() {
#endif /* OBSW_ADD_STAR_TRACKER == 1 */
#endif
- //acsCtrl->startTask();
+#if OBSW_ADD_ACS_HANDLERS == 1
+ acsCtrl->startTask();
+#endif
sif::info << "Tasks started.." << std::endl;
}
@@ -250,6 +254,7 @@ void initmission::createPstTasks(TaskFactory& factory,
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "InitMission::initTasks: Creating PST failed!" << std::endl;
}
+ taskVec.push_back(i2cPst);
FixedTimeslotTaskIF* gomSpacePstTask = factory.createFixedTimeslotTask(
"GS_PST_TASK", 70, PeriodicTaskIF::MINIMUM_STACK_SIZE * 4, 1.0, missedDeadlineFunc);
@@ -258,7 +263,7 @@ void initmission::createPstTasks(TaskFactory& factory,
sif::error << "InitMission::initTasks: GomSpace PST initialization failed!" << std::endl;
}
taskVec.push_back(gomSpacePstTask);
-#else /* BOARD_TE7020 == 0 */
+#else /* BOARD_TE7020 == 0 */
FixedTimeslotTaskIF* pollingSequenceTaskTE0720 = factory.createFixedTimeslotTask(
"PST_TASK_TE0720", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE * 8, 3.0, missedDeadlineFunc);
result = pst::pollingSequenceTE0720(pollingSequenceTaskTE0720);
diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp
index 477976d0..13a1624c 100644
--- a/bsp_q7s/core/ObjectFactory.cpp
+++ b/bsp_q7s/core/ObjectFactory.cpp
@@ -5,6 +5,7 @@
#include "OBSWConfig.h"
#include "bsp_q7s/boardtest/Q7STestTask.h"
#include "bsp_q7s/callbacks/gnssCallback.h"
+#include "bsp_q7s/callbacks/pcduSwitchCb.h"
#include "bsp_q7s/callbacks/rwSpiCallback.h"
#include "bsp_q7s/core/CoreController.h"
#include "bsp_q7s/devices/PlocMemoryDumper.h"
@@ -44,7 +45,7 @@
#include "linux/devices/devicedefinitions/SusDefinitions.h"
#include "mission/core/GenericFactory.h"
#include "mission/devices/ACUHandler.h"
-#include "mission/devices/GPSHyperionHandler.h"
+#include "mission/devices/GPSHyperionLinuxController.h"
#include "mission/devices/GyroADIS1650XHandler.h"
#include "mission/devices/HeaterHandler.h"
#include "mission/devices/IMTQHandler.h"
@@ -74,12 +75,11 @@
#include "linux/boardtest/LibgpiodTest.h"
#endif
+#include
#include
#include
#include
#include
-#include
-#include
ResetArgs resetArgsGnss0;
ResetArgs resetArgsGnss1;
@@ -122,13 +122,14 @@ void ObjectFactory::produce(void* args) {
#if BOARD_TE0720 == 0
new CoreController(objects::CORE_CONTROLLER);
- createPcduComponents();
+ createPcduComponents(gpioComIF);
createRadSensorComponent(gpioComIF);
createSunSensorComponents(gpioComIF, spiComIF);
#if OBSW_ADD_ACS_BOARD == 1
createAcsBoardComponents(gpioComIF, uartComIF);
-#endif /* OBSW_ADD_ACS_BOARD == 1 */
+#endif
+
createHeaterComponents();
createSolarArrayDeploymentComponents();
#if OBSW_ADD_SYRLINKS == 1
@@ -139,9 +140,18 @@ void ObjectFactory::produce(void* args) {
createRtdComponents(gpioComIF);
#endif /* OBSW_ADD_RTD_DEVICES == 1 */
+#if OBSW_ADD_MGT == 1
I2cCookie* imtqI2cCookie =
new I2cCookie(addresses::IMTQ, IMTQ::MAX_REPLY_SIZE, q7s::I2C_DEFAULT_DEV);
- new IMTQHandler(objects::IMTQ_HANDLER, objects::I2C_COM_IF, imtqI2cCookie);
+ auto imtqHandler = new IMTQHandler(objects::IMTQ_HANDLER, objects::I2C_COM_IF, imtqI2cCookie);
+ static_cast(imtqHandler);
+#if OBSW_DEBUG_IMTQ == 1
+ imtqHandler->setToGoToNormal(true);
+ imtqHandler->setStartUpImmediately();
+#else
+ (void)imtqHandler;
+#endif
+#endif
createReactionWheelComponents(gpioComIF);
I2cCookie* bpxI2cCookie = new I2cCookie(addresses::BPX_BATTERY, 100, q7s::I2C_DEFAULT_DEV);
@@ -236,7 +246,7 @@ void ObjectFactory::createCommunicationInterfaces(LinuxLibgpioIF** gpioComIF, Ua
#endif
}
-void ObjectFactory::createPcduComponents() {
+void ObjectFactory::createPcduComponents(LinuxLibgpioIF* gpioComIF) {
CspCookie* p60DockCspCookie = new CspCookie(P60Dock::MAX_REPLY_LENGTH, addresses::P60DOCK);
CspCookie* pdu1CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, addresses::PDU1);
CspCookie* pdu2CspCookie = new CspCookie(PDU::MAX_REPLY_LENGTH, addresses::PDU2);
@@ -246,8 +256,10 @@ void ObjectFactory::createPcduComponents() {
new P60DockHandler(objects::P60DOCK_HANDLER, objects::CSP_COM_IF, p60DockCspCookie);
PDU1Handler* pdu1handler =
new PDU1Handler(objects::PDU1_HANDLER, objects::CSP_COM_IF, pdu1CspCookie);
+ pdu1handler->assignChannelHookFunction(&pcdu::switchCallback, gpioComIF);
PDU2Handler* pdu2handler =
new PDU2Handler(objects::PDU2_HANDLER, objects::CSP_COM_IF, pdu2CspCookie);
+ pdu2handler->assignChannelHookFunction(&pcdu::switchCallback, gpioComIF);
ACUHandler* acuhandler = new ACUHandler(objects::ACU_HANDLER, objects::CSP_COM_IF, acuCspCookie);
new PCDUHandler(objects::PCDU_HANDLER, 50);
@@ -472,8 +484,15 @@ void ObjectFactory::createAcsBoardComponents(LinuxLibgpioIF* gpioComIF, UartComI
gpio::LOW);
gpioCookieAcsBoard->addGpio(gpioIds::GNSS_1_ENABLE, gpio);
+ // Select pin. 0 for GPS side A, 1 for GPS side B
+ consumer.str("");
+ consumer << "0x" << std::hex << objects::GPS_CONTROLLER;
+ gpio = new GpiodRegularByLineName(q7s::gpioNames::GNSS_SELECT, consumer.str(), gpio::DIR_OUT,
+ gpio::LOW);
+ gpioCookieAcsBoard->addGpio(gpioIds::GNSS_SELECT, gpio);
gpioComIF->addGpios(gpioCookieAcsBoard);
+#if OBSW_ADD_ACS_HANDLERS == 1
std::string spiDev = q7s::SPI_DEFAULT_DEV;
SpiCookie* spiCookie =
new SpiCookie(addresses::MGM_0_LIS3, gpioIds::MGM_0_LIS3_CS, spiDev,
@@ -568,8 +587,10 @@ void ObjectFactory::createAcsBoardComponents(LinuxLibgpioIF* gpioComIF, UartComI
resetArgsGnss0.gnss1 = false;
resetArgsGnss0.gpioComIF = gpioComIF;
resetArgsGnss0.waitPeriodMs = 100;
- auto gpsHandler0 = new GPSHyperionHandler(objects::GPS_CONTROLLER, objects::NO_OBJECT, debugGps);
+ auto gpsHandler0 =
+ new GPSHyperionLinuxController(objects::GPS_CONTROLLER, objects::NO_OBJECT, debugGps);
gpsHandler0->setResetPinTriggerFunction(gps::triggerGpioResetPin, &resetArgsGnss0);
+#endif /* OBSW_ADD_ACS_HANDLERS == 1 */
}
void ObjectFactory::createHeaterComponents() {
@@ -895,49 +916,50 @@ void ObjectFactory::createCcsdsComponents(LinuxLibgpioIF* gpioComIF) {
GpioCookie* gpioCookiePtmeIp = new GpioCookie;
GpiodRegularByLineName* gpio = nullptr;
std::stringstream consumer;
- consumer << "0x" << std::hex << objects::PAPB_VC0;
+ consumer.str("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;
+ consumer.str("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;
+ consumer.str("PAPB VC 1");
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());
+ consumer.str("PAPB VC 1");
gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_EMPTY, gpio);
consumer.str("");
- consumer << "0x" << std::hex << objects::PAPB_VC2;
+ consumer.str("PAPB VC 2");
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;
+ consumer.str("PAPB VC 2");
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;
+ consumer.str("PAPB VC 3");
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;
+ consumer.str("PAPB VC 3");
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);
+ VcInterfaceIF* vc0 =
+ new PapbVcInterface(gpioComIF, gpioIds::VC0_PAPB_BUSY, gpioIds::VC0_PAPB_EMPTY, q7s::UIO_PTME,
+ q7s::uiomapids::PTME_VC0);
+ VcInterfaceIF* vc1 =
+ new PapbVcInterface(gpioComIF, gpioIds::VC1_PAPB_BUSY, gpioIds::VC1_PAPB_EMPTY, q7s::UIO_PTME,
+ q7s::uiomapids::PTME_VC1);
+ VcInterfaceIF* vc2 =
+ new PapbVcInterface(gpioComIF, gpioIds::VC2_PAPB_BUSY, gpioIds::VC2_PAPB_EMPTY, q7s::UIO_PTME,
+ q7s::uiomapids::PTME_VC2);
+ VcInterfaceIF* vc3 =
+ new PapbVcInterface(gpioComIF, gpioIds::VC3_PAPB_BUSY, gpioIds::VC3_PAPB_EMPTY, q7s::UIO_PTME,
+ q7s::uiomapids::PTME_VC3);
// Creating ptme object and adding virtual channel interfaces
Ptme* ptme = new Ptme(objects::PTME);
@@ -946,19 +968,11 @@ void ObjectFactory::createCcsdsComponents(LinuxLibgpioIF* gpioComIF) {
ptme->addVcInterface(ccsds::VC2, vc2);
ptme->addVcInterface(ccsds::VC3, vc3);
- GpioCookie* gpioCookieRateSetter = new GpioCookie;
- consumer.str("");
- consumer << "ptme rate setter";
- // Init to low -> default bit rate is low bit rate (200 kbps in downlink with syrlinks)
- gpio = new GpiodRegularByLineName(q7s::gpioNames::BIT_RATE_SEL, consumer.str(), gpio::DIR_OUT,
- gpio::LOW);
- gpioCookieRateSetter->addGpio(gpioIds::BIT_RATE_SEL, gpio);
- gpioComIF->addGpios(gpioCookieRateSetter);
-
- TxRateSetterIF* txRateSetterIF = new PtmeRateSetter(gpioIds::BIT_RATE_SEL, gpioComIF);
-
+ AxiPtmeConfig* axiPtmeConfig =
+ new AxiPtmeConfig(objects::AXI_PTME_CONFIG, q7s::UIO_PTME, q7s::uiomapids::PTME_CONFIG);
+ PtmeConfig* ptmeConfig = new PtmeConfig(objects::PTME_CONFIG, axiPtmeConfig);
CCSDSHandler* ccsdsHandler = new CCSDSHandler(
- objects::CCSDS_HANDLER, objects::PTME, objects::CCSDS_PACKET_DISTRIBUTOR, txRateSetterIF,
+ objects::CCSDS_HANDLER, objects::PTME, objects::CCSDS_PACKET_DISTRIBUTOR, ptmeConfig,
gpioComIF, gpioIds::RS485_EN_TX_CLOCK, gpioIds::RS485_EN_TX_DATA);
VirtualChannel* vc = nullptr;
@@ -982,8 +996,7 @@ void ObjectFactory::createCcsdsComponents(LinuxLibgpioIF* gpioComIF) {
gpioComIF->addGpios(gpioCookiePdec);
new PdecHandler(objects::PDEC_HANDLER, objects::CCSDS_HANDLER, gpioComIF, gpioIds::PDEC_RESET,
- std::string(q7s::UIO_PDEC_CONFIG_MEMORY), std::string(q7s::UIO_PDEC_RAM),
- std::string(q7s::UIO_PDEC_REGISTERS));
+ q7s::UIO_PDEC_CONFIG_MEMORY, q7s::UIO_PDEC_RAM, q7s::UIO_PDEC_REGISTERS);
#if BOARD_TE0720 == 0
GpioCookie* gpioRS485Chip = new GpioCookie;
diff --git a/bsp_q7s/core/ObjectFactory.h b/bsp_q7s/core/ObjectFactory.h
index 47e06e33..8fa4a147 100644
--- a/bsp_q7s/core/ObjectFactory.h
+++ b/bsp_q7s/core/ObjectFactory.h
@@ -13,7 +13,7 @@ void produce(void* args);
void createCommunicationInterfaces(LinuxLibgpioIF** gpioComIF, UartComIF** uartComIF,
SpiComIF** spiComIF);
void createTmpComponents();
-void createPcduComponents();
+void createPcduComponents(LinuxLibgpioIF* gpioComIF);
void createRadSensorComponent(LinuxLibgpioIF* gpioComIF);
void createSunSensorComponents(LinuxLibgpioIF* gpioComIF, SpiComIF* spiComIF);
void createAcsBoardComponents(LinuxLibgpioIF* gpioComIF, UartComIF* uartComIF);
diff --git a/common/config/commonClassIds.h b/common/config/commonClassIds.h
index cd90272d..ab8e06d5 100644
--- a/common/config/commonClassIds.h
+++ b/common/config/commonClassIds.h
@@ -24,6 +24,7 @@ enum commonClassIds: uint8_t {
PLOC_MEMORY_DUMPER, //PLMEMDUMP
PDEC_HANDLER, //PDEC
CCSDS_HANDLER, //CCSDS
+ RATE_SETTER, //RS
ARCSEC_JSON_BASE, //JSONBASE
NVM_PARAM_BASE, //NVMB
COMMON_CLASS_ID_END // [EXPORT] : [END]
diff --git a/common/config/commonObjects.h b/common/config/commonObjects.h
index 135259d6..bd364daf 100644
--- a/common/config/commonObjects.h
+++ b/common/config/commonObjects.h
@@ -12,11 +12,7 @@ enum commonObjects: uint32_t {
TMTC_POLLING_TASK = 0x50000400,
FILE_SYSTEM_HANDLER = 0x50000500,
PTME = 0x50000600,
- PAPB_VC0 = 0x50000700,
- PAPB_VC1 = 0x50000701,
- PAPB_VC2 = 0x50000702,
- PAPB_VC3 = 0x50000703,
- PDEC_HANDLER = 0x50000704,
+ PDEC_HANDLER = 0x50000700,
CCSDS_HANDLER = 0x50000800,
/* 0x43 ('C') for Controllers */
@@ -90,7 +86,9 @@ enum commonObjects: uint32_t {
PLOC_UPDATER = 0x44330000,
PLOC_MEMORY_DUMPER = 0x44330001,
- STR_HELPER = 0x44330002
+ STR_HELPER = 0x44330002,
+ AXI_PTME_CONFIG = 44330003,
+ PTME_CONFIG = 44330004,
};
}
diff --git a/fsfw b/fsfw
index 9b770602..33386550 160000
--- a/fsfw
+++ b/fsfw
@@ -1 +1 @@
-Subproject commit 9b77060295c9c32ebfc2e7cf6517eb2e66216191
+Subproject commit 33386550cf81e47f4a3c95cd063349442dd83d09
diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in
index ea26425b..324481c5 100644
--- a/linux/fsfwconfig/OBSWConfig.h.in
+++ b/linux/fsfwconfig/OBSWConfig.h.in
@@ -39,35 +39,21 @@ debugging. */
// Set to 1 if telecommands are received via the PDEC IP Core
#define OBSW_TC_FROM_PDEC 1
-#define TMTC_TEST_SETUP 1
-
#define OBSW_ENABLE_TIMERS 1
+#define OBSW_ADD_MGT 1
#define OBSW_ADD_STAR_TRACKER 0
#define OBSW_ADD_PLOC_SUPERVISOR 0
#define OBSW_ADD_PLOC_MPSOC 0
#define OBSW_ADD_SUN_SENSORS 0
-#define OBSW_ADD_ACS_BOARD 0
-#define OBSW_ADD_RW 0
-#define OBSW_ADD_RTD_DEVICES 0
-#define OBSW_ADD_TMP_DEVICES 0
-#define OBSW_ADD_RAD_SENSORS 0
-#define OBSW_ADD_SYRLINKS 0
-
-#elif defined RASPBERRY_PI
-
-#define OBSW_ENABLE_TIMERS 1
-#define OBSW_ADD_STAR_TRACKER 0
-#define OBSW_ADD_PLOC_SUPERVISOR 0
-#define OBSW_ADD_PLOC_MPSOC 0
-#define OBSW_ADD_SUN_SENSORS 0
-#define OBSW_ADD_ACS_BOARD 0
-#define OBSW_ADD_GPS_0 0
-#define OBSW_ADD_GPS_1 0
+#define OBSW_ADD_ACS_BOARD 1
+#define OBSW_ADD_ACS_HANDLERS 0
#define OBSW_ADD_RW 0
#define OBSW_ADD_RTD_DEVICES 0
#define OBSW_ADD_TMP_DEVICES 0
#define OBSW_ADD_RAD_SENSORS 0
#define OBSW_ADD_SYRLINKS 0
+#define OBSW_ENABLE_SYRLINKS_TRANSMIT_TIMEOUT 0
+#define OBSW_SYRLINKS_SIMULATED 1
#endif
@@ -78,6 +64,7 @@ debugging. */
//! /* Can be used to switch device to NORMAL mode immediately */
#define OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP 1
#define OBSW_PRINT_MISSED_DEADLINES 1
+
// If this is enabled, all other SPI code should be disabled
#define OBSW_ADD_TEST_CODE 0
#define OBSW_ADD_SPI_TEST_CODE 0
@@ -99,7 +86,7 @@ debugging. */
#define OBSW_DEBUG_GPS 0
#define OBSW_DEBUG_ACU 0
#define OBSW_DEBUG_SYRLINKS 0
-#define OBSW_DEBUG_IMQT 0
+#define OBSW_DEBUG_IMTQ 0
#define OBSW_DEBUG_RAD_SENSOR 0
#define OBSW_DEBUG_SUS 0
#define OBSW_DEBUG_RTD 0
@@ -109,6 +96,24 @@ debugging. */
#define OBSW_DEBUG_PLOC_SUPERVISOR 0
#define OBSW_DEBUG_PDEC_HANDLER 0
+#ifdef RASPBERRY_PI
+
+#define OBSW_ENABLE_TIMERS 1
+#define OBSW_ADD_STAR_TRACKER 0
+#define OBSW_ADD_PLOC_SUPERVISOR 0
+#define OBSW_ADD_PLOC_MPSOC 0
+#define OBSW_ADD_SUN_SENSORS 0
+#define OBSW_ADD_ACS_BOARD 0
+#define OBSW_ADD_GPS_0 0
+#define OBSW_ADD_GPS_1 0
+#define OBSW_ADD_RW 0
+#define OBSW_ADD_RTD_DEVICES 0
+#define OBSW_ADD_TMP_DEVICES 0
+#define OBSW_ADD_RAD_SENSORS 0
+#define OBSW_ADD_SYRLINKS 0
+
+#endif
+
/*******************************************************************/
/** Hardcoded */
/*******************************************************************/
diff --git a/linux/fsfwconfig/devices/addresses.h b/linux/fsfwconfig/devices/addresses.h
index 3405eb47..a69cdaf9 100644
--- a/linux/fsfwconfig/devices/addresses.h
+++ b/linux/fsfwconfig/devices/addresses.h
@@ -46,9 +46,9 @@ enum logicalAddresses : address_t {
enum i2cAddresses : address_t {
BPX_BATTERY = 0x07,
- IMTQ = 16,
- TMP1075_TCS_1 = 72,
- TMP1075_TCS_2 = 73,
+ IMTQ = 0x10,
+ TMP1075_TCS_1 = 0x48,
+ TMP1075_TCS_2 = 0x49,
};
enum spiAddresses : address_t {
diff --git a/linux/fsfwconfig/devices/gpioIds.h b/linux/fsfwconfig/devices/gpioIds.h
index bb753a30..46717569 100644
--- a/linux/fsfwconfig/devices/gpioIds.h
+++ b/linux/fsfwconfig/devices/gpioIds.h
@@ -29,6 +29,7 @@ enum gpioId_t {
GNSS_1_NRESET,
GNSS_0_ENABLE,
GNSS_1_ENABLE,
+ GNSS_SELECT,
GYRO_0_ENABLE,
GYRO_2_ENABLE,
diff --git a/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp b/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp
index 814e5c2d..70119272 100644
--- a/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp
+++ b/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp
@@ -435,7 +435,7 @@ ReturnValue_t pst::pstSpi(FixedTimeslotTaskIF *thisSequence) {
thisSequence->addSlot(objects::RW4, length * 0.8, DeviceHandlerIF::GET_READ);
#endif
-#if OBSW_ADD_ACS_BOARD == 1
+#if OBSW_ADD_ACS_BOARD == 1 && OBSW_ADD_ACS_HANDLERS == 1
bool enableAside = true;
bool enableBside = false;
if (enableAside) {
@@ -501,7 +501,7 @@ ReturnValue_t pst::pstSpi(FixedTimeslotTaskIF *thisSequence) {
thisSequence->addSlot(objects::GYRO_3_L3G_HANDLER, length * 0.75, DeviceHandlerIF::SEND_READ);
thisSequence->addSlot(objects::GYRO_3_L3G_HANDLER, length * 0.85, DeviceHandlerIF::GET_READ);
}
-#endif /* OBSW_ADD_ACS_BOARD == 1 */
+#endif /* OBSW_ADD_ACS_BOARD == 1 && OBSW_ADD_ACS_HANDLERS == 1 */
ReturnValue_t seqCheck = thisSequence->checkSequence();
if (seqCheck != HasReturnvaluesIF::RETURN_OK) {
@@ -519,11 +519,13 @@ ReturnValue_t pst::pstSpi(FixedTimeslotTaskIF *thisSequence) {
ReturnValue_t pst::pstI2c(FixedTimeslotTaskIF *thisSequence) {
// Length of a communication cycle
uint32_t length = thisSequence->getPeriodMs();
+#if OBSW_ADD_MGT == 1
thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION);
thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.2, DeviceHandlerIF::SEND_WRITE);
thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE);
thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ);
thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ);
+#endif
if (thisSequence->checkSequence() != HasReturnvaluesIF::RETURN_OK) {
sif::error << "I2C PST initialization failed" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
diff --git a/linux/obc/AxiPtmeConfig.cpp b/linux/obc/AxiPtmeConfig.cpp
new file mode 100644
index 00000000..26830d05
--- /dev/null
+++ b/linux/obc/AxiPtmeConfig.cpp
@@ -0,0 +1,119 @@
+#include "AxiPtmeConfig.h"
+
+#include "fsfw/serviceinterface/ServiceInterface.h"
+#include "fsfw_hal/linux/uio/UioMapper.h"
+
+AxiPtmeConfig::AxiPtmeConfig(object_id_t objectId, std::string axiUio, int mapNum)
+ : SystemObject(objectId), axiUio(axiUio), mapNum(mapNum) {
+ mutex = MutexFactory::instance()->createMutex();
+ if (mutex == nullptr) {
+ sif::warning << "Failed to create mutex" << std::endl;
+ }
+}
+
+AxiPtmeConfig::~AxiPtmeConfig() {}
+
+ReturnValue_t AxiPtmeConfig::initialize() {
+ ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
+ UioMapper uioMapper(axiUio, mapNum);
+ result = uioMapper.getMappedAdress(&baseAddress, UioMapper::Permissions::READ_WRITE);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t AxiPtmeConfig::writeCaduRateReg(uint8_t rateVal) {
+ ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
+ result = mutex->lockMutex(timeoutType, mutexTimeout);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ sif::warning << "AxiPtmeConfig::writeCaduRateReg: Failed to lock mutex" << std::endl;
+ return HasReturnvaluesIF::RETURN_FAILED;
+ }
+ *(baseAddress + CADU_BITRATE_REG) = static_cast(rateVal);
+ result = mutex->unlockMutex();
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ sif::warning << "AxiPtmeConfig::writeCaduRateReg: Failed to unlock mutex" << std::endl;
+ return HasReturnvaluesIF::RETURN_FAILED;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t AxiPtmeConfig::enableTxclockManipulator() {
+ ReturnValue_t result = writeBit(COMMON_CONFIG_REG, true, BitPos::EN_TX_CLK_MANIPULATOR);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t AxiPtmeConfig::disableTxclockManipulator() {
+ ReturnValue_t result = writeBit(COMMON_CONFIG_REG, false, BitPos::EN_TX_CLK_MANIPULATOR);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t AxiPtmeConfig::enableTxclockInversion() {
+ ReturnValue_t result = writeBit(COMMON_CONFIG_REG, true, BitPos::INVERT_CLOCK);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t AxiPtmeConfig::disableTxclockInversion() {
+ ReturnValue_t result = writeBit(COMMON_CONFIG_REG, false, BitPos::INVERT_CLOCK);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t AxiPtmeConfig::writeReg(uint32_t regOffset, uint32_t writeVal) {
+ ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
+ result = mutex->lockMutex(timeoutType, mutexTimeout);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ sif::warning << "AxiPtmeConfig::readReg: Failed to lock mutex" << std::endl;
+ return HasReturnvaluesIF::RETURN_FAILED;
+ }
+ *(baseAddress + regOffset / ADRESS_DIVIDER) = writeVal;
+ result = mutex->unlockMutex();
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ sif::warning << "AxiPtmeConfig::readReg: Failed to unlock mutex" << std::endl;
+ return HasReturnvaluesIF::RETURN_FAILED;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t AxiPtmeConfig::readReg(uint32_t regOffset, uint32_t* readVal) {
+ ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
+ result = mutex->lockMutex(timeoutType, mutexTimeout);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ sif::warning << "AxiPtmeConfig::readReg: Failed to lock mutex" << std::endl;
+ return HasReturnvaluesIF::RETURN_FAILED;
+ }
+ *readVal = *(baseAddress + regOffset / ADRESS_DIVIDER);
+ result = mutex->unlockMutex();
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ sif::warning << "AxiPtmeConfig::readReg: Failed to unlock mutex" << std::endl;
+ return HasReturnvaluesIF::RETURN_FAILED;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t AxiPtmeConfig::writeBit(uint32_t regOffset, bool bitVal, BitPos bitPos) {
+ uint32_t readVal = 0;
+ ReturnValue_t result = readReg(regOffset, &readVal);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
+ uint32_t writeVal =
+ (readVal & ~(1 << static_cast(bitPos))) | bitVal << static_cast(bitPos);
+ result = writeReg(regOffset, writeVal);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
diff --git a/linux/obc/AxiPtmeConfig.h b/linux/obc/AxiPtmeConfig.h
new file mode 100644
index 00000000..c86bb429
--- /dev/null
+++ b/linux/obc/AxiPtmeConfig.h
@@ -0,0 +1,99 @@
+#ifndef LINUX_OBC_AXIPTMECONFIG_H_
+#define LINUX_OBC_AXIPTMECONFIG_H_
+
+#include
+
+#include "fsfw/ipc/MutexIF.h"
+#include "fsfw/objectmanager/SystemObject.h"
+#include "fsfw/returnvalues/HasReturnvaluesIF.h"
+
+/**
+ * @brief Class providing low level access to the configuration interface of the PTME.
+ *
+ * @author J. Meier
+ */
+class AxiPtmeConfig : public SystemObject {
+ public:
+ /**
+ * @brief Constructor
+ * @param axiUio Device file of UIO belonging to the AXI configuration interface.
+ * @param mapNum Number of map belonging to axi configuration interface.
+ */
+ AxiPtmeConfig(object_id_t objectId, std::string axiUio, int mapNum);
+ virtual ~AxiPtmeConfig();
+
+ virtual ReturnValue_t initialize() override;
+ /**
+ * @brief Will write to the bitrate configuration register. Actual generated rate depends on
+ * frequency of the clock connected to the bit clock input of PTME.
+ */
+ ReturnValue_t writeCaduRateReg(uint8_t rateVal);
+
+ /**
+ * @brief Next to functions control the tx clock manipulator component
+ *
+ * @details If the tx clock manipulator is enabled the output clock of the PTME is manipulated
+ * in a way that both high and low periods in the clock signal have equal lengths.
+ * The default implementation of the PTME generates a clock where the high level is
+ * only one bit clock period long. This might be too short to match the setup and hold
+ * times of the S-and transceiver.
+ */
+ ReturnValue_t enableTxclockManipulator();
+ ReturnValue_t disableTxclockManipulator();
+
+ /**
+ * @brief The next to functions control whether data will be updated on the rising or falling edge
+ * of the tx clock.
+ * Enable inversion will update data on falling edge (not the configuration required by the
+ * syrlinks)
+ * Disable clock inversion. Data updated on rising edge.
+ */
+ ReturnValue_t enableTxclockInversion();
+ ReturnValue_t disableTxclockInversion();
+
+ private:
+ // Address of register storing the bitrate configuration parameter
+ static const uint32_t CADU_BITRATE_REG = 0x0;
+ // Address to register storing common configuration parameters
+ static const uint32_t COMMON_CONFIG_REG = 0x4;
+ static const uint32_t ADRESS_DIVIDER = 4;
+
+ enum class BitPos : uint32_t { EN_TX_CLK_MANIPULATOR, INVERT_CLOCK };
+
+ std::string axiUio;
+ std::string uioMap;
+ int mapNum = 0;
+ MutexIF* mutex = nullptr;
+ MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
+ uint32_t mutexTimeout = 20;
+
+ uint32_t* baseAddress = nullptr;
+
+ /**
+ * @brief Function to write to configuration registers
+ *
+ * @param writeVal Value to write
+ */
+ ReturnValue_t writeReg(uint32_t regOffset, uint32_t writeVal);
+
+ /**
+ * @brief Reads value from configuration register
+ *
+ * @param regOffset Offset of register from base address to read from
+ * Qparam readVal Pointer to variable where read value will be written to
+ */
+ ReturnValue_t readReg(uint32_t regOffset, uint32_t* readVal);
+
+ /**
+ * @brief Sets one bit in a register
+ *
+ * @param regOffset Offset of the register where to set the bit
+ * @param bitVal The value of the bit to set (1 or 0)
+ * @param bitPos The position of the bit within the register to set
+ *
+ * @return RETURN_OK if successful, otherwise RETURN_FAILED
+ */
+ ReturnValue_t writeBit(uint32_t regOffset, bool bitVal, BitPos bitPos);
+};
+
+#endif /* LINUX_OBC_AXIPTMECONFIG_H_ */
diff --git a/linux/obc/CMakeLists.txt b/linux/obc/CMakeLists.txt
index 4119624c..79e32a78 100644
--- a/linux/obc/CMakeLists.txt
+++ b/linux/obc/CMakeLists.txt
@@ -3,7 +3,8 @@ target_sources(${TARGET_NAME} PUBLIC
Ptme.cpp
PdecHandler.cpp
PdecConfig.cpp
- PtmeRateSetter.cpp
+ PtmeConfig.cpp
+ AxiPtmeConfig.cpp
)
diff --git a/linux/obc/PapbVcInterface.cpp b/linux/obc/PapbVcInterface.cpp
index f144306c..5636975a 100644
--- a/linux/obc/PapbVcInterface.cpp
+++ b/linux/obc/PapbVcInterface.cpp
@@ -1,26 +1,27 @@
+#include
#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),
+PapbVcInterface::PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId,
+ gpioId_t papbEmptyId, std::string uioFile, int mapNum)
+ : gpioComIF(gpioComIF),
papbBusyId(papbBusyId),
papbEmptyId(papbEmptyId),
- vcOffset(vcOffset) {}
+ uioFile(uioFile),
+ mapNum(mapNum) {}
PapbVcInterface::~PapbVcInterface() {}
-void PapbVcInterface::setRegisterAddress(uint32_t* ptmeBaseAddress) {
- vcBaseReg = ptmeBaseAddress + vcOffset;
+ReturnValue_t PapbVcInterface::initialize() {
+ UioMapper uioMapper(uioFile, mapNum);
+ return uioMapper.getMappedAdress(&vcBaseReg, UioMapper::Permissions::WRITE_ONLY);
}
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(*(data + idx));
@@ -30,7 +31,6 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) {
return RETURN_FAILED;
}
}
-
if (pollPapbBusySignal() == RETURN_OK) {
endPacketTransfer();
}
diff --git a/linux/obc/PapbVcInterface.h b/linux/obc/PapbVcInterface.h
index e7d03a70..0d6382e3 100644
--- a/linux/obc/PapbVcInterface.h
+++ b/linux/obc/PapbVcInterface.h
@@ -5,7 +5,6 @@
#include
#include "OBSWConfig.h"
-#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "linux/obc/VcInterfaceIF.h"
@@ -15,26 +14,27 @@
*
* @author J. Meier
*/
-class PapbVcInterface : public SystemObject, public VcInterfaceIF, public HasReturnvaluesIF {
+class PapbVcInterface : 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).
+ * @param uioFile UIO file providing access to the PAPB bus
+ * @param mapNum Map number of UIO map associated with this virtual channel
*/
- PapbVcInterface(object_id_t objectId, LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId,
- gpioId_t papbEmptyId, uint32_t vcOffset);
+ PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId, gpioId_t papbEmptyId,
+ std::string uioFile, int mapNum);
virtual ~PapbVcInterface();
ReturnValue_t write(const uint8_t* data, size_t size) override;
- void setRegisterAddress(uint32_t* ptmeBaseAddress) override;
+ ReturnValue_t initialize() override;
private:
static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_IP_CORE_BRIDGE;
@@ -69,6 +69,9 @@ class PapbVcInterface : public SystemObject, public VcInterfaceIF, public HasRet
/** High when external buffer memory of virtual channel is empty */
gpioId_t papbEmptyId = gpio::NO_GPIO;
+ std::string uioFile;
+ int mapNum = 0;
+
uint32_t* vcBaseReg = nullptr;
uint32_t vcOffset = 0;
diff --git a/linux/obc/PdecHandler.cpp b/linux/obc/PdecHandler.cpp
index a5ee98d6..f97c3965 100644
--- a/linux/obc/PdecHandler.cpp
+++ b/linux/obc/PdecHandler.cpp
@@ -11,6 +11,7 @@
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
+#include "fsfw_hal/linux/uio/UioMapper.h"
PdecHandler::PdecHandler(object_id_t objectId, object_id_t tcDestinationId,
LinuxLibgpioIF* gpioComIF, gpioId_t pdecReset, std::string uioConfigMemory,
@@ -44,17 +45,18 @@ ReturnValue_t PdecHandler::initialize() {
ReturnValue_t result = RETURN_OK;
- result = getRegisterAddress();
+ UioMapper regMapper(uioRegisters);
+ result = regMapper.getMappedAdress(®isterBaseAddress, UioMapper::Permissions::READ_WRITE);
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
-
- result = getConfigMemoryBaseAddress();
+ UioMapper configMemMapper(uioConfigMemory);
+ result = configMemMapper.getMappedAdress(&memoryBaseAddress, UioMapper::Permissions::READ_WRITE);
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
-
- result = getRamBaseAddress();
+ UioMapper ramMapper(uioRamMemory);
+ result = ramMapper.getMappedAdress(&ramBaseAddress, UioMapper::Permissions::READ_WRITE);
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
@@ -76,55 +78,6 @@ ReturnValue_t PdecHandler::initialize() {
MessageQueueId_t PdecHandler::getCommandQueue() const { return commandQueue->getId(); }
-ReturnValue_t PdecHandler::getRegisterAddress() {
- int fd = open(uioRegisters.c_str(), O_RDWR);
- if (fd < 1) {
- sif::warning << "PdecHandler::getRegisterAddress: Invalid UIO device file" << std::endl;
- return RETURN_FAILED;
- }
-
- registerBaseAddress = static_cast(
- mmap(NULL, REGISTER_MAP_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0));
-
- if (registerBaseAddress == MAP_FAILED) {
- sif::error << "PdecHandler::getRegisterAddress: Failed to map uio address" << std::endl;
- return RETURN_FAILED;
- }
-
- return RETURN_OK;
-}
-
-ReturnValue_t PdecHandler::getConfigMemoryBaseAddress() {
- int fd = open(uioConfigMemory.c_str(), O_RDWR);
- if (fd < 1) {
- sif::warning << "PdecHandler::getConfigMemoryBaseAddress: Invalid UIO device file" << std::endl;
- return RETURN_FAILED;
- }
-
- memoryBaseAddress = static_cast(
- mmap(NULL, CONFIG_MEMORY_MAP_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0));
-
- if (memoryBaseAddress == MAP_FAILED) {
- sif::error << "PdecHandler::getConfigMemoryBaseAddress: Failed to map uio address" << std::endl;
- return RETURN_FAILED;
- }
-
- return RETURN_OK;
-}
-
-ReturnValue_t PdecHandler::getRamBaseAddress() {
- int fd = open(uioRamMemory.c_str(), O_RDWR);
-
- ramBaseAddress =
- static_cast(mmap(NULL, RAM_MAP_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0));
-
- if (ramBaseAddress == MAP_FAILED) {
- sif::error << "PdecHandler::getRamBaseAddress: Failed to map RAM base address" << std::endl;
- return RETURN_FAILED;
- }
- return RETURN_OK;
-}
-
void PdecHandler::writePdecConfig() {
PdecConfig pdecConfig;
diff --git a/linux/obc/PdecHandler.h b/linux/obc/PdecHandler.h
index 2125800f..16a9abd4 100644
--- a/linux/obc/PdecHandler.h
+++ b/linux/obc/PdecHandler.h
@@ -231,25 +231,6 @@ class PdecHandler : public SystemObject,
*/
void readCommandQueue(void);
- /**
- * @brief Opens UIO device assigned to AXI to AHB converter giving access to the PDEC
- * registers. The register base address will be mapped into the virtual address space.
- */
- ReturnValue_t getRegisterAddress();
-
- /**
- * @brief Opens UIO device assigned to the base address of the PDEC memory space and maps the
- * physical address into the virtual address space.
- */
- ReturnValue_t getConfigMemoryBaseAddress();
-
- /**
- * @brief Opens UIO device assigned to the RAM section of the PDEC IP core memory map.
- *
- * @details A received TC segment will be written to this memory area.
- */
- ReturnValue_t getRamBaseAddress();
-
/**
* @brief This functions writes the configuration parameters to the configuration
* section of the PDEC.
diff --git a/linux/obc/Ptme.cpp b/linux/obc/Ptme.cpp
index 237e66ab..68ba3924 100644
--- a/linux/obc/Ptme.cpp
+++ b/linux/obc/Ptme.cpp
@@ -1,6 +1,7 @@
#include
#include
#include
+#include
#include "PtmeConfig.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
@@ -10,28 +11,10 @@ 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(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);
+ iter->second->initialize();
}
-
return RETURN_OK;
}
diff --git a/linux/obc/Ptme.h b/linux/obc/Ptme.h
index d85885bc..cdb2d6c6 100644
--- a/linux/obc/Ptme.h
+++ b/linux/obc/Ptme.h
@@ -44,14 +44,6 @@ class Ptme : public PtmeIF, public SystemObject, public HasReturnvaluesIF {
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
diff --git a/linux/obc/PtmeConfig.cpp b/linux/obc/PtmeConfig.cpp
new file mode 100644
index 00000000..9cbda7a6
--- /dev/null
+++ b/linux/obc/PtmeConfig.cpp
@@ -0,0 +1,50 @@
+#include "PtmeConfig.h"
+
+#include "fsfw/serviceinterface/ServiceInterface.h"
+
+PtmeConfig::PtmeConfig(object_id_t objectId, AxiPtmeConfig* axiPtmeConfig)
+ : SystemObject(objectId), axiPtmeConfig(axiPtmeConfig) {}
+
+PtmeConfig::~PtmeConfig() {}
+
+ReturnValue_t PtmeConfig::initialize() {
+ if (axiPtmeConfig == nullptr) {
+ sif::warning << "PtmeConfig::initialize: Invalid AxiPtmeConfig object" << std::endl;
+ return RETURN_FAILED;
+ }
+ return RETURN_OK;
+}
+
+ReturnValue_t PtmeConfig::setRate(uint32_t bitRate) {
+ if (bitRate == 0) {
+ return BAD_BIT_RATE;
+ }
+ uint32_t rateVal = BIT_CLK_FREQ / bitRate - 1;
+ if (rateVal > 0xFF) {
+ return RATE_NOT_SUPPORTED;
+ }
+ return axiPtmeConfig->writeCaduRateReg(static_cast(rateVal));
+}
+
+ReturnValue_t PtmeConfig::invertTxClock(bool invert) {
+ ReturnValue_t result = RETURN_OK;
+ if (invert) {
+ result = axiPtmeConfig->enableTxclockInversion();
+ } else {
+ result = axiPtmeConfig->disableTxclockInversion();
+ }
+ if (result != RETURN_OK) {
+ return CLK_INVERSION_FAILED;
+ }
+ return result;
+}
+
+ReturnValue_t PtmeConfig::configTxManipulator(bool enable) {
+ ReturnValue_t result = RETURN_OK;
+ if (enable) {
+ result = axiPtmeConfig->enableTxclockManipulator();
+ } else {
+ result = axiPtmeConfig->disableTxclockManipulator();
+ }
+ return result;
+}
diff --git a/linux/obc/PtmeConfig.h b/linux/obc/PtmeConfig.h
index b5b722ac..d6e35b57 100644
--- a/linux/obc/PtmeConfig.h
+++ b/linux/obc/PtmeConfig.h
@@ -1,31 +1,76 @@
#ifndef LINUX_OBC_PTMECONFIG_H_
#define LINUX_OBC_PTMECONFIG_H_
-#include
-
-#include "OBSWConfig.h"
+#include "AxiPtmeConfig.h"
+#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
+#include "linux/obc/PtmeConfig.h"
/**
- * @brief PTME specific configuration parameters derived from FPGA design and device tree.
+ * @brief Class to configure donwlink specific parameters in the PTME IP core.
*
* @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;
-#if BOARD_TE0720 == 0
-static const char UIO_DEVICE_FILE[] = "/dev/uio1";
-#else
-static const char UIO_DEVICE_FILE[] = "/dev/uio1";
-#endif
+class PtmeConfig : public SystemObject, public HasReturnvaluesIF {
+ public:
+ /**
+ * @brief Constructor
+ *
+ * ptmeAxiConfig Pointer to object providing access to PTME configuration registers.
+ */
+ PtmeConfig(object_id_t opbjectId, AxiPtmeConfig* axiPtmeConfig);
+ virtual ~PtmeConfig();
-}; // namespace PtmeConfig
+ virtual ReturnValue_t initialize() override;
+ /**
+ * @brief Changes the input frequency to the S-Band transceiver and thus the downlink rate
+ *
+ * @details This is the bitrate of the CADU clock and not the downlink which has twice the bitrate
+ * of the CADU clock due to the convolutional code added by the s-Band transceiver.
+ */
+ ReturnValue_t setRate(uint32_t bitRate);
+
+ /**
+ * @brief Will change the time the tx data signal is updated with respect to the tx clock
+ *
+ * @param invert True -> Data signal will be updated on the falling edge (not desired by the
+ * Syrlinks)
+ * False -> Data signal updated on rising edge (default configuration and desired
+ * by the syrlinks)
+ *
+ * @return REUTRN_OK if successful, otherwise error return value
+ */
+ ReturnValue_t invertTxClock(bool invert);
+
+ /**
+ * @brief Controls the tx clock manipulator of the PTME wrapper component
+ *
+ * @param enable Manipulator will be enabled (this is also the default configuration)
+ * @param disable Manipulator will be disabled
+ *
+ * @return REUTRN_OK if successful, otherwise error return value
+ */
+ ReturnValue_t configTxManipulator(bool enable);
+
+ private:
+ static const uint8_t INTERFACE_ID = CLASS_ID::RATE_SETTER;
+
+ //! [EXPORT] : [COMMENT] The commanded rate is not supported by the current FPGA design
+ static const ReturnValue_t RATE_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0);
+ //! [EXPORT] : [COMMENT] Bad bitrate has been commanded (e.g. 0)
+ static const ReturnValue_t BAD_BIT_RATE = MAKE_RETURN_CODE(0xA1);
+ //! [EXPORT] : [COMMENT] Failed to invert clock and thus change the time the data is updated with
+ //! respect to the tx clock
+ static const ReturnValue_t CLK_INVERSION_FAILED = MAKE_RETURN_CODE(0xA2);
+ //! [EXPORT] : [COMMENT] Failed to change configuration bit of tx clock manipulator
+ static const ReturnValue_t TX_MANIPULATOR_CONFIG_FAILED = MAKE_RETURN_CODE(0xA3);
+
+ // Bitrate register field is only 8 bit wide
+ static const uint32_t MAX_BITRATE = 0xFF;
+ // Bit clock frequency of PMTE IP core in Hz
+ static const uint32_t BIT_CLK_FREQ = 20000000;
+
+ AxiPtmeConfig* axiPtmeConfig = nullptr;
+};
#endif /* LINUX_OBC_PTMECONFIG_H_ */
diff --git a/linux/obc/PtmeRateSetter.cpp b/linux/obc/PtmeRateSetter.cpp
deleted file mode 100644
index b5a6ee1c..00000000
--- a/linux/obc/PtmeRateSetter.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "PtmeRateSetter.h"
-
-#include "fsfw/serviceinterface/ServiceInterface.h"
-
-PtmeRateSetter::PtmeRateSetter(gpioId_t bitrateSel, GpioIF* gpioif)
- : bitrateSel(bitrateSel), gpioif(gpioif) {}
-
-PtmeRateSetter::~PtmeRateSetter() {}
-
-ReturnValue_t PtmeRateSetter::setRate(BitRates rate) {
- ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
- switch (rate) {
- case RATE_2000KHZ:
- result = gpioif->pullHigh(bitrateSel);
- break;
- case RATE_400KHZ:
- result = gpioif->pullLow(bitrateSel);
- break;
- default:
- sif::debug << "PtmeRateSetter::setRate: Invalid rate" << std::endl;
- result = HasReturnvaluesIF::RETURN_FAILED;
- break;
- }
- return result;
-}
diff --git a/linux/obc/PtmeRateSetter.h b/linux/obc/PtmeRateSetter.h
deleted file mode 100644
index 14dfec4b..00000000
--- a/linux/obc/PtmeRateSetter.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef LINUX_OBC_PTMERATESETTER_H_
-#define LINUX_OBC_PTMERATESETTER_H_
-
-#include "TxRateSetterIF.h"
-#include "fsfw/returnvalues/HasReturnvaluesIF.h"
-#include "fsfw_hal/common/gpio/GpioIF.h"
-#include "fsfw_hal/common/gpio/gpioDefinitions.h"
-
-/**
- * @brief Class to set the downlink bit rate by using the cadu_rate_switcher implemented in
- * the programmable logic.
- *
- * @details The cadu_rate_switcher module sets the input rate to the syrlinks transceiver either
- * to 2000 kHz (bitrateSel = 1) or 400 kHz (bitrate = 0).
- *
- * @author J. Meier
- */
-class PtmeRateSetter : public TxRateSetterIF {
- public:
- /**
- * @brief Constructor
- *
- * @param bitrateSel GPIO ID of the GPIO connected to the bitrate_sel input of the
- * cadu_rate_switcher.
- * @param gpioif GPIO interface to drive the bitrateSel GPIO
- */
- PtmeRateSetter(gpioId_t bitrateSel, GpioIF* gpioif);
- virtual ~PtmeRateSetter();
-
- virtual ReturnValue_t setRate(BitRates rate);
-
- private:
- gpioId_t bitrateSel = gpio::NO_GPIO;
-
- GpioIF* gpioif = nullptr;
-};
-
-#endif /* LINUX_OBC_PTMERATESETTER_H_ */
diff --git a/linux/obc/TxRateSetterIF.h b/linux/obc/TxRateSetterIF.h
deleted file mode 100644
index 1eaded33..00000000
--- a/linux/obc/TxRateSetterIF.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef LINUX_OBC_TXRATESETTERIF_H_
-#define LINUX_OBC_TXRATESETTERIF_H_
-
-#include "fsfw/returnvalues/HasReturnvaluesIF.h"
-
-enum BitRates : uint32_t { RATE_2000KHZ, RATE_400KHZ };
-
-/**
- * @brief Abstract class for objects implementing the functionality to switch the
- * downlink bit rate.
- *
- * @author J. Meier
- */
-class TxRateSetterIF {
- public:
- TxRateSetterIF(){};
- virtual ~TxRateSetterIF(){};
-
- virtual ReturnValue_t setRate(BitRates bitRate) = 0;
-};
-
-#endif /* LINUX_OBC_TXRATESETTERIF_H_ */
diff --git a/linux/obc/VcInterfaceIF.h b/linux/obc/VcInterfaceIF.h
index 0aa95691..45226e21 100644
--- a/linux/obc/VcInterfaceIF.h
+++ b/linux/obc/VcInterfaceIF.h
@@ -24,7 +24,7 @@ class VcInterfaceIF {
*/
virtual ReturnValue_t write(const uint8_t* data, size_t size) = 0;
- virtual void setRegisterAddress(uint32_t* ptmeBaseAddress) = 0;
+ virtual ReturnValue_t initialize() = 0;
};
#endif /* LINUX_OBC_VCINTERFACEIF_H_ */
diff --git a/misc/eclipse/.cproject b/misc/eclipse/.cproject
index 3bab5367..e2984ed8 100644
--- a/misc/eclipse/.cproject
+++ b/misc/eclipse/.cproject
@@ -19,10 +19,12 @@
-
+
@@ -31,6 +33,8 @@
@@ -38,6 +42,8 @@
@@ -79,6 +85,8 @@
@@ -87,6 +95,8 @@
@@ -94,6 +104,8 @@
@@ -137,6 +149,8 @@
+
+
@@ -209,6 +229,8 @@
+
+
@@ -225,6 +247,8 @@
+
+
@@ -334,7 +358,10 @@
-
+
+
+
+
@@ -342,6 +369,8 @@
+
+
@@ -355,6 +384,8 @@
+
+
@@ -406,9 +437,6 @@
-
-
-
@@ -494,6 +522,8 @@
+
+
@@ -502,6 +532,8 @@
+
+
@@ -514,6 +546,8 @@
+
+
@@ -652,6 +686,7 @@
+
@@ -662,6 +697,7 @@
+
@@ -677,6 +713,7 @@
+
@@ -815,6 +852,8 @@
+
+
@@ -824,6 +863,8 @@
+
+
@@ -836,6 +877,8 @@
+
+
@@ -973,6 +1016,8 @@
+
+
@@ -983,6 +1028,8 @@
+
+
@@ -997,6 +1044,8 @@
+
+
@@ -1134,6 +1183,7 @@
+
@@ -1144,6 +1194,7 @@
+
@@ -1159,6 +1210,7 @@
+
@@ -1297,6 +1349,7 @@
+
@@ -1307,6 +1360,7 @@
+
@@ -1322,6 +1376,7 @@
+
@@ -1361,7 +1416,7 @@
-
+
@@ -1374,16 +1429,17 @@
-
+
-
+
-
-
+
+
+
@@ -1392,8 +1448,8 @@
-
-
+
+
@@ -1410,6 +1466,8 @@
+
+
@@ -1439,6 +1497,9 @@
+
+
+
@@ -1472,18 +1533,9 @@
-
-
-
-
-
-
-
-
-
@@ -1499,6 +1551,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1511,25 +1599,16 @@
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
diff --git a/mission/devices/ACUHandler.cpp b/mission/devices/ACUHandler.cpp
index 239a0c7a..60e26302 100644
--- a/mission/devices/ACUHandler.cpp
+++ b/mission/devices/ACUHandler.cpp
@@ -273,7 +273,8 @@ ReturnValue_t ACUHandler::initializeLocalDataPool(localpool::DataPool &localData
return HasReturnvaluesIF::RETURN_OK;
}
-ReturnValue_t ACUHandler::deviceSpecificCommand(DeviceCommandId_t cmd) {
+ReturnValue_t ACUHandler::childCommandHook(DeviceCommandId_t cmd, const uint8_t *commandData,
+ size_t commandDataLen) {
switch (cmd) {
case PRINT_CHANNEL_STATS: {
printChannelStats();
diff --git a/mission/devices/ACUHandler.h b/mission/devices/ACUHandler.h
index 0d93c5fe..f3af5eae 100644
--- a/mission/devices/ACUHandler.h
+++ b/mission/devices/ACUHandler.h
@@ -28,7 +28,8 @@ class ACUHandler : public GomspaceDeviceHandler {
virtual void fillCommandAndReplyMap() override;
- virtual ReturnValue_t deviceSpecificCommand(DeviceCommandId_t cmd) override;
+ virtual ReturnValue_t childCommandHook(DeviceCommandId_t cmd, const uint8_t* commandData,
+ size_t commandDataLen) override;
private:
static const DeviceCommandId_t PRINT_CHANNEL_STATS = 51;
diff --git a/mission/devices/CMakeLists.txt b/mission/devices/CMakeLists.txt
index a9c52b0b..03ff3556 100644
--- a/mission/devices/CMakeLists.txt
+++ b/mission/devices/CMakeLists.txt
@@ -1,5 +1,5 @@
target_sources(${TARGET_NAME} PUBLIC
- GPSHyperionHandler.cpp
+ GPSHyperionLinuxController.cpp
GomspaceDeviceHandler.cpp
BpxBatteryHandler.cpp
Tmp1075Handler.cpp
diff --git a/mission/devices/GPSHyperionHandler.cpp b/mission/devices/GPSHyperionHandler.cpp
index 37b11bcb..d6928bb5 100644
--- a/mission/devices/GPSHyperionHandler.cpp
+++ b/mission/devices/GPSHyperionHandler.cpp
@@ -3,45 +3,58 @@
#include "devicedefinitions/GPSDefinitions.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include "fsfw/timemanager/Clock.h"
-
-#ifdef FSFW_OSAL_LINUX
-#include
-#include
-#endif
-
-#include
+#include "lwgps/lwgps.h"
#if FSFW_DEV_HYPERION_GPS_CREATE_NMEA_CSV == 1
#include
#include
#endif
-GPSHyperionHandler::GPSHyperionHandler(object_id_t objectId, object_id_t parentId,
- bool debugHyperionGps)
- : ExtendedControllerBase(objectId, objects::NO_OBJECT),
+GPSHyperionHandler::GPSHyperionHandler(object_id_t objectId, object_id_t deviceCommunication,
+ CookieIF *comCookie, bool debugHyperionGps)
+ : DeviceHandlerBase(objectId, deviceCommunication, comCookie),
gpsSet(this),
- debugHyperionGps(debugHyperionGps) {}
+ debugHyperionGps(debugHyperionGps) {
+ lwgps_init(&gpsData);
+}
GPSHyperionHandler::~GPSHyperionHandler() {}
-void GPSHyperionHandler::performControlOperation() {
-#ifdef FSFW_OSAL_LINUX
- readGpsDataFromGpsd();
-#endif
+void GPSHyperionHandler::doStartUp() {
+ if (internalState == InternalStates::NONE) {
+ commandExecuted = false;
+ internalState = InternalStates::WAIT_FIRST_MESSAGE;
+ }
+
+ if (internalState == InternalStates::WAIT_FIRST_MESSAGE) {
+ if (commandExecuted) {
+ internalState = InternalStates::IDLE;
+ setMode(MODE_ON);
+ commandExecuted = false;
+ }
+ }
}
-LocalPoolDataSetBase *GPSHyperionHandler::getDataSetHandle(sid_t sid) {
- return &gpsSet;
+void GPSHyperionHandler::doShutDown() {
+ internalState = InternalStates::NONE;
+ commandExecuted = false;
+ setMode(_MODE_POWER_DOWN);
}
-ReturnValue_t GPSHyperionHandler::checkModeCommand(Mode_t mode, Submode_t submode,
- uint32_t *msToReachTheMode) {
- return HasReturnvaluesIF::RETURN_OK;
+ReturnValue_t GPSHyperionHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) {
+ return NOTHING_TO_SEND;
}
-ReturnValue_t GPSHyperionHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
- const uint8_t *data, size_t size) {
- switch (actionId) {
+ReturnValue_t GPSHyperionHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) {
+ return NOTHING_TO_SEND;
+}
+
+ReturnValue_t GPSHyperionHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
+ const uint8_t *commandData,
+ size_t commandDataLen) {
+ // By default, send nothing
+ rawPacketLen = 0;
+ switch (deviceCommand) {
case (GpsHyperion::TRIGGER_RESET_PIN): {
if (resetCallback != nullptr) {
PoolReadGuard pg(&gpsSet);
@@ -56,12 +69,97 @@ ReturnValue_t GPSHyperionHandler::executeAction(ActionId_t actionId, MessageQueu
return HasReturnvaluesIF::RETURN_OK;
}
+ReturnValue_t GPSHyperionHandler::scanForReply(const uint8_t *start, size_t len,
+ DeviceCommandId_t *foundId, size_t *foundLen) {
+ // Pass data to GPS library
+ if (len > 0) {
+ // sif::debug << "GPSHandler::scanForReply: Received " << len << " bytes" << std::endl;
+ if (internalState == InternalStates::WAIT_FIRST_MESSAGE) {
+ // TODO: Check whether data is valid by checking whether NMEA start string is valid?
+ commandExecuted = true;
+ }
+ int result = lwgps_process(&gpsData, start, len);
+ if (result != 1) {
+ sif::warning << "GPSHandler::scanForReply: Issue processing GPS data with lwgps" << std::endl;
+ } else {
+ // The data from the device will generally be read all at once. Therefore, we
+ // can set all field here
+ PoolReadGuard pg(&gpsSet);
+ if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) {
+#if FSFW_VERBOSE_LEVEL >= 1
+ sif::warning << "GPSHyperionHandler::scanForReply: Reading dataset failed" << std::endl;
+#endif
+ }
+ // Print messages
+ if (gpsData.is_valid) {
+ // Set all entries valid now, set invalid on case basis if values are sanitized
+ gpsSet.setValidity(true, true);
+ }
+ // Negative latitude -> South direction
+ gpsSet.latitude.value = gpsData.latitude;
+ // Negative longitude -> West direction
+ gpsSet.longitude.value = gpsData.longitude;
+ if (gpsData.altitude > 600000.0 or gpsData.altitude < 400000.0) {
+ gpsSet.altitude.setValid(false);
+ } else {
+ gpsSet.altitude.setValid(true);
+ gpsSet.altitude.value = gpsData.altitude;
+ }
+ gpsSet.fixMode.value = gpsData.fix_mode;
+ gpsSet.satInUse.value = gpsData.sats_in_use;
+ Clock::TimeOfDay_t timeStruct = {};
+ timeStruct.day = gpsData.date;
+ timeStruct.hour = gpsData.hours;
+ timeStruct.minute = gpsData.minutes;
+ timeStruct.month = gpsData.month;
+ timeStruct.second = gpsData.seconds;
+ // Convert two-digit year to full year (AD)
+ timeStruct.year = gpsData.year + 2000;
+ timeval timeval = {};
+ Clock::convertTimeOfDayToTimeval(&timeStruct, &timeval);
+ gpsSet.year = timeStruct.year;
+ gpsSet.month = gpsData.month;
+ gpsSet.day = gpsData.date;
+ gpsSet.hours = gpsData.hours;
+ gpsSet.minutes = gpsData.minutes;
+ gpsSet.seconds = gpsData.seconds;
+ gpsSet.unixSeconds = timeval.tv_sec;
+ if (debugHyperionGps) {
+ sif::info << "GPS Data" << std::endl;
+ printf("Valid status: %d\n", gpsData.is_valid);
+ printf("Latitude: %f degrees\n", gpsData.latitude);
+ printf("Longitude: %f degrees\n", gpsData.longitude);
+ printf("Altitude: %f meters\n", gpsData.altitude);
+ }
+#if FSFW_DEV_HYPERION_GPS_CREATE_NMEA_CSV == 1
+ std::string filename = "/mnt/sd0/gps_log.txt";
+ std::ofstream gpsFile;
+ if (not std::filesystem::exists(filename)) {
+ gpsFile.open(filename, std::ofstream::out);
+ }
+ gpsFile.open(filename, std::ofstream::out | std::ofstream::app);
+ gpsFile.write("\n", 1);
+ gpsFile.write(reinterpret_cast(start), len);
+#endif
+ }
+ *foundLen = len;
+ *foundId = GpsHyperion::GPS_REPLY;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t GPSHyperionHandler::interpretDeviceReply(DeviceCommandId_t id,
+ const uint8_t *packet) {
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+uint32_t GPSHyperionHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { return 5000; }
+
ReturnValue_t GPSHyperionHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(GpsHyperion::ALTITUDE, new PoolEntry({0.0}));
localDataPoolMap.emplace(GpsHyperion::LONGITUDE, new PoolEntry({0.0}));
localDataPoolMap.emplace(GpsHyperion::LATITUDE, new PoolEntry({0.0}));
- localDataPoolMap.emplace(GpsHyperion::SPEED, new PoolEntry({0.0}));
localDataPoolMap.emplace(GpsHyperion::YEAR, new PoolEntry());
localDataPoolMap.emplace(GpsHyperion::MONTH, new PoolEntry());
localDataPoolMap.emplace(GpsHyperion::DAY, new PoolEntry());
@@ -70,111 +168,36 @@ ReturnValue_t GPSHyperionHandler::initializeLocalDataPool(localpool::DataPool &l
localDataPoolMap.emplace(GpsHyperion::SECONDS, new PoolEntry());
localDataPoolMap.emplace(GpsHyperion::UNIX_SECONDS, new PoolEntry());
localDataPoolMap.emplace(GpsHyperion::SATS_IN_USE, new PoolEntry());
- localDataPoolMap.emplace(GpsHyperion::SATS_IN_VIEW, new PoolEntry());
localDataPoolMap.emplace(GpsHyperion::FIX_MODE, new PoolEntry());
poolManager.subscribeForPeriodicPacket(gpsSet.getSid(), true, 2.0, false);
return HasReturnvaluesIF::RETURN_OK;
}
+void GPSHyperionHandler::fillCommandAndReplyMap() {
+ // Reply length does not matter, packets should always arrive periodically
+ insertInReplyMap(GpsHyperion::GPS_REPLY, 4, &gpsSet, 0, true);
+ insertInCommandMap(GpsHyperion::TRIGGER_RESET_PIN);
+}
+
+void GPSHyperionHandler::modeChanged() { internalState = InternalStates::NONE; }
+
void GPSHyperionHandler::setResetPinTriggerFunction(gpioResetFunction_t resetCallback, void *args) {
this->resetCallback = resetCallback;
resetCallbackArgs = args;
}
+void GPSHyperionHandler::debugInterface(uint8_t positionTracker, object_id_t objectId,
+ uint32_t parameter) {}
+
ReturnValue_t GPSHyperionHandler::initialize() {
- ReturnValue_t result = ExtendedControllerBase::initialize();
+ ReturnValue_t result = DeviceHandlerBase::initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
- return result;
+ // Enable reply immediately for now
+ return updatePeriodicReply(true, GpsHyperion::GPS_REPLY);
}
-ReturnValue_t GPSHyperionHandler::handleCommandMessage(CommandMessage *message) {
- return ExtendedControllerBase::handleCommandMessage(message);
+ReturnValue_t GPSHyperionHandler::acceptExternalDeviceCommands() {
+ return DeviceHandlerBase::acceptExternalDeviceCommands();
}
-
-#ifdef FSFW_OSAL_LINUX
-void GPSHyperionHandler::readGpsDataFromGpsd() {
- // The data from the device will generally be read all at once. Therefore, we
- // can set all field here
- gpsmm gpsmm(GPSD_SHARED_MEMORY, 0);
- gps_data_t *gps;
- gps = gpsmm.read();
- if (gps == nullptr) {
- sif::warning << "Q7STestTask: Reading GPS data failed" << std::endl;
- }
- PoolReadGuard pg(&gpsSet);
- if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) {
-#if FSFW_VERBOSE_LEVEL >= 1
- sif::warning << "GPSHyperionHandler::scanForReply: Reading dataset failed" << std::endl;
-#endif
- }
- // Print messages
- if ((gps->set & MODE_SET) != MODE_SET) {
- // Could not even set mode
- gpsSet.setValidity(false, true);
- return;
- }
-
- if (gps->satellites_used > 0) {
- gpsSet.setValidity(true, true);
- }
-
- gpsSet.satInUse.value = gps->satellites_used;
- gpsSet.satInView.value = gps->satellites_visible;
-
- // 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix
- gpsSet.fixMode = gps->fix.mode;
- if (std::isfinite(gps->fix.latitude)) {
- // Negative latitude -> South direction
- gpsSet.latitude.value = gps->fix.latitude;
- } else {
- gpsSet.latitude.setValid(false);
- }
-
- if (std::isfinite(gps->fix.longitude)) {
- // Negative longitude -> West direction
- gpsSet.longitude.value = gps->fix.longitude;
- } else {
- gpsSet.longitude.setValid(false);
- }
-
- if (std::isfinite(gps->fix.altitude)) {
- gpsSet.altitude.value = gps->fix.altitude;
- } else {
- gpsSet.altitude.setValid(false);
- }
-
- if (std::isfinite(gps->fix.speed)) {
- gpsSet.speed.value = gps->fix.speed;
- } else {
- gpsSet.speed.setValid(false);
- }
-
- gpsSet.unixSeconds.value = gps->fix.time.tv_sec;
- timeval time = {};
- time.tv_sec = gpsSet.unixSeconds.value;
- time.tv_usec = gps->fix.time.tv_nsec / 1000;
- Clock::TimeOfDay_t timeOfDay = {};
- Clock::convertTimevalToTimeOfDay(&time, &timeOfDay);
- gpsSet.year = timeOfDay.year;
- gpsSet.month = timeOfDay.month;
- gpsSet.day = timeOfDay.day;
- gpsSet.hours = timeOfDay.hour;
- gpsSet.minutes = timeOfDay.minute;
- gpsSet.seconds = timeOfDay.second;
- if (debugHyperionGps) {
- sif::info << "-- Hyperion GPS Data --" << std::endl;
- time_t timeRaw = gps->fix.time.tv_sec;
- std::tm *time = gmtime(&timeRaw);
- std::cout << "Time: " << std::put_time(time, "%c %Z") << std::endl;
- std::cout << "Visible satellites: " << gps->satellites_visible << std::endl;
- std::cout << "Satellites used: " << gps->satellites_used << std::endl;
- std::cout << "Fix (0:Not Seen|1:No Fix|2:2D|3:3D): " << gps->fix.mode << std::endl;
- std::cout << "Latitude: " << gps->fix.latitude << std::endl;
- std::cout << "Longitude: " << gps->fix.longitude << std::endl;
- std::cout << "Altitude(MSL): " << gps->fix.altMSL << std::endl;
- std::cout << "Speed(m/s): " << gps->fix.speed << std::endl;
- }
-}
-#endif
diff --git a/mission/devices/GPSHyperionHandler.h b/mission/devices/GPSHyperionHandler.h
index 026e1779..b5734f23 100644
--- a/mission/devices/GPSHyperionHandler.h
+++ b/mission/devices/GPSHyperionHandler.h
@@ -3,8 +3,8 @@
#include "devicedefinitions/GPSDefinitions.h"
#include "fsfw/FSFW.h"
-#include "fsfw/controller/ExtendedControllerBase.h"
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
+#include "lwgps/lwgps.h"
/**
* @brief Device handler for the Hyperion HT-GPS200 device
@@ -12,35 +12,50 @@
* Flight manual:
* https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/Hyperion_HT-GPS200
*/
-class GPSHyperionHandler : public ExtendedControllerBase {
+class GPSHyperionHandler : public DeviceHandlerBase {
public:
- GPSHyperionHandler(object_id_t objectId, object_id_t parentId, bool debugHyperionGps = false);
+ GPSHyperionHandler(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie,
+ bool debugHyperionGps = false);
virtual ~GPSHyperionHandler();
- using gpioResetFunction_t = ReturnValue_t (*)(void* args);
+ using gpioResetFunction_t = ReturnValue_t (*)(void *args);
+
+ void setResetPinTriggerFunction(gpioResetFunction_t resetCallback, void *args);
+ ReturnValue_t acceptExternalDeviceCommands() override;
- void setResetPinTriggerFunction(gpioResetFunction_t resetCallback, void* args);
- ReturnValue_t handleCommandMessage(CommandMessage* message) override;
- void performControlOperation() override;
- LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
- ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
- uint32_t* msToReachTheMode) override;
- ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
- const uint8_t* data, size_t size) override;
ReturnValue_t initialize() override;
protected:
gpioResetFunction_t resetCallback = nullptr;
- void* resetCallbackArgs = nullptr;
+ void *resetCallbackArgs = nullptr;
- ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
- LocalDataPoolManager& poolManager) override;
+ enum class InternalStates { NONE, WAIT_FIRST_MESSAGE, IDLE };
+ InternalStates internalState = InternalStates::NONE;
+ bool commandExecuted = false;
+
+ /* DeviceHandlerBase overrides */
+ ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t *id) override;
+ void doStartUp() override;
+ void doShutDown() override;
+ ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
+ ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t *commandData,
+ size_t commandDataLen) override;
+ ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId,
+ size_t *foundLen) override;
+ ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override;
+
+ void fillCommandAndReplyMap() override;
+ void modeChanged() override;
+ uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override;
+ ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
+ LocalDataPoolManager &poolManager) override;
+ virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
+ uint32_t parameter = 0) override;
private:
+ lwgps_t gpsData = {};
GpsPrimaryDataset gpsSet;
bool debugHyperionGps = false;
-
- void readGpsDataFromGpsd();
};
#endif /* MISSION_DEVICES_GPSHYPERIONHANDLER_H_ */
diff --git a/mission/devices/GPSHyperionLinuxController.cpp b/mission/devices/GPSHyperionLinuxController.cpp
new file mode 100644
index 00000000..0955e1c7
--- /dev/null
+++ b/mission/devices/GPSHyperionLinuxController.cpp
@@ -0,0 +1,178 @@
+#include "GPSHyperionLinuxController.h"
+
+#include
+
+#include "devicedefinitions/GPSDefinitions.h"
+#include "fsfw/datapool/PoolReadGuard.h"
+#include "fsfw/timemanager/Clock.h"
+
+#if FSFW_DEV_HYPERION_GPS_CREATE_NMEA_CSV == 1
+#include
+#include
+#endif
+
+GPSHyperionLinuxController::GPSHyperionLinuxController(object_id_t objectId, object_id_t parentId,
+ bool debugHyperionGps)
+ : ExtendedControllerBase(objectId, objects::NO_OBJECT),
+ gpsSet(this),
+ myGpsmm(GPSD_SHARED_MEMORY, nullptr),
+ debugHyperionGps(debugHyperionGps) {}
+
+GPSHyperionLinuxController::~GPSHyperionLinuxController() {}
+
+void GPSHyperionLinuxController::performControlOperation() {
+#ifdef FSFW_OSAL_LINUX
+ readGpsDataFromGpsd();
+#endif
+}
+
+LocalPoolDataSetBase *GPSHyperionLinuxController::getDataSetHandle(sid_t sid) { return &gpsSet; }
+
+ReturnValue_t GPSHyperionLinuxController::checkModeCommand(Mode_t mode, Submode_t submode,
+ uint32_t *msToReachTheMode) {
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t GPSHyperionLinuxController::executeAction(ActionId_t actionId,
+ MessageQueueId_t commandedBy,
+ const uint8_t *data, size_t size) {
+ switch (actionId) {
+ case (GpsHyperion::TRIGGER_RESET_PIN): {
+ if (resetCallback != nullptr) {
+ PoolReadGuard pg(&gpsSet);
+ // Set HK entries invalid
+ gpsSet.setValidity(false, true);
+ resetCallback(resetCallbackArgs);
+ return HasActionsIF::EXECUTION_FINISHED;
+ }
+ return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
+ }
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+ReturnValue_t GPSHyperionLinuxController::initializeLocalDataPool(
+ localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
+ localDataPoolMap.emplace(GpsHyperion::ALTITUDE, new PoolEntry({0.0}));
+ localDataPoolMap.emplace(GpsHyperion::LONGITUDE, new PoolEntry({0.0}));
+ localDataPoolMap.emplace(GpsHyperion::LATITUDE, new PoolEntry({0.0}));
+ localDataPoolMap.emplace(GpsHyperion::SPEED, new PoolEntry({0.0}));
+ localDataPoolMap.emplace(GpsHyperion::YEAR, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::MONTH, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::DAY, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::HOURS, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::MINUTES, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::SECONDS, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::UNIX_SECONDS, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::SATS_IN_USE, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::SATS_IN_VIEW, new PoolEntry());
+ localDataPoolMap.emplace(GpsHyperion::FIX_MODE, new PoolEntry());
+ poolManager.subscribeForPeriodicPacket(gpsSet.getSid(), true, 2.0, false);
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
+void GPSHyperionLinuxController::setResetPinTriggerFunction(gpioResetFunction_t resetCallback,
+ void *args) {
+ this->resetCallback = resetCallback;
+ resetCallbackArgs = args;
+}
+
+ReturnValue_t GPSHyperionLinuxController::initialize() {
+ ReturnValue_t result = ExtendedControllerBase::initialize();
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
+ return result;
+}
+
+ReturnValue_t GPSHyperionLinuxController::handleCommandMessage(CommandMessage *message) {
+ return ExtendedControllerBase::handleCommandMessage(message);
+}
+
+#ifdef FSFW_OSAL_LINUX
+void GPSHyperionLinuxController::readGpsDataFromGpsd() {
+ // The data from the device will generally be read all at once. Therefore, we
+ // can set all field here
+ if (not myGpsmm.is_open()) {
+ // Opening failed
+#if FSFW_VERBOSE_LEVEL >= 1
+ sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Opening GPSMM failed" << std::endl;
+#endif
+ }
+ gps_data_t *gps = nullptr;
+ gps = myGpsmm.read();
+ if (gps == nullptr) {
+ sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading GPS data failed" << std::endl;
+ }
+ PoolReadGuard pg(&gpsSet);
+ if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) {
+#if FSFW_VERBOSE_LEVEL >= 1
+ sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading dataset failed" << std::endl;
+#endif
+ }
+
+ // 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix
+ gpsSet.fixMode.value = gps->fix.mode;
+ if (gps->fix.mode == 0 or gps->fix.mode == 1) {
+ gpsSet.setValidity(false, true);
+ } else if (gps->satellites_used > 0) {
+ gpsSet.setValidity(true, true);
+ }
+
+ gpsSet.satInUse.value = gps->satellites_used;
+ gpsSet.satInView.value = gps->satellites_visible;
+
+ if (std::isfinite(gps->fix.latitude)) {
+ // Negative latitude -> South direction
+ gpsSet.latitude.value = gps->fix.latitude;
+ } else {
+ gpsSet.latitude.setValid(false);
+ }
+
+ if (std::isfinite(gps->fix.longitude)) {
+ // Negative longitude -> West direction
+ gpsSet.longitude.value = gps->fix.longitude;
+ } else {
+ gpsSet.longitude.setValid(false);
+ }
+
+ if (std::isfinite(gps->fix.altitude)) {
+ gpsSet.altitude.value = gps->fix.altitude;
+ } else {
+ gpsSet.altitude.setValid(false);
+ }
+
+ if (std::isfinite(gps->fix.speed)) {
+ gpsSet.speed.value = gps->fix.speed;
+ } else {
+ gpsSet.speed.setValid(false);
+ }
+
+ gpsSet.unixSeconds.value = gps->fix.time.tv_sec;
+ timeval time = {};
+ time.tv_sec = gpsSet.unixSeconds.value;
+ time.tv_usec = gps->fix.time.tv_nsec / 1000;
+ Clock::TimeOfDay_t timeOfDay = {};
+ Clock::convertTimevalToTimeOfDay(&time, &timeOfDay);
+ gpsSet.year = timeOfDay.year;
+ gpsSet.month = timeOfDay.month;
+ gpsSet.day = timeOfDay.day;
+ gpsSet.hours = timeOfDay.hour;
+ gpsSet.minutes = timeOfDay.minute;
+ gpsSet.seconds = timeOfDay.second;
+ debugHyperionGps = true;
+ if (debugHyperionGps) {
+ sif::info << "-- Hyperion GPS Data --" << std::endl;
+ time_t timeRaw = gps->fix.time.tv_sec;
+ std::tm *time = gmtime(&timeRaw);
+ std::cout << "Time: " << std::put_time(time, "%c %Z") << std::endl;
+ std::cout << "Visible satellites: " << gps->satellites_visible << std::endl;
+ std::cout << "Satellites used: " << gps->satellites_used << std::endl;
+ std::cout << "Fix (0:Not Seen|1:No Fix|2:2D|3:3D): " << gps->fix.mode << std::endl;
+ std::cout << "Latitude: " << gps->fix.latitude << std::endl;
+ std::cout << "Longitude: " << gps->fix.longitude << std::endl;
+ std::cout << "Altitude(MSL): " << gps->fix.altMSL << std::endl;
+ std::cout << "Speed(m/s): " << gps->fix.speed << std::endl;
+ }
+}
+#endif
diff --git a/mission/devices/GPSHyperionLinuxController.h b/mission/devices/GPSHyperionLinuxController.h
new file mode 100644
index 00000000..57da40e6
--- /dev/null
+++ b/mission/devices/GPSHyperionLinuxController.h
@@ -0,0 +1,55 @@
+#ifndef MISSION_DEVICES_GPSHYPERIONHANDLER_H_
+#define MISSION_DEVICES_GPSHYPERIONHANDLER_H_
+
+#include "devicedefinitions/GPSDefinitions.h"
+#include "fsfw/FSFW.h"
+#include "fsfw/controller/ExtendedControllerBase.h"
+#include "fsfw/devicehandlers/DeviceHandlerBase.h"
+
+#ifdef FSFW_OSAL_LINUX
+#include
+#include
+#endif
+
+/**
+ * @brief Device handler for the Hyperion HT-GPS200 device
+ * @details
+ * Flight manual:
+ * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/Hyperion_HT-GPS200
+ * This device handler can only be used on Linux system where the gpsd daemon with shared memory
+ * export is running.
+ */
+class GPSHyperionLinuxController : public ExtendedControllerBase {
+ public:
+ GPSHyperionLinuxController(object_id_t objectId, object_id_t parentId,
+ bool debugHyperionGps = false);
+ virtual ~GPSHyperionLinuxController();
+
+ using gpioResetFunction_t = ReturnValue_t (*)(void* args);
+
+ void setResetPinTriggerFunction(gpioResetFunction_t resetCallback, void* args);
+ ReturnValue_t handleCommandMessage(CommandMessage* message) override;
+ void performControlOperation() override;
+ LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
+ ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
+ uint32_t* msToReachTheMode) override;
+ ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
+ const uint8_t* data, size_t size) override;
+ ReturnValue_t initialize() override;
+
+ protected:
+ gpioResetFunction_t resetCallback = nullptr;
+ void* resetCallbackArgs = nullptr;
+
+ ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
+ LocalDataPoolManager& poolManager) override;
+
+ private:
+ GpsPrimaryDataset gpsSet;
+ gpsmm myGpsmm;
+ bool debugHyperionGps = false;
+
+ void readGpsDataFromGpsd();
+};
+
+#endif /* MISSION_DEVICES_GPSHYPERIONHANDLER_H_ */
diff --git a/mission/devices/GomspaceDeviceHandler.cpp b/mission/devices/GomspaceDeviceHandler.cpp
index eea1368a..4cec651e 100644
--- a/mission/devices/GomspaceDeviceHandler.cpp
+++ b/mission/devices/GomspaceDeviceHandler.cpp
@@ -36,7 +36,7 @@ ReturnValue_t GomspaceDeviceHandler::buildTransitionDeviceCommand(DeviceCommandI
ReturnValue_t GomspaceDeviceHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
const uint8_t* commandData,
size_t commandDataLen) {
- ReturnValue_t result;
+ ReturnValue_t result = childCommandHook(deviceCommand, commandData, commandDataLen);
switch (deviceCommand) {
case (GOMSPACE::PING): {
result = generatePingCommand(commandData, commandDataLen);
@@ -82,7 +82,7 @@ ReturnValue_t GomspaceDeviceHandler::buildCommandFromCommand(DeviceCommandId_t d
break;
}
default:
- return deviceSpecificCommand(deviceCommand);
+ return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
}
return HasReturnvaluesIF::RETURN_OK;
}
@@ -170,6 +170,7 @@ ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id,
if (*packet != PARAM_SET_OK) {
return HasReturnvaluesIF::RETURN_FAILED;
}
+ setParamCallback(setParamCacher, true);
break;
}
case (GOMSPACE::REQUEST_HK_TABLE): {
@@ -186,17 +187,20 @@ void GomspaceDeviceHandler::setNormalDatapoolEntriesInvalid() {}
ReturnValue_t GomspaceDeviceHandler::generateSetParamCommand(const uint8_t* commandData,
size_t commandDataLen) {
- SetParamMessageUnpacker setParamMessageUnpacker;
- ReturnValue_t result = setParamMessageUnpacker.deSerialize(&commandData, &commandDataLen,
- SerializeIF::Endianness::BIG);
+ ReturnValue_t result =
+ setParamCacher.deSerialize(&commandData, &commandDataLen, SerializeIF::Endianness::BIG);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "GomspaceDeviceHandler: Failed to deserialize set parameter "
"message"
<< std::endl;
return result;
}
+ result = setParamCallback(setParamCacher, false);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ return result;
+ }
/* Get and check address */
- uint16_t address = setParamMessageUnpacker.getAddress();
+ uint16_t address = setParamCacher.getAddress();
if (address > maxConfigTableAddress) {
sif::error << "GomspaceDeviceHandler: Invalid address for set parameter "
<< "action" << std::endl;
@@ -207,8 +211,8 @@ ReturnValue_t GomspaceDeviceHandler::generateSetParamCommand(const uint8_t* comm
uint16_t total = 0;
/* CSP reply only contains the transaction state */
uint16_t querySize = 1;
- const uint8_t* parameterPtr = setParamMessageUnpacker.getParameter();
- uint8_t parameterSize = setParamMessageUnpacker.getParameterSize();
+ const uint8_t* parameterPtr = setParamCacher.getParameter();
+ uint8_t parameterSize = setParamCacher.getParameterSize();
uint16_t payloadlength = sizeof(address) + parameterSize;
/* Generate command for CspComIF */
@@ -335,6 +339,17 @@ void GomspaceDeviceHandler::generateRebootCommand() {
rawPacketLen = cspPacketLen;
}
+ReturnValue_t GomspaceDeviceHandler::childCommandHook(DeviceCommandId_t cmd,
+ const uint8_t* commandData,
+ size_t commandDataLen) {
+ return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
+}
+
+ReturnValue_t GomspaceDeviceHandler::setParamCallback(SetParamMessageUnpacker& unpacker,
+ bool afterExecution) {
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
ReturnValue_t GomspaceDeviceHandler::generateResetWatchdogCmd() {
WatchdogResetCommand watchdogResetCommand;
size_t cspPacketLen = 0;
@@ -386,10 +401,6 @@ LocalPoolDataSetBase* GomspaceDeviceHandler::getDataSetHandle(sid_t sid) {
}
}
-ReturnValue_t GomspaceDeviceHandler::deviceSpecificCommand(DeviceCommandId_t cmd) {
- return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
-}
-
void GomspaceDeviceHandler::setModeNormal() { mode = MODE_NORMAL; }
ReturnValue_t GomspaceDeviceHandler::printStatus(DeviceCommandId_t cmd) {
diff --git a/mission/devices/GomspaceDeviceHandler.h b/mission/devices/GomspaceDeviceHandler.h
index c9c08609..3d50b27b 100644
--- a/mission/devices/GomspaceDeviceHandler.h
+++ b/mission/devices/GomspaceDeviceHandler.h
@@ -1,6 +1,8 @@
#ifndef MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_
#define MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_
+#include
+
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "mission/devices/devicedefinitions/GomspaceDefinitions.h"
#include "returnvalues/classIds.h"
@@ -101,17 +103,31 @@ class GomspaceDeviceHandler : public DeviceHandlerBase {
virtual LocalPoolDataSetBase *getDataSetHandle(sid_t sid) override;
/**
- * @brief Can be used by gomspace devices to implement device specific commands.
+ * @brief Can be overriden by child classes to implement device specific commands.
+ * @return Return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED to let this handler handle
+ * the command or RETURN_OK if the child handles the command
*/
- virtual ReturnValue_t deviceSpecificCommand(DeviceCommandId_t cmd);
+ virtual ReturnValue_t childCommandHook(DeviceCommandId_t cmd, const uint8_t *commandData,
+ size_t commandDataLen);
private:
+ SetParamMessageUnpacker setParamCacher;
/**
* @brief Function to generate the command to set a parameter. Command
* will be sent to the ComIF over the rawPacket buffer.
*/
ReturnValue_t generateSetParamCommand(const uint8_t *commandData, size_t commandDataLen);
+ /**
+ * Callback is called on a parameter set command. It is called before executing it and after
+ * after successful execution
+ * @param unpacker Passed before
+ * @param beforeSet False for callback before execution, true if called after successful
+ * execution
+ * @return
+ */
+ virtual ReturnValue_t setParamCallback(SetParamMessageUnpacker &unpacker, bool afterExecution);
+
/**
* @brief Function to generate the command to get a parameter from a
* gomspace device. Command will be sent to the ComIF over the
diff --git a/mission/devices/GyroADIS1650XHandler.cpp b/mission/devices/GyroADIS1650XHandler.cpp
index 717a1bfd..0965e265 100644
--- a/mission/devices/GyroADIS1650XHandler.cpp
+++ b/mission/devices/GyroADIS1650XHandler.cpp
@@ -55,7 +55,7 @@ void GyroADIS1650XHandler::doStartUp() {
}
if (internalState == InternalState::IDLE) {
- if(goToNormalMode) {
+ if (goToNormalMode) {
setMode(MODE_NORMAL);
} else {
setMode(MODE_ON);
@@ -211,7 +211,7 @@ ReturnValue_t GyroADIS1650XHandler::interpretDeviceReply(DeviceCommandId_t id,
if (((adisType == ADIS1650X::Type::ADIS16507) and (readProdId != ADIS1650X::PROD_ID_16507)) or
((adisType == ADIS1650X::Type::ADIS16505) and (readProdId != ADIS1650X::PROD_ID_16505))) {
#if OBSW_VERBOSE_LEVEL >= 1
- if(warningSwitch) {
+ if (warningSwitch) {
sif::warning << "GyroADIS1650XHandler::interpretDeviceReply: Invalid product ID "
<< readProdId << std::endl;
}
@@ -327,9 +327,7 @@ ReturnValue_t GyroADIS1650XHandler::handleSensorData(const uint8_t *packet) {
return HasReturnvaluesIF::RETURN_OK;
}
-uint32_t GyroADIS1650XHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) {
- return 6000;
-}
+uint32_t GyroADIS1650XHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return 6000; }
void GyroADIS1650XHandler::prepareWriteCommand(uint8_t startReg, uint8_t valueOne,
uint8_t valueTwo) {
diff --git a/mission/devices/IMTQHandler.cpp b/mission/devices/IMTQHandler.cpp
index 499b4d6e..3c3e1a66 100644
--- a/mission/devices/IMTQHandler.cpp
+++ b/mission/devices/IMTQHandler.cpp
@@ -2,7 +2,8 @@
#include
#include
-#include
+
+#include
#include "OBSWConfig.h"
@@ -25,11 +26,11 @@ IMTQHandler::IMTQHandler(object_id_t objectId, object_id_t comIF, CookieIF* comC
IMTQHandler::~IMTQHandler() {}
void IMTQHandler::doStartUp() {
-#if OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP == 1
- setMode(MODE_NORMAL);
-#else
- setMode(_MODE_TO_ON);
-#endif
+ if (goToNormalMode) {
+ setMode(MODE_NORMAL);
+ } else {
+ setMode(_MODE_TO_ON);
+ }
}
void IMTQHandler::doShutDown() { setMode(_MODE_POWER_DOWN); }
@@ -694,7 +695,7 @@ void IMTQHandler::fillEngHkDataset(const uint8_t* packet) {
#endif
}
-void IMTQHandler::setModeNormal() { mode = MODE_NORMAL; }
+void IMTQHandler::setToGoToNormal(bool enable) { this->goToNormalMode = enable; }
void IMTQHandler::handleDeviceTM(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId) {
if (wiretappingMode == RAW) {
diff --git a/mission/devices/IMTQHandler.h b/mission/devices/IMTQHandler.h
index b12cdf97..f54306f4 100644
--- a/mission/devices/IMTQHandler.h
+++ b/mission/devices/IMTQHandler.h
@@ -18,7 +18,7 @@ class IMTQHandler : public DeviceHandlerBase {
/**
* @brief Sets mode to MODE_NORMAL. Can be used for debugging.
*/
- void setModeNormal();
+ void setToGoToNormal(bool enable);
protected:
void doStartUp() override;
@@ -96,6 +96,7 @@ class IMTQHandler : public DeviceHandlerBase {
IMTQ::NegZSelfTestSet negZselfTestDataset;
uint8_t commandBuffer[IMTQ::MAX_COMMAND_SIZE];
+ bool goToNormalMode = false;
enum class CommunicationStep {
GET_ENG_HK_DATA,
diff --git a/mission/devices/PDU1Handler.cpp b/mission/devices/PDU1Handler.cpp
index a1486588..48b79551 100644
--- a/mission/devices/PDU1Handler.cpp
+++ b/mission/devices/PDU1Handler.cpp
@@ -1,6 +1,7 @@
#include "PDU1Handler.h"
#include
+#include
#include "OBSWConfig.h"
@@ -67,6 +68,61 @@ void PDU1Handler::letChildHandleHkReply(DeviceCommandId_t id, const uint8_t *pac
#endif
}
+void PDU1Handler::assignChannelHookFunction(GOMSPACE::ChannelSwitchHook hook, void *args) {
+ this->channelSwitchHook = hook;
+ this->hookArgs = args;
+}
+
+ReturnValue_t PDU1Handler::setParamCallback(SetParamMessageUnpacker &unpacker,
+ bool afterExecution) {
+ using namespace PDU1;
+ GOMSPACE::Pdu pdu = GOMSPACE::Pdu::PDU1;
+ if (not afterExecution) {
+ return HasReturnvaluesIF::RETURN_OK;
+ }
+ if (channelSwitchHook != nullptr and unpacker.getParameterSize() == 1) {
+ switch (unpacker.getAddress()) {
+ case (CONFIG_ADDRESS_OUT_EN_TCS_BOARD_3V3): {
+ channelSwitchHook(pdu, 0, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_SYRLINKS): {
+ channelSwitchHook(pdu, 1, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_STAR_TRACKER): {
+ channelSwitchHook(pdu, 2, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_MGT): {
+ channelSwitchHook(pdu, 3, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_SUS_NOMINAL): {
+ channelSwitchHook(pdu, 4, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_SOLAR_CELL_EXP): {
+ channelSwitchHook(pdu, 5, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_PLOC): {
+ channelSwitchHook(pdu, 6, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_ACS_BOARD_SIDE_A): {
+ channelSwitchHook(pdu, 7, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_CHANNEL8): {
+ channelSwitchHook(pdu, 8, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ }
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
+
void PDU1Handler::parseHkTableReply(const uint8_t *packet) {
uint16_t dataOffset = 0;
PoolReadGuard pg(&pdu1HkTableDataset);
diff --git a/mission/devices/PDU1Handler.h b/mission/devices/PDU1Handler.h
index 0715b078..c140648b 100644
--- a/mission/devices/PDU1Handler.h
+++ b/mission/devices/PDU1Handler.h
@@ -27,6 +27,8 @@ class PDU1Handler : public GomspaceDeviceHandler {
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
+ void assignChannelHookFunction(GOMSPACE::ChannelSwitchHook hook, void* args);
+
protected:
/**
* @brief In MODE_NORMAL, a command will be built periodically by this function.
@@ -35,9 +37,13 @@ class PDU1Handler : public GomspaceDeviceHandler {
virtual void letChildHandleHkReply(DeviceCommandId_t id, const uint8_t* packet) override;
ReturnValue_t printStatus(DeviceCommandId_t cmd) override;
+ ReturnValue_t setParamCallback(SetParamMessageUnpacker& unpacker, bool afterExectuion) override;
+
private:
/** Dataset for the housekeeping table of the PDU1 */
PDU1::PDU1HkTableDataset pdu1HkTableDataset;
+ GOMSPACE::ChannelSwitchHook channelSwitchHook = nullptr;
+ void* hookArgs = nullptr;
void printHkTable();
void parseHkTableReply(const uint8_t* packet);
diff --git a/mission/devices/PDU2Handler.cpp b/mission/devices/PDU2Handler.cpp
index b5c34af6..776cae58 100644
--- a/mission/devices/PDU2Handler.cpp
+++ b/mission/devices/PDU2Handler.cpp
@@ -49,6 +49,11 @@ void PDU2Handler::letChildHandleHkReply(DeviceCommandId_t id, const uint8_t *pac
#endif
}
+void PDU2Handler::assignChannelHookFunction(GOMSPACE::ChannelSwitchHook hook, void *args) {
+ this->channelSwitchHook = hook;
+ this->hookArgs = args;
+}
+
void PDU2Handler::parseHkTableReply(const uint8_t *packet) {
uint16_t dataOffset = 0;
pdu2HkTableDataset.read();
@@ -421,3 +426,53 @@ void PDU2Handler::printHkTable() {
<< std::setw(4) << pdu2HkTableDataset.voltageOutPayloadCamera.value << std::right
<< std::endl;
}
+
+ReturnValue_t PDU2Handler::setParamCallback(SetParamMessageUnpacker &unpacker,
+ bool afterExecution) {
+ using namespace PDU2;
+ GOMSPACE::Pdu pdu = GOMSPACE::Pdu::PDU2;
+ if (not afterExecution) {
+ return HasReturnvaluesIF::RETURN_OK;
+ }
+ if (channelSwitchHook != nullptr and unpacker.getParameterSize() == 1) {
+ switch (unpacker.getAddress()) {
+ case (CONFIG_ADDRESS_OUT_EN_Q7S): {
+ channelSwitchHook(pdu, 0, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_PAYLOAD_PCDU_CH1): {
+ channelSwitchHook(pdu, 1, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_RW): {
+ channelSwitchHook(pdu, 2, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_TCS_BOARD_HEATER_IN): {
+ channelSwitchHook(pdu, 3, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_SUS_REDUNDANT): {
+ channelSwitchHook(pdu, 4, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_DEPLOYMENT_MECHANISM): {
+ channelSwitchHook(pdu, 5, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_PAYLOAD_PCDU_CH6PLOC): {
+ channelSwitchHook(pdu, 6, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_ACS_BOARD_SIDE_B): {
+ channelSwitchHook(pdu, 7, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ case (CONFIG_ADDRESS_OUT_EN_PAYLOAD_CAMERA): {
+ channelSwitchHook(pdu, 8, unpacker.getParameter()[0], hookArgs);
+ break;
+ }
+ }
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+}
diff --git a/mission/devices/PDU2Handler.h b/mission/devices/PDU2Handler.h
index 258b616d..f2323615 100644
--- a/mission/devices/PDU2Handler.h
+++ b/mission/devices/PDU2Handler.h
@@ -26,6 +26,7 @@ class PDU2Handler : public GomspaceDeviceHandler {
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
+ void assignChannelHookFunction(GOMSPACE::ChannelSwitchHook hook, void* args);
protected:
/**
@@ -34,10 +35,13 @@ class PDU2Handler : public GomspaceDeviceHandler {
virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t* id) override;
virtual void letChildHandleHkReply(DeviceCommandId_t id, const uint8_t* packet) override;
ReturnValue_t printStatus(DeviceCommandId_t cmd) override;
+ ReturnValue_t setParamCallback(SetParamMessageUnpacker& unpacker, bool afterExecution) override;
private:
/** Dataset for the housekeeping table of the PDU2 */
PDU2::PDU2HkTableDataset pdu2HkTableDataset;
+ GOMSPACE::ChannelSwitchHook channelSwitchHook = nullptr;
+ void* hookArgs = nullptr;
void printHkTable();
diff --git a/mission/devices/devicedefinitions/GPSDefinitions.h b/mission/devices/devicedefinitions/GPSDefinitions.h
index ce58f680..5a565fea 100644
--- a/mission/devices/devicedefinitions/GPSDefinitions.h
+++ b/mission/devices/devicedefinitions/GPSDefinitions.h
@@ -55,7 +55,7 @@ class GpsPrimaryDataset : public StaticLocalDataSet<18> {
lp_var_t(sid.objectId, GpsHyperion::UNIX_SECONDS, this);
private:
- friend class GPSHyperionHandler;
+ friend class GPSHyperionLinuxController;
GpsPrimaryDataset(HasLocalDataPoolIF* hkOwner)
: StaticLocalDataSet(hkOwner, GpsHyperion::DATASET_ID) {}
};
diff --git a/mission/devices/devicedefinitions/GomspaceDefinitions.h b/mission/devices/devicedefinitions/GomspaceDefinitions.h
index a575747f..995d9a7a 100644
--- a/mission/devices/devicedefinitions/GomspaceDefinitions.h
+++ b/mission/devices/devicedefinitions/GomspaceDefinitions.h
@@ -1,11 +1,3 @@
-/*
- * GomspaceDefinitions.h
- *
- * @brief This file holds all definitions specific for devices from gomspace.
- * @date 20.12.2020
- * @author J. Meier
- */
-
#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_
#define MISSION_DEVICES_DEVICEDEFINITIONS_GOMSPACEDEFINITIONS_H_
@@ -16,6 +8,11 @@
#include
namespace GOMSPACE {
+
+enum class Pdu { PDU1, PDU2 };
+
+using ChannelSwitchHook = void (*)(Pdu pdu, uint8_t channel, bool on, void* args);
+
static const uint16_t IGNORE_CHECKSUM = 0xbb0;
/** The size of the header of a gomspace CSP packet. */
static const uint8_t GS_HDR_LENGTH = 12;
@@ -363,6 +360,22 @@ enum P60SytemPoolIds : lp_id_t {
namespace P60Dock {
+enum SwitchChannels : uint8_t {
+ ACU = 0,
+ PDU1 = 1,
+ X3_IDLE = 2,
+ PDU2_VCC = 3,
+ ACU_VBAT = 4,
+ PDU1_VBAT = 5,
+ X3_IDLE_VBAT = 6,
+ PDU2_VBAT = 7,
+ STACK_VBAT = 8,
+ STACK_3V3 = 9,
+ STACK_5V = 10,
+ GS3V3 = 11,
+ GS5V = 12
+};
+
/** Max reply size reached when requesting full hk table */
static const uint16_t MAX_REPLY_LENGTH = 407;
@@ -611,19 +624,32 @@ static const uint8_t HK_TABLE_ENTRIES = 73;
namespace PDU1 {
static const uint32_t HK_TABLE_DATA_SET_ID = 0x1; // hk table has table id 4
+
+enum SwitchChannels : uint8_t {
+ TCS_BOARD_3V3 = 0,
+ SYRLINKS = 1,
+ STR = 2,
+ MGT = 3,
+ SUS_NOMINAL = 4,
+ SOL_CELL_EXPERIMENT = 5,
+ PLOC = 6,
+ ACS_A_SIDE = 7,
+ UNUSED = 8
+};
+
/**
* Addresses within configuration table to enable or disable output channels. Refer also to
* gs-man-nanopower-p60-pdu-200.pdf on page 16.
*/
static const uint16_t CONFIG_ADDRESS_OUT_EN_TCS_BOARD_3V3 = 0x48;
static const uint16_t CONFIG_ADDRESS_OUT_EN_SYRLINKS = 0x49;
-static const uint16_t CONFIG_ADDRESS_OUT_EN_STAR_TRACKER = 0x50;
-static const uint16_t CONFIG_ADDRESS_OUT_EN_MGT = 0x51;
-static const uint16_t CONFIG_ADDRESS_OUT_EN_SUS_NOMINAL = 0x52;
-static const uint16_t CONFIG_ADDRESS_OUT_EN_SOLAR_CELL_EXP = 0x53;
-static const uint16_t CONFIG_ADDRESS_OUT_EN_PLOC = 0x54;
-static const uint16_t CONFIG_ADDRESS_OUT_EN_ACS_BOARD_SIDE_A = 0x55;
-static const uint16_t CONFIG_ADDRESS_OUT_EN_CHANNEL8 = 0x56;
+static const uint16_t CONFIG_ADDRESS_OUT_EN_STAR_TRACKER = 0x4A;
+static const uint16_t CONFIG_ADDRESS_OUT_EN_MGT = 0x4B;
+static const uint16_t CONFIG_ADDRESS_OUT_EN_SUS_NOMINAL = 0x4C;
+static const uint16_t CONFIG_ADDRESS_OUT_EN_SOLAR_CELL_EXP = 0x4D;
+static const uint16_t CONFIG_ADDRESS_OUT_EN_PLOC = 0x4E;
+static const uint16_t CONFIG_ADDRESS_OUT_EN_ACS_BOARD_SIDE_A = 0x4F;
+static const uint16_t CONFIG_ADDRESS_OUT_EN_CHANNEL8 = 0x50;
/**
* @brief This class defines a dataset for the hk table of the PDU1.
@@ -799,6 +825,19 @@ class PDU1HkTableDataset : public StaticLocalDataSet {
namespace PDU2 {
static const uint32_t HK_TABLE_DATA_SET_ID = 0x2;
+
+enum SwitchChannels : uint8_t {
+ Q7S = 0,
+ PAYLOAD_PCDU_CH1 = 1,
+ RW = 2,
+ TCS_HEATER_IN = 3,
+ SUS_REDUNDANT = 4,
+ DEPY_MECHANISM = 5,
+ PAYLOAD_PCDU_CH6 = 6,
+ ACS_B_SIDE = 7,
+ PAYLOAD_CAMERA = 8
+};
+
/**
* Addresses within configuration table to enable or disable output channels. Refer also to
* gs-man-nanopower-p60-pdu-200.pdf on page 16.
diff --git a/mission/tmtc/CCSDSHandler.cpp b/mission/tmtc/CCSDSHandler.cpp
index ba34d273..35978627 100644
--- a/mission/tmtc/CCSDSHandler.cpp
+++ b/mission/tmtc/CCSDSHandler.cpp
@@ -1,22 +1,24 @@
#include "CCSDSHandler.h"
#include
+#include
#include "fsfw/events/EventManagerIF.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
+#include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
CCSDSHandler::CCSDSHandler(object_id_t objectId, object_id_t ptmeId, object_id_t tcDestination,
- TxRateSetterIF* txRateSetterIF, GpioIF* gpioIF, gpioId_t enTxClock,
+ PtmeConfig* ptmeConfig, GpioIF* gpioIF, gpioId_t enTxClock,
gpioId_t enTxData)
: SystemObject(objectId),
ptmeId(ptmeId),
tcDestination(tcDestination),
parameterHelper(this),
actionHelper(this, nullptr),
- txRateSetterIF(txRateSetterIF),
+ ptmeConfig(ptmeConfig),
gpioIF(gpioIF),
enTxClock(enTxClock),
enTxData(enTxData) {
@@ -110,6 +112,15 @@ ReturnValue_t CCSDSHandler::initialize() {
#endif
return result;
}
+ result = ptmeConfig->initialize();
+ if (result != RETURN_OK) {
+ return ObjectManagerIF::CHILD_INIT_FAILED;
+ }
+
+#if OBSW_SYRLINKS_SIMULATED == 1
+ ptmeConfig->invertTxClock(true);
+#endif /* OBSW_SYRLINKS_SIMULATED == 1*/
+
return result;
}
@@ -189,26 +200,53 @@ MessageQueueId_t CCSDSHandler::getRequestQueue() {
ReturnValue_t CCSDSHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
+ ReturnValue_t result = RETURN_OK;
switch (actionId) {
case SET_LOW_RATE: {
- txRateSetterIF->setRate(BitRates::RATE_400KHZ);
- return EXECUTION_FINISHED;
+ result = ptmeConfig->setRate(RATE_100KBPS);
+ break;
}
case SET_HIGH_RATE: {
- txRateSetterIF->setRate(BitRates::RATE_2000KHZ);
- return EXECUTION_FINISHED;
+ result = ptmeConfig->setRate(RATE_500KBPS);
+ break;
+ }
+ case ARBITRARY_RATE: {
+ uint32_t bitrate = 0;
+ SerializeAdapter::deSerialize(&bitrate, &data, &size, SerializeIF::Endianness::BIG);
+ result = ptmeConfig->setRate(bitrate);
+ break;
}
case EN_TRANSMITTER: {
enableTransmit();
return EXECUTION_FINISHED;
}
- case DIS_TRANSMITTER: {
+ case DISABLE_TRANSMITTER: {
disableTransmit();
return EXECUTION_FINISHED;
}
+ case ENABLE_TX_CLK_MANIPULATOR: {
+ result = ptmeConfig->configTxManipulator(true);
+ break;
+ }
+ case DISABLE_TX_CLK_MANIPULATOR: {
+ result = ptmeConfig->configTxManipulator(false);
+ break;
+ }
+ case UPDATE_ON_RISING_EDGE: {
+ result = ptmeConfig->invertTxClock(false);
+ break;
+ }
+ case UPDATE_ON_FALLING_EDGE: {
+ result = ptmeConfig->invertTxClock(true);
+ break;
+ }
default:
return COMMAND_NOT_IMPLEMENTED;
}
+ if (result != RETURN_OK) {
+ return result;
+ }
+ return EXECUTION_FINISHED;
}
void CCSDSHandler::checkEvents() {
diff --git a/mission/tmtc/CCSDSHandler.h b/mission/tmtc/CCSDSHandler.h
index 8203b807..4f62102c 100644
--- a/mission/tmtc/CCSDSHandler.h
+++ b/mission/tmtc/CCSDSHandler.h
@@ -17,12 +17,15 @@
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
#include "fsfw_hal/common/gpio/GpioIF.h"
#include "fsfw_hal/common/gpio/gpioDefinitions.h"
-#include "linux/obc/TxRateSetterIF.h"
+#include "linux/obc/PtmeConfig.h"
/**
* @brief This class handles the data exchange with the CCSDS IP cores implemented in the
* programmable logic of the Q7S.
*
+ * @details After reboot default CADU bitrate is always set to 100 kbps (results in downlink rate
+ * of 200 kbps due to convolutional code added by syrlinks transceiver)
+ *
* @author J. Meier
*/
class CCSDSHandler : public SystemObject,
@@ -48,8 +51,7 @@ class CCSDSHandler : public SystemObject,
* @param enTxData GPIO ID of RS485 tx data enable
*/
CCSDSHandler(object_id_t objectId, object_id_t ptmeId, object_id_t tcDestination,
- TxRateSetterIF* txRateSetterIF, GpioIF* gpioIF, gpioId_t enTxClock,
- gpioId_t enTxData);
+ PtmeConfig* ptmeConfig, GpioIF* gpioIF, gpioId_t enTxClock, gpioId_t enTxData);
~CCSDSHandler();
@@ -84,18 +86,31 @@ class CCSDSHandler : public SystemObject,
static const ActionId_t SET_LOW_RATE = 0;
static const ActionId_t SET_HIGH_RATE = 1;
static const ActionId_t EN_TRANSMITTER = 2;
- static const ActionId_t DIS_TRANSMITTER = 3;
+ static const ActionId_t DISABLE_TRANSMITTER = 3;
+ static const ActionId_t ARBITRARY_RATE = 4;
+ static const ActionId_t ENABLE_TX_CLK_MANIPULATOR = 5;
+ static const ActionId_t DISABLE_TX_CLK_MANIPULATOR = 6;
+ // Will update data with respect to tx clock signal of cadu bitsream on rising edge
+ static const ActionId_t UPDATE_ON_RISING_EDGE = 7;
+ // Will update data with respect to tx clock signal of cadu bitsream on falling edge
+ static const ActionId_t UPDATE_ON_FALLING_EDGE = 8;
+
+ // Syrlinks supports two bitrates (200 kbps and 1000 kbps)
+ // Due to convolutional code added by the syrlinks the input frequency must be half the
+ // target frequency
+ static const uint32_t RATE_100KBPS = 100000;
+ static const uint32_t RATE_500KBPS = 500000;
//! [EXPORT] : [COMMENT] Received action message with unknown action id
static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xA0);
-#if TMTC_TEST_SETUP == 0
+#if OBSW_ENABLE_SYRLINKS_TRANSMIT_TIMEOUT == 1
// syrlinks must not be transmitting more than 15 minutes (according to datasheet)
static const uint32_t TRANSMITTER_TIMEOUT = 900000; // 900000 ms = 15 min
#else
// Set to high value when not sending via syrlinks
static const uint32_t TRANSMITTER_TIMEOUT = 86400000; // 1 day
-#endif /* TMTC_TEST_SETUP == 0 */
+#endif /* OBSW_SYRLINKS_DOWNLINK == 0 */
static const bool UP = true;
static const bool DOWN = false;
@@ -119,7 +134,7 @@ class CCSDSHandler : public SystemObject,
MessageQueueId_t tcDistributorQueueId;
- TxRateSetterIF* txRateSetterIF = nullptr;
+ PtmeConfig* ptmeConfig = nullptr;
GpioIF* gpioIF = nullptr;
gpioId_t enTxClock = gpio::NO_GPIO;
diff --git a/scripts/q7s-cp.py b/scripts/q7s-cp.py
index 0c8c1a79..0478001a 100755
--- a/scripts/q7s-cp.py
+++ b/scripts/q7s-cp.py
@@ -1,44 +1,75 @@
#!/usr/bin/env python3
import argparse
import os
+import sys
def main():
args = handle_args()
cmd = build_cmd(args)
# Run the command
- print(f'Running command: {cmd}')
+ print(f"Running command: {cmd}")
result = os.system(cmd)
if result != 0:
- print('')
- print('Removing problematic SSH key and trying again..')
- remove_ssh_key_cmd = 'ssh-keygen -f "${HOME}/.ssh/known_hosts" -R "[localhost]:1535"'
+ print("")
+ print("Removing problematic SSH key and trying again..")
+ remove_ssh_key_cmd = (
+ 'ssh-keygen -f "${HOME}/.ssh/known_hosts" -R "[localhost]:1535"'
+ )
os.system(remove_ssh_key_cmd)
+ print(f'Running command "{cmd}"')
result = os.system(cmd)
def handle_args():
- help_string = 'This script copies files to the Q7S as long as port forwarding is active.\n'
- help_string += 'You can set up port forwarding with ' \
- '"ssh -L 1535:192.168.133.10:22 " -t /bin/bash'
- parser = argparse.ArgumentParser(
- description=help_string
+ help_string = (
+ "This script copies files to the Q7S as long as port forwarding is active.\n"
)
+ help_string += (
+ "You can set up port forwarding with "
+ '"ssh -L 1535:192.168.133.10:22 " -t /bin/bash'
+ )
+ parser = argparse.ArgumentParser(description=help_string)
# Optional arguments
- parser.add_argument('-r', '--recursive', dest='recursive', default=False, action='store_true')
- parser.add_argument('-t', '--target', help='Target destination', default='/tmp')
- parser.add_argument('-P', '--port', help='Target port', default=1535)
+ parser.add_argument(
+ "-r", "--recursive", dest="recursive", default=False, action="store_true"
+ )
+ parser.add_argument(
+ "-t",
+ "--target",
+ help="Target destination. If files are copied to Q7S, will be /tmp by default. "
+ "If files are copied back to host, will be current directory by default",
+ default="",
+ )
+ parser.add_argument("-P", "--port", help="Target port", default=1535)
+ parser.add_argument(
+ "-i",
+ "--invert",
+ default=False,
+ action="store_true",
+ help="Copy from Q7S to host instead. Always copies to current directory.",
+ )
# Positional argument(s)
- parser.add_argument('source', help='Source files to copy')
+ parser.add_argument(
+ "source", help="Source files to copy or target files to copy back to host"
+ )
return parser.parse_args()
def build_cmd(args):
# Build run command
- cmd = 'scp '
+ cmd = "scp "
if args.recursive:
- cmd += '-r '
- cmd += f'-P {args.port} {args.source} root@localhost:'
+ cmd += "-r "
+ target = args.target
+ if args.invert and target == "":
+ target = "."
+ elif target == "":
+ target = f"/tmp"
+ if args.invert:
+ cmd += f"-P {args.port} root@localhost:{args.source} {target}"
+ else:
+ cmd += f"-P {args.port} {args.source} root@localhost:{target}"
if args.target:
cmd += args.target
return cmd
diff --git a/tmtc b/tmtc
index 6f24d6a8..8da50e2c 160000
--- a/tmtc
+++ b/tmtc
@@ -1 +1 @@
-Subproject commit 6f24d6a83995ca7a895c17a77a00bceac4d7f141
+Subproject commit 8da50e2c3f709def5b26fd9df1cd23beac35482e