| #ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_COLLECTOR_SENSOR_COLLECTOR_H_ |
| #define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_COLLECTOR_SENSOR_COLLECTOR_H_ |
| |
| #include <cstddef> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <thread> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/base/thread_annotations.h" |
| #include "absl/container/flat_hash_map.h" |
| #include "absl/functional/any_invocable.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/synchronization/mutex.h" |
| #include "boost/asio.hpp" //NOLINT: boost::asio is commonly used in BMC |
| #include "thread/thread.h" |
| #include "time/clock.h" |
| #include "nlohmann/json.hpp" |
| #include "tlbmc/collector/collector.h" |
| #include "tlbmc/configs/entity_config.h" |
| #include "tlbmc/hal/sysfs/i2c.h" |
| #include "sensor.pb.h" |
| #include "tlbmc/scheduler/scheduler.h" |
| #include "tlbmc/sensors/sensor.h" |
| |
| namespace milotic_tlbmc { |
| |
| struct ThreadManager { |
| explicit ThreadManager(ecclesia::Clock* clock) |
| : task_scheduler(std::make_unique<TaskScheduler>(clock)) {} |
| |
| ~ThreadManager(); |
| |
| std::vector<std::unique_ptr<ecclesia::ThreadInterface>> threads; |
| std::vector<std::shared_ptr<boost::asio::io_context>> io_contexts; |
| std::vector< |
| boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> |
| work_guards; |
| std::unique_ptr<TaskScheduler> task_scheduler; |
| // This is used to store the task id of the sensor to allow managing the |
| // lifetime of the sensor. |
| absl::flat_hash_map<std::string, int> sensor_key_to_task_id; |
| }; |
| |
| // Register a callback to be invoked when a collector refreshes data. |
| // This class is thread safe. |
| // Used mostly for testing. |
| class SensorNotification { |
| public: |
| explicit SensorNotification( |
| absl::AnyInvocable<void(const std::shared_ptr<const SensorValue>&)> |
| callback) |
| : callback_(std::move(callback)) {} |
| |
| void NotifyWithData(const std::shared_ptr<const SensorValue>& sensor_data) |
| ABSL_LOCKS_EXCLUDED(mutex_) { |
| absl::MutexLock lock(&mutex_); |
| callback_(sensor_data); |
| } |
| |
| private: |
| mutable absl::Mutex mutex_; |
| absl::AnyInvocable<void(const std::shared_ptr<const SensorValue>&)> callback_ |
| ABSL_GUARDED_BY(mutex_); |
| }; |
| |
| class SensorCollector : public Collector { |
| public: |
| // Parameters for creating a sensor collector. |
| struct Params { |
| const EntityConfig& entity_config; |
| const I2cSysfs& i2c_sysfs; |
| // Using a thread factory to allow us to switch to fibers in future when it |
| // gets open sourced. |
| ecclesia::ThreadFactoryInterface* thread_factory = |
| ecclesia::GetDefaultThreadFactory(); |
| SensorNotification* refresh_notification = nullptr; |
| ecclesia::Clock* clock = ecclesia::Clock::RealClock(); |
| // Typically used when we want to override the default sensor sampling |
| // interval. |
| std::optional<int> override_sensor_sampling_interval_ms = std::nullopt; |
| }; |
| |
| // Creates a sensor collector. |
| static absl::StatusOr<std::unique_ptr<SensorCollector>> Create( |
| const Params& params); |
| |
| // Returns the sorted list of sensor names contained by the given Config name. |
| virtual std::vector<std::string> GetAllSensorKeysByConfigName( |
| const std::string& board_config_name) const; |
| |
| // Returns all the sensors sorted by sensor name. |
| virtual std::vector<std::shared_ptr<const Sensor>> GetAllSensors() const; |
| |
| // Configures the sensor collector. |
| // A key usage of this method is to configure the sampling interval of the |
| // data. |
| absl::Status ConfigureCollection(const Config& config) const override; |
| |
| // Returns the sensor for the given board config name and given sensor |
| // key. |
| virtual std::shared_ptr<const Sensor> GetSensorByConfigNameAndSensorKey( |
| const std::string& board_config_name, |
| const std::string& sensor_key) const; |
| |
| nlohmann::json GetSchedulerStats() const override { |
| return thread_manager_->task_scheduler->ToJson(); |
| } |
| |
| nlohmann::json ToJson() const override; |
| |
| protected: |
| // Protected constructor to allow mocking. |
| SensorCollector() = default; |
| |
| private: |
| SensorCollector(std::vector<std::shared_ptr<Sensor>>&& sensors, |
| std::unique_ptr<ThreadManager> thread_manager, |
| const SensorNotification* refresh_notification); |
| |
| // In today's use case, we will never have dynamic set of sensors. All sensors |
| // are created during daemon start-up. |
| // First dimension: board_config_name |
| // Second dimension: sensor_key |
| const absl::flat_hash_map< |
| std::string, absl::flat_hash_map<std::string, std::shared_ptr<Sensor>>> |
| sensor_table_; |
| std::unique_ptr<ThreadManager> thread_manager_; |
| const SensorNotification* refresh_notification_; |
| }; |
| |
| } // namespace milotic_tlbmc |
| |
| #endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_COLLECTOR_SENSOR_COLLECTOR_H_ |