blob: 83393ae231431d184feea000d7d078a4de61b6db [file] [log] [blame]
#ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SENSORS_SENSOR_H_
#define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SENSORS_SENSOR_H_
#include <chrono> // NOLINT
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/btree_set.h"
#include "absl/functional/any_invocable.h"
#include "absl/functional/function_ref.h"
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include "boost/circular_buffer.hpp" //NOLINT: boost is commonly used in BMC
#include "entity_common_config.pb.h"
#include "hal_common_config.pb.h"
#include "reading_transform_config.pb.h"
#include "tlbmc/configs/subscription_config.h"
#include "tlbmc/hal/sysfs/i2c.h"
#include "resource.pb.h"
#include "sensor.pb.h"
namespace milotic_tlbmc {
std::string GetTrimmedSensorName(absl::string_view sensor_name);
// Any implementation of this interface must be thread-safe regarding the listed
// functions.
class Sensor {
public:
// Callback used export batch of sensor data.
using NotificationCb = absl::FunctionRef<void(
std::vector<std::shared_ptr<const SensorValue>>&&)>;
static SensorAttributesStatic CreateStaticAttributes(
absl::string_view sensor_name, const SensorUnit& sensor_unit,
const HalCommonConfig& hal_common_config,
const EntityCommonConfig& entity_common_config,
const ReadingRangeConfigs& reading_range_configs,
const ReadingTransformConfig& reading_transform_config);
virtual ~Sensor() = default;
// Returns the latest sensor reading.
std::shared_ptr<const SensorValue> GetSensorData() const
ABSL_LOCKS_EXCLUDED(sensor_data_mutex_) {
absl::MutexLock lock(&sensor_data_mutex_);
return sensor_data_.empty() ? nullptr : sensor_data_.back();
}
std::vector<std::shared_ptr<const SensorValue>> GetSensorDataHistory() const
ABSL_LOCKS_EXCLUDED(sensor_data_mutex_) {
absl::MutexLock lock(&sensor_data_mutex_);
return {sensor_data_.begin(), sensor_data_.end()};
}
std::vector<std::shared_ptr<const SensorValue>> GetSensorDataHistorySince(
absl::Time start_time) const ABSL_LOCKS_EXCLUDED(sensor_data_mutex_);
// Refreshes the sensor data once asynchronously. The sensor data will be
// updated when the refresh is done. On errors, nullptr will be fed to the
// callback. Detailed error message can be found in the sensor's state.
// The `callback` will be called when the refresh is done with the SensorData
// that has been refreshed or nullptr if there is an error. The `callback` can
// be nullptr. The callback is supposed to be blocking.
// Implementation is also supposed to implement metrics update in this method.
virtual void RefreshOnceAsync(
absl::AnyInvocable<void(const std::shared_ptr<const SensorValue>&)>
callback) = 0;
// Writes the sensor reading to the sensor hardware synchronously.
// Note, this does not update the cached sensor data directly. Sensor data is
// still updated asynchronously by `RefreshOnceAsync`.
virtual absl::Status WriteReading(const SensorValue& value);
// Returns the key of the sensor. A key shall be constant for a sensor's
// lifetime.
std::string GetKey() const {
return sensor_attributes_static_.attributes().key();
}
// Returns the config key of the board that contains this sensor.
std::string GetBoardConfigKey() const {
return sensor_attributes_static_.entity_common_config().board_config_key();
}
SensorAttributesDynamic GetSensorAttributesDynamic() const {
absl::MutexLock lock(&sensor_attributes_dynamic_mutex_);
return sensor_attributes_dynamic_;
}
const SensorAttributesStatic& GetSensorAttributesStatic() const {
return sensor_attributes_static_;
}
SensorMetrics GetSensorMetrics() const;
// Subscribes to the sensor data.
absl::Status Subscribe(const SubscriptionParams* subscription_params);
// Deletes an existing subscription.
absl::Status Unsubscribe(const SubscriptionParams* subscription_params);
void UpdateState(State&& state);
// Updates the thresholds for the sensor.
void UpdateThresholds(const ThresholdConfigs& threshold_configs);
// Resize the buffer for the sensor.
void ResizeBuffer(size_t buffer_size);
// Resets the metrics for the sensor. This is used when the sensor is
// configured with a different sampling interval.
void ResetMetrics();
// When a sensor is configured with a different sampling interval, we use this
// function to update the sampling interval in the sensor dynamic attributes
void UpdateSensorSamplingInterval(absl::Duration new_sampling_interval);
// Since Reinitialize may have to be performed asynchronously, we will invoke
// the callback when the reinitialization is done. The status passed to it
// will indicate the status of the reinitialization.
virtual void Reinitialize(absl::AnyInvocable<void(absl::Status)> callback) {
callback(absl::UnimplementedError("Reinitialize is not implemented for " +
GetKey() +
" with "
"config " +
GetBoardConfigKey()));
}
protected:
Sensor(SensorAttributesStatic&& sensor_attributes_static,
const ThresholdConfigs& threshold_configs,
std::optional<NotificationCb> notification_cb)
: sensor_attributes_static_(std::move(sensor_attributes_static)),
sensor_data_(static_cast<size_t>(
sensor_attributes_static_.entity_common_config().queue_size())),
notification_cb_(notification_cb) {
UpdateThresholds(threshold_configs);
}
Sensor() : sensor_data_(1) {
DLOG(INFO) << "Sensor created with default queue size of "
<< sensor_data_.capacity();
}
// Buffers the sensor data and notifies the subscribers if the batch size
// reaches the threshold.
void StoreSensorData(const std::shared_ptr<const SensorValue>& sensor_data)
ABSL_LOCKS_EXCLUDED(sensor_data_mutex_, sensor_attributes_dynamic_mutex_);
// Given the latency of the most recent hardware polling latency, updates the
// metrics.
void UpdateHardwarePollingMetrics(std::chrono::steady_clock::duration latency)
ABSL_LOCKS_EXCLUDED(sensor_metrics_mutex_);
// Given the timestamp of the most recent software polling read start
// interval, updates the metrics.
void UpdateSoftwarePollingStartMetrics(
std::chrono::steady_clock::duration interval)
ABSL_LOCKS_EXCLUDED(sensor_metrics_mutex_);
// Given the timestamp of the most recent software polling read end interval,
// updates the metrics.
void UpdateSoftwarePollingEndMetrics(
std::chrono::steady_clock::duration interval)
ABSL_LOCKS_EXCLUDED(sensor_metrics_mutex_);
void SetLastRefreshStartTime(std::chrono::steady_clock::time_point time) {
// NOLINTNEXTLINE: Yocto's Abseil doesn't support non-pointer constructor.
absl::MutexLock lock(&sensor_metrics_mutex_);
last_refresh_start_time_ = time;
}
std::chrono::steady_clock::time_point GetLastRefreshStartTime() const {
// NOLINTNEXTLINE: Yocto's Abseil doesn't support non-pointer constructor.
absl::MutexLock lock(&sensor_metrics_mutex_);
return last_refresh_start_time_;
}
void SetLastRefreshEndTime(std::chrono::steady_clock::time_point time) {
// NOLINTNEXTLINE: Yocto's Abseil doesn't support non-pointer constructor.
absl::MutexLock lock(&sensor_metrics_mutex_);
last_refresh_end_time_ = time;
}
std::chrono::steady_clock::time_point GetLastRefreshEndTime() const {
// NOLINTNEXTLINE: Yocto's Abseil doesn't support non-pointer constructor.
absl::MutexLock lock(&sensor_metrics_mutex_);
return last_refresh_end_time_;
}
const SensorAttributesStatic sensor_attributes_static_;
mutable absl::Mutex sensor_attributes_dynamic_mutex_;
SensorAttributesDynamic sensor_attributes_dynamic_
ABSL_GUARDED_BY(sensor_attributes_dynamic_mutex_);
mutable absl::Mutex sensor_data_mutex_;
// Front() returns the oldest data.
boost::circular_buffer<std::shared_ptr<const SensorValue>> sensor_data_
ABSL_GUARDED_BY(sensor_data_mutex_);
// The set of batch sizes that are subscribed to the sensor.
absl::btree_set<const SubscriptionParams*, SubscriptionParams::Compare>
subscription_params_ ABSL_GUARDED_BY(sensor_attributes_dynamic_mutex_);
// Callback to be invoked when the batch size reaches the threshold.
// Not locked: The callback is instantiated in the constructor and is
// supposed to be invoked from a single io_context thread.
const std::optional<NotificationCb> notification_cb_ = std::nullopt;
mutable absl::Mutex sensor_metrics_mutex_;
// The total number of hardware reads.
uint64_t total_hardware_read_cnt_ = 0;
// The total latency of hardware reads in milliseconds.
uint64_t total_hardware_latency_ms_ = 0;
// The total software polling start interval in milliseconds.
uint64_t total_software_polling_start_interval_ms_ = 0;
// The total number of software polling start.
uint64_t total_software_polling_start_cnt_ = 0;
// The total software polling end interval in milliseconds.
uint64_t total_software_polling_end_interval_ms_ = 0;
// The total number of software polling end.
uint64_t total_software_polling_end_cnt_ = 0;
std::chrono::steady_clock::time_point last_refresh_start_time_ =
std::chrono::steady_clock::time_point::min();
std::chrono::steady_clock::time_point last_refresh_end_time_ =
std::chrono::steady_clock::time_point::min();
};
} // namespace milotic_tlbmc
#endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SENSORS_SENSOR_H_