blob: 98359fcc2d558ce37cdbef8c917fa90d80c15bb7 [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>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070020
21namespace ipmi
22{
Jason M. Bills72867de2018-11-28 12:46:59 -080023static constexpr int16_t maxInt10 = 0x1FF;
James Feist39417c72019-01-03 09:14:24 -080024static constexpr int16_t minInt10 = -0x200;
Jason M. Bills72867de2018-11-28 12:46:59 -080025static constexpr int8_t maxInt4 = 7;
26static constexpr int8_t minInt4 = -8;
27
28static inline bool getSensorAttributes(const double max, const double min,
29 int16_t& mValue, int8_t& rExp,
30 int16_t& bValue, int8_t& bExp,
31 bool& bSigned)
32{
33 // computing y = (10^rRexp) * (Mx + (B*(10^Bexp)))
34 // check for 0, assume always positive
35 double mDouble;
36 double bDouble;
James Feist39417c72019-01-03 09:14:24 -080037 if (max <= min)
Jason M. Bills72867de2018-11-28 12:46:59 -080038 {
Vernon Mauery53870d72019-06-04 14:21:10 -070039 std::cerr << "getSensorAttributes: Max must be greater than min\n";
Jason M. Bills72867de2018-11-28 12:46:59 -080040 return false;
41 }
James Feist39417c72019-01-03 09:14:24 -080042
43 mDouble = (max - min) / 0xFF;
Jason M. Bills72867de2018-11-28 12:46:59 -080044
45 if (min < 0)
46 {
47 bSigned = true;
48 bDouble = floor(0.5 + ((max + min) / 2));
49 }
50 else
51 {
52 bSigned = false;
53 bDouble = min;
54 }
55
56 rExp = 0;
57
58 // M too big for 10 bit variable
59 while (mDouble > maxInt10)
60 {
James Feist39417c72019-01-03 09:14:24 -080061 if (rExp >= maxInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -080062 {
Vernon Mauery53870d72019-06-04 14:21:10 -070063 std::cerr << "rExp Too big, Max and Min range too far REXP=" << rExp
64 << "\n";
Jason M. Bills72867de2018-11-28 12:46:59 -080065 return false;
66 }
67 mDouble /= 10;
James Feist39417c72019-01-03 09:14:24 -080068 rExp++;
Jason M. Bills72867de2018-11-28 12:46:59 -080069 }
70
71 // M too small, loop until we lose less than 1 eight bit count of precision
72 while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255))
73 {
James Feist39417c72019-01-03 09:14:24 -080074 if (rExp <= minInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -080075 {
Vernon Mauery53870d72019-06-04 14:21:10 -070076 std::cerr << "rExp Too Small, Max and Min range too close\n";
Jason M. Bills72867de2018-11-28 12:46:59 -080077 return false;
78 }
79 // check to see if we reached the limit of where we can adjust back the
80 // B value
81 if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble)
82 {
83 if (mDouble < 1.0)
84 {
Vernon Mauery53870d72019-06-04 14:21:10 -070085 std::cerr << "Could not find mValue and B value with enough "
86 "precision.\n";
Jason M. Bills72867de2018-11-28 12:46:59 -080087 return false;
88 }
89 break;
90 }
91 // can't multiply M any more, max precision reached
92 else if (mDouble * 10 > maxInt10)
93 {
94 break;
95 }
96 mDouble *= 10;
James Feist39417c72019-01-03 09:14:24 -080097 rExp--;
Jason M. Bills72867de2018-11-28 12:46:59 -080098 }
99
100 bDouble /= std::pow(10, rExp);
101 bExp = 0;
102
103 // B too big for 10 bit variable
104 while (bDouble > maxInt10 || bDouble < minInt10)
105 {
James Feist39417c72019-01-03 09:14:24 -0800106 if (bExp >= maxInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -0800107 {
Vernon Mauery53870d72019-06-04 14:21:10 -0700108 std::cerr
109 << "bExp Too Big, Max and Min range need to be adjusted\n";
Jason M. Bills72867de2018-11-28 12:46:59 -0800110 return false;
111 }
112 bDouble /= 10;
James Feist39417c72019-01-03 09:14:24 -0800113 bExp++;
Jason M. Bills72867de2018-11-28 12:46:59 -0800114 }
115
116 while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) >
117 (1.0 / 255))
118 {
James Feist39417c72019-01-03 09:14:24 -0800119 if (bExp <= minInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -0800120 {
Vernon Mauery53870d72019-06-04 14:21:10 -0700121 std::cerr
122 << "bExp Too Small, Max and Min range need to be adjusted\n";
Jason M. Bills72867de2018-11-28 12:46:59 -0800123 return false;
124 }
125 bDouble *= 10;
126 bExp -= 1;
127 }
128
James Feistaecaef72019-04-26 10:30:32 -0700129 mValue = static_cast<int16_t>(std::round(mDouble)) & maxInt10;
James Feist39417c72019-01-03 09:14:24 -0800130 bValue = static_cast<int16_t>(bDouble) & maxInt10;
Jason M. Bills72867de2018-11-28 12:46:59 -0800131
132 return true;
133}
134
135static inline uint8_t
136 scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
137 const int8_t rExp, const uint16_t bValue,
138 const int8_t bExp, const bool bSigned)
139{
140 uint32_t scaledValue =
141 (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) /
142 (mValue * std::pow(10, rExp));
James Feist39417c72019-01-03 09:14:24 -0800143
144 if (scaledValue > std::numeric_limits<uint8_t>::max() ||
145 scaledValue < std::numeric_limits<uint8_t>::lowest())
146 {
147 throw std::out_of_range("Value out of range");
148 }
Jason M. Bills72867de2018-11-28 12:46:59 -0800149 if (bSigned)
150 {
151 return static_cast<int8_t>(scaledValue);
152 }
153 else
154 {
155 return static_cast<uint8_t>(scaledValue);
156 }
157}
158
159static inline uint8_t getScaledIPMIValue(const double value, const double max,
160 const double min)
161{
162 int16_t mValue = 0;
163 int8_t rExp = 0;
164 int16_t bValue = 0;
165 int8_t bExp = 0;
166 bool bSigned = 0;
167 bool result = 0;
168
169 result = getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned);
170 if (!result)
171 {
James Feist39417c72019-01-03 09:14:24 -0800172 throw std::runtime_error("Illegal sensor attributes");
Jason M. Bills72867de2018-11-28 12:46:59 -0800173 }
174 return scaleIPMIValueFromDouble(value, mValue, rExp, bValue, bExp, bSigned);
175}
176
James Feist2a265d52019-04-08 11:16:27 -0700177} // namespace ipmi