1d7abf367SMatt Spinler /**
2d7abf367SMatt Spinler * Copyright © 2017 IBM Corporation
3d7abf367SMatt Spinler *
4d7abf367SMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License");
5d7abf367SMatt Spinler * you may not use this file except in compliance with the License.
6d7abf367SMatt Spinler * You may obtain a copy of the License at
7d7abf367SMatt Spinler *
8d7abf367SMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0
9d7abf367SMatt Spinler *
10d7abf367SMatt Spinler * Unless required by applicable law or agreed to in writing, software
11d7abf367SMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS,
12d7abf367SMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7abf367SMatt Spinler * See the License for the specific language governing permissions and
14d7abf367SMatt Spinler * limitations under the License.
15d7abf367SMatt Spinler */
16d7abf367SMatt Spinler #include "record_manager.hpp"
17d7abf367SMatt Spinler
18f0f02b9aSMatt Spinler #include <math.h>
19f0f02b9aSMatt Spinler
20f0f02b9aSMatt Spinler #include <phosphor-logging/log.hpp>
21f0f02b9aSMatt Spinler
222c4fbc4cSPatrick Williams #include <chrono>
232c4fbc4cSPatrick Williams
24d7abf367SMatt Spinler namespace witherspoon
25d7abf367SMatt Spinler {
26d7abf367SMatt Spinler namespace power
27d7abf367SMatt Spinler {
28d7abf367SMatt Spinler namespace history
29d7abf367SMatt Spinler {
30d7abf367SMatt Spinler
3128fa1b6bSMatt Spinler using namespace phosphor::logging;
3228fa1b6bSMatt Spinler
add(const std::vector<uint8_t> & rawRecord)338168d280SMatt Spinler bool RecordManager::add(const std::vector<uint8_t>& rawRecord)
348168d280SMatt Spinler {
358168d280SMatt Spinler if (rawRecord.size() == 0)
368168d280SMatt Spinler {
378168d280SMatt Spinler // The PS has no data - either the power supply just started up,
388168d280SMatt Spinler // or it just got a SYNC. Clear the history.
398168d280SMatt Spinler records.clear();
408168d280SMatt Spinler return true;
418168d280SMatt Spinler }
428168d280SMatt Spinler
438168d280SMatt Spinler try
448168d280SMatt Spinler {
458168d280SMatt Spinler // Peek at the ID to see if more processing is needed.
468168d280SMatt Spinler auto id = getRawRecordID(rawRecord);
478168d280SMatt Spinler
488168d280SMatt Spinler if (!records.empty())
498168d280SMatt Spinler {
508168d280SMatt Spinler auto previousID = std::get<recIDPos>(records.front());
518168d280SMatt Spinler
528168d280SMatt Spinler // Already have this record. Done.
538168d280SMatt Spinler if (previousID == id)
548168d280SMatt Spinler {
558168d280SMatt Spinler return false;
568168d280SMatt Spinler }
578168d280SMatt Spinler
588168d280SMatt Spinler // Check that the sequence ID is in order.
598168d280SMatt Spinler // If not, clear out current list.
608168d280SMatt Spinler if ((previousID + 1) != id)
618168d280SMatt Spinler {
628168d280SMatt Spinler // If it just rolled over from 0xFF to 0x00, then no
638168d280SMatt Spinler // need to clear. If we see a 0 seemingly out of nowhere,
648168d280SMatt Spinler // then it was a sync so clear the old records.
65*b7ed5773SPatrick Williams auto rolledOver = (previousID == lastSequenceID) &&
66*b7ed5773SPatrick Williams (id == FIRST_SEQUENCE_ID);
678168d280SMatt Spinler
688168d280SMatt Spinler if (!rolledOver)
698168d280SMatt Spinler {
708168d280SMatt Spinler if (id != FIRST_SEQUENCE_ID)
718168d280SMatt Spinler {
728168d280SMatt Spinler log<level::INFO>(
738168d280SMatt Spinler "Noncontiguous INPUT_HISTORY sequence ID "
748168d280SMatt Spinler "found. Clearing old entries",
758168d280SMatt Spinler entry("OLD_ID=%ld", previousID),
768168d280SMatt Spinler entry("NEW_ID=%ld", id));
778168d280SMatt Spinler }
788168d280SMatt Spinler records.clear();
798168d280SMatt Spinler }
808168d280SMatt Spinler }
818168d280SMatt Spinler }
828168d280SMatt Spinler
838168d280SMatt Spinler records.push_front(std::move(createRecord(rawRecord)));
848168d280SMatt Spinler
858168d280SMatt Spinler // If no more should be stored, prune the oldest
868168d280SMatt Spinler if (records.size() > maxRecords)
878168d280SMatt Spinler {
888168d280SMatt Spinler records.pop_back();
898168d280SMatt Spinler }
908168d280SMatt Spinler }
918168d280SMatt Spinler catch (InvalidRecordException& e)
928168d280SMatt Spinler {
938168d280SMatt Spinler return false;
948168d280SMatt Spinler }
958168d280SMatt Spinler
968168d280SMatt Spinler return true;
978168d280SMatt Spinler }
988168d280SMatt Spinler
getAverageRecords()99c3414388SMatt Spinler auto RecordManager::getAverageRecords() -> DBusRecordList
100c3414388SMatt Spinler {
101c3414388SMatt Spinler DBusRecordList list;
102c3414388SMatt Spinler
103c3414388SMatt Spinler for (const auto& r : records)
104c3414388SMatt Spinler {
105f0f02b9aSMatt Spinler list.emplace_back(std::get<recTimePos>(r), std::get<recAvgPos>(r));
106c3414388SMatt Spinler }
107c3414388SMatt Spinler
108c3414388SMatt Spinler return list;
109c3414388SMatt Spinler }
110c3414388SMatt Spinler
getMaximumRecords()111c3414388SMatt Spinler auto RecordManager::getMaximumRecords() -> DBusRecordList
112c3414388SMatt Spinler {
113c3414388SMatt Spinler DBusRecordList list;
114c3414388SMatt Spinler
115c3414388SMatt Spinler for (const auto& r : records)
116c3414388SMatt Spinler {
117f0f02b9aSMatt Spinler list.emplace_back(std::get<recTimePos>(r), std::get<recMaxPos>(r));
118c3414388SMatt Spinler }
119c3414388SMatt Spinler
120c3414388SMatt Spinler return list;
121c3414388SMatt Spinler }
122c3414388SMatt Spinler
getRawRecordID(const std::vector<uint8_t> & data) const123f0f02b9aSMatt Spinler size_t RecordManager::getRawRecordID(const std::vector<uint8_t>& data) const
12428fa1b6bSMatt Spinler {
12528fa1b6bSMatt Spinler if (data.size() != RAW_RECORD_SIZE)
12628fa1b6bSMatt Spinler {
12728fa1b6bSMatt Spinler log<level::ERR>("Invalid INPUT_HISTORY size",
12828fa1b6bSMatt Spinler entry("SIZE=%d", data.size()));
12928fa1b6bSMatt Spinler throw InvalidRecordException{};
13028fa1b6bSMatt Spinler }
13128fa1b6bSMatt Spinler
13228fa1b6bSMatt Spinler return data[RAW_RECORD_ID_OFFSET];
13328fa1b6bSMatt Spinler }
13428fa1b6bSMatt Spinler
createRecord(const std::vector<uint8_t> & data)13528fa1b6bSMatt Spinler Record RecordManager::createRecord(const std::vector<uint8_t>& data)
13628fa1b6bSMatt Spinler {
13728fa1b6bSMatt Spinler // The raw record format is:
13828fa1b6bSMatt Spinler // 0xAABBCCDDEE
13928fa1b6bSMatt Spinler //
14028fa1b6bSMatt Spinler // where:
14128fa1b6bSMatt Spinler // 0xAA = sequence ID
14228fa1b6bSMatt Spinler // 0xBBCC = average power in linear format (0xCC = MSB)
14328fa1b6bSMatt Spinler // 0xDDEE = maximum power in linear format (0xEE = MSB)
14428fa1b6bSMatt Spinler auto id = getRawRecordID(data);
14528fa1b6bSMatt Spinler
14628fa1b6bSMatt Spinler auto time = std::chrono::duration_cast<std::chrono::milliseconds>(
147f0f02b9aSMatt Spinler std::chrono::system_clock::now().time_since_epoch())
148f0f02b9aSMatt Spinler .count();
14928fa1b6bSMatt Spinler
15028fa1b6bSMatt Spinler auto val = static_cast<uint16_t>(data[2]) << 8 | data[1];
15128fa1b6bSMatt Spinler auto averagePower = linearToInteger(val);
15228fa1b6bSMatt Spinler
15328fa1b6bSMatt Spinler val = static_cast<uint16_t>(data[4]) << 8 | data[3];
15428fa1b6bSMatt Spinler auto maxPower = linearToInteger(val);
15528fa1b6bSMatt Spinler
15628fa1b6bSMatt Spinler return Record{id, time, averagePower, maxPower};
15728fa1b6bSMatt Spinler }
15828fa1b6bSMatt Spinler
linearToInteger(uint16_t data)159e710d189SMatt Spinler int64_t RecordManager::linearToInteger(uint16_t data)
160e710d189SMatt Spinler {
161e710d189SMatt Spinler // The exponent is the first 5 bits, followed by 11 bits of mantissa.
162e710d189SMatt Spinler int8_t exponent = (data & 0xF800) >> 11;
163e710d189SMatt Spinler int16_t mantissa = (data & 0x07FF);
164e710d189SMatt Spinler
165e710d189SMatt Spinler // If exponent's MSB on, then it's negative.
166e710d189SMatt Spinler // Convert from two's complement.
167e710d189SMatt Spinler if (exponent & 0x10)
168e710d189SMatt Spinler {
169e710d189SMatt Spinler exponent = (~exponent) & 0x1F;
170e710d189SMatt Spinler exponent = (exponent + 1) * -1;
171e710d189SMatt Spinler }
172e710d189SMatt Spinler
173e710d189SMatt Spinler // If mantissa's MSB on, then it's negative.
174e710d189SMatt Spinler // Convert from two's complement.
175e710d189SMatt Spinler if (mantissa & 0x400)
176e710d189SMatt Spinler {
177e710d189SMatt Spinler mantissa = (~mantissa) & 0x07FF;
178e710d189SMatt Spinler mantissa = (mantissa + 1) * -1;
179e710d189SMatt Spinler }
180e710d189SMatt Spinler
181e710d189SMatt Spinler auto value = static_cast<float>(mantissa) * pow(2, exponent);
182e710d189SMatt Spinler return value;
183e710d189SMatt Spinler }
184d7abf367SMatt Spinler
185f0f02b9aSMatt Spinler } // namespace history
186f0f02b9aSMatt Spinler } // namespace power
187f0f02b9aSMatt Spinler } // namespace witherspoon
188