SPI update, Version bump #22

Merged
meierj merged 52 commits from mueller/spi-com-if-tested into develop 2021-03-04 18:23:43 +01:00
84 changed files with 2896 additions and 1391 deletions

View File

@ -61,6 +61,14 @@ if(TGT_BSP)
set(ADD_LINUX_FILES TRUE) set(ADD_LINUX_FILES TRUE)
set(ADD_CSP_LIB TRUE) set(ADD_CSP_LIB TRUE)
endif() endif()
if(${TGT_BSP} MATCHES "arm/raspberrypi")
add_definitions(-DRASPBERRY_PI)
endif()
if(${TGT_BSP} MATCHES "arm/q7s")
add_definitions(-DXIPHOS_Q7S)
endif()
else() else()
# Required by FSFW library # Required by FSFW library
set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig") set(FSFW_CONFIG_PATH "${BSP_PATH}/fsfwconfig")

View File

@ -11,6 +11,8 @@
#include <fsfw/tasks/PeriodicTaskIF.h> #include <fsfw/tasks/PeriodicTaskIF.h>
#include <fsfw/tasks/TaskFactory.h> #include <fsfw/tasks/TaskFactory.h>
#include <mission/utility/InitMission.h>
#include <iostream> #include <iostream>
// This is configured for linux without \cr // This is configured for linux without \cr
@ -28,7 +30,7 @@ ServiceInterfaceStream sif::error("ERROR", true, false, true);
ObjectManagerIF *objectManager = nullptr; ObjectManagerIF *objectManager = nullptr;
void InitMission::initMission() { void initmission::initMission() {
sif::info << "Building global objects.." << std::endl; sif::info << "Building global objects.." << std::endl;
/* Instantiate global object manager and also create all objects */ /* Instantiate global object manager and also create all objects */
objectManager = new ObjectManager(ObjectFactory::produce); objectManager = new ObjectManager(ObjectFactory::produce);
@ -39,7 +41,7 @@ void InitMission::initMission() {
initTasks(); initTasks();
} }
void InitMission::initTasks(){ void initmission::initTasks(){
/* TMTC Distribution */ /* TMTC Distribution */
PeriodicTaskIF* TmTcDistributor = TaskFactory::instance()-> PeriodicTaskIF* TmTcDistributor = TaskFactory::instance()->
createPeriodicTask("DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, createPeriodicTask("DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE,

View File

@ -1,7 +1,7 @@
#ifndef BSP_LINUX_INITMISSION_H_ #ifndef BSP_LINUX_INITMISSION_H_
#define BSP_LINUX_INITMISSION_H_ #define BSP_LINUX_INITMISSION_H_
namespace InitMission { namespace initmission {
void initMission(); void initMission();
void initTasks(); void initTasks();
}; };

View File

@ -24,7 +24,7 @@ int main(void)
<< SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl; << SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl;
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl; std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
InitMission::initMission(); initmission::initMission();
for(;;) { for(;;) {
// suspend main thread by sleeping it. // suspend main thread by sleeping it.

View File

@ -6,6 +6,7 @@ target_sources(${TARGET_NAME} PUBLIC
add_subdirectory(boardconfig) add_subdirectory(boardconfig)
add_subdirectory(comIF) add_subdirectory(comIF)
add_subdirectory(devices)
add_subdirectory(boardtest) add_subdirectory(boardtest)

View File

@ -2,6 +2,8 @@
#include "ObjectFactory.h" #include "ObjectFactory.h"
#include <OBSWConfig.h> #include <OBSWConfig.h>
#include <mission/utility/InitMission.h>
#include <fsfw/objectmanager/ObjectManagerIF.h> #include <fsfw/objectmanager/ObjectManagerIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h> #include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h> #include <fsfw/serviceinterface/ServiceInterfaceStream.h>
@ -13,7 +15,7 @@
#include <iostream> #include <iostream>
// This is configured for linux without \cr /* This is configured for linux without CR */
#ifdef LINUX #ifdef LINUX
ServiceInterfaceStream sif::debug("DEBUG"); ServiceInterfaceStream sif::debug("DEBUG");
ServiceInterfaceStream sif::info("INFO"); ServiceInterfaceStream sif::info("INFO");
@ -28,7 +30,7 @@ ServiceInterfaceStream sif::error("ERROR", true, false, true);
ObjectManagerIF *objectManager = nullptr; ObjectManagerIF *objectManager = nullptr;
void InitMission::initMission() { void initmission::initMission() {
sif::info << "Building global objects.." << std::endl; sif::info << "Building global objects.." << std::endl;
/* Instantiate global object manager and also create all objects */ /* Instantiate global object manager and also create all objects */
objectManager = new ObjectManager(ObjectFactory::produce); objectManager = new ObjectManager(ObjectFactory::produce);
@ -39,144 +41,148 @@ void InitMission::initMission() {
initTasks(); initTasks();
} }
void InitMission::initTasks(){ void initmission::initTasks() {
TaskFactory* factory = TaskFactory::instance();
if(factory == nullptr) {
/* Should never happen ! */
return;
}
#if OBSW_PRINT_MISSED_DEADLINES == 1
void (*missedDeadlineFunc) (void) = TaskFactory::printMissedDeadline;
#else
void (*missedDeadlineFunc) (void) = nullptr;
#endif
/* TMTC Distribution */ /* TMTC Distribution */
PeriodicTaskIF* TmTcDistributor = TaskFactory::instance()-> PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask(
createPeriodicTask("DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, "DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
0.2, nullptr); ReturnValue_t result = tmTcDistributor->addComponent(
ReturnValue_t result = TmTcDistributor->addComponent(
objects::CCSDS_PACKET_DISTRIBUTOR); objects::CCSDS_PACKET_DISTRIBUTOR);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = TmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = TmTcDistributor->addComponent(objects::TM_FUNNEL);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Object add component failed" << std::endl; initmission::printAddObjectError("CCSDS_DISTRIB", objects::CCSDS_PACKET_DISTRIBUTOR);
}
result = tmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_PACKET_DISTRIB", objects::PUS_PACKET_DISTRIBUTOR);
}
result = tmTcDistributor->addComponent(objects::TM_FUNNEL);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("TM_FUNNEL", objects::TM_FUNNEL);
} }
/* UDP bridge */ /* UDP bridge */
PeriodicTaskIF* UdpBridgeTask = TaskFactory::instance()->createPeriodicTask( PeriodicTaskIF* udpBridgeTask = factory->createPeriodicTask(
"UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, "UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
0.2, nullptr); result = udpBridgeTask->addComponent(objects::UDP_BRIDGE);
result = UdpBridgeTask->addComponent(objects::UDP_BRIDGE);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Unix Bridge failed" << std::endl; initmission::printAddObjectError("UDP_BRIDGE", objects::UDP_BRIDGE);
} }
PeriodicTaskIF* UdpPollingTask = TaskFactory::instance()-> PeriodicTaskIF* udpPollingTask = factory->createPeriodicTask(
createPeriodicTask("UDP_POLLING", 80, "UDP_POLLING", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, nullptr); result = udpPollingTask->addComponent(objects::UDP_POLLING_TASK);
result = UdpPollingTask->addComponent(objects::UDP_POLLING_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Polling failed" << std::endl; initmission::printAddObjectError("UDP_POLLING", objects::UDP_POLLING_TASK);
} }
/* PUS Services */ /* PUS Services */
PeriodicTaskIF* PusVerification = TaskFactory::instance()-> PeriodicTaskIF* pusVerification = factory->createPeriodicTask(
createPeriodicTask("PUS_VERIF_1", 40, "PUS_VERIF", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr); result = pusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
result = PusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION); if(result != HasReturnvaluesIF::RETURN_OK) {
if(result != HasReturnvaluesIF::RETURN_OK){ initmission::printAddObjectError("PUS_VERIF", objects::PUS_SERVICE_1_VERIFICATION);
sif::error << "Object add component failed" << std::endl;
} }
PeriodicTaskIF* PusEvents = TaskFactory::instance()-> PeriodicTaskIF* pusEvents = factory->createPeriodicTask(
createPeriodicTask("PUS_VERIF_1", 60, "PUS_EVENTS", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr); result = pusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
result = PusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING); if(result != HasReturnvaluesIF::RETURN_OK) {
if(result != HasReturnvaluesIF::RETURN_OK){ initmission::printAddObjectError("PUS_EVENTS", objects::PUS_SERVICE_5_EVENT_REPORTING);
sif::error << "Object add component failed" << std::endl;
} }
PeriodicTaskIF* PusHighPrio = TaskFactory::instance()-> PeriodicTaskIF* pusHighPrio = factory->createPeriodicTask(
createPeriodicTask("PUS_HIGH_PRIO", 50, "PUS_HIGH_PRIO", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, result = pusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
0.200, nullptr); if(result != HasReturnvaluesIF::RETURN_OK) {
result = PusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS); initmission::printAddObjectError("PUS_2", objects::PUS_SERVICE_2_DEVICE_ACCESS);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
} }
result = PusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT); result = pusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT);
if(result!=HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Object add component failed" << std::endl; initmission::printAddObjectError("PUS_9", objects::PUS_SERVICE_9_TIME_MGMT);
} }
PeriodicTaskIF* PusMedPrio = TaskFactory::instance()-> PeriodicTaskIF* pusMedPrio = factory->createPeriodicTask(
createPeriodicTask("PUS_HIGH_PRIO", 40, "PUS_MED_PRIO", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, result = pusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
0.8, nullptr); if(result != HasReturnvaluesIF::RETURN_OK) {
result = PusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT); initmission::printAddObjectError("PUS_8", objects::PUS_SERVICE_8_FUNCTION_MGMT);
if(result!=HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
} }
result = PusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT); result = pusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
if(result!=HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Object add component failed" << std::endl; initmission::printAddObjectError("PUS_200", objects::PUS_SERVICE_200_MODE_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_20_PARAMETERS);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS_20", objects::PUS_SERVICE_20_PARAMETERS);
} }
PeriodicTaskIF* PusLowPrio = TaskFactory::instance()-> PeriodicTaskIF* pusLowPrio = factory->createPeriodicTask(
createPeriodicTask("PUSB", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, "PUS_LOW_PRIO", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.6, missedDeadlineFunc);
1.6, nullptr); result = pusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST);
result = PusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST); if(result != HasReturnvaluesIF::RETURN_OK) {
if(result!=HasReturnvaluesIF::RETURN_OK){ initmission::printAddObjectError("PUS_17", objects::PUS_SERVICE_17_TEST);
sif::error << "Object add component failed" << std::endl;
} }
//TODO: Add handling of missed deadlines //TODO: Add handling of missed deadlines
/* Polling Sequence Table Default */ /* Polling Sequence Table Default */
FixedTimeslotTaskIF * PollingSequenceTableTaskDefault = FixedTimeslotTaskIF * pollingSequenceTableTaskDefault = factory->createFixedTimeslotTask(
TaskFactory::instance()->createFixedTimeslotTask("PST_TASK_DEFAULT", "PST_TASK_DEFAULT", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE * 4, 3.0,
50, PeriodicTaskIF::MINIMUM_STACK_SIZE*4, 3.0, missedDeadlineFunc);
nullptr); result = pst::pollingSequenceInitDefault(pollingSequenceTableTaskDefault);
result = pst::pollingSequenceInitDefault(PollingSequenceTableTaskDefault);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "InitMission::initTasks: Creating PST failed!" sif::error << "InitMission::initTasks: Creating PST failed!" << std::endl;
<< std::endl;
} }
#if TE0720 == 0 #if TE0720 == 0
FixedTimeslotTaskIF* GomSpacePstTask = TaskFactory::instance()-> FixedTimeslotTaskIF* gomSpacePstTask = factory->
createFixedTimeslotTask("GS_PST_TASK", 50, createFixedTimeslotTask("GS_PST_TASK", 50,
PeriodicTaskIF::MINIMUM_STACK_SIZE*8, 3.0, nullptr); PeriodicTaskIF::MINIMUM_STACK_SIZE*8, 3.0, missedDeadlineFunc);
result = pst::gomspacePstInit(GomSpacePstTask); result = pst::gomspacePstInit(gomSpacePstTask);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "InitMission::initTasks: GomSpace PST initialization " sif::error << "InitMission::initTasks: GomSpace PST initialization failed!" << std::endl;
<< "failed!" << std::endl;
} }
#endif #endif
PeriodicTaskIF* testTask = factory->createPeriodicTask(
"GPIOD_TEST", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1, missedDeadlineFunc);
#if OBSW_ADD_TEST_CODE == 1
result = testTask->addComponent(objects::TEST_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("TEST_TASK", objects::TEST_TASK);
}
#endif /* OBSW_ADD_TEST_CODE == 1 */
#if TE0720 == 1 && TEST_LIBGPIOD == 1 #if TE0720 == 1 && TEST_LIBGPIOD == 1
PeriodicTaskIF* TestTask = TaskFactory::instance()-> result = testTask->addComponent(objects::LIBGPIOD_TEST);
createPeriodicTask("Libgpiod Test Task", 60, if(result != HasReturnvaluesIF::RETURN_OK) {
PeriodicTaskIF::MINIMUM_STACK_SIZE, 1, nullptr); initmission::printAddObjectError("GPIOD_TEST", objects::LIBGPIOD_TEST);
result = TestTask->addComponent(objects::LIBGPIOD_TEST);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component libgpiod test task object" << std::endl;
} }
#endif #endif /* TE0720 == 1 && TEST_LIBGPIOD == 1 */
//Main thread sleep
sif::info << "Starting tasks.." << std::endl; sif::info << "Starting tasks.." << std::endl;
TmTcDistributor->startTask(); tmTcDistributor->startTask();
UdpBridgeTask->startTask(); udpBridgeTask->startTask();
UdpPollingTask->startTask(); udpPollingTask->startTask();
#if TE0720 == 0 #if TE0720 == 0
GomSpacePstTask->startTask(); gomSpacePstTask->startTask();
#endif #endif
PollingSequenceTableTaskDefault->startTask(); pollingSequenceTableTaskDefault->startTask();
PusVerification->startTask(); pusVerification->startTask();
PusEvents->startTask(); pusEvents->startTask();
PusHighPrio->startTask(); pusHighPrio->startTask();
PusMedPrio->startTask(); pusMedPrio->startTask();
PusLowPrio->startTask(); pusLowPrio->startTask();
#if TE0720 == 1 && TEST_LIBGPIOD == 1 testTask->startTask();
TestTask->startTask();
#endif
sif::info << "Tasks started.." << std::endl; sif::info << "Tasks started.." << std::endl;
} }

View File

@ -1,7 +1,7 @@
#ifndef BSP_Q7S_INITMISSION_H_ #ifndef BSP_Q7S_INITMISSION_H_
#define BSP_Q7S_INITMISSION_H_ #define BSP_Q7S_INITMISSION_H_
namespace InitMission { namespace initmission {
void initMission(); void initMission();
void initTasks(); void initTasks();
}; };

View File

@ -4,15 +4,9 @@
#include <devices/addresses.h> #include <devices/addresses.h>
#include <devices/gpioIds.h> #include <devices/gpioIds.h>
#include <tmtc/pusIds.h> #include <tmtc/pusIds.h>
#include <devices/powerSwitcherList.h>
#include <fsfw/datapoollocal/LocalDataPoolManager.h> #include <bsp_q7s/devices/HeaterHandler.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h>
#include <fsfw/osal/linux/TmTcUnixUdpBridge.h>
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#include <fsfw/osal/linux/TcUnixUdpPollingTask.h>
#include <fsfwconfig/devices/powerSwitcherList.h>
#include <mission/core/GenericFactory.h> #include <mission/core/GenericFactory.h>
#include <mission/devices/PDU1Handler.h> #include <mission/devices/PDU1Handler.h>
@ -21,7 +15,6 @@
#include <mission/devices/PCDUHandler.h> #include <mission/devices/PCDUHandler.h>
#include <mission/devices/P60DockHandler.h> #include <mission/devices/P60DockHandler.h>
#include <mission/devices/Tmp1075Handler.h> #include <mission/devices/Tmp1075Handler.h>
#include <mission/devices/HeaterHandler.h>
#include <mission/devices/SolarArrayDeploymentHandler.h> #include <mission/devices/SolarArrayDeploymentHandler.h>
#include <mission/devices/devicedefinitions/GomSpacePackets.h> #include <mission/devices/devicedefinitions/GomSpacePackets.h>
#include <mission/devices/devicedefinitions/GomspaceDefinitions.h> #include <mission/devices/devicedefinitions/GomspaceDefinitions.h>
@ -34,8 +27,15 @@
#include <linux/gpio/LinuxLibgpioIF.h> #include <linux/gpio/LinuxLibgpioIF.h>
#include <linux/gpio/GpioCookie.h> #include <linux/gpio/GpioCookie.h>
#include <fsfw/datapoollocal/LocalDataPoolManager.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h>
#include <fsfw/osal/linux/TmTcUnixUdpBridge.h>
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#include <fsfw/osal/linux/TcUnixUdpPollingTask.h>
#if TEST_LIBGPIOD == 1 #if TEST_LIBGPIOD == 1
#include "LibgpiodTest.h" #include <linux/boardtest/LibgpiodTest.h>
#endif #endif
void Factory::setStaticFrameworkObjectIds() { void Factory::setStaticFrameworkObjectIds() {
@ -119,37 +119,37 @@ void ObjectFactory::produce(){
new LinuxLibgpioIF(objects::GPIO_IF); new LinuxLibgpioIF(objects::GPIO_IF);
#if TE0720 == 0 #if TE0720 == 0
/* Pin H2-11 on stack connector */ /* Pin H2-11 on stack connector */
GpioConfig_t gpioConfigHeater0(std::string("gpiochip7"), 18, GpiodRegular gpioConfigHeater0(std::string("gpiochip7"), 18,
std::string("Heater0"), gpio::OUT, 0); std::string("Heater0"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigHeater0); heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigHeater0);
/* Pin H2-12 on stack connector */ /* Pin H2-12 on stack connector */
GpioConfig_t gpioConfigHeater1(std::string("gpiochip7"), 14, GpiodRegular gpioConfigHeater1(std::string("gpiochip7"), 14,
std::string("Heater1"), gpio::OUT, 0); std::string("Heater1"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_1, gpioConfigHeater1); heaterGpiosCookie->addGpio(gpioIds::HEATER_1, gpioConfigHeater1);
/* Pin H2-13 on stack connector */ /* Pin H2-13 on stack connector */
GpioConfig_t gpioConfigHeater2(std::string("gpiochip7"), 20, GpiodRegular gpioConfigHeater2(std::string("gpiochip7"), 20,
std::string("Heater2"), gpio::OUT, 0); std::string("Heater2"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_2, gpioConfigHeater2); heaterGpiosCookie->addGpio(gpioIds::HEATER_2, gpioConfigHeater2);
GpioConfig_t gpioConfigHeater3(std::string("gpiochip7"), 16, GpiodRegular gpioConfigHeater3(std::string("gpiochip7"), 16,
std::string("Heater3"), gpio::OUT, 0); std::string("Heater3"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_3, gpioConfigHeater3); heaterGpiosCookie->addGpio(gpioIds::HEATER_3, gpioConfigHeater3);
GpioConfig_t gpioConfigHeater4(std::string("gpiochip7"), 24, GpiodRegular gpioConfigHeater4(std::string("gpiochip7"), 24,
std::string("Heater4"), gpio::OUT, 0); std::string("Heater4"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_4, gpioConfigHeater4); heaterGpiosCookie->addGpio(gpioIds::HEATER_4, gpioConfigHeater4);
GpioConfig_t gpioConfigHeater5(std::string("gpiochip7"), 26, GpiodRegular gpioConfigHeater5(std::string("gpiochip7"), 26,
std::string("Heater5"), gpio::OUT, 0); std::string("Heater5"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_5, gpioConfigHeater5); heaterGpiosCookie->addGpio(gpioIds::HEATER_5, gpioConfigHeater5);
GpioConfig_t gpioConfigHeater6(std::string("gpiochip7"), 22, GpiodRegular gpioConfigHeater6(std::string("gpiochip7"), 22,
std::string("Heater6"), gpio::OUT, 0); std::string("Heater6"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_6, gpioConfigHeater6); heaterGpiosCookie->addGpio(gpioIds::HEATER_6, gpioConfigHeater6);
GpioConfig_t gpioConfigHeater7(std::string("gpiochip7"), 28, GpiodRegular gpioConfigHeater7(std::string("gpiochip7"), 28,
std::string("Heater7"), gpio::OUT, 0); std::string("Heater7"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_7, gpioConfigHeater7); heaterGpiosCookie->addGpio(gpioIds::HEATER_7, gpioConfigHeater7);
@ -157,10 +157,10 @@ void ObjectFactory::produce(){
pcduSwitches::TCS_BOARD_8V_HEATER_IN); pcduSwitches::TCS_BOARD_8V_HEATER_IN);
GpioCookie* solarArrayDeplCookie = new GpioCookie; GpioCookie* solarArrayDeplCookie = new GpioCookie;
GpioConfig_t gpioConfigDeplSA1(std::string("gpiochip7"), 25, GpiodRegular gpioConfigDeplSA1(std::string("gpiochip7"), 25,
std::string("DeplSA1"), gpio::OUT, 0); std::string("DeplSA1"), gpio::OUT, 0);
solarArrayDeplCookie->addGpio(gpioIds::DEPLSA1, gpioConfigDeplSA1); solarArrayDeplCookie->addGpio(gpioIds::DEPLSA1, gpioConfigDeplSA1);
GpioConfig_t gpioConfigDeplSA2(std::string("gpiochip7"), 23, GpiodRegular gpioConfigDeplSA2(std::string("gpiochip7"), 23,
std::string("DeplSA2"), gpio::OUT, 0); std::string("DeplSA2"), gpio::OUT, 0);
solarArrayDeplCookie->addGpio(gpioIds::DEPLSA2, gpioConfigDeplSA2); solarArrayDeplCookie->addGpio(gpioIds::DEPLSA2, gpioConfigDeplSA2);
@ -180,14 +180,14 @@ void ObjectFactory::produce(){
GpioConfig_t gpioConfigMio0(std::string("gpiochip0"), 0, GpioConfig_t gpioConfigMio0(std::string("gpiochip0"), 0,
std::string("MIO0"), gpio::IN, 0); std::string("MIO0"), gpio::IN, 0);
GpioCookie* gpioCookie = new GpioCookie; GpioCookie* gpioCookie = new GpioCookie;
gpioCookie->addGpio(gpioIds::Test_ID, gpioConfigMio0); gpioCookie->addGpio(gpioIds::TEST_ID_0, gpioConfigMio0);
new LibgpiodTest(objects::LIBGPIOD_TEST, objects::GPIO_IF, gpioCookie); new LibgpiodTest(objects::LIBGPIOD_TEST, objects::GPIO_IF, gpioCookie);
#elif TE0720 == 1 #elif TE0720 == 1
/* Configuration for MIO0 on TE0720-03-1CFA */ /* Configuration for MIO0 on TE0720-03-1CFA */
GpioConfig_t gpioConfigForDummyHeater(std::string("gpiochip0"), 0, GpioConfig_t gpioConfigForDummyHeater(std::string("gpiochip0"), 0,
std::string("Heater0"), gpio::OUT, 0); std::string("Heater0"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigForDummyHeater); heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigForDummyHeater);
new HeaterHandler(objects::HEATER_HANDLER, objects::GPIO_IF, heaterGpiosCookie, objects::PCDU_HANDLER, new HeaterHandler(objects::HEATER_HANDLER, objects::GPIO_IF, heaterGpiosCookie,
pcduSwitches::TCS_BOARD_8V_HEATER_IN); objects::PCDU_HANDLER, pcduSwitches::TCS_BOARD_8V_HEATER_IN);
#endif #endif
} }

View File

@ -1,5 +1,4 @@
target_sources(${TARGET_NAME} PRIVATE target_sources(${TARGET_NAME} PRIVATE
LibgpiodTest.cpp
) )

View File

@ -1,37 +0,0 @@
#include "LibgpiodTest.h"
#include <fsfwconfig/devices/gpioIds.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#include <fsfw/objectmanager/ObjectManagerIF.h>
LibgpiodTest::LibgpiodTest(object_id_t objectId, object_id_t gpioIfobjectId,
GpioCookie* gpioCookie):
TestTask(objectId) {
gpioInterface = objectManager->get<GpioIF>(gpioIfobjectId);
if (gpioInterface == nullptr) {
sif::error << "LibgpiodTest::LibgpiodTest: Invalid Gpio interface." << std::endl;
}
gpioInterface->initialize(gpioCookie);
}
LibgpiodTest::~LibgpiodTest() {
}
ReturnValue_t LibgpiodTest::performPeriodicAction() {
int gpioState;
ReturnValue_t result;
result = gpioInterface->readGpio(gpioIds::Test_ID, &gpioState);
if (result != RETURN_OK) {
sif::debug << "LibgpiodTest::performPeriodicAction: Failed to read gpio "
<< std::endl;
return RETURN_FAILED;
}
else {
sif::debug << "LibgpiodTest::performPeriodicAction: MIO 0 state = " << gpioState
<< std::endl;
}
return RETURN_OK;
}

View File

@ -0,0 +1,3 @@
target_sources(${TARGET_NAME} PRIVATE
HeaterHandler.cpp
)

View File

@ -1,13 +1,14 @@
#include <mission/devices/HeaterHandler.h> #include "HeaterHandler.h"
#include <fsfwconfig/devices/powerSwitcherList.h> #include <fsfwconfig/devices/powerSwitcherList.h>
#include <fsfw/ipc/QueueFactory.h> #include <fsfw/ipc/QueueFactory.h>
#include <devices/gpioIds.h> #include <devices/gpioIds.h>
#include <linux/gpio/GpioCookie.h>
HeaterHandler::HeaterHandler(object_id_t setObjectId_, object_id_t gpioDriverId_, HeaterHandler::HeaterHandler(object_id_t setObjectId_, object_id_t gpioDriverId_,
CookieIF * gpioCookie_, object_id_t mainLineSwitcherObjectId_, uint8_t mainLineSwitch_) : CookieIF * gpioCookie_, object_id_t mainLineSwitcherObjectId_, uint8_t mainLineSwitch_) :
SystemObject(setObjectId_), gpioDriverId(gpioDriverId_), gpioCookie(gpioCookie_), mainLineSwitcherObjectId( SystemObject(setObjectId_), gpioDriverId(gpioDriverId_), gpioCookie(gpioCookie_),
mainLineSwitcherObjectId_), mainLineSwitch(mainLineSwitch_), actionHelper(this, mainLineSwitcherObjectId(mainLineSwitcherObjectId_), mainLineSwitch(mainLineSwitch_),
nullptr) { actionHelper(this, nullptr) {
commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize,
MessageQueueMessage::MAX_MESSAGE_SIZE); MessageQueueMessage::MAX_MESSAGE_SIZE);
} }
@ -42,7 +43,7 @@ ReturnValue_t HeaterHandler::initialize() {
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
result = gpioInterface->initialize(gpioCookie); result = gpioInterface->addGpios(dynamic_cast<GpioCookie*>(gpioCookie));
if (result != RETURN_OK) { if (result != RETURN_OK) {
sif::error << "HeaterHandler::initialize: Failed to initialize Gpio interface" << std::endl; sif::error << "HeaterHandler::initialize: Failed to initialize Gpio interface" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;

View File

@ -116,7 +116,7 @@ private:
CookieIF * gpioCookie; CookieIF * gpioCookie;
GpioIF* gpioInterface; GpioIF* gpioInterface = nullptr;
/** Queue to receive messages from other objects. */ /** Queue to receive messages from other objects. */
MessageQueueIF* commandQueue = nullptr; MessageQueueIF* commandQueue = nullptr;

View File

@ -13,15 +13,15 @@
int main(void) int main(void)
{ {
std::cout << "-- EIVE OBSW --" << std::endl; std::cout << "-- EIVE OBSW --" << std::endl;
std::cout << "-- Compiled for Linux " << " --" << std::endl; std::cout << "-- Compiled for Linux (Xiphos Q7S) --" << std::endl;
std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "." std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "."
<< SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl; << SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl;
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl; std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
InitMission::initMission(); initmission::initMission();
for(;;) { for(;;) {
// suspend main thread by sleeping it. /* Suspend main thread by sleeping it. */
TaskFactory::delayTask(5000); TaskFactory::delayTask(5000);
} }
} }

View File

@ -6,11 +6,8 @@ target_sources(${TARGET_NAME} PUBLIC
add_subdirectory(boardconfig) add_subdirectory(boardconfig)
add_subdirectory(boardtest) add_subdirectory(boardtest)
add_subdirectory(gpio)
# wiringPi is deprecated unfortunately..
#target_link_libraries(${TARGET_NAME} PRIVATE
# wiringPi
#)

View File

@ -1,16 +1,19 @@
#include "InitMission.h" #include "InitMission.h"
#include "ObjectFactory.h" #include "ObjectFactory.h"
#include <fsfwconfig/objects/systemObjectList.h>
#include <fsfwconfig/OBSWConfig.h>
#include <fsfwconfig/pollingsequence/PollingSequenceFactory.h>
#include <mission/utility/InitMission.h>
#include <fsfw/objectmanager/ObjectManagerIF.h> #include <fsfw/objectmanager/ObjectManagerIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h> #include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h> #include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/objectmanager/ObjectManager.h> #include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/tasks/FixedTimeslotTaskIF.h> #include <fsfw/tasks/FixedTimeslotTaskIF.h>
#include <fsfw/tasks/PeriodicTaskIF.h> #include <fsfw/tasks/PeriodicTaskIF.h>
#include <fsfw/tasks/TaskFactory.h> #include <fsfw/tasks/TaskFactory.h>
#include <fsfwconfig/objects/systemObjectList.h>
#include <fsfwconfig/OBSWConfig.h>
#include <fsfwconfig/pollingsequence/PollingSequenceFactory.h>
#include <iostream> #include <iostream>
@ -21,7 +24,7 @@ ServiceInterfaceStream sif::error("ERROR");
ObjectManagerIF *objectManager = nullptr; ObjectManagerIF *objectManager = nullptr;
void InitMission::initMission() { void initmission::initMission() {
sif::info << "Building global objects.." << std::endl; sif::info << "Building global objects.." << std::endl;
/* Instantiate global object manager and also create all objects */ /* Instantiate global object manager and also create all objects */
objectManager = new ObjectManager(ObjectFactory::produce); objectManager = new ObjectManager(ObjectFactory::produce);
@ -32,129 +35,144 @@ void InitMission::initMission() {
initTasks(); initTasks();
} }
void InitMission::initTasks(){ void initmission::initTasks() {
TaskFactory* factory = TaskFactory::instance();
if(factory == nullptr) {
/* Should never happen ! */
return;
}
#if OBSW_PRINT_MISSED_DEADLINES == 1
void (*missedDeadlineFunc) (void) = TaskFactory::printMissedDeadline;
#else
void (*missedDeadlineFunc) (void) = nullptr;
#endif
/* TMTC Distribution */ /* TMTC Distribution */
PeriodicTaskIF* TmTcDistributor = TaskFactory::instance()-> PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask(
createPeriodicTask("DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, "DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
0.100, nullptr); ReturnValue_t result = tmTcDistributor->addComponent(
ReturnValue_t result = TmTcDistributor->addComponent(
objects::CCSDS_PACKET_DISTRIBUTOR); objects::CCSDS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl; sif::error << "Object add component failed" << std::endl;
} }
result = TmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR); result = tmTcDistributor->addComponent(objects::PUS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl; sif::error << "Object add component failed" << std::endl;
} }
result = TmTcDistributor->addComponent(objects::TM_FUNNEL); result = tmTcDistributor->addComponent(objects::TM_FUNNEL);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Object add component failed" << std::endl; sif::error << "Object add component failed" << std::endl;
} }
/* UDP bridge */ /* UDP bridge */
PeriodicTaskIF* UdpBridgeTask = TaskFactory::instance()->createPeriodicTask( PeriodicTaskIF* udpBridgeTask = factory->createPeriodicTask(
"UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, "UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
0.2, nullptr); result = udpBridgeTask->addComponent(objects::UDP_BRIDGE);
result = UdpBridgeTask->addComponent(objects::UDP_BRIDGE);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Unix Bridge failed" << std::endl; sif::error << "Add component UDP Unix Bridge failed" << std::endl;
} }
PeriodicTaskIF* UdpPollingTask = TaskFactory::instance()-> PeriodicTaskIF* udpPollingTask = factory->createPeriodicTask(
createPeriodicTask("UDP_POLLING", 80, "UDP_POLLING", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, nullptr); result = udpPollingTask->addComponent(objects::UDP_POLLING_TASK);
result = UdpPollingTask->addComponent(objects::UDP_POLLING_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Polling failed" << std::endl; sif::error << "Add component UDP Polling failed" << std::endl;
} }
/* PUS Services */ /* PUS Services */
PeriodicTaskIF* PusVerification = TaskFactory::instance()-> PeriodicTaskIF* pusVerification = factory->createPeriodicTask(
createPeriodicTask("PUS_VERIF_1", 40, "PUS_VERIF", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr); result = pusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
result = PusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
if(result != HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl; sif::error << "Object add component failed" << std::endl;
} }
PeriodicTaskIF* PusEvents = TaskFactory::instance()-> PeriodicTaskIF* pusEvents = factory->createPeriodicTask(
createPeriodicTask("PUS_VERIF_1", 60, "PUS_EVENTS", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr); result = pusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
result = PusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
if(result != HasReturnvaluesIF::RETURN_OK){ if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl; initmission::printAddObjectError("PUS5", objects::PUS_SERVICE_5_EVENT_REPORTING);
} }
PeriodicTaskIF* PusHighPrio = TaskFactory::instance()-> PeriodicTaskIF* pusHighPrio = factory->createPeriodicTask(
createPeriodicTask("PUS_HIGH_PRIO", 50, "PUS_HIGH_PRIO", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
PeriodicTaskIF::MINIMUM_STACK_SIZE, result = pusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
0.200, nullptr);
result = PusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = PusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* PusMedPrio = TaskFactory::instance()->
createPeriodicTask("PUS_HIGH_PRIO", 40,
PeriodicTaskIF::MINIMUM_STACK_SIZE,
0.8, nullptr);
result = PusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
result = PusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* PusLowPrio = TaskFactory::instance()->
createPeriodicTask("PUSB", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE,
1.6, nullptr);
result = PusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
#if OBSW_ADD_TEST_CODE == 1
FixedTimeslotTaskIF* TestTimeslotTask = TaskFactory::instance()->
createFixedTimeslotTask("PST_TEST_TASK", 10,
PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.0, nullptr);
result = pst::pollingSequenceTestFunction(TestTimeslotTask);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "InitMission::createTasks: Test PST initialization " initmission::printAddObjectError("PUS2", objects::PUS_SERVICE_2_DEVICE_ACCESS);
<< "failed!" << std::endl; }
result = pusHighPrio->addComponent(objects::PUS_SERVICE_9_TIME_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS9", objects::PUS_SERVICE_9_TIME_MGMT);
} }
#endif PeriodicTaskIF* pusMedPrio = factory->createPeriodicTask(
"PUS_MED_PRIO", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc);
PeriodicTaskIF* SpiTestTask = TaskFactory::instance()-> result = pusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
createPeriodicTask("SPI_TEST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, if(result != HasReturnvaluesIF::RETURN_OK) {
2.0, nullptr); initmission::printAddObjectError("PUS8", objects::PUS_SERVICE_8_FUNCTION_MGMT);
result = SpiTestTask->addComponent(objects::SPI_TEST); }
if(result != HasReturnvaluesIF::RETURN_OK){ result = pusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
sif::error << "Object add SPI test failed" << std::endl; if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS200", objects::PUS_SERVICE_200_MODE_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_20_PARAMETERS);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS20", objects::PUS_SERVICE_20_PARAMETERS);
} }
//Main thread sleep PeriodicTaskIF* pusLowPrio = factory->createPeriodicTask(
"PUS_LOW_PRIO", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE, 1.6, missedDeadlineFunc);
result = pusLowPrio->addComponent(objects::PUS_SERVICE_17_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS17", objects::PUS_SERVICE_17_TEST);
}
#if RPI_TEST_ACS_BOARD == 1
FixedTimeslotTaskIF* acsTask = factory->createFixedTimeslotTask(
"ACS_PST", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 2.0, missedDeadlineFunc);
result = pst::pollingSequenceAcsTest(acsTask);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "initmission::initTasks: ACS PST initialization failed!" << std::endl;
}
#endif /* RPI_TEST_ACS_BOARD == 1 */
PeriodicTaskIF* testTask = factory->createPeriodicTask(
"TEST_TASK", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
#if OBSW_ADD_TEST_CODE == 1
result = testTask->addComponent(objects::TEST_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("TEST_TASK", objects::TEST_TASK);
}
#endif /* OBSW_ADD_TEST_CODE == 1 */
#if RPI_ADD_SPI_TEST == 1
result = testTask->addComponent(objects::SPI_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("SPI_TEST", objects::SPI_TEST);
}
#endif /* RPI_ADD_SPI_TEST == 1 */
#if RPI_ADD_GPIO_TEST == 1
result = testTask->addComponent(objects::LIBGPIOD_TEST);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("GPIOD_TEST", objects::LIBGPIOD_TEST);
}
#endif /* RPI_ADD_GPIO_TEST == 1 */
sif::info << "Starting tasks.." << std::endl; sif::info << "Starting tasks.." << std::endl;
TmTcDistributor->startTask(); tmTcDistributor->startTask();
UdpBridgeTask->startTask(); udpBridgeTask->startTask();
UdpPollingTask->startTask(); udpPollingTask->startTask();
PusVerification->startTask(); pusVerification->startTask();
PusEvents->startTask(); pusEvents->startTask();
PusHighPrio->startTask(); pusHighPrio->startTask();
PusMedPrio->startTask(); pusMedPrio->startTask();
PusLowPrio->startTask(); pusLowPrio->startTask();
SpiTestTask->startTask();
#if OBSW_ADD_TEST_CODE == 1 #if OBSW_ADD_TEST_CODE == 1
TestTimeslotTask->startTask(); testTask->startTask();
#endif #endif /* OBSW_ADD_TEST_CODE == 1 */
#if RPI_TEST_ACS_BOARD == 1
acsTask->startTask();
#endif /* RPI_TEST_ACS_BOARD == 1 */
sif::info << "Tasks started.." << std::endl; sif::info << "Tasks started.." << std::endl;
} }

View File

@ -1,7 +1,7 @@
#ifndef BSP_LINUX_INITMISSION_H_ #ifndef BSP_LINUX_INITMISSION_H_
#define BSP_LINUX_INITMISSION_H_ #define BSP_LINUX_INITMISSION_H_
namespace InitMission { namespace initmission {
void initMission(); void initMission();
void initTasks(); void initTasks();
}; };

View File

@ -1,20 +1,32 @@
#include "ObjectFactory.h" #include "ObjectFactory.h"
#include <bsp_rpi/boardtest/SpiTest.h> #include <bsp_rpi/gpio/GPIORPi.h>
#include <fsfw/datapoollocal/LocalDataPoolManager.h>
#include <objects/systemObjectList.h> #include <objects/systemObjectList.h>
#include <devices/addresses.h>
#include <devices/gpioIds.h>
#include <OBSWConfig.h> #include <OBSWConfig.h>
#include <tmtc/apid.h> #include <tmtc/apid.h>
#include <tmtc/pusIds.h> #include <tmtc/pusIds.h>
#include <linux/boardtest/LibgpiodTest.h>
#include <linux/boardtest/SpiTestClass.h>
#include <linux/gpio/GpioCookie.h>
#include <linux/gpio/LinuxLibgpioIF.h>
#include <linux/spi/SpiCookie.h>
#include <mission/core/GenericFactory.h>
#include <mission/utility/TmFunnel.h>
#include <mission/devices/MGMHandlerLIS3MDL.h>
#include <fsfw/datapoollocal/LocalDataPoolManager.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h> #include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h> #include <fsfw/tmtcservices/PusServiceBase.h>
#include <fsfw/osal/linux/TmTcUnixUdpBridge.h> #include <fsfw/osal/linux/TmTcUnixUdpBridge.h>
#include <fsfw/tmtcpacket/pus/TmPacketStored.h> #include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#include <fsfw/osal/linux/TcUnixUdpPollingTask.h> #include <fsfw/osal/linux/TcUnixUdpPollingTask.h>
#include <fsfw/tasks/TaskFactory.h>
#include <mission/core/GenericFactory.h> #include <linux/spi/SpiComIF.h>
#include <mission/utility/TmFunnel.h>
void Factory::setStaticFrameworkObjectIds() { void Factory::setStaticFrameworkObjectIds() {
PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR; PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR;
@ -44,5 +56,52 @@ void ObjectFactory::produce(){
objects::TM_STORE, objects::TC_STORE); objects::TM_STORE, objects::TC_STORE);
new TcUnixUdpPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE); new TcUnixUdpPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE);
new SpiTest(objects::SPI_TEST); GpioIF* gpioIF = new LinuxLibgpioIF(objects::GPIO_IF);
#if RPI_ADD_SPI_TEST == 1
new SpiTestClass(objects::SPI_TEST, gpioIF);
#endif
#if RPI_LOOPBACK_TEST_GPIO == 1
GpioCookie* gpioCookieLoopback = new GpioCookie();
/* Loopback pins. Adapt according to setup */
gpioId_t gpioIdSender = gpioIds::TEST_ID_0;
int bcmPinSender = 26;
gpioId_t gpioIdReader = gpioIds::TEST_ID_1;
int bcmPinReader = 16;
gpio::createRpiGpioConfig(gpioCookieLoopback, gpioIdSender, bcmPinSender, "GPIO_LB_SENDER",
gpio::Direction::OUT, 0);
gpio::createRpiGpioConfig(gpioCookieLoopback, gpioIdReader, bcmPinReader, "GPIO_LB_READER",
gpio::Direction::IN, 0);
new LibgpiodTest(objects::LIBGPIOD_TEST, objects::GPIO_IF, gpioCookieLoopback);
#endif /* RPI_LOOPBACK_TEST_GPIO == 1 */
new SpiComIF(objects::SPI_COM_IF, gpioIF);
#if RPI_TEST_ACS_BOARD == 1
GpioCookie* gpioCookieAcsBoard = new GpioCookie();
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::MGM_0_LIS3_CS, gpio::MGM_0_BCM_PIN,
"MGM_0_LIS3", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::MGM_1_RM3100_CS, gpio::MGM_1_BCM_PIN,
"MGM_1_RM3100", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::MGM_2_LIS3_CS, gpio::MGM_2_BCM_PIN,
"MGM_2_LIS3", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::MGM_3_RM3100_CS, gpio::MGM_3_BCM_PIN,
"MGM_3_RM3100", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::GYRO_0_ADIS_CS, gpio::GYRO_0_BCM_PIN,
"GYRO_0_ADIS", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::GYRO_1_L3G_CS, gpio::GYRO_1_BCM_PIN,
"GYRO_1_L3G", gpio::Direction::OUT, 1);
gpio::createRpiGpioConfig(gpioCookieAcsBoard, gpioIds::GYRO_2_L3G_CS, gpio::GYRO_2_BCM_PIN,
"GYRO_2_L3G", gpio::Direction::OUT, 1);
gpioIF->addGpios(gpioCookieAcsBoard);
SpiCookie* spiCookie = new SpiCookie(addresses::MGM_0_LIS3,
gpioIds::MGM_0_LIS3_CS, "/dev/spidev0.0", 24, spi::SpiMode::MODE_3, 3'900'000);
auto mgmHandler = new MGMHandlerLIS3MDL(objects::MGM_0_LIS3_HANDLER,
objects::SPI_COM_IF, spiCookie);
mgmHandler->setStartUpImmediately();
#endif /* RPI_TEST_ACS_BOARD == 1 */
} }

View File

@ -0,0 +1,24 @@
#ifndef BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_
#define BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_
#include <cstdint>
#define RPI_ADD_GPIO_TEST 0
#define RPI_LOOPBACK_TEST_GPIO 0
/* Only one of those 2 should be enabled! */
#define RPI_ADD_SPI_TEST 0
#define RPI_TEST_ACS_BOARD 1
/* Adapt these values accordingly */
namespace gpio {
static constexpr uint8_t MGM_0_BCM_PIN = 0;
static constexpr uint8_t MGM_1_BCM_PIN = 1;
static constexpr uint8_t MGM_2_BCM_PIN = 17;
static constexpr uint8_t MGM_3_BCM_PIN = 27;
static constexpr uint8_t GYRO_0_BCM_PIN = 5;
static constexpr uint8_t GYRO_1_BCM_PIN = 6;
static constexpr uint8_t GYRO_2_BCM_PIN = 4;
}
#endif /* BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_ */

View File

@ -1,6 +1,4 @@
target_sources(${TARGET_NAME} PRIVATE target_sources(${TARGET_NAME} PRIVATE
SpiTest.cpp
RPiGPIO.cpp
) )

View File

@ -1,61 +0,0 @@
#include "SpiTest.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fcntl.h>
#include <sys/ioctl.h>
SpiTest::SpiTest(object_id_t objectId): SystemObject(objectId) {
sif::info << "Setting up Raspberry Pi WiringPi library." << std::endl;
// wiringPiSetupGpio();
// pinMode(SS_MGM_0_LIS3, OUTPUT);
// pinMode(SS_MGM_1_RM, OUTPUT);
// pinMode(SS_GYRO_0_ADIS, OUTPUT);
// pinMode(SS_GYRO_1_L3G, OUTPUT);
// pinMode(SS_GYRO_2_L3G, OUTPUT);
// pinMode(SS_MGM_2_LIS3, OUTPUT);
// pinMode(SS_MGM_3_RM, OUTPUT);
//
// digitalWrite(SS_MGM_0_LIS3, HIGH);
// digitalWrite(SS_MGM_1_RM, HIGH);
// digitalWrite(SS_GYRO_0_ADIS, HIGH);
// digitalWrite(SS_GYRO_1_L3G, HIGH);
// digitalWrite(SS_GYRO_2_L3G, HIGH);
// digitalWrite(SS_MGM_2_LIS3, HIGH);
// digitalWrite(SS_MGM_3_RM, HIGH);
int spiFd = open(spiDeviceName.c_str(), O_RDWR);
if (spiFd < 0){
sif::error << "Could not open SPI device!" << std::endl;
}
spiMode = SPI_MODE_3;
int ret = ioctl(spiFd, SPI_IOC_WR_MODE, &spiMode);
if(ret < 0) {
sif::error << "Could not set write mode!" << std::endl;
}
/* Datenrate setzen */
ret = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed);
if(ret < 0) {
sif::error << "Could not SPI speed!" << std::endl;
}
}
ReturnValue_t SpiTest::performOperation(uint8_t opCode) {
if(oneShot) {
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t SpiTest::initialize() {
//transferHandle.rx_buf = reinterpret_cast<__u64>(receiveBuffer);
//transferHandle.tx_buf = reinterpret_cast<__u64>(sendBuffer);
//transferHandle.speed_hz = 976000;
//transferHandle.len = 2;
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,45 +0,0 @@
#ifndef BSP_LINUX_TEST_SPITEST_H_
#define BSP_LINUX_TEST_SPITEST_H_
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
#include <linux/spi/spidev.h>
#include <string>
class SpiTest:
public SystemObject,
public ExecutableObjectIF {
public:
SpiTest(object_id_t objectId);
ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initialize() override;
private:
// These chip selects (BCM number) will be pulled high if not used
// ACS board specific.
enum SpiChipSelects {
SS_MGM_0_LIS3 = 0, //!< MGM 0, LIS3MDLTR, U6, A side
SS_MGM_1_RM = 1, //!< MGM 1, RM3100, U7, A side
SS_GYRO_0_ADIS = 2, //!< Gyro 0, ADIS16485, U3, A side
SS_GYRO_1_L3G = 3, //!< Gyro 1, L3GD20H, U4, A side
SS_GYRO_2_L3G = 4, //!< Gyro 2, L3GD20h, U5, B side
SS_MGM_2_LIS3 = 17, //!< MGM 2, LIS3MDLTR, U8, B side
SS_MGM_3_RM = 27, //!< MGM 3, RM3100, U9, B side
};
const std::string spiDeviceName = "/dev/spidev0.0";
int spiFd = 0;
uint8_t spiMode = SPI_MODE_3;
uint32_t spiSpeed = 976000;
uint8_t sendBuffer[32];
uint8_t receiveBuffer[32];
struct spi_ioc_transfer transferHandle;
bool oneShot = true;
};
#endif /* BSP_LINUX_TEST_SPITEST_H_ */

View File

@ -0,0 +1,9 @@
target_sources(${TARGET_NAME} PUBLIC
GPIORPi.cpp
)

36
bsp_rpi/gpio/GPIORPi.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "GPIORPi.h"
#include <FSFWConfig.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <linux/gpio/GpioCookie.h>
ReturnValue_t gpio::createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin,
std::string consumer, gpio::Direction direction, int initValue) {
if(cookie == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
GpiodRegular config;
/* Default chipname for Raspberry Pi. There is still gpiochip1 for expansion, but most users
will not need this */
config.chipname = "gpiochip0";
config.consumer = consumer;
config.direction = direction;
config.initValue = initValue;
/* Sanity check for the BCM pins before assigning it */
if(bcmPin > 27) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "createRpiGpioConfig: BCM pin " << bcmPin << " invalid!" << std::endl;
#else
sif::printError("createRpiGpioConfig: BCM pin %d invalid!\n", bcmPin);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return HasReturnvaluesIF::RETURN_FAILED;
}
config.lineNum = bcmPin;
cookie->addGpio(gpioId, config);
return HasReturnvaluesIF::RETURN_OK;
}

26
bsp_rpi/gpio/GPIORPi.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef BSP_RPI_GPIO_GPIORPI_H_
#define BSP_RPI_GPIO_GPIORPI_H_
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <linux/gpio/gpioDefinitions.h>
class GpioCookie;
namespace gpio {
/**
* Create a GpioConfig_t. This function does a sanity check on the BCM pin number and fails if the
* BCM pin is invalid.
* @param cookie Adds the configuration to this cookie directly
* @param gpioId ID which identifies the GPIO configuration
* @param bcmPin Raspberry Pi BCM pin
* @param consumer Information string
* @param direction GPIO direction
* @param initValue Intial value for output pins, 0 for low, 1 for high
* @return
*/
ReturnValue_t createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin,
std::string consumer, gpio::Direction direction, int initValue);
}
#endif /* BSP_RPI_GPIO_GPIORPI_H_ */

View File

@ -1,28 +1,26 @@
#include "InitMission.h" #include "InitMission.h"
#include <OBSWVersion.h> #include <OBSWVersion.h>
#include <fsfw/tasks/TaskFactory.h> #include <fsfw/tasks/TaskFactory.h>
#include <iostream> #include <iostream>
#include <unistd.h>
/** /**
* @brief This is the main program for the target hardware. * @brief This is the main program and entry point for the Raspberry Pi.
* @return * @return
*/ */
int main(void) int main(void)
{ {
std::cout << "-- EIVE OBSW --" << std::endl; std::cout << "-- EIVE OBSW --" << std::endl;
std::cout << "-- Compiled for Linux " << " --" << std::endl; std::cout << "-- Compiled for Linux (Raspberry Pi) --" << std::endl;
std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "." std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "."
<< SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl; << SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl;
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl; std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
InitMission::initMission(); initmission::initMission();
for(;;) { for(;;) {
// suspend main thread by sleeping it. /* Suspend main thread by sleeping it. */
TaskFactory::delayTask(5000); TaskFactory::delayTask(5000);
} }
} }

View File

@ -17,6 +17,7 @@ fi
os_fsfw="linux" os_fsfw="linux"
tgt_bsp="arm/raspberrypi" tgt_bsp="arm/raspberrypi"
build_generator="" build_generator=""
build_dir="Debug-RPi"
if [ "${OS}" = "Windows_NT" ]; then if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles" build_generator="MinGW Makefiles"
# Could be other OS but this works for now. # Could be other OS but this works for now.
@ -24,4 +25,5 @@ else
build_generator="Unix Makefiles" build_generator="Unix Makefiles"
fi fi
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -t "${tgt_bsp}" python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "debug" -t "${tgt_bsp}" \
-l"${build_dir}"

View File

@ -17,6 +17,7 @@ fi
os_fsfw="linux" os_fsfw="linux"
tgt_bsp="arm/raspberrypi" tgt_bsp="arm/raspberrypi"
build_generator="" build_generator=""
build_dir="Release-RPi"
if [ "${OS}" = "Windows_NT" ]; then if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles" build_generator="MinGW Makefiles"
# Could be other OS but this works for now. # Could be other OS but this works for now.
@ -24,4 +25,5 @@ else
build_generator="Unix Makefiles" build_generator="Unix Makefiles"
fi fi
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "release" -t "${tgt_bsp}" python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "release" -t "${tgt_bsp}" \
-l"${build_dir}"

View File

@ -17,6 +17,7 @@ fi
os_fsfw="linux" os_fsfw="linux"
tgt_bsp="arm/raspberrypi" tgt_bsp="arm/raspberrypi"
build_generator="" build_generator=""
build_dir="RelWithDeb-RPi"
if [ "${OS}" = "Windows_NT" ]; then if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles" build_generator="MinGW Makefiles"
# Could be other OS but this works for now. # Could be other OS but this works for now.
@ -24,4 +25,5 @@ else
build_generator="Unix Makefiles" build_generator="Unix Makefiles"
fi fi
python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "reldeb" -t "${tgt_bsp}" python3 cmake_build_config.py -o "${os_fsfw}" -g "${build_generator}" -b "reldeb" -t "${tgt_bsp}" \
-l"${build_dir}"

View File

@ -61,8 +61,9 @@ def main():
else: else:
cmake_target_cfg_cmd = "" cmake_target_cfg_cmd = ""
# TODO: Use builddir if given (need to check whether path is relative or absolute)
build_folder = cmake_build_type build_folder = cmake_build_type
if args.builddir is not None:
build_folder = args.builddir
build_path = source_location + os.path.sep + build_folder build_path = source_location + os.path.sep + build_folder
if os.path.isdir(build_path): if os.path.isdir(build_path):

2
fsfw

@ -1 +1 @@
Subproject commit 7d0916a44e18c87b00998448333023186b3d85b1 Subproject commit 92f249dc62cf02a5052fee4e9877bc89b2be1ab5

View File

@ -6,11 +6,17 @@
#ifndef FSFWCONFIG_OBSWCONFIG_H_ #ifndef FSFWCONFIG_OBSWCONFIG_H_
#define FSFWCONFIG_OBSWCONFIG_H_ #define FSFWCONFIG_OBSWCONFIG_H_
#define TEST_LIBGPIOD 0 #ifdef RASPBERRY_PI
#include <rpi_config.h>
#endif
#include "OBSWVersion.h"
/* These defines should be disabled for mission code but are useful for /* These defines should be disabled for mission code but are useful for
debugging. */ debugging. */
#define OBSW_VERBOSE_LEVEL 1 #define OBSW_VERBOSE_LEVEL 1
#define OBSW_PRINT_MISSED_DEADLINES 1
#define OBSW_ADD_TEST_CODE 1
#define TEST_LIBGPIOD 0
#define TE0720 0 #define TE0720 0
@ -19,8 +25,6 @@ debugging. */
#define PDU2_DEBUG 0 #define PDU2_DEBUG 0
#define ACU_DEBUG 1 #define ACU_DEBUG 1
#include "OBSWVersion.h"
#ifdef __cplusplus #ifdef __cplusplus
#include "objects/systemObjectList.h" #include "objects/systemObjectList.h"

View File

@ -4,8 +4,8 @@
//! TODO: Think of a cool name for the software releases. //! TODO: Think of a cool name for the software releases.
const char* const SW_NAME = "eive"; const char* const SW_NAME = "eive";
#define SW_VERSION 0 #define SW_VERSION 1
#define SW_SUBVERSION 2 #define SW_SUBVERSION 0
#define SW_SUBSUBVERSION 0 #define SW_SUBSUBVERSION 0

View File

@ -1,20 +1,24 @@
/**
* \file addresses.cpp
*
* \date 07.11.2019
*/
#ifndef FSFWCONFIG_DEVICES_ADDRESSES_H_ #ifndef FSFWCONFIG_DEVICES_ADDRESSES_H_
#define FSFWCONFIG_DEVICES_ADDRESSES_H_ #define FSFWCONFIG_DEVICES_ADDRESSES_H_
#include <stdint.h>
#include <fsfw/devicehandlers/CookieIF.h> #include <fsfw/devicehandlers/CookieIF.h>
#include <fsfwconfig/objects/systemObjectList.h> #include <fsfwconfig/objects/systemObjectList.h>
#include <cstdint>
namespace addresses { namespace addresses {
/* Logical addresses have uint32_t datatype */ /* Logical addresses have uint32_t datatype */
enum logicalAddresses: address_t { enum logicalAddresses: address_t {
PCDU, PCDU,
MGM_0_LIS3 = objects::MGM_0_LIS3_HANDLER,
MGM_1_RM3100 = objects::MGM_1_RM3100_HANDLER,
MGM_2_LIS3 = objects::MGM_2_LIS3_HANDLER,
MGM_3_RM3100 = objects::MGM_3_RM3100_HANDLER,
GYRO_0_ADIS = objects::GYRO_0_ADIS_HANDLER,
GYRO_1_L3G = objects::GYRO_1_L3G_HANDLER,
GYRO_2_L3G = objects::GYRO_2_L3G_HANDLER,
/* Dummy and Test Addresses */ /* Dummy and Test Addresses */
DUMMY_ECHO = 129, DUMMY_ECHO = 129,
DUMMY_GPS0 = 130, DUMMY_GPS0 = 130,

View File

@ -15,7 +15,17 @@ namespace gpioIds {
HEATER_7, HEATER_7,
DEPLSA1, DEPLSA1,
DEPLSA2, DEPLSA2,
Test_ID
MGM_0_LIS3_CS,
MGM_1_RM3100_CS,
GYRO_0_ADIS_CS,
GYRO_1_L3G_CS,
GYRO_2_L3G_CS,
MGM_2_LIS3_CS,
MGM_3_RM3100_CS,
TEST_ID_0,
TEST_ID_1
}; };
} }

View File

@ -30,6 +30,7 @@ namespace objects {
ARDUINO_COM_IF = 0x49000001, ARDUINO_COM_IF = 0x49000001,
CSP_COM_IF = 0x49000002, CSP_COM_IF = 0x49000002,
I2C_COM_IF = 0x49000003, I2C_COM_IF = 0x49000003,
SPI_COM_IF = 0x49000004,
/* 0x47 ('G') for Gpio Interfaces */ /* 0x47 ('G') for Gpio Interfaces */
GPIO_IF = 0x47000001, GPIO_IF = 0x47000001,
@ -41,10 +42,17 @@ namespace objects {
ACU_HANDLER = 0x44000004, ACU_HANDLER = 0x44000004,
TMP1075_HANDLER_1 = 0x44000005, TMP1075_HANDLER_1 = 0x44000005,
TMP1075_HANDLER_2 = 0x44000006, TMP1075_HANDLER_2 = 0x44000006,
MGM_0_LIS3_HANDLER = 0x4400007,
MGM_1_RM3100_HANDLER = 0x44000008,
MGM_2_LIS3_HANDLER = 0x44000009,
MGM_3_RM3100_HANDLER = 0x44000010,
GYRO_0_ADIS_HANDLER = 0x44000011,
GYRO_1_L3G_HANDLER = 0x44000012,
GYRO_2_L3G_HANDLER = 0x44000013,
/* Custom device handler */ /* Custom device handler */
PCDU_HANDLER = 0x44000007, PCDU_HANDLER = 0x44001000,
SOLAR_ARRAY_DEPL_HANDLER = 0x44000008, SOLAR_ARRAY_DEPL_HANDLER = 0x44001001,
/* 0x54 ('T') for thermal objects */ /* 0x54 ('T') for thermal objects */
HEATER_HANDLER = 0x54000003, HEATER_HANDLER = 0x54000003,

View File

@ -33,14 +33,12 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence)
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else {
sif::error << "PollingSequence::initialize has errors!" << std::endl; sif::error << "PollingSequence::initialize has errors!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
}
} }
ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){
uint32_t length = thisSequence->getPeriodMs(); uint32_t length = thisSequence->getPeriodMs();
thisSequence->addSlot(objects::PCDU_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); thisSequence->addSlot(objects::PCDU_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION);
@ -91,12 +89,29 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){
thisSequence->addSlot(objects::ACU_HANDLER, thisSequence->addSlot(objects::ACU_HANDLER,
length * 0.8, DeviceHandlerIF::GET_READ); length * 0.8, DeviceHandlerIF::GET_READ);
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { if (thisSequence->checkSequence() != HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
sif::error << "Initialization of GomSpace PST failed" << std::endl; sif::error << "Initialization of GomSpace PST failed" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t pst::pollingSequenceAcsTest(FixedTimeslotTaskIF *thisSequence) {
uint32_t length = thisSequence->getPeriodMs();
thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0,
DeviceHandlerIF::PERFORM_OPERATION);
thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.2,
DeviceHandlerIF::SEND_WRITE);
thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.4,
DeviceHandlerIF::GET_WRITE);
thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.6,
DeviceHandlerIF::SEND_READ);
thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.8,
DeviceHandlerIF::GET_READ);
if (thisSequence->checkSequence() != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Initialization of ACS Board PST failed" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -32,6 +32,8 @@ ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence);
* blocking calls when requesting data from devices. * blocking calls when requesting data from devices.
*/ */
ReturnValue_t gomspacePstInit(FixedTimeslotTaskIF *thisSequence); ReturnValue_t gomspacePstInit(FixedTimeslotTaskIF *thisSequence);
ReturnValue_t pollingSequenceAcsTest(FixedTimeslotTaskIF* thisSequence);
} }

View File

@ -14,6 +14,7 @@ enum {
MGM_LIS3MDL, MGM_LIS3MDL,
MGM_RM3100, MGM_RM3100,
LINUX_LIBGPIO_IF, LINUX_LIBGPIO_IF,
LINUX_SPI_COM_IF,
PCDU_HANDLER, PCDU_HANDLER,
HEATER_HANDLER, HEATER_HANDLER,
SA_DEPL_HANDLER SA_DEPL_HANDLER

View File

@ -2,4 +2,6 @@ add_subdirectory(gpio)
add_subdirectory(i2c) add_subdirectory(i2c)
add_subdirectory(csp) add_subdirectory(csp)
add_subdirectory(spi) add_subdirectory(spi)
add_subdirectory(utility)
add_subdirectory(boardtest)

View File

@ -0,0 +1,10 @@
target_sources(${TARGET_NAME} PRIVATE
LibgpiodTest.cpp
I2cTestClass.cpp
SpiTestClass.cpp
UartTestClass.cpp
)

View File

@ -0,0 +1,8 @@
#include <linux/boardtest/I2cTestClass.h>
I2cTestClass::I2cTestClass(object_id_t objectId): TestTask(objectId) {
}
ReturnValue_t I2cTestClass::performPeriodicAction() {
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,17 @@
#ifndef LINUX_BOARDTEST_I2CTESTCLASS_H_
#define LINUX_BOARDTEST_I2CTESTCLASS_H_
#include <test/testtasks/TestTask.h>
class I2cTestClass: public TestTask {
public:
I2cTestClass(object_id_t objectId);
ReturnValue_t performPeriodicAction() override;
private:
};
#endif /* LINUX_BOARDTEST_I2CTESTCLASS_H_ */

View File

@ -0,0 +1,99 @@
#include "LibgpiodTest.h"
#include <fsfwconfig/devices/gpioIds.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#include <fsfw/objectmanager/ObjectManagerIF.h>
#include <fsfw/tasks/TaskFactory.h>
LibgpiodTest::LibgpiodTest(object_id_t objectId, object_id_t gpioIfobjectId,
GpioCookie* gpioCookie):
TestTask(objectId) {
gpioInterface = objectManager->get<GpioIF>(gpioIfobjectId);
if (gpioInterface == nullptr) {
sif::error << "LibgpiodTest::LibgpiodTest: Invalid Gpio interface." << std::endl;
}
gpioInterface->addGpios(gpioCookie);
testCase = TestCases::LOOPBACK;
}
LibgpiodTest::~LibgpiodTest() {
}
ReturnValue_t LibgpiodTest::performPeriodicAction() {
int gpioState;
ReturnValue_t result;
switch(testCase) {
case(TestCases::READ): {
result = gpioInterface->readGpio(gpioIds::TEST_ID_0, &gpioState);
if (result != RETURN_OK) {
sif::debug << "LibgpiodTest::performPeriodicAction: Failed to read gpio "
<< std::endl;
return RETURN_FAILED;
}
else {
sif::debug << "LibgpiodTest::performPeriodicAction: MIO 0 state = " << gpioState
<< std::endl;
}
break;
}
case(TestCases::LOOPBACK): {
break;
}
}
return RETURN_OK;
}
ReturnValue_t LibgpiodTest::performOneShotAction() {
int gpioState;
ReturnValue_t result;
switch(testCase) {
case(TestCases::READ): {
break;
}
case(TestCases::LOOPBACK): {
result = gpioInterface->pullHigh(gpioIds::TEST_ID_0);
if(result == HasReturnvaluesIF::RETURN_OK) {
sif::info << "LibgpiodTest::performOneShotAction: "
"GPIO pulled high successfully for loopback test" << std::endl;
}
else {
sif::warning << "LibgpiodTest::performOneShotAction: Could not pull GPIO high!"
<< std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
result = gpioInterface->readGpio(gpioIds::TEST_ID_1, &gpioState);
if(result == HasReturnvaluesIF::RETURN_OK and gpioState == 1) {
sif::info << "LibgpiodTest::performOneShotAction: "
"GPIO state read successfully and is high" << std::endl;
}
else {
sif::warning << "LibgpiodTest::performOneShotAction: GPIO read and is not high!"
<< std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
result = gpioInterface->pullLow(gpioIds::TEST_ID_0);
if(result == HasReturnvaluesIF::RETURN_OK) {
sif::info << "LibgpiodTest::performOneShotAction: "
"GPIO pulled low successfully for loopback test" << std::endl;
}
result = gpioInterface->readGpio(gpioIds::TEST_ID_1, &gpioState);
if(result == HasReturnvaluesIF::RETURN_OK and gpioState == 0) {
sif::info << "LibgpiodTest::performOneShotAction: "
"GPIO state read successfully and is low" << std::endl;
}
else {
sif::warning << "LibgpiodTest::performOneShotAction: GPIO read and is not low!"
<< std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
break;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -12,11 +12,19 @@
*/ */
class LibgpiodTest: public TestTask { class LibgpiodTest: public TestTask {
public: public:
enum TestCases {
READ = 0,
LOOPBACK = 1
};
TestCases testCase;
LibgpiodTest(object_id_t objectId, object_id_t gpioIfobjectId, GpioCookie* gpioCookie); LibgpiodTest(object_id_t objectId, object_id_t gpioIfobjectId, GpioCookie* gpioCookie);
virtual ~LibgpiodTest(); virtual ~LibgpiodTest();
protected: protected:
virtual ReturnValue_t performPeriodicAction() override; ReturnValue_t performOneShotAction() override;
ReturnValue_t performPeriodicAction() override;
private: private:
GpioIF* gpioInterface; GpioIF* gpioInterface;

View File

@ -0,0 +1,231 @@
#include "SpiTestClass.h"
#include <fsfwconfig/devices/gpioIds.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <fsfw/timemanager/Stopwatch.h>
#include <linux/gpio/gpioDefinitions.h>
#include <linux/gpio/GpioCookie.h>
#include <linux/utility/Utility.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <bitset>
SpiTestClass::SpiTestClass(object_id_t objectId, GpioIF* gpioIF): TestTask(objectId),
gpioIF(gpioIF) {
if(gpioIF == nullptr) {
sif::error << "SpiTestClass::SpiTestClass: Invalid GPIO ComIF!" << std::endl;
}
testMode = TestModes::MGM_LIS3MDL;
spiTransferStruct.rx_buf = reinterpret_cast<__u64>(recvBuffer.data());
spiTransferStruct.tx_buf = reinterpret_cast<__u64>(sendBuffer.data());
}
ReturnValue_t SpiTestClass::performOneShotAction() {
switch(testMode) {
case(TestModes::NONE): {
break;
}
case(TestModes::MGM_LIS3MDL): {
performLis3MdlTest(mgm0Lis3ChipSelect);
break;
}
case(TestModes::MGM_RM3100): {
performRm3100Test(mgm1Rm3100ChipSelect);
break;
}
case(TestModes::GYRO_L3GD20H): {
break;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t SpiTestClass::performPeriodicAction() {
return HasReturnvaluesIF::RETURN_OK;
}
void SpiTestClass::performRm3100Test(uint8_t mgmId) {
/* Configure all SPI chip selects and pull them high */
acsInit();
/* Adapt accordingly */
if(mgmId != mgm1Rm3100ChipSelect and mgmId != mgm3Rm3100ChipSelect) {
sif::warning << "SpiTestClass::performRm3100Test: Invalid MGM ID!" << std::endl;
}
gpioId_t currentGpioId = 0;
uint8_t chipSelectPin = mgmId;
if(chipSelectPin == mgm1Rm3100ChipSelect) {
currentGpioId = gpioIds::MGM_1_RM3100_CS;
}
else {
currentGpioId = gpioIds::MGM_3_RM3100_CS;
}
uint32_t rm3100speed = 3'900'000;
uint8_t rm3100revidReg = 0x36;
spi::SpiMode rm3100mode = spi::SpiMode::MODE_3;
//spiTransferStruct.speed_hz = rm3100Speed;
#ifdef RASPBERRY_PI
std::string deviceName = "/dev/spidev0.0";
#else
std::string deviceName = "placeholder";
#endif
int fileDescriptor = 0;
utility::UnixFileHelper fileHelper(deviceName, &fileDescriptor, O_RDWR,
"SpiComIF::initializeInterface: ");
if(fileHelper.getOpenResult()) {
sif::error << "SpiTestClass::performRm3100Test: File descriptor could not be opened!"
<< std::endl;
return;
}
setSpiSpeedAndMode(fileDescriptor, rm3100mode, rm3100speed);
uint8_t revId = readStmRegister(fileDescriptor, currentGpioId, rm3100revidReg, false);
sif::info << "SpiTestClass::performRm3100Test: Revision ID 0b" << std::bitset<8>(revId) <<
std::endl;
}
void SpiTestClass::performLis3MdlTest(uint8_t lis3Id) {
/* Configure all SPI chip selects and pull them high */
acsInit();
/* Adapt accordingly */
if(lis3Id != mgm0Lis3ChipSelect and lis3Id != mgm2Lis3mdlChipSelect) {
sif::warning << "SpiTestClass::performLis3MdlTest: Invalid MGM ID!" << std::endl;
}
gpioId_t currentGpioId = 0;
uint8_t chipSelectPin = lis3Id;
uint8_t whoAmIReg = 0b0000'1111;
if(chipSelectPin == mgm0Lis3ChipSelect) {
currentGpioId = gpioIds::MGM_0_LIS3_CS;
}
else {
currentGpioId = gpioIds::MGM_2_LIS3_CS;
}
uint32_t spiSpeed = 3'900'000;
spi::SpiMode spiMode = spi::SpiMode::MODE_3;
#ifdef RASPBERRY_PI
std::string deviceName = "/dev/spidev0.0";
#else
std::string deviceName = "placeholder";
#endif
int fileDescriptor = 0;
utility::UnixFileHelper fileHelper(deviceName, &fileDescriptor, O_RDWR,
"SpiComIF::initializeInterface: ");
if(fileHelper.getOpenResult()) {
sif::error << "SpiTestClass::performLis3Mdl3100Test: File descriptor could not be opened!"
<< std::endl;
return;
}
setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed);
uint8_t whoAmIRegVal = readStmRegister(fileDescriptor, currentGpioId, whoAmIReg, false);
sif::info << "SpiTestClass::performLis3MdlTest: WHO AM I Regiter 0b" <<
std::bitset<8>(whoAmIRegVal) << std::endl;
}
void SpiTestClass::acsInit() {
GpioCookie* gpioCookie = new GpioCookie();
std::string rpiGpioName = "gpiochip0";
{
GpiodRegular gpio(rpiGpioName, mgm0Lis3ChipSelect, "MGM_0_LIS3",
gpio::Direction::OUT, 1);
gpioCookie->addGpio(gpioIds::MGM_0_LIS3_CS, gpio);
}
{
GpiodRegular gpio(rpiGpioName, mgm1Rm3100ChipSelect, "MGM_1_RM3100",
gpio::Direction::OUT, 1);
gpioCookie->addGpio(gpioIds::MGM_1_RM3100_CS, gpio);
}
{
GpiodRegular gpio(rpiGpioName, gyro0AdisChipSelect, "GYRO_0_ADIS",
gpio::Direction::OUT, 1);
gpioCookie->addGpio(gpioIds::GYRO_0_ADIS_CS, gpio);
}
{
GpiodRegular gpio(rpiGpioName, gyro1L3gd20ChipSelect, "GYRO_1_L3G",
gpio::Direction::OUT, 1);
gpioCookie->addGpio(gpioIds::GYRO_1_L3G_CS, gpio);
}
{
GpiodRegular gpio(rpiGpioName, gyro2L3gd20ChipSelect, "GYRO_2_L3G",
gpio::Direction::OUT, 1);
gpioCookie->addGpio(gpioIds::GYRO_2_L3G_CS, gpio);
}
{
GpiodRegular gpio(rpiGpioName, mgm2Lis3mdlChipSelect, "MGM_2_LIS3",
gpio::Direction::OUT, 1);
gpioCookie->addGpio(gpioIds::MGM_2_LIS3_CS, gpio);
}
{
GpiodRegular gpio(rpiGpioName, mgm3Rm3100ChipSelect, "MGM_3_RM3100",
gpio::Direction::OUT, 1);
gpioCookie->addGpio(gpioIds::MGM_3_RM3100_CS, gpio);
}
if(gpioIF != nullptr) {
gpioIF->addGpios(gpioCookie);
}
}
void SpiTestClass::writeStmRegister(int fd, gpioId_t chipSelect, uint8_t reg, uint8_t value,
bool autoIncrement) {
if(autoIncrement) {
reg |= STM_AUTO_INCR_MASK;
}
spiTransferStruct.len = 2;
sendBuffer[0] = reg;
sendBuffer[1] = value;
if(gpioIF != nullptr and chipSelect != gpio::NO_GPIO) {
gpioIF->pullLow(chipSelect);
}
int retval = ioctl(fd, SPI_IOC_MESSAGE(1), &spiTransferStruct);
if(retval != 0) {
utility::handleIoctlError("SpiTestClass::writeStmRegister: Write failed");
}
if(gpioIF != nullptr and chipSelect != gpio::NO_GPIO) {
gpioIF->pullHigh(chipSelect);
}
}
void SpiTestClass::setSpiSpeedAndMode(int spiFd, spi::SpiMode mode, uint32_t speed) {
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
if(retval != 0) {
utility::handleIoctlError("SpiTestClass::performRm3100Test: Setting SPI mode failed!");
}
retval = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if(retval != 0) {
utility::handleIoctlError("SpiTestClass::performRm3100Test: Setting SPI speed failed!");
}
}
uint8_t SpiTestClass::readStmRegister(int fd, gpioId_t chipSelect, uint8_t reg,
bool autoIncrement) {
reg |= STM_READ_MASK;
if(autoIncrement) {
reg |= STM_AUTO_INCR_MASK;
}
spiTransferStruct.len = 2;
sendBuffer[0] = reg;
sendBuffer[1] = 0;
if(gpioIF != nullptr and chipSelect != gpio::NO_GPIO) {
gpioIF->pullLow(chipSelect);
}
int retval = ioctl(fd, SPI_IOC_MESSAGE(1), &spiTransferStruct);
if(retval < 0) {
utility::handleIoctlError("SpiTestClass::readStmRegiste: Read failed");
}
if(gpioIF != nullptr and chipSelect != gpio::NO_GPIO) {
gpioIF->pullHigh(chipSelect);
}
return recvBuffer[1];
}

View File

@ -0,0 +1,61 @@
#ifndef LINUX_BOARDTEST_SPITESTCLASS_H_
#define LINUX_BOARDTEST_SPITESTCLASS_H_
#include <linux/gpio/GpioIF.h>
#include <linux/spi/SpiCookie.h>
#include <test/testtasks/TestTask.h>
#include <vector>
class SpiTestClass: public TestTask {
public:
enum TestModes {
NONE,
MGM_LIS3MDL,
MGM_RM3100,
GYRO_L3GD20H,
};
TestModes testMode;
SpiTestClass(object_id_t objectId, GpioIF* gpioIF);
ReturnValue_t performOneShotAction() override;
ReturnValue_t performPeriodicAction() override;
private:
GpioIF* gpioIF;
std::array<uint8_t, 128> recvBuffer;
std::array<uint8_t, 128> sendBuffer;
struct spi_ioc_transfer spiTransferStruct;
void performRm3100Test(uint8_t mgmId);
void performLis3MdlTest(uint8_t lis3Id);
/* ACS board specific code which pulls all GPIOs high */
void acsInit();
/* ACS board specific variables */
uint8_t mgm0Lis3ChipSelect = 0;
uint8_t mgm1Rm3100ChipSelect = 1;
uint8_t gyro0AdisChipSelect = 5;
uint8_t gyro1L3gd20ChipSelect = 6;
uint8_t gyro2L3gd20ChipSelect = 4;
uint8_t mgm2Lis3mdlChipSelect = 17;
uint8_t mgm3Rm3100ChipSelect = 27;
static constexpr uint8_t STM_READ_MASK = 0b1000'0000;
static constexpr uint8_t STM_AUTO_INCR_MASK = 0b0100'0000;
void setSpiSpeedAndMode(int spiFd, spi::SpiMode mode, uint32_t speed);
void writeStmRegister(int fd, gpioId_t chipSelect, uint8_t reg, uint8_t value,
bool autoIncrement);
uint8_t readStmRegister(int fd, gpioId_t chipSelect, uint8_t reg, bool autoIncrement);
};
#endif /* LINUX_BOARDTEST_SPITESTCLASS_H_ */

View File

@ -0,0 +1,8 @@
#include <linux/boardtest/UartTestClass.h>
UartTestClass::UartTestClass(object_id_t objectId): TestTask(objectId) {
}
ReturnValue_t UartTestClass::performPeriodicAction() {
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,15 @@
#ifndef LINUX_BOARDTEST_UARTTESTCLASS_H_
#define LINUX_BOARDTEST_UARTTESTCLASS_H_
#include <test/testtasks/TestTask.h>
class UartTestClass: public TestTask {
public:
UartTestClass(object_id_t objectId);
ReturnValue_t performPeriodicAction() override;
private:
};
#endif /* LINUX_BOARDTEST_UARTTESTCLASS_H_ */

View File

@ -1,5 +1,5 @@
#ifndef BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ #ifndef LINUX_CSP_CSPCOMIF_H_
#define BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ #define LINUX_CSP_CSPCOMIF_H_
#include <fsfw/devicehandlers/DeviceCommunicationIF.h> #include <fsfw/devicehandlers/DeviceCommunicationIF.h>
#include <fsfw/objectmanager/SystemObject.h> #include <fsfw/objectmanager/SystemObject.h>
@ -86,4 +86,4 @@ private:
void initiatePingRequest(uint8_t cspAddress, uint16_t querySize); void initiatePingRequest(uint8_t cspAddress, uint16_t querySize);
}; };
#endif /* BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_ */ #endif /* LINUX_CSP_CSPCOMIF_H_ */

View File

@ -1,5 +1,5 @@
#ifndef BSP_Q7S_COMIF_COOKIES_CSPCOOKIE_H_ #ifndef LINUX_CSP_CSPCOOKIE_H_
#define BSP_Q7S_COMIF_COOKIES_CSPCOOKIE_H_ #define LINUX_CSP_CSPCOOKIE_H_
#include <fsfw/devicehandlers/CookieIF.h> #include <fsfw/devicehandlers/CookieIF.h>
#include <cstdint> #include <cstdint>
@ -24,4 +24,4 @@ private:
uint8_t cspAddress; uint8_t cspAddress;
}; };
#endif /* BSP_Q7S_COMIF_COOKIES_CSPCOOKIE_H_ */ #endif /* LINUX_CSP_CSPCOOKIE_H_ */

View File

@ -3,6 +3,10 @@ target_sources(${TARGET_NAME} PUBLIC
LinuxLibgpioIF.cpp LinuxLibgpioIF.cpp
) )
target_link_libraries(${TARGET_NAME} PUBLIC
gpiod
)

View File

@ -1,25 +1,29 @@
#include "GpioCookie.h" #include "GpioCookie.h"
#include <fsfw/serviceinterface/ServiceInterfaceStream.h> #include <fsfw/serviceinterface/ServiceInterface.h>
GpioCookie::GpioCookie() { GpioCookie::GpioCookie() {
} }
void GpioCookie::addGpio(gpioId_t gpioId, GpioConfig_t gpioConfig){ ReturnValue_t GpioCookie::addGpio(gpioId_t gpioId, GpiodRegular& gpioConfig){
gpioMapIter = gpioMap.find(gpioId); auto gpioMapIter = gpioMap.find(gpioId);
if(gpioMapIter == gpioMap.end()) { if(gpioMapIter == gpioMap.end()) {
std::pair status = gpioMap.emplace(gpioId, gpioConfig); auto statusPair = gpioMap.emplace(gpioId, new GpiodRegular(gpioConfig));
if (status.second == false) { if (statusPair.second == false) {
sif::error << "GpioCookie::addGpio: Failed to add GPIO " #if FSFW_VERBOSE_LEVEL >= 1
<< gpioId << "to GPIO map" << std::endl; sif::error << "GpioCookie::addGpio: Failed to add GPIO " << gpioId <<
"to GPIO map" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK;
} }
else { #if FSFW_VERBOSE_LEVEL >= 1
sif::error << "GpioCookie::addGpio: GPIO already exists in GPIO map " sif::error << "GpioCookie::addGpio: GPIO already exists in GPIO map " << std::endl;
<< std::endl; #endif
} return HasReturnvaluesIF::RETURN_FAILED;
} }
GpioMap GpioCookie::getGpioMap() const{ GpioMap GpioCookie::getGpioMap() const {
return gpioMap; return gpioMap;
} }

View File

@ -1,48 +1,10 @@
#ifndef SAM9G20_COMIF_COOKIES_GPIO_COOKIE_H_ #ifndef LINUX_GPIO_GPIOCOOKIE_H_
#define SAM9G20_COMIF_COOKIES_GPIO_COOKIE_H_ #define LINUX_GPIO_GPIOCOOKIE_H_
#include "GpioIF.h" #include "GpioIF.h"
#include "gpioDefinitions.h"
#include <fsfw/devicehandlers/CookieIF.h> #include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h> #include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <string>
#include <unordered_map>
namespace gpio {
enum Direction {
IN = 0,
OUT = 1
};
}
/**
* @brief Struct containing information about the GPIO to use. This is
* required by the libgpiod to access and drive a GPIO.
* @param chipname String of the chipname specifying the group which contains
* the GPIO to access. E.g. gpiochip0. To detect names of
* GPIO groups run gpiodetect on the linux command line.
* @param lineNum The offset of the GPIO within the GPIO group.
* @param consumer Name of the consumer. Simply a description of the GPIO configuration.
* @param direction Specifies whether the GPIO should be used as in- or output.
* @param initValue Defines the initial state of the GPIO when configured as output. Only required
* for output GPIOs.
* @param lineHandle The handle returned by gpiod_chip_get_line will be later written to this
* pointer.
*/
typedef struct GpioConfig {
GpioConfig(std::string chipname_, int lineNum_, std::string consumer_,
gpio::Direction direction_, int initValue_) :
chipname(chipname_), lineNum(lineNum_), consumer(consumer_), direction(direction_),
initValue(initValue_) {
}
std::string chipname;
int lineNum;
std::string consumer;
gpio::Direction direction;
int initValue;
struct gpiod_line* lineHandle = nullptr;
} GpioConfig_t;
using GpioMap = std::unordered_map<gpioId_t, GpioConfig_t>;
using GpioMapIter = GpioMap::iterator;
/** /**
* @brief Cookie for the GpioIF. Allows the GpioIF to determine which * @brief Cookie for the GpioIF. Allows the GpioIF to determine which
@ -61,16 +23,17 @@ public:
virtual ~GpioCookie(); virtual ~GpioCookie();
void addGpio(gpioId_t gpioId, GpioConfig_t gpioConfig); ReturnValue_t addGpio(gpioId_t gpioId, GpiodRegular& gpioConfig);
/** /**
* @brief Get map with registered GPIOs. * @brief Get map with registered GPIOs.
*/ */
GpioMap getGpioMap() const; GpioMap getGpioMap() const;
private: private:
/**
* Returns a copy of the internal GPIO map.
*/
GpioMap gpioMap; GpioMap gpioMap;
GpioMapIter gpioMapIter;
}; };
#endif #endif /* LINUX_GPIO_GPIOCOOKIE_H_ */

View File

@ -1,17 +1,18 @@
#ifndef BSP_Q7S_GPIO_GPIOIF_H_ #ifndef LINUX_GPIO_GPIOIF_H_
#define BSP_Q7S_GPIO_GPIOIF_H_ #define LINUX_GPIO_GPIOIF_H_
#include "gpioDefinitions.h"
#include <fsfw/returnvalues/HasReturnvaluesIF.h> #include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/devicehandlers/CookieIF.h> #include <fsfw/devicehandlers/CookieIF.h>
typedef uint16_t gpioId_t; class GpioCookie;
/** /**
* @brief This class defines the interface for objects requiring the control * @brief This class defines the interface for objects requiring the control
* over GPIOs. * over GPIOs.
* @author J. Meier * @author J. Meier
*/ */
class GpioIF : public HasReturnvaluesIF{ class GpioIF : public HasReturnvaluesIF {
public: public:
virtual ~GpioIF() {}; virtual ~GpioIF() {};
@ -21,13 +22,14 @@ public:
* @param cookie Cookie specifying informations of the GPIOs required * @param cookie Cookie specifying informations of the GPIOs required
* by a object. * by a object.
*/ */
virtual ReturnValue_t initialize(CookieIF * cookie) = 0; virtual ReturnValue_t addGpios(GpioCookie* cookie) = 0;
/** /**
* @brief By implementing this function a child must provide the * @brief By implementing this function a child must provide the
* functionality to pull a certain GPIO to high logic level. * functionality to pull a certain GPIO to high logic level.
* *
* @param gpioId A unique number which specifies the GPIO to drive. * @param gpioId A unique number which specifies the GPIO to drive.
* @return Returns RETURN_OK for success. This should never return RETURN_FAILED.
*/ */
virtual ReturnValue_t pullHigh(gpioId_t gpioId) = 0; virtual ReturnValue_t pullHigh(gpioId_t gpioId) = 0;
@ -49,4 +51,4 @@ public:
virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0; virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
}; };
#endif /* BSP_Q7S_GPIO_GPIOIF_H_ */ #endif /* LINUX_GPIO_GPIOIF_H_ */

View File

@ -1,71 +1,91 @@
#include "LinuxLibgpioIF.h" #include "LinuxLibgpioIF.h"
#include "GpioCookie.h"
#include <fsfw/serviceinterface/ServiceInterface.h> #include <fsfw/serviceinterface/ServiceInterface.h>
#include <linux/gpio/gpioDefinitions.h>
#include <utility> #include <utility>
#include <unistd.h> #include <unistd.h>
#include <gpiod.h> #include <gpiod.h>
LinuxLibgpioIF::LinuxLibgpioIF(object_id_t objectId) : SystemObject(objectId) { LinuxLibgpioIF::LinuxLibgpioIF(object_id_t objectId) : SystemObject(objectId) {
} }
LinuxLibgpioIF::~LinuxLibgpioIF() { LinuxLibgpioIF::~LinuxLibgpioIF() {
} }
ReturnValue_t LinuxLibgpioIF::initialize(CookieIF * cookie){ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
ReturnValue_t result; ReturnValue_t result;
GpioMap mapToAdd; if(gpioCookie == nullptr) {
if(cookie == nullptr) {
sif::error << "LinuxLibgpioIF::initialize: Invalid cookie" << std::endl; sif::error << "LinuxLibgpioIF::initialize: Invalid cookie" << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
GpioCookie* gpioCookie = dynamic_cast<GpioCookie*>(cookie);
if(gpioCookie == nullptr) {
sif::error << "LinuxLibgpioIF: Invalid Gpio Cookie!"
<< std::endl;
return RETURN_FAILED;
}
mapToAdd = gpioCookie->getGpioMap(); GpioMap mapToAdd = gpioCookie->getGpioMap();
/* Check whether this ID already exists in the map and remove duplicates */
result = checkForConflicts(mapToAdd); result = checkForConflicts(mapToAdd);
if (result != RETURN_OK){ if (result != RETURN_OK){
return result; return result;
} }
result = configureGpios(&mapToAdd); result = configureGpios(mapToAdd);
if (result != RETURN_OK) { if (result != RETURN_OK) {
return RETURN_FAILED; return RETURN_FAILED;
} }
/* Register new GPIOs in gpioMap*/ /* Register new GPIOs in gpioMap */
gpioMap.insert(mapToAdd.begin(), mapToAdd.end()); gpioMap.insert(mapToAdd.begin(), mapToAdd.end());
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap* mapToAdd) { ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
GpioMapIter mapToAddIter; for(auto& gpioConfig: mapToAdd) {
switch(gpioConfig.second->gpioType) {
case(gpio::GpioTypes::NONE): {
return GPIO_INVALID_INSTANCE;
}
case(gpio::GpioTypes::GPIOD_REGULAR): {
GpiodRegular* regularGpio = dynamic_cast<GpiodRegular*>(gpioConfig.second);
if(regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE;
}
configureRegularGpio(gpioConfig.first, regularGpio);
break;
}
case(gpio::GpioTypes::CALLBACK): {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if(gpioCallback->callback == nullptr) {
return GPIO_INVALID_INSTANCE;
}
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::READ,
gpioCallback->initValue, gpioCallback->callbackArgs);
}
}
}
return RETURN_OK;
}
ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular *regularGpio) {
std::string chipname; std::string chipname;
unsigned int lineNum; unsigned int lineNum;
struct gpiod_chip *chip; struct gpiod_chip *chip;
gpio::Direction direction; gpio::Direction direction;
std::string consumer; std::string consumer;
struct gpiod_line *lineHandle; struct gpiod_line *lineHandle;
int result; int result = 0;
mapToAddIter = mapToAdd->begin(); chipname = regularGpio->chipname;
for (; mapToAddIter != mapToAdd->end(); mapToAddIter++) {
chipname = mapToAddIter->second.chipname;
chip = gpiod_chip_open_by_name(chipname.c_str()); chip = gpiod_chip_open_by_name(chipname.c_str());
if (!chip) { if (!chip) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to open chip " sif::error << "LinuxLibgpioIF::configureGpios: Failed to open chip "
<< chipname << ". Gpio ID: " << mapToAddIter->first << std::endl; << chipname << ". Gpio ID: " << gpioId << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
lineNum = mapToAddIter->second.lineNum; lineNum = regularGpio->lineNum;
lineHandle = gpiod_chip_get_line(chip, lineNum); lineHandle = gpiod_chip_get_line(chip, lineNum);
if (!lineHandle) { if (!lineHandle) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to open line" << std::endl; sif::error << "LinuxLibgpioIF::configureGpios: Failed to open line" << std::endl;
@ -73,69 +93,98 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap* mapToAdd) {
return RETURN_FAILED; return RETURN_FAILED;
} }
direction = mapToAddIter->second.direction; direction = regularGpio->direction;
consumer = mapToAddIter->second.consumer; consumer = regularGpio->consumer;
/* Configure direction and add a description to the GPIO */ /* Configure direction and add a description to the GPIO */
switch (direction) { switch (direction) {
case gpio::OUT: case(gpio::OUT): {
result = gpiod_line_request_output(lineHandle, consumer.c_str(), result = gpiod_line_request_output(lineHandle, consumer.c_str(),
mapToAddIter->second.initValue); regularGpio->initValue);
if (result < 0) { if (result < 0) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " << lineNum <<
<< lineNum << " from GPIO instance with ID: " << mapToAddIter->first " from GPIO instance with ID: " << gpioId << std::endl;
<< std::endl;
gpiod_line_release(lineHandle); gpiod_line_release(lineHandle);
return RETURN_FAILED; return RETURN_FAILED;
} }
break; break;
case gpio::IN: }
case(gpio::IN): {
result = gpiod_line_request_input(lineHandle, consumer.c_str()); result = gpiod_line_request_input(lineHandle, consumer.c_str());
if (result < 0) { if (result < 0) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line "
<< lineNum << " from GPIO instance with ID: " << mapToAddIter->first << lineNum << " from GPIO instance with ID: " << gpioId << std::endl;
<< std::endl;
gpiod_line_release(lineHandle); gpiod_line_release(lineHandle);
return RETURN_FAILED; return RETURN_FAILED;
} }
break; break;
default: }
default: {
sif::error << "LinuxLibgpioIF::configureGpios: Invalid direction specified" sif::error << "LinuxLibgpioIF::configureGpios: Invalid direction specified"
<< std::endl; << std::endl;
return RETURN_FAILED; return GPIO_INVALID_INSTANCE;
}
} }
/** /**
* Write line handle to GPIO configuration instance so it can later be used to set or * Write line handle to GPIO configuration instance so it can later be used to set or
* read states of GPIOs. * read states of GPIOs.
*/ */
mapToAddIter->second.lineHandle = lineHandle; regularGpio->lineHandle = lineHandle;
}
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId){ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
return driveGpio(gpioId, 1); gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) {
sif::warning << "LinuxLibgpioIF::driveGpio: Unknown GPIOD ID " << gpioId << std::endl;
return UNKNOWN_GPIO_ID;
}
if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIOD_REGULAR) {
return driveGpio(gpioId, dynamic_cast<GpiodRegular*>(gpioMapIter->second), 1);
}
else {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if(gpioCallback->callback == nullptr) {
return GPIO_INVALID_INSTANCE;
}
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE,
1, gpioCallback->callbackArgs);
}
return GPIO_TYPE_FAILURE;
} }
ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId){ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
return driveGpio(gpioId, 0); gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) {
sif::warning << "LinuxLibgpioIF::driveGpio: Unknown GPIOD ID " << gpioId << std::endl;
return UNKNOWN_GPIO_ID;
}
if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIOD_REGULAR) {
return driveGpio(gpioId, dynamic_cast<GpiodRegular*>(gpioMapIter->second), 0);
}
else {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if(gpioCallback->callback == nullptr) {
return GPIO_INVALID_INSTANCE;
}
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE,
0, gpioCallback->callbackArgs);
}
return GPIO_TYPE_FAILURE;
} }
ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId,
unsigned int logiclevel) { GpiodRegular* regularGpio, unsigned int logicLevel) {
int result; if(regularGpio == nullptr) {
struct gpiod_line *lineHandle; return GPIO_TYPE_FAILURE;
gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()){
sif::debug << "LinuxLibgpioIF::driveGpio: Unknown gpio id " << gpioId << std::endl;
return RETURN_FAILED;
} }
lineHandle = gpioMapIter->second.lineHandle; int result = gpiod_line_set_value(regularGpio->lineHandle, logicLevel);
result = gpiod_line_set_value(lineHandle, logiclevel);
if (result < 0) { if (result < 0) {
sif::error << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId <<
<< gpioId << " to logic level " << logiclevel << std::endl; " to logic level " << logicLevel << std::endl;
return DRIVE_GPIO_FAILURE; return DRIVE_GPIO_FAILURE;
} }
@ -143,38 +192,107 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId,
} }
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) { ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
struct gpiod_line *lineHandle;
gpioMapIter = gpioMap.find(gpioId); gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()){ if (gpioMapIter == gpioMap.end()){
sif::debug << "LinuxLibgpioIF::readGpio: Unknown gpio id " << gpioId << std::endl; sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl;
return RETURN_FAILED; return UNKNOWN_GPIO_ID;
}
if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIOD_REGULAR) {
GpiodRegular* regularGpio = dynamic_cast<GpiodRegular*>(gpioMapIter->second);
if(regularGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
*gpioState = gpiod_line_get_value(regularGpio->lineHandle);
}
else {
} }
lineHandle = gpioMapIter->second.lineHandle;
*gpioState = gpiod_line_get_value(lineHandle);
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap mapToAdd){ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){
gpioId_t gpioId; ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
GpioMapIter mapToAddIter = mapToAdd.begin(); ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
for(; mapToAddIter != mapToAdd.end(); mapToAddIter++){ for(auto& gpioConfig: mapToAdd) {
gpioId = mapToAddIter->first; switch(gpioConfig.second->gpioType) {
gpioMapIter = gpioMap.find(gpioId); case(gpio::GpioTypes::GPIOD_REGULAR): {
if(gpioMapIter != mapToAdd.end()){ auto regularGpio = dynamic_cast<GpiodRegular*>(gpioConfig.second);
/* An entry for this GPIO already exists. Check if configuration if(regularGpio == nullptr) {
* of direction is equivalent */ return GPIO_TYPE_FAILURE;
if (mapToAddIter->second.direction != gpioMapIter->second.direction){
sif::error << "LinuxLibgpioIF::checkForConflicts: Detected conflict "
<< "for GPIO " << mapToAddIter->first << std::endl;
return RETURN_OK;
} }
/* Check for conflicts and remove duplicates if necessary */
result = checkForConflictsRegularGpio(gpioConfig.first, regularGpio, mapToAdd);
if(result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
break;
}
case(gpio::GpioTypes::CALLBACK): {
auto callbackGpio = dynamic_cast<GpioCallback*>(gpioConfig.second);
if(callbackGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
/* Check for conflicts and remove duplicates if necessary */
result = checkForConflictsCallbackGpio(gpioConfig.first, callbackGpio, mapToAdd);
if(result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
break;
}
default: {
}
}
}
return status;
}
ReturnValue_t LinuxLibgpioIF::checkForConflictsRegularGpio(gpioId_t gpioIdToCheck,
GpiodRegular* gpioToCheck, GpioMap& mapToAdd) {
/* Cross check with private map */
gpioMapIter = gpioMap.find(gpioIdToCheck);
if(gpioMapIter != gpioMap.end()) {
if(gpioMapIter->second->gpioType != gpio::GpioTypes::GPIOD_REGULAR) {
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different "
"GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl;
mapToAdd.erase(gpioIdToCheck);
return HasReturnvaluesIF::RETURN_OK;
}
auto ownRegularGpio = dynamic_cast<GpiodRegular*>(gpioMapIter->second);
if(ownRegularGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
/* Remove element from map to add because a entry for this GPIO /* Remove element from map to add because a entry for this GPIO
* already exists */ already exists */
mapToAdd.erase(mapToAddIter); sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition"
<< " detected. Duplicate will be removed from map to add." << std::endl;
mapToAdd.erase(gpioIdToCheck);
} }
} return HasReturnvaluesIF::RETURN_OK;
return RETURN_OK; }
ReturnValue_t LinuxLibgpioIF::checkForConflictsCallbackGpio(gpioId_t gpioIdToCheck,
GpioCallback *callbackGpio, GpioMap& mapToAdd) {
/* Cross check with private map */
gpioMapIter = gpioMap.find(gpioIdToCheck);
if(gpioMapIter != gpioMap.end()) {
if(gpioMapIter->second->gpioType != gpio::GpioTypes::CALLBACK) {
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different "
"GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl;
mapToAdd.erase(gpioIdToCheck);
return HasReturnvaluesIF::RETURN_OK;
}
/* Remove element from map to add because a entry for this GPIO
already exists */
sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition"
<< " detected. Duplicate will be removed from map to add." << std::endl;
mapToAdd.erase(gpioIdToCheck);
}
return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -1,11 +1,12 @@
#ifndef BSP_Q7S_GPIO_LINUXLIBGPIOIF_H_ #ifndef LINUX_GPIO_LINUXLIBGPIOIF_H_
#define BSP_Q7S_GPIO_LINUXLIBGPIOIF_H_ #define LINUX_GPIO_LINUXLIBGPIOIF_H_
#include <linux/gpio/GpioIF.h> #include <linux/gpio/GpioIF.h>
#include <linux/gpio/GpioCookie.h>
#include <fsfwconfig/returnvalues/classIds.h> #include <fsfwconfig/returnvalues/classIds.h>
#include <fsfw/objectmanager/SystemObject.h> #include <fsfw/objectmanager/SystemObject.h>
class GpioCookie;
/** /**
* @brief This class implements the GpioIF for a linux based system. The * @brief This class implements the GpioIF for a linux based system. The
* implementation is based on the libgpiod lib which requires linux 4.8 * implementation is based on the libgpiod lib which requires linux 4.8
@ -16,21 +17,27 @@
class LinuxLibgpioIF : public GpioIF, public SystemObject { class LinuxLibgpioIF : public GpioIF, public SystemObject {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::LINUX_LIBGPIO_IF; static const uint8_t gpioRetvalId = CLASS_ID::LINUX_LIBGPIO_IF;
static const ReturnValue_t DRIVE_GPIO_FAILURE = MAKE_RETURN_CODE(0x2); static constexpr ReturnValue_t UNKNOWN_GPIO_ID =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 1);
static constexpr ReturnValue_t DRIVE_GPIO_FAILURE =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 2);
static constexpr ReturnValue_t GPIO_TYPE_FAILURE =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 3);
static constexpr ReturnValue_t GPIO_INVALID_INSTANCE =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
LinuxLibgpioIF(object_id_t objectId); LinuxLibgpioIF(object_id_t objectId);
virtual ~LinuxLibgpioIF(); virtual ~LinuxLibgpioIF();
ReturnValue_t initialize(CookieIF * cookie) override; ReturnValue_t addGpios(GpioCookie* gpioCookie) override;
ReturnValue_t pullHigh(gpioId_t gpioId) override; ReturnValue_t pullHigh(gpioId_t gpioId) override;
ReturnValue_t pullLow(gpioId_t gpioId) override; ReturnValue_t pullLow(gpioId_t gpioId) override;
ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override; ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
private: private:
/* Holds the information and configuration of all used GPIOs */
/*Holds the information and configuration of all used GPIOs */
GpioMap gpioMap; GpioMap gpioMap;
GpioMapIter gpioMapIter; GpioMapIter gpioMapIter;
@ -40,8 +47,9 @@ private:
* @param gpioId The GPIO ID of the GPIO to drive. * @param gpioId The GPIO ID of the GPIO to drive.
* @param logiclevel The logic level to set. O or 1. * @param logiclevel The logic level to set. O or 1.
*/ */
ReturnValue_t driveGpio(gpioId_t gpioId, ReturnValue_t driveGpio(gpioId_t gpioId, GpiodRegular* regularGpio, unsigned int logiclevel);
unsigned int logiclevel);
ReturnValue_t configureRegularGpio(gpioId_t gpioId, GpiodRegular* regularGpio);
/** /**
* @brief This function checks if GPIOs are already registered and whether * @brief This function checks if GPIOs are already registered and whether
@ -52,12 +60,18 @@ private:
* *
* @return RETURN_OK if successful, otherwise RETURN_FAILED * @return RETURN_OK if successful, otherwise RETURN_FAILED
*/ */
ReturnValue_t checkForConflicts(GpioMap mapToAdd); ReturnValue_t checkForConflicts(GpioMap& mapToAdd);
ReturnValue_t checkForConflictsRegularGpio(gpioId_t gpiodId, GpiodRegular* regularGpio,
GpioMap& mapToAdd);
ReturnValue_t checkForConflictsCallbackGpio(gpioId_t gpiodId, GpioCallback* regularGpio,
GpioMap& mapToAdd);
/** /**
* @brief Performs the initial configuration of all GPIOs specified in the GpioMap mapToAdd. * @brief Performs the initial configuration of all GPIOs specified in the GpioMap mapToAdd.
*/ */
ReturnValue_t configureGpios(GpioMap* mapToAdd); ReturnValue_t configureGpios(GpioMap& mapToAdd);
}; };
#endif /* BSP_Q7S_GPIO_LINUXLIBGPIOIF_H_ */ #endif /* LINUX_GPIO_LINUXLIBGPIOIF_H_ */

View File

@ -0,0 +1,92 @@
#ifndef LINUX_GPIO_GPIODEFINITIONS_H_
#define LINUX_GPIO_GPIODEFINITIONS_H_
#include <string>
#include <unordered_map>
using gpioId_t = uint16_t;
namespace gpio {
enum Direction {
IN = 0,
OUT = 1
};
enum GpioOperation {
READ,
WRITE
};
enum GpioTypes {
NONE,
GPIOD_REGULAR,
CALLBACK
};
static constexpr gpioId_t NO_GPIO = -1;
}
/**
* @brief Struct containing information about the GPIO to use. This is
* required by the libgpiod to access and drive a GPIO.
* @param chipname String of the chipname specifying the group which contains the GPIO to
* access. E.g. gpiochip0. To detect names of GPIO groups run gpiodetect on
* the linux command line.
* @param lineNum The offset of the GPIO within the GPIO group.
* @param consumer Name of the consumer. Simply a description of the GPIO configuration.
* @param direction Specifies whether the GPIO should be used as in- or output.
* @param initValue Defines the initial state of the GPIO when configured as output.
* Only required for output GPIOs.
* @param lineHandle The handle returned by gpiod_chip_get_line will be later written to this
* pointer.
*/
class GpioBase {
public:
GpioBase() = default;
GpioBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction,
int initValue):
gpioType(gpioType), consumer(consumer),direction(direction), initValue(initValue) {}
virtual~ GpioBase() {};
/* Can be used to cast GpioBase to a concrete child implementation */
gpio::GpioTypes gpioType = gpio::GpioTypes::NONE;
std::string consumer;
gpio::Direction direction = gpio::Direction::IN;
int initValue = 0;
};
class GpiodRegular: public GpioBase {
public:
GpiodRegular(): GpioBase(gpio::GpioTypes::GPIOD_REGULAR, std::string(),
gpio::Direction::IN, 0) {};
GpiodRegular(std::string chipname_, int lineNum_, std::string consumer_,
gpio::Direction direction_, int initValue_):
GpioBase(gpio::GpioTypes::GPIOD_REGULAR, consumer_, direction_, initValue_),
chipname(chipname_), lineNum(lineNum_) {}
std::string chipname;
int lineNum = 0;
struct gpiod_line* lineHandle = nullptr;
};
class GpioCallback: public GpioBase {
public:
GpioCallback(std::string consumer, gpio::Direction direction_, int initValue_,
void (* callback) (gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args),
void* callbackArgs):
GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_),
callback(callback), callbackArgs(callbackArgs) {}
void (* callback) (gpioId_t gpioId, gpio::GpioOperation gpioOp,
int value, void* args) = nullptr;
void* callbackArgs = nullptr;
};
using GpioMap = std::unordered_map<gpioId_t, GpioBase*>;
using GpioMapIter = GpioMap::iterator;
#endif /* LINUX_GPIO_GPIODEFINITIONS_H_ */

View File

@ -1,12 +1,13 @@
#include "I2cComIF.h" #include "I2cComIF.h"
#include <fsfw/serviceinterface/ServiceInterface.h> #include <fsfw/serviceinterface/ServiceInterface.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/i2c-dev.h> #include <linux/i2c-dev.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <linux/utility/Utility.h>
#include <cstring>
I2cComIF::I2cComIF(object_id_t objectId): SystemObject(objectId){ I2cComIF::I2cComIF(object_id_t objectId): SystemObject(objectId){
@ -14,18 +15,18 @@ I2cComIF::I2cComIF(object_id_t objectId): SystemObject(objectId){
I2cComIF::~I2cComIF() {} I2cComIF::~I2cComIF() {}
ReturnValue_t I2cComIF::initializeInterface(CookieIF * cookie) { ReturnValue_t I2cComIF::initializeInterface(CookieIF* cookie) {
address_t i2cAddress; address_t i2cAddress;
std::string deviceFile; std::string deviceFile;
if(cookie == nullptr) { if(cookie == nullptr) {
sif::error << "I2cComIF::initializeInterface: Invalid cookie!" << std::endl;
return NULLPOINTER; return NULLPOINTER;
} }
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie); I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) { if(i2cCookie == nullptr) {
sif::error << "I2cComIF: Invalid I2C Cookie!" sif::error << "I2cComIF::initializeInterface: Invalid I2C cookie!" << std::endl;
<< std::endl;
return NULLPOINTER; return NULLPOINTER;
} }
@ -35,25 +36,18 @@ ReturnValue_t I2cComIF::initializeInterface(CookieIF * cookie) {
if(i2cDeviceMapIter == i2cDeviceMap.end()) { if(i2cDeviceMapIter == i2cDeviceMap.end()) {
size_t maxReplyLen = i2cCookie->getMaxReplyLen(); size_t maxReplyLen = i2cCookie->getMaxReplyLen();
I2cInstance_t i2cInstance = {std::vector<uint8_t>(maxReplyLen), 0}; I2cInstance_t i2cInstance = {std::vector<uint8_t>(maxReplyLen), 0};
std::pair status = i2cDeviceMap.emplace(i2cAddress, i2cInstance); auto statusPair = i2cDeviceMap.emplace(i2cAddress, i2cInstance);
if (status.second == false) { if (not statusPair.second) {
sif::error << "I2cComIF::initializeInterface: Failed to insert " sif::error << "I2cComIF::initializeInterface: Failed to insert device with address " <<
<< "device with address " << i2cAddress << "to I2C device " i2cAddress << "to I2C device " << "map" << std::endl;
<< "map" << std::endl; return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
}
else {
sif::error << "I2cComIF: Device with address " << i2cAddress
<< "already in use" << std::endl;
}
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress); sif::error << "I2cComIF::initializeInterface: Device with address " << i2cAddress <<
if(i2cDeviceMapIter == i2cDeviceMap.end()) { "already in use" << std::endl;
sif::error << "Failure" << std::endl; return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t I2cComIF::sendMessage(CookieIF *cookie, ReturnValue_t I2cComIF::sendMessage(CookieIF *cookie,
@ -75,8 +69,7 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF *cookie,
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie); I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) { if(i2cCookie == nullptr) {
sif::error << "I2cComIF::sendMessasge: Invalid I2C Cookie!" sif::error << "I2cComIF::sendMessage: Invalid I2C Cookie!" << std::endl;
<< std::endl;
return NULLPOINTER; return NULLPOINTER;
} }
@ -89,6 +82,10 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF *cookie,
} }
deviceFile = i2cCookie->getDeviceFile(); deviceFile = i2cCookie->getDeviceFile();
utility::UnixFileHelper fileHelper(deviceFile, &fd, O_RDWR, "I2cComIF::sendMessage");
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return fileHelper.getOpenResult();
}
result = openDevice(deviceFile, i2cAddress, &fd); result = openDevice(deviceFile, i2cAddress, &fd);
if (result != HasReturnvaluesIF::RETURN_OK){ if (result != HasReturnvaluesIF::RETURN_OK){
return result; return result;
@ -98,10 +95,8 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF *cookie,
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C " sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
"device with error code " << errno << ". Error description: " "device with error code " << errno << ". Error description: "
<< strerror(errno) << std::endl; << strerror(errno) << std::endl;
close(fd);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
close(fd);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -111,7 +106,6 @@ ReturnValue_t I2cComIF::getSendSuccess(CookieIF *cookie) {
ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF *cookie, ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF *cookie,
size_t requestLen) { size_t requestLen) {
ReturnValue_t result; ReturnValue_t result;
int fd; int fd;
std::string deviceFile; std::string deviceFile;
@ -122,8 +116,7 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF *cookie,
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie); I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) { if(i2cCookie == nullptr) {
sif::error << "I2cComIF::requestReceiveMessage: Invalid I2C Cookie!" sif::error << "I2cComIF::requestReceiveMessage: Invalid I2C Cookie!" << std::endl;
<< std::endl;
i2cDeviceMapIter->second.replyLen = 0; i2cDeviceMapIter->second.replyLen = 0;
return NULLPOINTER; return NULLPOINTER;
} }
@ -138,6 +131,10 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF *cookie,
} }
deviceFile = i2cCookie->getDeviceFile(); deviceFile = i2cCookie->getDeviceFile();
utility::UnixFileHelper fileHelper(deviceFile, &fd, O_RDWR, "I2cComIF::requestReceiveMessage");
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return fileHelper.getOpenResult();
}
result = openDevice(deviceFile, i2cAddress, &fd); result = openDevice(deviceFile, i2cAddress, &fd);
if (result != HasReturnvaluesIF::RETURN_OK){ if (result != HasReturnvaluesIF::RETURN_OK){
i2cDeviceMapIter->second.replyLen = 0; i2cDeviceMapIter->second.replyLen = 0;
@ -146,19 +143,15 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF *cookie,
uint8_t* replyBuffer = i2cDeviceMapIter->second.replyBuffer.data(); uint8_t* replyBuffer = i2cDeviceMapIter->second.replyBuffer.data();
if (read(fd, replyBuffer, requestLen) != (int)requestLen) { if (read(fd, replyBuffer, requestLen) != static_cast<int>(requestLen)) {
sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C " sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C "
<< "device failed with error code " << errno <<". Description" << "device failed with error code " << errno <<". Description"
<< " of error: " << strerror(errno) << std::endl; << " of error: " << strerror(errno) << std::endl;
close(fd);
i2cDeviceMapIter->second.replyLen = 0; i2cDeviceMapIter->second.replyLen = 0;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
i2cDeviceMapIter->second.replyLen = requestLen; i2cDeviceMapIter->second.replyLen = requestLen;
close(fd);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -166,8 +159,7 @@ ReturnValue_t I2cComIF::readReceivedMessage(CookieIF *cookie,
uint8_t **buffer, size_t* size) { uint8_t **buffer, size_t* size) {
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie); I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) { if(i2cCookie == nullptr) {
sif::error << "I2cComIF::readReceivedMessage: Invalid I2C Cookie!" sif::error << "I2cComIF::readReceivedMessage: Invalid I2C Cookie!" << std::endl;
<< std::endl;
return NULLPOINTER; return NULLPOINTER;
} }
@ -186,18 +178,18 @@ ReturnValue_t I2cComIF::readReceivedMessage(CookieIF *cookie,
ReturnValue_t I2cComIF::openDevice(std::string deviceFile, ReturnValue_t I2cComIF::openDevice(std::string deviceFile,
address_t i2cAddress, int* fileDescriptor) { address_t i2cAddress, int* fileDescriptor) {
*fileDescriptor = open(deviceFile.c_str(), O_RDWR);
if (*fileDescriptor < 0) {
sif::error << "I2cComIF: Opening i2c device failed with error code "
<< errno << ". Error description: " << strerror(errno)
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if (ioctl(*fileDescriptor, I2C_SLAVE, i2cAddress) < 0) { if (ioctl(*fileDescriptor, I2C_SLAVE, i2cAddress) < 0) {
sif::error << "I2cComIF: Specifying target device failed with error " #if FSFW_VERBOSE_LEVEL >= 1
<< "code " << errno << ". Error description " #if FSFW_CPP_OSTREAM_ENABLED == 1
<< strerror(errno) << std::endl; sif::warning << "I2cComIF: Specifying target device failed with error code " << errno << "."
<< std::endl;
sif::warning << "Error description " << strerror(errno) << std::endl;
#else
sif::printWarning("I2cComIF: Specifying target device failed with error code %d.\n");
sif::printWarning("Error description: %s\n", strerror(errno));
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;

View File

@ -1,5 +1,5 @@
#ifndef BSP_Q7S_COMIF_I2COMIF_H_ #ifndef LINUX_I2C_I2COMIF_H_
#define BSP_Q7S_COMIF_I2COMIF_H_ #define LINUX_I2C_I2COMIF_H_
#include "I2cCookie.h" #include "I2cCookie.h"
#include <fsfw/objectmanager/SystemObject.h> #include <fsfw/objectmanager/SystemObject.h>
@ -45,8 +45,8 @@ private:
I2cDeviceMapIter i2cDeviceMapIter; I2cDeviceMapIter i2cDeviceMapIter;
/** /**
* @brief This function opens an i2c device and binds the opened file * @brief This function opens an I2C device and binds the opened file
* to a specific i2c address. * to a specific I2C address.
* @param deviceFile The name of the device file. E.g. i2c-0 * @param deviceFile The name of the device file. E.g. i2c-0
* @param i2cAddress The address of the i2c slave device. * @param i2cAddress The address of the i2c slave device.
* @param fileDescriptor Pointer to device descriptor. * @param fileDescriptor Pointer to device descriptor.
@ -56,4 +56,4 @@ private:
address_t i2cAddress, int* fileDescriptor); address_t i2cAddress, int* fileDescriptor);
}; };
#endif /* BSP_Q7S_COMIF_I2COMIF_H_ */ #endif /* LINUX_I2C_I2COMIF_H_ */

View File

@ -2,8 +2,7 @@
I2cCookie::I2cCookie(address_t i2cAddress_, size_t maxReplyLen_, I2cCookie::I2cCookie(address_t i2cAddress_, size_t maxReplyLen_,
std::string deviceFile_) : std::string deviceFile_) :
i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile( i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile(deviceFile_) {
deviceFile_) {
} }
address_t I2cCookie::getAddress() const { address_t I2cCookie::getAddress() const {

View File

@ -1,5 +1,5 @@
#ifndef SAM9G20_COMIF_COOKIES_I2C_COOKIE_H_ #ifndef LINUX_I2C_I2CCOOKIE_H_
#define SAM9G20_COMIF_COOKIES_I2C_COOKIE_H_ #define LINUX_I2C_I2CCOOKIE_H_
#include <fsfw/devicehandlers/CookieIF.h> #include <fsfw/devicehandlers/CookieIF.h>
#include <string> #include <string>
@ -34,4 +34,4 @@ private:
std::string deviceFile; std::string deviceFile;
}; };
#endif #endif /* LINUX_I2C_I2CCOOKIE_H_ */

View File

@ -1,4 +1,6 @@
target_sources(${TARGET_NAME} PUBLIC target_sources(${TARGET_NAME} PUBLIC
SpiComIF.cpp
SpiCookie.cpp
) )

308
linux/spi/SpiComIF.cpp Normal file
View File

@ -0,0 +1,308 @@
#include "SpiComIF.h"
#include <linux/utility/Utility.h>
#include <linux/spi/SpiCookie.h>
#include <fsfw/ipc/MutexFactory.h>
#include <fsfw/ipc/MutexHelper.h>
#include <fsfw/globalfunctions/arrayprinter.h>
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <cerrno>
#include <cstring>
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): SystemObject(objectId),
gpioComIF(gpioComIF) {
if(gpioComIF == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::SpiComIF: GPIO communication interface invalid!" << std::endl;
#else
sif::printError("SpiComIF::SpiComIF: GPIO communication interface invalid!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
}
spiMutex = MutexFactory::instance()->createMutex();
}
ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) {
int retval = 0;
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
if(spiCookie == nullptr) {
return NULLPOINTER;
}
address_t spiAddress = spiCookie->getSpiAddress();
auto iter = spiDeviceMap.find(spiAddress);
if(iter == spiDeviceMap.end()) {
size_t bufferSize = spiCookie->getMaxBufferSize();
SpiInstance spiInstance = {std::vector<uint8_t>(bufferSize)};
auto statusPair = spiDeviceMap.emplace(spiAddress, spiInstance);
if (not statusPair.second) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::initializeInterface: Failed to insert device with address " <<
spiAddress << "to SPI device map" << std::endl;
#else
sif::printError("SpiComIF::initializeInterface: Failed to insert device with address "
"%lu to SPI device map\n", static_cast<unsigned long>(spiAddress));
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return HasReturnvaluesIF::RETURN_FAILED;
}
/* Now we emplaced the read buffer in the map, we still need to assign that location
to the SPI driver transfer struct */
spiCookie->assignReadBuffer(statusPair.first->second.replyBuffer.data());
}
else {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::initializeInterface: SPI address already exists!" << std::endl;
#else
sif::printError("SpiComIF::initializeInterface: SPI address already exists!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return HasReturnvaluesIF::RETURN_FAILED;
}
/* Pull CS high in any case to be sure that device is inactive */
gpioId_t gpioId = spiCookie->getChipSelectPin();
if(gpioId != gpio::NO_GPIO) {
gpioComIF->pullHigh(gpioId);
}
size_t spiSpeed = 0;
spi::SpiMode spiMode = spi::SpiMode::MODE_0;
SpiCookie::UncommonParameters params;
spiCookie->getSpiParameters(spiMode, spiSpeed, &params);
int fileDescriptor = 0;
utility::UnixFileHelper fileHelper(spiCookie->getSpiDevice(), &fileDescriptor, O_RDWR,
"SpiComIF::initializeInterface: ");
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return fileHelper.getOpenResult();
}
/* These flags are rather uncommon */
if(params.threeWireSpi or params.noCs or params.csHigh) {
uint32_t currentMode = 0;
retval = ioctl(fileDescriptor, SPI_IOC_RD_MODE32, &currentMode);
if(retval != 0) {
utility::handleIoctlError("SpiComIF::initialiezInterface: Could not read full mode!");
}
if(params.threeWireSpi) {
currentMode |= SPI_3WIRE;
}
if(params.noCs) {
/* Some drivers like the Raspberry Pi ignore this flag in any case */
currentMode |= SPI_NO_CS;
}
if(params.csHigh) {
currentMode |= SPI_CS_HIGH;
}
/* Write adapted mode */
retval = ioctl(fileDescriptor, SPI_IOC_WR_MODE32, &currentMode);
if(retval != 0) {
utility::handleIoctlError("SpiComIF::initialiezInterface: Could not write full mode!");
}
}
if(params.lsbFirst) {
retval = ioctl(fileDescriptor, SPI_IOC_WR_LSB_FIRST, &params.lsbFirst);
if(retval != 0) {
utility::handleIoctlError("SpiComIF::initializeInterface: Setting LSB first failed");
}
}
if(params.bitsPerWord != 8) {
retval = ioctl(fileDescriptor, SPI_IOC_WR_BITS_PER_WORD, &params.bitsPerWord);
if(retval != 0) {
utility::handleIoctlError("SpiComIF::initializeInterface: "
"Could not write bits per word!");
}
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) {
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
int retval = 0;
if(spiCookie == nullptr) {
return NULLPOINTER;
}
if(sendLen > spiCookie->getMaxBufferSize()) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SpiComIF::sendMessage: Too much data sent, send length" << sendLen <<
"larger than maximum buffer length" << spiCookie->getMaxBufferSize() << std::endl;
#else
sif::printWarning("SpiComIF::sendMessage: Too much data sent, send length %lu larger "
"than maximum buffer length %lu!\n", static_cast<unsigned long>(sendLen),
static_cast<unsigned long>(spiCookie->getMaxBufferSize()));
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return DeviceCommunicationIF::TOO_MUCH_DATA;
}
/* Prepare transfer */
int fileDescriptor = 0;
std::string device = spiCookie->getSpiDevice();
utility::UnixFileHelper fileHelper(device, &fileDescriptor, O_RDWR,
"SpiComIF::sendMessage: ");
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return OPENING_FILE_FAILED;
}
spi::SpiMode spiMode = spi::SpiMode::MODE_0;
uint32_t spiSpeed = 0;
spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr);
setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed);
spiCookie->assignWriteBuffer(sendData);
spiCookie->assignTransferSize(sendLen);
bool fullDuplex = spiCookie->isFullDuplex();
gpioId_t gpioId = spiCookie->getChipSelectPin();
/* GPIO access is mutex protected */
MutexHelper(spiMutex, timeoutType, timeoutMs);
/* Pull SPI CS low. For now, no support for active high given */
if(gpioId != gpio::NO_GPIO) {
gpioComIF->pullLow(gpioId);
}
/* Execute transfer */
if(fullDuplex) {
/* Initiate a full duplex SPI transfer. */
retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle());
if(retval < 0) {
utility::handleIoctlError("SpiComIF::sendMessage: ioctl error.");
result = FULL_DUPLEX_TRANSFER_FAILED;
}
}
else {
/* We write with a blocking half-duplex transfer here */
if (write(fileDescriptor, sendData, sendLen) != static_cast<ssize_t>(sendLen)) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" <<
std::endl;
#else
sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
result = HALF_DUPLEX_TRANSFER_FAILED;
}
}
if(gpioId != gpio::NO_GPIO) {
gpioComIF->pullHigh(gpioId);
}
return result;
}
ReturnValue_t SpiComIF::getSendSuccess(CookieIF *cookie) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
if(spiCookie == nullptr) {
return NULLPOINTER;
}
bool fullDuplex = spiCookie->isFullDuplex();
if(fullDuplex) {
return HasReturnvaluesIF::RETURN_OK;
}
std::string device = spiCookie->getSpiDevice();
int fileDescriptor = 0;
utility::UnixFileHelper fileHelper(device, &fileDescriptor, O_RDWR,
"SpiComIF::requestReceiveMessage: ");
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return OPENING_FILE_FAILED;
}
uint8_t* rxBuf = nullptr;
size_t readSize = spiCookie->getCurrentTransferSize();
result = getReadBuffer(spiCookie->getSpiAddress(), &rxBuf);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
gpioId_t gpioId = spiCookie->getChipSelectPin();
MutexHelper(spiMutex, timeoutType, timeoutMs);
if(gpioId != gpio::NO_GPIO) {
gpioComIF->pullLow(gpioId);
}
if(read(fileDescriptor, rxBuf, readSize) != static_cast<ssize_t>(readSize)) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SpiComIF::sendMessage: Half-Duplex read operation failed!" << std::endl;
#else
sif::printWarning("SpiComIF::sendMessage: Half-Duplex read operation failed!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
result = HALF_DUPLEX_TRANSFER_FAILED;
}
if(gpioId != gpio::NO_GPIO) {
gpioComIF->pullHigh(gpioId);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) {
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
if(spiCookie == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint8_t* rxBuf = nullptr;
ReturnValue_t result = getReadBuffer(spiCookie->getSpiAddress(), &rxBuf);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*buffer = rxBuf;
*size = spiCookie->getCurrentTransferSize();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
if(buffer == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
auto iter = spiDeviceMap.find(spiAddress);
if(iter == spiDeviceMap.end()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
*buffer = iter->second.replyBuffer.data();
return HasReturnvaluesIF::RETURN_OK;
}
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiMode mode, uint32_t speed) {
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
if(retval != 0) {
utility::handleIoctlError("SpiTestClass::performRm3100Test: Setting SPI mode failed!");
}
retval = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if(retval != 0) {
utility::handleIoctlError("SpiTestClass::performRm3100Test: Setting SPI speed failed!");
}
}

63
linux/spi/SpiComIF.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef LINUX_SPI_SPICOMIF_H_
#define LINUX_SPI_SPICOMIF_H_
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
#include <fsfw/objectmanager/SystemObject.h>
#include <linux/gpio/GpioIF.h>
#include <linux/spi/spiDefinitions.h>
#include <returnvalues/classIds.h>
#include <vector>
#include <unordered_map>
/**
* @brief Encapsulates access to linux SPI driver for FSFW objects
* @details
* Right now, only full-duplex SPI is supported.
* @author R. Mueller
*/
class SpiComIF: public DeviceCommunicationIF, public SystemObject {
public:
static constexpr uint8_t spiRetvalId = CLASS_ID::LINUX_SPI_COM_IF;
static constexpr ReturnValue_t OPENING_FILE_FAILED =
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 0);
/* Full duplex (ioctl) transfer failure */
static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED =
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 1);
/* Half duplex (read/write) transfer failure */
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED =
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 2);
SpiComIF(object_id_t objectId, GpioIF* gpioComIF);
ReturnValue_t initializeInterface(CookieIF * cookie) override;
ReturnValue_t sendMessage(CookieIF *cookie,const uint8_t *sendData,
size_t sendLen) override;
ReturnValue_t getSendSuccess(CookieIF *cookie) override;
ReturnValue_t requestReceiveMessage(CookieIF *cookie,
size_t requestLen) override;
ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
size_t *size) override;
private:
struct SpiInstance {
std::vector<uint8_t> replyBuffer;
};
GpioIF* gpioComIF = nullptr;
MutexIF* spiMutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20;
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
using SpiDeviceMapIter = SpiDeviceMap::iterator;
SpiDeviceMap spiDeviceMap;
ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer);
void setSpiSpeedAndMode(int spiFd, spi::SpiMode mode, uint32_t speed);
};
#endif /* LINUX_SPI_SPICOMIF_H_ */

99
linux/spi/SpiCookie.cpp Normal file
View File

@ -0,0 +1,99 @@
#include "SpiCookie.h"
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
const size_t maxSize, spi::SpiMode spiMode, uint32_t spiSpeed): spiAddress(spiAddress),
chipSelectPin(chipSelect), spiDevice(spiDev), maxSize(maxSize), spiMode(spiMode),
spiSpeed(spiSpeed) {
}
SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize,
spi::SpiMode spiMode, uint32_t spiSpeed):
SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) {
}
void SpiCookie::getSpiParameters(spi::SpiMode& spiMode, uint32_t& spiSpeed,
UncommonParameters* parameters) const {
spiMode = this->spiMode;
spiSpeed = this->spiSpeed;
if(parameters != nullptr) {
parameters->threeWireSpi = uncommonParameters.threeWireSpi;
parameters->lsbFirst = uncommonParameters.lsbFirst;
parameters->noCs = uncommonParameters.noCs;
parameters->bitsPerWord = uncommonParameters.bitsPerWord;
parameters->csHigh = uncommonParameters.csHigh;
}
}
gpioId_t SpiCookie::getChipSelectPin() const {
return chipSelectPin;
}
size_t SpiCookie::getMaxBufferSize() const {
return maxSize;
}
address_t SpiCookie::getSpiAddress() const {
return spiAddress;
}
std::string SpiCookie::getSpiDevice() const {
return spiDevice;
}
void SpiCookie::setThreeWireSpi(bool enable) {
uncommonParameters.threeWireSpi = enable;
}
void SpiCookie::setLsbFirst(bool enable) {
uncommonParameters.lsbFirst = enable;
}
void SpiCookie::setNoCs(bool enable) {
uncommonParameters.noCs = enable;
}
void SpiCookie::setBitsPerWord(uint8_t bitsPerWord) {
uncommonParameters.bitsPerWord = bitsPerWord;
}
void SpiCookie::setCsHigh(bool enable) {
uncommonParameters.csHigh = enable;
}
void SpiCookie::activateCsDeselect(bool deselectCs, uint16_t delayUsecs) {
spiTransferStruct.cs_change = deselectCs;
spiTransferStruct.delay_usecs = delayUsecs;
}
void SpiCookie::assignReadBuffer(uint8_t* rx) {
if(rx != nullptr) {
spiTransferStruct.rx_buf = reinterpret_cast<__u64>(rx);
}
}
void SpiCookie::assignWriteBuffer(const uint8_t* tx) {
if(tx != nullptr) {
spiTransferStruct.tx_buf = reinterpret_cast<__u64>(tx);
}
}
spi_ioc_transfer* SpiCookie::getTransferStructHandle() {
return &spiTransferStruct;
}
void SpiCookie::setFullOrHalfDuplex(bool halfDuplex) {
this->halfDuplex = halfDuplex;
}
bool SpiCookie::isFullDuplex() const {
return not this->halfDuplex;
}
void SpiCookie::assignTransferSize(size_t transferSize) {
spiTransferStruct.len = transferSize;
}
size_t SpiCookie::getCurrentTransferSize() const {
return spiTransferStruct.len;
}

113
linux/spi/SpiCookie.h Normal file
View File

@ -0,0 +1,113 @@
#ifndef LINUX_SPI_SPICOOKIE_H_
#define LINUX_SPI_SPICOOKIE_H_
#include "spiDefinitions.h"
#include <fsfw/devicehandlers/CookieIF.h>
#include <linux/gpio/gpioDefinitions.h>
#include <linux/spi/spidev.h>
class SpiCookie: public CookieIF {
public:
/**
* Each SPI device will have a corresponding cookie. The cookie is used by the communication
* interface and contains device specific information like the largest expected size to be
* sent and received and the GPIO pin used to toggle the SPI slave select pin.
* @param spiAddress
* @param chipSelect Chip select. gpio::NO_GPIO can be used for hardware slave selects.
* @param spiDev
* @param maxSize
*/
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
const size_t maxReplySize, spi::SpiMode spiMode, uint32_t spiSpeed);
/**
* Like constructor above, but without a dedicated GPIO CS. Can be used for hardware
* slave select or if CS logic is performed with decoders.
*/
SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize,
spi::SpiMode spiMode, uint32_t spiSpeed);
address_t getSpiAddress() const;
std::string getSpiDevice() const;
gpioId_t getChipSelectPin() const;
size_t getMaxBufferSize() const;
/**
* True if SPI transfers should be performed in full duplex mode
* @return
*/
bool isFullDuplex() const;
/**
* Set transfer type to full duplex or half duplex. Full duplex is the default setting,
* ressembling common SPI hardware implementation with shift registers, where read and writes
* happen simultaneosly.
* @param fullDuplex
*/
void setFullOrHalfDuplex(bool halfDuplex);
/**
* This needs to be called to specify where the SPI driver writes to or reads from.
* @param readLocation
* @param writeLocation
*/
void assignReadBuffer(uint8_t* rx);
void assignWriteBuffer(const uint8_t* tx);
/**
* Assign size for the next transfer.
* @param transferSize
*/
void assignTransferSize(size_t transferSize);
size_t getCurrentTransferSize() const;
struct UncommonParameters {
uint8_t bitsPerWord = 8;
bool noCs = false;
bool csHigh = false;
bool threeWireSpi = false;
/* MSB first is more common */
bool lsbFirst = false;
};
/**
* Can be used to explicitely disable hardware chip select.
* Some drivers like the Raspberry Pi Linux driver will not use hardware chip select by default
* (see https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md)
* @param enable
*/
void setNoCs(bool enable);
void setThreeWireSpi(bool enable);
void setLsbFirst(bool enable);
void setCsHigh(bool enable);
void setBitsPerWord(uint8_t bitsPerWord);
void getSpiParameters(spi::SpiMode& spiMode, uint32_t& spiSpeed,
UncommonParameters* parameters = nullptr) const;
/**
* See spidev.h cs_change and delay_usecs
* @param deselectCs
* @param delayUsecs
*/
void activateCsDeselect(bool deselectCs, uint16_t delayUsecs);
spi_ioc_transfer* getTransferStructHandle();
private:
size_t currentTransferSize = 0;
address_t spiAddress;
gpioId_t chipSelectPin;
std::string spiDevice;
const size_t maxSize;
spi::SpiMode spiMode;
uint32_t spiSpeed;
bool halfDuplex = false;
struct spi_ioc_transfer spiTransferStruct = {};
UncommonParameters uncommonParameters;
};
#endif /* LINUX_SPI_SPICOOKIE_H_ */

View File

@ -0,0 +1,15 @@
#ifndef LINUX_SPI_SPIDEFINITONS_H_
#define LINUX_SPI_SPIDEFINITONS_H_
namespace spi {
enum SpiMode {
MODE_0,
MODE_1,
MODE_2,
MODE_3
};
}
#endif /* LINUX_SPI_SPIDEFINITONS_H_ */

View File

@ -0,0 +1,7 @@
target_sources(${TARGET_NAME} PUBLIC
Utility.cpp
)

52
linux/utility/Utility.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "Utility.h"
void utility::handleIoctlError(const char* const customPrintout) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
if(customPrintout != nullptr) {
sif::warning << customPrintout << std::endl;
}
sif::warning << "handleIoctlError: Error code " << errno << ", "<< strerror(errno) <<
std::endl;
#else
if(customPrintout != nullptr) {
sif::printWarning("%s\n", customPrintout);
}
sif::printWarning("handleIoctlError: Error code %d, %s\n", errno, strerror(errno));
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
}
utility::UnixFileHelper::UnixFileHelper(std::string device, int* fileDescriptor, int flags,
std::string diagnosticPrefix):
fileDescriptor(fileDescriptor) {
if(fileDescriptor == nullptr) {
return;
}
*fileDescriptor = open(device.c_str(), flags);
if (*fileDescriptor < 0) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << diagnosticPrefix <<"Opening device failed with error code " << errno <<
"." << std::endl;
sif::warning << "Error description: " << strerror(errno) << std::endl;
#else
sif::printError("%sOpening device failed with error code %d.\n", diagnosticPrefix);
sif::printWarning("Error description: %s\n", strerror(errno));
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
openStatus = OPEN_FILE_FAILED;
}
}
utility::UnixFileHelper::~UnixFileHelper() {
if(fileDescriptor != nullptr) {
close(*fileDescriptor);
}
}
ReturnValue_t utility::UnixFileHelper::getOpenResult() const {
return openStatus;
}

36
linux/utility/Utility.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef LINUX_UTILITY_UTILITY_H_
#define LINUX_UTILITY_UTILITY_H_
#include <cerrno>
#include <cstring>
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fcntl.h>
#include <unistd.h>
namespace utility {
void handleIoctlError(const char* const customPrintout);
class UnixFileHelper {
public:
static constexpr int READ_WRITE_FLAG = O_RDWR;
static constexpr int READ_ONLY_FLAG = O_RDONLY;
static constexpr int NON_BLOCKING_IO_FLAG = O_NONBLOCK;
static constexpr ReturnValue_t OPEN_FILE_FAILED = 1;
UnixFileHelper(std::string device, int* fileDescriptor, int flags,
std::string diagnosticPrefix = "");
virtual~ UnixFileHelper();
ReturnValue_t getOpenResult() const;
private:
int* fileDescriptor = nullptr;
ReturnValue_t openStatus = HasReturnvaluesIF::RETURN_OK;
};
}
#endif /* LINUX_UTILITY_UTILITY_H_ */

View File

@ -11,6 +11,7 @@
#include <fsfw/pus/CService200ModeCommanding.h> #include <fsfw/pus/CService200ModeCommanding.h>
#include <fsfw/pus/Service17Test.h> #include <fsfw/pus/Service17Test.h>
#include <fsfw/pus/Service1TelecommandVerification.h> #include <fsfw/pus/Service1TelecommandVerification.h>
#include <fsfw/pus/Service20ParameterManagement.h>
#include <fsfw/pus/Service3Housekeeping.h> #include <fsfw/pus/Service3Housekeeping.h>
#include <fsfw/pus/Service2DeviceAccess.h> #include <fsfw/pus/Service2DeviceAccess.h>
#include <fsfw/pus/Service5EventReporting.h> #include <fsfw/pus/Service5EventReporting.h>
@ -78,6 +79,8 @@ void ObjectFactory::produceGenericObjects() {
apid::EIVE_OBSW, pus::PUS_SERVICE_9); apid::EIVE_OBSW, pus::PUS_SERVICE_9);
new Service17Test(objects::PUS_SERVICE_17_TEST, apid::EIVE_OBSW, new Service17Test(objects::PUS_SERVICE_17_TEST, apid::EIVE_OBSW,
pus::PUS_SERVICE_17); pus::PUS_SERVICE_17);
new Service20ParameterManagement(objects::PUS_SERVICE_20_PARAMETERS, apid::EIVE_OBSW,
pus::PUS_SERVICE_20);
new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT, new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT,
apid::EIVE_OBSW, pus::PUS_SERVICE_200); apid::EIVE_OBSW, pus::PUS_SERVICE_200);

View File

@ -10,7 +10,6 @@ target_sources(${TARGET_NAME} PUBLIC
PDU1Handler.cpp PDU1Handler.cpp
PDU2Handler.cpp PDU2Handler.cpp
ACUHandler.cpp ACUHandler.cpp
HeaterHandler.cpp
SolarArrayDeploymentHandler.cpp SolarArrayDeploymentHandler.cpp
) )

View File

@ -1,3 +1,4 @@
#include <fsfw/datapool/PoolReadHelper.h>
#include "MGMHandlerLIS3MDL.h" #include "MGMHandlerLIS3MDL.h"
@ -8,7 +9,7 @@ MGMHandlerLIS3MDL::MGMHandlerLIS3MDL(object_id_t objectId,
#if OBSW_VERBOSE_LEVEL >= 1 #if OBSW_VERBOSE_LEVEL >= 1
debugDivider = new PeriodicOperationDivider(10); debugDivider = new PeriodicOperationDivider(10);
#endif #endif
// Set to default values right away. /* Set to default values right away. */
registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT;
registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT;
registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT;
@ -23,22 +24,27 @@ MGMHandlerLIS3MDL::~MGMHandlerLIS3MDL() {
void MGMHandlerLIS3MDL::doStartUp() { void MGMHandlerLIS3MDL::doStartUp() {
switch (internalState) { switch (internalState) {
case(InternalState::STATE_NONE): case(InternalState::STATE_NONE): {
internalState = InternalState::STATE_FIRST_CONTACT; internalState = InternalState::STATE_FIRST_CONTACT;
break; break;
}
case(InternalState::STATE_FIRST_CONTACT): case(InternalState::STATE_FIRST_CONTACT): {
internalState = InternalState::STATE_SETUP; /* Will be set by checking device ID (WHO AM I register) */
break;
case(InternalState::STATE_SETUP):
internalState = InternalState::STATE_CHECK_REGISTERS;
break;
case(InternalState::STATE_CHECK_REGISTERS): {
// Set up cached registers which will be used to configure the MGM.
if(commandExecuted) { if(commandExecuted) {
commandExecuted = false; commandExecuted = false;
}
internalState = InternalState::STATE_SETUP;
break;
}
case(InternalState::STATE_SETUP): {
internalState = InternalState::STATE_CHECK_REGISTERS;
break;
}
case(InternalState::STATE_CHECK_REGISTERS): {
/* Set up cached registers which will be used to configure the MGM. */
if(commandExecuted) {
commandExecuted = false;
/* Replace _MODE_TO_ON with MODE_NORMAL to jump to normal mode quickly */
setMode(_MODE_TO_ON); setMode(_MODE_TO_ON);
} }
break; break;
@ -72,12 +78,18 @@ ReturnValue_t MGMHandlerLIS3MDL::buildTransitionDeviceCommand(
*id = MGMLIS3MDL::READ_CONFIG_AND_DATA; *id = MGMLIS3MDL::READ_CONFIG_AND_DATA;
break; break;
} }
default: default: {
// might be a configuration error. /* might be a configuration error. */
sif::debug << "GyroHandler::buildTransitionDeviceCommand: Unknown " #if FSFW_CPP_OSTREAM_ENABLED == 1
<< "internal state!" << std::endl; sif::warning << "GyroHandler::buildTransitionDeviceCommand: Unknown internal state!" <<
std::endl;
#else
sif::printWarning("GyroHandler::buildTransitionDeviceCommand: Unknown internal state!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
}
return buildCommandFromCommand(*id, NULL, 0); return buildCommandFromCommand(*id, NULL, 0);
} }
@ -184,6 +196,13 @@ ReturnValue_t MGMHandlerLIS3MDL::scanForReply(const uint8_t *start,
if (start[1] != registers[0] or start[2] != registers[1] or if (start[1] != registers[0] or start[2] != registers[1] or
start[3] != registers[2] or start[4] != registers[3] or start[3] != registers[2] or start[4] != registers[3] or
start[5] != registers[4]) { start[5] != registers[4]) {
#if OBSW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "MGMHandlerLIS3MDL::scanForReply: Invalid registers!" << std::endl;
#else
sif::printWarning("MGMHandlerLIS3MDL::scanForReply: Invalid registers!\n");
#endif
#endif
return DeviceHandlerIF::INVALID_DATA; return DeviceHandlerIF::INVALID_DATA;
} }
if(mode == _MODE_START_UP) { if(mode == _MODE_START_UP) {
@ -202,12 +221,28 @@ ReturnValue_t MGMHandlerLIS3MDL::scanForReply(const uint8_t *start,
else if (len == SINGLE_COMMAND_ANSWER_LEN) { else if (len == SINGLE_COMMAND_ANSWER_LEN) {
*foundLen = len; *foundLen = len;
*foundId = getPendingCommand(); *foundId = getPendingCommand();
if(*foundId == MGMLIS3MDL::IDENTIFY_DEVICE) {
if(start[1] != MGMLIS3MDL::DEVICE_ID) {
#if OBSW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "MGMHandlerLIS3MDL::scanForReply: Invalid registers!" << std::endl;
#else
sif::printWarning("MGMHandlerLIS3MDL::scanForReply: Invalid registers!\n");
#endif
#endif
return DeviceHandlerIF::INVALID_DATA;
}
if(mode == _MODE_START_UP) {
commandExecuted = true;
}
}
} }
else { else {
return DeviceHandlerIF::INVALID_DATA; return DeviceHandlerIF::INVALID_DATA;
} }
// Data with SPI Interface has always this answer /* Data with SPI Interface always has this answer */
if (start[0] == 0b11111111) { if (start[0] == 0b11111111) {
return RETURN_OK; return RETURN_OK;
} }
@ -227,7 +262,7 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id,
break; break;
} }
case MGMLIS3MDL::READ_CONFIG_AND_DATA: { case MGMLIS3MDL::READ_CONFIG_AND_DATA: {
// TODO: Store configuration and sensor values in new local datasets. // TODO: Store configuration in new local datasets.
uint8_t scale = getFullScale(registers[2]); uint8_t scale = getFullScale(registers[2]);
float sensitivityFactor = getSensitivityFactor(scale); float sensitivityFactor = getSensitivityFactor(scale);
@ -239,7 +274,7 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id,
int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8
| packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ; | packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ;
// Target value in microtesla /* Target value in microtesla */
float mgmX = static_cast<float>(mgmMeasurementRawX) * sensitivityFactor float mgmX = static_cast<float>(mgmMeasurementRawX) * sensitivityFactor
* MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR;
float mgmY = static_cast<float>(mgmMeasurementRawY) * sensitivityFactor float mgmY = static_cast<float>(mgmMeasurementRawY) * sensitivityFactor
@ -249,21 +284,27 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id,
#if OBSW_VERBOSE_LEVEL >= 1 #if OBSW_VERBOSE_LEVEL >= 1
if(debugDivider->checkAndIncrement()) { if(debugDivider->checkAndIncrement()) {
/* Set terminal to utf-8 if there is an issue with micro printout. */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "MGMHandlerLIS3: Magnetic field strength in" sif::info << "MGMHandlerLIS3: Magnetic field strength in"
" microtesla:" << std::endl; " microtesla:" << std::endl;
// Set terminal to utf-8 if there is an issue with micro printout.
sif::info << "X: " << mgmX << " \xC2\xB5T" << std::endl; sif::info << "X: " << mgmX << " \xC2\xB5T" << std::endl;
sif::info << "Y: " << mgmY << " \xC2\xB5T" << std::endl; sif::info << "Y: " << mgmY << " \xC2\xB5T" << std::endl;
sif::info << "Z: " << mgmZ << " \xC2\xB5T" << std::endl; sif::info << "Z: " << mgmZ << " \xC2\xB5T" << std::endl;
#else
sif::printInfo("MGMHandlerLIS3: Magnetic field strength in microtesla:\n");
sif::printInfo("X: %f " "\xC2\xB5" "T\n", mgmX);
sif::printInfo("Y: %f " "\xC2\xB5" "T\n", mgmY);
sif::printInfo("Z: %f " "\xC2\xB5" "T\n", mgmZ);
#endif
} }
#endif #endif
ReturnValue_t result = dataset.read(); PoolReadHelper readHelper(&dataset);
if(result == HasReturnvaluesIF::RETURN_OK) { if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
dataset.fieldStrengthX = mgmX; dataset.fieldStrengthX = mgmX;
dataset.fieldStrengthY = mgmY; dataset.fieldStrengthY = mgmY;
dataset.fieldStrengthZ = mgmZ; dataset.fieldStrengthZ = mgmZ;
dataset.setValidity(true, true); dataset.setValidity(true, true);
dataset.commit();
} }
break; break;
} }
@ -273,9 +314,13 @@ ReturnValue_t MGMHandlerLIS3MDL::interpretDeviceReply(DeviceCommandId_t id,
float tempValue = 25.0 + ((static_cast<float>(tempValueRaw)) / 8.0); float tempValue = 25.0 + ((static_cast<float>(tempValueRaw)) / 8.0);
#if OBSW_VERBOSE_LEVEL >= 1 #if OBSW_VERBOSE_LEVEL >= 1
if(debugDivider->check()) { if(debugDivider->check()) {
// Set terminal to utf-8 if there is an issue with micro printout. /* Set terminal to utf-8 if there is an issue with micro printout. */
sif::info << "MGMHandlerLIS3: Temperature: " << tempValue<< " °C" #if FSFW_CPP_OSTREAM_ENABLED == 1
<< std::endl; sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " \xC2\xB0" << "C" <<
std::endl;
#else
sif::printInfo("MGMHandlerLIS3: Temperature: %f" "\xC2\xB0" "C\n");
#endif
} }
#endif #endif
ReturnValue_t result = dataset.read(); ReturnValue_t result = dataset.read();
@ -397,7 +442,6 @@ void MGMHandlerLIS3MDL::fillCommandAndReplyMap() {
} }
ReturnValue_t MGMHandlerLIS3MDL::prepareCtrlRegisterWrite() { ReturnValue_t MGMHandlerLIS3MDL::prepareCtrlRegisterWrite() {
commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true);
for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) {
@ -406,7 +450,7 @@ ReturnValue_t MGMHandlerLIS3MDL::prepareCtrlRegisterWrite() {
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1;
// We dont have to check if this is working because we just did it /* We dont have to check if this is working because we just did it */
return RETURN_OK; return RETURN_OK;
} }
@ -415,7 +459,7 @@ void MGMHandlerLIS3MDL::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {
} }
uint32_t MGMHandlerLIS3MDL::getTransitionDelayMs(Mode_t from, Mode_t to) { uint32_t MGMHandlerLIS3MDL::getTransitionDelayMs(Mode_t from, Mode_t to) {
return 5000; return 30000;
} }
void MGMHandlerLIS3MDL::modeChanged(void) { void MGMHandlerLIS3MDL::modeChanged(void) {
@ -434,3 +478,6 @@ ReturnValue_t MGMHandlerLIS3MDL::initializeLocalDataPool(
new PoolEntry<float>({0.0})); new PoolEntry<float>({0.0}));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void MGMHandlerLIS3MDL::performOperationHook() {
}

View File

@ -161,6 +161,8 @@ private:
PeriodicOperationDivider* debugDivider; PeriodicOperationDivider* debugDivider;
#endif #endif
void performOperationHook() override;
}; };
#endif /* MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ */ #endif /* MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ */

View File

@ -1,14 +1,17 @@
#include <mission/devices/SolarArrayDeploymentHandler.h> #include <devices/powerSwitcherList.h>
#include <fsfwconfig/devices/powerSwitcherList.h>
#include <fsfw/ipc/QueueFactory.h>
#include <devices/gpioIds.h> #include <devices/gpioIds.h>
#include <mission/devices/SolarArrayDeploymentHandler.h>
#include <linux/gpio/GpioCookie.h>
#include <fsfw/ipc/QueueFactory.h>
SolarArrayDeploymentHandler::SolarArrayDeploymentHandler(object_id_t setObjectId_, SolarArrayDeploymentHandler::SolarArrayDeploymentHandler(object_id_t setObjectId_,
object_id_t gpioDriverId_, CookieIF * gpioCookie_, object_id_t mainLineSwitcherObjectId_, object_id_t gpioDriverId_, CookieIF * gpioCookie_, object_id_t mainLineSwitcherObjectId_,
uint8_t mainLineSwitch_, gpioId_t deplSA1, gpioId_t deplSA2, uint32_t burnTimeMs) : uint8_t mainLineSwitch_, gpioId_t deplSA1, gpioId_t deplSA2, uint32_t burnTimeMs) :
SystemObject(setObjectId_), gpioDriverId(gpioDriverId_), gpioCookie(gpioCookie_), mainLineSwitcherObjectId( SystemObject(setObjectId_), gpioDriverId(gpioDriverId_), gpioCookie(gpioCookie_),
mainLineSwitcherObjectId_), mainLineSwitch(mainLineSwitch_), deplSA1(deplSA1), deplSA2( mainLineSwitcherObjectId(mainLineSwitcherObjectId_), mainLineSwitch(mainLineSwitch_),
deplSA2), burnTimeMs(burnTimeMs), actionHelper(this, nullptr) { deplSA1(deplSA1), deplSA2(deplSA2), burnTimeMs(burnTimeMs), actionHelper(this, nullptr) {
commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize,
MessageQueueMessage::MAX_MESSAGE_SIZE); MessageQueueMessage::MAX_MESSAGE_SIZE);
} }
@ -38,7 +41,7 @@ ReturnValue_t SolarArrayDeploymentHandler::initialize() {
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
result = gpioInterface->initialize(gpioCookie); result = gpioInterface->addGpios(dynamic_cast<GpioCookie*>(gpioCookie));
if (result != RETURN_OK) { if (result != RETURN_OK) {
sif::error << "SolarArrayDeploymentHandler::initialize: Failed to initialize Gpio interface" sif::error << "SolarArrayDeploymentHandler::initialize: Failed to initialize Gpio interface"
<< std::endl; << std::endl;

View File

@ -1,6 +1,8 @@
#ifndef MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ #ifndef MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_
#define MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ #define MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_
#include <linux/gpio/GpioIF.h>
#include <fsfw/objectmanager/SystemObject.h> #include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/tasks/ExecutableObjectIF.h> #include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h> #include <fsfw/returnvalues/HasReturnvaluesIF.h>
@ -9,7 +11,7 @@
#include <fsfw/devicehandlers/CookieIF.h> #include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/devicehandlers/DeviceHandlerIF.h> #include <fsfw/devicehandlers/DeviceHandlerIF.h>
#include <fsfw/timemanager/Countdown.h> #include <fsfw/timemanager/Countdown.h>
#include <linux/gpio/GpioIF.h>
#include <unordered_map> #include <unordered_map>
/** /**
@ -115,7 +117,7 @@ private:
gpioId_t deplSA1; gpioId_t deplSA1;
gpioId_t deplSA2; gpioId_t deplSA2;
GpioIF* gpioInterface; GpioIF* gpioInterface = nullptr;
/** Time duration switches are active to cut the burn wire */ /** Time duration switches are active to cut the burn wire */
uint32_t burnTimeMs; uint32_t burnTimeMs;

View File

@ -24,11 +24,11 @@ static const DeviceCommandId_t IDENTIFY_DEVICE = 0x03;
static const DeviceCommandId_t TEMP_SENSOR_ENABLE = 0x04; static const DeviceCommandId_t TEMP_SENSOR_ENABLE = 0x04;
static const DeviceCommandId_t ACCURACY_OP_MODE_SET = 0x05; static const DeviceCommandId_t ACCURACY_OP_MODE_SET = 0x05;
//Number of all control registers /* Number of all control registers */
static const uint8_t NR_OF_CTRL_REGISTERS = 5; static const uint8_t NR_OF_CTRL_REGISTERS = 5;
//Number of registers in the MGM /* Number of registers in the MGM */
static const uint8_t NR_OF_REGISTERS = 19; static const uint8_t NR_OF_REGISTERS = 19;
//Total number of adresses for all registers /* Total number of adresses for all registers */
static const uint8_t TOTAL_NR_OF_ADRESSES = 52; static const uint8_t TOTAL_NR_OF_ADRESSES = 52;
static const uint8_t NR_OF_DATA_AND_CFG_REGISTERS = 14; static const uint8_t NR_OF_DATA_AND_CFG_REGISTERS = 14;
static const uint8_t TEMPERATURE_REPLY_LEN = 3; static const uint8_t TEMPERATURE_REPLY_LEN = 3;
@ -37,47 +37,47 @@ static const uint8_t SETUP_REPLY_LEN = 6;
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Register adresses */ /* Register adresses */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
// Register adress returns identifier of device with default 0b00111101 /* Register adress returns identifier of device with default 0b00111101 */
static const uint8_t IDENTIFY_DEVICE_REG_ADDR = 0b00001111; static const uint8_t IDENTIFY_DEVICE_REG_ADDR = 0b00001111;
static const uint8_t DEVICE_ID = 0b00111101; // Identifier for Device static const uint8_t DEVICE_ID = 0b00111101; // Identifier for Device
//Register adress to access register 1 /* Register adress to access register 1 */
static const uint8_t CTRL_REG1 = 0b00100000; static const uint8_t CTRL_REG1 = 0b00100000;
//Register adress to access register 2 /* Register adress to access register 2 */
static const uint8_t CTRL_REG2 = 0b00100001; static const uint8_t CTRL_REG2 = 0b00100001;
//Register adress to access register 3 /* Register adress to access register 3 */
static const uint8_t CTRL_REG3 = 0b00100010; static const uint8_t CTRL_REG3 = 0b00100010;
//Register adress to access register 4 /* Register adress to access register 4 */
static const uint8_t CTRL_REG4 = 0b00100011; static const uint8_t CTRL_REG4 = 0b00100011;
//Register adress to access register 5 /* Register adress to access register 5 */
static const uint8_t CTRL_REG5 = 0b00100100; static const uint8_t CTRL_REG5 = 0b00100100;
//Register adress to access status register /* Register adress to access status register */
static const uint8_t STATUS_REG_IDX = 8; static const uint8_t STATUS_REG_IDX = 8;
static const uint8_t STATUS_REG = 0b00100111; static const uint8_t STATUS_REG = 0b00100111;
//Register adress to access low byte of x-axis /* Register adress to access low byte of x-axis */
static const uint8_t X_LOWBYTE_IDX = 9; static const uint8_t X_LOWBYTE_IDX = 9;
static const uint8_t X_LOWBYTE = 0b00101000; static const uint8_t X_LOWBYTE = 0b00101000;
//Register adress to access high byte of x-axis /* Register adress to access high byte of x-axis */
static const uint8_t X_HIGHBYTE_IDX = 10; static const uint8_t X_HIGHBYTE_IDX = 10;
static const uint8_t X_HIGHBYTE = 0b00101001; static const uint8_t X_HIGHBYTE = 0b00101001;
//Register adress to access low byte of y-axis /* Register adress to access low byte of y-axis */
static const uint8_t Y_LOWBYTE_IDX = 11; static const uint8_t Y_LOWBYTE_IDX = 11;
static const uint8_t Y_LOWBYTE = 0b00101010; static const uint8_t Y_LOWBYTE = 0b00101010;
//Register adress to access high byte of y-axis /* Register adress to access high byte of y-axis */
static const uint8_t Y_HIGHBYTE_IDX = 12; static const uint8_t Y_HIGHBYTE_IDX = 12;
static const uint8_t Y_HIGHBYTE = 0b00101011; static const uint8_t Y_HIGHBYTE = 0b00101011;
//Register adress to access low byte of z-axis /* Register adress to access low byte of z-axis */
static const uint8_t Z_LOWBYTE_IDX = 13; static const uint8_t Z_LOWBYTE_IDX = 13;
static const uint8_t Z_LOWBYTE = 0b00101100; static const uint8_t Z_LOWBYTE = 0b00101100;
//Register adress to access high byte of z-axis /* Register adress to access high byte of z-axis */
static const uint8_t Z_HIGHBYTE_IDX = 14; static const uint8_t Z_HIGHBYTE_IDX = 14;
static const uint8_t Z_HIGHBYTE = 0b00101101; static const uint8_t Z_HIGHBYTE = 0b00101101;
//Register adress to access low byte of temperature sensor /* Register adress to access low byte of temperature sensor */
static const uint8_t TEMP_LOWBYTE = 0b00101110; static const uint8_t TEMP_LOWBYTE = 0b00101110;
//Register adress to access high byte of temperature sensor /* Register adress to access high byte of temperature sensor */
static const uint8_t TEMP_HIGHBYTE = 0b00101111; static const uint8_t TEMP_HIGHBYTE = 0b00101111;
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/

View File

@ -0,0 +1,22 @@
#ifndef MISSION_UTILITY_INITMISSION_H_
#define MISSION_UTILITY_INITMISSION_H_
#include <fsfw/objectmanager/SystemObjectIF.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
namespace initmission {
void printAddObjectError(const char* name, object_id_t objectId) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "InitMission::printAddError: Adding object " << name << " with object ID 0x"
<< std::hex << std::setfill('0') << std::setw(8) << objectId
<< " failed!" << std::dec << std::endl;
#else
sif::printError("InitMission::printAddError: Adding object %s with object ID 0x%08x failed!\n" ,
name, objectId);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
}
#endif /* MISSION_UTILITY_INITMISSION_H_ */

View File

@ -8,14 +8,9 @@
#include <array> #include <array>
#include <cstring> #include <cstring>
bool TestTask::oneShotAction = true;
MutexIF* TestTask::testLock = nullptr;
TestTask::TestTask(object_id_t objectId_): TestTask::TestTask(object_id_t objectId_):
SystemObject(objectId_), testMode(testModes::A) { SystemObject(objectId_), testMode(testModes::A) {
if(testLock == nullptr) {
testLock = MutexFactory::instance()->createMutex();
}
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
} }
@ -24,19 +19,17 @@ TestTask::~TestTask() {
ReturnValue_t TestTask::performOperation(uint8_t operationCode) { ReturnValue_t TestTask::performOperation(uint8_t operationCode) {
ReturnValue_t result = RETURN_OK; ReturnValue_t result = RETURN_OK;
sif::info << "Hallo EIVE!" << std::endl;
testLock ->lockMutex(MutexIF::TimeoutType::WAITING, 20);
if(oneShotAction) { if(oneShotAction) {
// Add code here which should only be run once /* Add code here which should only be run once */
performOneShotAction(); performOneShotAction();
oneShotAction = false; oneShotAction = false;
} }
testLock->unlockMutex();
// Add code here which should only be run once per performOperation /* Add code here which should only be run once per performOperation */
performPeriodicAction(); performPeriodicAction();
// Add code here which should only be run on alternating cycles. /* Add code here which should only be run on alternating cycles. */
if(testMode == testModes::A) { if(testMode == testModes::A) {
performActionA(); performActionA();
testMode = testModes::B; testMode = testModes::B;
@ -49,7 +42,7 @@ ReturnValue_t TestTask::performOperation(uint8_t operationCode) {
} }
ReturnValue_t TestTask::performOneShotAction() { ReturnValue_t TestTask::performOneShotAction() {
// Everything here will only be performed once. /* Everything here will only be performed once. */
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -61,12 +54,12 @@ ReturnValue_t TestTask::performPeriodicAction() {
ReturnValue_t TestTask::performActionA() { ReturnValue_t TestTask::performActionA() {
ReturnValue_t result = RETURN_OK; ReturnValue_t result = RETURN_OK;
// Add periodically executed code here /* Add periodically executed code here */
return result; return result;
} }
ReturnValue_t TestTask::performActionB() { ReturnValue_t TestTask::performActionB() {
ReturnValue_t result = RETURN_OK; ReturnValue_t result = RETURN_OK;
// Add periodically executed code here /* Add periodically executed code here */
return result; return result;
} }

View File

@ -48,8 +48,7 @@ protected:
private: private:
// Actually, to be really thread-safe, a mutex should be used as well // Actually, to be really thread-safe, a mutex should be used as well
// Let's keep it simple for now. // Let's keep it simple for now.
static bool oneShotAction; bool oneShotAction = true;
static MutexIF* testLock;
StorageManagerIF* IPCStore; StorageManagerIF* IPCStore;
}; };

2
tmtc

@ -1 +1 @@
Subproject commit 1d5fe4ebc7165c2a4979c5f9be9cfa0324e366fb Subproject commit 90c45ea0c77f04677322b3c8c9077db841fc3129