Add tlBMC sensor value override functionality Introduces thread-safe software override support in the `milotic_tlbmc::Sensor` base class and overridden sensors. Key changes: - Adds `SetOverrideValue()`, `ClearOverride()`, `IsOverridden()`, and `GetOverrideValue()` to `Sensor`, guarded by `override_mutex_`. - Updates `PollingBaseSensor::GetSensorData()` and `BulkSensor::GetSensorData()` to return the active override value when present. - Updates `Sensor::GetSensorAttributesDynamic()` and `BulkSensor::GetSensorAttributesDynamic()` to report `STATUS_READY` when overridden. - Shields `SyncPollingSensor::RefreshOnceAsync()` and `AdcSensor::RefreshOnceAsync()` by skipping physical hardware reads while an override is active and immediately dispatching the callback with the overridden reading. - Adds comprehensive unit tests in `polling_base_sensor_test.cc` verifying override set, get, clear, dynamic attributes, threshold evaluations, and polling shielding. Google-Bug-Id:550410302 PiperOrigin-RevId: 975255792 Change-Id: I3e793b2f0d75a78a4c97e8612b6096d5bf01bd1d
diff --git a/tlbmc/sensors/adc_sensor.cc b/tlbmc/sensors/adc_sensor.cc index 483b011..64066f5 100644 --- a/tlbmc/sensors/adc_sensor.cc +++ b/tlbmc/sensors/adc_sensor.cc
@@ -290,6 +290,13 @@ void AdcSensor::RefreshOnceAsync( absl::AnyInvocable<void(const std::shared_ptr<const SensorValue>&)> callback) { + if (IsOverridden()) { + if (callback) { + callback(GetSensorData()); + } + return; + } + std::weak_ptr<AdcSensor> weak_self = shared_from_this(); auto on_read_done = [weak_self, callback = std::move(callback)](
diff --git a/tlbmc/sensors/polling_base_sensor.h b/tlbmc/sensors/polling_base_sensor.h index 175fc1f..f222612 100644 --- a/tlbmc/sensors/polling_base_sensor.h +++ b/tlbmc/sensors/polling_base_sensor.h
@@ -37,7 +37,13 @@ // Returns the latest sensor reading. std::shared_ptr<const SensorValue> GetSensorData() const override - ABSL_LOCKS_EXCLUDED(sensor_data_mutex_) { + ABSL_LOCKS_EXCLUDED(sensor_data_mutex_, override_mutex_) { + { + absl::MutexLock lock(override_mutex_); + if (override_value_.has_value()) { + return std::make_shared<const SensorValue>(*override_value_); + } + } absl::MutexLock lock(sensor_data_mutex_); return sensor_data_.empty() ? nullptr : sensor_data_.back(); }
diff --git a/tlbmc/sensors/sensor.cc b/tlbmc/sensors/sensor.cc index c18f4fd..f149bfc 100644 --- a/tlbmc/sensors/sensor.cc +++ b/tlbmc/sensors/sensor.cc
@@ -3,6 +3,7 @@ #include <algorithm> #include <cstdint> #include <memory> +#include <optional> #include <string> #include <utility> #include <vector> @@ -258,6 +259,28 @@ ready_for_read_ = false; } +absl::Status Sensor::SetOverrideValue(const SensorValue& value) { + absl::MutexLock lock(override_mutex_); + override_value_ = value; + return absl::OkStatus(); +} + +absl::Status Sensor::ClearOverride() { + absl::MutexLock lock(override_mutex_); + override_value_.reset(); + return absl::OkStatus(); +} + +bool Sensor::IsOverridden() const { + absl::MutexLock lock(override_mutex_); + return override_value_.has_value(); +} + +std::optional<SensorValue> Sensor::GetOverrideValue() const { + absl::MutexLock lock(override_mutex_); + return override_value_; +} + std::string GetTrimmedSensorName(absl::string_view sensor_name) { std::string stripped_sensor_name; if (uint64_t under_pos = sensor_name.find('_');
diff --git a/tlbmc/sensors/sensor.h b/tlbmc/sensors/sensor.h index bdbb51e..61688db 100644 --- a/tlbmc/sensors/sensor.h +++ b/tlbmc/sensors/sensor.h
@@ -25,7 +25,6 @@ #include "reading_transform_config.pb.h" #include "sensor_instance_properties.pb.h" #include "threshold_config.pb.h" -#include "tlbmc/host_state/power_control.h" #include "resource.pb.h" #include "sensor.pb.h" #include "google/protobuf/util/json_util.h" @@ -92,13 +91,34 @@ virtual SensorAttributesDynamic GetSensorAttributesDynamic() const { absl::MutexLock lock(sensor_attributes_dynamic_mutex_); - return sensor_attributes_dynamic_; + SensorAttributesDynamic attributes = sensor_attributes_dynamic_; + { + absl::MutexLock override_lock(override_mutex_); + if (override_value_.has_value()) { + attributes.mutable_state()->set_status(STATUS_READY); + } + } + return attributes; } const SensorAttributesStatic& GetSensorAttributesStatic() const { return sensor_attributes_static_; } + // Sets the software override value for this sensor. + // When set, GetSensorData() will return this value and RefreshOnceAsync() + // will not overwrite it. + virtual absl::Status SetOverrideValue(const SensorValue& value); + + // Clears any active software override, restoring normal hardware polling. + virtual absl::Status ClearOverride(); + + // Returns true if a software override is currently active. + virtual bool IsOverridden() const; + + // Returns the active override value if present. + virtual std::optional<SensorValue> GetOverrideValue() const; + virtual SensorMetrics GetSensorMetrics() const; virtual absl::StatusOr<nlohmann::json> GetMetricsAsJson( const ::google::protobuf::util::JsonPrintOptions& options) const; @@ -228,6 +248,9 @@ std::atomic<bool> ready_for_read_ = true; std::string devpath_; + + mutable absl::Mutex override_mutex_; + std::optional<SensorValue> override_value_ ABSL_GUARDED_BY(override_mutex_); }; std::string GetTrimmedSensorName(absl::string_view sensor_name);
diff --git a/tlbmc/sensors/sync_polling_sensor.cc b/tlbmc/sensors/sync_polling_sensor.cc index 68f3e7b..5c8cf05 100644 --- a/tlbmc/sensors/sync_polling_sensor.cc +++ b/tlbmc/sensors/sync_polling_sensor.cc
@@ -35,6 +35,12 @@ LOG(WARNING) << "Sensor is destroyed; cancel the refresh."; return; } + if (sensor->IsOverridden()) { + if (callback) { + callback(sensor->GetSensorData()); + } + return; + } std::chrono::steady_clock::time_point last_refresh_start_time = sensor->GetLastRefreshStartTime(); if (last_refresh_start_time !=