blob: 62e2cd251381cf8ddcfcc4ef54e27af4e27fe293 [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#include <host-ipmid/ipmid-api.h>
17
18#include <cmath>
19#include <iostream>
20#include <phosphor-logging/log.hpp>
21#include <sensorutils.hpp>
22
23namespace ipmi
24{
25static constexpr int16_t maxInt10 = 0x1FF;
26static constexpr int16_t minInt10 = -(0x200);
27static constexpr int8_t maxInt4 = 7;
28static constexpr int8_t minInt4 = -8;
29
30bool getSensorAttributes(const double max, const double min, int16_t &mValue,
31 int8_t &rExp, 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;
38 if (!(max > min))
39 {
40 phosphor::logging::log<phosphor::logging::level::DEBUG>(
41 "getSensorAttributes: Max must be greater than min");
42 return false;
43 }
44 else
45 {
46 mDouble = (max - min) / 0xFF;
47 }
48 if (!mDouble)
49 {
50 mDouble = 1;
51 }
52
53 if (min < 0)
54 {
55 bSigned = true;
56 bDouble = floor(0.5 + ((max + min) / 2));
57 }
58 else
59 {
60 bSigned = false;
61 bDouble = min;
62 }
63
64 rExp = 0;
65
66 // M too big for 10 bit variable
67 while (mDouble > maxInt10)
68 {
69 if (rExp == maxInt4)
70 {
71 phosphor::logging::log<phosphor::logging::level::DEBUG>(
72 "rExp Too big, Max and Min range too far");
73 return false;
74 }
75 mDouble /= 10;
76 rExp += 1;
77 }
78
79 // M too small, loop until we loose less than 1 eight bit count of precision
80 while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255))
81 {
82 if (rExp == minInt4)
83 {
84 phosphor::logging::log<phosphor::logging::level::DEBUG>(
85 "rExp Too Small, Max and Min range too close");
86 return false;
87 }
88 // check to see if we reached the limit of where we can adjust back the
89 // B value
90 if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble)
91 {
92 if (mDouble < 1.0)
93 {
94 phosphor::logging::log<phosphor::logging::level::DEBUG>(
95 "Could not find mValue and B value with enough "
96 "precision.");
97 return false;
98 }
99 break;
100 }
101 // can't multiply M any more, max precision reached
102 else if (mDouble * 10 > maxInt10)
103 {
104 break;
105 }
106 mDouble *= 10;
107 rExp -= 1;
108 }
109
110 bDouble /= std::pow(10, rExp);
111 bExp = 0;
112
113 // B too big for 10 bit variable
114 while (bDouble > maxInt10 || bDouble < minInt10)
115 {
116 if (bExp == maxInt4)
117 {
118 phosphor::logging::log<phosphor::logging::level::DEBUG>(
119 "bExp Too Big, Max and Min range need to be adjusted");
120 return false;
121 }
122 bDouble /= 10;
123 bExp += 1;
124 }
125
126 while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) >
127 (1.0 / 255))
128 {
129 if (bExp == minInt4)
130 {
131 phosphor::logging::log<phosphor::logging::level::DEBUG>(
132 "bExp Too Small, Max and Min range need to be adjusted");
133 return false;
134 }
135 bDouble *= 10;
136 bExp -= 1;
137 }
138
139 mValue = static_cast<int16_t>(mDouble + 0.5) & maxInt10;
140 bValue = static_cast<int16_t>(bDouble + 0.5) & maxInt10;
141
142 return true;
143}
144
145uint8_t scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
146 const int8_t rExp, const uint16_t bValue,
147 const int8_t bExp, const bool bSigned)
148{
149 uint32_t scaledValue =
150 (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) /
151 (mValue * std::pow(10, rExp));
152 if (bSigned)
153 {
154 return static_cast<int8_t>(scaledValue);
155 }
156 else
157 {
158 return static_cast<uint8_t>(scaledValue);
159 }
160}
161} // namespace ipmi