Update 3 #20

Closed
muellerr wants to merge 35 commits from mueller/update-3 into develop
76 changed files with 1830 additions and 794 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,15 +4,9 @@
#include <devices/addresses.h>
#include <devices/gpioIds.h>
#include <tmtc/pusIds.h>
#include <devices/powerSwitcherList.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>
#include <fsfwconfig/devices/powerSwitcherList.h>
#include <bsp_q7s/devices/HeaterHandler.h>
#include <mission/core/GenericFactory.h>
#include <mission/devices/PDU1Handler.h>
@ -21,7 +15,6 @@
#include <mission/devices/PCDUHandler.h>
#include <mission/devices/P60DockHandler.h>
#include <mission/devices/Tmp1075Handler.h>
#include <mission/devices/HeaterHandler.h>
#include <mission/devices/SolarArrayDeploymentHandler.h>
#include <mission/devices/devicedefinitions/GomSpacePackets.h>
#include <mission/devices/devicedefinitions/GomspaceDefinitions.h>
@ -34,8 +27,15 @@
#include <linux/gpio/LinuxLibgpioIF.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
#include "LibgpiodTest.h"
#include <linux/boardtest/LibgpiodTest.h>
#endif
void Factory::setStaticFrameworkObjectIds() {
@ -119,37 +119,37 @@ void ObjectFactory::produce(){
new LinuxLibgpioIF(objects::GPIO_IF);
#if TE0720 == 0
/* 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);
heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigHeater0);
/* 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);
heaterGpiosCookie->addGpio(gpioIds::HEATER_1, gpioConfigHeater1);
/* 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);
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);
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);
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);
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);
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);
heaterGpiosCookie->addGpio(gpioIds::HEATER_7, gpioConfigHeater7);
@ -157,10 +157,10 @@ void ObjectFactory::produce(){
pcduSwitches::TCS_BOARD_8V_HEATER_IN);
GpioCookie* solarArrayDeplCookie = new GpioCookie;
GpioConfig_t gpioConfigDeplSA1(std::string("gpiochip7"), 25,
GpiodRegular gpioConfigDeplSA1(std::string("gpiochip7"), 25,
std::string("DeplSA1"), gpio::OUT, 0);
solarArrayDeplCookie->addGpio(gpioIds::DEPLSA1, gpioConfigDeplSA1);
GpioConfig_t gpioConfigDeplSA2(std::string("gpiochip7"), 23,
GpiodRegular gpioConfigDeplSA2(std::string("gpiochip7"), 23,
std::string("DeplSA2"), gpio::OUT, 0);
solarArrayDeplCookie->addGpio(gpioIds::DEPLSA2, gpioConfigDeplSA2);
@ -180,14 +180,14 @@ void ObjectFactory::produce(){
GpioConfig_t gpioConfigMio0(std::string("gpiochip0"), 0,
std::string("MIO0"), gpio::IN, 0);
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);
#elif TE0720 == 1
/* Configuration for MIO0 on TE0720-03-1CFA */
GpioConfig_t gpioConfigForDummyHeater(std::string("gpiochip0"), 0,
std::string("Heater0"), gpio::OUT, 0);
heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigForDummyHeater);
new HeaterHandler(objects::HEATER_HANDLER, objects::GPIO_IF, heaterGpiosCookie, objects::PCDU_HANDLER,
pcduSwitches::TCS_BOARD_8V_HEATER_IN);
new HeaterHandler(objects::HEATER_HANDLER, objects::GPIO_IF, heaterGpiosCookie,
objects::PCDU_HANDLER, pcduSwitches::TCS_BOARD_8V_HEATER_IN);
#endif
}

View File

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

View File

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

View File

@ -13,15 +13,15 @@
int main(void)
{
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 << "."
<< SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl;
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
InitMission::initMission();
initmission::initMission();
for(;;) {
// suspend main thread by sleeping it.
/* Suspend main thread by sleeping it. */
TaskFactory::delayTask(5000);
}
}

View File

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

View File

@ -1,16 +1,19 @@
#include "InitMission.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/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
#include <fsfw/tasks/PeriodicTaskIF.h>
#include <fsfw/tasks/TaskFactory.h>
#include <fsfwconfig/objects/systemObjectList.h>
#include <fsfwconfig/OBSWConfig.h>
#include <fsfwconfig/pollingsequence/PollingSequenceFactory.h>
#include <iostream>
@ -21,7 +24,7 @@ ServiceInterfaceStream sif::error("ERROR");
ObjectManagerIF *objectManager = nullptr;
void InitMission::initMission() {
void initmission::initMission() {
sif::info << "Building global objects.." << std::endl;
/* Instantiate global object manager and also create all objects */
objectManager = new ObjectManager(ObjectFactory::produce);
@ -32,129 +35,131 @@ void InitMission::initMission() {
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 */
PeriodicTaskIF* TmTcDistributor = TaskFactory::instance()->
createPeriodicTask("DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE,
0.100, nullptr);
ReturnValue_t result = TmTcDistributor->addComponent(
PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask(
"DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
ReturnValue_t result = tmTcDistributor->addComponent(
objects::CCSDS_PACKET_DISTRIBUTOR);
if(result != HasReturnvaluesIF::RETURN_OK){
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){
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) {
sif::error << "Object add component failed" << std::endl;
}
/* UDP bridge */
PeriodicTaskIF* UdpBridgeTask = TaskFactory::instance()->createPeriodicTask(
"UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE,
0.2, nullptr);
result = UdpBridgeTask->addComponent(objects::UDP_BRIDGE);
PeriodicTaskIF* udpBridgeTask = factory->createPeriodicTask(
"UDP_UNIX_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
result = udpBridgeTask->addComponent(objects::UDP_BRIDGE);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Unix Bridge failed" << std::endl;
}
PeriodicTaskIF* UdpPollingTask = TaskFactory::instance()->
createPeriodicTask("UDP_POLLING", 80,
PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, nullptr);
result = UdpPollingTask->addComponent(objects::UDP_POLLING_TASK);
PeriodicTaskIF* udpPollingTask = factory->createPeriodicTask(
"UDP_POLLING", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
result = udpPollingTask->addComponent(objects::UDP_POLLING_TASK);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Add component UDP Polling failed" << std::endl;
}
/* PUS Services */
PeriodicTaskIF* PusVerification = TaskFactory::instance()->
createPeriodicTask("PUS_VERIF_1", 40,
PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr);
result = PusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
PeriodicTaskIF* pusVerification = factory->createPeriodicTask(
"PUS_VERIF", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusVerification->addComponent(objects::PUS_SERVICE_1_VERIFICATION);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add component failed" << std::endl;
}
PeriodicTaskIF* PusEvents = TaskFactory::instance()->
createPeriodicTask("PUS_VERIF_1", 60,
PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, nullptr);
result = PusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
PeriodicTaskIF* pusEvents = factory->createPeriodicTask(
"PUS_EVENTS", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusVerification->addComponent(objects::PUS_SERVICE_5_EVENT_REPORTING);
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()->
createPeriodicTask("PUS_HIGH_PRIO", 50,
PeriodicTaskIF::MINIMUM_STACK_SIZE,
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);
PeriodicTaskIF* pusHighPrio = factory->createPeriodicTask(
"PUS_HIGH_PRIO", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.200, missedDeadlineFunc);
result = pusHighPrio->addComponent(objects::PUS_SERVICE_2_DEVICE_ACCESS);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "InitMission::createTasks: Test PST initialization "
<< "failed!" << std::endl;
initmission::printAddObjectError("PUS2", objects::PUS_SERVICE_2_DEVICE_ACCESS);
}
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* SpiTestTask = TaskFactory::instance()->
createPeriodicTask("SPI_TEST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE,
2.0, nullptr);
result = SpiTestTask->addComponent(objects::SPI_TEST);
if(result != HasReturnvaluesIF::RETURN_OK){
sif::error << "Object add SPI test failed" << std::endl;
PeriodicTaskIF* pusMedPrio = factory->createPeriodicTask(
"PUS_HIGH_PRIO", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc);
result = pusMedPrio->addComponent(objects::PUS_SERVICE_8_FUNCTION_MGMT);
if(result != HasReturnvaluesIF::RETURN_OK) {
initmission::printAddObjectError("PUS8", objects::PUS_SERVICE_8_FUNCTION_MGMT);
}
result = pusMedPrio->addComponent(objects::PUS_SERVICE_200_MODE_MGMT);
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);
}
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;
TmTcDistributor->startTask();
UdpBridgeTask->startTask();
UdpPollingTask->startTask();
tmTcDistributor->startTask();
udpBridgeTask->startTask();
udpPollingTask->startTask();
PusVerification->startTask();
PusEvents->startTask();
PusHighPrio->startTask();
PusMedPrio->startTask();
PusLowPrio->startTask();
SpiTestTask->startTask();
pusVerification->startTask();
pusEvents->startTask();
pusHighPrio->startTask();
pusMedPrio->startTask();
pusLowPrio->startTask();
#if OBSW_ADD_TEST_CODE == 1
TestTimeslotTask->startTask();
#endif
testTask->startTask();
#endif /* OBSW_ADD_TEST_CODE == 1 */
sif::info << "Tasks started.." << std::endl;
}

View File

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

View File

@ -1,20 +1,27 @@
#include "ObjectFactory.h"
#include <bsp_rpi/boardtest/SpiTest.h>
#include <fsfw/datapoollocal/LocalDataPoolManager.h>
#include <bsp_rpi/gpio/GPIORPi.h>
#include <objects/systemObjectList.h>
#include <devices/gpioIds.h>
#include <OBSWConfig.h>
#include <tmtc/apid.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 <mission/core/GenericFactory.h>
#include <mission/utility/TmFunnel.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>
#include <mission/core/GenericFactory.h>
#include <mission/utility/TmFunnel.h>
#include <fsfw/tasks/TaskFactory.h>
void Factory::setStaticFrameworkObjectIds() {
PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR;
@ -44,5 +51,23 @@ void ObjectFactory::produce(){
objects::TM_STORE, objects::TC_STORE);
new TcUnixUdpPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE);
new SpiTest(objects::SPI_TEST);
new LinuxLibgpioIF(objects::GPIO_IF);
#if RPI_ADD_SPI_TEST == 1
new SpiTestClass(objects::SPI_TEST);
#endif
#if RPI_LOOPBACK_TEST_GPIO == 1
GpioCookie* gpioCookie = 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(gpioCookie, gpioIdSender, bcmPinSender, "GPIO_LB_SENDER",
gpio::Direction::OUT, 0);
gpio::createRpiGpioConfig(gpioCookie, gpioIdReader, bcmPinReader, "GPIO_LB_READER",
gpio::Direction::IN, 0);
new LibgpiodTest(objects::LIBGPIOD_TEST, objects::GPIO_IF, gpioCookie);
#endif
}

View File

@ -0,0 +1,10 @@
#ifndef BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_
#define BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_
#define RPI_ADD_GPIO_TEST 1
#define RPI_ADD_SPI_TEST 1
#define RPI_LOOPBACK_TEST_GPIO 1
#endif /* BSP_RPI_BOARDCONFIG_RPI_CONFIG_H_ */

View File

@ -1,6 +1,4 @@
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,12 +1,10 @@
#include "InitMission.h"
#include <OBSWVersion.h>
#include <fsfw/tasks/TaskFactory.h>
#include <iostream>
#include <unistd.h>
/**
* @brief This is the main program for the target hardware.
* @return
@ -14,15 +12,15 @@
int main(void)
{
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 << "."
<< SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl;
std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl;
InitMission::initMission();
initmission::initMission();
for(;;) {
// suspend main thread by sleeping it.
/* suspend main thread by sleeping it. */
TaskFactory::delayTask(5000);
}
}

View File

@ -17,6 +17,7 @@ fi
os_fsfw="linux"
tgt_bsp="arm/raspberrypi"
build_generator=""
build_dir="Debug-RPi"
if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles"
# Could be other OS but this works for now.
@ -24,4 +25,5 @@ else
build_generator="Unix Makefiles"
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"
tgt_bsp="arm/raspberrypi"
build_generator=""
build_dir="Release-RPi"
if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles"
# Could be other OS but this works for now.
@ -24,4 +25,5 @@ else
build_generator="Unix Makefiles"
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"
tgt_bsp="arm/raspberrypi"
build_generator=""
build_dir="RelWithDeb-RPi"
if [ "${OS}" = "Windows_NT" ]; then
build_generator="MinGW Makefiles"
# Could be other OS but this works for now.
@ -24,4 +25,5 @@ else
build_generator="Unix Makefiles"
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,9 +61,10 @@ def main():
else:
cmake_target_cfg_cmd = ""
# TODO: Use builddir if given (need to check whether path is relative or absolute)
build_folder = cmake_build_type
if args.builddir is not None:
build_folder = args.builddir
build_path = source_location + os.path.sep + build_folder
if os.path.isdir(build_path):
remove_old_dir = input(f"{build_folder} folder already exists. Remove old directory? [y/n]: ")

2
fsfw

@ -1 +1 @@
Subproject commit 7d0916a44e18c87b00998448333023186b3d85b1
Subproject commit 8b561d073c5a664bae2a901c142fcb2e10faf539

View File

@ -6,20 +6,24 @@
#ifndef 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
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
#define P60DOCK_DEBUG 0
#define PDU1_DEBUG 0
#define PDU2_DEBUG 0
#define ACU_DEBUG 1
#include "OBSWVersion.h"
#define P60DOCK_DEBUG 0
#define PDU1_DEBUG 0
#define PDU2_DEBUG 0
#define ACU_DEBUG 1
#ifdef __cplusplus

View File

@ -15,7 +15,8 @@ namespace gpioIds {
HEATER_7,
DEPLSA1,
DEPLSA2,
Test_ID
TEST_ID_0,
TEST_ID_1
};
}

View File

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

View File

@ -2,4 +2,6 @@ add_subdirectory(gpio)
add_subdirectory(i2c)
add_subdirectory(csp)
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 {
public:
enum TestCases {
READ = 0,
LOOPBACK = 1
};
TestCases testCase;
LibgpiodTest(object_id_t objectId, object_id_t gpioIfobjectId, GpioCookie* gpioCookie);
virtual ~LibgpiodTest();
protected:
virtual ReturnValue_t performPeriodicAction() override;
ReturnValue_t performOneShotAction() override;
ReturnValue_t performPeriodicAction() override;
private:
GpioIF* gpioInterface;

View File

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

View File

@ -0,0 +1,18 @@
#ifndef LINUX_BOARDTEST_SPITESTCLASS_H_
#define LINUX_BOARDTEST_SPITESTCLASS_H_
#include <test/testtasks/TestTask.h>
class SpiTestClass: public TestTask {
public:
SpiTestClass(object_id_t objectId);
ReturnValue_t performPeriodicAction() override;
private:
};
#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_
#define BSP_LINUX_COMIF_COOKIES_CSPCOMIF_H_
#ifndef LINUX_CSP_CSPCOMIF_H_
#define LINUX_CSP_CSPCOMIF_H_
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
#include <fsfw/objectmanager/SystemObject.h>
@ -86,4 +86,4 @@ private:
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_
#define BSP_Q7S_COMIF_COOKIES_CSPCOOKIE_H_
#ifndef LINUX_CSP_CSPCOOKIE_H_
#define LINUX_CSP_CSPCOOKIE_H_
#include <fsfw/devicehandlers/CookieIF.h>
#include <cstdint>
@ -24,4 +24,4 @@ private:
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
)
target_link_libraries(${TARGET_NAME} PUBLIC
gpiod
)

View File

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

View File

@ -1,48 +1,10 @@
#ifndef SAM9G20_COMIF_COOKIES_GPIO_COOKIE_H_
#define SAM9G20_COMIF_COOKIES_GPIO_COOKIE_H_
#ifndef LINUX_GPIO_GPIOCOOKIE_H_
#define LINUX_GPIO_GPIOCOOKIE_H_
#include "GpioIF.h"
#include "gpioDefinitions.h"
#include <fsfw/devicehandlers/CookieIF.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
@ -61,16 +23,17 @@ public:
virtual ~GpioCookie();
void addGpio(gpioId_t gpioId, GpioConfig_t gpioConfig);
ReturnValue_t addGpio(gpioId_t gpioId, GpiodRegular& gpioConfig);
/**
* @brief Get map with registered GPIOs.
*/
GpioMap getGpioMap() const;
private:
/**
* Returns a copy of the internal GPIO map.
*/
GpioMap gpioMap;
GpioMapIter gpioMapIter;
};
#endif
#endif /* LINUX_GPIO_GPIOCOOKIE_H_ */

View File

@ -1,33 +1,35 @@
#ifndef BSP_Q7S_GPIO_GPIOIF_H_
#define BSP_Q7S_GPIO_GPIOIF_H_
#ifndef LINUX_GPIO_GPIOIF_H_
#define LINUX_GPIO_GPIOIF_H_
#include "gpioDefinitions.h"
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <fsfw/devicehandlers/CookieIF.h>
typedef uint16_t gpioId_t;
class GpioCookie;
/**
* @brief This class defines the interface for objects requiring the control
* over GPIOs.
* @author J. Meier
*/
class GpioIF : public HasReturnvaluesIF{
class GpioIF : public HasReturnvaluesIF {
public:
virtual ~GpioIF() {};
/**
* @brief Called by the GPIO using object.
* @brief Called by the GPIO using object.
* @param cookie Cookie specifying informations of the GPIOs required
* 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
* functionality to pull a certain GPIO to high logic level.
*
* @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;
@ -49,4 +51,4 @@ public:
virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
};
#endif /* BSP_Q7S_GPIO_GPIOIF_H_ */
#endif /* LINUX_GPIO_GPIOIF_H_ */

View File

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

View File

@ -1,11 +1,12 @@
#ifndef BSP_Q7S_GPIO_LINUXLIBGPIOIF_H_
#define BSP_Q7S_GPIO_LINUXLIBGPIOIF_H_
#ifndef LINUX_GPIO_LINUXLIBGPIOIF_H_
#define LINUX_GPIO_LINUXLIBGPIOIF_H_
#include <linux/gpio/GpioIF.h>
#include <linux/gpio/GpioCookie.h>
#include <fsfwconfig/returnvalues/classIds.h>
#include <fsfw/objectmanager/SystemObject.h>
class GpioCookie;
/**
* @brief This class implements the GpioIF for a linux based system. The
* implementation is based on the libgpiod lib which requires linux 4.8
@ -16,21 +17,27 @@
class LinuxLibgpioIF : public GpioIF, public SystemObject {
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);
virtual ~LinuxLibgpioIF();
ReturnValue_t initialize(CookieIF * cookie) override;
ReturnValue_t addGpios(GpioCookie* gpioCookie) override;
ReturnValue_t pullHigh(gpioId_t gpioId) override;
ReturnValue_t pullLow(gpioId_t gpioId) override;
ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
private:
/*Holds the information and configuration of all used GPIOs */
/* Holds the information and configuration of all used GPIOs */
GpioMap gpioMap;
GpioMapIter gpioMapIter;
@ -40,8 +47,9 @@ private:
* @param gpioId The GPIO ID of the GPIO to drive.
* @param logiclevel The logic level to set. O or 1.
*/
ReturnValue_t driveGpio(gpioId_t gpioId,
unsigned int logiclevel);
ReturnValue_t driveGpio(gpioId_t gpioId, GpiodRegular* regularGpio, unsigned int logiclevel);
ReturnValue_t configureRegularGpio(gpioId_t gpioId, GpiodRegular* regularGpio);
/**
* @brief This function checks if GPIOs are already registered and whether
@ -52,12 +60,15 @@ private:
*
* @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);
/**
* @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 <fsfw/serviceinterface/ServiceInterface.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <errno.h>
#include <string.h>
#include <linux/utility/Utility.h>
#include <cstring>
I2cComIF::I2cComIF(object_id_t objectId): SystemObject(objectId){
@ -14,191 +15,182 @@ I2cComIF::I2cComIF(object_id_t objectId): SystemObject(objectId){
I2cComIF::~I2cComIF() {}
ReturnValue_t I2cComIF::initializeInterface(CookieIF * cookie) {
ReturnValue_t I2cComIF::initializeInterface(CookieIF* cookie) {
address_t i2cAddress;
std::string deviceFile;
address_t i2cAddress;
std::string deviceFile;
if(cookie == nullptr) {
return NULLPOINTER;
}
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) {
sif::error << "I2cComIF: Invalid I2C Cookie!"
<< std::endl;
return NULLPOINTER;
}
if(cookie == nullptr) {
sif::error << "I2cComIF::initializeInterface: Invalid cookie!" << std::endl;
return NULLPOINTER;
}
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) {
sif::error << "I2cComIF::initializeInterface: Invalid I2C cookie!" << std::endl;
return NULLPOINTER;
}
i2cAddress = i2cCookie->getAddress();
i2cAddress = i2cCookie->getAddress();
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if(i2cDeviceMapIter == i2cDeviceMap.end()) {
size_t maxReplyLen = i2cCookie->getMaxReplyLen();
I2cInstance_t i2cInstance = {std::vector<uint8_t>(maxReplyLen), 0};
std::pair status = i2cDeviceMap.emplace(i2cAddress, i2cInstance);
if (status.second == false) {
sif::error << "I2cComIF::initializeInterface: Failed to insert "
<< "device with address " << i2cAddress << "to I2C device "
<< "map" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
}
else {
sif::error << "I2cComIF: Device with address " << i2cAddress
<< "already in use" << std::endl;
}
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if(i2cDeviceMapIter == i2cDeviceMap.end()) {
size_t maxReplyLen = i2cCookie->getMaxReplyLen();
I2cInstance_t i2cInstance = {std::vector<uint8_t>(maxReplyLen), 0};
auto statusPair = i2cDeviceMap.emplace(i2cAddress, i2cInstance);
if (not statusPair.second) {
sif::error << "I2cComIF::initializeInterface: Failed to insert device with address " <<
i2cAddress << "to I2C device " << "map" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if(i2cDeviceMapIter == i2cDeviceMap.end()) {
sif::error << "Failure" << std::endl;
}
return HasReturnvaluesIF::RETURN_OK;
sif::error << "I2cComIF::initializeInterface: Device with address " << i2cAddress <<
"already in use" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t I2cComIF::sendMessage(CookieIF *cookie,
const uint8_t *sendData, size_t sendLen) {
ReturnValue_t result;
int fd;
std::string deviceFile;
ReturnValue_t result;
int fd;
std::string deviceFile;
if(sendData == nullptr) {
sif::error << "I2cComIF::sendMessage: Send Data is nullptr"
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(sendData == nullptr) {
sif::error << "I2cComIF::sendMessage: Send Data is nullptr"
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(sendLen == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
if(sendLen == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) {
sif::error << "I2cComIF::sendMessasge: Invalid I2C Cookie!"
<< std::endl;
return NULLPOINTER;
}
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) {
sif::error << "I2cComIF::sendMessage: Invalid I2C Cookie!" << std::endl;
return NULLPOINTER;
}
address_t i2cAddress = i2cCookie->getAddress();
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if (i2cDeviceMapIter == i2cDeviceMap.end()) {
sif::error << "I2cComIF::sendMessage: i2cAddress of Cookie not "
<< "registered in i2cDeviceMap" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
address_t i2cAddress = i2cCookie->getAddress();
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if (i2cDeviceMapIter == i2cDeviceMap.end()) {
sif::error << "I2cComIF::sendMessage: i2cAddress of Cookie not "
<< "registered in i2cDeviceMap" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
deviceFile = i2cCookie->getDeviceFile();
result = openDevice(deviceFile, i2cAddress, &fd);
if (result != HasReturnvaluesIF::RETURN_OK){
return result;
}
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);
if (result != HasReturnvaluesIF::RETURN_OK){
return result;
}
if (write(fd, sendData, sendLen) != (int)sendLen) {
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
"device with error code " << errno << ". Error description: "
<< strerror(errno) << std::endl;
close(fd);
return HasReturnvaluesIF::RETURN_FAILED;
}
close(fd);
return HasReturnvaluesIF::RETURN_OK;
if (write(fd, sendData, sendLen) != (int)sendLen) {
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
"device with error code " << errno << ". Error description: "
<< strerror(errno) << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t I2cComIF::getSendSuccess(CookieIF *cookie) {
return HasReturnvaluesIF::RETURN_OK;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF *cookie,
size_t requestLen) {
size_t requestLen) {
ReturnValue_t result;
int fd;
std::string deviceFile;
ReturnValue_t result;
int fd;
std::string deviceFile;
if (requestLen == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
if (requestLen == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) {
sif::error << "I2cComIF::requestReceiveMessage: Invalid I2C Cookie!" << std::endl;
i2cDeviceMapIter->second.replyLen = 0;
return NULLPOINTER;
}
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) {
sif::error << "I2cComIF::requestReceiveMessage: Invalid I2C Cookie!"
<< std::endl;
i2cDeviceMapIter->second.replyLen = 0;
return NULLPOINTER;
}
address_t i2cAddress = i2cCookie->getAddress();
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if (i2cDeviceMapIter == i2cDeviceMap.end()) {
sif::error << "I2cComIF::requestReceiveMessage: i2cAddress of Cookie not "
<< "registered in i2cDeviceMap" << std::endl;
i2cDeviceMapIter->second.replyLen = 0;
return HasReturnvaluesIF::RETURN_FAILED;
}
address_t i2cAddress = i2cCookie->getAddress();
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if (i2cDeviceMapIter == i2cDeviceMap.end()) {
sif::error << "I2cComIF::requestReceiveMessage: i2cAddress of Cookie not "
<< "registered in i2cDeviceMap" << std::endl;
i2cDeviceMapIter->second.replyLen = 0;
return HasReturnvaluesIF::RETURN_FAILED;
}
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);
if (result != HasReturnvaluesIF::RETURN_OK){
i2cDeviceMapIter->second.replyLen = 0;
return result;
}
deviceFile = i2cCookie->getDeviceFile();
result = openDevice(deviceFile, i2cAddress, &fd);
if (result != HasReturnvaluesIF::RETURN_OK){
i2cDeviceMapIter->second.replyLen = 0;
return result;
}
uint8_t* replyBuffer = i2cDeviceMapIter->second.replyBuffer.data();
uint8_t* replyBuffer = i2cDeviceMapIter->second.replyBuffer.data();
if (read(fd, replyBuffer, requestLen) != static_cast<int>(requestLen)) {
sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C "
<< "device failed with error code " << errno <<". Description"
<< " of error: " << strerror(errno) << std::endl;
i2cDeviceMapIter->second.replyLen = 0;
return HasReturnvaluesIF::RETURN_FAILED;
}
if (read(fd, replyBuffer, requestLen) != (int)requestLen) {
sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C "
<< "device failed with error code " << errno <<". Description"
<< " of error: " << strerror(errno) << std::endl;
close(fd);
i2cDeviceMapIter->second.replyLen = 0;
return HasReturnvaluesIF::RETURN_FAILED;
}
i2cDeviceMapIter->second.replyLen = requestLen;
close(fd);
return HasReturnvaluesIF::RETURN_OK;
i2cDeviceMapIter->second.replyLen = requestLen;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t I2cComIF::readReceivedMessage(CookieIF *cookie,
uint8_t **buffer, size_t* size) {
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) {
sif::error << "I2cComIF::readReceivedMessage: Invalid I2C Cookie!"
<< std::endl;
return NULLPOINTER;
}
uint8_t **buffer, size_t* size) {
I2cCookie* i2cCookie = dynamic_cast<I2cCookie*>(cookie);
if(i2cCookie == nullptr) {
sif::error << "I2cComIF::readReceivedMessage: Invalid I2C Cookie!" << std::endl;
return NULLPOINTER;
}
address_t i2cAddress = i2cCookie->getAddress();
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if (i2cDeviceMapIter == i2cDeviceMap.end()) {
sif::error << "I2cComIF::readReceivedMessage: i2cAddress of Cookie not "
<< "found in i2cDeviceMap" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
*buffer = i2cDeviceMapIter->second.replyBuffer.data();
*size = i2cDeviceMapIter->second.replyLen;
address_t i2cAddress = i2cCookie->getAddress();
i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if (i2cDeviceMapIter == i2cDeviceMap.end()) {
sif::error << "I2cComIF::readReceivedMessage: i2cAddress of Cookie not "
<< "found in i2cDeviceMap" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
*buffer = i2cDeviceMapIter->second.replyBuffer.data();
*size = i2cDeviceMapIter->second.replyLen;
return HasReturnvaluesIF::RETURN_OK;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t I2cComIF::openDevice(std::string deviceFile,
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;
}
address_t i2cAddress, int* fileDescriptor) {
if (ioctl(*fileDescriptor, I2C_SLAVE, i2cAddress) < 0) {
sif::error << "I2cComIF: Specifying target device failed with error "
<< "code " << errno << ". Error description "
<< strerror(errno) << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
if (ioctl(*fileDescriptor, I2C_SLAVE, i2cAddress) < 0) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
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_OK;
}

View File

@ -1,5 +1,5 @@
#ifndef BSP_Q7S_COMIF_I2COMIF_H_
#define BSP_Q7S_COMIF_I2COMIF_H_
#ifndef LINUX_I2C_I2COMIF_H_
#define LINUX_I2C_I2COMIF_H_
#include "I2cCookie.h"
#include <fsfw/objectmanager/SystemObject.h>
@ -45,8 +45,8 @@ private:
I2cDeviceMapIter i2cDeviceMapIter;
/**
* @brief This function opens an i2c device and binds the opened file
* to a specific i2c address.
* @brief This function opens an I2C device and binds the opened file
* to a specific I2C address.
* @param deviceFile The name of the device file. E.g. i2c-0
* @param i2cAddress The address of the i2c slave device.
* @param fileDescriptor Pointer to device descriptor.
@ -56,4 +56,4 @@ private:
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_,
std::string deviceFile_) :
i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile(
deviceFile_) {
i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile(deviceFile_) {
}
address_t I2cCookie::getAddress() const {

View File

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

View File

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

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

@ -0,0 +1,294 @@
#include "SpiComIF.h"
#include "spiDefinitions.h"
#include <linux/utility/Utility.h>
#include <linux/spi/SpiCookie.h>
#include <fsfw/ipc/MutexFactory.h>
#include <fsfw/ipc/MutexHelper.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) {
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;
}
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();
}
int retval = ioctl(fileDescriptor, SPI_IOC_WR_MODE, spiSpeed);
if(retval != 0) {
utility::handleIoctlError("SpiComIF::initializeInterface: Setting SPI mode failed!");
}
retval = ioctl(fileDescriptor, SPI_IOC_WR_MAX_SPEED_HZ, spiSpeed);
if(retval != 0) {
utility::handleIoctlError("SpiComIF::initializeInterface: Setting SPI speed failed!");
}
/* 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, true);
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;
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;
}
spiCookie->assignWriteBuffer(sendData);
spiCookie->assignTransferSize(sendLen);
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;
}
bool fullDuplex = spiCookie->isFullDuplex();
int retval = 0;
gpioId_t gpioId = spiCookie->getChipSelectPin();
MutexHelper(spiMutex, timeoutType, timeoutMs);
if(gpioId != gpio::NO_GPIO) {
/* For now, no support for active high given */
gpioComIF->pullLow(gpioId);
}
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 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;
}

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

@ -0,0 +1,60 @@
#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 <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);
};
#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/Service17Test.h>
#include <fsfw/pus/Service1TelecommandVerification.h>
#include <fsfw/pus/Service20ParameterManagement.h>
#include <fsfw/pus/Service3Housekeeping.h>
#include <fsfw/pus/Service2DeviceAccess.h>
#include <fsfw/pus/Service5EventReporting.h>
@ -78,11 +79,13 @@ void ObjectFactory::produceGenericObjects() {
apid::EIVE_OBSW, pus::PUS_SERVICE_9);
new Service17Test(objects::PUS_SERVICE_17_TEST, apid::EIVE_OBSW,
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,
apid::EIVE_OBSW, pus::PUS_SERVICE_200);
/* Test Device Handler */
#if OBSW_ADD_TEST_CODE == 1
new TestTask(objects::TEST_TASK);
new TestTask(objects::TEST_TASK);
#endif
}

View File

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

View File

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

View File

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

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

View File

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

2
tmtc

@ -1 +1 @@
Subproject commit 1d5fe4ebc7165c2a4979c5f9be9cfa0324e366fb
Subproject commit 2b85ece07195ee905c35b35494bc7a86b94335f5