blob: 30fee668328fa0898d9fd957c13d55d9286f918c [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>
James Feist2a265d52019-04-08 11:16:27 -070020#include <ipmid/api.hpp>
Jason M. Bills72867de2018-11-28 12:46:59 -080021#include <phosphor-logging/log.hpp>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070022
23namespace ipmi
24{
Jason M. Bills72867de2018-11-28 12:46:59 -080025static constexpr int16_t maxInt10 = 0x1FF;
James Feist39417c72019-01-03 09:14:24 -080026static constexpr int16_t minInt10 = -0x200;
Jason M. Bills72867de2018-11-28 12:46:59 -080027static constexpr int8_t maxInt4 = 7;
28static constexpr int8_t minInt4 = -8;
29
30static inline bool getSensorAttributes(const double max, const double min,
31 int16_t& mValue, int8_t& rExp,
32 int16_t& bValue, int8_t& bExp,
33 bool& bSigned)
34{
35 // computing y = (10^rRexp) * (Mx + (B*(10^Bexp)))
36 // check for 0, assume always positive
37 double mDouble;
38 double bDouble;
James Feist39417c72019-01-03 09:14:24 -080039 if (max <= min)
Jason M. Bills72867de2018-11-28 12:46:59 -080040 {
41 phosphor::logging::log<phosphor::logging::level::DEBUG>(
42 "getSensorAttributes: Max must be greater than min");
43 return false;
44 }
James Feist39417c72019-01-03 09:14:24 -080045
46 mDouble = (max - min) / 0xFF;
Jason M. Bills72867de2018-11-28 12:46:59 -080047
48 if (min < 0)
49 {
50 bSigned = true;
51 bDouble = floor(0.5 + ((max + min) / 2));
52 }
53 else
54 {
55 bSigned = false;
56 bDouble = min;
57 }
58
59 rExp = 0;
60
61 // M too big for 10 bit variable
62 while (mDouble > maxInt10)
63 {
James Feist39417c72019-01-03 09:14:24 -080064 if (rExp >= maxInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -080065 {
66 phosphor::logging::log<phosphor::logging::level::DEBUG>(
67 "rExp Too big, Max and Min range too far",
68 phosphor::logging::entry("REXP=%d", rExp));
69 return false;
70 }
71 mDouble /= 10;
James Feist39417c72019-01-03 09:14:24 -080072 rExp++;
Jason M. Bills72867de2018-11-28 12:46:59 -080073 }
74
75 // M too small, loop until we lose less than 1 eight bit count of precision
76 while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255))
77 {
James Feist39417c72019-01-03 09:14:24 -080078 if (rExp <= minInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -080079 {
80 phosphor::logging::log<phosphor::logging::level::DEBUG>(
81 "rExp Too Small, Max and Min range too close");
82 return false;
83 }
84 // check to see if we reached the limit of where we can adjust back the
85 // B value
86 if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble)
87 {
88 if (mDouble < 1.0)
89 {
90 phosphor::logging::log<phosphor::logging::level::DEBUG>(
91 "Could not find mValue and B value with enough "
92 "precision.");
93 return false;
94 }
95 break;
96 }
97 // can't multiply M any more, max precision reached
98 else if (mDouble * 10 > maxInt10)
99 {
100 break;
101 }
102 mDouble *= 10;
James Feist39417c72019-01-03 09:14:24 -0800103 rExp--;
Jason M. Bills72867de2018-11-28 12:46:59 -0800104 }
105
106 bDouble /= std::pow(10, rExp);
107 bExp = 0;
108
109 // B too big for 10 bit variable
110 while (bDouble > maxInt10 || bDouble < minInt10)
111 {
James Feist39417c72019-01-03 09:14:24 -0800112 if (bExp >= maxInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -0800113 {
114 phosphor::logging::log<phosphor::logging::level::DEBUG>(
115 "bExp Too Big, Max and Min range need to be adjusted");
116 return false;
117 }
118 bDouble /= 10;
James Feist39417c72019-01-03 09:14:24 -0800119 bExp++;
Jason M. Bills72867de2018-11-28 12:46:59 -0800120 }
121
122 while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) >
123 (1.0 / 255))
124 {
James Feist39417c72019-01-03 09:14:24 -0800125 if (bExp <= minInt4)
Jason M. Bills72867de2018-11-28 12:46:59 -0800126 {
127 phosphor::logging::log<phosphor::logging::level::DEBUG>(
128 "bExp Too Small, Max and Min range need to be adjusted");
129 return false;
130 }
131 bDouble *= 10;
132 bExp -= 1;
133 }
134
James Feist39417c72019-01-03 09:14:24 -0800135 mValue = static_cast<int16_t>(mDouble) & maxInt10;
136 bValue = static_cast<int16_t>(bDouble) & maxInt10;
Jason M. Bills72867de2018-11-28 12:46:59 -0800137
138 return true;
139}
140
141static inline uint8_t
142 scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
143 const int8_t rExp, const uint16_t bValue,
144 const int8_t bExp, const bool bSigned)
145{
146 uint32_t scaledValue =
147 (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) /
148 (mValue * std::pow(10, rExp));
James Feist39417c72019-01-03 09:14:24 -0800149
150 if (scaledValue > std::numeric_limits<uint8_t>::max() ||
151 scaledValue < std::numeric_limits<uint8_t>::lowest())
152 {
153 throw std::out_of_range("Value out of range");
154 }
Jason M. Bills72867de2018-11-28 12:46:59 -0800155 if (bSigned)
156 {
157 return static_cast<int8_t>(scaledValue);
158 }
159 else
160 {
161 return static_cast<uint8_t>(scaledValue);
162 }
163}
164
165static inline uint8_t getScaledIPMIValue(const double value, const double max,
166 const double min)
167{
168 int16_t mValue = 0;
169 int8_t rExp = 0;
170 int16_t bValue = 0;
171 int8_t bExp = 0;
172 bool bSigned = 0;
173 bool result = 0;
174
175 result = getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned);
176 if (!result)
177 {
James Feist39417c72019-01-03 09:14:24 -0800178 throw std::runtime_error("Illegal sensor attributes");
Jason M. Bills72867de2018-11-28 12:46:59 -0800179 }
180 return scaleIPMIValueFromDouble(value, mValue, rExp, bValue, bExp, bSigned);
181}
182
James Feist2a265d52019-04-08 11:16:27 -0700183} // namespace ipmi