blob: ffd06a0bc98106954534c49a82a2956700e35e32 [file] [log] [blame]
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001/*
2// Copyright (c) 2017 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#pragma once
Jason M. Bills6d9c83f2019-02-08 14:02:19 -080018#include <ipmid/api.h>
Jason M. Bills72867de2018-11-28 12:46:59 -080019
20#include <cmath>
21#include <iostream>
22#include <phosphor-logging/log.hpp>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070023
24namespace ipmi
25{
Jason M. Bills72867de2018-11-28 12:46:59 -080026static constexpr int16_t maxInt10 = 0x1FF;
James Feist39417c72019-01-03 09:14:24 -080027static constexpr int16_t minInt10 = -0x200;
Jason M. Bills72867de2018-11-28 12:46:59 -080028static constexpr int8_t maxInt4 = 7;
29static constexpr int8_t minInt4 = -8;
30
31static inline bool getSensorAttributes(const double max, const double min,
32 int16_t& mValue, int8_t& rExp,
33 int16_t& bValue, int8_t& bExp,
34 bool& bSigned)
35{
36 // computing y = (10^rRexp) * (Mx + (B*(10^Bexp)))
37 // check for 0, assume always positive
38 double mDouble;
39 double bDouble;
James Feist39417c72019-01-03 09:14:24 -080040 if (max <= min)
Jason M. Bills72867de2018-11-28 12:46:59 -080041 {
42 phosphor::logging::log<phosphor::logging::level::DEBUG>(
43 "getSensorAttributes: Max must be greater than min");
44 return false;
45 }
James Feist39417c72019-01-03 09:14:24 -080046
47 mDouble = (max - min) / 0xFF;
Jason M. Bills72867de2018-11-28 12:46:59 -080048
49 if (min < 0)
50 {
51 bSigned = true;
52 bDouble = floor(0.5 + ((max + min) / 2));
53 }
54 else
55 {
56 bSigned = false;
57 bDouble = min;
58 }
59
60 rExp = 0;
61
62 // M too big for 10 bit variable
63 while (mDouble > maxInt10)
64 {
James Feist39417c72019-01-03 09:14:24 -080065 if (rExp >= maxInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -080066 {
67 phosphor::logging::log<phosphor::logging::level::DEBUG>(
68 "rExp Too big, Max and Min range too far",
69 phosphor::logging::entry("REXP=%d", rExp));
70 return false;
71 }
72 mDouble /= 10;
James Feist39417c72019-01-03 09:14:24 -080073 rExp++;
Jason M. Bills72867de2018-11-28 12:46:59 -080074 }
75
76 // M too small, loop until we lose less than 1 eight bit count of precision
77 while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255))
78 {
James Feist39417c72019-01-03 09:14:24 -080079 if (rExp <= minInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -080080 {
81 phosphor::logging::log<phosphor::logging::level::DEBUG>(
82 "rExp Too Small, Max and Min range too close");
83 return false;
84 }
85 // check to see if we reached the limit of where we can adjust back the
86 // B value
87 if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble)
88 {
89 if (mDouble < 1.0)
90 {
91 phosphor::logging::log<phosphor::logging::level::DEBUG>(
92 "Could not find mValue and B value with enough "
93 "precision.");
94 return false;
95 }
96 break;
97 }
98 // can't multiply M any more, max precision reached
99 else if (mDouble * 10 > maxInt10)
100 {
101 break;
102 }
103 mDouble *= 10;
James Feist39417c72019-01-03 09:14:24 -0800104 rExp--;
Jason M. Bills72867de2018-11-28 12:46:59 -0800105 }
106
107 bDouble /= std::pow(10, rExp);
108 bExp = 0;
109
110 // B too big for 10 bit variable
111 while (bDouble > maxInt10 || bDouble < minInt10)
112 {
James Feist39417c72019-01-03 09:14:24 -0800113 if (bExp >= maxInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -0800114 {
115 phosphor::logging::log<phosphor::logging::level::DEBUG>(
116 "bExp Too Big, Max and Min range need to be adjusted");
117 return false;
118 }
119 bDouble /= 10;
James Feist39417c72019-01-03 09:14:24 -0800120 bExp++;
Jason M. Bills72867de2018-11-28 12:46:59 -0800121 }
122
123 while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) >
124 (1.0 / 255))
125 {
James Feist39417c72019-01-03 09:14:24 -0800126 if (bExp <= minInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -0800127 {
128 phosphor::logging::log<phosphor::logging::level::DEBUG>(
129 "bExp Too Small, Max and Min range need to be adjusted");
130 return false;
131 }
132 bDouble *= 10;
133 bExp -= 1;
134 }
135
James Feist39417c72019-01-03 09:14:24 -0800136 mValue = static_cast<int16_t>(mDouble) & maxInt10;
137 bValue = static_cast<int16_t>(bDouble) & maxInt10;
Jason M. Bills72867de2018-11-28 12:46:59 -0800138
139 return true;
140}
141
142static inline uint8_t
143 scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
144 const int8_t rExp, const uint16_t bValue,
145 const int8_t bExp, const bool bSigned)
146{
147 uint32_t scaledValue =
148 (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) /
149 (mValue * std::pow(10, rExp));
James Feist39417c72019-01-03 09:14:24 -0800150
151 if (scaledValue > std::numeric_limits<uint8_t>::max() ||
152 scaledValue < std::numeric_limits<uint8_t>::lowest())
153 {
154 throw std::out_of_range("Value out of range");
155 }
Jason M. Bills72867de2018-11-28 12:46:59 -0800156 if (bSigned)
157 {
158 return static_cast<int8_t>(scaledValue);
159 }
160 else
161 {
162 return static_cast<uint8_t>(scaledValue);
163 }
164}
165
166static inline uint8_t getScaledIPMIValue(const double value, const double max,
167 const double min)
168{
169 int16_t mValue = 0;
170 int8_t rExp = 0;
171 int16_t bValue = 0;
172 int8_t bExp = 0;
173 bool bSigned = 0;
174 bool result = 0;
175
176 result = getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned);
177 if (!result)
178 {
James Feist39417c72019-01-03 09:14:24 -0800179 throw std::runtime_error("Illegal sensor attributes");
Jason M. Bills72867de2018-11-28 12:46:59 -0800180 }
181 return scaleIPMIValueFromDouble(value, mValue, rExp, bValue, bExp, bSigned);
182}
183
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700184} // namespace ipmi