13f7c5e40SJason M. Bills /*
23f7c5e40SJason M. Bills // Copyright (c) 2017 2018 Intel Corporation
33f7c5e40SJason M. Bills //
43f7c5e40SJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License");
53f7c5e40SJason M. Bills // you may not use this file except in compliance with the License.
63f7c5e40SJason M. Bills // You may obtain a copy of the License at
73f7c5e40SJason M. Bills //
83f7c5e40SJason M. Bills //      http://www.apache.org/licenses/LICENSE-2.0
93f7c5e40SJason M. Bills //
103f7c5e40SJason M. Bills // Unless required by applicable law or agreed to in writing, software
113f7c5e40SJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS,
123f7c5e40SJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f7c5e40SJason M. Bills // See the License for the specific language governing permissions and
143f7c5e40SJason M. Bills // limitations under the License.
153f7c5e40SJason M. Bills */
163f7c5e40SJason M. Bills 
173f7c5e40SJason M. Bills #pragma once
18*72867debSJason M. Bills #include <host-ipmid/ipmid-api.h>
19*72867debSJason M. Bills 
20*72867debSJason M. Bills #include <cmath>
21*72867debSJason M. Bills #include <iostream>
22*72867debSJason M. Bills #include <phosphor-logging/log.hpp>
233f7c5e40SJason M. Bills 
243f7c5e40SJason M. Bills namespace ipmi
253f7c5e40SJason M. Bills {
26*72867debSJason M. Bills static constexpr int16_t maxInt10 = 0x1FF;
27*72867debSJason M. Bills static constexpr int16_t minInt10 = -(0x200);
28*72867debSJason M. Bills static constexpr int8_t maxInt4 = 7;
29*72867debSJason M. Bills static constexpr int8_t minInt4 = -8;
30*72867debSJason M. Bills 
31*72867debSJason M. Bills static inline bool getSensorAttributes(const double max, const double min,
32*72867debSJason M. Bills                                        int16_t& mValue, int8_t& rExp,
33*72867debSJason M. Bills                                        int16_t& bValue, int8_t& bExp,
34*72867debSJason M. Bills                                        bool& bSigned)
35*72867debSJason M. Bills {
36*72867debSJason M. Bills     // computing y = (10^rRexp) * (Mx + (B*(10^Bexp)))
37*72867debSJason M. Bills     // check for 0, assume always positive
38*72867debSJason M. Bills     double mDouble;
39*72867debSJason M. Bills     double bDouble;
40*72867debSJason M. Bills     if (!(max > min))
41*72867debSJason M. Bills     {
42*72867debSJason M. Bills         phosphor::logging::log<phosphor::logging::level::DEBUG>(
43*72867debSJason M. Bills             "getSensorAttributes: Max must be greater than min");
44*72867debSJason M. Bills         return false;
45*72867debSJason M. Bills     }
46*72867debSJason M. Bills     else
47*72867debSJason M. Bills     {
48*72867debSJason M. Bills         mDouble = (max - min) / 0xFF;
49*72867debSJason M. Bills     }
50*72867debSJason M. Bills     if (!mDouble)
51*72867debSJason M. Bills     {
52*72867debSJason M. Bills         mDouble = 1;
53*72867debSJason M. Bills     }
54*72867debSJason M. Bills 
55*72867debSJason M. Bills     if (min < 0)
56*72867debSJason M. Bills     {
57*72867debSJason M. Bills         bSigned = true;
58*72867debSJason M. Bills         bDouble = floor(0.5 + ((max + min) / 2));
59*72867debSJason M. Bills     }
60*72867debSJason M. Bills     else
61*72867debSJason M. Bills     {
62*72867debSJason M. Bills         bSigned = false;
63*72867debSJason M. Bills         bDouble = min;
64*72867debSJason M. Bills     }
65*72867debSJason M. Bills 
66*72867debSJason M. Bills     rExp = 0;
67*72867debSJason M. Bills 
68*72867debSJason M. Bills     // M too big for 10 bit variable
69*72867debSJason M. Bills     while (mDouble > maxInt10)
70*72867debSJason M. Bills     {
71*72867debSJason M. Bills         if (rExp == maxInt4)
72*72867debSJason M. Bills         {
73*72867debSJason M. Bills             phosphor::logging::log<phosphor::logging::level::DEBUG>(
74*72867debSJason M. Bills                 "rExp Too big, Max and Min range too far",
75*72867debSJason M. Bills                 phosphor::logging::entry("REXP=%d", rExp));
76*72867debSJason M. Bills             return false;
77*72867debSJason M. Bills         }
78*72867debSJason M. Bills         mDouble /= 10;
79*72867debSJason M. Bills         rExp += 1;
80*72867debSJason M. Bills     }
81*72867debSJason M. Bills 
82*72867debSJason M. Bills     // M too small, loop until we lose less than 1 eight bit count of precision
83*72867debSJason M. Bills     while (((mDouble - floor(mDouble)) / mDouble) > (1.0 / 255))
84*72867debSJason M. Bills     {
85*72867debSJason M. Bills         if (rExp == minInt4)
86*72867debSJason M. Bills         {
87*72867debSJason M. Bills             phosphor::logging::log<phosphor::logging::level::DEBUG>(
88*72867debSJason M. Bills                 "rExp Too Small, Max and Min range too close");
89*72867debSJason M. Bills             return false;
90*72867debSJason M. Bills         }
91*72867debSJason M. Bills         // check to see if we reached the limit of where we can adjust back the
92*72867debSJason M. Bills         // B value
93*72867debSJason M. Bills         if (bDouble / std::pow(10, rExp + minInt4 - 1) > bDouble)
94*72867debSJason M. Bills         {
95*72867debSJason M. Bills             if (mDouble < 1.0)
96*72867debSJason M. Bills             {
97*72867debSJason M. Bills                 phosphor::logging::log<phosphor::logging::level::DEBUG>(
98*72867debSJason M. Bills                     "Could not find mValue and B value with enough "
99*72867debSJason M. Bills                     "precision.");
100*72867debSJason M. Bills                 return false;
101*72867debSJason M. Bills             }
102*72867debSJason M. Bills             break;
103*72867debSJason M. Bills         }
104*72867debSJason M. Bills         // can't multiply M any more, max precision reached
105*72867debSJason M. Bills         else if (mDouble * 10 > maxInt10)
106*72867debSJason M. Bills         {
107*72867debSJason M. Bills             break;
108*72867debSJason M. Bills         }
109*72867debSJason M. Bills         mDouble *= 10;
110*72867debSJason M. Bills         rExp -= 1;
111*72867debSJason M. Bills     }
112*72867debSJason M. Bills 
113*72867debSJason M. Bills     bDouble /= std::pow(10, rExp);
114*72867debSJason M. Bills     bExp = 0;
115*72867debSJason M. Bills 
116*72867debSJason M. Bills     // B too big for 10 bit variable
117*72867debSJason M. Bills     while (bDouble > maxInt10 || bDouble < minInt10)
118*72867debSJason M. Bills     {
119*72867debSJason M. Bills         if (bExp == maxInt4)
120*72867debSJason M. Bills         {
121*72867debSJason M. Bills             phosphor::logging::log<phosphor::logging::level::DEBUG>(
122*72867debSJason M. Bills                 "bExp Too Big, Max and Min range need to be adjusted");
123*72867debSJason M. Bills             return false;
124*72867debSJason M. Bills         }
125*72867debSJason M. Bills         bDouble /= 10;
126*72867debSJason M. Bills         bExp += 1;
127*72867debSJason M. Bills     }
128*72867debSJason M. Bills 
129*72867debSJason M. Bills     while (((fabs(bDouble) - floor(fabs(bDouble))) / fabs(bDouble)) >
130*72867debSJason M. Bills            (1.0 / 255))
131*72867debSJason M. Bills     {
132*72867debSJason M. Bills         if (bExp == minInt4)
133*72867debSJason M. Bills         {
134*72867debSJason M. Bills             phosphor::logging::log<phosphor::logging::level::DEBUG>(
135*72867debSJason M. Bills                 "bExp Too Small, Max and Min range need to be adjusted");
136*72867debSJason M. Bills             return false;
137*72867debSJason M. Bills         }
138*72867debSJason M. Bills         bDouble *= 10;
139*72867debSJason M. Bills         bExp -= 1;
140*72867debSJason M. Bills     }
141*72867debSJason M. Bills 
142*72867debSJason M. Bills     mValue = static_cast<int16_t>(mDouble + 0.5) & maxInt10;
143*72867debSJason M. Bills     bValue = static_cast<int16_t>(bDouble + 0.5) & maxInt10;
144*72867debSJason M. Bills 
145*72867debSJason M. Bills     return true;
146*72867debSJason M. Bills }
147*72867debSJason M. Bills 
148*72867debSJason M. Bills static inline uint8_t
149*72867debSJason M. Bills     scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
1503f7c5e40SJason M. Bills                              const int8_t rExp, const uint16_t bValue,
151*72867debSJason M. Bills                              const int8_t bExp, const bool bSigned)
152*72867debSJason M. Bills {
153*72867debSJason M. Bills     uint32_t scaledValue =
154*72867debSJason M. Bills         (value - (bValue * std::pow(10, bExp) * std::pow(10, rExp))) /
155*72867debSJason M. Bills         (mValue * std::pow(10, rExp));
156*72867debSJason M. Bills     if (bSigned)
157*72867debSJason M. Bills     {
158*72867debSJason M. Bills         return static_cast<int8_t>(scaledValue);
159*72867debSJason M. Bills     }
160*72867debSJason M. Bills     else
161*72867debSJason M. Bills     {
162*72867debSJason M. Bills         return static_cast<uint8_t>(scaledValue);
163*72867debSJason M. Bills     }
164*72867debSJason M. Bills }
165*72867debSJason M. Bills 
166*72867debSJason M. Bills static inline uint8_t getScaledIPMIValue(const double value, const double max,
167*72867debSJason M. Bills                                          const double min)
168*72867debSJason M. Bills {
169*72867debSJason M. Bills     int16_t mValue = 0;
170*72867debSJason M. Bills     int8_t rExp = 0;
171*72867debSJason M. Bills     int16_t bValue = 0;
172*72867debSJason M. Bills     int8_t bExp = 0;
173*72867debSJason M. Bills     bool bSigned = 0;
174*72867debSJason M. Bills     bool result = 0;
175*72867debSJason M. Bills 
176*72867debSJason M. Bills     result = getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned);
177*72867debSJason M. Bills     if (!result)
178*72867debSJason M. Bills     {
179*72867debSJason M. Bills         return 0xFF;
180*72867debSJason M. Bills     }
181*72867debSJason M. Bills     return scaleIPMIValueFromDouble(value, mValue, rExp, bValue, bExp, bSigned);
182*72867debSJason M. Bills }
183*72867debSJason M. Bills 
1843f7c5e40SJason M. Bills } // namespace ipmi