blob: 533c94d37182c75b0e85fcfa80d7283a0b2de394 [file] [log] [blame]
James Feistbc896df2018-11-26 16:28:17 -08001/*
2// Copyright (c) 2018 Intel 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
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103017#include "ExitAirTempSensor.hpp"
18
Ed Tanouseacbfdd2024-04-04 12:00:24 -070019#include "SensorPaths.hpp"
20#include "Thresholds.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103021#include "Utils.hpp"
22#include "VariantVisitors.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070023#include "sensor.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103024
James Feistbc896df2018-11-26 16:28:17 -080025#include <boost/algorithm/string/replace.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070026#include <boost/asio/error.hpp>
27#include <boost/asio/io_context.hpp>
28#include <boost/asio/post.hpp>
29#include <boost/asio/steady_timer.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070030#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070031#include <sdbusplus/asio/connection.hpp>
32#include <sdbusplus/asio/object_server.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070033#include <sdbusplus/bus.hpp>
James Feist38fb5982020-05-28 10:09:54 -070034#include <sdbusplus/bus/match.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070035#include <sdbusplus/message.hpp>
James Feist38fb5982020-05-28 10:09:54 -070036
Ed Tanouseacbfdd2024-04-04 12:00:24 -070037#include <algorithm>
James Feist38fb5982020-05-28 10:09:54 -070038#include <array>
James Feistbc896df2018-11-26 16:28:17 -080039#include <chrono>
Patrick Venture96e97db2019-10-31 13:44:38 -070040#include <cmath>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070041#include <cstddef>
42#include <cstdint>
Patrick Venture96e97db2019-10-31 13:44:38 -070043#include <functional>
James Feistbc896df2018-11-26 16:28:17 -080044#include <iostream>
45#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070046#include <memory>
Patrick Venture96e97db2019-10-31 13:44:38 -070047#include <stdexcept>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070048#include <string>
Patrick Venture96e97db2019-10-31 13:44:38 -070049#include <utility>
50#include <variant>
James Feistbc896df2018-11-26 16:28:17 -080051#include <vector>
52
Ed Tanous8a57ec02020-10-09 12:46:52 -070053constexpr const double altitudeFactor = 1.14;
Zev Weiss054aad82022-08-18 01:37:34 -070054constexpr const char* exitAirType = "ExitAirTempSensor";
55constexpr const char* cfmType = "CFMSensor";
James Feistbc896df2018-11-26 16:28:17 -080056
57// todo: this *might* need to be configurable
58constexpr const char* inletTemperatureSensor = "temperature/Front_Panel_Temp";
James Feist13452092019-03-07 16:38:12 -080059constexpr const char* pidConfigurationType =
60 "xyz.openbmc_project.Configuration.Pid";
61constexpr const char* settingsDaemon = "xyz.openbmc_project.Settings";
62constexpr const char* cfmSettingPath = "/xyz/openbmc_project/control/cfm_limit";
63constexpr const char* cfmSettingIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistbc896df2018-11-26 16:28:17 -080064
Ed Tanous8a57ec02020-10-09 12:46:52 -070065static constexpr bool debug = false;
James Feistbc896df2018-11-26 16:28:17 -080066
James Feistb2eb3f52018-12-04 16:17:50 -080067static constexpr double cfmMaxReading = 255;
68static constexpr double cfmMinReading = 0;
69
James Feist13452092019-03-07 16:38:12 -080070static constexpr size_t minSystemCfm = 50;
71
Zev Weiss054aad82022-08-18 01:37:34 -070072constexpr const auto monitorTypes{
73 std::to_array<const char*>({exitAirType, cfmType})};
James Feist655f3762020-10-05 15:28:15 -070074
James Feist9a25ed42019-10-15 15:43:44 -070075static std::vector<std::shared_ptr<CFMSensor>> cfmSensors;
76
James Feistb2eb3f52018-12-04 16:17:50 -080077static void setupSensorMatch(
Patrick Williams92f8f512022-07-22 19:26:55 -050078 std::vector<sdbusplus::bus::match_t>& matches, sdbusplus::bus_t& connection,
79 const std::string& type,
80 std::function<void(const double&, sdbusplus::message_t&)>&& callback)
James Feistb2eb3f52018-12-04 16:17:50 -080081{
Patrick Williams92f8f512022-07-22 19:26:55 -050082 std::function<void(sdbusplus::message_t & message)> eventHandler =
83 [callback{std::move(callback)}](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -070084 std::string objectName;
85 boost::container::flat_map<std::string, std::variant<double, int64_t>>
86 values;
87 message.read(objectName, values);
88 auto findValue = values.find("Value");
89 if (findValue == values.end())
90 {
91 return;
92 }
93 double value = std::visit(VariantToDoubleVisitor(), findValue->second);
94 if (std::isnan(value))
95 {
96 return;
97 }
James Feist9566bfa2019-01-29 15:31:23 -080098
Ed Tanousbb679322022-05-16 16:10:00 -070099 callback(value, message);
100 };
James Feistb2eb3f52018-12-04 16:17:50 -0800101 matches.emplace_back(connection,
102 "type='signal',"
103 "member='PropertiesChanged',interface='org."
104 "freedesktop.DBus.Properties',path_"
105 "namespace='/xyz/openbmc_project/sensors/" +
106 std::string(type) +
107 "',arg0='xyz.openbmc_project.Sensor.Value'",
108 std::move(eventHandler));
109}
110
James Feist13452092019-03-07 16:38:12 -0800111static void setMaxPWM(const std::shared_ptr<sdbusplus::asio::connection>& conn,
112 double value)
113{
114 using GetSubTreeType = std::vector<std::pair<
115 std::string,
116 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
117
118 conn->async_method_call(
119 [conn, value](const boost::system::error_code ec,
120 const GetSubTreeType& ret) {
Ed Tanousbb679322022-05-16 16:10:00 -0700121 if (ec)
122 {
123 std::cerr << "Error calling mapper\n";
124 return;
125 }
126 for (const auto& [path, objDict] : ret)
127 {
128 if (objDict.empty())
James Feist13452092019-03-07 16:38:12 -0800129 {
James Feist13452092019-03-07 16:38:12 -0800130 return;
131 }
Ed Tanousbb679322022-05-16 16:10:00 -0700132 const std::string& owner = objDict.begin()->first;
133
134 conn->async_method_call(
135 [conn, value, owner,
136 path{path}](const boost::system::error_code ec,
137 const std::variant<std::string>& classType) {
138 if (ec)
139 {
140 std::cerr << "Error getting pid class\n";
141 return;
142 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700143 const auto* classStr = std::get_if<std::string>(&classType);
Ed Tanousbb679322022-05-16 16:10:00 -0700144 if (classStr == nullptr || *classStr != "fan")
James Feist13452092019-03-07 16:38:12 -0800145 {
146 return;
147 }
James Feist13452092019-03-07 16:38:12 -0800148 conn->async_method_call(
Ed Tanousbb679322022-05-16 16:10:00 -0700149 [](boost::system::error_code& ec) {
150 if (ec)
151 {
152 std::cerr << "Error setting pid class\n";
153 return;
154 }
Patrick Williams597e8422023-10-20 11:19:01 -0500155 },
Ed Tanousbb679322022-05-16 16:10:00 -0700156 owner, path, "org.freedesktop.DBus.Properties", "Set",
157 pidConfigurationType, "OutLimitMax",
158 std::variant<double>(value));
Patrick Williams597e8422023-10-20 11:19:01 -0500159 },
Ed Tanousbb679322022-05-16 16:10:00 -0700160 owner, path, "org.freedesktop.DBus.Properties", "Get",
161 pidConfigurationType, "Class");
162 }
Patrick Williams597e8422023-10-20 11:19:01 -0500163 },
James Feista5e58722019-04-22 14:43:11 -0700164 mapper::busName, mapper::path, mapper::interface, mapper::subtree, "/",
165 0, std::array<std::string, 1>{pidConfigurationType});
James Feist13452092019-03-07 16:38:12 -0800166}
167
James Feistb2eb3f52018-12-04 16:17:50 -0800168CFMSensor::CFMSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
169 const std::string& sensorName,
170 const std::string& sensorConfiguration,
171 sdbusplus::asio::object_server& objectServer,
James Feistb839c052019-05-15 10:25:24 -0700172 std::vector<thresholds::Threshold>&& thresholdData,
James Feistb2eb3f52018-12-04 16:17:50 -0800173 std::shared_ptr<ExitAirTempSensor>& parent) :
Zhikui Renda98f092021-11-01 09:41:08 -0700174 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -0700175 sensorConfiguration, "CFMSensor", false, false, cfmMaxReading,
176 cfmMinReading, conn, PowerState::on),
Ed Tanous2049bd22022-07-09 07:20:26 -0700177 parent(parent), objServer(objectServer)
James Feistb2eb3f52018-12-04 16:17:50 -0800178{
Basheer Ahmed Muddebihale5b867b2021-07-26 08:32:19 -0700179 sensorInterface = objectServer.add_interface(
180 "/xyz/openbmc_project/sensors/airflow/" + name,
181 "xyz.openbmc_project.Sensor.Value");
James Feistb2eb3f52018-12-04 16:17:50 -0800182
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530183 for (const auto& threshold : thresholds)
James Feistb2eb3f52018-12-04 16:17:50 -0800184 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530185 std::string interface = thresholds::getInterface(threshold.level);
186 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
187 objectServer.add_interface(
188 "/xyz/openbmc_project/sensors/airflow/" + name, interface);
James Feistb2eb3f52018-12-04 16:17:50 -0800189 }
James Feist078f2322019-03-08 11:09:05 -0800190
191 association = objectServer.add_interface(
Basheer Ahmed Muddebihale5b867b2021-07-26 08:32:19 -0700192 "/xyz/openbmc_project/sensors/airflow/" + name, association::interface);
James Feist078f2322019-03-08 11:09:05 -0800193
Andrei Kartashev39287412022-02-04 16:04:47 +0300194 setInitialProperties(sensor_paths::unitCFM);
James Feist9a25ed42019-10-15 15:43:44 -0700195
James Feist13452092019-03-07 16:38:12 -0800196 pwmLimitIface =
197 objectServer.add_interface("/xyz/openbmc_project/control/pwm_limit",
198 "xyz.openbmc_project.Control.PWMLimit");
199 cfmLimitIface =
200 objectServer.add_interface("/xyz/openbmc_project/control/MaxCFM",
201 "xyz.openbmc_project.Control.CFMLimit");
James Feist9a25ed42019-10-15 15:43:44 -0700202}
James Feist13452092019-03-07 16:38:12 -0800203
James Feist9a25ed42019-10-15 15:43:44 -0700204void CFMSensor::setupMatches()
205{
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700206 std::weak_ptr<CFMSensor> weakRef = weak_from_this();
Ed Tanous8a17c302021-09-02 15:07:11 -0700207 setupSensorMatch(
208 matches, *dbusConnection, "fan_tach",
Patrick Williams92f8f512022-07-22 19:26:55 -0500209 [weakRef](const double& value, sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700210 auto self = weakRef.lock();
211 if (!self)
212 {
213 return;
214 }
215 self->tachReadings[message.get_path()] = value;
216 if (self->tachRanges.find(message.get_path()) == self->tachRanges.end())
217 {
218 // calls update reading after updating ranges
219 self->addTachRanges(message.get_sender(), message.get_path());
220 }
221 else
222 {
223 self->updateReading();
224 }
Patrick Williams597e8422023-10-20 11:19:01 -0500225 });
James Feist9a25ed42019-10-15 15:43:44 -0700226
227 dbusConnection->async_method_call(
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700228 [weakRef](const boost::system::error_code ec,
229 const std::variant<double> cfmVariant) {
Ed Tanousbb679322022-05-16 16:10:00 -0700230 auto self = weakRef.lock();
231 if (!self)
232 {
233 return;
234 }
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700235
Ed Tanousbb679322022-05-16 16:10:00 -0700236 uint64_t maxRpm = 100;
237 if (!ec)
238 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700239 const auto* cfm = std::get_if<double>(&cfmVariant);
Ed Tanousbb679322022-05-16 16:10:00 -0700240 if (cfm != nullptr && *cfm >= minSystemCfm)
241 {
242 maxRpm = self->getMaxRpm(*cfm);
James Feist13452092019-03-07 16:38:12 -0800243 }
Ed Tanousbb679322022-05-16 16:10:00 -0700244 }
245 self->pwmLimitIface->register_property("Limit", maxRpm);
246 self->pwmLimitIface->initialize();
247 setMaxPWM(self->dbusConnection, maxRpm);
Patrick Williams597e8422023-10-20 11:19:01 -0500248 },
James Feist13452092019-03-07 16:38:12 -0800249 settingsDaemon, cfmSettingPath, "org.freedesktop.DBus.Properties",
250 "Get", cfmSettingIface, "Limit");
251
Ed Tanousbb679322022-05-16 16:10:00 -0700252 matches.emplace_back(*dbusConnection,
253 "type='signal',"
254 "member='PropertiesChanged',interface='org."
255 "freedesktop.DBus.Properties',path='" +
256 std::string(cfmSettingPath) + "',arg0='" +
257 std::string(cfmSettingIface) + "'",
Patrick Williams92f8f512022-07-22 19:26:55 -0500258 [weakRef](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700259 auto self = weakRef.lock();
260 if (!self)
261 {
262 return;
263 }
264 boost::container::flat_map<std::string, std::variant<double>> values;
265 std::string objectName;
266 message.read(objectName, values);
267 const auto findValue = values.find("Limit");
268 if (findValue == values.end())
269 {
270 return;
271 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700272 auto* const reading = std::get_if<double>(&(findValue->second));
Ed Tanousbb679322022-05-16 16:10:00 -0700273 if (reading == nullptr)
274 {
275 std::cerr << "Got CFM Limit of wrong type\n";
276 return;
277 }
278 if (*reading < minSystemCfm && *reading != 0)
279 {
280 std::cerr << "Illegal CFM setting detected\n";
281 return;
282 }
283 uint64_t maxRpm = self->getMaxRpm(*reading);
284 self->pwmLimitIface->set_property("Limit", maxRpm);
285 setMaxPWM(self->dbusConnection, maxRpm);
286 });
James Feistb2eb3f52018-12-04 16:17:50 -0800287}
288
James Feist9566bfa2019-01-29 15:31:23 -0800289CFMSensor::~CFMSensor()
290{
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530291 for (const auto& iface : thresholdInterfaces)
292 {
293 objServer.remove_interface(iface);
294 }
James Feist9566bfa2019-01-29 15:31:23 -0800295 objServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800296 objServer.remove_interface(association);
James Feist13452092019-03-07 16:38:12 -0800297 objServer.remove_interface(cfmLimitIface);
298 objServer.remove_interface(pwmLimitIface);
299}
300
Ed Tanous201a1012024-04-03 18:07:28 -0700301void CFMSensor::createMaxCFMIface()
James Feist13452092019-03-07 16:38:12 -0800302{
James Feistb6c0b912019-07-09 12:21:44 -0700303 cfmLimitIface->register_property("Limit", c2 * maxCFM * tachs.size());
James Feist13452092019-03-07 16:38:12 -0800304 cfmLimitIface->initialize();
James Feist9566bfa2019-01-29 15:31:23 -0800305}
306
James Feistb2eb3f52018-12-04 16:17:50 -0800307void CFMSensor::addTachRanges(const std::string& serviceName,
308 const std::string& path)
309{
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700310 std::weak_ptr<CFMSensor> weakRef = weak_from_this();
James Feistb2eb3f52018-12-04 16:17:50 -0800311 dbusConnection->async_method_call(
Zev Weissafd15042022-07-18 12:28:40 -0700312 [weakRef, path](const boost::system::error_code ec,
313 const SensorBaseConfigMap& data) {
Ed Tanousbb679322022-05-16 16:10:00 -0700314 if (ec)
315 {
316 std::cerr << "Error getting properties from " << path << "\n";
317 return;
318 }
319 auto self = weakRef.lock();
320 if (!self)
321 {
322 return;
323 }
324 double max = loadVariant<double>(data, "MaxValue");
325 double min = loadVariant<double>(data, "MinValue");
326 self->tachRanges[path] = std::make_pair(min, max);
327 self->updateReading();
Patrick Williams597e8422023-10-20 11:19:01 -0500328 },
James Feistb2eb3f52018-12-04 16:17:50 -0800329 serviceName, path, "org.freedesktop.DBus.Properties", "GetAll",
330 "xyz.openbmc_project.Sensor.Value");
331}
332
Ed Tanous201a1012024-04-03 18:07:28 -0700333void CFMSensor::checkThresholds()
James Feistb2eb3f52018-12-04 16:17:50 -0800334{
335 thresholds::checkThresholds(this);
336}
337
Ed Tanous201a1012024-04-03 18:07:28 -0700338void CFMSensor::updateReading()
James Feistb2eb3f52018-12-04 16:17:50 -0800339{
340 double val = 0.0;
341 if (calculate(val))
342 {
343 if (value != val && parent)
344 {
345 parent->updateReading();
346 }
347 updateValue(val);
348 }
349 else
350 {
351 updateValue(std::numeric_limits<double>::quiet_NaN());
352 }
353}
354
Ed Tanous2049bd22022-07-09 07:20:26 -0700355uint64_t CFMSensor::getMaxRpm(uint64_t cfmMaxSetting) const
James Feist13452092019-03-07 16:38:12 -0800356{
357 uint64_t pwmPercent = 100;
358 double totalCFM = std::numeric_limits<double>::max();
359 if (cfmMaxSetting == 0)
360 {
361 return pwmPercent;
362 }
363
James Feist52427952019-04-05 14:23:35 -0700364 bool firstLoop = true;
James Feist13452092019-03-07 16:38:12 -0800365 while (totalCFM > cfmMaxSetting)
366 {
James Feist52427952019-04-05 14:23:35 -0700367 if (firstLoop)
368 {
369 firstLoop = false;
370 }
371 else
372 {
373 pwmPercent--;
374 }
375
James Feist13452092019-03-07 16:38:12 -0800376 double ci = 0;
377 if (pwmPercent == 0)
378 {
379 ci = 0;
380 }
381 else if (pwmPercent < tachMinPercent)
382 {
383 ci = c1;
384 }
385 else if (pwmPercent > tachMaxPercent)
386 {
387 ci = c2;
388 }
389 else
390 {
391 ci = c1 + (((c2 - c1) * (pwmPercent - tachMinPercent)) /
392 (tachMaxPercent - tachMinPercent));
393 }
394
395 // Now calculate the CFM for this tach
396 // CFMi = Ci * Qmaxi * TACHi
397 totalCFM = ci * maxCFM * pwmPercent;
398 totalCFM *= tachs.size();
399 // divide by 100 since pwm is in percent
400 totalCFM /= 100;
401
James Feist13452092019-03-07 16:38:12 -0800402 if (pwmPercent <= 0)
403 {
404 break;
405 }
406 }
James Feist52427952019-04-05 14:23:35 -0700407
James Feist13452092019-03-07 16:38:12 -0800408 return pwmPercent;
409}
410
James Feistb2eb3f52018-12-04 16:17:50 -0800411bool CFMSensor::calculate(double& value)
412{
413 double totalCFM = 0;
414 for (const std::string& tachName : tachs)
415 {
416 auto findReading = std::find_if(
Zev Weiss6c106d62022-08-17 20:50:00 -0700417 tachReadings.begin(), tachReadings.end(),
418 [&](const auto& item) { return item.first.ends_with(tachName); });
Patrick Williams597e8422023-10-20 11:19:01 -0500419 auto findRange = std::find_if(
420 tachRanges.begin(), tachRanges.end(),
421 [&](const auto& item) { return item.first.ends_with(tachName); });
James Feistb2eb3f52018-12-04 16:17:50 -0800422 if (findReading == tachReadings.end())
423 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700424 if constexpr (debug)
James Feista96329f2019-01-24 10:08:27 -0800425 {
426 std::cerr << "Can't find " << tachName << "in readings\n";
427 }
James Feist9566bfa2019-01-29 15:31:23 -0800428 continue; // haven't gotten a reading
James Feistb2eb3f52018-12-04 16:17:50 -0800429 }
430
431 if (findRange == tachRanges.end())
432 {
James Feist523828e2019-03-04 14:38:37 -0800433 std::cerr << "Can't find " << tachName << " in ranges\n";
James Feistb2eb3f52018-12-04 16:17:50 -0800434 return false; // haven't gotten a max / min
435 }
436
437 // avoid divide by 0
438 if (findRange->second.second == 0)
439 {
440 std::cerr << "Tach Max Set to 0 " << tachName << "\n";
441 return false;
442 }
443
444 double rpm = findReading->second;
445
446 // for now assume the min for a fan is always 0, divide by max to get
447 // percent and mult by 100
448 rpm /= findRange->second.second;
449 rpm *= 100;
450
Ed Tanous8a57ec02020-10-09 12:46:52 -0700451 if constexpr (debug)
James Feistb2eb3f52018-12-04 16:17:50 -0800452 {
453 std::cout << "Tach " << tachName << "at " << rpm << "\n";
454 }
455
456 // Do a linear interpolation to get Ci
457 // Ci = C1 + (C2 - C1)/(RPM2 - RPM1) * (TACHi - TACH1)
458
459 double ci = 0;
460 if (rpm == 0)
461 {
462 ci = 0;
463 }
464 else if (rpm < tachMinPercent)
465 {
466 ci = c1;
467 }
468 else if (rpm > tachMaxPercent)
469 {
470 ci = c2;
471 }
472 else
473 {
474 ci = c1 + (((c2 - c1) * (rpm - tachMinPercent)) /
475 (tachMaxPercent - tachMinPercent));
476 }
477
478 // Now calculate the CFM for this tach
479 // CFMi = Ci * Qmaxi * TACHi
480 totalCFM += ci * maxCFM * rpm;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700481 if constexpr (debug)
James Feista5e58722019-04-22 14:43:11 -0700482 {
483 std::cerr << "totalCFM = " << totalCFM << "\n";
484 std::cerr << "Ci " << ci << " MaxCFM " << maxCFM << " rpm " << rpm
485 << "\n";
486 std::cerr << "c1 " << c1 << " c2 " << c2 << " max "
487 << tachMaxPercent << " min " << tachMinPercent << "\n";
488 }
James Feistb2eb3f52018-12-04 16:17:50 -0800489 }
490
491 // divide by 100 since rpm is in percent
492 value = totalCFM / 100;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700493 if constexpr (debug)
James Feista5e58722019-04-22 14:43:11 -0700494 {
495 std::cerr << "cfm value = " << value << "\n";
496 }
James Feist9566bfa2019-01-29 15:31:23 -0800497 return true;
James Feistb2eb3f52018-12-04 16:17:50 -0800498}
499
500static constexpr double exitAirMaxReading = 127;
501static constexpr double exitAirMinReading = -128;
James Feistbc896df2018-11-26 16:28:17 -0800502ExitAirTempSensor::ExitAirTempSensor(
503 std::shared_ptr<sdbusplus::asio::connection>& conn,
James Feistb2eb3f52018-12-04 16:17:50 -0800504 const std::string& sensorName, const std::string& sensorConfiguration,
James Feistbc896df2018-11-26 16:28:17 -0800505 sdbusplus::asio::object_server& objectServer,
James Feistb839c052019-05-15 10:25:24 -0700506 std::vector<thresholds::Threshold>&& thresholdData) :
Zhikui Renda98f092021-11-01 09:41:08 -0700507 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -0700508 sensorConfiguration, "ExitAirTemp", false, false, exitAirMaxReading,
509 exitAirMinReading, conn, PowerState::on),
Ed Tanous2049bd22022-07-09 07:20:26 -0700510 objServer(objectServer)
James Feistbc896df2018-11-26 16:28:17 -0800511{
512 sensorInterface = objectServer.add_interface(
513 "/xyz/openbmc_project/sensors/temperature/" + name,
514 "xyz.openbmc_project.Sensor.Value");
515
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530516 for (const auto& threshold : thresholds)
James Feistbc896df2018-11-26 16:28:17 -0800517 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530518 std::string interface = thresholds::getInterface(threshold.level);
519 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
520 objectServer.add_interface(
521 "/xyz/openbmc_project/sensors/temperature/" + name, interface);
James Feistbc896df2018-11-26 16:28:17 -0800522 }
James Feist078f2322019-03-08 11:09:05 -0800523 association = objectServer.add_interface(
524 "/xyz/openbmc_project/sensors/temperature/" + name,
James Feist2adc95c2019-09-30 14:55:28 -0700525 association::interface);
Andrei Kartashev39287412022-02-04 16:04:47 +0300526 setInitialProperties(sensor_paths::unitDegreesC);
James Feistbc896df2018-11-26 16:28:17 -0800527}
528
529ExitAirTempSensor::~ExitAirTempSensor()
530{
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530531 for (const auto& iface : thresholdInterfaces)
532 {
533 objServer.remove_interface(iface);
534 }
James Feist523828e2019-03-04 14:38:37 -0800535 objServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800536 objServer.remove_interface(association);
James Feistbc896df2018-11-26 16:28:17 -0800537}
538
Ed Tanous201a1012024-04-03 18:07:28 -0700539void ExitAirTempSensor::setupMatches()
James Feistbc896df2018-11-26 16:28:17 -0800540{
Brandon Kim66558232021-11-09 16:53:08 -0800541 constexpr const auto matchTypes{
542 std::to_array<const char*>({"power", inletTemperatureSensor})};
James Feistbc896df2018-11-26 16:28:17 -0800543
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700544 std::weak_ptr<ExitAirTempSensor> weakRef = weak_from_this();
Ed Tanous13b63f82021-05-11 16:12:52 -0700545 for (const std::string type : matchTypes)
James Feistbc896df2018-11-26 16:28:17 -0800546 {
James Feistb2eb3f52018-12-04 16:17:50 -0800547 setupSensorMatch(matches, *dbusConnection, type,
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700548 [weakRef, type](const double& value,
Patrick Williams92f8f512022-07-22 19:26:55 -0500549 sdbusplus::message_t& message) {
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700550 auto self = weakRef.lock();
551 if (!self)
552 {
553 return;
554 }
Ed Tanousbb679322022-05-16 16:10:00 -0700555 if (type == "power")
556 {
557 std::string path = message.get_path();
558 if (path.find("PS") != std::string::npos &&
Zev Weiss6c106d62022-08-17 20:50:00 -0700559 path.ends_with("Input_Power"))
Ed Tanousbb679322022-05-16 16:10:00 -0700560 {
561 self->powerReadings[message.get_path()] = value;
562 }
563 }
564 else if (type == inletTemperatureSensor)
565 {
566 self->inletTemp = value;
567 }
568 self->updateReading();
569 });
570 }
571 dbusConnection->async_method_call(
572 [weakRef](boost::system::error_code ec,
573 const std::variant<double>& value) {
574 if (ec)
575 {
576 // sensor not ready yet
577 return;
578 }
579 auto self = weakRef.lock();
580 if (!self)
581 {
582 return;
583 }
584 self->inletTemp = std::visit(VariantToDoubleVisitor(), value);
Patrick Williams597e8422023-10-20 11:19:01 -0500585 },
James Feist9566bfa2019-01-29 15:31:23 -0800586 "xyz.openbmc_project.HwmonTempSensor",
587 std::string("/xyz/openbmc_project/sensors/") + inletTemperatureSensor,
James Feista5e58722019-04-22 14:43:11 -0700588 properties::interface, properties::get, sensorValueInterface, "Value");
589 dbusConnection->async_method_call(
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700590 [weakRef](boost::system::error_code ec, const GetSubTreeType& subtree) {
Ed Tanousbb679322022-05-16 16:10:00 -0700591 if (ec)
592 {
593 std::cerr << "Error contacting mapper\n";
594 return;
595 }
596 auto self = weakRef.lock();
597 if (!self)
598 {
599 return;
600 }
Zev Weiss72f322f2022-08-12 18:21:01 -0700601 for (const auto& [path, matches] : subtree)
Ed Tanousbb679322022-05-16 16:10:00 -0700602 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700603 size_t lastSlash = path.rfind('/');
604 if (lastSlash == std::string::npos || lastSlash == path.size() ||
605 matches.empty())
James Feista5e58722019-04-22 14:43:11 -0700606 {
Ed Tanousbb679322022-05-16 16:10:00 -0700607 continue;
James Feista5e58722019-04-22 14:43:11 -0700608 }
Zev Weiss72f322f2022-08-12 18:21:01 -0700609 std::string sensorName = path.substr(lastSlash + 1);
Zev Weiss6c106d62022-08-17 20:50:00 -0700610 if (sensorName.starts_with("PS") &&
611 sensorName.ends_with("Input_Power"))
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700612 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700613 // lambda capture requires a proper variable (not a structured
614 // binding)
615 const std::string& cbPath = path;
Ed Tanousbb679322022-05-16 16:10:00 -0700616 self->dbusConnection->async_method_call(
Zev Weiss72f322f2022-08-12 18:21:01 -0700617 [weakRef, cbPath](boost::system::error_code ec,
618 const std::variant<double>& value) {
Ed Tanousbb679322022-05-16 16:10:00 -0700619 if (ec)
620 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700621 std::cerr << "Error getting value from " << cbPath
Ed Tanousbb679322022-05-16 16:10:00 -0700622 << "\n";
623 }
624 auto self = weakRef.lock();
625 if (!self)
626 {
627 return;
628 }
Patrick Williams779c96a2023-05-10 07:50:42 -0500629 double reading = std::visit(VariantToDoubleVisitor(),
630 value);
Ed Tanousbb679322022-05-16 16:10:00 -0700631 if constexpr (debug)
632 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700633 std::cerr << cbPath << "Reading " << reading << "\n";
Ed Tanousbb679322022-05-16 16:10:00 -0700634 }
Zev Weiss72f322f2022-08-12 18:21:01 -0700635 self->powerReadings[cbPath] = reading;
Patrick Williams597e8422023-10-20 11:19:01 -0500636 },
Zev Weiss72f322f2022-08-12 18:21:01 -0700637 matches[0].first, cbPath, properties::interface,
Ed Tanousbb679322022-05-16 16:10:00 -0700638 properties::get, sensorValueInterface, "Value");
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700639 }
Ed Tanousbb679322022-05-16 16:10:00 -0700640 }
Patrick Williams597e8422023-10-20 11:19:01 -0500641 },
James Feista5e58722019-04-22 14:43:11 -0700642 mapper::busName, mapper::path, mapper::interface, mapper::subtree,
643 "/xyz/openbmc_project/sensors/power", 0,
644 std::array<const char*, 1>{sensorValueInterface});
James Feistbc896df2018-11-26 16:28:17 -0800645}
646
Ed Tanous201a1012024-04-03 18:07:28 -0700647void ExitAirTempSensor::updateReading()
James Feistbc896df2018-11-26 16:28:17 -0800648{
James Feistbc896df2018-11-26 16:28:17 -0800649 double val = 0.0;
650 if (calculate(val))
651 {
James Feist18af4232019-03-13 11:14:00 -0700652 val = std::floor(val + 0.5);
James Feistbc896df2018-11-26 16:28:17 -0800653 updateValue(val);
654 }
655 else
656 {
657 updateValue(std::numeric_limits<double>::quiet_NaN());
658 }
659}
660
Ed Tanous201a1012024-04-03 18:07:28 -0700661double ExitAirTempSensor::getTotalCFM()
James Feistbc896df2018-11-26 16:28:17 -0800662{
James Feistb2eb3f52018-12-04 16:17:50 -0800663 double sum = 0;
664 for (auto& sensor : cfmSensors)
James Feistbc896df2018-11-26 16:28:17 -0800665 {
James Feistb2eb3f52018-12-04 16:17:50 -0800666 double reading = 0;
667 if (!sensor->calculate(reading))
James Feistbc896df2018-11-26 16:28:17 -0800668 {
James Feistbc896df2018-11-26 16:28:17 -0800669 return -1;
670 }
James Feistb2eb3f52018-12-04 16:17:50 -0800671 sum += reading;
James Feistbc896df2018-11-26 16:28:17 -0800672 }
James Feistb2eb3f52018-12-04 16:17:50 -0800673
674 return sum;
James Feistbc896df2018-11-26 16:28:17 -0800675}
676
677bool ExitAirTempSensor::calculate(double& val)
678{
Zhikui Ren12e3d672020-12-03 15:14:49 -0800679 constexpr size_t maxErrorPrint = 5;
James Feistbc896df2018-11-26 16:28:17 -0800680 static bool firstRead = false;
James Feistae11cfc2019-05-07 15:01:20 -0700681 static size_t errorPrint = maxErrorPrint;
682
James Feistbc896df2018-11-26 16:28:17 -0800683 double cfm = getTotalCFM();
684 if (cfm <= 0)
685 {
686 std::cerr << "Error getting cfm\n";
687 return false;
688 }
689
Zhikui Ren12e3d672020-12-03 15:14:49 -0800690 // Though cfm is not expected to be less than qMin normally,
691 // it is not a hard limit for exit air temp calculation.
692 // 50% qMin is chosen as a generic limit between providing
693 // a valid derived exit air temp and reporting exit air temp not available.
694 constexpr const double cfmLimitFactor = 0.5;
695 if (cfm < (qMin * cfmLimitFactor))
696 {
697 if (errorPrint > 0)
698 {
699 errorPrint--;
700 std::cerr << "cfm " << cfm << " is too low, expected qMin " << qMin
701 << "\n";
702 }
703 val = 0;
704 return false;
705 }
706
James Feistbc896df2018-11-26 16:28:17 -0800707 // if there is an error getting inlet temp, return error
708 if (std::isnan(inletTemp))
709 {
James Feistae11cfc2019-05-07 15:01:20 -0700710 if (errorPrint > 0)
711 {
712 errorPrint--;
713 std::cerr << "Cannot get inlet temp\n";
714 }
James Feistbc896df2018-11-26 16:28:17 -0800715 val = 0;
716 return false;
717 }
718
719 // if fans are off, just make the exit temp equal to inlet
James Feist71d31b22019-01-02 16:57:54 -0800720 if (!isPowerOn())
James Feistbc896df2018-11-26 16:28:17 -0800721 {
722 val = inletTemp;
723 return true;
724 }
725
726 double totalPower = 0;
Zev Weiss72f322f2022-08-12 18:21:01 -0700727 for (const auto& [path, reading] : powerReadings)
James Feistbc896df2018-11-26 16:28:17 -0800728 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700729 if (std::isnan(reading))
James Feistbc896df2018-11-26 16:28:17 -0800730 {
731 continue;
732 }
Zev Weiss72f322f2022-08-12 18:21:01 -0700733 totalPower += reading;
James Feistbc896df2018-11-26 16:28:17 -0800734 }
735
736 // Calculate power correction factor
737 // Ci = CL + (CH - CL)/(QMax - QMin) * (CFM - QMin)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700738 double powerFactor = 0.0;
James Feistbc896df2018-11-26 16:28:17 -0800739 if (cfm <= qMin)
740 {
741 powerFactor = powerFactorMin;
742 }
743 else if (cfm >= qMax)
744 {
745 powerFactor = powerFactorMax;
746 }
747 else
748 {
749 powerFactor = powerFactorMin + ((powerFactorMax - powerFactorMin) /
750 (qMax - qMin) * (cfm - qMin));
751 }
752
Ed Tanous8a57ec02020-10-09 12:46:52 -0700753 totalPower *= powerFactor;
James Feistbc896df2018-11-26 16:28:17 -0800754 totalPower += pOffset;
755
756 if (totalPower == 0)
757 {
James Feistae11cfc2019-05-07 15:01:20 -0700758 if (errorPrint > 0)
759 {
760 errorPrint--;
761 std::cerr << "total power 0\n";
762 }
James Feistbc896df2018-11-26 16:28:17 -0800763 val = 0;
764 return false;
765 }
766
Ed Tanous8a57ec02020-10-09 12:46:52 -0700767 if constexpr (debug)
James Feistbc896df2018-11-26 16:28:17 -0800768 {
769 std::cout << "Power Factor " << powerFactor << "\n";
770 std::cout << "Inlet Temp " << inletTemp << "\n";
771 std::cout << "Total Power" << totalPower << "\n";
772 }
773
774 // Calculate the exit air temp
775 // Texit = Tfp + (1.76 * TotalPower / CFM * Faltitude)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700776 double reading = 1.76 * totalPower * altitudeFactor;
James Feistbc896df2018-11-26 16:28:17 -0800777 reading /= cfm;
778 reading += inletTemp;
779
Ed Tanous8a57ec02020-10-09 12:46:52 -0700780 if constexpr (debug)
James Feistbc896df2018-11-26 16:28:17 -0800781 {
782 std::cout << "Reading 1: " << reading << "\n";
783 }
784
785 // Now perform the exponential average
786 // Calculate alpha based on SDR values and CFM
787 // Ai = As + (Af - As)/(QMax - QMin) * (CFM - QMin)
788
789 double alpha = 0.0;
790 if (cfm < qMin)
791 {
792 alpha = alphaS;
793 }
794 else if (cfm >= qMax)
795 {
796 alpha = alphaF;
797 }
798 else
799 {
800 alpha = alphaS + ((alphaF - alphaS) * (cfm - qMin) / (qMax - qMin));
801 }
802
Zhikui Ren12e3d672020-12-03 15:14:49 -0800803 auto time = std::chrono::steady_clock::now();
James Feistbc896df2018-11-26 16:28:17 -0800804 if (!firstRead)
805 {
806 firstRead = true;
807 lastTime = time;
808 lastReading = reading;
809 }
810 double alphaDT =
811 std::chrono::duration_cast<std::chrono::seconds>(time - lastTime)
812 .count() *
813 alpha;
814
815 // cap at 1.0 or the below fails
816 if (alphaDT > 1.0)
817 {
818 alphaDT = 1.0;
819 }
820
Ed Tanous8a57ec02020-10-09 12:46:52 -0700821 if constexpr (debug)
James Feistbc896df2018-11-26 16:28:17 -0800822 {
823 std::cout << "AlphaDT: " << alphaDT << "\n";
824 }
825
826 reading = ((reading * alphaDT) + (lastReading * (1.0 - alphaDT)));
827
Ed Tanous8a57ec02020-10-09 12:46:52 -0700828 if constexpr (debug)
James Feistbc896df2018-11-26 16:28:17 -0800829 {
830 std::cout << "Reading 2: " << reading << "\n";
831 }
832
833 val = reading;
834 lastReading = reading;
835 lastTime = time;
James Feistae11cfc2019-05-07 15:01:20 -0700836 errorPrint = maxErrorPrint;
James Feistbc896df2018-11-26 16:28:17 -0800837 return true;
838}
839
Ed Tanous201a1012024-04-03 18:07:28 -0700840void ExitAirTempSensor::checkThresholds()
James Feistbc896df2018-11-26 16:28:17 -0800841{
842 thresholds::checkThresholds(this);
843}
844
Zev Weissafd15042022-07-18 12:28:40 -0700845static void loadVariantPathArray(const SensorBaseConfigMap& data,
846 const std::string& key,
847 std::vector<std::string>& resp)
James Feistbc896df2018-11-26 16:28:17 -0800848{
849 auto it = data.find(key);
850 if (it == data.end())
851 {
852 std::cerr << "Configuration missing " << key << "\n";
853 throw std::invalid_argument("Key Missing");
854 }
855 BasicVariantType copy = it->second;
James Feist3eb82622019-02-08 13:10:22 -0800856 std::vector<std::string> config = std::get<std::vector<std::string>>(copy);
James Feistbc896df2018-11-26 16:28:17 -0800857 for (auto& str : config)
858 {
859 boost::replace_all(str, " ", "_");
860 }
861 resp = std::move(config);
862}
863
864void createSensor(sdbusplus::asio::object_server& objectServer,
James Feistb2eb3f52018-12-04 16:17:50 -0800865 std::shared_ptr<ExitAirTempSensor>& exitAirSensor,
James Feistbc896df2018-11-26 16:28:17 -0800866 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
867{
868 if (!dbusConnection)
869 {
870 std::cerr << "Connection not created\n";
871 return;
872 }
James Feist655f3762020-10-05 15:28:15 -0700873 auto getter = std::make_shared<GetSensorConfiguration>(
Patrick Williams597e8422023-10-20 11:19:01 -0500874 dbusConnection, [&objectServer, &dbusConnection,
875 &exitAirSensor](const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700876 cfmSensors.clear();
Zev Weiss72f322f2022-08-12 18:21:01 -0700877 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700878 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700879 for (const auto& [intf, cfg] : interfaces)
James Feistbc896df2018-11-26 16:28:17 -0800880 {
Zev Weiss054aad82022-08-18 01:37:34 -0700881 if (intf == configInterfaceName(exitAirType))
James Feistbc896df2018-11-26 16:28:17 -0800882 {
Ed Tanousbb679322022-05-16 16:10:00 -0700883 // thresholds should be under the same path
884 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss72f322f2022-08-12 18:21:01 -0700885 parseThresholdsFromConfig(interfaces, sensorThresholds);
James Feistbc896df2018-11-26 16:28:17 -0800886
Zev Weiss72f322f2022-08-12 18:21:01 -0700887 std::string name = loadVariant<std::string>(cfg, "Name");
Matt Simmeringbcb062a2023-12-13 15:13:03 -0800888 exitAirSensor = nullptr;
Ed Tanousbb679322022-05-16 16:10:00 -0700889 exitAirSensor = std::make_shared<ExitAirTempSensor>(
Zev Weiss72f322f2022-08-12 18:21:01 -0700890 dbusConnection, name, path.str, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700891 std::move(sensorThresholds));
892 exitAirSensor->powerFactorMin =
Zev Weiss72f322f2022-08-12 18:21:01 -0700893 loadVariant<double>(cfg, "PowerFactorMin");
Ed Tanousbb679322022-05-16 16:10:00 -0700894 exitAirSensor->powerFactorMax =
Zev Weiss72f322f2022-08-12 18:21:01 -0700895 loadVariant<double>(cfg, "PowerFactorMax");
896 exitAirSensor->qMin = loadVariant<double>(cfg, "QMin");
897 exitAirSensor->qMax = loadVariant<double>(cfg, "QMax");
898 exitAirSensor->alphaS = loadVariant<double>(cfg, "AlphaS");
899 exitAirSensor->alphaF = loadVariant<double>(cfg, "AlphaF");
Ed Tanousbb679322022-05-16 16:10:00 -0700900 }
Zev Weiss054aad82022-08-18 01:37:34 -0700901 else if (intf == configInterfaceName(cfmType))
Ed Tanousbb679322022-05-16 16:10:00 -0700902 {
903 // thresholds should be under the same path
904 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss72f322f2022-08-12 18:21:01 -0700905 parseThresholdsFromConfig(interfaces, sensorThresholds);
906 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700907 auto sensor = std::make_shared<CFMSensor>(
Zev Weiss72f322f2022-08-12 18:21:01 -0700908 dbusConnection, name, path.str, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700909 std::move(sensorThresholds), exitAirSensor);
Zev Weiss72f322f2022-08-12 18:21:01 -0700910 loadVariantPathArray(cfg, "Tachs", sensor->tachs);
911 sensor->maxCFM = loadVariant<double>(cfg, "MaxCFM");
James Feistbc896df2018-11-26 16:28:17 -0800912
Ed Tanousbb679322022-05-16 16:10:00 -0700913 // change these into percent upon getting the data
Zev Weiss72f322f2022-08-12 18:21:01 -0700914 sensor->c1 = loadVariant<double>(cfg, "C1") / 100;
915 sensor->c2 = loadVariant<double>(cfg, "C2") / 100;
Ed Tanousbb679322022-05-16 16:10:00 -0700916 sensor->tachMinPercent =
Zev Weiss72f322f2022-08-12 18:21:01 -0700917 loadVariant<double>(cfg, "TachMinPercent");
Ed Tanousbb679322022-05-16 16:10:00 -0700918 sensor->tachMaxPercent =
Zev Weiss72f322f2022-08-12 18:21:01 -0700919 loadVariant<double>(cfg, "TachMaxPercent");
Ed Tanousbb679322022-05-16 16:10:00 -0700920 sensor->createMaxCFMIface();
921 sensor->setupMatches();
James Feistbc896df2018-11-26 16:28:17 -0800922
Ed Tanousbb679322022-05-16 16:10:00 -0700923 cfmSensors.emplace_back(std::move(sensor));
James Feistbc896df2018-11-26 16:28:17 -0800924 }
925 }
Ed Tanousbb679322022-05-16 16:10:00 -0700926 }
927 if (exitAirSensor)
928 {
929 exitAirSensor->setupMatches();
930 exitAirSensor->updateReading();
931 }
Patrick Williams597e8422023-10-20 11:19:01 -0500932 });
James Feist655f3762020-10-05 15:28:15 -0700933 getter->getConfiguration(
Zev Weiss054aad82022-08-18 01:37:34 -0700934 std::vector<std::string>(monitorTypes.begin(), monitorTypes.end()));
James Feistbc896df2018-11-26 16:28:17 -0800935}
936
James Feistb6c0b912019-07-09 12:21:44 -0700937int main()
James Feistbc896df2018-11-26 16:28:17 -0800938{
Ed Tanous1f978632023-02-28 18:16:39 -0800939 boost::asio::io_context io;
James Feistbc896df2018-11-26 16:28:17 -0800940 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Johnathan Mantey661d4372022-10-27 09:00:59 -0700941 sdbusplus::asio::object_server objectServer(systemBus, true);
942 objectServer.add_manager("/xyz/openbmc_project/sensors");
James Feistbc896df2018-11-26 16:28:17 -0800943 systemBus->request_name("xyz.openbmc_project.ExitAirTempSensor");
James Feistbc896df2018-11-26 16:28:17 -0800944 std::shared_ptr<ExitAirTempSensor> sensor =
945 nullptr; // wait until we find the config
James Feistbc896df2018-11-26 16:28:17 -0800946
Ed Tanous83db50c2023-03-01 10:20:24 -0800947 boost::asio::post(io,
948 [&]() { createSensor(objectServer, sensor, systemBus); });
James Feistbc896df2018-11-26 16:28:17 -0800949
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700950 boost::asio::steady_timer configTimer(io);
James Feistbc896df2018-11-26 16:28:17 -0800951
Patrick Williams92f8f512022-07-22 19:26:55 -0500952 std::function<void(sdbusplus::message_t&)> eventHandler =
953 [&](sdbusplus::message_t&) {
Ed Tanous83db50c2023-03-01 10:20:24 -0800954 configTimer.expires_after(std::chrono::seconds(1));
Ed Tanousbb679322022-05-16 16:10:00 -0700955 // create a timer because normally multiple properties change
956 configTimer.async_wait([&](const boost::system::error_code& ec) {
957 if (ec == boost::asio::error::operation_aborted)
958 {
959 return; // we're being canceled
960 }
961 createSensor(objectServer, sensor, systemBus);
962 if (!sensor)
963 {
964 std::cout << "Configuration not detected\n";
965 }
966 });
967 };
Zev Weiss214d9712022-08-12 12:54:31 -0700968 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
Zev Weiss054aad82022-08-18 01:37:34 -0700969 setupPropertiesChangedMatches(*systemBus, monitorTypes, eventHandler);
James Feistbc896df2018-11-26 16:28:17 -0800970
Bruce Lee913d4d02021-07-22 10:18:42 +0800971 setupManufacturingModeMatch(*systemBus);
James Feistbc896df2018-11-26 16:28:17 -0800972 io.run();
Zhikui Ren8685b172021-06-29 15:16:52 -0700973 return 0;
James Feistbc896df2018-11-26 16:28:17 -0800974}