2 * This file is part of Cleanflight.
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.
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.
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/>.
21 //#define DEBUG_BATTERY
24 #include "sensors/battery.h"
25 #include "fc/rc_controls.h"
26 #include "io/beeper.h"
29 #include "unittest_macros.h"
30 #include "gtest/gtest.h"
32 typedef struct batteryAdcToVoltageExpectation_s {
34 uint16_t expectedVoltageInDeciVoltSteps;
36 } batteryAdcToVoltageExpectation_t;
38 #define ELEVEN_TO_ONE_VOLTAGE_DIVIDER 110 // (10k:1k) * 10 for 0.1V
40 TEST(BatteryTest, BatteryADCToVoltage)
42 // batteryInit() reads a bunch of fields including vbatscale, so set up the config with useful initial values:
43 batteryConfig_t batteryConfig = {
44 .vbatscale = VBAT_SCALE_DEFAULT,
45 .vbatresdivval = VBAT_RESDIVVAL_DEFAULT,
46 .vbatresdivmultiplier = VBAT_RESDIVMULTIPLIER_DEFAULT,
47 .vbatmaxcellvoltage = 43,
48 .vbatmincellvoltage = 33,
49 .vbatwarningcellvoltage = 35,
50 .currentMeterScale = 400,
51 .currentMeterOffset = 0,
52 .currentMeterType = CURRENT_SENSOR_NONE,
53 .multiwiiCurrentMeterOutput = 0,
54 .batteryCapacity = 2200,
57 batteryInit(&batteryConfig);
59 batteryAdcToVoltageExpectation_t batteryAdcToVoltageExpectations[] = {
60 {1420, 126 /*125.88*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
61 {1430, 127 /*126.76*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
62 {1440, 128 /*127.65*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
63 {1890, 168 /*167.54*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
64 {1900, 168 /*168.42*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
65 {1910, 169 /*169.31*/, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
66 { 0, 0 /* 0.00*/, VBAT_SCALE_MAX},
67 {4096, 842 /*841.71*/, VBAT_SCALE_MAX}
69 uint8_t testIterationCount = sizeof(batteryAdcToVoltageExpectations) / sizeof(batteryAdcToVoltageExpectation_t);
73 for (uint8_t index = 0; index < testIterationCount; index ++) {
74 batteryAdcToVoltageExpectation_t *batteryAdcToVoltageExpectation = &batteryAdcToVoltageExpectations[index];
75 batteryConfig.vbatscale = batteryAdcToVoltageExpectation->scale;
77 printf("adcReading: %d, vbatscale: %d\n",
78 batteryAdcToVoltageExpectation->adcReading,
79 batteryAdcToVoltageExpectation->scale
82 uint16_t pointOneVoltSteps = batteryAdcToVoltage(batteryAdcToVoltageExpectation->adcReading);
84 EXPECT_EQ(batteryAdcToVoltageExpectation->expectedVoltageInDeciVoltSteps, pointOneVoltSteps);
88 uint16_t currentADCReading;
91 typedef struct batteryAdcToBatteryStateExpectation_s
94 uint16_t expectedVoltageInDeciVoltSteps;
95 batteryState_e expectedBatteryState;
97 } batteryAdcToBatteryStateExpectation_t;
99 /* Test the battery state and hysteresis code */
100 TEST(BatteryTest, BatteryState)
102 // batteryInit() reads a bunch of fields including vbatscale, so set up the config with useful initial values:
103 batteryConfig_t batteryConfig = {
104 .vbatscale = VBAT_SCALE_DEFAULT,
105 .vbatresdivval = VBAT_RESDIVVAL_DEFAULT,
106 .vbatresdivmultiplier = VBAT_RESDIVMULTIPLIER_DEFAULT,
107 .vbatmaxcellvoltage = 43,
108 .vbatmincellvoltage = 33,
109 .vbatwarningcellvoltage = 35,
110 .currentMeterScale = 400,
111 .currentMeterOffset = 0,
112 .currentMeterType = CURRENT_SENSOR_NONE,
113 .multiwiiCurrentMeterOutput = 0,
114 .batteryCapacity = 2200,
117 batteryInit(&batteryConfig);
119 batteryAdcToBatteryStateExpectation_t batteryAdcToBatteryStateExpectations[] = {
120 {1420, 126, BATTERY_OK, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
121 /* fall down to battery warning level */
122 {1185, 105, BATTERY_OK, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
123 {1175, 104, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
124 /* creep back up to battery ok */
125 {1185, 105, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
126 {1195, 106, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
127 {1207, 107, BATTERY_OK, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
128 /* fall down to battery critical level */
129 {1175, 104, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
130 {1108, 98, BATTERY_CRITICAL, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
131 /* creep back up to battery warning */
132 {1115, 99, BATTERY_CRITICAL, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
133 {1130, 100, BATTERY_CRITICAL, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
134 {1145, 101, BATTERY_WARNING, ELEVEN_TO_ONE_VOLTAGE_DIVIDER},
137 uint8_t testIterationCount = sizeof(batteryAdcToBatteryStateExpectations) / sizeof(batteryAdcToBatteryStateExpectation_t);
140 for (uint8_t index = 0; index < testIterationCount; index ++) {
141 batteryAdcToBatteryStateExpectation_t *batteryAdcToBatteryStateExpectation = &batteryAdcToBatteryStateExpectations[index];
142 batteryConfig.vbatscale = batteryAdcToBatteryStateExpectation->scale;
143 currentADCReading = batteryAdcToBatteryStateExpectation->adcReading;
145 batteryState_e batteryState = getBatteryState();
146 EXPECT_EQ(batteryAdcToBatteryStateExpectation->expectedBatteryState, batteryState);
150 typedef struct batteryAdcToCellCountExpectation_s
153 uint16_t expectedVoltageInDeciVoltSteps;
156 } batteryAdcToCellCountExpectation_t;
158 /* Test the cell count is correctly detected if we start at 0V */
159 TEST(BatteryTest, CellCount)
161 // batteryInit() reads a bunch of fields including vbatscale, so set up the config with useful initial values:
162 batteryConfig_t batteryConfig = {
163 .vbatscale = VBAT_SCALE_DEFAULT,
164 .vbatresdivval = VBAT_RESDIVVAL_DEFAULT,
165 .vbatresdivmultiplier = VBAT_RESDIVMULTIPLIER_DEFAULT,
166 .vbatmaxcellvoltage = 43,
167 .vbatmincellvoltage = 33,
168 .vbatwarningcellvoltage = 35,
169 .currentMeterScale = 400,
170 .currentMeterOffset = 0,
171 .currentMeterType = CURRENT_SENSOR_NONE,
172 .multiwiiCurrentMeterOutput = 0,
173 .batteryCapacity = 2200,
176 batteryInit(&batteryConfig);
178 batteryAdcToCellCountExpectation_t batteryAdcToCellCountExpectations[] = {
179 {0, 0, ELEVEN_TO_ONE_VOLTAGE_DIVIDER, 1},
180 {1420, 126, ELEVEN_TO_ONE_VOLTAGE_DIVIDER, 3},
182 uint8_t testIterationCount = sizeof(batteryAdcToCellCountExpectations) / sizeof(batteryAdcToCellCountExpectation_t);
185 for (uint8_t index = 0; index < testIterationCount; index ++) {
186 batteryAdcToCellCountExpectation_t *batteryAdcToCellCountExpectation = &batteryAdcToCellCountExpectations[index];
187 batteryConfig.vbatscale = batteryAdcToCellCountExpectation->scale;
188 currentADCReading = batteryAdcToCellCountExpectation->adcReading;
190 EXPECT_EQ(batteryAdcToCellCountExpectation->cellCount, batteryCellCount);
194 //#define DEBUG_ROLLOVER_PATTERNS
196 * 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.
198 * The 'signed diff timing' pattern is followed in a few places in the production codebase.
200 TEST(BatteryTest, RollOverPattern1)
203 uint16_t servicedAt = 0;
204 uint16_t serviceInterval = 5000;
205 int serviceCount = 0;
206 int rolloverCount = 0;
208 while(rolloverCount < 3) {
210 int16_t diff = (now - servicedAt);
211 if (diff >= serviceInterval) {
213 if (now < servicedAt) {
218 #ifdef DEBUG_ROLLOVER_PATTERNS
219 printf("servicedAt: %d, diff: %d\n", servicedAt, diff);
224 EXPECT_GE(diff, serviceInterval); // service interval must have passed
225 EXPECT_LT(diff, serviceInterval + 95 + 10); // but never more than the service interval + ticks + jitter
228 now += 95 + (rand() % 10); // simulate 100 ticks +/- 5 ticks of jitter, this can rollover
230 EXPECT_GT(serviceCount, 0);
233 TEST(BatteryTest, RollOverPattern2)
236 uint16_t serviceAt = 0;
237 uint16_t serviceInterval = 5000;
238 int serviceCount = 0;
239 int rolloverCount = 0;
241 while(rolloverCount < 3) {
243 int16_t diff = (now - serviceAt);
246 if (now < serviceAt) {
250 serviceAt = now + serviceInterval; // this can rollover
251 #ifdef DEBUG_ROLLOVER_PATTERNS
252 printf("servicedAt: %d, nextServiceAt: %d, diff: %d\n", now, serviceAt, diff);
258 EXPECT_LE(diff, serviceInterval);
259 EXPECT_LT(diff, 95 + 10); // never more than the ticks + jitter
262 now += 95 + (rand() % 10); // simulate 100 ticks +/- 5 ticks of jitter, this can rollover
264 EXPECT_GT(serviceCount, 0);
272 uint8_t armingFlags = 0;
273 float rcCommand[4] = {0,0,0,0};
276 bool featureIsEnabled(uint32_t mask)
282 throttleStatus_e calculateThrottleStatus(rxConfig_t *rxConfig, uint16_t deadband3d_throttle)
285 UNUSED(deadband3d_throttle);
286 return THROTTLE_HIGH;
289 uint16_t adcGetChannel(uint8_t channel)
292 return currentADCReading;
295 void delay(uint32_t ms)
301 int32_t lowpassFixed(lowpass_t *filter, int32_t in, int16_t freq)
308 void beeper(beeperMode_e mode)