blob: 506823a811a93e275a1b230fc2f5cd456deb665f [file] [log] [blame]
Josh Lehan2a40e932020-09-02 11:48:14 -07001#include "ExternalSensor.hpp"
2
3#include "SensorPaths.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -07004#include "Thresholds.hpp"
5#include "Utils.hpp"
6#include "sensor.hpp"
Josh Lehan2a40e932020-09-02 11:48:14 -07007
Josh Lehan2a40e932020-09-02 11:48:14 -07008#include <sdbusplus/asio/connection.hpp>
9#include <sdbusplus/asio/object_server.hpp>
10
Josh Lehan72432172021-03-17 13:35:43 -070011#include <chrono>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070012#include <cstddef>
13#include <functional>
Josh Lehan2a40e932020-09-02 11:48:14 -070014#include <iostream>
Josh Lehan2a40e932020-09-02 11:48:14 -070015#include <limits>
16#include <memory>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070017#include <stdexcept>
Josh Lehan2a40e932020-09-02 11:48:14 -070018#include <string>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070019#include <utility>
Josh Lehan2a40e932020-09-02 11:48:14 -070020#include <vector>
21
Josh Lehan72432172021-03-17 13:35:43 -070022static constexpr bool debug = false;
23
Josh Lehan2a40e932020-09-02 11:48:14 -070024ExternalSensor::ExternalSensor(
25 const std::string& objectType, sdbusplus::asio::object_server& objectServer,
26 std::shared_ptr<sdbusplus::asio::connection>& conn,
27 const std::string& sensorName, const std::string& sensorUnits,
Jeff Lin7b7a9de2021-02-22 11:16:27 +080028 std::vector<thresholds::Threshold>&& thresholdsIn,
Josh Lehan72432172021-03-17 13:35:43 -070029 const std::string& sensorConfiguration, double maxReading,
Josh Lehan03627382021-03-17 13:35:43 -070030 double minReading, double timeoutSecs, const PowerState& powerState) :
Zhikui Renda98f092021-11-01 09:41:08 -070031 Sensor(escapeName(sensorName), std::move(thresholdsIn), sensorConfiguration,
32 objectType, true, true, maxReading, minReading, conn, powerState),
Ed Tanous2049bd22022-07-09 07:20:26 -070033 objServer(objectServer), writeLast(std::chrono::steady_clock::now()),
Josh Lehan72432172021-03-17 13:35:43 -070034 writeTimeout(
35 std::chrono::duration_cast<std::chrono::steady_clock::duration>(
36 std::chrono::duration<double>(timeoutSecs))),
Ed Tanousb429f312022-06-27 16:09:53 -070037 writePerishable(timeoutSecs > 0.0)
Josh Lehan2a40e932020-09-02 11:48:14 -070038{
39 // The caller must specify what physical characteristic
40 // an external sensor is expected to be measuring, such as temperature,
41 // as, unlike others, this is not implied by device type name.
Ed Tanous6cb732a2021-02-18 15:33:51 -080042 std::string dbusPath = sensor_paths::getPathForUnits(sensorUnits);
Josh Lehan2a40e932020-09-02 11:48:14 -070043 if (dbusPath.empty())
44 {
45 throw std::runtime_error("Units not in allow list");
46 }
Ed Tanous6cb732a2021-02-18 15:33:51 -080047 std::string objectPath = "/xyz/openbmc_project/sensors/";
Josh Lehan2a40e932020-09-02 11:48:14 -070048 objectPath += dbusPath;
49 objectPath += '/';
50 objectPath += sensorName;
51
52 sensorInterface = objectServer.add_interface(
53 objectPath, "xyz.openbmc_project.Sensor.Value");
54
Jayashree Dhanapal56678082022-01-04 17:27:20 +053055 for (const auto& threshold : thresholds)
Josh Lehan2a40e932020-09-02 11:48:14 -070056 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053057 std::string interface = thresholds::getInterface(threshold.level);
58 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
59 objectServer.add_interface(objectPath, interface);
Josh Lehan2a40e932020-09-02 11:48:14 -070060 }
61
Patrick Williams2aaf7172024-08-16 15:20:40 -040062 association =
63 objectServer.add_interface(objectPath, association::interface);
Andrei Kartashev39287412022-02-04 16:04:47 +030064 setInitialProperties(sensorUnits);
Josh Lehan72432172021-03-17 13:35:43 -070065
Josh Lehan72432172021-03-17 13:35:43 -070066 if constexpr (debug)
67 {
68 std::cerr << "ExternalSensor " << name << " constructed: path "
69 << configurationPath << ", type " << objectType << ", min "
70 << minReading << ", max " << maxReading << ", timeout "
71 << std::chrono::duration_cast<std::chrono::microseconds>(
72 writeTimeout)
73 .count()
74 << " us\n";
75 }
Josh Lehan2a40e932020-09-02 11:48:14 -070076}
77
Josh Lehan03627382021-03-17 13:35:43 -070078// Separate function from constructor, because of a gotcha: can't use the
79// enable_shared_from_this() API until after the constructor has completed.
80void ExternalSensor::initWriteHook(
81 std::function<void(std::chrono::steady_clock::time_point now)>&&
82 writeHookIn)
83{
84 // Connect ExternalSensorMain with ExternalSensor
85 writeHook = std::move(writeHookIn);
86
87 // Connect ExternalSensor with Sensor
88 auto weakThis = weak_from_this();
Ed Tanous8a17c302021-09-02 15:07:11 -070089 externalSetHook = [weakThis]() {
Josh Lehan03627382021-03-17 13:35:43 -070090 auto lockThis = weakThis.lock();
91 if (lockThis)
92 {
93 lockThis->externalSetTrigger();
94 return;
95 }
96 if constexpr (debug)
97 {
98 std::cerr << "ExternalSensor receive ignored, sensor gone\n";
99 }
Ed Tanous8a17c302021-09-02 15:07:11 -0700100 };
Josh Lehan03627382021-03-17 13:35:43 -0700101}
102
Josh Lehan2a40e932020-09-02 11:48:14 -0700103ExternalSensor::~ExternalSensor()
104{
Josh Lehan72432172021-03-17 13:35:43 -0700105 // Make sure the write hook does not reference this object anymore
106 externalSetHook = nullptr;
107
Josh Lehan2a40e932020-09-02 11:48:14 -0700108 objServer.remove_interface(association);
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530109 for (const auto& iface : thresholdInterfaces)
110 {
111 objServer.remove_interface(iface);
112 }
Josh Lehan2a40e932020-09-02 11:48:14 -0700113 objServer.remove_interface(sensorInterface);
Josh Lehan72432172021-03-17 13:35:43 -0700114
115 if constexpr (debug)
116 {
117 std::cerr << "ExternalSensor " << name << " destructed\n";
118 }
Josh Lehan2a40e932020-09-02 11:48:14 -0700119}
120
Ed Tanous201a1012024-04-03 18:07:28 -0700121void ExternalSensor::checkThresholds()
Josh Lehan2a40e932020-09-02 11:48:14 -0700122{
123 thresholds::checkThresholds(this);
124}
Josh Lehan72432172021-03-17 13:35:43 -0700125
Ed Tanous201a1012024-04-03 18:07:28 -0700126bool ExternalSensor::isAliveAndPerishable() const
Josh Lehan72432172021-03-17 13:35:43 -0700127{
128 return (writeAlive && writePerishable);
129}
130
131bool ExternalSensor::isAliveAndFresh(
132 const std::chrono::steady_clock::time_point& now) const
133{
134 // Must be alive and perishable, to have possibility of being fresh
135 if (!isAliveAndPerishable())
136 {
137 return false;
138 }
139
140 // If age, as of now, is less than timeout, it is deemed fresh
Andrew Jeffery92b96292021-05-27 16:41:31 +0930141 // NOLINTNEXTLINE
Josh Lehan72432172021-03-17 13:35:43 -0700142 return (ageElapsed(now) < writeTimeout);
143}
144
145void ExternalSensor::writeBegin(
146 const std::chrono::steady_clock::time_point& now)
147{
148 if (!writeAlive)
149 {
150 std::cerr << "ExternalSensor " << name
151 << " online, receiving first value " << value << "\n";
152 }
153
154 writeLast = now;
155 writeAlive = true;
156}
157
Ed Tanous201a1012024-04-03 18:07:28 -0700158void ExternalSensor::writeInvalidate()
Josh Lehan72432172021-03-17 13:35:43 -0700159{
160 writeAlive = false;
161
162 std::cerr << "ExternalSensor " << name << " offline, timed out\n";
163
164 // Take back control of this sensor from the external override,
165 // as the external source has timed out.
166 // This allows sensor::updateValue() to work normally,
167 // as it would do for internal sensors with values from hardware.
168 overriddenState = false;
169
170 // Invalidate the existing Value, similar to what internal sensors do,
171 // when they encounter errors trying to read from hardware.
172 updateValue(std::numeric_limits<double>::quiet_NaN());
173}
174
175std::chrono::steady_clock::duration ExternalSensor::ageElapsed(
176 const std::chrono::steady_clock::time_point& now) const
177{
178 // Comparing 2 time_point will return duration
179 return (now - writeLast);
180}
181
182std::chrono::steady_clock::duration ExternalSensor::ageRemaining(
183 const std::chrono::steady_clock::time_point& now) const
184{
185 // Comparing duration will return another duration
186 return (writeTimeout - ageElapsed(now));
187}
188
Ed Tanous201a1012024-04-03 18:07:28 -0700189void ExternalSensor::externalSetTrigger()
Josh Lehan72432172021-03-17 13:35:43 -0700190{
191 if constexpr (debug)
192 {
193 std::cerr << "ExternalSensor " << name << " received " << value << "\n";
194 }
195
196 auto now = std::chrono::steady_clock::now();
197
198 writeBegin(now);
199
200 // Tell the owner to recalculate the expiration timer
201 writeHook(now);
202}