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"
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 {
36 uint16_t expectedVoltageInDeciVoltSteps;
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,
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}
71 uint8_t testIterationCount = sizeof(batteryAdcToVoltageExpectations) / sizeof(batteryAdcToVoltageExpectation_t);
75 for (uint8_t index = 0; index < testIterationCount; index ++) {
76 batteryAdcToVoltageExpectation_t *batteryAdcToVoltageExpectation = &batteryAdcToVoltageExpectations[index];
77 batteryConfig.vbatscale = batteryAdcToVoltageExpectation->scale;
79 printf("adcReading: %d, vbatscale: %d\n",
80 batteryAdcToVoltageExpectation->adcReading,
81 batteryAdcToVoltageExpectation->scale
84 uint16_t pointOneVoltSteps = batteryAdcToVoltage(batteryAdcToVoltageExpectation->adcReading);
86 EXPECT_EQ(batteryAdcToVoltageExpectation->expectedVoltageInDeciVoltSteps, pointOneVoltSteps);
90 uint16_t currentADCReading;
93 typedef struct batteryAdcToBatteryStateExpectation_s
96 uint16_t expectedVoltageInDeciVoltSteps;
97 batteryState_e expectedBatteryState;
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,
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},
139 uint8_t testIterationCount = sizeof(batteryAdcToBatteryStateExpectations) / sizeof(batteryAdcToBatteryStateExpectation_t);
142 for (uint8_t index = 0; index < testIterationCount; index ++) {
143 batteryAdcToBatteryStateExpectation_t *batteryAdcToBatteryStateExpectation = &batteryAdcToBatteryStateExpectations[index];
144 batteryConfig.vbatscale = batteryAdcToBatteryStateExpectation->scale;
145 currentADCReading = batteryAdcToBatteryStateExpectation->adcReading;
147 batteryState_e batteryState = getBatteryState();
148 EXPECT_EQ(batteryAdcToBatteryStateExpectation->expectedBatteryState, batteryState);
152 typedef struct batteryAdcToCellCountExpectation_s
155 uint16_t expectedVoltageInDeciVoltSteps;
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,
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},
184 uint8_t testIterationCount = sizeof(batteryAdcToCellCountExpectations) / sizeof(batteryAdcToCellCountExpectation_t);
187 for (uint8_t index = 0; index < testIterationCount; index ++) {
188 batteryAdcToCellCountExpectation_t *batteryAdcToCellCountExpectation = &batteryAdcToCellCountExpectations[index];
189 batteryConfig.vbatscale = batteryAdcToCellCountExpectation->scale;
190 currentADCReading = batteryAdcToCellCountExpectation->adcReading;
192 EXPECT_EQ(batteryAdcToCellCountExpectation->cellCount, batteryCellCount);
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.
202 TEST(BatteryTest, RollOverPattern1)
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) {
220 #ifdef DEBUG_ROLLOVER_PATTERNS
221 printf("servicedAt: %d, diff: %d\n", servicedAt, diff);
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
230 now += 95 + (rand() % 10); // simulate 100 ticks +/- 5 ticks of jitter, this can rollover
232 EXPECT_GT(serviceCount, 0);
235 TEST(BatteryTest, RollOverPattern2)
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);
248 if (now < serviceAt) {
252 serviceAt = now + serviceInterval; // this can rollover
253 #ifdef DEBUG_ROLLOVER_PATTERNS
254 printf("servicedAt: %d, nextServiceAt: %d, diff: %d\n", now, serviceAt, diff);
260 EXPECT_LE(diff, serviceInterval);
261 EXPECT_LT(diff, 95 + 10); // never more than the ticks + jitter
264 now += 95 + (rand() % 10); // simulate 100 ticks +/- 5 ticks of jitter, this can rollover
266 EXPECT_GT(serviceCount, 0);
274 uint8_t armingFlags = 0;
275 int16_t rcCommand[4] = {0,0,0,0};
278 bool feature(uint32_t mask)
284 throttleStatus_e calculateThrottleStatus(rxConfig_t *rxConfig, uint16_t mid_throttle_deadband)
287 UNUSED(mid_throttle_deadband);
288 return THROTTLE_HIGH;
291 uint16_t adcGetChannel(uint8_t channel)
294 return currentADCReading;
297 void delay(uint32_t ms)
303 int32_t lowpassFixed(lowpass_t *filter, int32_t in, int16_t freq)
310 void beeper(beeperMode_e mode)