13f7c5e40SJason M. Bills /* 23f7c5e40SJason M. Bills // Copyright (c) 2017 2018 Intel Corporation 33f7c5e40SJason M. Bills // 43f7c5e40SJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License"); 53f7c5e40SJason M. Bills // you may not use this file except in compliance with the License. 63f7c5e40SJason M. Bills // You may obtain a copy of the License at 73f7c5e40SJason M. Bills // 83f7c5e40SJason M. Bills // http://www.apache.org/licenses/LICENSE-2.0 93f7c5e40SJason M. Bills // 103f7c5e40SJason M. Bills // Unless required by applicable law or agreed to in writing, software 113f7c5e40SJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS, 123f7c5e40SJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f7c5e40SJason M. Bills // See the License for the specific language governing permissions and 143f7c5e40SJason M. Bills // limitations under the License. 153f7c5e40SJason M. Bills */ 163f7c5e40SJason M. Bills 173f7c5e40SJason M. Bills #pragma once 18*72867debSJason M. Bills #include <host-ipmid/ipmid-api.h> 19*72867debSJason M. Bills 20*72867debSJason M. Bills #include <cmath> 21*72867debSJason M. Bills #include <iostream> 22*72867debSJason M. Bills #include <phosphor-logging/log.hpp> 233f7c5e40SJason M. Bills 243f7c5e40SJason M. Bills namespace ipmi 253f7c5e40SJason M. Bills { 26*72867debSJason M. Bills static constexpr int16_t maxInt10 = 0x1FF; 27*72867debSJason M. Bills static constexpr int16_t minInt10 = -(0x200); 28*72867debSJason M. Bills static constexpr int8_t maxInt4 = 7; 29*72867debSJason M. Bills static constexpr int8_t minInt4 = -8; 30*72867debSJason M. Bills 31*72867debSJason M. Bills static inline bool getSensorAttributes(const double max, const double min, 32*72867debSJason M. Bills int16_t& mValue, int8_t& rExp, 33*72867debSJason M. Bills int16_t& bValue, int8_t& bExp, 34*72867debSJason M. Bills bool& bSigned) 35*72867debSJason M. Bills { 36*72867debSJason M. Bills // computing y = (10^rRexp) * (Mx + (B*(10^Bexp))) 37*72867debSJason M. Bills // check for 0, assume always positive 38*72867debSJason M. Bills double mDouble; 39*72867debSJason M. Bills double bDouble; 40*72867debSJason M. Bills if (!(max > min)) 41*72867debSJason M. Bills { 42*72867debSJason M. Bills phosphor::logging::log<phosphor::logging::level::DEBUG>( 43*72867debSJason M. Bills "getSensorAttributes: Max must be greater than min"); 44*72867debSJason M. Bills return false; 45*72867debSJason M. Bills } 46*72867debSJason M. Bills else 47*72867debSJason M. Bills { 48*72867debSJason M. Bills mDouble = (max - min) / 0xFF; 49*72867debSJason M. Bills } 50*72867debSJason M. Bills if (!mDouble) 51*72867debSJason M. Bills { 52*72867debSJason M. Bills mDouble = 1; 53*72867debSJason M. Bills } 54*72867debSJason M. Bills 55*72867debSJason M. Bills if (min < 0) 56*72867debSJason M. Bills { 57*72867debSJason M. Bills bSigned = true; 58*72867debSJason M. Bills bDouble = floor(0.5 + ((max + min) / 2)); 59*72867debSJason M. Bills } 60*72867debSJason M. Bills else 61*72867debSJason M. Bills { 62*72867debSJason M. Bills bSigned = false; 63*72867debSJason M. Bills bDouble = min; 64*72867debSJason M. Bills } 65*72867debSJason M. Bills 66*72867debSJason M. Bills rExp = 0; 67*72867debSJason M. Bills 68*72867debSJason M. Bills // M too big for 10 bit variable 69*72867debSJason M. Bills while (mDouble > maxInt10) 70*72867debSJason M. Bills { 71*72867debSJason M. Bills if (rExp == maxInt4) 72*72867debSJason M. Bills { 73*72867debSJason M. Bills phosphor::logging::log<phosphor::logging::level::DEBUG>( 74*72867debSJason M. Bills "rExp Too big, Max and Min range too far", 75*72867debSJason M. Bills phosphor::logging::entry("REXP=%d", rExp)); 76*72867debSJason M. Bills return false; 77*72867debSJason M. Bills } 78*72867debSJason M. Bills mDouble /= 10; 79*72867debSJason M. Bills rExp += 1; 80*72867debSJason M. Bills } 81*72867debSJason M. Bills 82*72867debSJason M. Bills // M too small, loop until we lose less than 1 eight bit count of precision 83*72867debSJason M. Bills while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255)) 84*72867debSJason M. Bills { 85*72867debSJason M. Bills if (rExp == minInt4) 86*72867debSJason M. Bills { 87*72867debSJason M. Bills phosphor::logging::log<phosphor::logging::level::DEBUG>( 88*72867debSJason M. Bills "rExp Too Small, Max and Min range too close"); 89*72867debSJason M. Bills return false; 90*72867debSJason M. Bills } 91*72867debSJason M. Bills // check to see if we reached the limit of where we can adjust back the 92*72867debSJason M. Bills // B value 93*72867debSJason M. Bills if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble) 94*72867debSJason M. Bills { 95*72867debSJason M. Bills if (mDouble < 1.0) 96*72867debSJason M. Bills { 97*72867debSJason M. Bills phosphor::logging::log<phosphor::logging::level::DEBUG>( 98*72867debSJason M. Bills "Could not find mValue and B value with enough " 99*72867debSJason M. Bills "precision."); 100*72867debSJason M. Bills return false; 101*72867debSJason M. Bills } 102*72867debSJason M. Bills break; 103*72867debSJason M. Bills } 104*72867debSJason M. Bills // can't multiply M any more, max precision reached 105*72867debSJason M. Bills else if (mDouble * 10 > maxInt10) 106*72867debSJason M. Bills { 107*72867debSJason M. Bills break; 108*72867debSJason M. Bills } 109*72867debSJason M. Bills mDouble *= 10; 110*72867debSJason M. Bills rExp -= 1; 111*72867debSJason M. Bills } 112*72867debSJason M. Bills 113*72867debSJason M. Bills bDouble /= std::pow(10, rExp); 114*72867debSJason M. Bills bExp = 0; 115*72867debSJason M. Bills 116*72867debSJason M. Bills // B too big for 10 bit variable 117*72867debSJason M. Bills while (bDouble > maxInt10 || bDouble < minInt10) 118*72867debSJason M. Bills { 119*72867debSJason M. Bills if (bExp == maxInt4) 120*72867debSJason M. Bills { 121*72867debSJason M. Bills phosphor::logging::log<phosphor::logging::level::DEBUG>( 122*72867debSJason M. Bills "bExp Too Big, Max and Min range need to be adjusted"); 123*72867debSJason M. Bills return false; 124*72867debSJason M. Bills } 125*72867debSJason M. Bills bDouble /= 10; 126*72867debSJason M. Bills bExp += 1; 127*72867debSJason M. Bills } 128*72867debSJason M. Bills 129*72867debSJason M. Bills while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) > 130*72867debSJason M. Bills (1.0 / 255)) 131*72867debSJason M. Bills { 132*72867debSJason M. Bills if (bExp == minInt4) 133*72867debSJason M. Bills { 134*72867debSJason M. Bills phosphor::logging::log<phosphor::logging::level::DEBUG>( 135*72867debSJason M. Bills "bExp Too Small, Max and Min range need to be adjusted"); 136*72867debSJason M. Bills return false; 137*72867debSJason M. Bills } 138*72867debSJason M. Bills bDouble *= 10; 139*72867debSJason M. Bills bExp -= 1; 140*72867debSJason M. Bills } 141*72867debSJason M. Bills 142*72867debSJason M. Bills mValue = static_cast<int16_t>(mDouble + 0.5) & maxInt10; 143*72867debSJason M. Bills bValue = static_cast<int16_t>(bDouble + 0.5) & maxInt10; 144*72867debSJason M. Bills 145*72867debSJason M. Bills return true; 146*72867debSJason M. Bills } 147*72867debSJason M. Bills 148*72867debSJason M. Bills static inline uint8_t 149*72867debSJason M. Bills scaleIPMIValueFromDouble(const double value, const uint16_t mValue, 1503f7c5e40SJason M. Bills const int8_t rExp, const uint16_t bValue, 151*72867debSJason M. Bills const int8_t bExp, const bool bSigned) 152*72867debSJason M. Bills { 153*72867debSJason M. Bills uint32_t scaledValue = 154*72867debSJason M. Bills (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) / 155*72867debSJason M. Bills (mValue * std::pow(10, rExp)); 156*72867debSJason M. Bills if (bSigned) 157*72867debSJason M. Bills { 158*72867debSJason M. Bills return static_cast<int8_t>(scaledValue); 159*72867debSJason M. Bills } 160*72867debSJason M. Bills else 161*72867debSJason M. Bills { 162*72867debSJason M. Bills return static_cast<uint8_t>(scaledValue); 163*72867debSJason M. Bills } 164*72867debSJason M. Bills } 165*72867debSJason M. Bills 166*72867debSJason M. Bills static inline uint8_t getScaledIPMIValue(const double value, const double max, 167*72867debSJason M. Bills const double min) 168*72867debSJason M. Bills { 169*72867debSJason M. Bills int16_t mValue = 0; 170*72867debSJason M. Bills int8_t rExp = 0; 171*72867debSJason M. Bills int16_t bValue = 0; 172*72867debSJason M. Bills int8_t bExp = 0; 173*72867debSJason M. Bills bool bSigned = 0; 174*72867debSJason M. Bills bool result = 0; 175*72867debSJason M. Bills 176*72867debSJason M. Bills result = getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned); 177*72867debSJason M. Bills if (!result) 178*72867debSJason M. Bills { 179*72867debSJason M. Bills return 0xFF; 180*72867debSJason M. Bills } 181*72867debSJason M. Bills return scaleIPMIValueFromDouble(value, mValue, rExp, bValue, bExp, bSigned); 182*72867debSJason M. Bills } 183*72867debSJason M. Bills 1843f7c5e40SJason M. Bills } // namespace ipmi