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 */ 1628fa1b6bSMatt Spinler #include <chrono> 17e710d189SMatt Spinler #include <math.h> 1828fa1b6bSMatt Spinler #include <phosphor-logging/log.hpp> 19d7abf367SMatt Spinler #include "record_manager.hpp" 20d7abf367SMatt Spinler 21d7abf367SMatt Spinler namespace witherspoon 22d7abf367SMatt Spinler { 23d7abf367SMatt Spinler namespace power 24d7abf367SMatt Spinler { 25d7abf367SMatt Spinler namespace history 26d7abf367SMatt Spinler { 27d7abf367SMatt Spinler 2828fa1b6bSMatt Spinler using namespace phosphor::logging; 2928fa1b6bSMatt Spinler 30*8168d280SMatt Spinler bool RecordManager::add(const std::vector<uint8_t>& rawRecord) 31*8168d280SMatt Spinler { 32*8168d280SMatt Spinler if (rawRecord.size() == 0) 33*8168d280SMatt Spinler { 34*8168d280SMatt Spinler //The PS has no data - either the power supply just started up, 35*8168d280SMatt Spinler //or it just got a SYNC. Clear the history. 36*8168d280SMatt Spinler records.clear(); 37*8168d280SMatt Spinler return true; 38*8168d280SMatt Spinler } 39*8168d280SMatt Spinler 40*8168d280SMatt Spinler try 41*8168d280SMatt Spinler { 42*8168d280SMatt Spinler //Peek at the ID to see if more processing is needed. 43*8168d280SMatt Spinler auto id = getRawRecordID(rawRecord); 44*8168d280SMatt Spinler 45*8168d280SMatt Spinler if (!records.empty()) 46*8168d280SMatt Spinler { 47*8168d280SMatt Spinler auto previousID = std::get<recIDPos>(records.front()); 48*8168d280SMatt Spinler 49*8168d280SMatt Spinler //Already have this record. Done. 50*8168d280SMatt Spinler if (previousID == id) 51*8168d280SMatt Spinler { 52*8168d280SMatt Spinler return false; 53*8168d280SMatt Spinler } 54*8168d280SMatt Spinler 55*8168d280SMatt Spinler //Check that the sequence ID is in order. 56*8168d280SMatt Spinler //If not, clear out current list. 57*8168d280SMatt Spinler if ((previousID + 1) != id) 58*8168d280SMatt Spinler { 59*8168d280SMatt Spinler //If it just rolled over from 0xFF to 0x00, then no 60*8168d280SMatt Spinler //need to clear. If we see a 0 seemingly out of nowhere, 61*8168d280SMatt Spinler //then it was a sync so clear the old records. 62*8168d280SMatt Spinler auto rolledOver = 63*8168d280SMatt Spinler (previousID == lastSequenceID) && 64*8168d280SMatt Spinler (id == FIRST_SEQUENCE_ID); 65*8168d280SMatt Spinler 66*8168d280SMatt Spinler if (!rolledOver) 67*8168d280SMatt Spinler { 68*8168d280SMatt Spinler if (id != FIRST_SEQUENCE_ID) 69*8168d280SMatt Spinler { 70*8168d280SMatt Spinler log<level::INFO>( 71*8168d280SMatt Spinler "Noncontiguous INPUT_HISTORY sequence ID " 72*8168d280SMatt Spinler "found. Clearing old entries", 73*8168d280SMatt Spinler entry("OLD_ID=%ld", previousID), 74*8168d280SMatt Spinler entry("NEW_ID=%ld", id)); 75*8168d280SMatt Spinler } 76*8168d280SMatt Spinler records.clear(); 77*8168d280SMatt Spinler } 78*8168d280SMatt Spinler } 79*8168d280SMatt Spinler } 80*8168d280SMatt Spinler 81*8168d280SMatt Spinler records.push_front(std::move(createRecord(rawRecord))); 82*8168d280SMatt Spinler 83*8168d280SMatt Spinler //If no more should be stored, prune the oldest 84*8168d280SMatt Spinler if (records.size() > maxRecords) 85*8168d280SMatt Spinler { 86*8168d280SMatt Spinler records.pop_back(); 87*8168d280SMatt Spinler } 88*8168d280SMatt Spinler } 89*8168d280SMatt Spinler catch (InvalidRecordException& e) 90*8168d280SMatt Spinler { 91*8168d280SMatt Spinler return false; 92*8168d280SMatt Spinler } 93*8168d280SMatt Spinler 94*8168d280SMatt Spinler return true; 95*8168d280SMatt Spinler } 96*8168d280SMatt Spinler 9728fa1b6bSMatt Spinler size_t RecordManager::getRawRecordID( 9828fa1b6bSMatt Spinler const std::vector<uint8_t>& data) const 9928fa1b6bSMatt Spinler { 10028fa1b6bSMatt Spinler if (data.size() != RAW_RECORD_SIZE) 10128fa1b6bSMatt Spinler { 10228fa1b6bSMatt Spinler log<level::ERR>("Invalid INPUT_HISTORY size", 10328fa1b6bSMatt Spinler entry("SIZE=%d", data.size())); 10428fa1b6bSMatt Spinler throw InvalidRecordException{}; 10528fa1b6bSMatt Spinler } 10628fa1b6bSMatt Spinler 10728fa1b6bSMatt Spinler return data[RAW_RECORD_ID_OFFSET]; 10828fa1b6bSMatt Spinler } 10928fa1b6bSMatt Spinler 11028fa1b6bSMatt Spinler Record RecordManager::createRecord(const std::vector<uint8_t>& data) 11128fa1b6bSMatt Spinler { 11228fa1b6bSMatt Spinler //The raw record format is: 11328fa1b6bSMatt Spinler // 0xAABBCCDDEE 11428fa1b6bSMatt Spinler // 11528fa1b6bSMatt Spinler // where: 11628fa1b6bSMatt Spinler // 0xAA = sequence ID 11728fa1b6bSMatt Spinler // 0xBBCC = average power in linear format (0xCC = MSB) 11828fa1b6bSMatt Spinler // 0xDDEE = maximum power in linear format (0xEE = MSB) 11928fa1b6bSMatt Spinler auto id = getRawRecordID(data); 12028fa1b6bSMatt Spinler 12128fa1b6bSMatt Spinler auto time = std::chrono::duration_cast<std::chrono::milliseconds>( 12228fa1b6bSMatt Spinler std::chrono::system_clock::now().time_since_epoch()).count(); 12328fa1b6bSMatt Spinler 12428fa1b6bSMatt Spinler auto val = static_cast<uint16_t>(data[2]) << 8 | data[1]; 12528fa1b6bSMatt Spinler auto averagePower = linearToInteger(val); 12628fa1b6bSMatt Spinler 12728fa1b6bSMatt Spinler val = static_cast<uint16_t>(data[4]) << 8 | data[3]; 12828fa1b6bSMatt Spinler auto maxPower = linearToInteger(val); 12928fa1b6bSMatt Spinler 13028fa1b6bSMatt Spinler return Record{id, time, averagePower, maxPower}; 13128fa1b6bSMatt Spinler } 13228fa1b6bSMatt Spinler 133e710d189SMatt Spinler int64_t RecordManager::linearToInteger(uint16_t data) 134e710d189SMatt Spinler { 135e710d189SMatt Spinler //The exponent is the first 5 bits, followed by 11 bits of mantissa. 136e710d189SMatt Spinler int8_t exponent = (data & 0xF800) >> 11; 137e710d189SMatt Spinler int16_t mantissa = (data & 0x07FF); 138e710d189SMatt Spinler 139e710d189SMatt Spinler //If exponent's MSB on, then it's negative. 140e710d189SMatt Spinler //Convert from two's complement. 141e710d189SMatt Spinler if (exponent & 0x10) 142e710d189SMatt Spinler { 143e710d189SMatt Spinler exponent = (~exponent) & 0x1F; 144e710d189SMatt Spinler exponent = (exponent + 1) * -1; 145e710d189SMatt Spinler } 146e710d189SMatt Spinler 147e710d189SMatt Spinler //If mantissa's MSB on, then it's negative. 148e710d189SMatt Spinler //Convert from two's complement. 149e710d189SMatt Spinler if (mantissa & 0x400) 150e710d189SMatt Spinler { 151e710d189SMatt Spinler mantissa = (~mantissa) & 0x07FF; 152e710d189SMatt Spinler mantissa = (mantissa + 1) * -1; 153e710d189SMatt Spinler } 154e710d189SMatt Spinler 155e710d189SMatt Spinler auto value = static_cast<float>(mantissa) * pow(2, exponent); 156e710d189SMatt Spinler return value; 157e710d189SMatt Spinler } 158d7abf367SMatt Spinler 159d7abf367SMatt Spinler } 160d7abf367SMatt Spinler } 161d7abf367SMatt Spinler } 162