From 48ad43ddcfddc9472f4e9c2519c86075f070a5f0 Mon Sep 17 00:00:00 2001 From: Tian Jingzai Date: Wed, 26 Jun 2024 19:39:25 +0800 Subject: [PATCH] gpio-manager: Refactored the code once While maintaining the original functionality, the code was refactored, excess comments were removed, the code structure was adjusted, and the delay waiting in the code was replaced with asynchronous operations in boost. Signed-off-by: Tian Jingzai Change-Id: I4e8658d731b5f4754fa955c6fe5b9e8536439d6a --- .../dbusmanager.cpp | 172 ++++++------ .../dbusmanager.hpp | 35 +-- gpio.cpp | 64 +++++ include/Gpio.hpp => gpio.hpp | 98 ++----- json/json.cpp | 147 ++++++++++ json/json.hpp | 24 ++ src/GpioMain.cpp => main.cpp | 42 ++- meson.build | 67 +---- .../powercontrol.cpp | 80 +++--- .../powercontrol.hpp | 35 ++- services/gpio-manager@.service | 2 +- src/Gpio.cpp | 251 ------------------ 12 files changed, 448 insertions(+), 569 deletions(-) rename src/GpioDbusManager.cpp => dbus/dbusmanager.cpp (35%) rename include/GpioDbusManager.hpp => dbus/dbusmanager.hpp (74%) create mode 100644 gpio.cpp rename include/Gpio.hpp => gpio.hpp (42%) create mode 100644 json/json.cpp create mode 100644 json/json.hpp rename src/GpioMain.cpp => main.cpp (64%) rename src/PowerControl.cpp => power/powercontrol.cpp (40%) rename include/PowerControl.hpp => power/powercontrol.hpp (65%) delete mode 100644 src/Gpio.cpp diff --git a/src/GpioDbusManager.cpp b/dbus/dbusmanager.cpp similarity index 35% rename from src/GpioDbusManager.cpp rename to dbus/dbusmanager.cpp index 89e8ddb..374d52e 100644 --- a/src/GpioDbusManager.cpp +++ b/dbus/dbusmanager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Phytium Technology Co., Ltd. + * Copyright (c) 2024, Phytium Technology Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,121 +14,120 @@ * limitations under the License. */ -#include "config.h" +#include "dbus/dbusmanager.hpp" -#include "GpioDbusManager.hpp" - -#include #include #include #include GpioDbusManager::GpioDbusManager( - const GpioInfo& gpioInfo, + const GpioInfo& info, std::shared_ptr interface, const std::string& property, boost::asio::io_context& io, - const std::pair& target) : - Gpio(gpioInfo), + const std::pair& target) : + Gpio(info), currentState(Gpio::getCurrentGpioValue()), interface(interface), - property(property), fd(io), target(target) + _property(property), _fd(io), _timer(io), _target(target) { - try + if (!Gpio::getGpioInfo().direction) { - if (!Gpio::getGpioInfo().direction) + try { int gpioFd = line.event_get_fd(); if (gpioFd < 0) { - std::cerr << "Get Fd Error" << std::endl; - + std::cerr << "Get Fd Error\n"; return; } - - fd.assign(gpioFd); - - interface->register_property(property, currentState); - gpioEventLoop(); + _fd.assign(gpioFd); } - else + catch (...) { - interface->register_property( - property, currentState, [this](const int& req, int& old) { - try - { - Gpio::setCurrentGpioValue(req); - old = Gpio::getCurrentGpioValue(); - } - catch (...) - { - return false; - } - return true; - }); + std::cerr << "Unknown initialization error\n"; + return; } + + interface->register_property(_property, currentState); + gpioEventLoop(); } - catch (...) + else { - std::cerr << "GpioDbusManager Init Error" << std::endl; - - return; + interface->register_property(_property, currentState, + [this](const int& req, int& old) { + try + { + Gpio::setCurrentGpioValue(req); + old = Gpio::getCurrentGpioValue(); + return true; + } + catch (...) + { + /** + * Do not perform any other + * operations. + * */ + } + return false; + }); } } GpioDbusManager::~GpioDbusManager() { - fd.close(); + _fd.close(); + _timer.cancel(); } void GpioDbusManager::gpioEventLoop() { - fd.async_wait(boost::asio::posix::stream_descriptor::wait_read, - [this](const boost::system::error_code& ec) { - if (ec == boost::system::errc::bad_file_descriptor) - { - std::cerr << "Fd error" << std::endl; - - return; - } - - try - { - line.event_read(); - - /* If there is an effective time for configuring the - * GPIO level, continue to check once after the time - * has ended. */ - boost::this_thread::sleep( - boost::posix_time::milliseconds( - Gpio::getGpioInfo().delayTime)); - if (currentState == Gpio::getCurrentGpioValue()) - { - gpioEventLoop(); - - return; - } - - currentState = Gpio::getCurrentGpioValue(); - interface->set_property(property, currentState); - - /* If there are services that rely on execution. */ - if (target != std::pair{}) - { - if (target.first == BOTH || - target.first == currentState) - { - startUnit(target.second, currentState); - } - } - } - catch (...) - { - std::cerr << "GPIO Event Loop error" << std::endl; - } - - gpioEventLoop(); - }); + _fd.async_wait( + boost::asio::posix::stream_descriptor::wait_read, + [this](const boost::system::error_code& ec) { + if (ec == boost::system::errc::bad_file_descriptor) + { + std::cerr << "Fd error\n"; + return; + } + + line.event_read(); + + /** + * The delay of the input signal depends on the corresponding JSON + * configuration file. The purpose of this is to filter out some + * erroneous input signals. + * */ + _timer.expires_after( + std::chrono::milliseconds(Gpio::getGpioInfo().delayTime)); + _timer.async_wait([this](const boost::system::error_code& ec) { + if (ec == boost::asio::error::operation_aborted || + currentState == Gpio::getCurrentGpioValue()) + { + return; + } + + currentState = Gpio::getCurrentGpioValue(); + interface->set_property(_property, currentState); + + /** + * Whether to execute corresponding services for changes in + * input signals depends on whether the corresponding JSON file + * is configured. + * */ + if (_target != std::pair{}) + { + static const std::array state{"low", "high", + "both"}; + if (_target.first == state.back() || + _target.first == state[currentState]) + { + startUnit(_target.second, currentState); + } + } + }); + gpioEventLoop(); + }); } void startUnit(std::string target, const int status) @@ -148,8 +147,9 @@ void startUnit(std::string target, const int status) try { auto bus = sdbusplus::bus::new_default(); - auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_PATH, - SYSTEMD_INTERFACE, "StartUnit"); + auto method = bus.new_method_call( + "org.freedesktop.systemd1", "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", "StartUnit"); method.append(target); method.append("replace"); @@ -159,6 +159,6 @@ void startUnit(std::string target, const int status) } catch (const sdbusplus::exception::exception& e) { - std::cerr << "Dbus execution failed" << e.what() << std::endl; + std::cerr << e.what() << "\n"; } } diff --git a/include/GpioDbusManager.hpp b/dbus/dbusmanager.hpp similarity index 74% rename from include/GpioDbusManager.hpp rename to dbus/dbusmanager.hpp index 5896173..22d3314 100644 --- a/include/GpioDbusManager.hpp +++ b/dbus/dbusmanager.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Phytium Technology Co., Ltd. + * Copyright (c) 2024, Phytium Technology Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,11 @@ */ #pragma once -#include "Gpio.hpp" + +#include "gpio.hpp" #include +#include #include #include #include @@ -26,9 +28,8 @@ #include /** - * @class GpioDbusManager - * @brief The class managed by gpio. - */ + * @brief Manage GPIO classes in a Dbus manner. + * */ class GpioDbusManager : public Gpio { public: @@ -48,35 +49,25 @@ class GpioDbusManager : public Gpio * @param[in] target - The target content required for GPIO * monitoring. */ - GpioDbusManager(const GpioInfo& gpioInfo, + GpioDbusManager(const GpioInfo& info, std::shared_ptr interface, const std::string& property, boost::asio::io_context& io, - const std::pair& target = - std::pair{}); - - /** @brief The destructor of GpioDbusManager. */ + const std::pair& target = + std::pair{}); ~GpioDbusManager(); /** @brief GPIO event function. */ void gpioEventLoop(); protected: - /** @brief Current GPIO status. */ int currentState; - - /** @brief Dbus interface. */ std::shared_ptr interface; private: - - /** @brief The registered dbus attribute name. */ - const std::string property; - - /** @brief Stream descriptor. */ - boost::asio::posix::stream_descriptor fd; - - /** @brief Target state and target system unit. */ - const std::pair target; + const std::string _property; + boost::asio::posix::stream_descriptor _fd; + boost::asio::steady_timer _timer; + const std::pair _target; }; /** diff --git a/gpio.cpp b/gpio.cpp new file mode 100644 index 0000000..ecd1d7d --- /dev/null +++ b/gpio.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, Phytium Technology Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gpio.hpp" + +#include + +#include +#include +#include + +Gpio::Gpio(const GpioInfo& info) : + line(gpiod::chip(std::to_string(info.chip), gpiod::chip::OPEN_BY_NUMBER) + .get_line(info.line)), + _info(info) +{ + try + { + line.request( + {_info.name, + _info.direction ? gpiod::line_request::DIRECTION_OUTPUT + : gpiod::line_request::EVENT_BOTH_EDGES, + _info.polarity ? gpiod::line_request::FLAG_ACTIVE_LOW : 0}, + _info.defaultValue); + } + catch (...) + { + std::cerr << _info.name << " Init Error\n"; + return; + } +} + +Gpio::~Gpio() +{ + line.release(); +} + +int Gpio::getCurrentGpioValue() const +{ + return line.get_value(); +} + +void Gpio::setCurrentGpioValue(int value) const +{ + line.set_value(value); +} + +const GpioInfo& Gpio::getGpioInfo() const +{ + return _info; +} diff --git a/include/Gpio.hpp b/gpio.hpp similarity index 42% rename from include/Gpio.hpp rename to gpio.hpp index 10e5b33..1b6922e 100644 --- a/include/Gpio.hpp +++ b/gpio.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Phytium Technology Co., Ltd. + * Copyright (c) 2024, Phytium Technology Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,10 +23,9 @@ #include /** - * @struct GpioInfo - * @brief Structure of gpio information. - */ -struct GpioInfo + * @brief GPIO information structure. + * */ +typedef struct { int chip; int line; @@ -35,103 +34,54 @@ struct GpioInfo bool direction; bool defaultValue; std::string name; -}; +} GpioInfo; /** - * @struct GpioManger - * @brief Structure of GPIO management information. - */ -struct GpioManager + * @brief GPIO management structure. + * */ +typedef struct { GpioInfo manager; - uint8_t monitor; + std::string monitor; std::string target; -}; +} Manager; -/** - * @struct PowerControl - * @brief Structure of power control information. - */ -struct PowerControlInfo +typedef struct { - GpioInfo control; + GpioInfo info; bool isLevelTriggered; - uint8_t controlMethod; -}; - -/** - * @struct PowerManger - * @brief Structure of power information. - */ -struct PowerManger -{ - GpioManager pgood; - std::vector outs; - std::vector resetOuts; -}; + std::string controlMethod; +} Power; /** - * @struct Gpios - * @brief Structure of all gpio information. - */ -struct Gpios + * @brief Power management structure. + * */ +typedef struct { - PowerManger power; - std::vector managers; -}; + Manager pgood; + std::vector controls; + /** Not currently used. */ + std::vector resets; +} Powers; -/** - * @class Gpio - * @brief The base class for gpio information. - */ class Gpio { public: - Gpio() = delete; Gpio(const Gpio&) = delete; Gpio& operator=(const Gpio&) = delete; Gpio(const Gpio&&) = delete; Gpio&& operator=(const Gpio&&) = delete; - /** - * @brief The constructor for Gpio. - * - * @param[in] gpioInfo - Basic information of gpio. - */ - Gpio(const GpioInfo& gpioInfo); - - /** @brief The destructor of Gpio. */ + Gpio(const GpioInfo& info); ~Gpio(); - /** - * @brief Gets the value of the current gpio. - * @return int - Returns the current value. - */ int getCurrentGpioValue() const; - - /** - * @brief Set the current gpio. - * @param[in] value - Set the current gpio value. - */ void setCurrentGpioValue(int value) const; - - /** @brief Obtain current Gpio information. */ const GpioInfo& getGpioInfo() const; protected: - /** @brief The gpio line object. */ gpiod::line line; private: - /** @brief Basic information of gpio. */ - GpioInfo gpioInfo; + const GpioInfo& _info; }; - -/** - * @brief Load data managed by gpio. - * - * @param[in] gpios - Load the saved data. - * - * @return bool - Check whether the execution is successful. - */ -bool loadGpioInfoFromJson(Gpios& rawGpioData); diff --git a/json/json.cpp b/json/json.cpp new file mode 100644 index 0000000..9936044 --- /dev/null +++ b/json/json.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2024, Phytium Technology Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "json/json.hpp" + +#include + +#include +#include +#include +#include +#include + +void from_json(const nlohmann::json& j, GpioInfo& m) +{ + j.at("Name").get_to(m.name); + j.at("Chip").get_to(m.chip); + j.at("Line").get_to(m.line); + + std::string direction = j.at("Direction"); + if (direction == "in") + { + m.direction = false; + } + else if (direction == "out") + { + m.direction = true; + } + else + { + throw std::runtime_error("Direction Error"); + } + + if (j.contains("Polarity")) + { + j.at("Polarity").get_to(m.polarity); + } + else + { + m.polarity = true; + } + + if (j.contains("DelayTime")) + { + j.at("DelayTime").get_to(m.delayTime); + } + + if (j.contains("DefaultValue")) + { + m.defaultValue = j.at("DefaultValue") == 1 ? true : false; + } +} + +namespace json +{ +void buildGpioJson(std::vector& dataManagers, Powers& powers) +{ + std::ifstream file("/etc/default/obmc/gpio/gpio_defs.json"); + if (!file.is_open()) + { + throw std::runtime_error("Failed to open file"); + return; + } + + auto json = nlohmann::json::parse(file, nullptr, false); + if (json.is_discarded()) + { + throw std::runtime_error("JSON parsing failed"); + return; + } + + std::vector gpios; + + for (const auto& definition : json["gpio_definitions"]) + { + gpios.emplace_back(definition.get()); + } + + auto findDefinition = [&gpios](const std::string& name) -> GpioInfo { + for (auto gpio : gpios) + { + if (gpio.name == name) + { + return gpio; + } + } + throw std::runtime_error("Not Found"); + return GpioInfo{}; + }; + + auto& power = json.at("power_config"); + auto& monitors = json.at("gpio_monitor"); + + std::string pgood = power.at("power_good_in").get(); + + if (monitors.contains(pgood)) + { + powers.pgood = Manager{findDefinition(pgood), + monitors[pgood].at("Monitor").get(), + monitors[pgood].at("Target").get()}; + } + else + { + powers.pgood = Manager{findDefinition(pgood), "", ""}; + } + + auto& outs = power.at("power_up_outs"); + for (const auto& out : outs) + { + const std::string& name = out.at("Name"); + + powers.controls.emplace_back(Power{findDefinition(name), + out.at("LevelTriggered").get(), + out.at("Power").get()}); + } + + auto& managers = json.at("gpio_manager"); + + for (const std::string& manager : managers) + { + if (monitors.contains(manager)) + { + dataManagers.emplace_back( + Manager{findDefinition(manager), + monitors[manager].at("Monitor").get(), + monitors[manager].at("Target").get()}); + } + else + { + dataManagers.emplace_back(Manager{findDefinition(manager), "", ""}); + } + } +} +}; // namespace json diff --git a/json/json.hpp b/json/json.hpp new file mode 100644 index 0000000..72784b7 --- /dev/null +++ b/json/json.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023, Phytium Technology Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "gpio.hpp" + +namespace json +{ +void buildGpioJson(std::vector& dataManagers, Powers& powers); +}; diff --git a/src/GpioMain.cpp b/main.cpp similarity index 64% rename from src/GpioMain.cpp rename to main.cpp index 7c03828..14b27da 100644 --- a/src/GpioMain.cpp +++ b/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Phytium Technology Co., Ltd. + * Copyright (c) 2024, Phytium Technology Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,10 @@ * limitations under the License. */ -#include "config.h" - -#include "Gpio.hpp" -#include "GpioDbusManager.hpp" -#include "PowerControl.hpp" +#include "dbus/dbusmanager.hpp" +#include "gpio.hpp" +#include "json/json.hpp" +#include "power/powercontrol.hpp" #include #include @@ -29,44 +28,39 @@ int main() { - /* Load data from JSON */ - Gpios tempGpioInfoFormJson; + std::vector dataManagers; + Powers powers; - if (!loadGpioInfoFromJson(tempGpioInfoFormJson)) - { - std::cerr << "Empty data" << std::endl; - return 0; - } + json::buildGpioJson(dataManagers, powers); - /* GPIO management service */ auto io = std::make_shared(); auto conn = std::make_shared(*io); auto objServer = sdbusplus::asio::object_server(conn); std::vector> managers; - conn->request_name(GPIO_MANAGER_SERVICE); + conn->request_name("xyz.openbmc_project.Gpio.Manager"); - for (const GpioManager& manager : tempGpioInfoFormJson.managers) + for (const Manager& manager : dataManagers) { auto interface = objServer.add_interface( - GPIO_MANAGER_PATH + manager.manager.name, GPIO_MANAGER_INTERFACE); + "/xyz/openbmc_project/gpio/" + manager.manager.name, + "xyz.openbmc_project.Gpio.Manager"); if (manager.target.empty()) { managers.emplace_back(std::make_unique( - manager.manager, interface, GPIO_VALUE_PROPERTY, *io)); + manager.manager, interface, "Value", *io)); } else { managers.emplace_back(std::make_unique( - manager.manager, interface, GPIO_VALUE_PROPERTY, *io, + manager.manager, interface, "Value", *io, std::make_pair(manager.monitor, manager.target))); } interface->initialize(); } - /* Power control service */ std::shared_ptr sdbusp; sd_bus* bus = nullptr; @@ -75,12 +69,14 @@ int main() { sdbusp = std::make_shared(*io, bus); } - sdbusp->request_name(POWER_SERVICE); + sdbusp->request_name("org.openbmc.control.Power"); auto obj = sdbusplus::asio::object_server(sdbusp); - PowerControl control(std::move(tempGpioInfoFormJson.power), - obj.add_interface(POWER_PATH, POWER_INTERFACE), *io); + PowerControl control(powers, + obj.add_interface("/org/openbmc/control/power0", + "org.openbmc.control.Power"), + *io); io->run(); diff --git a/meson.build b/meson.build index 9a8c9c4..093d10a 100644 --- a/meson.build +++ b/meson.build @@ -5,77 +5,26 @@ project('gpio-manager', 'warning_level=3', 'cpp_std=c++20' ]) -conf = configuration_data() -conf.set_quoted('JSON_NAME', 'Name') -conf.set_quoted('JSON_CHIP', 'Chip') -conf.set_quoted('JSON_LINE', 'Line') -conf.set_quoted('JSON_DELAYTIME', 'DelayTime') -conf.set_quoted('JSON_POLARITY', 'Polarity') -conf.set_quoted('JSON_LEVELTRIGGERED', 'LevelTriggered') -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') -conf.set_quoted('GPIO_DEFINITIONS', 'gpio_definitions') -conf.set_quoted('POWER_RESET_OUTS', 'reset_outs') -conf.set_quoted('GPIO_MANAGER', 'gpio_manager') -conf.set_quoted('GPIO_MONITOR', 'gpio_monitor') - -conf.set_quoted('JSON_FILEPATH', '/etc/default/obmc/gpio/gpio_defs.json') - -conf.set_quoted('GPIO_VALUE_PROPERTY', 'Value') -conf.set_quoted('POWER_GOOD', 'pgood') -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('GPIO_MANAGER_SERVICE', 'xyz.openbmc_project.Gpio.Manager') -conf.set_quoted('GPIO_MANAGER_PATH', '/xyz/openbmc_project/gpio/') -conf.set_quoted('GPIO_MANAGER_INTERFACE', 'xyz.openbmc_project.Gpio.Manager') -conf.set_quoted('POWER_SERVICE', 'org.openbmc.control.Power') -conf.set_quoted('POWER_PATH', '/org/openbmc/control/power0') -conf.set_quoted('POWER_INTERFACE', 'org.openbmc.control.Power') -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') nlohmann_json = dependency('nlohmann_json') sdbusplus = dependency('sdbusplus') boost = dependency('boost') libgpiod = dependency('libgpiod') -executable('gpio-management', - 'src/GpioMain.cpp', - 'src/Gpio.cpp', - 'src/GpioDbusManager.cpp', - 'src/PowerControl.cpp', - link_args: ['-lgpiodcxx', '-lboost_thread'], +executable('gpiomanagement', + 'main.cpp', + 'gpio.cpp', + 'json/json.cpp', + 'dbus/dbusmanager.cpp', + 'power/powercontrol.cpp', + link_args: ['-lgpiodcxx'], dependencies: [ nlohmann_json, systemd, sdbusplus, boost, libgpiod, ], - include_directories: 'include', + include_directories: '.', install : true, install_dir: get_option('bindir')) diff --git a/src/PowerControl.cpp b/power/powercontrol.cpp similarity index 40% rename from src/PowerControl.cpp rename to power/powercontrol.cpp index 8950094..deb3ab7 100644 --- a/src/PowerControl.cpp +++ b/power/powercontrol.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Phytium Technology Co., Ltd. + * Copyright (c) 2024, Phytium Technology Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,59 +14,60 @@ * limitations under the License. */ -#include "config.h" - -#include "PowerControl.hpp" - -#include +#include "power/powercontrol.hpp" #include PowerControl::PowerControl( - const PowerManger& powers, + const Powers& powers, std::shared_ptr interface, boost::asio::io_context& io) : - GpioDbusManager(powers.pgood.manager, interface, POWER_GOOD, io, - std::make_pair(powers.pgood.monitor, powers.pgood.target)) + GpioDbusManager(powers.pgood.manager, interface, "pgood", io, + std::make_pair(powers.pgood.monitor, powers.pgood.target)), + _timer(io) { - /* Initialize and create GPIO control objects */ - for (const auto& out : powers.outs) + for (const auto& control : powers.controls) { - gpios.emplace_back(std::make_unique( - out.isLevelTriggered, out.controlMethod, - std::make_unique(out.control))); + _controls.emplace_back(std::make_unique( + control.isLevelTriggered, control.controlMethod, + std::make_unique(control.info))); } - /* Register the corresponding properties and methods */ - interface->register_property(POWER_STATE, GpioDbusManager::currentState); + interface->register_property("state", GpioDbusManager::currentState); interface->register_method( - GET_POWER_STATE, [this]() { return GpioDbusManager::currentState; }); - interface->register_method(SET_POWER_STATE, [&](int state) { + "getPowerState", [this]() { return GpioDbusManager::currentState; }); + interface->register_method("setPowerState", [&](int state) { if (state == Gpio::getCurrentGpioValue()) { std::cout - << "The status has not changed and does not need to be set" - << std::endl; + << "The status has not changed and does not need to be set\n"; } else { - /* There are two different control methods, namely level triggering - * and pulse form */ - for (const auto& gpio : gpios) + for (const auto& control : _controls) { - if (gpio->controlMethod == BOTH || gpio->controlMethod == state) + static const std::array powerState{"off", "on", + "both"}; + if (control->controlMethod == powerState.back() || + control->controlMethod == powerState[state]) { - if (!gpio->isLevelTriggered) + if (!control->isLevelTriggered) { - gpio->control->setCurrentGpioValue(0); - boost::this_thread::sleep( - boost::posix_time::milliseconds( - gpio->control->getGpioInfo().delayTime)); - gpio->control->setCurrentGpioValue(1); + control->control->setCurrentGpioValue(0); + _timer.expires_after(std::chrono::milliseconds( + control->control->getGpioInfo().delayTime)); + _timer.async_wait( + [&control](const boost::system::error_code& ec) { + if (ec == boost::asio::error::operation_aborted) + { + return; + } + control->control->setCurrentGpioValue(1); + }); } else { - gpio->control->setCurrentGpioValue(state); + control->control->setCurrentGpioValue(state); } } } @@ -74,13 +75,24 @@ PowerControl::PowerControl( << std::endl; } - interface->set_property(POWER_STATE, Gpio::getCurrentGpioValue()); + interface->set_property("state", state); }); interface->initialize(); - /* If it is turned on by default, update the status */ + /** + * When the initialization phase is in the power on state, execute the + * corresponding service. + * */ if (GpioDbusManager::currentState) { - startUnit(powers.pgood.target, 1); + if (!powers.pgood.target.empty()) + { + startUnit(powers.pgood.target, 1); + } } }; + +PowerControl::~PowerControl() +{ + _timer.cancel(); +} diff --git a/include/PowerControl.hpp b/power/powercontrol.hpp similarity index 65% rename from include/PowerControl.hpp rename to power/powercontrol.hpp index cd9c305..9af0a02 100644 --- a/include/PowerControl.hpp +++ b/power/powercontrol.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Phytium Technology Co., Ltd. + * Copyright (c) 2024, Phytium Technology Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,16 @@ #pragma once -#include "GpioDbusManager.hpp" +#include "dbus/dbusmanager.hpp" +#include "gpio.hpp" + +#include + +#include /** - * @class PowerControl - * @brief The object of power control. - */ + * @brief GPIO controls the class of power up and down. + * */ class PowerControl : public GpioDbusManager { public: @@ -31,26 +35,19 @@ class PowerControl : public GpioDbusManager PowerControl(const PowerControl&&) = delete; PowerControl&& operator=(const PowerControl&&) = delete; - /** - * @brief The constructor for PowerControl. - * - * @param[in] powers - Power management information. - * @param[in] io - Io context. - * @param[in] interface - Dbus interface. - * - */ - PowerControl(const PowerManger& powers, + PowerControl(const Powers& powers, std::shared_ptr interface, boost::asio::io_context& io); + ~PowerControl(); private: - struct ControlSet + typedef struct { bool isLevelTriggered; - uint8_t controlMethod; + std::string controlMethod; std::unique_ptr control; - }; + } ControlSet; - /** @brief On/off control. */ - std::vector> gpios; + std::vector> _controls; + boost::asio::steady_timer _timer; }; diff --git a/services/gpio-manager@.service b/services/gpio-manager@.service index 0139bd9..9bdf3d0 100644 --- a/services/gpio-manager@.service +++ b/services/gpio-manager@.service @@ -3,7 +3,7 @@ Description=GPIO management [Service] Restart=always -ExecStart=/usr/bin/gpio-management +ExecStart=/usr/bin/gpiomanagement SyslogIdentifier=gpio-management Type=dbus BusName=org.openbmc.control.Power diff --git a/src/Gpio.cpp b/src/Gpio.cpp deleted file mode 100644 index c1d6111..0000000 --- a/src/Gpio.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2023, Phytium Technology Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "config.h" - -#include "Gpio.hpp" - -#include - -#include -#include -#include - -Gpio::Gpio(const GpioInfo& gpioInfo) : - line(gpiod::chip(std::to_string(gpioInfo.chip), gpiod::chip::OPEN_BY_NUMBER) - .get_line(gpioInfo.line)), - gpioInfo(std::move(gpioInfo)) -{ - try - { - line.request( - {gpioInfo.name, - gpioInfo.direction ? gpiod::line_request::DIRECTION_OUTPUT - : gpiod::line_request::EVENT_BOTH_EDGES, - gpioInfo.polarity ? gpiod::line_request::FLAG_ACTIVE_LOW : 0}, - gpioInfo.defaultValue); - } - catch (...) - { - std::cerr << gpioInfo.name << " Init Error" << std::endl; - - return; - } -} - -Gpio::~Gpio() -{ - line.release(); -} - -int Gpio::getCurrentGpioValue() const -{ - return line.get_value(); -} - -void Gpio::setCurrentGpioValue(int value) const -{ - line.set_value(value); -} - -const GpioInfo& Gpio::getGpioInfo() const -{ - return gpioInfo; -} - -static bool loadGpioData(const nlohmann::json& defs, - const std::string& gpioName, GpioInfo& dataIn) -{ - try - { - auto it = std::find_if(defs.begin(), defs.end(), - [&gpioName](const auto& def) { - return def.at(JSON_NAME) == gpioName; - }); - - if (it != defs.end()) - { - 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 << 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& rawGpioData) -{ - if (!std::filesystem::exists(JSON_FILEPATH)) - { - std::cerr << JSON_FILEPATH << " not found" << std::endl; - - return false; - } - - std::ifstream inputStream(JSON_FILEPATH); - - if (!inputStream.good()) - { - std::cerr << JSON_FILEPATH << " can not open" << std::endl; - - return false; - } - - nlohmann::json loadJson; - - try - { - loadJson = nlohmann::json::parse(inputStream); - } - catch (const nlohmann::json::parse_error& e) - { - std::cerr << "Parse json error:" << e.what() << std::endl; - inputStream.close(); - - return false; - } - inputStream.close(); - - const auto& defs = loadJson[GPIO_DEFINITIONS]; - const auto& monitors = loadJson[GPIO_MONITOR]; - const std::string& pgood = loadJson[POWER_CONFIG][POWER_GOOD_IN]; - GpioManager tempGpioManager; - - /* pgoood */ - if (loadGpioManagerData(defs, monitors, pgood, tempGpioManager)) - { - rawGpioData.power.pgood = std::move(tempGpioManager); - } - - /* control outs */ - const auto& powerUpOuts = loadJson[POWER_CONFIG][POWER_UP_OUTS]; - - for (const nlohmann::json& out : powerUpOuts) - { - try - { - PowerControlInfo rawPowerData; - const std::string& powerMethod = out.at(JSON_POWER); - - if (powerMethod != BOTH_STR && powerMethod != POWER_OFF_STR && - powerMethod != POWER_ON_STR) - { - continue; - } - - 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 (...) - { - std::cerr << "controls data format error" << std::endl; - } - } - - /* reset outs(Currently not in use.) */ - GpioInfo tempGpio; - const auto& powerResetOuts = loadJson[POWER_CONFIG][POWER_RESET_OUTS]; - - for (const auto& reset : powerResetOuts) - { - if (!loadGpioData(defs, reset, tempGpio)) - { - continue; - } - - rawGpioData.power.resetOuts.emplace_back(tempGpio); - } - - /* gpio manager */ - const auto& managers = loadJson[GPIO_MANAGER]; - - for (const std::string& manager : managers) - { - if (!loadGpioManagerData(defs, monitors, manager, tempGpioManager)) - { - continue; - } - - rawGpioData.managers.emplace_back(std::move(tempGpioManager)); - } - - return true; -} -- Gitee