From 3f41adf3404034f18fd52a3115ce00e867cb4446 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" Date: Fri, 12 Feb 2021 21:23:35 +0100 Subject: [PATCH] improved linux libgpiod interface --- bsp_q7s/ObjectFactory.cpp | 18 ++-- bsp_q7s/gpio/GpioIF.h | 9 ++ bsp_q7s/gpio/LinuxLibgpioIF.cpp | 156 ++++++++++++++++++++---------- bsp_q7s/gpio/LinuxLibgpioIF.h | 12 ++- bsp_q7s/gpio/cookies/GpioCookie.h | 14 ++- mission/devices/HeaterHandler.cpp | 20 +++- 6 files changed, 155 insertions(+), 74 deletions(-) diff --git a/bsp_q7s/ObjectFactory.cpp b/bsp_q7s/ObjectFactory.cpp index 59c8c817..37692eb6 100644 --- a/bsp_q7s/ObjectFactory.cpp +++ b/bsp_q7s/ObjectFactory.cpp @@ -101,42 +101,42 @@ void ObjectFactory::produce(){ #if TE0720 == 1 // Configuration for MIO0 on TE0720-03-1CFA GpioConfig_t gpioConfigForDummyHeater(std::string("gpiochip0"), 0, - std::string("Heater0"), Gpio::OUT); + std::string("Heater0"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_0, gpioConfigForDummyHeater); #else /* Pin H2-11 on stack connector */ GpioConfig_t gpioConfigHeater0(std::string("gpiochip7"), 18, - std::string("Heater0"), Gpio::OUT); + std::string("Heater0"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_0, gpioConfigHeater0); /* Pin H2-12 on stack connector */ GpioConfig_t gpioConfigHeater1(std::string("gpiochip7"), 14, - std::string("Heater1"), Gpio::OUT); + std::string("Heater1"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_1, gpioConfigHeater1); /* Pin H2-13 on stack connector */ GpioConfig_t gpioConfigHeater2(std::string("gpiochip7"), 20, - std::string("Heater2"), Gpio::OUT); + std::string("Heater2"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_2, gpioConfigHeater2); GpioConfig_t gpioConfigHeater3(std::string("gpiochip7"), 16, - std::string("Heater3"), Gpio::OUT); + std::string("Heater3"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_3, gpioConfigHeater3); GpioConfig_t gpioConfigHeater4(std::string("gpiochip7"), 24, - std::string("Heater4"), Gpio::OUT); + std::string("Heater4"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_4, gpioConfigHeater4); GpioConfig_t gpioConfigHeater5(std::string("gpiochip7"), 26, - std::string("Heater5"), Gpio::OUT); + std::string("Heater5"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_5, gpioConfigHeater5); GpioConfig_t gpioConfigHeater6(std::string("gpiochip7"), 22, - std::string("Heater6"), Gpio::OUT); + std::string("Heater6"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_6, gpioConfigHeater6); GpioConfig_t gpioConfigHeater7(std::string("gpiochip7"), 28, - std::string("Heater7"), Gpio::OUT); + std::string("Heater7"), Gpio::OUT, 0); gpioCookie->addGpio(gpioIds::HEATER_7, gpioConfigHeater7); #endif diff --git a/bsp_q7s/gpio/GpioIF.h b/bsp_q7s/gpio/GpioIF.h index cf688db8..d1f02dd8 100644 --- a/bsp_q7s/gpio/GpioIF.h +++ b/bsp_q7s/gpio/GpioIF.h @@ -38,6 +38,15 @@ public: * @param gpioId A unique number which specifies the GPIO to drive. */ virtual ReturnValue_t pullLow(gpioId_t gpioId) = 0; + + /** + * @brief This function requires a child to implement the functionaliy to read the state of + * an ouput or input gpio. + * + * @param gpioId A unique number which specifies the GPIO to read. + * @param gpioState State of GPIO will be written to this pointer. + */ + virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0; }; #endif /* BSP_Q7S_GPIO_GPIOIF_H_ */ diff --git a/bsp_q7s/gpio/LinuxLibgpioIF.cpp b/bsp_q7s/gpio/LinuxLibgpioIF.cpp index 7e98abd6..415ce3d0 100644 --- a/bsp_q7s/gpio/LinuxLibgpioIF.cpp +++ b/bsp_q7s/gpio/LinuxLibgpioIF.cpp @@ -14,7 +14,6 @@ LinuxLibgpioIF::~LinuxLibgpioIF() { ReturnValue_t LinuxLibgpioIF::initialize(CookieIF * cookie){ ReturnValue_t result; GpioMap mapToAdd; - GpioMapIter mapToAddIter; if(cookie == nullptr) { sif::error << "LinuxLibgpioIF::initialize: Invalid cookie" << std::endl; @@ -30,14 +29,86 @@ ReturnValue_t LinuxLibgpioIF::initialize(CookieIF * cookie){ mapToAdd = gpioCookie->getGpioMap(); result = checkForConflicts(mapToAdd); - if (result != HasReturnvaluesIF::RETURN_OK){ + if (result != RETURN_OK){ return result; } + result = configureGpios(mapToAdd); + if (result != RETURN_OK) { + return RETURN_FAILED; + } + /* Register new GPIOs in gpioMap*/ gpioMap.insert(mapToAdd.begin(), mapToAdd.end()); - return HasReturnvaluesIF::RETURN_OK; + return RETURN_OK; +} + +ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap mapToAdd) { + GpioMapIter mapToAddIter; + std::string chipname; + unsigned int lineNum; + struct gpiod_chip *chip; + Gpio::Direction direction; + std::string consumer; + struct gpiod_line *lineHandle; + int result; + + for (mapToAddIter = mapToAdd.begin(); mapToAddIter != mapToAdd.end(); mapToAddIter++) { + + chipname = gpioMapIter->second.chipname; + chip = gpiod_chip_open_by_name(chipname.c_str()); + if (!chip) { + sif::error << "LinuxLibgpioIF::configureGpios: Failed to open chip " + << chipname << ". Gpio ID: " << gpioMapIter->first << std::endl; + return RETURN_FAILED; + } + + lineNum = gpioMapIter->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 = gpioMapIter->second.direction; + consumer = gpioMapIter->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(), + gpioMapIter->second.initValue); + if (result < 0) { + sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " + << lineNum << " from GPIO instance with ID: " << gpioMapIter->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: " << gpioMapIter->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. + */ + gpioMapIter->second.lineHandle = lineHandle; + } + return RETURN_OK; } ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId){ @@ -50,60 +121,39 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId){ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, unsigned int logiclevel) { + int result; + struct gpiod_line *lineHandle; + GpioMapIter gpioMapIter = gpioMap.find(gpioId); - std::string chipname; - unsigned int lineNum; - struct gpiod_chip *chip; - struct gpiod_line *line; - int result; - Gpio::Direction direction; - std::string consumer; + if (gpioMapIter == gpioMap.end()){ + sif::debug << "LinuxLibgpioIF::driveGpio: Unknown gpio id " << gpioId << std::endl; + return RETURN_FAILED; + } - /* Verify if GPIO has been configured as output */ - direction = gpioMapIter->second.direction; - if (direction != Gpio::OUT) { - sif::error << "LinuxLibgpioIF::driveGpio: GPIO with ID " << gpioId - << "not configured as output" << std::endl; - return CONFIGURATION_FAILURE; - } - - chipname = gpioMapIter->second.chipname; - chip = gpiod_chip_open_by_name(chipname.c_str()); - if (!chip) { - sif::error << "LinuxLibgpioIF::driveGpio: Failed to open chip " - << chipname << ". Gpio ID: " << gpioId << std::endl; - return OPEN_CHIP_FAILURE; - } - - lineNum = gpioMapIter->second.lineNum; - line = gpiod_chip_get_line(chip, lineNum); - if (!line) { - sif::error << "LinuxLibgpioIF::driveGpio: Failed to open line. Gpio ID " - << gpioId << std::endl; - gpiod_chip_close(chip); - return OPEN_LINE_FAILURE; - } - - consumer = gpioMapIter->second.consumer; - result = gpiod_line_request_output(line, consumer.c_str(), 0); - if (result < 0) { - sif::error << "LinuxLibgpioIF::driveGpio: Failed to request line " - << line << " from GPIO instance with ID: " << gpioId - << std::endl; - gpiod_line_release(line); - return REQUEST_LINE_FAILURE; - } - - result = gpiod_line_set_value(line, logiclevel); + lineHandle = gpioMapIter->second.lineHandle; + result = gpiod_line_set_value(lineHandle, logiclevel); if (result < 0) { sif::error << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " - << gpioId << "to low" << std::endl; - gpiod_line_release(line); - return PULLING_HIGH_FAILURE; + << gpioId << "to logic level" << logiclevel << std::endl; + return DRIVE_GPIO_FAILURE; } - gpiod_line_release(line); - return HasReturnvaluesIF::RETURN_OK; + return RETURN_OK; +} + +ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) { + struct gpiod_line *lineHandle; + + GpioMapIter gpioMapIter = gpioMap.find(gpioId); + if (gpioMapIter == gpioMap.end()){ + sif::debug << "LinuxLibgpioIF::readGpio: Unknown gpio id " << gpioId << std::endl; + return RETURN_FAILED; + } + + lineHandle = gpioMapIter->second.lineHandle; + *gpioState = gpiod_line_get_value(lineHandle); + + return RETURN_OK; } ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap mapToAdd){ @@ -118,12 +168,12 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap mapToAdd){ if (mapToAddIter->second.direction != gpioMapIter->second.direction){ sif::error << "LinuxLibgpioIF::checkForConflicts: Detected conflict " << "for GPIO " << mapToAddIter->first << std::endl; - return HasReturnvaluesIF::RETURN_OK; + return RETURN_OK; } /* Remove element from map to add because a entry for this GPIO * already exists */ mapToAdd.erase(mapToAddIter); } } - return HasReturnvaluesIF::RETURN_OK; + return RETURN_OK; } diff --git a/bsp_q7s/gpio/LinuxLibgpioIF.h b/bsp_q7s/gpio/LinuxLibgpioIF.h index 0eaf8c48..ef2bf8b5 100644 --- a/bsp_q7s/gpio/LinuxLibgpioIF.h +++ b/bsp_q7s/gpio/LinuxLibgpioIF.h @@ -18,11 +18,7 @@ public: static const uint8_t INTERFACE_ID = CLASS_ID::LINUX_LIBGPIO_IF; - static const ReturnValue_t CONFIGURATION_FAILURE = MAKE_RETURN_CODE(0x1); - static const ReturnValue_t OPEN_CHIP_FAILURE = MAKE_RETURN_CODE(0x2); - static const ReturnValue_t OPEN_LINE_FAILURE = MAKE_RETURN_CODE(0x3); - static const ReturnValue_t REQUEST_LINE_FAILURE = MAKE_RETURN_CODE(0x4); - static const ReturnValue_t PULLING_HIGH_FAILURE = MAKE_RETURN_CODE(0x5); + static const ReturnValue_t DRIVE_GPIO_FAILURE = MAKE_RETURN_CODE(0x2); LinuxLibgpioIF(object_id_t objectId); virtual ~LinuxLibgpioIF(); @@ -30,6 +26,7 @@ public: ReturnValue_t initialize(CookieIF * cookie) 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: @@ -56,6 +53,11 @@ private: * @return RETURN_OK if successful, otherwise RETURN_FAILED */ ReturnValue_t checkForConflicts(GpioMap mapToAdd); + + /** + * @brief Performs the initial configuration of all GPIOs specified in the GpioMap mapToAdd. + */ + ReturnValue_t configureGpios(GpioMap mapToAdd); }; #endif /* BSP_Q7S_GPIO_LINUXLIBGPIOIF_H_ */ diff --git a/bsp_q7s/gpio/cookies/GpioCookie.h b/bsp_q7s/gpio/cookies/GpioCookie.h index 16ba3b8c..517434c1 100644 --- a/bsp_q7s/gpio/cookies/GpioCookie.h +++ b/bsp_q7s/gpio/cookies/GpioCookie.h @@ -21,19 +21,25 @@ namespace Gpio { * 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 currently accessing the GPIO. - * @param direction Specifies whether the GPIO should be used as in- or output. + * @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_) : + Gpio::Direction direction_, int initValue_) : chipname(chipname_), lineNum(lineNum_), consumer(consumer_), direction( - direction_) { + direction_), initValue(initValue_) { } std::string chipname; int lineNum; std::string consumer; Gpio::Direction direction; + int initValue; + struct gpiod_line *lineHandle; } GpioConfig_t; using GpioMap = std::unordered_map; using GpioMapIter = GpioMap::iterator; diff --git a/mission/devices/HeaterHandler.cpp b/mission/devices/HeaterHandler.cpp index aedb4b03..0545a9e1 100644 --- a/mission/devices/HeaterHandler.cpp +++ b/mission/devices/HeaterHandler.cpp @@ -213,15 +213,22 @@ void HeaterHandler::handleSwitchOnCommand(HeaterMapIter heaterMapIter) { if (!checkSwitchState(switchNr)) { gpioId_t gpioId = getGpioIdFromSwitchNr(switchNr); result = gpioInterface->pullHigh(gpioId); - result = RETURN_OK; if (result != RETURN_OK) { - sif::error << "HeaterHandler::handleSwitchOffCommand: Failed to pull gpio with id" + sif::error << "HeaterHandler::handleSwitchOnCommand: Failed to pull gpio with id" << gpioId << "high" << std::endl; triggerEvent(GPIO_PULL_HIGH_FAILED, result); } else { switchStates[switchNr] = ON; } + int gpioState; + result = gpioInterface->readGpio(gpioId, &gpioState); + if (result != RETURN_OK) { + sif::debug << "HeaterHandler::handleSwitchOnCommand: Failed to read gpio" + << std::endl; + } + sif::debug << "HeaterHandler::handleSwitchOnCommand: GPIO state: " << gpioState + << std::endl; } else { triggerEvent(SWITCH_ALREADY_ON, switchNr); @@ -264,7 +271,6 @@ void HeaterHandler::handleSwitchOffCommand(HeaterMapIter heaterMapIter) { if (checkSwitchState(switchNr)) { gpioId_t gpioId = getGpioIdFromSwitchNr(switchNr); result = gpioInterface->pullLow(gpioId); - result = RETURN_OK; if (result != RETURN_OK) { sif::error << "HeaterHandler::handleSwitchOffCommand: Failed to pull gpio with id" << gpioId << " low" << std::endl; @@ -277,6 +283,14 @@ void HeaterHandler::handleSwitchOffCommand(HeaterMapIter heaterMapIter) { mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF); } } + int gpioState; + result = gpioInterface->readGpio(gpioId, &gpioState); + if (result != RETURN_OK) { + sif::debug << "HeaterHandler::handleSwitchOnCommand: Failed to read gpio" + << std::endl; + } + sif::debug << "HeaterHandler::handleSwitchOnCommand: GPIO state: " << gpioState + << std::endl; } else { sif::info << "HeaterHandler::handleSwitchOffCommand: Switch already off" << std::endl;