xref: /openbmc/witherspoon-pfault-analysis/power-supply/record_manager.hpp (revision b7ed5773faba29c897871edfce4c9f8a237f499a)
1d7abf367SMatt Spinler #pragma once
2d7abf367SMatt Spinler 
32c4fbc4cSPatrick Williams #include <cstdint>
4d7abf367SMatt Spinler #include <deque>
52c4fbc4cSPatrick Williams #include <stdexcept>
6d7abf367SMatt Spinler #include <tuple>
7d7abf367SMatt Spinler #include <vector>
8d7abf367SMatt Spinler 
9d7abf367SMatt Spinler namespace witherspoon
10d7abf367SMatt Spinler {
11d7abf367SMatt Spinler namespace power
12d7abf367SMatt Spinler {
13d7abf367SMatt Spinler namespace history
14d7abf367SMatt Spinler {
15d7abf367SMatt Spinler 
16d7abf367SMatt Spinler static constexpr auto recIDPos = 0;
17d7abf367SMatt Spinler static constexpr auto recTimePos = 1;
18d7abf367SMatt Spinler static constexpr auto recAvgPos = 2;
19d7abf367SMatt Spinler static constexpr auto recMaxPos = 3;
20d7abf367SMatt Spinler using Record = std::tuple<size_t, int64_t, int64_t, int64_t>;
21d7abf367SMatt Spinler 
22d7abf367SMatt Spinler /**
2328fa1b6bSMatt Spinler  * @class InvalidRecordException
2428fa1b6bSMatt Spinler  *
2528fa1b6bSMatt Spinler  * The exception that is thrown when a raw history record
2628fa1b6bSMatt Spinler  * cannot be parsed.
2728fa1b6bSMatt Spinler  */
2828fa1b6bSMatt Spinler class InvalidRecordException : public std::runtime_error
2928fa1b6bSMatt Spinler {
3028fa1b6bSMatt Spinler   public:
InvalidRecordException()31*b7ed5773SPatrick Williams     InvalidRecordException() : std::runtime_error("Invalid history record") {}
3228fa1b6bSMatt Spinler };
3328fa1b6bSMatt Spinler 
3428fa1b6bSMatt Spinler /**
35d7abf367SMatt Spinler  * @class RecordManager
36d7abf367SMatt Spinler  *
37d7abf367SMatt Spinler  * This class manages the records for the input power history of
38d7abf367SMatt Spinler  * a power supply.
39d7abf367SMatt Spinler  *
40d7abf367SMatt Spinler  * The history is the average and maximum power values across 30s
41d7abf367SMatt Spinler  * intervals.  Every 30s, a new record will be available from the
42d7abf367SMatt Spinler  * PS.  This class takes that raw PS data and converts it into
43cab48342SGunnar Mills  * something usable by D-Bus.  It ensures the readings are always
44d7abf367SMatt Spinler  * sorted newest to oldest, and prunes out the oldest entries when
45d7abf367SMatt Spinler  * necessary.  If there is a problem with the ordering IDs coming
46d7abf367SMatt Spinler  * from the PS, it will clear out the old records and start over.
47d7abf367SMatt Spinler  */
48d7abf367SMatt Spinler class RecordManager
49d7abf367SMatt Spinler {
50d7abf367SMatt Spinler   public:
5128fa1b6bSMatt Spinler     static constexpr auto RAW_RECORD_SIZE = 5;
5228fa1b6bSMatt Spinler     static constexpr auto RAW_RECORD_ID_OFFSET = 0;
538168d280SMatt Spinler     static constexpr auto FIRST_SEQUENCE_ID = 0;
54d7abf367SMatt Spinler     static constexpr auto LAST_SEQUENCE_ID = 0xFF;
55d7abf367SMatt Spinler 
56d7abf367SMatt Spinler     using DBusRecord = std::tuple<uint64_t, int64_t>;
57d7abf367SMatt Spinler     using DBusRecordList = std::vector<DBusRecord>;
58d7abf367SMatt Spinler 
59d7abf367SMatt Spinler     RecordManager() = delete;
60d7abf367SMatt Spinler     ~RecordManager() = default;
61d7abf367SMatt Spinler     RecordManager(const RecordManager&) = default;
62d7abf367SMatt Spinler     RecordManager& operator=(const RecordManager&) = default;
63d7abf367SMatt Spinler     RecordManager(RecordManager&&) = default;
64d7abf367SMatt Spinler     RecordManager& operator=(RecordManager&&) = default;
65d7abf367SMatt Spinler 
66d7abf367SMatt Spinler     /**
67d7abf367SMatt Spinler      * @brief Constructor
68d7abf367SMatt Spinler      *
69d7abf367SMatt Spinler      * @param[in] maxRec - the maximum number of history
70d7abf367SMatt Spinler      *                     records to keep at a time
71d7abf367SMatt Spinler      */
RecordManager(size_t maxRec)72*b7ed5773SPatrick Williams     RecordManager(size_t maxRec) : RecordManager(maxRec, LAST_SEQUENCE_ID) {}
73d7abf367SMatt Spinler 
74d7abf367SMatt Spinler     /**
75d7abf367SMatt Spinler      * @brief Constructor
76d7abf367SMatt Spinler      *
77d7abf367SMatt Spinler      * @param[in] maxRec - the maximum number of history
78d7abf367SMatt Spinler      *                     records to keep at a time
79d7abf367SMatt Spinler      * @param[in] lastSequenceID - the last sequence ID the power supply
80d7abf367SMatt Spinler      *                             will use before starting over
81d7abf367SMatt Spinler      */
RecordManager(size_t maxRec,size_t lastSequenceID)82d7abf367SMatt Spinler     RecordManager(size_t maxRec, size_t lastSequenceID) :
83f0f02b9aSMatt Spinler         maxRecords(maxRec), lastSequenceID(lastSequenceID)
842c4fbc4cSPatrick Williams     {}
85d7abf367SMatt Spinler 
86d7abf367SMatt Spinler     /**
878168d280SMatt Spinler      * @brief Adds a new entry to the history
888168d280SMatt Spinler      *
898168d280SMatt Spinler      * Also checks to see if the old history should be
908168d280SMatt Spinler      * cleared, such as when there is an invalid record
918168d280SMatt Spinler      * sequence ID or if there was no data from the PS.
928168d280SMatt Spinler      *
938168d280SMatt Spinler      * @param[in] rawRecord - the record data straight
948168d280SMatt Spinler      *                    from the power supply
958168d280SMatt Spinler      *
968168d280SMatt Spinler      * @return bool - If there has been a change to the
978168d280SMatt Spinler      *                history records that needs to be
988168d280SMatt Spinler      *                reflected in D-Bus.
998168d280SMatt Spinler      */
1008168d280SMatt Spinler     bool add(const std::vector<uint8_t>& rawRecord);
1018168d280SMatt Spinler 
1028168d280SMatt Spinler     /**
103c3414388SMatt Spinler      * @brief Returns the history of average input power
104c3414388SMatt Spinler      *        in a representation used by D-Bus.
105c3414388SMatt Spinler      *
106c3414388SMatt Spinler      * @return DBusRecordList - A list of averages with
107c3414388SMatt Spinler      *         a timestamp for each entry.
108c3414388SMatt Spinler      */
109c3414388SMatt Spinler     DBusRecordList getAverageRecords();
110c3414388SMatt Spinler 
111c3414388SMatt Spinler     /**
112c3414388SMatt Spinler      * @brief Returns the history of maximum input power
113c3414388SMatt Spinler      *        in a representation used by D-Bus.
114c3414388SMatt Spinler      *
115c3414388SMatt Spinler      * @return DBusRecordList - A list of maximums with
116c3414388SMatt Spinler      *         a timestamp for each entry.
117c3414388SMatt Spinler      */
118c3414388SMatt Spinler     DBusRecordList getMaximumRecords();
119c3414388SMatt Spinler 
120c3414388SMatt Spinler     /**
121e710d189SMatt Spinler      * @brief Converts a Linear Format power number to an integer
122e710d189SMatt Spinler      *
123e710d189SMatt Spinler      * The PMBus spec describes a 2 byte Linear Format
124e710d189SMatt Spinler      * number that is composed of an exponent and mantissa
125e710d189SMatt Spinler      * in two's complement notation.
126e710d189SMatt Spinler      *
127e710d189SMatt Spinler      * Value = Mantissa * 2**Exponent
128e710d189SMatt Spinler      *
129e710d189SMatt Spinler      * @return int64_t the converted value
130e710d189SMatt Spinler      */
131e710d189SMatt Spinler     static int64_t linearToInteger(uint16_t data);
132e710d189SMatt Spinler 
133e710d189SMatt Spinler     /**
134d7abf367SMatt Spinler      * @brief Returns the number of records
135d7abf367SMatt Spinler      *
136d7abf367SMatt Spinler      * @return size_t - the number of records
137d7abf367SMatt Spinler      *
138d7abf367SMatt Spinler      */
getNumRecords() const139d7abf367SMatt Spinler     inline size_t getNumRecords() const
140d7abf367SMatt Spinler     {
141d7abf367SMatt Spinler         return records.size();
142d7abf367SMatt Spinler     }
143d7abf367SMatt Spinler 
144d7abf367SMatt Spinler     /**
145d7abf367SMatt Spinler      * @brief Deletes all records
146d7abf367SMatt Spinler      */
clear()147d7abf367SMatt Spinler     inline void clear()
148d7abf367SMatt Spinler     {
149d7abf367SMatt Spinler         records.clear();
150d7abf367SMatt Spinler     }
151d7abf367SMatt Spinler 
152d7abf367SMatt Spinler   private:
153d7abf367SMatt Spinler     /**
15428fa1b6bSMatt Spinler      * @brief returns the sequence ID from a raw history record
15528fa1b6bSMatt Spinler      *
15628fa1b6bSMatt Spinler      * Throws InvalidRecordException if the data is the wrong length.
15728fa1b6bSMatt Spinler      *
15828fa1b6bSMatt Spinler      * @param[in] data - the raw record data as the PS returns it
15928fa1b6bSMatt Spinler      *
16028fa1b6bSMatt Spinler      * @return size_t - the ID from byte 0
16128fa1b6bSMatt Spinler      */
16228fa1b6bSMatt Spinler     size_t getRawRecordID(const std::vector<uint8_t>& data) const;
16328fa1b6bSMatt Spinler 
16428fa1b6bSMatt Spinler     /**
16528fa1b6bSMatt Spinler      * @brief Creates an instance of a Record from the raw PS data
16628fa1b6bSMatt Spinler      *
16728fa1b6bSMatt Spinler      * @param[in] data - the raw record data as the PS returns it
16828fa1b6bSMatt Spinler      *
16928fa1b6bSMatt Spinler      * @return Record - A filled in Record instance
17028fa1b6bSMatt Spinler      */
17128fa1b6bSMatt Spinler     Record createRecord(const std::vector<uint8_t>& data);
17228fa1b6bSMatt Spinler 
17328fa1b6bSMatt Spinler     /**
174d7abf367SMatt Spinler      * @brief The maximum number of entries to keep in the history.
175d7abf367SMatt Spinler      *
176d7abf367SMatt Spinler      * When a new record is added, the oldest one will be removed.
177d7abf367SMatt Spinler      */
178d7abf367SMatt Spinler     const size_t maxRecords;
179d7abf367SMatt Spinler 
180d7abf367SMatt Spinler     /**
181d7abf367SMatt Spinler      * @brief The last ID the power supply returns before rolling over
182d7abf367SMatt Spinler      *        back to the first ID of 0.
183d7abf367SMatt Spinler      */
184d7abf367SMatt Spinler     const size_t lastSequenceID;
185d7abf367SMatt Spinler 
186d7abf367SMatt Spinler     /**
187d7abf367SMatt Spinler      * @brief The list of timestamp/average/maximum records.
188d7abf367SMatt Spinler      *        Newer records are added to the front, and older ones
189d7abf367SMatt Spinler      *        removed from the back.
190d7abf367SMatt Spinler      */
191d7abf367SMatt Spinler     std::deque<Record> records;
192d7abf367SMatt Spinler };
193d7abf367SMatt Spinler 
194f0f02b9aSMatt Spinler } // namespace history
195f0f02b9aSMatt Spinler } // namespace power
196f0f02b9aSMatt Spinler } // namespace witherspoon
197