blob: 4cb4c29247635a3155760dfcf9bb7f6e17bbfb09 [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. Bills72867de2018-11-28 12:46:59 -080018#include <cmath>
19#include <iostream>
20#include <phosphor-logging/log.hpp>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070021
22namespace ipmi
23{
Jason M. Bills72867de2018-11-28 12:46:59 -080024static constexpr int16_t maxInt10 = 0x1FF;
James Feist39417c72019-01-03 09:14:24 -080025static constexpr int16_t minInt10 = -0x200;
Jason M. Bills72867de2018-11-28 12:46:59 -080026static constexpr int8_t maxInt4 = 7;
27static constexpr int8_t minInt4 = -8;
28
29static inline bool getSensorAttributes(const double max, const double min,
30 int16_t& mValue, int8_t& rExp,
31 int16_t& bValue, int8_t& bExp,
32 bool& bSigned)
33{
34 // computing y = (10^rRexp) * (Mx + (B*(10^Bexp)))
35 // check for 0, assume always positive
36 double mDouble;
37 double bDouble;
James Feist39417c72019-01-03 09:14:24 -080038 if (max <= min)
Jason M. Bills72867de2018-11-28 12:46:59 -080039 {
40 phosphor::logging::log<phosphor::logging::level::DEBUG>(
41 "getSensorAttributes: Max must be greater than min");
42 return false;
43 }
James Feist39417c72019-01-03 09:14:24 -080044
45 mDouble = (max - min) / 0xFF;
Jason M. Bills72867de2018-11-28 12:46:59 -080046
47 if (min < 0)
48 {
49 bSigned = true;
50 bDouble = floor(0.5 + ((max + min) / 2));
51 }
52 else
53 {
54 bSigned = false;
55 bDouble = min;
56 }
57
58 rExp = 0;
59
60 // M too big for 10 bit variable
61 while (mDouble > maxInt10)
62 {
James Feist39417c72019-01-03 09:14:24 -080063 if (rExp >= maxInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -080064 {
65 phosphor::logging::log<phosphor::logging::level::DEBUG>(
66 "rExp Too big, Max and Min range too far",
67 phosphor::logging::entry("REXP=%d", rExp));
68 return false;
69 }
70 mDouble /= 10;
James Feist39417c72019-01-03 09:14:24 -080071 rExp++;
Jason M. Bills72867de2018-11-28 12:46:59 -080072 }
73
74 // M too small, loop until we lose less than 1 eight bit count of precision
75 while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255))
76 {
James Feist39417c72019-01-03 09:14:24 -080077 if (rExp <= minInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -080078 {
79 phosphor::logging::log<phosphor::logging::level::DEBUG>(
80 "rExp Too Small, Max and Min range too close");
81 return false;
82 }
83 // check to see if we reached the limit of where we can adjust back the
84 // B value
85 if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble)
86 {
87 if (mDouble < 1.0)
88 {
89 phosphor::logging::log<phosphor::logging::level::DEBUG>(
90 "Could not find mValue and B value with enough "
91 "precision.");
92 return false;
93 }
94 break;
95 }
96 // can't multiply M any more, max precision reached
97 else if (mDouble * 10 > maxInt10)
98 {
99 break;
100 }
101 mDouble *= 10;
James Feist39417c72019-01-03 09:14:24 -0800102 rExp--;
Jason M. Bills72867de2018-11-28 12:46:59 -0800103 }
104
105 bDouble /= std::pow(10, rExp);
106 bExp = 0;
107
108 // B too big for 10 bit variable
109 while (bDouble > maxInt10 || bDouble < minInt10)
110 {
James Feist39417c72019-01-03 09:14:24 -0800111 if (bExp >= maxInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -0800112 {
113 phosphor::logging::log<phosphor::logging::level::DEBUG>(
114 "bExp Too Big, Max and Min range need to be adjusted");
115 return false;
116 }
117 bDouble /= 10;
James Feist39417c72019-01-03 09:14:24 -0800118 bExp++;
Jason M. Bills72867de2018-11-28 12:46:59 -0800119 }
120
121 while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) >
122 (1.0 / 255))
123 {
James Feist39417c72019-01-03 09:14:24 -0800124 if (bExp <= minInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -0800125 {
126 phosphor::logging::log<phosphor::logging::level::DEBUG>(
127 "bExp Too Small, Max and Min range need to be adjusted");
128 return false;
129 }
130 bDouble *= 10;
131 bExp -= 1;
132 }
133
James Feistaecaef72019-04-26 10:30:32 -0700134 mValue = static_cast<int16_t>(std::round(mDouble)) & maxInt10;
James Feist39417c72019-01-03 09:14:24 -0800135 bValue = static_cast<int16_t>(bDouble) & maxInt10;
Jason M. Bills72867de2018-11-28 12:46:59 -0800136
137 return true;
138}
139
140static inline uint8_t
141 scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
142 const int8_t rExp, const uint16_t bValue,
143 const int8_t bExp, const bool bSigned)
144{
145 uint32_t scaledValue =
146 (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) /
147 (mValue * std::pow(10, rExp));
James Feist39417c72019-01-03 09:14:24 -0800148
149 if (scaledValue > std::numeric_limits<uint8_t>::max() ||
150 scaledValue < std::numeric_limits<uint8_t>::lowest())
151 {
152 throw std::out_of_range("Value out of range");
153 }
Jason M. Bills72867de2018-11-28 12:46:59 -0800154 if (bSigned)
155 {
156 return static_cast<int8_t>(scaledValue);
157 }
158 else
159 {
160 return static_cast<uint8_t>(scaledValue);
161 }
162}
163
164static inline uint8_t getScaledIPMIValue(const double value, const double max,
165 const double min)
166{
167 int16_t mValue = 0;
168 int8_t rExp = 0;
169 int16_t bValue = 0;
170 int8_t bExp = 0;
171 bool bSigned = 0;
172 bool result = 0;
173
174 result = getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned);
175 if (!result)
176 {
James Feist39417c72019-01-03 09:14:24 -0800177 throw std::runtime_error("Illegal sensor attributes");
Jason M. Bills72867de2018-11-28 12:46:59 -0800178 }
179 return scaleIPMIValueFromDouble(value, mValue, rExp, bValue, bExp, bSigned);
180}
181
James Feist2a265d52019-04-08 11:16:27 -0700182} // namespace ipmi