blob: c75866925da4dce6154add952a0d9e398d5afeb9 [file] [log] [blame]
Matthew Barthfd05d642019-11-14 15:01:57 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <string>
Matthew Barth0961fae2019-11-15 09:00:27 -060017#include <filesystem>
18#include <fstream>
19#include <nlohmann/json.hpp>
20#include <phosphor-logging/log.hpp>
Matthew Barthfd05d642019-11-14 15:01:57 -060021
22#include "json_config.hpp"
Matthew Barthe7566632019-11-18 16:13:04 -060023#include "tach.hpp"
24#include "gpio.hpp"
Matthew Barthfd05d642019-11-14 15:01:57 -060025
26namespace phosphor
27{
28namespace fan
29{
30namespace presence
31{
32
Matthew Barth0961fae2019-11-15 09:00:27 -060033using json = nlohmann::json;
34namespace fs = std::filesystem;
35using namespace phosphor::logging;
36
Matthew Barthfd05d642019-11-14 15:01:57 -060037policies JsonConfig::_policies;
Matthew Barthe7566632019-11-18 16:13:04 -060038const std::map<std::string, methodHandler> JsonConfig::_methods =
39{
40 {"tach", method::getTach},
41 {"gpio", method::getGpio}
42};
Matthew Barthfd05d642019-11-14 15:01:57 -060043
44JsonConfig::JsonConfig(const std::string& jsonFile)
45{
Matthew Barth0961fae2019-11-15 09:00:27 -060046 fs::path confFile{jsonFile};
47 std::ifstream file;
48 json jsonConf;
Matthew Barthfd05d642019-11-14 15:01:57 -060049
Matthew Barth0961fae2019-11-15 09:00:27 -060050 if (fs::exists(confFile))
51 {
52 file.open(confFile);
53 try
54 {
55 jsonConf = json::parse(file);
56 }
57 catch (std::exception& e)
58 {
59 log<level::ERR>("Failed to parse JSON config file",
60 entry("JSON_FILE=%s", jsonFile.c_str()),
61 entry("JSON_ERROR=%s", e.what()));
62 throw std::runtime_error("Failed to parse JSON config file");
63 }
64 }
65 else
66 {
67 log<level::ERR>("Unable to open JSON config file",
68 entry("JSON_FILE=%s", jsonFile.c_str()));
69 throw std::runtime_error("Unable to open JSON config file");
70 }
Matthew Barth4a94dec2019-11-15 10:40:47 -060071
72 process(jsonConf);
Matthew Barthfd05d642019-11-14 15:01:57 -060073}
74
75const policies& JsonConfig::get()
76{
77 return _policies;
78}
79
Matthew Barth4a94dec2019-11-15 10:40:47 -060080void JsonConfig::process(const json& jsonConf)
81{
82 for (auto& member : jsonConf)
83 {
Matthew Barthe7566632019-11-18 16:13:04 -060084 if (!member.contains("name") || !member.contains("path") ||
85 !member.contains("methods"))
Matthew Barth4a94dec2019-11-15 10:40:47 -060086 {
87 log<level::ERR>(
88 "Missing required fan presence properties",
Matthew Barthe7566632019-11-18 16:13:04 -060089 entry("REQUIRED_PROPERTIES=%s", "{name, path, methods}"));
Matthew Barth4a94dec2019-11-15 10:40:47 -060090 throw std::runtime_error(
91 "Missing required fan presence properties");
92 }
93 // Create a fan object
94 _fans.emplace_back(std::make_tuple(member["name"], member["path"]));
Matthew Barthe7566632019-11-18 16:13:04 -060095
96 // Loop thru the configured methods of presence detection
97 for (auto& method : member["methods"].items())
98 {
99 if (!method.value().contains("type"))
100 {
101 log<level::ERR>(
102 "Missing required fan presence method type",
103 entry("FAN_NAME=%s",
104 member["name"].get<std::string>().c_str()));
105 throw std::runtime_error(
106 "Missing required fan presence method type");
107 }
108 // The method type of fan presence detection
109 // (Must have a supported function within the method namespace)
110 auto type = method.value()["type"].get<std::string>();
111 std::transform(type.begin(), type.end(), type.begin(), tolower);
112 auto func = _methods.find(type);
113 if (func != _methods.end())
114 {
115 // Call function for method type
116 auto sensor = func->second((_fans.size() - 1), method.value());
117 if (sensor)
118 {
119 _sensors.emplace_back(std::move(sensor));
120 }
121 }
122 else
123 {
124 log<level::ERR>("Invalid fan presence method type",
125 entry("FAN_NAME=%s",
126 member["name"].get<std::string>().c_str()),
127 entry("METHOD_TYPE=%s", type.c_str()));
128 throw std::runtime_error("Invalid fan presence method type");
129 }
130 }
Matthew Barth4a94dec2019-11-15 10:40:47 -0600131 }
132}
133
Matthew Barthe7566632019-11-18 16:13:04 -0600134/**
135 * Methods of fan presence detection function definitions
136 */
137namespace method
138{
139 // Get a constructed presence sensor for fan presence detection by tach
140 std::unique_ptr<PresenceSensor> getTach(size_t fanIndex, const json& method)
141 {
Matthew Barthe0d98a32019-11-19 15:40:57 -0600142 if (!method.contains("sensors") ||
143 method["sensors"].size() == 0)
144 {
145 log<level::ERR>(
146 "Missing required tach method properties",
147 entry("FAN_ENTRY=%d", fanIndex),
148 entry("REQUIRED_PROPERTIES=%s", "{sensors}"));
149 throw std::runtime_error("Missing required tach method properties");
150 }
151
152 std::vector<std::string> sensors;
153 for (auto& sensor : method["sensors"])
154 {
155 sensors.emplace_back(sensor.get<std::string>());
156 }
157
158 return std::make_unique<PolicyAccess<Tach, JsonConfig>>(
159 fanIndex, std::move(sensors));
Matthew Barthe7566632019-11-18 16:13:04 -0600160 }
161
162 // Get a constructed presence sensor for fan presence detection by gpio
163 std::unique_ptr<PresenceSensor> getGpio(size_t fanIndex, const json& method)
164 {
Matthew Barthe0d98a32019-11-19 15:40:57 -0600165 if (!method.contains("physpath") ||
166 !method.contains("devpath") ||
167 !method.contains("key"))
168 {
169 log<level::ERR>(
170 "Missing required gpio method properties",
171 entry("FAN_ENTRY=%d", fanIndex),
172 entry("REQUIRED_PROPERTIES=%s", "{physpath, devpath, key}"));
173 throw std::runtime_error("Missing required gpio method properties");
174 }
175
176 auto physpath = method["physpath"].get<std::string>();
177 auto devpath = method["devpath"].get<std::string>();
178 auto key = method["key"].get<unsigned int>();
179
180 return std::make_unique<PolicyAccess<Gpio, JsonConfig>>(
181 fanIndex, physpath, devpath, key);
Matthew Barthe7566632019-11-18 16:13:04 -0600182 }
183
184} // namespace method
185
Matthew Barthfd05d642019-11-14 15:01:57 -0600186} // namespace presence
187} // namespace fan
188} // namespace phosphor