blob: 5c8cf057ef7022a9784b9b0053c8e5660a60764d [file]
#include "tlbmc/sensors/sync_polling_sensor.h"
#include <chrono> // NOLINT
#include <memory>
#include <optional>
#include <utility>
#include "absl/functional/any_invocable.h"
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "resource.pb.h"
#include "sensor.pb.h"
#include "tlbmc/sensors/polling_base_sensor.h"
namespace milotic_tlbmc {
SyncPollingSensor::SyncPollingSensor(
SensorAttributesStatic&& sensor_attributes_static,
const ThresholdConfigs& threshold_configs,
const std::shared_ptr<boost::asio::io_context>& io_context,
std::optional<NotificationCb> notification_cb)
: PollingBaseSensor(std::move(sensor_attributes_static), threshold_configs,
notification_cb),
io_context_(io_context) {}
void SyncPollingSensor::RefreshOnceAsync(
absl::AnyInvocable<void(const std::shared_ptr<const SensorValue>&)>
callback) {
std::weak_ptr<SyncPollingSensor> self = shared_from_this();
boost::asio::post(*io_context_, [self = std::move(self),
callback = std::move(callback)]() mutable {
std::shared_ptr<SyncPollingSensor> sensor = self.lock();
if (!sensor) {
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 !=
std::chrono::steady_clock::time_point::min()) {
sensor->UpdateSoftwarePollingStartMetrics(
std::chrono::steady_clock::now() - last_refresh_start_time);
}
sensor->SetLastRefreshStartTime(std::chrono::steady_clock::now());
// Get the sensor value
std::chrono::time_point<std::chrono::steady_clock> start_time =
std::chrono::steady_clock::now();
absl::StatusOr<SensorValue> result = sensor->ReadSensorData();
sensor->UpdateHardwarePollingMetrics(std::chrono::steady_clock::now() -
start_time);
if (!result.ok()) {
State state = sensor->GetSensorAttributesDynamic().state();
// Case 1: The sensor implementation (e.g., NicSensor) already updated
// its dynamic state with a granular error status (DRIVER_READ_ERROR,
// INVALID_DATA, or OTHER_ERROR) before returning the error. In this
// case, we preserve the specific root-cause status.
//
// Case 2 (Otherwise): The sensor failed to read without setting a
// granular status (e.g., legacy sensors or tests where state is still
// STATUS_READY or STATUS_UNKNOWN). In this case, we fall back to
// STATUS_STALE so that a failing sensor is not reported as READY.
if (state.status() != STATUS_DRIVER_READ_ERROR &&
state.status() != STATUS_INVALID_DATA &&
state.status() != STATUS_OTHER_ERROR) {
state.set_status(STATUS_STALE);
}
state.set_status_message(result.status().message());
sensor->UpdateState(std::move(state));
if (callback) {
callback(sensor->GetSensorData());
}
} else {
sensor->StoreSensorData(
std::make_shared<const SensorValue>(std::move(*result)));
State state;
state.set_status(STATUS_READY);
sensor->UpdateState(std::move(state));
if (callback) {
callback(sensor->GetSensorData());
}
}
std::chrono::steady_clock::time_point last_refresh_end_time =
sensor->GetLastRefreshEndTime();
if (last_refresh_end_time != std::chrono::steady_clock::time_point::min()) {
sensor->UpdateSoftwarePollingEndMetrics(std::chrono::steady_clock::now() -
last_refresh_end_time);
}
sensor->SetLastRefreshEndTime(std::chrono::steady_clock::now());
});
}
} // namespace milotic_tlbmc