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 1872867debSJason M. Bills #include <cmath> 1972867debSJason M. Bills #include <iostream> 203f7c5e40SJason M. Bills 213f7c5e40SJason M. Bills namespace ipmi 223f7c5e40SJason M. Bills { 2372867debSJason M. Bills static constexpr int16_t maxInt10 = 0x1FF; 2439417c7bSJames Feist static constexpr int16_t minInt10 = -0x200; 2572867debSJason M. Bills static constexpr int8_t maxInt4 = 7; 2672867debSJason M. Bills static constexpr int8_t minInt4 = -8; 2772867debSJason M. Bills 2872867debSJason M. Bills static inline bool getSensorAttributes(const double max, const double min, 2972867debSJason M. Bills int16_t& mValue, int8_t& rExp, 3072867debSJason M. Bills int16_t& bValue, int8_t& bExp, 3172867debSJason M. Bills bool& bSigned) 3272867debSJason M. Bills { 3372867debSJason M. Bills // computing y = (10^rRexp) * (Mx + (B*(10^Bexp))) 3472867debSJason M. Bills // check for 0, assume always positive 3572867debSJason M. Bills double mDouble; 3672867debSJason M. Bills double bDouble; 3739417c7bSJames Feist if (max <= min) 3872867debSJason M. Bills { 39*53870d73SVernon Mauery std::cerr << "getSensorAttributes: Max must be greater than min\n"; 4072867debSJason M. Bills return false; 4172867debSJason M. Bills } 4239417c7bSJames Feist 4372867debSJason M. Bills mDouble = (max - min) / 0xFF; 4472867debSJason M. Bills 4572867debSJason M. Bills if (min < 0) 4672867debSJason M. Bills { 4772867debSJason M. Bills bSigned = true; 4872867debSJason M. Bills bDouble = floor(0.5 + ((max + min) / 2)); 4972867debSJason M. Bills } 5072867debSJason M. Bills else 5172867debSJason M. Bills { 5272867debSJason M. Bills bSigned = false; 5372867debSJason M. Bills bDouble = min; 5472867debSJason M. Bills } 5572867debSJason M. Bills 5672867debSJason M. Bills rExp = 0; 5772867debSJason M. Bills 5872867debSJason M. Bills // M too big for 10 bit variable 5972867debSJason M. Bills while (mDouble > maxInt10) 6072867debSJason M. Bills { 6139417c7bSJames Feist if (rExp >= maxInt4) 6272867debSJason M. Bills { 63*53870d73SVernon Mauery std::cerr << "rExp Too big, Max and Min range too far REXP=" << rExp 64*53870d73SVernon Mauery << "\n"; 6572867debSJason M. Bills return false; 6672867debSJason M. Bills } 6772867debSJason M. Bills mDouble /= 10; 6839417c7bSJames Feist rExp++; 6972867debSJason M. Bills } 7072867debSJason M. Bills 7172867debSJason M. Bills // M too small, loop until we lose less than 1 eight bit count of precision 7272867debSJason M. Bills while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255)) 7372867debSJason M. Bills { 7439417c7bSJames Feist if (rExp <= minInt4) 7572867debSJason M. Bills { 76*53870d73SVernon Mauery std::cerr << "rExp Too Small, Max and Min range too close\n"; 7772867debSJason M. Bills return false; 7872867debSJason M. Bills } 7972867debSJason M. Bills // check to see if we reached the limit of where we can adjust back the 8072867debSJason M. Bills // B value 8172867debSJason M. Bills if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble) 8272867debSJason M. Bills { 8372867debSJason M. Bills if (mDouble < 1.0) 8472867debSJason M. Bills { 85*53870d73SVernon Mauery std::cerr << "Could not find mValue and B value with enough " 86*53870d73SVernon Mauery "precision.\n"; 8772867debSJason M. Bills return false; 8872867debSJason M. Bills } 8972867debSJason M. Bills break; 9072867debSJason M. Bills } 9172867debSJason M. Bills // can't multiply M any more, max precision reached 9272867debSJason M. Bills else if (mDouble * 10 > maxInt10) 9372867debSJason M. Bills { 9472867debSJason M. Bills break; 9572867debSJason M. Bills } 9672867debSJason M. Bills mDouble *= 10; 9739417c7bSJames Feist rExp--; 9872867debSJason M. Bills } 9972867debSJason M. Bills 10072867debSJason M. Bills bDouble /= std::pow(10, rExp); 10172867debSJason M. Bills bExp = 0; 10272867debSJason M. Bills 10372867debSJason M. Bills // B too big for 10 bit variable 10472867debSJason M. Bills while (bDouble > maxInt10 || bDouble < minInt10) 10572867debSJason M. Bills { 10639417c7bSJames Feist if (bExp >= maxInt4) 10772867debSJason M. Bills { 108*53870d73SVernon Mauery std::cerr 109*53870d73SVernon Mauery << "bExp Too Big, Max and Min range need to be adjusted\n"; 11072867debSJason M. Bills return false; 11172867debSJason M. Bills } 11272867debSJason M. Bills bDouble /= 10; 11339417c7bSJames Feist bExp++; 11472867debSJason M. Bills } 11572867debSJason M. Bills 11672867debSJason M. Bills while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) > 11772867debSJason M. Bills (1.0 / 255)) 11872867debSJason M. Bills { 11939417c7bSJames Feist if (bExp <= minInt4) 12072867debSJason M. Bills { 121*53870d73SVernon Mauery std::cerr 122*53870d73SVernon Mauery << "bExp Too Small, Max and Min range need to be adjusted\n"; 12372867debSJason M. Bills return false; 12472867debSJason M. Bills } 12572867debSJason M. Bills bDouble *= 10; 12672867debSJason M. Bills bExp -= 1; 12772867debSJason M. Bills } 12872867debSJason M. Bills 129aecaef7eSJames Feist mValue = static_cast<int16_t>(std::round(mDouble)) & maxInt10; 13039417c7bSJames Feist bValue = static_cast<int16_t>(bDouble) & maxInt10; 13172867debSJason M. Bills 13272867debSJason M. Bills return true; 13372867debSJason M. Bills } 13472867debSJason M. Bills 13572867debSJason M. Bills static inline uint8_t 13672867debSJason M. Bills scaleIPMIValueFromDouble(const double value, const uint16_t mValue, 1373f7c5e40SJason M. Bills const int8_t rExp, const uint16_t bValue, 13872867debSJason M. Bills const int8_t bExp, const bool bSigned) 13972867debSJason M. Bills { 14072867debSJason M. Bills uint32_t scaledValue = 14172867debSJason M. Bills (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) / 14272867debSJason M. Bills (mValue * std::pow(10, rExp)); 14339417c7bSJames Feist 14439417c7bSJames Feist if (scaledValue > std::numeric_limits<uint8_t>::max() || 14539417c7bSJames Feist scaledValue < std::numeric_limits<uint8_t>::lowest()) 14639417c7bSJames Feist { 14739417c7bSJames Feist throw std::out_of_range("Value out of range"); 14839417c7bSJames Feist } 14972867debSJason M. Bills if (bSigned) 15072867debSJason M. Bills { 15172867debSJason M. Bills return static_cast<int8_t>(scaledValue); 15272867debSJason M. Bills } 15372867debSJason M. Bills else 15472867debSJason M. Bills { 15572867debSJason M. Bills return static_cast<uint8_t>(scaledValue); 15672867debSJason M. Bills } 15772867debSJason M. Bills } 15872867debSJason M. Bills 15972867debSJason M. Bills static inline uint8_t getScaledIPMIValue(const double value, const double max, 16072867debSJason M. Bills const double min) 16172867debSJason M. Bills { 16272867debSJason M. Bills int16_t mValue = 0; 16372867debSJason M. Bills int8_t rExp = 0; 16472867debSJason M. Bills int16_t bValue = 0; 16572867debSJason M. Bills int8_t bExp = 0; 16672867debSJason M. Bills bool bSigned = 0; 16772867debSJason M. Bills bool result = 0; 16872867debSJason M. Bills 16972867debSJason M. Bills result = getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned); 17072867debSJason M. Bills if (!result) 17172867debSJason M. Bills { 17239417c7bSJames Feist throw std::runtime_error("Illegal sensor attributes"); 17372867debSJason M. Bills } 17472867debSJason M. Bills return scaleIPMIValueFromDouble(value, mValue, rExp, bValue, bExp, bSigned); 17572867debSJason M. Bills } 17672867debSJason M. Bills 1773f7c5e40SJason M. Bills } // namespace ipmi 178