diff --git a/README.md b/README.md index e1b0e4b4289c9bcf13f943907959ac00433e51f1..bff81f4dc7c1d3348c55ae22e03fffdd1f53f0d2 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,32 @@ # gpio-manager #### 介绍 - - gpio-manager用于以DBus的形式管理GPIO,包括输出控制,输入监控(DBus signal和执行GPIO服务单元)以及简单的上下电控制。软件支持配置延时防抖,上下电控制支持配置电平或者脉冲的方式。 +``` + gpio-manager用于以DBus的形式管理GPIO,包括输出控制,输入监控(DBus signal和执 +行GPIO服务单元)以及简单的上下电控制。软件支持配置延时防抖,上下电控制支持配置电平或 +者脉冲的方式。 +``` #### 使用说明 - - 通过配置gpio_defs.json文件,软件读取配置后将根据配置生成对应的DBus路径,配置示例如下: +``` + 通过配置gpio_defs.json文件,软件读取配置后将根据配置生成对应的DBus路径,配置示 +例如下: +``` ``` { "power_config": { "power_good_in": "TEST_PWRGD", "power_up_outs": [ - "TEST_BMC_PWRBTN" + {"Name": "POWER_BOTH", "Power": "both", "LevelTriggered": flase}, + {"Name": "POWER_ON", "Power": "on", "LevelTriggered": flase}, + {"Name": "POWER_OFF", "Power": "off", "LevelTriggered": flase} ], "reset_outs": [ ] }, "gpio_monitor": { "TEST_PWRGD": { - "Monitor": "BOTH", + "Monitor": "both", "Target": "power-good-event.service" } }, @@ -37,7 +44,6 @@ "Line": 1, "Direction": "out", "Polarity": false, - "LevelTriggered": true, "DelayTime": 1000 }, { @@ -45,26 +51,41 @@ "Chip": 0, "Line": 2, "Direction": "in", - "Polarity": false, - "LevelTriggered": true + "Polarity": false }, { "Name": "TEST_PWRGD", - "Chip": 2, - "Line": 10, + "Chip": 0, + "Line": 3, "Direction": "in", - "Polarity": false, - "LevelTriggered": true + "Polarity": false }, { - "Name": "TEST_BMC_PWRBTN", - "Chip": 4, + "Name": "POWER_BOTH", + "Chip": 1, "Line": 1, "Direction": "out", "Polarity": false, - "LevelTriggered": false, "DelayTime": 1000, - "DefaultValue": true + "DefaultValue": 1 + }, + { + "Name": "POWER_OFF", + "Chip": 1, + "Line": 2, + "Direction": "out", + "Polarity": false, + "DelayTime": 1000, + "DefaultValue": 1 + }, + { + "Name": "POWER_ON", + "Chip": 1, + "Line": 3, + "Direction": "out", + "Polarity": false, + "DelayTime": 1000, + "DefaultValue": 0 } ...... ...... @@ -72,14 +93,23 @@ ] } ``` - 其中Name、Chip、Line、Direction、Polarity、LevelTriggered为必选,DelayTime和DefaultValue为可选字段,对应键含义如下: +``` + 其中Name、Chip、Line、Direction、Polarity为必选,DelayTime和DefaultValue为可 +选字段,对应键含义如下: Name:GPIO名称(tring) Chip:对应的gpiochip编号(int) Line:对应line编号(int) Direction:配置GPIO的方向(string,"out"/"in") Polarity:配置对应GPIO的极性(bool) - LevelTriggered:输出模式下,电平触发(true)脉冲(fasle) DelayTime:配置的延时时间(uint64_t) DefaultValue:GPIO生成的默认值(bool) - power_config用于配置上下电的GPIO包括POWER GOOD输入GPIO以及控制的输出GPIO;gpio_monitor用于配置需要监控的输入GPIO,根据配置方式:由低到高(HIGH)由高到低(LOW)以及同时监控(BOTH),执行对应的服务;gpio_manager暴露到DBus的GPIO;gpio_definitions用于定义GPIO信息的集合。 + power_config用于配置上下电的GPIO包括POWER GOOD输入GPIO以及控制的输出GPIO;其中 +power_up_outs中的Name用于匹配定义的GPIO名字,Power用于指定此GPIO用于开机(on)、关 +机(off)或者都支持(both),LevelTriggered用于配置触发方式:电平触发(true)脉冲 +(false); + gpio_monitor用于配置需要监控的输入GPIO,根据配置方式:由低到高(high)由高到低 +(low)以及同时监控(both),执行对应的服务; + gpio_manager暴露到DBus的GPIO;gpio_definitions用于定义GPIO信息的集合。 +``` + diff --git a/include/Gpio.hpp b/include/Gpio.hpp index 243ce033950e2f549bb23ce112be474fcf367fb1..10e5b33fa932d31b97e6d736e8d444caa8a64508 100644 --- a/include/Gpio.hpp +++ b/include/Gpio.hpp @@ -18,6 +18,8 @@ #include +#include +#include #include /** @@ -30,21 +32,31 @@ struct GpioInfo int line; uint64_t delayTime; bool polarity; - bool levelTriggered; bool direction; bool defaultValue; std::string name; }; /** - * @struct PowerManger + * @struct GpioManger * @brief Structure of GPIO management information. */ struct GpioManager { GpioInfo manager; + uint8_t monitor; std::string target; - std::string monitor; +}; + +/** + * @struct PowerControl + * @brief Structure of power control information. + */ +struct PowerControlInfo +{ + GpioInfo control; + bool isLevelTriggered; + uint8_t controlMethod; }; /** @@ -54,7 +66,7 @@ struct GpioManager struct PowerManger { GpioManager pgood; - std::vector outs; + std::vector outs; std::vector resetOuts; }; @@ -111,7 +123,6 @@ class Gpio gpiod::line line; private: - /** @brief Basic information of gpio. */ GpioInfo gpioInfo; }; @@ -123,4 +134,4 @@ class Gpio * * @return bool - Check whether the execution is successful. */ -bool loadGpioInfoFromJson(Gpios& gpios); +bool loadGpioInfoFromJson(Gpios& rawGpioData); diff --git a/include/GpioDbusManager.hpp b/include/GpioDbusManager.hpp index fe3757fceb9cf3cfa275a62cf4b3e940f703aa0a..5cb85d1df8e5efda6b806757fd5b4efeb5895257 100644 --- a/include/GpioDbusManager.hpp +++ b/include/GpioDbusManager.hpp @@ -22,6 +22,9 @@ #include #include +#include +#include + /** * @class GpioDbusManager * @brief The class managed by gpio. @@ -48,8 +51,8 @@ class GpioDbusManager : public Gpio GpioDbusManager(const GpioInfo& gpioInfo, std::shared_ptr interface, const std::string& property, boost::asio::io_context& io, - const std::pair& target = - std::pair{}); + const std::pair& target = + std::pair{}); /** @brief The destructor of GpioDbusManager. */ ~GpioDbusManager(); @@ -73,7 +76,7 @@ class GpioDbusManager : public Gpio boost::asio::posix::stream_descriptor fd; /** @brief Target state and target system unit. */ - const std::pair target; + const std::pair target; }; /** diff --git a/include/PowerControl.hpp b/include/PowerControl.hpp index 79e2ab9f28eb745724e127ebe41455fe155d182f..cd9c305ec89fa5d79802e7bdcedb2cfd0ca59676 100644 --- a/include/PowerControl.hpp +++ b/include/PowerControl.hpp @@ -34,19 +34,23 @@ class PowerControl : public GpioDbusManager /** * @brief The constructor for PowerControl. * - * @param[in] powerGoodIn - Power good information. - * @param[in] controls - Power control related Gpio information. + * @param[in] powers - Power management information. * @param[in] io - Io context. * @param[in] interface - Dbus interface. + * */ - PowerControl(std::vector>& controls, - const GpioInfo& powerGoodIn, + PowerControl(const PowerManger& powers, std::shared_ptr interface, - boost::asio::io_context& io, - const std::pair& target = - std::pair{}); + boost::asio::io_context& io); private: + struct ControlSet + { + bool isLevelTriggered; + uint8_t controlMethod; + std::unique_ptr control; + }; + /** @brief On/off control. */ - std::vector> gpios; + std::vector> gpios; }; diff --git a/meson.build b/meson.build index ff91f8504760cd6bac61325228f9823881ae4df0..371408cdf7f91084cdcfbf4050721bfcfb85f644 100644 --- a/meson.build +++ b/meson.build @@ -19,6 +19,7 @@ conf.set_quoted('JSON_DIRECTION', 'Direction') conf.set_quoted('JSON_DEFAULTVALUE', 'DefaultValue') conf.set_quoted('JSON_TARGET', 'Target') conf.set_quoted('JSON_MONITOR', 'Monitor') +conf.set_quoted('JSON_POWER', 'Power') conf.set_quoted('POWER_CONFIG', 'power_config') conf.set_quoted('POWER_UP_OUTS', 'power_up_outs') conf.set_quoted('POWER_GOOD_IN', 'power_good_in') @@ -35,9 +36,6 @@ conf.set_quoted('POWER_STATE', 'state') conf.set_quoted('GET_POWER_STATE', 'getPowerState') conf.set_quoted('SET_POWER_STATE', 'setPowerState') conf.set_quoted('OUT', 'out') -conf.set_quoted('HIGH', 'HIGH') -conf.set_quoted('LOW', 'LOW') -conf.set_quoted('BOTH', 'BOTH') conf.set_quoted('GPIO_MANAGER_SERVICE', 'xyz.openbmc_project.Gpio.Manager') conf.set_quoted('GPIO_MANAGER_PATH', '/xyz/openbmc_project/gpio/') @@ -49,6 +47,21 @@ conf.set_quoted('SYSTEMD_SERVICE', 'org.freedesktop.systemd1') conf.set_quoted('SYSTEMD_PATH', '/org/freedesktop/systemd1') conf.set_quoted('SYSTEMD_INTERFACE', 'org.freedesktop.systemd1.Manager') +conf.set('LOW', 0) +conf.set_quoted('LOW_STR', 'low') + +conf.set('HIGH', 1) +conf.set_quoted('HIGH_STR', 'high') + +conf.set_quoted('BOTH_STR', 'both') +conf.set('BOTH', 2) + +conf.set('POWER_OFF', 0) +conf.set_quoted('POWER_OFF_STR', 'off') + +conf.set_quoted('POWER_ON_STR', 'on') +conf.set('POWER_ON', 1) + configure_file(output: 'config.h', configuration: conf) systemd = dependency('systemd') diff --git a/src/Gpio.cpp b/src/Gpio.cpp index f92c715c4fd42cc318b4b220af9013d217214c3d..19a82c6c291235ef9f25e760a6e925390e5b3804 100644 --- a/src/Gpio.cpp +++ b/src/Gpio.cpp @@ -41,6 +41,7 @@ Gpio::Gpio(const GpioInfo& gpioInfo) : catch (...) { std::cerr << gpioInfo.name << " Init Error." << std::endl; + return; } } @@ -77,33 +78,74 @@ static bool loadGpioData(const nlohmann::json& defs, if (it != defs.end()) { - dataIn = {it->at(JSON_CHIP), - it->at(JSON_LINE), - it->contains(JSON_DELAYTIME) - ? it->at(JSON_DELAYTIME).get() - : 0, - it->at(JSON_POLARITY), - it->at(JSON_LEVELTRIGGERED), - std::string(it->at(JSON_DIRECTION)) == OUT, - it->contains(JSON_DEFAULTVALUE) - ? it->at(JSON_DEFAULTVALUE).get() - : 0, - it->at(JSON_NAME)}; + dataIn = { + it->at(JSON_CHIP), + it->at(JSON_LINE), + it->contains(JSON_DELAYTIME) + ? it->at(JSON_DELAYTIME).get() + : static_cast(0), + it->at(JSON_POLARITY), + std::string(it->at(JSON_DIRECTION)) == OUT, + it->contains(JSON_DEFAULTVALUE) + ? static_cast(it->at(JSON_DEFAULTVALUE).get()) + : false, + it->at(JSON_NAME)}; } } catch (const nlohmann::json::exception& e) { - std::cerr << "JSON error:" << e.what() << std::endl; + std::cerr << gpioName << " json error:" << e.what() << std::endl; + + return false; + } + return true; +} + +static bool loadGpioManagerData(const nlohmann::json& defs, + const nlohmann::json& monitor, + const std::string& key, GpioManager& manager) +{ + if (!loadGpioData(defs, key, manager.manager)) + { + std::cerr << key << " data format error." << std::endl; + return false; } + + if (monitor.contains(key)) + { + try + { + const std::string& monitorStr = monitor[key].at(JSON_MONITOR); + + if (monitorStr != BOTH_STR && monitorStr != HIGH_STR && + monitorStr != LOW_STR) + { + return false; + } + + manager.monitor = monitorStr == BOTH_STR + ? BOTH + : monitorStr == HIGH_STR ? HIGH : LOW; + + manager.target = monitor[key].at(JSON_TARGET); + } + catch (const nlohmann::json::exception& e) + { + std::cerr << "JSON data format error: " << e.what() << std::endl; + + return false; + } + } return true; } -bool loadGpioInfoFromJson(Gpios& data) +bool loadGpioInfoFromJson(Gpios& rawGpioData) { if (!std::filesystem::exists(JSON_FILEPATH)) { std::cerr << JSON_FILEPATH << " not found." << std::endl; + return false; } @@ -112,6 +154,7 @@ bool loadGpioInfoFromJson(Gpios& data) if (!inputStream.good()) { std::cerr << JSON_FILEPATH << " can not open." << std::endl; + return false; } @@ -125,6 +168,7 @@ bool loadGpioInfoFromJson(Gpios& data) { std::cerr << "Parse json error:" << e.what() << std::endl; inputStream.close(); + return false; } inputStream.close(); @@ -132,42 +176,54 @@ bool loadGpioInfoFromJson(Gpios& data) const auto& defs = loadJson[GPIO_DEFINITIONS]; const auto& monitors = loadJson[GPIO_MONITOR]; const std::string& pgood = loadJson[POWER_CONFIG][POWER_GOOD_IN]; + GpioManager tempGpioManager; // Process JSON content for Power Good. - if (!loadGpioData(defs, pgood, data.power.pgood.manager)) + if (loadGpioManagerData(defs, monitors, pgood, tempGpioManager)) { - std::cerr << pgood << " failed to obtain." << std::endl; + rawGpioData.power.pgood = std::move(tempGpioManager); } - if (monitors.contains(pgood)) + + // Process JSON content for Power Up Outs. + const auto& powerUpOuts = loadJson[POWER_CONFIG][POWER_UP_OUTS]; + + for (const nlohmann::json& out : powerUpOuts) { try { - data.power.pgood.target = monitors[pgood].at(JSON_TARGET); - data.power.pgood.monitor = monitors[pgood].at(JSON_MONITOR); - } - catch (const nlohmann::json::exception& e) - { - std::cerr << "Data acquisition failed. " << e.what() << std::endl; - } - } + PowerControlInfo rawPowerData; + const std::string& powerMethod = out.at(JSON_POWER); - GpioInfo tempGpio; - const auto& powerUpOuts = loadJson[POWER_CONFIG][POWER_UP_OUTS]; + if (powerMethod != BOTH_STR && powerMethod != POWER_OFF_STR && + powerMethod != POWER_ON_STR) + { + continue; + } - // Process JSON content for Power Up Outs. - for (const auto& out : powerUpOuts) - { - if (!loadGpioData(defs, out, tempGpio)) + rawPowerData.controlMethod = + powerMethod == BOTH_STR + ? BOTH + : powerMethod == POWER_OFF_STR ? POWER_OFF : POWER_ON; + + rawPowerData.isLevelTriggered = out.at(JSON_LEVELTRIGGERED); + + if (!loadGpioData(defs, out.at(JSON_NAME), rawPowerData.control)) + { + continue; + } + + rawGpioData.power.outs.emplace_back(rawPowerData); + } + catch (...) { - continue; + std::cerr << "Power control data format error." << std::endl; } - - data.power.outs.emplace_back(tempGpio); } + // Process JSON content for Power Reset Outs. + GpioInfo tempGpio; const auto& powerResetOuts = loadJson[POWER_CONFIG][POWER_RESET_OUTS]; - // Process JSON content for Power Reset Outs. for (const auto& reset : powerResetOuts) { if (!loadGpioData(defs, reset, tempGpio)) @@ -175,36 +231,20 @@ bool loadGpioInfoFromJson(Gpios& data) continue; } - data.power.resetOuts.emplace_back(tempGpio); + rawGpioData.power.resetOuts.emplace_back(tempGpio); } + // Process JSON content for GPIO Manager. const auto& managers = loadJson[GPIO_MANAGER]; - // Process JSON content for GPIO Manager. for (const std::string& manager : managers) { - GpioManager gpioManager; - - if (!loadGpioData(defs, manager, gpioManager.manager)) + if (!loadGpioManagerData(defs, monitors, manager, tempGpioManager)) { continue; } - if (monitors.contains(manager)) - { - try - { - gpioManager.target = monitors[manager].at(JSON_TARGET); - gpioManager.monitor = monitors[manager].at(JSON_MONITOR); - } - catch (const nlohmann::json::exception& e) - { - std::cerr << "Data acquisition failed. " << e.what() - << std::endl; - } - } - - data.managers.emplace_back(gpioManager); + rawGpioData.managers.emplace_back(std::move(tempGpioManager)); } return true; diff --git a/src/GpioDbusManager.cpp b/src/GpioDbusManager.cpp index 02a1ecd8139fca8c12ce6165abec38424ad7a767..6e59854b28d181f232060896a922c479d7c9be09 100644 --- a/src/GpioDbusManager.cpp +++ b/src/GpioDbusManager.cpp @@ -18,8 +18,6 @@ #include "GpioDbusManager.hpp" -#include "Gpio.hpp" - #include #include @@ -29,19 +27,21 @@ GpioDbusManager::GpioDbusManager( const GpioInfo& gpioInfo, std::shared_ptr interface, const std::string& property, boost::asio::io_context& io, - const std::pair& target) : + const std::pair& target) : Gpio(gpioInfo), currentState(Gpio::getCurrentGpioValue()), interface(interface), property(property), fd(io), target(target) { try { - if (!gpioInfo.direction) + if (!Gpio::getGpioInfo().direction) { int gpioFd = line.event_get_fd(); + if (gpioFd < 0) { std::cerr << "Get Fd Error." << std::endl; + return; } @@ -70,6 +70,7 @@ GpioDbusManager::GpioDbusManager( catch (...) { std::cerr << "GpioDbusManager Init Error." << std::endl; + return; } } @@ -86,6 +87,7 @@ void GpioDbusManager::gpioEventLoop() if (ec == boost::system::errc::bad_file_descriptor) { std::cerr << "Fd error." << std::endl; + return; } @@ -100,20 +102,14 @@ void GpioDbusManager::gpioEventLoop() if (currentState == Gpio::getCurrentGpioValue()) { gpioEventLoop(); + return; } - if (target != std::pair{}) + if (target != std::pair{}) { - if (target.first == HIGH && !currentState) - { - startUnit(target.second); - } - else if (target.first == LOW && currentState) - { - startUnit(target.second); - } - else if (target.first == BOTH) + if (target.first == BOTH || + target.first != currentState) { startUnit(target.second); } @@ -124,8 +120,10 @@ void GpioDbusManager::gpioEventLoop() { std::cerr << "Event error." << std::endl; gpioEventLoop(); + return; } + interface->set_property(property, currentState); gpioEventLoop(); }); diff --git a/src/GpioMain.cpp b/src/GpioMain.cpp index 7d09c50f4fbd401c3c406b6e8ae3d49b262f3236..359d6dbc15b4621b230634518646b6b4085ffdd9 100644 --- a/src/GpioMain.cpp +++ b/src/GpioMain.cpp @@ -16,20 +16,23 @@ #include "config.h" +#include "Gpio.hpp" #include "GpioDbusManager.hpp" #include "PowerControl.hpp" +#include #include #include #include +#include int main() { // Load data from JSON. - Gpios allJSONData; + Gpios tempGpioInfoFormJson; - if (!loadGpioInfoFromJson(allJSONData)) + if (!loadGpioInfoFromJson(tempGpioInfoFormJson)) { std::cerr << "Not GPIO to manage." << std::endl; @@ -44,12 +47,12 @@ int main() conn->request_name(GPIO_MANAGER_SERVICE); - for (const GpioManager& manager : allJSONData.managers) + for (const GpioManager& manager : tempGpioInfoFormJson.managers) { auto interface = objServer.add_interface( GPIO_MANAGER_PATH + manager.manager.name, GPIO_MANAGER_INTERFACE); - if (manager.target.empty() || manager.monitor.empty()) + if (manager.target.empty()) { managers.emplace_back(std::make_unique( manager.manager, interface, GPIO_VALUE_PROPERTY, *io)); @@ -76,17 +79,9 @@ int main() sdbusp->request_name(POWER_SERVICE); auto obj = sdbusplus::asio::object_server(sdbusp); - std::vector> outs; - for (const GpioInfo& out : allJSONData.power.outs) - { - outs.emplace_back(std::make_unique(out)); - } - - PowerControl control(outs, allJSONData.power.pgood.manager, - obj.add_interface(POWER_PATH, POWER_INTERFACE), *io, - std::make_pair(allJSONData.power.pgood.monitor, - allJSONData.power.pgood.target)); + PowerControl control(std::move(tempGpioInfoFormJson.power), + obj.add_interface(POWER_PATH, POWER_INTERFACE), *io); io->run(); diff --git a/src/PowerControl.cpp b/src/PowerControl.cpp index cc206bd49211fd5b93ece0f2ce1de7449bd93cb5..55df4e15a9ddd9c08b1f2cd86fe0e62923e5fc30 100644 --- a/src/PowerControl.cpp +++ b/src/PowerControl.cpp @@ -23,13 +23,20 @@ #include PowerControl::PowerControl( - std::vector>& controls, const GpioInfo& powerGoodIn, + const PowerManger& powers, std::shared_ptr interface, - boost::asio::io_context& io, - const std::pair& target) : - GpioDbusManager(powerGoodIn, interface, POWER_GOOD, io, target), - gpios(std::move(controls)) + boost::asio::io_context& io) : + GpioDbusManager(powers.pgood.manager, interface, POWER_GOOD, io, + std::make_pair(powers.pgood.monitor, powers.pgood.target)) { + // Initialize and create GPIO control objects. + for (const auto& out : powers.outs) + { + gpios.emplace_back(std::make_unique( + out.isLevelTriggered, out.controlMethod, + std::make_unique(out.control))); + } + // Register the corresponding properties and methods. interface->register_property(POWER_STATE, GpioDbusManager::currentState); interface->register_method( @@ -45,18 +52,22 @@ PowerControl::PowerControl( { // There are two different control methods, namely level triggering // and pulse form. - for (const std::unique_ptr& gpio : gpios) + for (const auto& gpio : gpios) { - if (!gpio->getGpioInfo().levelTriggered) - { - gpio->setCurrentGpioValue(0); - boost::this_thread::sleep(boost::posix_time::milliseconds( - gpio->getGpioInfo().delayTime)); - gpio->setCurrentGpioValue(1); - } - else + if (gpio->controlMethod == BOTH || gpio->controlMethod == state) { - gpio->setCurrentGpioValue(state); + if (!gpio->isLevelTriggered) + { + gpio->control->setCurrentGpioValue(0); + boost::this_thread::sleep( + boost::posix_time::milliseconds( + gpio->control->getGpioInfo().delayTime)); + gpio->control->setCurrentGpioValue(1); + } + else + { + gpio->control->setCurrentGpioValue(state); + } } } std::cout << "POWER: " << std::string(state ? "ON" : "OFF") @@ -70,6 +81,6 @@ PowerControl::PowerControl( // If it is turned on by default, update the status. if (GpioDbusManager::currentState) { - startUnit(target.second); + startUnit(powers.pgood.target); } };