xref: /openbmc/intel-ipmi-oem/tests/test_sensorcommands.cpp (revision 1bcced0820999e7e050257b9f78cf36b23eb762b)
1e035c588SVernon Mauery #include "sensorutils.hpp"
23f7c5e40SJason M. Bills 
3fcd2d3a9SJames Feist #include <cmath>
4fcd2d3a9SJames Feist 
53f7c5e40SJason M. Bills #include "gtest/gtest.h"
63f7c5e40SJason M. Bills 
717e21c20SJosh Lehan // There is a surprising amount of slop in the math,
817e21c20SJosh Lehan // thanks to all the rounding and conversion.
917e21c20SJosh Lehan // The "x" byte value can drift by up to 2 away, I have seen.
1017e21c20SJosh Lehan static constexpr int8_t expectedSlopX = 2;
1117e21c20SJosh Lehan 
1217e21c20SJosh Lehan // Unlike expectedSlopX, this is a ratio, not an integer
1317e21c20SJosh Lehan // It scales based on the range of "y"
1417e21c20SJosh Lehan static constexpr double expectedSlopY = 0.01;
1517e21c20SJosh Lehan 
1617e21c20SJosh Lehan // The algorithm here was copied from ipmitool
1717e21c20SJosh Lehan // sdr_convert_sensor_reading() function
1817e21c20SJosh Lehan // https://github.com/ipmitool/ipmitool/blob/42a023ff0726c80e8cc7d30315b987fe568a981d/lib/ipmi_sdr.c#L360
ipmitool_y_from_x(uint8_t x,int m,int k2_rExp,int b,int k1_bExp,bool bSigned)1917e21c20SJosh Lehan double ipmitool_y_from_x(uint8_t x, int m, int k2_rExp, int b, int k1_bExp,
2017e21c20SJosh Lehan                          bool bSigned)
2117e21c20SJosh Lehan {
2217e21c20SJosh Lehan     double result;
2317e21c20SJosh Lehan 
2417e21c20SJosh Lehan     // Rename to exactly match names and types (except analog) from ipmitool
2517e21c20SJosh Lehan     uint8_t val = x;
2617e21c20SJosh Lehan     double k1 = k1_bExp;
2717e21c20SJosh Lehan     double k2 = k2_rExp;
2817e21c20SJosh Lehan     int analog = bSigned ? 2 : 0;
2917e21c20SJosh Lehan 
3017e21c20SJosh Lehan     // Begin paste here
3117e21c20SJosh Lehan     // Only change is to comment out complicated structure in switch statement
3217e21c20SJosh Lehan 
3317e21c20SJosh Lehan     switch (/*sensor->cmn.unit.*/ analog)
3417e21c20SJosh Lehan     {
3517e21c20SJosh Lehan         case 0:
3617e21c20SJosh Lehan             result = (double)(((m * val) + (b * pow(10, k1))) * pow(10, k2));
3717e21c20SJosh Lehan             break;
3817e21c20SJosh Lehan         case 1:
3917e21c20SJosh Lehan             if (val & 0x80)
4017e21c20SJosh Lehan                 val++;
4117e21c20SJosh Lehan             /* Deliberately fall through to case 2. */
42dcff1506SVernon Mauery             [[fallthrough]];
4317e21c20SJosh Lehan         case 2:
4417e21c20SJosh Lehan             result =
4517e21c20SJosh Lehan                 (double)(((m * (int8_t)val) + (b * pow(10, k1))) * pow(10, k2));
4617e21c20SJosh Lehan             break;
4717e21c20SJosh Lehan         default:
4817e21c20SJosh Lehan             /* Oops! This isn't an analog sensor. */
4917e21c20SJosh Lehan             return 0.0;
5017e21c20SJosh Lehan     }
5117e21c20SJosh Lehan 
5217e21c20SJosh Lehan     // End paste here
5317e21c20SJosh Lehan     // Ignoring linearization curves and postprocessing that follows,
5417e21c20SJosh Lehan     // assuming all sensors are perfectly linear
5517e21c20SJosh Lehan     return result;
5617e21c20SJosh Lehan }
5717e21c20SJosh Lehan 
testValue(int x,double y,int16_t M,int8_t rExp,int16_t B,int8_t bExp,bool bSigned,double yRange)5817e21c20SJosh Lehan void testValue(int x, double y, int16_t M, int8_t rExp, int16_t B, int8_t bExp,
5917e21c20SJosh Lehan                bool bSigned, double yRange)
6017e21c20SJosh Lehan {
6117e21c20SJosh Lehan     double yRoundtrip;
6217e21c20SJosh Lehan     int result;
6317e21c20SJosh Lehan 
6417e21c20SJosh Lehan     // There is intentionally no exception catching here,
6517e21c20SJosh Lehan     // because if getSensorAttributes() returned true,
6617e21c20SJosh Lehan     // it is a promise that all of these should work.
6717e21c20SJosh Lehan     if (bSigned)
6817e21c20SJosh Lehan     {
6917e21c20SJosh Lehan         int8_t expect = x;
70*1bcced08SPatrick Williams         int8_t actual =
71*1bcced08SPatrick Williams             ipmi::scaleIPMIValueFromDouble(y, M, rExp, B, bExp, bSigned);
7217e21c20SJosh Lehan 
7317e21c20SJosh Lehan         result = actual;
7417e21c20SJosh Lehan         yRoundtrip = ipmitool_y_from_x(actual, M, rExp, B, bExp, bSigned);
7517e21c20SJosh Lehan 
7617e21c20SJosh Lehan         EXPECT_NEAR(actual, expect, expectedSlopX);
7717e21c20SJosh Lehan     }
7817e21c20SJosh Lehan     else
7917e21c20SJosh Lehan     {
8017e21c20SJosh Lehan         uint8_t expect = x;
81*1bcced08SPatrick Williams         uint8_t actual =
82*1bcced08SPatrick Williams             ipmi::scaleIPMIValueFromDouble(y, M, rExp, B, bExp, bSigned);
8317e21c20SJosh Lehan 
8417e21c20SJosh Lehan         result = actual;
8517e21c20SJosh Lehan         yRoundtrip = ipmitool_y_from_x(actual, M, rExp, B, bExp, bSigned);
8617e21c20SJosh Lehan 
8717e21c20SJosh Lehan         EXPECT_NEAR(actual, expect, expectedSlopX);
8817e21c20SJosh Lehan     }
8917e21c20SJosh Lehan 
9017e21c20SJosh Lehan     // Scale the amount of allowed slop in y based on range, so ratio similar
9117e21c20SJosh Lehan     double yTolerance = yRange * expectedSlopY;
9217e21c20SJosh Lehan 
9317e21c20SJosh Lehan     EXPECT_NEAR(y, yRoundtrip, yTolerance);
9417e21c20SJosh Lehan 
9517e21c20SJosh Lehan     char szFormat[1024];
9617e21c20SJosh Lehan     sprintf(szFormat,
9717e21c20SJosh Lehan             "Value | xExpect %4d | xResult %4d "
9817e21c20SJosh Lehan             "| M %5d | rExp %3d "
9917e21c20SJosh Lehan             "| B %5d | bExp %3d | bSigned %1d | y %18.3f | yRoundtrip %18.3f\n",
10017e21c20SJosh Lehan             x, result, M, (int)rExp, B, (int)bExp, (int)bSigned, y, yRoundtrip);
10117e21c20SJosh Lehan     std::cout << szFormat;
10217e21c20SJosh Lehan }
10317e21c20SJosh Lehan 
testBounds(double yMin,double yMax,bool bExpectedOutcome=true)10417e21c20SJosh Lehan void testBounds(double yMin, double yMax, bool bExpectedOutcome = true)
10517e21c20SJosh Lehan {
10617e21c20SJosh Lehan     int16_t mValue;
10717e21c20SJosh Lehan     int8_t rExp;
10817e21c20SJosh Lehan     int16_t bValue;
10917e21c20SJosh Lehan     int8_t bExp;
11017e21c20SJosh Lehan     bool bSigned;
11117e21c20SJosh Lehan     bool result;
11217e21c20SJosh Lehan 
11317e21c20SJosh Lehan     result = ipmi::getSensorAttributes(yMax, yMin, mValue, rExp, bValue, bExp,
11417e21c20SJosh Lehan                                        bSigned);
11517e21c20SJosh Lehan     EXPECT_EQ(result, bExpectedOutcome);
11617e21c20SJosh Lehan 
11717e21c20SJosh Lehan     if (!result)
11817e21c20SJosh Lehan     {
11917e21c20SJosh Lehan         return;
12017e21c20SJosh Lehan     }
12117e21c20SJosh Lehan 
12217e21c20SJosh Lehan     char szFormat[1024];
12317e21c20SJosh Lehan     sprintf(szFormat,
12417e21c20SJosh Lehan             "Bounds | yMin %18.3f | yMax %18.3f | M %5d"
12517e21c20SJosh Lehan             " | rExp %3d | B %5d | bExp %3d | bSigned %1d\n",
12617e21c20SJosh Lehan             yMin, yMax, mValue, (int)rExp, bValue, (int)bExp, (int)bSigned);
12717e21c20SJosh Lehan     std::cout << szFormat;
12817e21c20SJosh Lehan 
12917e21c20SJosh Lehan     double y50p = (yMin + yMax) / 2.0;
13017e21c20SJosh Lehan 
13117e21c20SJosh Lehan     // Average the average
13217e21c20SJosh Lehan     double y25p = (yMin + y50p) / 2.0;
13317e21c20SJosh Lehan     double y75p = (y50p + yMax) / 2.0;
13417e21c20SJosh Lehan 
13517e21c20SJosh Lehan     // This range value is only used for tolerance checking, not computation
13617e21c20SJosh Lehan     double yRange = yMax - yMin;
13717e21c20SJosh Lehan 
13817e21c20SJosh Lehan     if (bSigned)
13917e21c20SJosh Lehan     {
14017e21c20SJosh Lehan         int8_t xMin = -128;
14117e21c20SJosh Lehan         int8_t x25p = -64;
14217e21c20SJosh Lehan         int8_t x50p = 0;
14317e21c20SJosh Lehan         int8_t x75p = 64;
14417e21c20SJosh Lehan         int8_t xMax = 127;
14517e21c20SJosh Lehan 
14617e21c20SJosh Lehan         testValue(xMin, yMin, mValue, rExp, bValue, bExp, bSigned, yRange);
14717e21c20SJosh Lehan         testValue(x25p, y25p, mValue, rExp, bValue, bExp, bSigned, yRange);
14817e21c20SJosh Lehan         testValue(x50p, y50p, mValue, rExp, bValue, bExp, bSigned, yRange);
14917e21c20SJosh Lehan         testValue(x75p, y75p, mValue, rExp, bValue, bExp, bSigned, yRange);
15017e21c20SJosh Lehan         testValue(xMax, yMax, mValue, rExp, bValue, bExp, bSigned, yRange);
15117e21c20SJosh Lehan     }
15217e21c20SJosh Lehan     else
15317e21c20SJosh Lehan     {
15417e21c20SJosh Lehan         uint8_t xMin = 0;
15517e21c20SJosh Lehan         uint8_t x25p = 64;
15617e21c20SJosh Lehan         uint8_t x50p = 128;
15717e21c20SJosh Lehan         uint8_t x75p = 192;
15817e21c20SJosh Lehan         uint8_t xMax = 255;
15917e21c20SJosh Lehan 
16017e21c20SJosh Lehan         testValue(xMin, yMin, mValue, rExp, bValue, bExp, bSigned, yRange);
16117e21c20SJosh Lehan         testValue(x25p, y25p, mValue, rExp, bValue, bExp, bSigned, yRange);
16217e21c20SJosh Lehan         testValue(x50p, y50p, mValue, rExp, bValue, bExp, bSigned, yRange);
16317e21c20SJosh Lehan         testValue(x75p, y75p, mValue, rExp, bValue, bExp, bSigned, yRange);
16417e21c20SJosh Lehan         testValue(xMax, yMax, mValue, rExp, bValue, bExp, bSigned, yRange);
16517e21c20SJosh Lehan     }
16617e21c20SJosh Lehan }
16717e21c20SJosh Lehan 
testRanges(void)16817e21c20SJosh Lehan void testRanges(void)
16917e21c20SJosh Lehan {
17017e21c20SJosh Lehan     // The ranges from the main TEST function
17117e21c20SJosh Lehan     testBounds(0x0, 0xFF);
17217e21c20SJosh Lehan     testBounds(-128, 127);
17317e21c20SJosh Lehan     testBounds(0, 16000);
17417e21c20SJosh Lehan     testBounds(0, 20);
17517e21c20SJosh Lehan     testBounds(8000, 16000);
17617e21c20SJosh Lehan     testBounds(-10, 10);
17717e21c20SJosh Lehan     testBounds(0, 277);
17817e21c20SJosh Lehan     testBounds(0, 0, false);
17917e21c20SJosh Lehan     testBounds(10, 12);
18017e21c20SJosh Lehan 
18117e21c20SJosh Lehan     // Additional test cases recommended to me by hardware people
18217e21c20SJosh Lehan     testBounds(-40, 150);
18317e21c20SJosh Lehan     testBounds(0, 1);
18417e21c20SJosh Lehan     testBounds(0, 2);
18517e21c20SJosh Lehan     testBounds(0, 4);
18617e21c20SJosh Lehan     testBounds(0, 8);
18717e21c20SJosh Lehan     testBounds(35, 65);
18817e21c20SJosh Lehan     testBounds(0, 18);
18917e21c20SJosh Lehan     testBounds(0, 25);
19017e21c20SJosh Lehan     testBounds(0, 80);
19117e21c20SJosh Lehan     testBounds(0, 500);
19217e21c20SJosh Lehan 
19317e21c20SJosh Lehan     // Additional sanity checks
19417e21c20SJosh Lehan     testBounds(0, 255);
19517e21c20SJosh Lehan     testBounds(-255, 0);
19617e21c20SJosh Lehan     testBounds(-255, 255);
19717e21c20SJosh Lehan     testBounds(0, 1000);
19817e21c20SJosh Lehan     testBounds(-1000, 0);
19917e21c20SJosh Lehan     testBounds(-1000, 1000);
20017e21c20SJosh Lehan     testBounds(0, 255000);
20117e21c20SJosh Lehan     testBounds(-128000000, 127000000);
20217e21c20SJosh Lehan     testBounds(-50000, 0);
20317e21c20SJosh Lehan     testBounds(-40000, 10000);
20417e21c20SJosh Lehan     testBounds(-30000, 20000);
20517e21c20SJosh Lehan     testBounds(-20000, 30000);
20617e21c20SJosh Lehan     testBounds(-10000, 40000);
20717e21c20SJosh Lehan     testBounds(0, 50000);
20817e21c20SJosh Lehan     testBounds(-1e3, 1e6);
20917e21c20SJosh Lehan     testBounds(-1e6, 1e3);
21017e21c20SJosh Lehan 
21117e21c20SJosh Lehan     // Extreme ranges are now possible
21217e21c20SJosh Lehan     testBounds(0, 1e10);
21317e21c20SJosh Lehan     testBounds(0, 1e11);
21417e21c20SJosh Lehan     testBounds(0, 1e12);
21517e21c20SJosh Lehan     testBounds(0, 1e13, false);
21617e21c20SJosh Lehan     testBounds(-1e10, 0);
21717e21c20SJosh Lehan     testBounds(-1e11, 0);
21817e21c20SJosh Lehan     testBounds(-1e12, 0);
21917e21c20SJosh Lehan     testBounds(-1e13, 0, false);
22017e21c20SJosh Lehan     testBounds(-1e9, 1e9);
22117e21c20SJosh Lehan     testBounds(-1e10, 1e10);
22217e21c20SJosh Lehan     testBounds(-1e11, 1e11);
22317e21c20SJosh Lehan     testBounds(-1e12, 1e12, false);
22417e21c20SJosh Lehan 
22517e21c20SJosh Lehan     // Large multiplier but small offset
22617e21c20SJosh Lehan     testBounds(1e4, 1e4 + 255);
22717e21c20SJosh Lehan     testBounds(1e5, 1e5 + 255);
22817e21c20SJosh Lehan     testBounds(1e6, 1e6 + 255);
22917e21c20SJosh Lehan     testBounds(1e7, 1e7 + 255);
23017e21c20SJosh Lehan     testBounds(1e8, 1e8 + 255);
23117e21c20SJosh Lehan     testBounds(1e9, 1e9 + 255);
23217e21c20SJosh Lehan     testBounds(1e10, 1e10 + 255, false);
23317e21c20SJosh Lehan 
23417e21c20SJosh Lehan     // Input validation against garbage
23517e21c20SJosh Lehan     testBounds(0, INFINITY, false);
23617e21c20SJosh Lehan     testBounds(-INFINITY, 0, false);
23717e21c20SJosh Lehan     testBounds(-INFINITY, INFINITY, false);
23817e21c20SJosh Lehan     testBounds(0, NAN, false);
23917e21c20SJosh Lehan     testBounds(NAN, 0, false);
24017e21c20SJosh Lehan     testBounds(NAN, NAN, false);
24117e21c20SJosh Lehan 
24217e21c20SJosh Lehan     // Noteworthy binary integers
24317e21c20SJosh Lehan     testBounds(0, std::pow(2.0, 32.0) - 1.0);
24417e21c20SJosh Lehan     testBounds(0, std::pow(2.0, 32.0));
24517e21c20SJosh Lehan     testBounds(0.0 - std::pow(2.0, 31.0), std::pow(2.0, 31.0));
24617e21c20SJosh Lehan     testBounds((0.0 - std::pow(2.0, 31.0)) - 1.0, std::pow(2.0, 31.0));
24717e21c20SJosh Lehan 
24817e21c20SJosh Lehan     // Similar but negative (note additional commented-out below)
24917e21c20SJosh Lehan     testBounds(-1e1, (-1e1) + 255);
25017e21c20SJosh Lehan     testBounds(-1e2, (-1e2) + 255);
25117e21c20SJosh Lehan 
25217e21c20SJosh Lehan     // Ranges of negative numbers (note additional commented-out below)
25317e21c20SJosh Lehan     testBounds(-10400, -10000);
25417e21c20SJosh Lehan     testBounds(-15000, -14000);
25517e21c20SJosh Lehan     testBounds(-10000, -9000);
25617e21c20SJosh Lehan     testBounds(-1000, -900);
25717e21c20SJosh Lehan     testBounds(-1000, -800);
25817e21c20SJosh Lehan     testBounds(-1000, -700);
25917e21c20SJosh Lehan     testBounds(-1000, -740);
26017e21c20SJosh Lehan 
26117e21c20SJosh Lehan     // Very small ranges (note additional commented-out below)
26217e21c20SJosh Lehan     testBounds(0, 0.1);
26317e21c20SJosh Lehan     testBounds(0, 0.01);
26417e21c20SJosh Lehan     testBounds(0, 0.001);
26517e21c20SJosh Lehan     testBounds(0, 0.0001);
26617e21c20SJosh Lehan     testBounds(0, 0.000001, false);
26717e21c20SJosh Lehan 
26817e21c20SJosh Lehan #if 0
26917e21c20SJosh Lehan     // TODO(): The algorithm in this module is better than it was before,
27017e21c20SJosh Lehan     // but the resulting value of X is still wrong under certain conditions,
27117e21c20SJosh Lehan     // such as when the range between min and max is around 255,
27217e21c20SJosh Lehan     // and the offset is fairly extreme compared to the multiplier.
27317e21c20SJosh Lehan     // Not sure why this is, but these ranges are contrived,
27417e21c20SJosh Lehan     // and real-world examples would most likely never be this way.
27517e21c20SJosh Lehan     testBounds(-10290, -10000);
27617e21c20SJosh Lehan     testBounds(-10280, -10000);
27717e21c20SJosh Lehan     testBounds(-10275,-10000);
27817e21c20SJosh Lehan     testBounds(-10270,-10000);
27917e21c20SJosh Lehan     testBounds(-10265,-10000);
28017e21c20SJosh Lehan     testBounds(-10260,-10000);
28117e21c20SJosh Lehan     testBounds(-10255,-10000);
28217e21c20SJosh Lehan     testBounds(-10250,-10000);
28317e21c20SJosh Lehan     testBounds(-10245,-10000);
28417e21c20SJosh Lehan     testBounds(-10256,-10000);
28517e21c20SJosh Lehan     testBounds(-10512, -10000);
28617e21c20SJosh Lehan     testBounds(-11024, -10000);
28717e21c20SJosh Lehan 
28817e21c20SJosh Lehan     // TODO(): This also fails, due to extreme small range, loss of precision
28917e21c20SJosh Lehan     testBounds(0, 0.00001);
29017e21c20SJosh Lehan 
29117e21c20SJosh Lehan     // TODO(): Interestingly, if bSigned is forced false,
29217e21c20SJosh Lehan     // causing "x" to have range of (0,255) instead of (-128,127),
29317e21c20SJosh Lehan     // these test cases change from failing to passing!
29417e21c20SJosh Lehan     // Not sure why this is, perhaps a mathematician might know.
29517e21c20SJosh Lehan     testBounds(-10300, -10000);
29617e21c20SJosh Lehan     testBounds(-1000,-750);
29717e21c20SJosh Lehan     testBounds(-1e3, (-1e3) + 255);
29817e21c20SJosh Lehan     testBounds(-1e4, (-1e4) + 255);
29917e21c20SJosh Lehan     testBounds(-1e5, (-1e5) + 255);
30017e21c20SJosh Lehan     testBounds(-1e6, (-1e6) + 255);
30117e21c20SJosh Lehan #endif
30217e21c20SJosh Lehan }
30317e21c20SJosh Lehan 
TEST(sensorutils,TranslateToIPMI)3043f7c5e40SJason M. Bills TEST(sensorutils, TranslateToIPMI)
3053f7c5e40SJason M. Bills {
3063f7c5e40SJason M. Bills     /*bool getSensorAttributes(double maxValue, double minValue, int16_t
3073f7c5e40SJason M. Bills        &mValue, int8_t &rExp, int16_t &bValue, int8_t &bExp, bool &bSigned); */
3083f7c5e40SJason M. Bills     // normal unsigned sensor
3093f7c5e40SJason M. Bills     double maxValue = 0xFF;
3103f7c5e40SJason M. Bills     double minValue = 0x0;
3113f7c5e40SJason M. Bills     int16_t mValue;
3123f7c5e40SJason M. Bills     int8_t rExp;
3133f7c5e40SJason M. Bills     int16_t bValue;
3143f7c5e40SJason M. Bills     int8_t bExp;
3153f7c5e40SJason M. Bills     bool bSigned;
3163f7c5e40SJason M. Bills     bool result;
3173f7c5e40SJason M. Bills 
3183f7c5e40SJason M. Bills     uint8_t scaledVal;
3193f7c5e40SJason M. Bills 
3203f7c5e40SJason M. Bills     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
3213f7c5e40SJason M. Bills                                        bExp, bSigned);
3223f7c5e40SJason M. Bills     EXPECT_EQ(result, true);
3233f7c5e40SJason M. Bills     if (result)
3243f7c5e40SJason M. Bills     {
3253f7c5e40SJason M. Bills         EXPECT_EQ(bSigned, false);
3263f7c5e40SJason M. Bills         EXPECT_EQ(mValue, 1);
3273f7c5e40SJason M. Bills         EXPECT_EQ(rExp, 0);
3283f7c5e40SJason M. Bills         EXPECT_EQ(bValue, 0);
3293f7c5e40SJason M. Bills         EXPECT_EQ(bExp, 0);
3303f7c5e40SJason M. Bills     }
3313f7c5e40SJason M. Bills     double expected = 0x50;
3323f7c5e40SJason M. Bills     scaledVal = ipmi::scaleIPMIValueFromDouble(0x50, mValue, rExp, bValue, bExp,
3333f7c5e40SJason M. Bills                                                bSigned);
3343f7c5e40SJason M. Bills     EXPECT_NEAR(scaledVal, expected, expected * 0.01);
3353f7c5e40SJason M. Bills 
3363f7c5e40SJason M. Bills     // normal signed sensor
3373f7c5e40SJason M. Bills     maxValue = 127;
3383f7c5e40SJason M. Bills     minValue = -128;
3393f7c5e40SJason M. Bills 
3403f7c5e40SJason M. Bills     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
3413f7c5e40SJason M. Bills                                        bExp, bSigned);
3423f7c5e40SJason M. Bills     EXPECT_EQ(result, true);
3433f7c5e40SJason M. Bills 
3443f7c5e40SJason M. Bills     if (result)
3453f7c5e40SJason M. Bills     {
3463f7c5e40SJason M. Bills         EXPECT_EQ(bSigned, true);
3473f7c5e40SJason M. Bills         EXPECT_EQ(mValue, 1);
3483f7c5e40SJason M. Bills         EXPECT_EQ(rExp, 0);
3493f7c5e40SJason M. Bills         EXPECT_EQ(bValue, 0);
3503f7c5e40SJason M. Bills         EXPECT_EQ(bExp, 0);
3513f7c5e40SJason M. Bills     }
3523f7c5e40SJason M. Bills 
353f6a07837SJames Feist     // check negative values
354f6a07837SJames Feist     expected = 236; // 2s compliment -20
355f6a07837SJames Feist     scaledVal = ipmi::scaleIPMIValueFromDouble(-20, mValue, rExp, bValue, bExp,
356f6a07837SJames Feist                                                bSigned);
357f6a07837SJames Feist     EXPECT_NEAR(scaledVal, expected, expected * 0.01);
358f6a07837SJames Feist 
3593f7c5e40SJason M. Bills     // fan example
3603f7c5e40SJason M. Bills     maxValue = 16000;
3613f7c5e40SJason M. Bills     minValue = 0;
3623f7c5e40SJason M. Bills 
3633f7c5e40SJason M. Bills     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
3643f7c5e40SJason M. Bills                                        bExp, bSigned);
3653f7c5e40SJason M. Bills     EXPECT_EQ(result, true);
3663f7c5e40SJason M. Bills     if (result)
3673f7c5e40SJason M. Bills     {
3683f7c5e40SJason M. Bills         EXPECT_EQ(bSigned, false);
369aecaef7eSJames Feist         EXPECT_EQ(mValue, floor((16000.0 / 0xFF) + 0.5));
3703f7c5e40SJason M. Bills         EXPECT_EQ(rExp, 0);
3713f7c5e40SJason M. Bills         EXPECT_EQ(bValue, 0);
3723f7c5e40SJason M. Bills         EXPECT_EQ(bExp, 0);
3733f7c5e40SJason M. Bills     }
3743f7c5e40SJason M. Bills 
3753f7c5e40SJason M. Bills     // voltage sensor example
3763f7c5e40SJason M. Bills     maxValue = 20;
3773f7c5e40SJason M. Bills     minValue = 0;
3783f7c5e40SJason M. Bills 
3793f7c5e40SJason M. Bills     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
3803f7c5e40SJason M. Bills                                        bExp, bSigned);
3813f7c5e40SJason M. Bills     EXPECT_EQ(result, true);
3823f7c5e40SJason M. Bills     if (result)
3833f7c5e40SJason M. Bills     {
3843f7c5e40SJason M. Bills         EXPECT_EQ(bSigned, false);
38517e21c20SJosh Lehan         EXPECT_EQ(mValue, floor(((20.0 / 0xFF) / std::pow(10, rExp)) + 0.5));
3863f7c5e40SJason M. Bills         EXPECT_EQ(rExp, -3);
3873f7c5e40SJason M. Bills         EXPECT_EQ(bValue, 0);
3883f7c5e40SJason M. Bills         EXPECT_EQ(bExp, 0);
3893f7c5e40SJason M. Bills     }
3903f7c5e40SJason M. Bills     scaledVal = ipmi::scaleIPMIValueFromDouble(12.2, mValue, rExp, bValue, bExp,
3913f7c5e40SJason M. Bills                                                bSigned);
3923f7c5e40SJason M. Bills 
3933f7c5e40SJason M. Bills     expected = 12.2 / (mValue * std::pow(10, rExp));
3943f7c5e40SJason M. Bills     EXPECT_NEAR(scaledVal, expected, expected * 0.01);
3953f7c5e40SJason M. Bills 
3963f7c5e40SJason M. Bills     // shifted fan example
3973f7c5e40SJason M. Bills     maxValue = 16000;
3983f7c5e40SJason M. Bills     minValue = 8000;
3993f7c5e40SJason M. Bills 
4003f7c5e40SJason M. Bills     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
4013f7c5e40SJason M. Bills                                        bExp, bSigned);
4023f7c5e40SJason M. Bills     EXPECT_EQ(result, true);
4033f7c5e40SJason M. Bills 
4043f7c5e40SJason M. Bills     if (result)
4053f7c5e40SJason M. Bills     {
4063f7c5e40SJason M. Bills         EXPECT_EQ(bSigned, false);
40717e21c20SJosh Lehan         EXPECT_EQ(mValue, floor(((8000.0 / 0xFF) / std::pow(10, rExp)) + 0.5));
40817e21c20SJosh Lehan         EXPECT_EQ(rExp, -1);
40917e21c20SJosh Lehan         EXPECT_EQ(bValue, 8);
41017e21c20SJosh Lehan         EXPECT_EQ(bExp, 4);
4113f7c5e40SJason M. Bills     }
4123f7c5e40SJason M. Bills 
4133f7c5e40SJason M. Bills     // signed voltage sensor example
4143f7c5e40SJason M. Bills     maxValue = 10;
4153f7c5e40SJason M. Bills     minValue = -10;
4163f7c5e40SJason M. Bills 
4173f7c5e40SJason M. Bills     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
4183f7c5e40SJason M. Bills                                        bExp, bSigned);
4193f7c5e40SJason M. Bills     EXPECT_EQ(result, true);
4203f7c5e40SJason M. Bills     if (result)
4213f7c5e40SJason M. Bills     {
4223f7c5e40SJason M. Bills         EXPECT_EQ(bSigned, true);
42317e21c20SJosh Lehan         EXPECT_EQ(mValue, floor(((20.0 / 0xFF) / std::pow(10, rExp)) + 0.5));
4243f7c5e40SJason M. Bills         EXPECT_EQ(rExp, -3);
42517e21c20SJosh Lehan         // Although this seems like a weird magic number,
42617e21c20SJosh Lehan         // it is because the range (-128,127) is not symmetrical about zero,
42717e21c20SJosh Lehan         // unlike the range (-10,10), so this introduces some distortion.
42817e21c20SJosh Lehan         EXPECT_EQ(bValue, 392);
42917e21c20SJosh Lehan         EXPECT_EQ(bExp, -1);
4303f7c5e40SJason M. Bills     }
4313f7c5e40SJason M. Bills 
432*1bcced08SPatrick Williams     scaledVal =
433*1bcced08SPatrick Williams         ipmi::scaleIPMIValueFromDouble(5, mValue, rExp, bValue, bExp, bSigned);
4343f7c5e40SJason M. Bills 
4353f7c5e40SJason M. Bills     expected = 5 / (mValue * std::pow(10, rExp));
4363f7c5e40SJason M. Bills     EXPECT_NEAR(scaledVal, expected, expected * 0.01);
4373f7c5e40SJason M. Bills 
438aecaef7eSJames Feist     // reading = max example
439aecaef7eSJames Feist     maxValue = 277;
440aecaef7eSJames Feist     minValue = 0;
441aecaef7eSJames Feist 
442aecaef7eSJames Feist     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
443aecaef7eSJames Feist                                        bExp, bSigned);
444aecaef7eSJames Feist     EXPECT_EQ(result, true);
445aecaef7eSJames Feist     if (result)
446aecaef7eSJames Feist     {
447aecaef7eSJames Feist         EXPECT_EQ(bSigned, false);
448aecaef7eSJames Feist     }
449aecaef7eSJames Feist 
450aecaef7eSJames Feist     scaledVal = ipmi::scaleIPMIValueFromDouble(maxValue, mValue, rExp, bValue,
451aecaef7eSJames Feist                                                bExp, bSigned);
452aecaef7eSJames Feist 
453aecaef7eSJames Feist     expected = 0xFF;
454aecaef7eSJames Feist     EXPECT_NEAR(scaledVal, expected, expected * 0.01);
455aecaef7eSJames Feist 
4563f7c5e40SJason M. Bills     // 0, 0 failure
4573f7c5e40SJason M. Bills     maxValue = 0;
4583f7c5e40SJason M. Bills     minValue = 0;
4593f7c5e40SJason M. Bills     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
4603f7c5e40SJason M. Bills                                        bExp, bSigned);
4613f7c5e40SJason M. Bills     EXPECT_EQ(result, false);
4623f7c5e40SJason M. Bills 
46317e21c20SJosh Lehan     // too close *success* (was previously failure!)
4643f7c5e40SJason M. Bills     maxValue = 12;
4653f7c5e40SJason M. Bills     minValue = 10;
4663f7c5e40SJason M. Bills     result = ipmi::getSensorAttributes(maxValue, minValue, mValue, rExp, bValue,
4673f7c5e40SJason M. Bills                                        bExp, bSigned);
46817e21c20SJosh Lehan     EXPECT_EQ(result, true);
46917e21c20SJosh Lehan     if (result)
47017e21c20SJosh Lehan     {
47117e21c20SJosh Lehan         EXPECT_EQ(bSigned, false);
47217e21c20SJosh Lehan         EXPECT_EQ(mValue, floor(((2.0 / 0xFF) / std::pow(10, rExp)) + 0.5));
47317e21c20SJosh Lehan         EXPECT_EQ(rExp, -4);
47417e21c20SJosh Lehan         EXPECT_EQ(bValue, 1);
47517e21c20SJosh Lehan         EXPECT_EQ(bExp, 5);
47617e21c20SJosh Lehan     }
47717e21c20SJosh Lehan }
47817e21c20SJosh Lehan 
TEST(sensorUtils,TestRanges)47917e21c20SJosh Lehan TEST(sensorUtils, TestRanges)
48017e21c20SJosh Lehan {
48117e21c20SJosh Lehan     // Additional test ranges, each running through a series of values,
48217e21c20SJosh Lehan     // to make sure the values of "x" and "y" go together and make sense,
48317e21c20SJosh Lehan     // for the resulting scaling attributes from each range.
48417e21c20SJosh Lehan     // Unlike the TranslateToIPMI test, exact matches of the
48517e21c20SJosh Lehan     // getSensorAttributes() results (the coefficients) are not required,
48617e21c20SJosh Lehan     // because they are tested through actual use, relating "x" to "y".
48717e21c20SJosh Lehan     testRanges();
4883f7c5e40SJason M. Bills }
489