blob: 62e2cd251381cf8ddcfcc4ef54e27af4e27fe293 [file] [log] [blame]
/*
// Copyright (c) 2017 2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#include <host-ipmid/ipmid-api.h>
#include <cmath>
#include <iostream>
#include <phosphor-logging/log.hpp>
#include <sensorutils.hpp>
namespace ipmi
{
static constexpr int16_t maxInt10 = 0x1FF;
static constexpr int16_t minInt10 = -(0x200);
static constexpr int8_t maxInt4 = 7;
static constexpr int8_t minInt4 = -8;
bool getSensorAttributes(const double max, const double min, int16_t &mValue,
int8_t &rExp, int16_t &bValue, int8_t &bExp,
bool &bSigned)
{
// computing y = (10^rRexp) * (Mx + (B*(10^Bexp)))
// check for 0, assume always positive
double mDouble;
double bDouble;
if (!(max > min))
{
phosphor::logging::log<phosphor::logging::level::DEBUG>(
"getSensorAttributes: Max must be greater than min");
return false;
}
else
{
mDouble = (max - min) / 0xFF;
}
if (!mDouble)
{
mDouble = 1;
}
if (min < 0)
{
bSigned = true;
bDouble = floor(0.5 + ((max + min) / 2));
}
else
{
bSigned = false;
bDouble = min;
}
rExp = 0;
// M too big for 10 bit variable
while (mDouble > maxInt10)
{
if (rExp == maxInt4)
{
phosphor::logging::log<phosphor::logging::level::DEBUG>(
"rExp Too big, Max and Min range too far");
return false;
}
mDouble /= 10;
rExp += 1;
}
// M too small, loop until we loose less than 1 eight bit count of precision
while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255))
{
if (rExp == minInt4)
{
phosphor::logging::log<phosphor::logging::level::DEBUG>(
"rExp Too Small, Max and Min range too close");
return false;
}
// check to see if we reached the limit of where we can adjust back the
// B value
if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble)
{
if (mDouble < 1.0)
{
phosphor::logging::log<phosphor::logging::level::DEBUG>(
"Could not find mValue and B value with enough "
"precision.");
return false;
}
break;
}
// can't multiply M any more, max precision reached
else if (mDouble * 10 > maxInt10)
{
break;
}
mDouble *= 10;
rExp -= 1;
}
bDouble /= std::pow(10, rExp);
bExp = 0;
// B too big for 10 bit variable
while (bDouble > maxInt10 || bDouble < minInt10)
{
if (bExp == maxInt4)
{
phosphor::logging::log<phosphor::logging::level::DEBUG>(
"bExp Too Big, Max and Min range need to be adjusted");
return false;
}
bDouble /= 10;
bExp += 1;
}
while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) >
(1.0 / 255))
{
if (bExp == minInt4)
{
phosphor::logging::log<phosphor::logging::level::DEBUG>(
"bExp Too Small, Max and Min range need to be adjusted");
return false;
}
bDouble *= 10;
bExp -= 1;
}
mValue = static_cast<int16_t>(mDouble + 0.5) & maxInt10;
bValue = static_cast<int16_t>(bDouble + 0.5) & maxInt10;
return true;
}
uint8_t scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
const int8_t rExp, const uint16_t bValue,
const int8_t bExp, const bool bSigned)
{
uint32_t scaledValue =
(value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) /
(mValue * std::pow(10, rExp));
if (bSigned)
{
return static_cast<int8_t>(scaledValue);
}
else
{
return static_cast<uint8_t>(scaledValue);
}
}
} // namespace ipmi