summaryrefslogtreecommitdiff
path: root/agent/sila/sensors.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'agent/sila/sensors.cpp')
-rw-r--r--agent/sila/sensors.cpp385
1 files changed, 385 insertions, 0 deletions
diff --git a/agent/sila/sensors.cpp b/agent/sila/sensors.cpp
new file mode 100644
index 0000000..5cb8392
--- /dev/null
+++ b/agent/sila/sensors.cpp
@@ -0,0 +1,385 @@
+/**
+ * @brief SILA sensors tables implementation.
+ *
+ * This file is part of sila-snmp project.
+ *
+ * Copyright (c) 2022 SILA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "tracing.hpp"
+#include "data/table.hpp"
+#include "data/table/item.hpp"
+#include "sila/sila_oid.hpp"
+#include "snmptrap.hpp"
+
+#include <cmath>
+
+namespace sila
+{
+namespace sensors
+{
+/**
+ * @brief Sensor implementation.
+ */
+struct Sensor
+ : public phosphor::snmp::data::table::Item<double, double, bool, double,
+ bool, double, bool, double, bool>
+{
+ /**
+ * @brief State codes like in MIB file.
+ */
+ enum state_t
+ {
+ E_DISABLED = 0,
+ E_NORMAL,
+ E_WARNING_LOW,
+ E_WARNING_HIGH,
+ E_CRITICAL_LOW,
+ E_CRITICAL_HIGH,
+ };
+
+ // SNMP table columns
+ enum Columns
+ {
+ COLUMN_SILASENSOR_NAME = 1,
+ COLUMN_SILASENSOR_VALUE,
+ COLUMN_SILASENSOR_WARNLOW,
+ COLUMN_SILASENSOR_WARNHIGH,
+ COLUMN_SILASENSOR_CRITLOW,
+ COLUMN_SILASENSOR_CRITHIGH,
+ COLUMN_SILASENSOR_STATE,
+ };
+
+ // Indexes of fields in tuple
+ enum Fields
+ {
+ FIELD_SENSOR_VALUE = 0,
+ FIELD_SENSOR_WARNLOW,
+ FIELD_SENSOR_WARNLOW_ALARM,
+ FIELD_SENSOR_WARNHI,
+ FIELD_SENSOR_WARNHI_ALARM,
+ FIELD_SENSOR_CRITLOW,
+ FIELD_SENSOR_CRITLOW_ALARM,
+ FIELD_SENSOR_CRITHI,
+ FIELD_SENSOR_CRITHI_ALARM,
+ };
+
+ // Sensor types (first letter in sensors folder name)
+ enum Types
+ {
+ ST_TEMPERATURE = 't', // temperature
+ ST_VOLTAGE = 'v', // voltage
+ ST_TACHOMETER = 'f', // fan_tach
+ ST_CURRENT = 'c', // current
+ ST_POWER = 'p', // power
+ };
+
+ /**
+ * @brief Object contructor.
+ */
+ Sensor(const std::string& folder, const std::string& name) :
+ phosphor::snmp::data::table::Item<double, double, bool, double, bool,
+ double, bool, double, bool>(
+ folder, name,
+ .0, // Value
+ .0, false, // WarningLow
+ .0, false, // WarningHigh
+ .0, false, // CriticalLow
+ .0, false) // CriticalHigh
+ {
+ auto n = folder.rfind('/');
+ if (n != std::string::npos)
+ {
+ // Prepare for send traps
+ switch (folder[n + 1])
+ {
+ case ST_TEMPERATURE:
+ _notifyOid.assign(SILA_OID(0, 2));
+ break;
+
+ case ST_VOLTAGE:
+ _notifyOid.assign(SILA_OID(0, 3));
+ break;
+
+ case ST_TACHOMETER:
+ _notifyOid.assign(SILA_OID(0, 4));
+ break;
+
+ case ST_CURRENT:
+ _notifyOid.assign(SILA_OID(0, 5));
+ break;
+
+ case ST_POWER:
+ _notifyOid.assign(SILA_OID(0, 6));
+ break;
+ }
+
+ // Correct scale power
+ // Required for TEXTUAL-CONVENTION in SILA-MIB.txt
+ switch (folder[n + 1])
+ {
+ case ST_TACHOMETER:
+ _power = 0;
+ break;
+ }
+ }
+
+ if (!_notifyOid.empty())
+ {
+ phosphor::snmp::agent::make_oid(
+ _stateOid, ".1.3.6.1.4.1.49769.1.%lu.1.7.\"%s\"",
+ _notifyOid.back(), name.c_str());
+ }
+ }
+
+ /**
+ * @brief Update fields with new values recieved from DBus.
+ */
+ void setFields(const fields_map_t& fields) override
+ {
+ auto prevValue = getValue<FIELD_SENSOR_VALUE>();
+ auto prevState = getState();
+
+ setField<FIELD_SENSOR_VALUE>(fields, "Value");
+ setField<FIELD_SENSOR_WARNLOW>(fields, "WarningLow");
+ setField<FIELD_SENSOR_WARNLOW_ALARM>(fields, "WarningAlarmLow");
+ setField<FIELD_SENSOR_WARNHI>(fields, "WarningHigh");
+ setField<FIELD_SENSOR_WARNHI_ALARM>(fields, "WarningAlarmHigh");
+ setField<FIELD_SENSOR_CRITLOW>(fields, "CriticalLow");
+ setField<FIELD_SENSOR_CRITLOW_ALARM>(fields, "CriticalAlarmLow");
+ setField<FIELD_SENSOR_CRITHI>(fields, "CriticalHigh");
+ setField<FIELD_SENSOR_CRITHI_ALARM>(fields, "CriticalAlarmHigh");
+
+ auto lastState = getState();
+
+ if (prevValue != getValue<FIELD_SENSOR_VALUE>() ||
+ prevState != lastState)
+ {
+ DEBUGMSGTL(("sila:sensors",
+ "Sensor '%s' changed: %d -> %d, state: %d -> %d\n",
+ name.c_str(), prevValue, getValue<FIELD_SENSOR_VALUE>(),
+ prevState, lastState));
+ }
+
+ if (prevState != lastState)
+ {
+ send_notify(lastState);
+ }
+ }
+
+ /**
+ * @brief Called when sensor added to table.
+ */
+ void onCreate() override
+ {
+ DEBUGMSGTL(("sila:sensors", "Sensor '%s' added, state=%d\n",
+ name.c_str(), getState()));
+ send_notify(E_NORMAL);
+ }
+
+ /**
+ * @brief Called when sensor removed from table.
+ */
+ void onDestroy() override
+ {
+ DEBUGMSGTL(("sila:sensors", "Sensor '%s' removed, state=%d\n",
+ name.c_str(), getState()));
+ send_notify(E_DISABLED);
+ }
+
+ /**
+ * @brief Send snmptrap about changed state.
+ *
+ * @param state - state value for sent with trap.
+ */
+ void send_notify(state_t state)
+ {
+ if (!_notifyOid.empty() && !_stateOid.empty())
+ {
+ phosphor::snmp::agent::Trap trap(_notifyOid);
+ trap.add_field(_stateOid.data(), _stateOid.size(), state);
+ trap.send();
+ }
+ else
+ {
+ TRACE_ERROR("Notify is unsupported for sensor '%s'\n",
+ name.c_str());
+ }
+ }
+
+ /**
+ * @brief Get current state.
+ */
+ state_t getState() const
+ {
+ if (std::get<FIELD_SENSOR_CRITHI_ALARM>(data))
+ {
+ return E_CRITICAL_HIGH;
+ }
+ else if (std::get<FIELD_SENSOR_WARNHI_ALARM>(data))
+ {
+ return E_WARNING_HIGH;
+ }
+ else if (std::get<FIELD_SENSOR_WARNLOW_ALARM>(data))
+ {
+ return E_WARNING_LOW;
+ }
+ else if (std::get<FIELD_SENSOR_CRITLOW_ALARM>(data))
+ {
+ return E_CRITICAL_LOW;
+ }
+
+ return E_NORMAL;
+ }
+
+ /**
+ * @brief snmp request handler.
+ */
+ void get_snmp_reply(netsnmp_agent_request_info* reqinfo,
+ netsnmp_request_info* request) const override
+ {
+ using namespace phosphor::snmp::agent;
+
+ netsnmp_table_request_info* tinfo = netsnmp_extract_table_info(request);
+
+ switch (tinfo->colnum)
+ {
+ case COLUMN_SILASENSOR_NAME:
+ VariableList::set(request->requestvb, name);
+ break;
+
+ case COLUMN_SILASENSOR_VALUE:
+ VariableList::set(request->requestvb,
+ getValue<FIELD_SENSOR_VALUE>());
+ break;
+
+ case COLUMN_SILASENSOR_WARNLOW:
+ VariableList::set(request->requestvb,
+ getValue<FIELD_SENSOR_WARNLOW>());
+ break;
+
+ case COLUMN_SILASENSOR_WARNHIGH:
+ VariableList::set(request->requestvb,
+ getValue<FIELD_SENSOR_WARNHI>());
+ break;
+
+ case COLUMN_SILASENSOR_CRITLOW:
+ VariableList::set(request->requestvb,
+ getValue<FIELD_SENSOR_CRITLOW>());
+ break;
+
+ case COLUMN_SILASENSOR_CRITHIGH:
+ VariableList::set(request->requestvb,
+ getValue<FIELD_SENSOR_CRITHI>());
+ break;
+
+ case COLUMN_SILASENSOR_STATE:
+ VariableList::set(request->requestvb, getState());
+ break;
+
+ default:
+ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
+ break;
+ }
+ }
+
+ /**
+ * @brief Scale and round sensors value.
+ */
+ template <size_t Idx> int getValue() const
+ {
+ return static_cast<int>(
+ std::round(std::get<Idx>(data) * powf(10.f, _power)));
+ }
+
+ std::vector<oid> _notifyOid;
+ std::vector<oid> _stateOid;
+ int _power = 3;
+};
+
+struct SensorsTable : public phosphor::snmp::data::Table<Sensor>
+{
+ using OID = std::vector<oid>;
+
+ SensorsTable(const std::string& folder, const std::string& tableName,
+ const OID& tableOID) :
+ phosphor::snmp::data::Table<Sensor>(
+ "/xyz/openbmc_project/sensors/" + folder,
+ {
+ "xyz.openbmc_project.Sensor.Value",
+ "xyz.openbmc_project.Sensor.Threshold.Warning",
+ "xyz.openbmc_project.Sensor.Threshold.Critical",
+ "xyz.openbmc_project.Sensor.Threshold.Fatal",
+ }),
+ tableName(tableName), tableOID(tableOID)
+
+ {
+ }
+
+ std::string tableName;
+ OID tableOID;
+};
+
+static std::array<SensorsTable, 5> sensors = {
+ SensorsTable{"temperature", "silaTempSensorsTable", SILA_OID(1, 2)},
+ SensorsTable{"voltage", "silaVoltSensorsTable", SILA_OID(1, 3)},
+ SensorsTable{"fan_tach", "silaTachSensorsTable", SILA_OID(1, 4)},
+ SensorsTable{"current", "silaCurrSensorsTable", SILA_OID(1, 5)},
+ SensorsTable{"power", "silaPowerSensorsTable", SILA_OID(1, 6)},
+};
+
+/**
+ * @brief Update all sensors.
+ */
+void update()
+{
+ for (auto& s : sensors)
+ {
+ s.update();
+ }
+}
+
+/**
+ * @brief Initialize sensors.
+ */
+void init()
+{
+ DEBUGMSGTL(("sila:init", "Initialize silaSensors\n"));
+
+ for (auto& s : sensors)
+ {
+ s.init_mib(s.tableName.c_str(), s.tableOID.data(), s.tableOID.size(),
+ Sensor::COLUMN_SILASENSOR_NAME,
+ Sensor::COLUMN_SILASENSOR_STATE);
+ s.update();
+ }
+}
+
+/**
+ * @brief Deinitialize sensors.
+ */
+void destroy()
+{
+ DEBUGMSGTL(("sila:shutdown", "Destroy silaSensors\n"));
+
+ for (auto& s : sensors)
+ {
+ unregister_mib(s.tableOID.data(), s.tableOID.size());
+ }
+}
+
+} // namespace sensors
+} // namespace sila