blob: 48d2300df874646f0336554ee76303200db7f087 [file] [log] [blame]
Yuan Li445efe32019-06-14 22:58:32 +08001/*
2// Copyright (c) 2019 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*/
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103016
17#include "MCUTempSensor.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"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070022#include "sensor.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103023
Ed Tanouseacbfdd2024-04-04 12:00:24 -070024#include <fcntl.h>
25#include <linux/i2c.h>
26#include <sys/ioctl.h>
27#include <unistd.h>
28
29#include <boost/asio/error.hpp>
30#include <boost/asio/io_context.hpp>
31#include <boost/asio/post.hpp>
32#include <boost/asio/steady_timer.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070033#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070034#include <sdbusplus/asio/connection.hpp>
35#include <sdbusplus/asio/object_server.hpp>
36#include <sdbusplus/bus/match.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070037#include <sdbusplus/message.hpp>
James Feist38fb5982020-05-28 10:09:54 -070038
Ed Tanouseacbfdd2024-04-04 12:00:24 -070039#include <array>
Yuan Li445efe32019-06-14 22:58:32 +080040#include <chrono>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070041#include <cstddef>
42#include <cstdint>
Patrick Venture96e97db2019-10-31 13:44:38 -070043#include <functional>
Yuan Li445efe32019-06-14 22:58:32 +080044#include <iostream>
Patrick Venture96e97db2019-10-31 13:44:38 -070045#include <memory>
Patrick Venture96e97db2019-10-31 13:44:38 -070046#include <string>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070047#include <utility>
Yuan Li445efe32019-06-14 22:58:32 +080048#include <vector>
49
James Feist38fb5982020-05-28 10:09:54 -070050extern "C"
51{
Yuan Li445efe32019-06-14 22:58:32 +080052#include <i2c/smbus.h>
53#include <linux/i2c-dev.h>
54}
55
56constexpr const bool debug = false;
57
Zev Weiss054aad82022-08-18 01:37:34 -070058constexpr const char* sensorType = "MCUTempSensor";
Yuan Li445efe32019-06-14 22:58:32 +080059static constexpr double mcuTempMaxReading = 0xFF;
60static constexpr double mcuTempMinReading = 0;
61
62boost::container::flat_map<std::string, std::unique_ptr<MCUTempSensor>> sensors;
63
64MCUTempSensor::MCUTempSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -080065 boost::asio::io_context& io,
Yuan Li445efe32019-06-14 22:58:32 +080066 const std::string& sensorName,
67 const std::string& sensorConfiguration,
68 sdbusplus::asio::object_server& objectServer,
69 std::vector<thresholds::Threshold>&& thresholdData,
70 uint8_t busId, uint8_t mcuAddress,
71 uint8_t tempReg) :
Zhikui Renda98f092021-11-01 09:41:08 -070072 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070073 sensorConfiguration, "MCUTempSensor", false, false,
Zev Weiss34d7b972022-08-17 19:38:59 -070074 mcuTempMaxReading, mcuTempMinReading, conn),
Brad Bishopfbb44ad2019-11-08 09:42:37 -050075 busId(busId), mcuAddress(mcuAddress), tempReg(tempReg),
James Feiste3338522020-09-15 15:40:30 -070076 objectServer(objectServer), waitTimer(io)
Yuan Li445efe32019-06-14 22:58:32 +080077{
78 sensorInterface = objectServer.add_interface(
79 "/xyz/openbmc_project/sensors/temperature/" + name,
80 "xyz.openbmc_project.Sensor.Value");
81
Jayashree Dhanapal56678082022-01-04 17:27:20 +053082 for (const auto& threshold : thresholds)
Yuan Li445efe32019-06-14 22:58:32 +080083 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053084 std::string interface = thresholds::getInterface(threshold.level);
85 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
86 objectServer.add_interface(
87 "/xyz/openbmc_project/sensors/temperature/" + name, interface);
Yuan Li445efe32019-06-14 22:58:32 +080088 }
89 association = objectServer.add_interface(
90 "/xyz/openbmc_project/sensors/temperature/" + name,
James Feist2adc95c2019-09-30 14:55:28 -070091 association::interface);
Yuan Li445efe32019-06-14 22:58:32 +080092}
93
94MCUTempSensor::~MCUTempSensor()
95{
96 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053097 for (const auto& iface : thresholdInterfaces)
98 {
99 objectServer.remove_interface(iface);
100 }
Yuan Li445efe32019-06-14 22:58:32 +0800101 objectServer.remove_interface(sensorInterface);
102 objectServer.remove_interface(association);
103}
104
Ed Tanous201a1012024-04-03 18:07:28 -0700105void MCUTempSensor::init()
Yuan Li445efe32019-06-14 22:58:32 +0800106{
Andrei Kartashev39287412022-02-04 16:04:47 +0300107 setInitialProperties(sensor_paths::unitDegreesC);
Yuan Li445efe32019-06-14 22:58:32 +0800108 read();
109}
110
Ed Tanous201a1012024-04-03 18:07:28 -0700111void MCUTempSensor::checkThresholds()
Yuan Li445efe32019-06-14 22:58:32 +0800112{
113 thresholds::checkThresholds(this);
114}
115
Saitwal, Meghanf1169f72023-04-23 05:14:14 +0000116int MCUTempSensor::getMCURegsInfoWord(uint8_t regs, int32_t* pu32data) const
Yuan Li445efe32019-06-14 22:58:32 +0800117{
118 std::string i2cBus = "/dev/i2c-" + std::to_string(busId);
Yuan Li445efe32019-06-14 22:58:32 +0800119
Ed Tanous99c44092022-01-14 09:59:09 -0800120 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
121 int fd = open(i2cBus.c_str(), O_RDWR);
Yuan Li445efe32019-06-14 22:58:32 +0800122 if (fd < 0)
123 {
124 std::cerr << " unable to open i2c device" << i2cBus << " err=" << fd
125 << "\n";
126 return -1;
127 }
128
Ed Tanous99c44092022-01-14 09:59:09 -0800129 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
Yuan Li445efe32019-06-14 22:58:32 +0800130 if (ioctl(fd, I2C_SLAVE_FORCE, mcuAddress) < 0)
131 {
132 std::cerr << " unable to set device address\n";
133 close(fd);
134 return -1;
135 }
136
137 unsigned long funcs = 0;
Ed Tanous99c44092022-01-14 09:59:09 -0800138 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
Yuan Li445efe32019-06-14 22:58:32 +0800139 if (ioctl(fd, I2C_FUNCS, &funcs) < 0)
140 {
141 std::cerr << " not support I2C_FUNCS\n";
142 close(fd);
143 return -1;
144 }
145
Ed Tanous2049bd22022-07-09 07:20:26 -0700146 if ((funcs & I2C_FUNC_SMBUS_READ_WORD_DATA) == 0U)
Yuan Li445efe32019-06-14 22:58:32 +0800147 {
148 std::cerr << " not support I2C_FUNC_SMBUS_READ_WORD_DATA\n";
149 close(fd);
150 return -1;
151 }
152
Saitwal, Meghanf1169f72023-04-23 05:14:14 +0000153 *pu32data = i2c_smbus_read_word_data(fd, regs);
Yuan Li445efe32019-06-14 22:58:32 +0800154 close(fd);
155
Saitwal, Meghanf1169f72023-04-23 05:14:14 +0000156 if (*pu32data < 0)
Yuan Li445efe32019-06-14 22:58:32 +0800157 {
158 std::cerr << " read word data failed at " << static_cast<int>(regs)
159 << "\n";
160 return -1;
161 }
162
163 return 0;
164}
165
Ed Tanous201a1012024-04-03 18:07:28 -0700166void MCUTempSensor::read()
Yuan Li445efe32019-06-14 22:58:32 +0800167{
168 static constexpr size_t pollTime = 1; // in seconds
169
Ed Tanous83db50c2023-03-01 10:20:24 -0800170 waitTimer.expires_after(std::chrono::seconds(pollTime));
Yuan Li445efe32019-06-14 22:58:32 +0800171 waitTimer.async_wait([this](const boost::system::error_code& ec) {
172 if (ec == boost::asio::error::operation_aborted)
173 {
174 return; // we're being cancelled
175 }
176 // read timer error
Ed Tanous8a57ec02020-10-09 12:46:52 -0700177 if (ec)
Yuan Li445efe32019-06-14 22:58:32 +0800178 {
179 std::cerr << "timer error\n";
180 return;
181 }
Saitwal, Meghanf1169f72023-04-23 05:14:14 +0000182 int32_t temp = 0;
Yuan Li445efe32019-06-14 22:58:32 +0800183 int ret = getMCURegsInfoWord(tempReg, &temp);
184 if (ret >= 0)
185 {
186 double v = static_cast<double>(temp) / 1000;
187 if constexpr (debug)
188 {
James Feistb6c0b912019-07-09 12:21:44 -0700189 std::cerr << "Value update to " << v << "raw reading "
Yuan Li445efe32019-06-14 22:58:32 +0800190 << static_cast<int>(temp) << "\n";
191 }
192 updateValue(v);
193 }
194 else
195 {
196 std::cerr << "Invalid read getMCURegsInfoWord\n";
James Feist961bf092020-07-01 16:38:12 -0700197 incrementError();
Yuan Li445efe32019-06-14 22:58:32 +0800198 }
199 read();
200 });
201}
202
203void createSensors(
Ed Tanous1f978632023-02-28 18:16:39 -0800204 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
Yuan Li445efe32019-06-14 22:58:32 +0800205 boost::container::flat_map<std::string, std::unique_ptr<MCUTempSensor>>&
206 sensors,
207 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
208{
209 if (!dbusConnection)
210 {
211 std::cerr << "Connection not created\n";
212 return;
213 }
214
215 dbusConnection->async_method_call(
216 [&io, &objectServer, &dbusConnection, &sensors](
217 boost::system::error_code ec, const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700218 if (ec)
219 {
220 std::cerr << "Error contacting entity manager\n";
221 return;
222 }
Zev Weissd7c1f762022-08-12 18:21:02 -0700223 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700224 {
Zev Weissd7c1f762022-08-12 18:21:02 -0700225 for (const auto& [intf, cfg] : interfaces)
Yuan Li445efe32019-06-14 22:58:32 +0800226 {
Zev Weiss054aad82022-08-18 01:37:34 -0700227 if (intf != configInterfaceName(sensorType))
Yuan Li445efe32019-06-14 22:58:32 +0800228 {
Ed Tanousbb679322022-05-16 16:10:00 -0700229 continue;
Yuan Li445efe32019-06-14 22:58:32 +0800230 }
Zev Weissd7c1f762022-08-12 18:21:02 -0700231 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700232
233 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weissd7c1f762022-08-12 18:21:02 -0700234 if (!parseThresholdsFromConfig(interfaces, sensorThresholds))
Ed Tanousbb679322022-05-16 16:10:00 -0700235 {
236 std::cerr << "error populating thresholds for " << name
237 << "\n";
238 }
239
Zev Weissd7c1f762022-08-12 18:21:02 -0700240 uint8_t busId = loadVariant<uint8_t>(cfg, "Bus");
241 uint8_t mcuAddress = loadVariant<uint8_t>(cfg, "Address");
242 uint8_t tempReg = loadVariant<uint8_t>(cfg, "Reg");
Ed Tanousbb679322022-05-16 16:10:00 -0700243
Patrick Williams779c96a2023-05-10 07:50:42 -0500244 std::string sensorClass = loadVariant<std::string>(cfg,
245 "Class");
Ed Tanousbb679322022-05-16 16:10:00 -0700246
247 if constexpr (debug)
248 {
Zev Weissd7c1f762022-08-12 18:21:02 -0700249 std::cerr << "Configuration parsed for \n\t" << intf << "\n"
Ed Tanousbb679322022-05-16 16:10:00 -0700250 << "with\n"
251 << "\tName: " << name << "\n"
252 << "\tBus: " << static_cast<int>(busId) << "\n"
253 << "\tAddress: " << static_cast<int>(mcuAddress)
254 << "\n"
255 << "\tReg: " << static_cast<int>(tempReg) << "\n"
256 << "\tClass: " << sensorClass << "\n";
257 }
258
259 auto& sensor = sensors[name];
260
261 sensor = std::make_unique<MCUTempSensor>(
Zev Weissd7c1f762022-08-12 18:21:02 -0700262 dbusConnection, io, name, path, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700263 std::move(sensorThresholds), busId, mcuAddress, tempReg);
264
265 sensor->init();
Yuan Li445efe32019-06-14 22:58:32 +0800266 }
Ed Tanousbb679322022-05-16 16:10:00 -0700267 }
Patrick Williams597e8422023-10-20 11:19:01 -0500268 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800269 entityManagerName, "/xyz/openbmc_project/inventory",
270 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Yuan Li445efe32019-06-14 22:58:32 +0800271}
272
James Feistb6c0b912019-07-09 12:21:44 -0700273int main()
Yuan Li445efe32019-06-14 22:58:32 +0800274{
Ed Tanous1f978632023-02-28 18:16:39 -0800275 boost::asio::io_context io;
Yuan Li445efe32019-06-14 22:58:32 +0800276 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanous14ed5e92022-07-12 15:50:23 -0700277 sdbusplus::asio::object_server objectServer(systemBus, true);
278 objectServer.add_manager("/xyz/openbmc_project/sensors");
279
Yuan Li445efe32019-06-14 22:58:32 +0800280 systemBus->request_name("xyz.openbmc_project.MCUTempSensor");
Yuan Li445efe32019-06-14 22:58:32 +0800281
Ed Tanous83db50c2023-03-01 10:20:24 -0800282 boost::asio::post(
283 io, [&]() { createSensors(io, objectServer, sensors, systemBus); });
Yuan Li445efe32019-06-14 22:58:32 +0800284
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700285 boost::asio::steady_timer configTimer(io);
Yuan Li445efe32019-06-14 22:58:32 +0800286
Patrick Williams92f8f512022-07-22 19:26:55 -0500287 std::function<void(sdbusplus::message_t&)> eventHandler =
288 [&](sdbusplus::message_t&) {
Ed Tanous83db50c2023-03-01 10:20:24 -0800289 configTimer.expires_after(std::chrono::seconds(1));
Ed Tanousbb679322022-05-16 16:10:00 -0700290 // create a timer because normally multiple properties change
291 configTimer.async_wait([&](const boost::system::error_code& ec) {
292 if (ec == boost::asio::error::operation_aborted)
293 {
294 return; // we're being canceled
295 }
296 // config timer error
297 if (ec)
298 {
299 std::cerr << "timer error\n";
300 return;
301 }
302 createSensors(io, objectServer, sensors, systemBus);
303 if (sensors.empty())
304 {
305 std::cout << "Configuration not detected\n";
306 }
307 });
308 };
Yuan Li445efe32019-06-14 22:58:32 +0800309
Zev Weiss214d9712022-08-12 12:54:31 -0700310 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
311 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700312 *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
Bruce Lee1263c3d2021-06-04 15:16:33 +0800313 setupManufacturingModeMatch(*systemBus);
Yuan Li445efe32019-06-14 22:58:32 +0800314 io.run();
Zhikui Ren8685b172021-06-29 15:16:52 -0700315 return 0;
Yuan Li445efe32019-06-14 22:58:32 +0800316}