blob: c82972169b8c3b4842cc4bd6b09c288da647a504 [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
107 DataReader(std::string propertyPrefix, std::optional<std::string> parent);
108};
109
110/** @brief Manages any component composing of static data only. The static data are provided as a DataTree in construction time. */
111struct StaticData : private DataReader {
112 StaticData(std::string propertyPrefix, std::optional<std::string> parent, DataTree tree);
113 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200114 ThresholdsBySensorPath thresholds() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100115};
116
117/** @brief Manages fans component. Data is provided by a sysfs::HWMon object. */
118struct Fans : private DataReader {
119private:
120 std::shared_ptr<sysfs::HWMon> m_hwmon;
121 unsigned m_fanChannelsCount;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200122 Thresholds<int64_t> m_thresholds;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100123
124public:
Tomáš Pecka4886db22023-05-10 10:46:15 +0200125 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 +0100126 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200127 ThresholdsBySensorPath thresholds() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100128};
129
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200130enum class SensorType {
Tomáš Pecka77e09c22023-05-04 20:39:57 +0200131 Temperature,
132 Current,
133 VoltageDC,
134 VoltageAC,
135 Power
Václav Kubernát97e5ea12021-03-24 00:36:57 +0100136
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200137};
138
139/** @brief Manages a single value from sysfs, data is provided by a sysfs::HWMon object. */
Tomáš Pecka77e09c22023-05-04 20:39:57 +0200140template <SensorType TYPE>
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200141struct SysfsValue : private DataReader {
Tomáš Pecka339bc672020-11-11 15:59:03 +0100142private:
143 std::shared_ptr<sysfs::HWMon> m_hwmon;
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200144 std::string m_sysfsFile;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200145 Thresholds<int64_t> m_thresholds;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100146
147public:
Tomáš Pecka4886db22023-05-10 10:46:15 +0200148 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 +0100149 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200150 ThresholdsBySensorPath thresholds() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100151};
152
153/** @brief Manages a single eMMC block device hardware component. Data is provided by a sysfs::EMMC object. */
154struct EMMC : private DataReader {
155private:
156 std::shared_ptr<sysfs::EMMC> m_emmc;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200157 Thresholds<int64_t> m_thresholds;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100158
159public:
Tomáš Pecka4886db22023-05-10 10:46:15 +0200160 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 +0100161 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200162 ThresholdsBySensorPath thresholds() const;
Tomáš Pecka339bc672020-11-11 15:59:03 +0100163};
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +0200164
165/** @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)
166 */
167struct Group {
168private:
169 std::vector<IETFHardware::DataReader> m_readers;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200170 ThresholdsBySensorPath m_thresholds;
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +0200171
172public:
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +0200173 DataTree operator()() const;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200174 ThresholdsBySensorPath thresholds() const;
175
176 template <class DataReaderType>
177 void registerDataReader(const DataReaderType& callable)
178 {
179 m_readers.push_back(callable);
180 m_thresholds.merge(callable.thresholds());
181 }
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +0200182};
183
Tomáš Pecka339bc672020-11-11 15:59:03 +0100184}
185}