blob: 73459dfe96cfe862416ef689f10fc5feb8811d04 [file] [log] [blame]
Matt Spinlerd7abf362018-01-18 12:40:02 -06001#pragma once
2
3#include <deque>
4#include <tuple>
5#include <vector>
6
7namespace witherspoon
8{
9namespace power
10{
11namespace history
12{
13
14static constexpr auto recIDPos = 0;
15static constexpr auto recTimePos = 1;
16static constexpr auto recAvgPos = 2;
17static constexpr auto recMaxPos = 3;
18using Record = std::tuple<size_t, int64_t, int64_t, int64_t>;
19
20/**
Matt Spinler28fa1b62018-01-18 13:15:02 -060021 * @class InvalidRecordException
22 *
23 * The exception that is thrown when a raw history record
24 * cannot be parsed.
25 */
26class InvalidRecordException : public std::runtime_error
27{
28 public:
29
30 InvalidRecordException() :
31 std::runtime_error("Invalid history record")
32 {
33 }
34};
35
36/**
Matt Spinlerd7abf362018-01-18 12:40:02 -060037 * @class RecordManager
38 *
39 * This class manages the records for the input power history of
40 * a power supply.
41 *
42 * The history is the average and maximum power values across 30s
43 * intervals. Every 30s, a new record will be available from the
44 * PS. This class takes that raw PS data and converts it into
45 * something useable by D-Bus. It ensures the readings are always
46 * sorted newest to oldest, and prunes out the oldest entries when
47 * necessary. If there is a problem with the ordering IDs coming
48 * from the PS, it will clear out the old records and start over.
49 */
50class RecordManager
51{
52 public:
53
Matt Spinler28fa1b62018-01-18 13:15:02 -060054 static constexpr auto RAW_RECORD_SIZE = 5;
55 static constexpr auto RAW_RECORD_ID_OFFSET = 0;
Matt Spinlerd7abf362018-01-18 12:40:02 -060056 static constexpr auto LAST_SEQUENCE_ID = 0xFF;
57
58 using DBusRecord = std::tuple<uint64_t, int64_t>;
59 using DBusRecordList = std::vector<DBusRecord>;
60
61 RecordManager() = delete;
62 ~RecordManager() = default;
63 RecordManager(const RecordManager&) = default;
64 RecordManager& operator=(const RecordManager&) = default;
65 RecordManager(RecordManager&&) = default;
66 RecordManager& operator=(RecordManager&&) = default;
67
68 /**
69 * @brief Constructor
70 *
71 * @param[in] maxRec - the maximum number of history
72 * records to keep at a time
73 */
74 RecordManager(size_t maxRec) :
75 RecordManager(maxRec, LAST_SEQUENCE_ID)
76 {
77 }
78
79 /**
80 * @brief Constructor
81 *
82 * @param[in] maxRec - the maximum number of history
83 * records to keep at a time
84 * @param[in] lastSequenceID - the last sequence ID the power supply
85 * will use before starting over
86 */
87 RecordManager(size_t maxRec, size_t lastSequenceID) :
88 maxRecords(maxRec),
89 lastSequenceID(lastSequenceID)
90 {
91 }
92
93 /**
Matt Spinlere710d182018-01-18 13:06:17 -060094 * @brief Converts a Linear Format power number to an integer
95 *
96 * The PMBus spec describes a 2 byte Linear Format
97 * number that is composed of an exponent and mantissa
98 * in two's complement notation.
99 *
100 * Value = Mantissa * 2**Exponent
101 *
102 * @return int64_t the converted value
103 */
104 static int64_t linearToInteger(uint16_t data);
105
106 /**
Matt Spinlerd7abf362018-01-18 12:40:02 -0600107 * @brief Returns the number of records
108 *
109 * @return size_t - the number of records
110 *
111 */
112 inline size_t getNumRecords() const
113 {
114 return records.size();
115 }
116
117 /**
118 * @brief Deletes all records
119 */
120 inline void clear()
121 {
122 records.clear();
123 }
124
125 private:
126
127 /**
Matt Spinler28fa1b62018-01-18 13:15:02 -0600128 * @brief returns the sequence ID from a raw history record
129 *
130 * Throws InvalidRecordException if the data is the wrong length.
131 *
132 * @param[in] data - the raw record data as the PS returns it
133 *
134 * @return size_t - the ID from byte 0
135 */
136 size_t getRawRecordID(const std::vector<uint8_t>& data) const;
137
138 /**
139 * @brief Creates an instance of a Record from the raw PS data
140 *
141 * @param[in] data - the raw record data as the PS returns it
142 *
143 * @return Record - A filled in Record instance
144 */
145 Record createRecord(const std::vector<uint8_t>& data);
146
147 /**
Matt Spinlerd7abf362018-01-18 12:40:02 -0600148 * @brief The maximum number of entries to keep in the history.
149 *
150 * When a new record is added, the oldest one will be removed.
151 */
152 const size_t maxRecords;
153
154 /**
155 * @brief The last ID the power supply returns before rolling over
156 * back to the first ID of 0.
157 */
158 const size_t lastSequenceID;
159
160 /**
161 * @brief The list of timestamp/average/maximum records.
162 * Newer records are added to the front, and older ones
163 * removed from the back.
164 */
165 std::deque<Record> records;
166};
167
168}
169}
170}