blob: c226e96b7cf06f29da6ee44e3c5a4db085324817 [file] [log] [blame]
Tomáš Pecka339bc672020-11-11 15:59:03 +01001/*
2 * Copyright (C) 2016-2020 CESNET, https://photonics.cesnet.cz/
3 *
4 * Written by Tomáš Pecka <tomas.pecka@fit.cvut.cz>
5 *
6 */
7
8#pragma once
9
10#include <functional>
11#include <map>
Jan Kundrát1c3b8812021-05-17 13:06:03 +020012#include <optional>
Tomáš Pecka339bc672020-11-11 15:59:03 +010013#include <utility>
14#include "ietf-hardware/sysfs/EMMC.h"
15#include "ietf-hardware/sysfs/HWMon.h"
Tomáš Pecka4886db22023-05-10 10:46:15 +020016#include "ietf-hardware/thresholds.h"
Tomáš Pecka339bc672020-11-11 15:59:03 +010017#include "utils/log-fwd.h"
18
19using namespace std::literals;
20
21namespace velia::ietf_hardware {
22
23using DataTree = std::map<std::string, std::string>;
Tomáš Pecka4886db22023-05-10 10:46:15 +020024using ThresholdsBySensorPath = std::map<std::string, Thresholds<int64_t>>;
Tomáš Pecka339bc672020-11-11 15:59:03 +010025
Tomáš Pecka0d8d8ee2023-05-10 12:22:58 +020026struct HardwareInfo {
27 DataTree dataTree;
28 std::map<std::string, State> updatedTresholdCrossing;
29};
30
Tomáš Pecka339bc672020-11-11 15:59:03 +010031/**
32 * @brief Readout of hardware-state related data according to RFC 8348 (App. A)
33 *
34 * IETFHardware implements readout of various hardware component data and provides them as a mapping
35 * nodePath -> value, where nodePath is an XPath conforming to ietf-hardware-state module (RFC 8348, App. A).
36 *
37 * The class is designed to be modular. IETFHardware does not do much, its only capabilities are:
38 * - Register data readers responsible for readout of data for individual hardware, and
39 * - ask registered data readers to provide the data.
40 *
41 * The data readers (IETFHardware::DataReader) are simple functors with signature DataTree() (i.e., std::map<std::string, std::string>())
42 * returning parts of the tree in the form described above (i.e., mapping nodePath -> value).
43 *
44 * The IETFHardware is *not aware* of Sysrepo.
45 * However, the data readers are aware of the tree structure of the YANG module ietf-hardware-state.
46 * That is because they also create the specified parts of the resulting tree.
47 *
48 * @see IETFHardware::DataReader The data reader.
49 * @see velia::ietf_hardware::data_reader Namespace containing several predefined components.
50 */
51class IETFHardware {
52
53public:
54 /** @brief The component */
55 using DataReader = std::function<DataTree()>;
56
57 IETFHardware();
58 ~IETFHardware();
Tomáš Pecka4886db22023-05-10 10:46:15 +020059
60 template <class DataReaderType>
61 void registerDataReader(const DataReaderType& callable)
62 {
63 m_callbacks.push_back(callable);
Tomáš Pecka0d8d8ee2023-05-10 12:22:58 +020064
65 for (const auto& [sensorPath, thresholds] : callable.thresholds()) {
66 m_thresholdsWatchers.emplace(sensorPath, thresholds);
67 }
Tomáš Pecka4886db22023-05-10 10:46:15 +020068 }
Tomáš Pecka339bc672020-11-11 15:59:03 +010069
Tomáš Pecka0d8d8ee2023-05-10 12:22:58 +020070 HardwareInfo process();
Tomáš Peckad2322ad2023-05-11 16:20:38 +020071 std::vector<std::string> sensorsXPaths() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +010072
73private:
Tomáš Pecka0d8d8ee2023-05-10 12:22:58 +020074 velia::Log m_log;
75
Tomáš Pecka339bc672020-11-11 15:59:03 +010076 /** @brief registered components for individual modules */
77 std::vector<DataReader> m_callbacks;
Tomáš Pecka0d8d8ee2023-05-10 12:22:58 +020078
79 /** @brief watchers for any sensor value xPath reported by data readers */
80 std::map<std::string, Watcher<int64_t>> m_thresholdsWatchers;
Tomáš Pecka339bc672020-11-11 15:59:03 +010081};
82
83/**
84 * This namespace contains several predefined data readers for IETFHardware.
85 * They are implemented as functors and fulfill the required interface -- std::function<DataTree()>
86 *
87 * The philosophy here is to initialize Component::m_staticData DataTree when constructing the object so the tree does not have to be completely reconstructed every time.
88 * When IETFHardwareState fetches the data from the data reader, an operator() is invoked.
89 * The dynamic data are fetched by IETFHardware class by the use of the operator().
90 * The result of call to operator() will be merged into the static data and returned to caller (IETFHardwareState).
91 *
92 * Note that a data reader can return any number of nodes and even multiple compoments.
93 * For example, Fans data reader will create multiple components in the tree, one for each fan.
94 */
95namespace data_reader {
96
97struct DataReader {
98 /** @brief name of the module component in the tree, e.g. ne:fans:fan1 */
99 std::string m_componentName;
100
101 /** @brief name of the parent module */
102 std::optional<std::string> m_parent;
103
104 /** @brief static hw-state related data */
105 DataTree m_staticData;
106
Tomáš Peckacd7f9cc2023-12-11 15:52:48 +0100107 velia::Log m_log;
108
Tomáš Pecka339bc672020-11-11 15:59:03 +0100109 DataReader(std::string propertyPrefix, std::optional<std::string> parent);
110};
111
112/** @brief Manages any component composing of static data only. The static data are provided as a DataTree in construction time. */
113struct StaticData : private DataReader {
114 StaticData(std::string propertyPrefix, std::optional<std::string> parent, DataTree tree);
115 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200116 ThresholdsBySensorPath thresholds() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100117};
118
119/** @brief Manages fans component. Data is provided by a sysfs::HWMon object. */
120struct Fans : private DataReader {
121private:
122 std::shared_ptr<sysfs::HWMon> m_hwmon;
123 unsigned m_fanChannelsCount;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200124 Thresholds<int64_t> m_thresholds;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100125
126public:
Tomáš Pecka4886db22023-05-10 10:46:15 +0200127 Fans(std::string propertyPrefix, std::optional<std::string> parent, std::shared_ptr<sysfs::HWMon> hwmon, unsigned fanChannelsCount, Thresholds<int64_t> thresholds = {});
Tomáš Pecka339bc672020-11-11 15:59:03 +0100128 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200129 ThresholdsBySensorPath thresholds() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100130};
131
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200132enum class SensorType {
Tomáš Pecka77e09c22023-05-04 20:39:57 +0200133 Temperature,
134 Current,
135 VoltageDC,
136 VoltageAC,
137 Power
Václav Kubernát97e5ea12021-03-24 00:36:57 +0100138
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200139};
140
141/** @brief Manages a single value from sysfs, data is provided by a sysfs::HWMon object. */
Tomáš Pecka77e09c22023-05-04 20:39:57 +0200142template <SensorType TYPE>
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200143struct SysfsValue : private DataReader {
Tomáš Pecka339bc672020-11-11 15:59:03 +0100144private:
145 std::shared_ptr<sysfs::HWMon> m_hwmon;
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200146 std::string m_sysfsFile;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200147 Thresholds<int64_t> m_thresholds;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100148
149public:
Tomáš Pecka4886db22023-05-10 10:46:15 +0200150 SysfsValue(std::string propertyPrefix, std::optional<std::string> parent, std::shared_ptr<sysfs::HWMon> hwmon, int sysfsChannelNr, Thresholds<int64_t> thresholds = {});
Tomáš Pecka339bc672020-11-11 15:59:03 +0100151 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200152 ThresholdsBySensorPath thresholds() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100153};
154
155/** @brief Manages a single eMMC block device hardware component. Data is provided by a sysfs::EMMC object. */
156struct EMMC : private DataReader {
157private:
158 std::shared_ptr<sysfs::EMMC> m_emmc;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200159 Thresholds<int64_t> m_thresholds;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100160
161public:
Tomáš Pecka4886db22023-05-10 10:46:15 +0200162 EMMC(std::string propertyPrefix, std::optional<std::string> parent, std::shared_ptr<sysfs::EMMC> emmc, Thresholds<int64_t> thresholds = {});
Tomáš Pecka339bc672020-11-11 15:59:03 +0100163 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200164 ThresholdsBySensorPath thresholds() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100165};
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +0200166
167/** @brief Use this when you want to wrap reading several properties in one go and still use it as a single DataReader instance (e.g. in on thread)
168 */
169struct Group {
170private:
171 std::vector<IETFHardware::DataReader> m_readers;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200172 ThresholdsBySensorPath m_thresholds;
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +0200173
174public:
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +0200175 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200176 ThresholdsBySensorPath thresholds() const;
177
178 template <class DataReaderType>
179 void registerDataReader(const DataReaderType& callable)
180 {
181 m_readers.push_back(callable);
182 m_thresholds.merge(callable.thresholds());
183 }
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +0200184};
185
Tomáš Pecka339bc672020-11-11 15:59:03 +0100186}
187}