blob: f235c26ee8324d96b7b866d4850c3149941fdaec [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
19#include "Utils.hpp"
20#include "VariantVisitors.hpp"
21
James Feistbc896df2018-11-26 16:28:17 -080022#include <boost/algorithm/string/replace.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070023#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070024#include <sdbusplus/asio/connection.hpp>
25#include <sdbusplus/asio/object_server.hpp>
26#include <sdbusplus/bus/match.hpp>
27
28#include <array>
James Feistbc896df2018-11-26 16:28:17 -080029#include <chrono>
Patrick Venture96e97db2019-10-31 13:44:38 -070030#include <cmath>
31#include <functional>
James Feistbc896df2018-11-26 16:28:17 -080032#include <iostream>
33#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070034#include <memory>
James Feistbc896df2018-11-26 16:28:17 -080035#include <numeric>
Patrick Venture96e97db2019-10-31 13:44:38 -070036#include <stdexcept>
37#include <utility>
38#include <variant>
James Feistbc896df2018-11-26 16:28:17 -080039#include <vector>
40
Ed Tanous8a57ec02020-10-09 12:46:52 -070041constexpr const double altitudeFactor = 1.14;
Zev Weiss054aad82022-08-18 01:37:34 -070042constexpr const char* exitAirType = "ExitAirTempSensor";
43constexpr const char* cfmType = "CFMSensor";
James Feistbc896df2018-11-26 16:28:17 -080044
45// todo: this *might* need to be configurable
46constexpr const char* inletTemperatureSensor = "temperature/Front_Panel_Temp";
James Feist13452092019-03-07 16:38:12 -080047constexpr const char* pidConfigurationType =
48 "xyz.openbmc_project.Configuration.Pid";
49constexpr const char* settingsDaemon = "xyz.openbmc_project.Settings";
50constexpr const char* cfmSettingPath = "/xyz/openbmc_project/control/cfm_limit";
51constexpr const char* cfmSettingIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistbc896df2018-11-26 16:28:17 -080052
Ed Tanous8a57ec02020-10-09 12:46:52 -070053static constexpr bool debug = false;
James Feistbc896df2018-11-26 16:28:17 -080054
James Feistb2eb3f52018-12-04 16:17:50 -080055static constexpr double cfmMaxReading = 255;
56static constexpr double cfmMinReading = 0;
57
James Feist13452092019-03-07 16:38:12 -080058static constexpr size_t minSystemCfm = 50;
59
Zev Weiss054aad82022-08-18 01:37:34 -070060constexpr const auto monitorTypes{
61 std::to_array<const char*>({exitAirType, cfmType})};
James Feist655f3762020-10-05 15:28:15 -070062
James Feist9a25ed42019-10-15 15:43:44 -070063static std::vector<std::shared_ptr<CFMSensor>> cfmSensors;
64
James Feistb2eb3f52018-12-04 16:17:50 -080065static void setupSensorMatch(
Patrick Williams92f8f512022-07-22 19:26:55 -050066 std::vector<sdbusplus::bus::match_t>& matches, sdbusplus::bus_t& connection,
67 const std::string& type,
68 std::function<void(const double&, sdbusplus::message_t&)>&& callback)
James Feistb2eb3f52018-12-04 16:17:50 -080069{
Patrick Williams92f8f512022-07-22 19:26:55 -050070 std::function<void(sdbusplus::message_t & message)> eventHandler =
71 [callback{std::move(callback)}](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -070072 std::string objectName;
73 boost::container::flat_map<std::string, std::variant<double, int64_t>>
74 values;
75 message.read(objectName, values);
76 auto findValue = values.find("Value");
77 if (findValue == values.end())
78 {
79 return;
80 }
81 double value = std::visit(VariantToDoubleVisitor(), findValue->second);
82 if (std::isnan(value))
83 {
84 return;
85 }
James Feist9566bfa2019-01-29 15:31:23 -080086
Ed Tanousbb679322022-05-16 16:10:00 -070087 callback(value, message);
88 };
James Feistb2eb3f52018-12-04 16:17:50 -080089 matches.emplace_back(connection,
90 "type='signal',"
91 "member='PropertiesChanged',interface='org."
92 "freedesktop.DBus.Properties',path_"
93 "namespace='/xyz/openbmc_project/sensors/" +
94 std::string(type) +
95 "',arg0='xyz.openbmc_project.Sensor.Value'",
96 std::move(eventHandler));
97}
98
James Feist13452092019-03-07 16:38:12 -080099static void setMaxPWM(const std::shared_ptr<sdbusplus::asio::connection>& conn,
100 double value)
101{
102 using GetSubTreeType = std::vector<std::pair<
103 std::string,
104 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
105
106 conn->async_method_call(
107 [conn, value](const boost::system::error_code ec,
108 const GetSubTreeType& ret) {
Ed Tanousbb679322022-05-16 16:10:00 -0700109 if (ec)
110 {
111 std::cerr << "Error calling mapper\n";
112 return;
113 }
114 for (const auto& [path, objDict] : ret)
115 {
116 if (objDict.empty())
James Feist13452092019-03-07 16:38:12 -0800117 {
James Feist13452092019-03-07 16:38:12 -0800118 return;
119 }
Ed Tanousbb679322022-05-16 16:10:00 -0700120 const std::string& owner = objDict.begin()->first;
121
122 conn->async_method_call(
123 [conn, value, owner,
124 path{path}](const boost::system::error_code ec,
125 const std::variant<std::string>& classType) {
126 if (ec)
127 {
128 std::cerr << "Error getting pid class\n";
129 return;
130 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700131 const auto* classStr = std::get_if<std::string>(&classType);
Ed Tanousbb679322022-05-16 16:10:00 -0700132 if (classStr == nullptr || *classStr != "fan")
James Feist13452092019-03-07 16:38:12 -0800133 {
134 return;
135 }
James Feist13452092019-03-07 16:38:12 -0800136 conn->async_method_call(
Ed Tanousbb679322022-05-16 16:10:00 -0700137 [](boost::system::error_code& ec) {
138 if (ec)
139 {
140 std::cerr << "Error setting pid class\n";
141 return;
142 }
Patrick Williams597e8422023-10-20 11:19:01 -0500143 },
Ed Tanousbb679322022-05-16 16:10:00 -0700144 owner, path, "org.freedesktop.DBus.Properties", "Set",
145 pidConfigurationType, "OutLimitMax",
146 std::variant<double>(value));
Patrick Williams597e8422023-10-20 11:19:01 -0500147 },
Ed Tanousbb679322022-05-16 16:10:00 -0700148 owner, path, "org.freedesktop.DBus.Properties", "Get",
149 pidConfigurationType, "Class");
150 }
Patrick Williams597e8422023-10-20 11:19:01 -0500151 },
James Feista5e58722019-04-22 14:43:11 -0700152 mapper::busName, mapper::path, mapper::interface, mapper::subtree, "/",
153 0, std::array<std::string, 1>{pidConfigurationType});
James Feist13452092019-03-07 16:38:12 -0800154}
155
James Feistb2eb3f52018-12-04 16:17:50 -0800156CFMSensor::CFMSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
157 const std::string& sensorName,
158 const std::string& sensorConfiguration,
159 sdbusplus::asio::object_server& objectServer,
James Feistb839c052019-05-15 10:25:24 -0700160 std::vector<thresholds::Threshold>&& thresholdData,
James Feistb2eb3f52018-12-04 16:17:50 -0800161 std::shared_ptr<ExitAirTempSensor>& parent) :
Zhikui Renda98f092021-11-01 09:41:08 -0700162 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -0700163 sensorConfiguration, "CFMSensor", false, false, cfmMaxReading,
164 cfmMinReading, conn, PowerState::on),
Ed Tanous2049bd22022-07-09 07:20:26 -0700165 parent(parent), objServer(objectServer)
James Feistb2eb3f52018-12-04 16:17:50 -0800166{
Basheer Ahmed Muddebihale5b867b2021-07-26 08:32:19 -0700167 sensorInterface = objectServer.add_interface(
168 "/xyz/openbmc_project/sensors/airflow/" + name,
169 "xyz.openbmc_project.Sensor.Value");
James Feistb2eb3f52018-12-04 16:17:50 -0800170
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530171 for (const auto& threshold : thresholds)
James Feistb2eb3f52018-12-04 16:17:50 -0800172 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530173 std::string interface = thresholds::getInterface(threshold.level);
174 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
175 objectServer.add_interface(
176 "/xyz/openbmc_project/sensors/airflow/" + name, interface);
James Feistb2eb3f52018-12-04 16:17:50 -0800177 }
James Feist078f2322019-03-08 11:09:05 -0800178
179 association = objectServer.add_interface(
Basheer Ahmed Muddebihale5b867b2021-07-26 08:32:19 -0700180 "/xyz/openbmc_project/sensors/airflow/" + name, association::interface);
James Feist078f2322019-03-08 11:09:05 -0800181
Andrei Kartashev39287412022-02-04 16:04:47 +0300182 setInitialProperties(sensor_paths::unitCFM);
James Feist9a25ed42019-10-15 15:43:44 -0700183
James Feist13452092019-03-07 16:38:12 -0800184 pwmLimitIface =
185 objectServer.add_interface("/xyz/openbmc_project/control/pwm_limit",
186 "xyz.openbmc_project.Control.PWMLimit");
187 cfmLimitIface =
188 objectServer.add_interface("/xyz/openbmc_project/control/MaxCFM",
189 "xyz.openbmc_project.Control.CFMLimit");
James Feist9a25ed42019-10-15 15:43:44 -0700190}
James Feist13452092019-03-07 16:38:12 -0800191
James Feist9a25ed42019-10-15 15:43:44 -0700192void CFMSensor::setupMatches()
193{
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700194 std::weak_ptr<CFMSensor> weakRef = weak_from_this();
Ed Tanous8a17c302021-09-02 15:07:11 -0700195 setupSensorMatch(
196 matches, *dbusConnection, "fan_tach",
Patrick Williams92f8f512022-07-22 19:26:55 -0500197 [weakRef](const double& value, sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700198 auto self = weakRef.lock();
199 if (!self)
200 {
201 return;
202 }
203 self->tachReadings[message.get_path()] = value;
204 if (self->tachRanges.find(message.get_path()) == self->tachRanges.end())
205 {
206 // calls update reading after updating ranges
207 self->addTachRanges(message.get_sender(), message.get_path());
208 }
209 else
210 {
211 self->updateReading();
212 }
Patrick Williams597e8422023-10-20 11:19:01 -0500213 });
James Feist9a25ed42019-10-15 15:43:44 -0700214
215 dbusConnection->async_method_call(
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700216 [weakRef](const boost::system::error_code ec,
217 const std::variant<double> cfmVariant) {
Ed Tanousbb679322022-05-16 16:10:00 -0700218 auto self = weakRef.lock();
219 if (!self)
220 {
221 return;
222 }
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700223
Ed Tanousbb679322022-05-16 16:10:00 -0700224 uint64_t maxRpm = 100;
225 if (!ec)
226 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700227 const auto* cfm = std::get_if<double>(&cfmVariant);
Ed Tanousbb679322022-05-16 16:10:00 -0700228 if (cfm != nullptr && *cfm >= minSystemCfm)
229 {
230 maxRpm = self->getMaxRpm(*cfm);
James Feist13452092019-03-07 16:38:12 -0800231 }
Ed Tanousbb679322022-05-16 16:10:00 -0700232 }
233 self->pwmLimitIface->register_property("Limit", maxRpm);
234 self->pwmLimitIface->initialize();
235 setMaxPWM(self->dbusConnection, maxRpm);
Patrick Williams597e8422023-10-20 11:19:01 -0500236 },
James Feist13452092019-03-07 16:38:12 -0800237 settingsDaemon, cfmSettingPath, "org.freedesktop.DBus.Properties",
238 "Get", cfmSettingIface, "Limit");
239
Ed Tanousbb679322022-05-16 16:10:00 -0700240 matches.emplace_back(*dbusConnection,
241 "type='signal',"
242 "member='PropertiesChanged',interface='org."
243 "freedesktop.DBus.Properties',path='" +
244 std::string(cfmSettingPath) + "',arg0='" +
245 std::string(cfmSettingIface) + "'",
Patrick Williams92f8f512022-07-22 19:26:55 -0500246 [weakRef](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700247 auto self = weakRef.lock();
248 if (!self)
249 {
250 return;
251 }
252 boost::container::flat_map<std::string, std::variant<double>> values;
253 std::string objectName;
254 message.read(objectName, values);
255 const auto findValue = values.find("Limit");
256 if (findValue == values.end())
257 {
258 return;
259 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700260 auto* const reading = std::get_if<double>(&(findValue->second));
Ed Tanousbb679322022-05-16 16:10:00 -0700261 if (reading == nullptr)
262 {
263 std::cerr << "Got CFM Limit of wrong type\n";
264 return;
265 }
266 if (*reading < minSystemCfm && *reading != 0)
267 {
268 std::cerr << "Illegal CFM setting detected\n";
269 return;
270 }
271 uint64_t maxRpm = self->getMaxRpm(*reading);
272 self->pwmLimitIface->set_property("Limit", maxRpm);
273 setMaxPWM(self->dbusConnection, maxRpm);
274 });
James Feistb2eb3f52018-12-04 16:17:50 -0800275}
276
James Feist9566bfa2019-01-29 15:31:23 -0800277CFMSensor::~CFMSensor()
278{
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530279 for (const auto& iface : thresholdInterfaces)
280 {
281 objServer.remove_interface(iface);
282 }
James Feist9566bfa2019-01-29 15:31:23 -0800283 objServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800284 objServer.remove_interface(association);
James Feist13452092019-03-07 16:38:12 -0800285 objServer.remove_interface(cfmLimitIface);
286 objServer.remove_interface(pwmLimitIface);
287}
288
289void CFMSensor::createMaxCFMIface(void)
290{
James Feistb6c0b912019-07-09 12:21:44 -0700291 cfmLimitIface->register_property("Limit", c2 * maxCFM * tachs.size());
James Feist13452092019-03-07 16:38:12 -0800292 cfmLimitIface->initialize();
James Feist9566bfa2019-01-29 15:31:23 -0800293}
294
James Feistb2eb3f52018-12-04 16:17:50 -0800295void CFMSensor::addTachRanges(const std::string& serviceName,
296 const std::string& path)
297{
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700298 std::weak_ptr<CFMSensor> weakRef = weak_from_this();
James Feistb2eb3f52018-12-04 16:17:50 -0800299 dbusConnection->async_method_call(
Zev Weissafd15042022-07-18 12:28:40 -0700300 [weakRef, path](const boost::system::error_code ec,
301 const SensorBaseConfigMap& data) {
Ed Tanousbb679322022-05-16 16:10:00 -0700302 if (ec)
303 {
304 std::cerr << "Error getting properties from " << path << "\n";
305 return;
306 }
307 auto self = weakRef.lock();
308 if (!self)
309 {
310 return;
311 }
312 double max = loadVariant<double>(data, "MaxValue");
313 double min = loadVariant<double>(data, "MinValue");
314 self->tachRanges[path] = std::make_pair(min, max);
315 self->updateReading();
Patrick Williams597e8422023-10-20 11:19:01 -0500316 },
James Feistb2eb3f52018-12-04 16:17:50 -0800317 serviceName, path, "org.freedesktop.DBus.Properties", "GetAll",
318 "xyz.openbmc_project.Sensor.Value");
319}
320
321void CFMSensor::checkThresholds(void)
322{
323 thresholds::checkThresholds(this);
324}
325
326void CFMSensor::updateReading(void)
327{
328 double val = 0.0;
329 if (calculate(val))
330 {
331 if (value != val && parent)
332 {
333 parent->updateReading();
334 }
335 updateValue(val);
336 }
337 else
338 {
339 updateValue(std::numeric_limits<double>::quiet_NaN());
340 }
341}
342
Ed Tanous2049bd22022-07-09 07:20:26 -0700343uint64_t CFMSensor::getMaxRpm(uint64_t cfmMaxSetting) const
James Feist13452092019-03-07 16:38:12 -0800344{
345 uint64_t pwmPercent = 100;
346 double totalCFM = std::numeric_limits<double>::max();
347 if (cfmMaxSetting == 0)
348 {
349 return pwmPercent;
350 }
351
James Feist52427952019-04-05 14:23:35 -0700352 bool firstLoop = true;
James Feist13452092019-03-07 16:38:12 -0800353 while (totalCFM > cfmMaxSetting)
354 {
James Feist52427952019-04-05 14:23:35 -0700355 if (firstLoop)
356 {
357 firstLoop = false;
358 }
359 else
360 {
361 pwmPercent--;
362 }
363
James Feist13452092019-03-07 16:38:12 -0800364 double ci = 0;
365 if (pwmPercent == 0)
366 {
367 ci = 0;
368 }
369 else if (pwmPercent < tachMinPercent)
370 {
371 ci = c1;
372 }
373 else if (pwmPercent > tachMaxPercent)
374 {
375 ci = c2;
376 }
377 else
378 {
379 ci = c1 + (((c2 - c1) * (pwmPercent - tachMinPercent)) /
380 (tachMaxPercent - tachMinPercent));
381 }
382
383 // Now calculate the CFM for this tach
384 // CFMi = Ci * Qmaxi * TACHi
385 totalCFM = ci * maxCFM * pwmPercent;
386 totalCFM *= tachs.size();
387 // divide by 100 since pwm is in percent
388 totalCFM /= 100;
389
James Feist13452092019-03-07 16:38:12 -0800390 if (pwmPercent <= 0)
391 {
392 break;
393 }
394 }
James Feist52427952019-04-05 14:23:35 -0700395
James Feist13452092019-03-07 16:38:12 -0800396 return pwmPercent;
397}
398
James Feistb2eb3f52018-12-04 16:17:50 -0800399bool CFMSensor::calculate(double& value)
400{
401 double totalCFM = 0;
402 for (const std::string& tachName : tachs)
403 {
404 auto findReading = std::find_if(
Zev Weiss6c106d62022-08-17 20:50:00 -0700405 tachReadings.begin(), tachReadings.end(),
406 [&](const auto& item) { return item.first.ends_with(tachName); });
Patrick Williams597e8422023-10-20 11:19:01 -0500407 auto findRange = std::find_if(
408 tachRanges.begin(), tachRanges.end(),
409 [&](const auto& item) { return item.first.ends_with(tachName); });
James Feistb2eb3f52018-12-04 16:17:50 -0800410 if (findReading == tachReadings.end())
411 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700412 if constexpr (debug)
James Feista96329f2019-01-24 10:08:27 -0800413 {
414 std::cerr << "Can't find " << tachName << "in readings\n";
415 }
James Feist9566bfa2019-01-29 15:31:23 -0800416 continue; // haven't gotten a reading
James Feistb2eb3f52018-12-04 16:17:50 -0800417 }
418
419 if (findRange == tachRanges.end())
420 {
James Feist523828e2019-03-04 14:38:37 -0800421 std::cerr << "Can't find " << tachName << " in ranges\n";
James Feistb2eb3f52018-12-04 16:17:50 -0800422 return false; // haven't gotten a max / min
423 }
424
425 // avoid divide by 0
426 if (findRange->second.second == 0)
427 {
428 std::cerr << "Tach Max Set to 0 " << tachName << "\n";
429 return false;
430 }
431
432 double rpm = findReading->second;
433
434 // for now assume the min for a fan is always 0, divide by max to get
435 // percent and mult by 100
436 rpm /= findRange->second.second;
437 rpm *= 100;
438
Ed Tanous8a57ec02020-10-09 12:46:52 -0700439 if constexpr (debug)
James Feistb2eb3f52018-12-04 16:17:50 -0800440 {
441 std::cout << "Tach " << tachName << "at " << rpm << "\n";
442 }
443
444 // Do a linear interpolation to get Ci
445 // Ci = C1 + (C2 - C1)/(RPM2 - RPM1) * (TACHi - TACH1)
446
447 double ci = 0;
448 if (rpm == 0)
449 {
450 ci = 0;
451 }
452 else if (rpm < tachMinPercent)
453 {
454 ci = c1;
455 }
456 else if (rpm > tachMaxPercent)
457 {
458 ci = c2;
459 }
460 else
461 {
462 ci = c1 + (((c2 - c1) * (rpm - tachMinPercent)) /
463 (tachMaxPercent - tachMinPercent));
464 }
465
466 // Now calculate the CFM for this tach
467 // CFMi = Ci * Qmaxi * TACHi
468 totalCFM += ci * maxCFM * rpm;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700469 if constexpr (debug)
James Feista5e58722019-04-22 14:43:11 -0700470 {
471 std::cerr << "totalCFM = " << totalCFM << "\n";
472 std::cerr << "Ci " << ci << " MaxCFM " << maxCFM << " rpm " << rpm
473 << "\n";
474 std::cerr << "c1 " << c1 << " c2 " << c2 << " max "
475 << tachMaxPercent << " min " << tachMinPercent << "\n";
476 }
James Feistb2eb3f52018-12-04 16:17:50 -0800477 }
478
479 // divide by 100 since rpm is in percent
480 value = totalCFM / 100;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700481 if constexpr (debug)
James Feista5e58722019-04-22 14:43:11 -0700482 {
483 std::cerr << "cfm value = " << value << "\n";
484 }
James Feist9566bfa2019-01-29 15:31:23 -0800485 return true;
James Feistb2eb3f52018-12-04 16:17:50 -0800486}
487
488static constexpr double exitAirMaxReading = 127;
489static constexpr double exitAirMinReading = -128;
James Feistbc896df2018-11-26 16:28:17 -0800490ExitAirTempSensor::ExitAirTempSensor(
491 std::shared_ptr<sdbusplus::asio::connection>& conn,
James Feistb2eb3f52018-12-04 16:17:50 -0800492 const std::string& sensorName, const std::string& sensorConfiguration,
James Feistbc896df2018-11-26 16:28:17 -0800493 sdbusplus::asio::object_server& objectServer,
James Feistb839c052019-05-15 10:25:24 -0700494 std::vector<thresholds::Threshold>&& thresholdData) :
Zhikui Renda98f092021-11-01 09:41:08 -0700495 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -0700496 sensorConfiguration, "ExitAirTemp", false, false, exitAirMaxReading,
497 exitAirMinReading, conn, PowerState::on),
Ed Tanous2049bd22022-07-09 07:20:26 -0700498 objServer(objectServer)
James Feistbc896df2018-11-26 16:28:17 -0800499{
500 sensorInterface = objectServer.add_interface(
501 "/xyz/openbmc_project/sensors/temperature/" + name,
502 "xyz.openbmc_project.Sensor.Value");
503
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530504 for (const auto& threshold : thresholds)
James Feistbc896df2018-11-26 16:28:17 -0800505 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530506 std::string interface = thresholds::getInterface(threshold.level);
507 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
508 objectServer.add_interface(
509 "/xyz/openbmc_project/sensors/temperature/" + name, interface);
James Feistbc896df2018-11-26 16:28:17 -0800510 }
James Feist078f2322019-03-08 11:09:05 -0800511 association = objectServer.add_interface(
512 "/xyz/openbmc_project/sensors/temperature/" + name,
James Feist2adc95c2019-09-30 14:55:28 -0700513 association::interface);
Andrei Kartashev39287412022-02-04 16:04:47 +0300514 setInitialProperties(sensor_paths::unitDegreesC);
James Feistbc896df2018-11-26 16:28:17 -0800515}
516
517ExitAirTempSensor::~ExitAirTempSensor()
518{
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530519 for (const auto& iface : thresholdInterfaces)
520 {
521 objServer.remove_interface(iface);
522 }
James Feist523828e2019-03-04 14:38:37 -0800523 objServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800524 objServer.remove_interface(association);
James Feistbc896df2018-11-26 16:28:17 -0800525}
526
527void ExitAirTempSensor::setupMatches(void)
528{
Brandon Kim66558232021-11-09 16:53:08 -0800529 constexpr const auto matchTypes{
530 std::to_array<const char*>({"power", inletTemperatureSensor})};
James Feistbc896df2018-11-26 16:28:17 -0800531
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700532 std::weak_ptr<ExitAirTempSensor> weakRef = weak_from_this();
Ed Tanous13b63f82021-05-11 16:12:52 -0700533 for (const std::string type : matchTypes)
James Feistbc896df2018-11-26 16:28:17 -0800534 {
James Feistb2eb3f52018-12-04 16:17:50 -0800535 setupSensorMatch(matches, *dbusConnection, type,
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700536 [weakRef, type](const double& value,
Patrick Williams92f8f512022-07-22 19:26:55 -0500537 sdbusplus::message_t& message) {
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700538 auto self = weakRef.lock();
539 if (!self)
540 {
541 return;
542 }
Ed Tanousbb679322022-05-16 16:10:00 -0700543 if (type == "power")
544 {
545 std::string path = message.get_path();
546 if (path.find("PS") != std::string::npos &&
Zev Weiss6c106d62022-08-17 20:50:00 -0700547 path.ends_with("Input_Power"))
Ed Tanousbb679322022-05-16 16:10:00 -0700548 {
549 self->powerReadings[message.get_path()] = value;
550 }
551 }
552 else if (type == inletTemperatureSensor)
553 {
554 self->inletTemp = value;
555 }
556 self->updateReading();
557 });
558 }
559 dbusConnection->async_method_call(
560 [weakRef](boost::system::error_code ec,
561 const std::variant<double>& value) {
562 if (ec)
563 {
564 // sensor not ready yet
565 return;
566 }
567 auto self = weakRef.lock();
568 if (!self)
569 {
570 return;
571 }
572 self->inletTemp = std::visit(VariantToDoubleVisitor(), value);
Patrick Williams597e8422023-10-20 11:19:01 -0500573 },
James Feist9566bfa2019-01-29 15:31:23 -0800574 "xyz.openbmc_project.HwmonTempSensor",
575 std::string("/xyz/openbmc_project/sensors/") + inletTemperatureSensor,
James Feista5e58722019-04-22 14:43:11 -0700576 properties::interface, properties::get, sensorValueInterface, "Value");
577 dbusConnection->async_method_call(
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700578 [weakRef](boost::system::error_code ec, const GetSubTreeType& subtree) {
Ed Tanousbb679322022-05-16 16:10:00 -0700579 if (ec)
580 {
581 std::cerr << "Error contacting mapper\n";
582 return;
583 }
584 auto self = weakRef.lock();
585 if (!self)
586 {
587 return;
588 }
Zev Weiss72f322f2022-08-12 18:21:01 -0700589 for (const auto& [path, matches] : subtree)
Ed Tanousbb679322022-05-16 16:10:00 -0700590 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700591 size_t lastSlash = path.rfind('/');
592 if (lastSlash == std::string::npos || lastSlash == path.size() ||
593 matches.empty())
James Feista5e58722019-04-22 14:43:11 -0700594 {
Ed Tanousbb679322022-05-16 16:10:00 -0700595 continue;
James Feista5e58722019-04-22 14:43:11 -0700596 }
Zev Weiss72f322f2022-08-12 18:21:01 -0700597 std::string sensorName = path.substr(lastSlash + 1);
Zev Weiss6c106d62022-08-17 20:50:00 -0700598 if (sensorName.starts_with("PS") &&
599 sensorName.ends_with("Input_Power"))
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700600 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700601 // lambda capture requires a proper variable (not a structured
602 // binding)
603 const std::string& cbPath = path;
Ed Tanousbb679322022-05-16 16:10:00 -0700604 self->dbusConnection->async_method_call(
Zev Weiss72f322f2022-08-12 18:21:01 -0700605 [weakRef, cbPath](boost::system::error_code ec,
606 const std::variant<double>& value) {
Ed Tanousbb679322022-05-16 16:10:00 -0700607 if (ec)
608 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700609 std::cerr << "Error getting value from " << cbPath
Ed Tanousbb679322022-05-16 16:10:00 -0700610 << "\n";
611 }
612 auto self = weakRef.lock();
613 if (!self)
614 {
615 return;
616 }
Patrick Williams779c96a2023-05-10 07:50:42 -0500617 double reading = std::visit(VariantToDoubleVisitor(),
618 value);
Ed Tanousbb679322022-05-16 16:10:00 -0700619 if constexpr (debug)
620 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700621 std::cerr << cbPath << "Reading " << reading << "\n";
Ed Tanousbb679322022-05-16 16:10:00 -0700622 }
Zev Weiss72f322f2022-08-12 18:21:01 -0700623 self->powerReadings[cbPath] = reading;
Patrick Williams597e8422023-10-20 11:19:01 -0500624 },
Zev Weiss72f322f2022-08-12 18:21:01 -0700625 matches[0].first, cbPath, properties::interface,
Ed Tanousbb679322022-05-16 16:10:00 -0700626 properties::get, sensorValueInterface, "Value");
Zhikui Rendbb73aa2021-04-02 13:39:04 -0700627 }
Ed Tanousbb679322022-05-16 16:10:00 -0700628 }
Patrick Williams597e8422023-10-20 11:19:01 -0500629 },
James Feista5e58722019-04-22 14:43:11 -0700630 mapper::busName, mapper::path, mapper::interface, mapper::subtree,
631 "/xyz/openbmc_project/sensors/power", 0,
632 std::array<const char*, 1>{sensorValueInterface});
James Feistbc896df2018-11-26 16:28:17 -0800633}
634
635void ExitAirTempSensor::updateReading(void)
636{
James Feistbc896df2018-11-26 16:28:17 -0800637 double val = 0.0;
638 if (calculate(val))
639 {
James Feist18af4232019-03-13 11:14:00 -0700640 val = std::floor(val + 0.5);
James Feistbc896df2018-11-26 16:28:17 -0800641 updateValue(val);
642 }
643 else
644 {
645 updateValue(std::numeric_limits<double>::quiet_NaN());
646 }
647}
648
James Feistb2eb3f52018-12-04 16:17:50 -0800649double ExitAirTempSensor::getTotalCFM(void)
James Feistbc896df2018-11-26 16:28:17 -0800650{
James Feistb2eb3f52018-12-04 16:17:50 -0800651 double sum = 0;
652 for (auto& sensor : cfmSensors)
James Feistbc896df2018-11-26 16:28:17 -0800653 {
James Feistb2eb3f52018-12-04 16:17:50 -0800654 double reading = 0;
655 if (!sensor->calculate(reading))
James Feistbc896df2018-11-26 16:28:17 -0800656 {
James Feistbc896df2018-11-26 16:28:17 -0800657 return -1;
658 }
James Feistb2eb3f52018-12-04 16:17:50 -0800659 sum += reading;
James Feistbc896df2018-11-26 16:28:17 -0800660 }
James Feistb2eb3f52018-12-04 16:17:50 -0800661
662 return sum;
James Feistbc896df2018-11-26 16:28:17 -0800663}
664
665bool ExitAirTempSensor::calculate(double& val)
666{
Zhikui Ren12e3d672020-12-03 15:14:49 -0800667 constexpr size_t maxErrorPrint = 5;
James Feistbc896df2018-11-26 16:28:17 -0800668 static bool firstRead = false;
James Feistae11cfc2019-05-07 15:01:20 -0700669 static size_t errorPrint = maxErrorPrint;
670
James Feistbc896df2018-11-26 16:28:17 -0800671 double cfm = getTotalCFM();
672 if (cfm <= 0)
673 {
674 std::cerr << "Error getting cfm\n";
675 return false;
676 }
677
Zhikui Ren12e3d672020-12-03 15:14:49 -0800678 // Though cfm is not expected to be less than qMin normally,
679 // it is not a hard limit for exit air temp calculation.
680 // 50% qMin is chosen as a generic limit between providing
681 // a valid derived exit air temp and reporting exit air temp not available.
682 constexpr const double cfmLimitFactor = 0.5;
683 if (cfm < (qMin * cfmLimitFactor))
684 {
685 if (errorPrint > 0)
686 {
687 errorPrint--;
688 std::cerr << "cfm " << cfm << " is too low, expected qMin " << qMin
689 << "\n";
690 }
691 val = 0;
692 return false;
693 }
694
James Feistbc896df2018-11-26 16:28:17 -0800695 // if there is an error getting inlet temp, return error
696 if (std::isnan(inletTemp))
697 {
James Feistae11cfc2019-05-07 15:01:20 -0700698 if (errorPrint > 0)
699 {
700 errorPrint--;
701 std::cerr << "Cannot get inlet temp\n";
702 }
James Feistbc896df2018-11-26 16:28:17 -0800703 val = 0;
704 return false;
705 }
706
707 // if fans are off, just make the exit temp equal to inlet
James Feist71d31b22019-01-02 16:57:54 -0800708 if (!isPowerOn())
James Feistbc896df2018-11-26 16:28:17 -0800709 {
710 val = inletTemp;
711 return true;
712 }
713
714 double totalPower = 0;
Zev Weiss72f322f2022-08-12 18:21:01 -0700715 for (const auto& [path, reading] : powerReadings)
James Feistbc896df2018-11-26 16:28:17 -0800716 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700717 if (std::isnan(reading))
James Feistbc896df2018-11-26 16:28:17 -0800718 {
719 continue;
720 }
Zev Weiss72f322f2022-08-12 18:21:01 -0700721 totalPower += reading;
James Feistbc896df2018-11-26 16:28:17 -0800722 }
723
724 // Calculate power correction factor
725 // Ci = CL + (CH - CL)/(QMax - QMin) * (CFM - QMin)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700726 double powerFactor = 0.0;
James Feistbc896df2018-11-26 16:28:17 -0800727 if (cfm <= qMin)
728 {
729 powerFactor = powerFactorMin;
730 }
731 else if (cfm >= qMax)
732 {
733 powerFactor = powerFactorMax;
734 }
735 else
736 {
737 powerFactor = powerFactorMin + ((powerFactorMax - powerFactorMin) /
738 (qMax - qMin) * (cfm - qMin));
739 }
740
Ed Tanous8a57ec02020-10-09 12:46:52 -0700741 totalPower *= powerFactor;
James Feistbc896df2018-11-26 16:28:17 -0800742 totalPower += pOffset;
743
744 if (totalPower == 0)
745 {
James Feistae11cfc2019-05-07 15:01:20 -0700746 if (errorPrint > 0)
747 {
748 errorPrint--;
749 std::cerr << "total power 0\n";
750 }
James Feistbc896df2018-11-26 16:28:17 -0800751 val = 0;
752 return false;
753 }
754
Ed Tanous8a57ec02020-10-09 12:46:52 -0700755 if constexpr (debug)
James Feistbc896df2018-11-26 16:28:17 -0800756 {
757 std::cout << "Power Factor " << powerFactor << "\n";
758 std::cout << "Inlet Temp " << inletTemp << "\n";
759 std::cout << "Total Power" << totalPower << "\n";
760 }
761
762 // Calculate the exit air temp
763 // Texit = Tfp + (1.76 * TotalPower / CFM * Faltitude)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700764 double reading = 1.76 * totalPower * altitudeFactor;
James Feistbc896df2018-11-26 16:28:17 -0800765 reading /= cfm;
766 reading += inletTemp;
767
Ed Tanous8a57ec02020-10-09 12:46:52 -0700768 if constexpr (debug)
James Feistbc896df2018-11-26 16:28:17 -0800769 {
770 std::cout << "Reading 1: " << reading << "\n";
771 }
772
773 // Now perform the exponential average
774 // Calculate alpha based on SDR values and CFM
775 // Ai = As + (Af - As)/(QMax - QMin) * (CFM - QMin)
776
777 double alpha = 0.0;
778 if (cfm < qMin)
779 {
780 alpha = alphaS;
781 }
782 else if (cfm >= qMax)
783 {
784 alpha = alphaF;
785 }
786 else
787 {
788 alpha = alphaS + ((alphaF - alphaS) * (cfm - qMin) / (qMax - qMin));
789 }
790
Zhikui Ren12e3d672020-12-03 15:14:49 -0800791 auto time = std::chrono::steady_clock::now();
James Feistbc896df2018-11-26 16:28:17 -0800792 if (!firstRead)
793 {
794 firstRead = true;
795 lastTime = time;
796 lastReading = reading;
797 }
798 double alphaDT =
799 std::chrono::duration_cast<std::chrono::seconds>(time - lastTime)
800 .count() *
801 alpha;
802
803 // cap at 1.0 or the below fails
804 if (alphaDT > 1.0)
805 {
806 alphaDT = 1.0;
807 }
808
Ed Tanous8a57ec02020-10-09 12:46:52 -0700809 if constexpr (debug)
James Feistbc896df2018-11-26 16:28:17 -0800810 {
811 std::cout << "AlphaDT: " << alphaDT << "\n";
812 }
813
814 reading = ((reading * alphaDT) + (lastReading * (1.0 - alphaDT)));
815
Ed Tanous8a57ec02020-10-09 12:46:52 -0700816 if constexpr (debug)
James Feistbc896df2018-11-26 16:28:17 -0800817 {
818 std::cout << "Reading 2: " << reading << "\n";
819 }
820
821 val = reading;
822 lastReading = reading;
823 lastTime = time;
James Feistae11cfc2019-05-07 15:01:20 -0700824 errorPrint = maxErrorPrint;
James Feistbc896df2018-11-26 16:28:17 -0800825 return true;
826}
827
828void ExitAirTempSensor::checkThresholds(void)
829{
830 thresholds::checkThresholds(this);
831}
832
Zev Weissafd15042022-07-18 12:28:40 -0700833static void loadVariantPathArray(const SensorBaseConfigMap& data,
834 const std::string& key,
835 std::vector<std::string>& resp)
James Feistbc896df2018-11-26 16:28:17 -0800836{
837 auto it = data.find(key);
838 if (it == data.end())
839 {
840 std::cerr << "Configuration missing " << key << "\n";
841 throw std::invalid_argument("Key Missing");
842 }
843 BasicVariantType copy = it->second;
James Feist3eb82622019-02-08 13:10:22 -0800844 std::vector<std::string> config = std::get<std::vector<std::string>>(copy);
James Feistbc896df2018-11-26 16:28:17 -0800845 for (auto& str : config)
846 {
847 boost::replace_all(str, " ", "_");
848 }
849 resp = std::move(config);
850}
851
852void createSensor(sdbusplus::asio::object_server& objectServer,
James Feistb2eb3f52018-12-04 16:17:50 -0800853 std::shared_ptr<ExitAirTempSensor>& exitAirSensor,
James Feistbc896df2018-11-26 16:28:17 -0800854 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
855{
856 if (!dbusConnection)
857 {
858 std::cerr << "Connection not created\n";
859 return;
860 }
James Feist655f3762020-10-05 15:28:15 -0700861 auto getter = std::make_shared<GetSensorConfiguration>(
Patrick Williams597e8422023-10-20 11:19:01 -0500862 dbusConnection, [&objectServer, &dbusConnection,
863 &exitAirSensor](const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700864 cfmSensors.clear();
Zev Weiss72f322f2022-08-12 18:21:01 -0700865 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700866 {
Zev Weiss72f322f2022-08-12 18:21:01 -0700867 for (const auto& [intf, cfg] : interfaces)
James Feistbc896df2018-11-26 16:28:17 -0800868 {
Zev Weiss054aad82022-08-18 01:37:34 -0700869 if (intf == configInterfaceName(exitAirType))
James Feistbc896df2018-11-26 16:28:17 -0800870 {
Ed Tanousbb679322022-05-16 16:10:00 -0700871 // thresholds should be under the same path
872 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss72f322f2022-08-12 18:21:01 -0700873 parseThresholdsFromConfig(interfaces, sensorThresholds);
James Feistbc896df2018-11-26 16:28:17 -0800874
Zev Weiss72f322f2022-08-12 18:21:01 -0700875 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700876 exitAirSensor = std::make_shared<ExitAirTempSensor>(
Zev Weiss72f322f2022-08-12 18:21:01 -0700877 dbusConnection, name, path.str, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700878 std::move(sensorThresholds));
879 exitAirSensor->powerFactorMin =
Zev Weiss72f322f2022-08-12 18:21:01 -0700880 loadVariant<double>(cfg, "PowerFactorMin");
Ed Tanousbb679322022-05-16 16:10:00 -0700881 exitAirSensor->powerFactorMax =
Zev Weiss72f322f2022-08-12 18:21:01 -0700882 loadVariant<double>(cfg, "PowerFactorMax");
883 exitAirSensor->qMin = loadVariant<double>(cfg, "QMin");
884 exitAirSensor->qMax = loadVariant<double>(cfg, "QMax");
885 exitAirSensor->alphaS = loadVariant<double>(cfg, "AlphaS");
886 exitAirSensor->alphaF = loadVariant<double>(cfg, "AlphaF");
Ed Tanousbb679322022-05-16 16:10:00 -0700887 }
Zev Weiss054aad82022-08-18 01:37:34 -0700888 else if (intf == configInterfaceName(cfmType))
Ed Tanousbb679322022-05-16 16:10:00 -0700889 {
890 // thresholds should be under the same path
891 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss72f322f2022-08-12 18:21:01 -0700892 parseThresholdsFromConfig(interfaces, sensorThresholds);
893 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700894 auto sensor = std::make_shared<CFMSensor>(
Zev Weiss72f322f2022-08-12 18:21:01 -0700895 dbusConnection, name, path.str, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700896 std::move(sensorThresholds), exitAirSensor);
Zev Weiss72f322f2022-08-12 18:21:01 -0700897 loadVariantPathArray(cfg, "Tachs", sensor->tachs);
898 sensor->maxCFM = loadVariant<double>(cfg, "MaxCFM");
James Feistbc896df2018-11-26 16:28:17 -0800899
Ed Tanousbb679322022-05-16 16:10:00 -0700900 // change these into percent upon getting the data
Zev Weiss72f322f2022-08-12 18:21:01 -0700901 sensor->c1 = loadVariant<double>(cfg, "C1") / 100;
902 sensor->c2 = loadVariant<double>(cfg, "C2") / 100;
Ed Tanousbb679322022-05-16 16:10:00 -0700903 sensor->tachMinPercent =
Zev Weiss72f322f2022-08-12 18:21:01 -0700904 loadVariant<double>(cfg, "TachMinPercent");
Ed Tanousbb679322022-05-16 16:10:00 -0700905 sensor->tachMaxPercent =
Zev Weiss72f322f2022-08-12 18:21:01 -0700906 loadVariant<double>(cfg, "TachMaxPercent");
Ed Tanousbb679322022-05-16 16:10:00 -0700907 sensor->createMaxCFMIface();
908 sensor->setupMatches();
James Feistbc896df2018-11-26 16:28:17 -0800909
Ed Tanousbb679322022-05-16 16:10:00 -0700910 cfmSensors.emplace_back(std::move(sensor));
James Feistbc896df2018-11-26 16:28:17 -0800911 }
912 }
Ed Tanousbb679322022-05-16 16:10:00 -0700913 }
914 if (exitAirSensor)
915 {
916 exitAirSensor->setupMatches();
917 exitAirSensor->updateReading();
918 }
Patrick Williams597e8422023-10-20 11:19:01 -0500919 });
James Feist655f3762020-10-05 15:28:15 -0700920 getter->getConfiguration(
Zev Weiss054aad82022-08-18 01:37:34 -0700921 std::vector<std::string>(monitorTypes.begin(), monitorTypes.end()));
James Feistbc896df2018-11-26 16:28:17 -0800922}
923
James Feistb6c0b912019-07-09 12:21:44 -0700924int main()
James Feistbc896df2018-11-26 16:28:17 -0800925{
Ed Tanous1f978632023-02-28 18:16:39 -0800926 boost::asio::io_context io;
James Feistbc896df2018-11-26 16:28:17 -0800927 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Johnathan Mantey661d4372022-10-27 09:00:59 -0700928 sdbusplus::asio::object_server objectServer(systemBus, true);
929 objectServer.add_manager("/xyz/openbmc_project/sensors");
James Feistbc896df2018-11-26 16:28:17 -0800930 systemBus->request_name("xyz.openbmc_project.ExitAirTempSensor");
James Feistbc896df2018-11-26 16:28:17 -0800931 std::shared_ptr<ExitAirTempSensor> sensor =
932 nullptr; // wait until we find the config
James Feistbc896df2018-11-26 16:28:17 -0800933
Ed Tanous83db50c2023-03-01 10:20:24 -0800934 boost::asio::post(io,
935 [&]() { createSensor(objectServer, sensor, systemBus); });
James Feistbc896df2018-11-26 16:28:17 -0800936
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700937 boost::asio::steady_timer configTimer(io);
James Feistbc896df2018-11-26 16:28:17 -0800938
Patrick Williams92f8f512022-07-22 19:26:55 -0500939 std::function<void(sdbusplus::message_t&)> eventHandler =
940 [&](sdbusplus::message_t&) {
Ed Tanous83db50c2023-03-01 10:20:24 -0800941 configTimer.expires_after(std::chrono::seconds(1));
Ed Tanousbb679322022-05-16 16:10:00 -0700942 // create a timer because normally multiple properties change
943 configTimer.async_wait([&](const boost::system::error_code& ec) {
944 if (ec == boost::asio::error::operation_aborted)
945 {
946 return; // we're being canceled
947 }
948 createSensor(objectServer, sensor, systemBus);
949 if (!sensor)
950 {
951 std::cout << "Configuration not detected\n";
952 }
953 });
954 };
Zev Weiss214d9712022-08-12 12:54:31 -0700955 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
Zev Weiss054aad82022-08-18 01:37:34 -0700956 setupPropertiesChangedMatches(*systemBus, monitorTypes, eventHandler);
James Feistbc896df2018-11-26 16:28:17 -0800957
Bruce Lee913d4d02021-07-22 10:18:42 +0800958 setupManufacturingModeMatch(*systemBus);
James Feistbc896df2018-11-26 16:28:17 -0800959 io.run();
Zhikui Ren8685b172021-06-29 15:16:52 -0700960 return 0;
James Feistbc896df2018-11-26 16:28:17 -0800961}