commence breakage
[inav.git] / src / test / unit / battery_unittest.cc.txt
blobef6ea641787a3ad36eb302614a2933dfa84ffe6a
1 /*
2  * This file is part of Cleanflight.
3  *
4  * Cleanflight is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Cleanflight is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Cleanflight.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include <stdint.h>
19 #include <limits.h>
21 //#define DEBUG_BATTERY
23 extern "C" {
24     #include "sensors/battery.h"
25     
26     #include "io/rc_controls.h"
27     #include "flight/lowpass.h"
28     #include "io/beeper.h"
31 #include "unittest_macros.h"
32 #include "gtest/gtest.h"
34 typedef struct batteryAdcToVoltageExpectation_s {
35     uint16_t adcReading;
36     uint16_t expectedVoltageInDeciVoltSteps;
37     uint8_t scale;
38 } batteryAdcToVoltageExpectation_t;
40 #define ELEVEN_TO_ONE_VOLTAGE_DIVIDER 110 // (10k:1k) * 10 for 0.1V
42 TEST(BatteryTest, BatteryADCToVoltage)
44     // batteryInit() reads a bunch of fields including vbatscale, so set up the config with useful initial values:
45     batteryConfig_t batteryConfig = {
46         .vbatscale = VBAT_SCALE_DEFAULT,
47         .vbatresdivval = VBAT_RESDIVVAL_DEFAULT,
48         .vbatresdivmultiplier = VBAT_RESDIVMULTIPLIER_DEFAULT,
49         .vbatmaxcellvoltage = 43,
50         .vbatmincellvoltage = 33,
51         .vbatwarningcellvoltage = 35,
52         .currentMeterScale = 400,
53         .currentMeterOffset = 0,
54         .currentMeterType = CURRENT_SENSOR_NONE,
55         .multiwiiCurrentMeterOutput = 0,
56         .batteryCapacity = 2200,
57     };
59     batteryInit(&batteryConfig);
61     batteryAdcToVoltageExpectation_t batteryAdcToVoltageExpectations[] = {
62             {1420, 126 /*125.88*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
63             {1430, 127 /*126.76*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
64             {1440, 128 /*127.65*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
65             {1890, 168 /*167.54*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
66             {1900, 168 /*168.42*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
67             {1910, 169 /*169.31*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
68             {   0,   0 /*  0.00*/, VBAT_SCALE_MAX},
69             {4096, 842 /*841.71*/, VBAT_SCALE_MAX}
70     };
71     uint8_t testIterationCount = sizeof(batteryAdcToVoltageExpectations) / sizeof(batteryAdcToVoltageExpectation_t);
73     // expect
75     for (uint8_t index = 0; index < testIterationCount; index ++) {
76         batteryAdcToVoltageExpectation_t *batteryAdcToVoltageExpectation = &batteryAdcToVoltageExpectations[index];
77         batteryConfig.vbatscale = batteryAdcToVoltageExpectation->scale;
78 #ifdef DEBUG_BATTERY
79         printf("adcReading: %d, vbatscale: %d\n",
80                 batteryAdcToVoltageExpectation->adcReading,
81                 batteryAdcToVoltageExpectation->scale
82         );
83 #endif
84         uint16_t pointOneVoltSteps = batteryAdcToVoltage(batteryAdcToVoltageExpectation->adcReading);
86         EXPECT_EQ(batteryAdcToVoltageExpectation->expectedVoltageInDeciVoltSteps, pointOneVoltSteps);
87     }
90 uint16_t currentADCReading;
93 typedef struct batteryAdcToBatteryStateExpectation_s
95     uint16_t adcReading;
96     uint16_t expectedVoltageInDeciVoltSteps;
97     batteryState_e expectedBatteryState;
98     uint8_t scale;
99 } batteryAdcToBatteryStateExpectation_t;
101 /* Test the battery state and hysteresis code */
102 TEST(BatteryTest, BatteryState)
104     // batteryInit() reads a bunch of fields including vbatscale, so set up the config with useful initial values:
105     batteryConfig_t batteryConfig = {
106         .vbatscale = VBAT_SCALE_DEFAULT,
107         .vbatresdivval = VBAT_RESDIVVAL_DEFAULT,
108         .vbatresdivmultiplier = VBAT_RESDIVMULTIPLIER_DEFAULT,
109         .vbatmaxcellvoltage = 43,
110         .vbatmincellvoltage = 33,
111         .vbatwarningcellvoltage = 35,
112         .currentMeterScale = 400,
113         .currentMeterOffset = 0,
114         .currentMeterType = CURRENT_SENSOR_NONE,
115         .multiwiiCurrentMeterOutput = 0,
116         .batteryCapacity = 2200,
117     };
119     batteryInit(&batteryConfig);
121     batteryAdcToBatteryStateExpectation_t batteryAdcToBatteryStateExpectations[] = {
122             {1420, 126, BATTERY_OK, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
123             /* fall down to battery warning level */
124             {1185, 105, BATTERY_OK, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
125             {1175, 104, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
126             /* creep back up to battery ok */
127             {1185, 105, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
128             {1195, 106, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
129             {1207, 107, BATTERY_OK, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
130             /* fall down to battery critical level */
131             {1175, 104, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
132             {1108, 98, BATTERY_CRITICAL, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
133             /* creep back up to battery warning */
134             {1115, 99, BATTERY_CRITICAL, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
135             {1130, 100, BATTERY_CRITICAL, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
136             {1145, 101, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
138     };
139     uint8_t testIterationCount = sizeof(batteryAdcToBatteryStateExpectations) / sizeof(batteryAdcToBatteryStateExpectation_t);
141     // expect
142     for (uint8_t index = 0; index < testIterationCount; index ++) {
143         batteryAdcToBatteryStateExpectation_t *batteryAdcToBatteryStateExpectation = &batteryAdcToBatteryStateExpectations[index];
144         batteryConfig.vbatscale = batteryAdcToBatteryStateExpectation->scale;
145         currentADCReading = batteryAdcToBatteryStateExpectation->adcReading;
146         updateBattery( );
147         batteryState_e batteryState = getBatteryState();
148         EXPECT_EQ(batteryAdcToBatteryStateExpectation->expectedBatteryState, batteryState);
149     }
152 typedef struct batteryAdcToCellCountExpectation_s
154     uint16_t adcReading;
155     uint16_t expectedVoltageInDeciVoltSteps;
156     uint8_t scale;
157     uint8_t cellCount;
158 } batteryAdcToCellCountExpectation_t;
160 /* Test the cell count is correctly detected if we start at 0V */
161 TEST(BatteryTest, CellCount)
163     // batteryInit() reads a bunch of fields including vbatscale, so set up the config with useful initial values:
164     batteryConfig_t batteryConfig = {
165         .vbatscale = VBAT_SCALE_DEFAULT,
166         .vbatresdivval = VBAT_RESDIVVAL_DEFAULT,
167         .vbatresdivmultiplier = VBAT_RESDIVMULTIPLIER_DEFAULT,
168         .vbatmaxcellvoltage = 43,
169         .vbatmincellvoltage = 33,
170         .vbatwarningcellvoltage = 35,
171         .currentMeterScale = 400,
172         .currentMeterOffset = 0,
173         .currentMeterType = CURRENT_SENSOR_NONE,
174         .multiwiiCurrentMeterOutput = 0,
175         .batteryCapacity = 2200,
176     };
178     batteryInit(&batteryConfig);
180     batteryAdcToCellCountExpectation_t batteryAdcToCellCountExpectations[] = {
181             {0, 0, ELEVEN_TO_ONE_VOLTAGE_DIVIDER, 1},
182             {1420, 126, ELEVEN_TO_ONE_VOLTAGE_DIVIDER, 3},
183     };
184     uint8_t testIterationCount = sizeof(batteryAdcToCellCountExpectations) / sizeof(batteryAdcToCellCountExpectation_t);
186     // expect
187     for (uint8_t index = 0; index < testIterationCount; index ++) {
188         batteryAdcToCellCountExpectation_t *batteryAdcToCellCountExpectation = &batteryAdcToCellCountExpectations[index];
189         batteryConfig.vbatscale = batteryAdcToCellCountExpectation->scale;
190         currentADCReading = batteryAdcToCellCountExpectation->adcReading;
191         updateBattery( );
192         EXPECT_EQ(batteryAdcToCellCountExpectation->cellCount, batteryCellCount);
193     }
196 //#define DEBUG_ROLLOVER_PATTERNS
198  * These next two tests do not test any production code (!) but serves as an example of how to use a signed variable for timing purposes.
200  * The 'signed diff timing' pattern is followed in a few places in the production codebase.
201  */
202 TEST(BatteryTest, RollOverPattern1)
204     uint16_t now = 0;
205     uint16_t servicedAt = 0;
206     uint16_t serviceInterval = 5000;
207     int serviceCount = 0;
208     int rolloverCount = 0;
210     while(rolloverCount < 3) {
212         int16_t diff = (now - servicedAt);
213         if (diff >= serviceInterval) {
215             if (now < servicedAt) {
216                 rolloverCount++;
217             }
219             servicedAt = now;
220 #ifdef DEBUG_ROLLOVER_PATTERNS
221             printf("servicedAt: %d, diff: %d\n", servicedAt, diff);
222 #endif
223             serviceCount++;
225             EXPECT_GT(diff, 0);
226             EXPECT_GE(diff, serviceInterval); // service interval must have passed
227             EXPECT_LT(diff, serviceInterval + 95 + 10); // but never more than the service interval + ticks + jitter
228         }
230         now += 95 + (rand() % 10); // simulate 100 ticks +/- 5 ticks of jitter, this can rollover
231     }
232     EXPECT_GT(serviceCount, 0);
235 TEST(BatteryTest, RollOverPattern2)
237     uint16_t now = 0;
238     uint16_t serviceAt = 0;
239     uint16_t serviceInterval = 5000;
240     int serviceCount = 0;
241     int rolloverCount = 0;
243     while(rolloverCount < 3) {
245         int16_t diff = (now - serviceAt);
246         if (diff >= 0) {
248             if (now < serviceAt) {
249                 rolloverCount++;
250             }
252             serviceAt = now + serviceInterval; // this can rollover
253 #ifdef DEBUG_ROLLOVER_PATTERNS
254             printf("servicedAt: %d, nextServiceAt: %d, diff: %d\n", now, serviceAt, diff);
255 #endif
257             serviceCount++;
259             EXPECT_GE(diff, 0);
260             EXPECT_LE(diff, serviceInterval);
261             EXPECT_LT(diff, 95 + 10); // never more than the ticks + jitter
262         }
264         now += 95 + (rand() % 10); // simulate 100 ticks +/- 5 ticks of jitter, this can rollover
265     }
266     EXPECT_GT(serviceCount, 0);
270 // STUBS
272 extern "C" {
274 uint8_t armingFlags = 0;
275 int16_t rcCommand[4] = {0,0,0,0};
278 bool feature(uint32_t mask)
280     UNUSED(mask);
281     return false;
284 throttleStatus_e calculateThrottleStatus(rxConfig_t *rxConfig, uint16_t mid_throttle_deadband)
286     UNUSED(*rxConfig);
287     UNUSED(mid_throttle_deadband);
288     return THROTTLE_HIGH;
291 uint16_t adcGetChannel(uint8_t channel)
293     UNUSED(channel);
294     return currentADCReading;
297 void delay(uint32_t ms)
299     UNUSED(ms);
300     return;
303 int32_t lowpassFixed(lowpass_t *filter, int32_t in, int16_t freq)
305     UNUSED(filter);
306     UNUSED(freq);
307     return in;
310 void beeper(beeperMode_e mode)
312     UNUSED(mode);