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/>.
22 //#define DEBUG_LEDSTRIP
25 #include "build_config.h"
27 #include "common/color.h"
28 #include "common/axis.h"
29 #include "common/utils.h"
31 #include "sensors/battery.h"
32 #include "config/runtime_config.h"
33 #include "config/config.h"
37 #include "io/rc_controls.h"
39 #include "drivers/light_ws2811strip.h"
40 #include "io/ledstrip.h"
43 #include "unittest_macros.h"
44 #include "gtest/gtest.h"
47 extern uint8_t highestYValueForNorth;
48 extern uint8_t lowestYValueForSouth;
49 extern uint8_t highestXValueForWest;
50 extern uint8_t lowestXValueForEast;
51 extern uint8_t ledGridWidth;
52 extern uint8_t ledGridHeight;
53 extern ledCounts_t ledCounts;
55 void updateLedCount(void);
56 void determineLedStripDimensions(void);
57 void determineOrientationLimits(void);
61 #define LF(name) LED_FUNCTION_ ## name
62 #define LO(name) LED_FLAG_OVERLAY(LED_OVERLAY_ ## name)
63 #define LD(name) LED_FLAG_DIRECTION(LED_DIRECTION_ ## name)
65 TEST(LedStripTest, parseLedStripConfig)
68 static const ledConfig_t expectedLedStripConfig[WS2811_LED_STRIP_LENGTH] = {
69 DEFINE_LED( 9, 9, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
70 DEFINE_LED(10, 10, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
71 DEFINE_LED(11, 11, 0, LD(SOUTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
72 DEFINE_LED(11, 11, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0),
73 DEFINE_LED(10, 10, 0, LD(EAST) , LF(FLIGHT_MODE) , 0, 0),
75 DEFINE_LED(10, 5, 0, LD(SOUTH) , LF(FLIGHT_MODE) , 0, 0),
76 DEFINE_LED(11, 4, 0, LD(SOUTH) , LF(FLIGHT_MODE) , 0, 0),
77 DEFINE_LED(12, 3, 0, LD(SOUTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
78 DEFINE_LED(12, 2, 0, LD(NORTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
79 DEFINE_LED(11, 1, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0, 0),
80 DEFINE_LED(10, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0, 0),
82 DEFINE_LED( 7, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
83 DEFINE_LED( 6, 0, 1, LD(NORTH) , LF(COLOR) , LO(WARNING) , 0),
84 DEFINE_LED( 5, 0, 1, LD(NORTH) , LF(COLOR) , LO(WARNING) , 0),
85 DEFINE_LED( 4, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
87 DEFINE_LED( 2, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0, 0),
88 DEFINE_LED( 1, 1, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0, 0),
89 DEFINE_LED( 0, 2, 0, LD(NORTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
90 DEFINE_LED( 0, 3, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0),
91 DEFINE_LED( 1, 4, 0, LD(WEST) , LF(FLIGHT_MODE) , 0, 0),
92 DEFINE_LED( 2, 5, 0, LD(WEST) , LF(FLIGHT_MODE) , 0, 0),
94 DEFINE_LED( 1, 10, 0, LD(WEST) , LF(FLIGHT_MODE) , 0, 0),
95 DEFINE_LED( 0, 11, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0),
96 DEFINE_LED( 0, 11, 0, LD(SOUTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
97 DEFINE_LED( 1, 10, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
98 DEFINE_LED( 2, 9, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
100 DEFINE_LED( 7, 7, 14, 0, LF(THRUST_RING) , 0 , 0),
101 DEFINE_LED( 8, 7, 15, 0, LF(THRUST_RING) , 0 , 0),
102 DEFINE_LED( 8, 8, 14, 0, LF(THRUST_RING) , 0 , 0),
103 DEFINE_LED( 7, 8, 15, 0, LF(THRUST_RING) , 0 , 0),
105 DEFINE_LED( 0, 0, 0, 0 , 0 , 0 , 0),
106 DEFINE_LED( 0, 0, 0, 0 , 0 , 0 , 0),
110 const char *ledStripConfigCommands[] = {
113 // right rear cluster
120 // right front cluster
128 // center front cluster
134 // left front cluster
156 memset(ledConfigs_arr(), 0, sizeof(*ledConfigs_arr()));
162 for (unsigned index = 0; index < ARRAYLEN(ledStripConfigCommands); index++) {
163 result = result && parseLedStripConfig(index, ledStripConfigCommands[index]);
167 EXPECT_EQ(true, result);
168 EXPECT_EQ(30, ledCounts.count);
169 EXPECT_EQ(4, ledCounts.ring);
173 for (int index = 0; index < WS2811_LED_STRIP_LENGTH; index++) {
174 #ifdef DEBUG_LEDSTRIP
175 printf("iteration: %d\n", index);
177 EXPECT_EQ(ledGetXY(&expectedLedStripConfig[index]), ledGetXY(ledConfigs(index)));
178 EXPECT_EQ(ledGetFunction(&expectedLedStripConfig[index]), ledGetFunction(ledConfigs(index)));
179 EXPECT_EQ(ledGetOverlay(&expectedLedStripConfig[index]), ledGetOverlay(ledConfigs(index)));
180 EXPECT_EQ(ledGetColor(&expectedLedStripConfig[index]), ledGetColor(ledConfigs(index)));
181 EXPECT_EQ(ledGetDirection(&expectedLedStripConfig[index]), ledGetDirection(ledConfigs(index)));
182 EXPECT_EQ(ledGetParams(&expectedLedStripConfig[index]), ledGetParams(ledConfigs(index)));
186 EXPECT_EQ(13, ledGridWidth);
187 EXPECT_EQ(12, ledGridHeight);
190 EXPECT_EQ(5, highestXValueForWest);
191 EXPECT_EQ(7, lowestXValueForEast);
192 EXPECT_EQ(5, highestYValueForNorth);
193 EXPECT_EQ(6, lowestYValueForSouth);
196 TEST(LedStripTest, smallestGridWithCenter)
199 memset(ledConfigs_arr(), 0, sizeof(*ledConfigs_arr()));
202 static const ledConfig_t testLedConfigs[] = {
203 DEFINE_LED( 2, 2, 0, LD(SOUTH) | LD(EAST) , LF(ARM_STATE) , LO(INDICATOR), 0),
204 DEFINE_LED( 2, 1, 0, LD(EAST) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
205 DEFINE_LED( 2, 0, 0, LD(NORTH) | LD(EAST) , LF(ARM_STATE) , LO(INDICATOR), 0),
206 DEFINE_LED( 1, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
207 DEFINE_LED( 0, 0, 0, LD(NORTH) | LD(WEST) , LF(ARM_STATE) , LO(INDICATOR), 0),
208 DEFINE_LED( 0, 1, 0, LD(WEST) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
209 DEFINE_LED( 0, 2, 0, LD(SOUTH) | LD(WEST) , LF(ARM_STATE) , LO(INDICATOR), 0),
210 DEFINE_LED( 1, 2, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
212 memcpy(ledConfigs_arr(), &testLedConfigs, sizeof(testLedConfigs));
216 determineLedStripDimensions();
219 EXPECT_EQ(8, ledCounts.count);
220 EXPECT_EQ(3, ledGridWidth);
221 EXPECT_EQ(3, ledGridHeight);
224 determineOrientationLimits();
227 EXPECT_EQ(0, highestXValueForWest);
228 EXPECT_EQ(2, lowestXValueForEast);
229 EXPECT_EQ(0, highestYValueForNorth);
230 EXPECT_EQ(2, lowestYValueForSouth);
233 TEST(LedStripTest, smallestGrid)
236 memset(ledConfigs_arr(), 0, sizeof(*ledConfigs_arr()));
239 static const ledConfig_t testLedConfigs[] = {
240 DEFINE_LED( 1, 1, 0, LD(SOUTH) | LD(EAST) , LF(FLIGHT_MODE) , LO(INDICATOR), 0),
241 DEFINE_LED( 1, 0, 0, LD(NORTH) | LD(EAST) , LF(FLIGHT_MODE) , LO(INDICATOR), 0),
242 DEFINE_LED( 0, 0, 0, LD(NORTH) | LD(WEST) , LF(FLIGHT_MODE) , LO(INDICATOR), 0),
243 DEFINE_LED( 0, 1, 0, LD(SOUTH) | LD(WEST) , LF(FLIGHT_MODE) , LO(INDICATOR), 0),
245 memcpy(ledConfigs_arr(), &testLedConfigs, sizeof(testLedConfigs));
249 determineLedStripDimensions();
252 EXPECT_EQ(4, ledCounts.count);
253 EXPECT_EQ(2, ledGridWidth);
254 EXPECT_EQ(2, ledGridHeight);
257 determineOrientationLimits();
260 EXPECT_EQ(0, highestXValueForWest);
261 EXPECT_EQ(1, lowestXValueForEast);
262 EXPECT_EQ(0, highestYValueForNorth);
263 EXPECT_EQ(1, lowestYValueForSouth);
267 LED( 1, 14, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(INDICATOR) , 0 ),
269 LED( 0, 13, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
270 LED( 0, 12, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
272 LED( 0, 11, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
273 LED( 0, 10, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
274 LED( 0, 9, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
275 LED( 0, 8, 0, LD(WEST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
276 LED( 0, 7, 0, LD(WEST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
277 LED( 0, 6, 0, LD(WEST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
278 LED( 0, 5, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
279 LED( 0, 4, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
280 LED( 0, 3, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
282 LED( 0, 2, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
283 LED( 0, 1, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
285 LED( 1, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(INDICATOR) , 0 ),
286 LED( 2, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0 , 0 ),
287 LED( 3, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(INDICATOR) , 0 ),
289 LED( 4, 1, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
290 LED( 4, 2, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
292 LED( 4, 3, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
293 LED( 4, 4, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
294 LED( 4, 5, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
295 LED( 4, 6, 0, LD(EAST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
296 LED( 4, 7, 0, LD(EAST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
297 LED( 4, 8, 0, LD(EAST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
298 LED( 4, 9, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
299 LED( 4, 10, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
300 LED( 4, 11, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
302 LED( 4, 12, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
303 LED( 4, 13, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
305 LED( 3, 14, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(INDICATOR) , 0 ),
309 hsvColor_t testColors[LED_CONFIGURABLE_COLOR_COUNT];
311 #define TEST_COLOR_COUNT 4
313 TEST(ColorTest, parseColor)
316 memset(colors_arr(), 0, sizeof(*colors_arr()));
319 const hsvColor_t expectedColors[TEST_COLOR_COUNT] = {
327 const char *testColors[TEST_COLOR_COUNT] = {
335 for (int index = 0; index < TEST_COLOR_COUNT; index++) {
336 #ifdef DEBUG_LEDSTRIP
337 printf("parse iteration: %d\n", index);
340 parseColor(index, testColors[index]);
345 for (int index = 0; index < TEST_COLOR_COUNT; index++) {
346 #ifdef DEBUG_LEDSTRIP
347 printf("iteration: %d\n", index);
350 EXPECT_EQ(expectedColors[index].h, colors(index)->h);
351 EXPECT_EQ(expectedColors[index].s, colors(index)->s);
352 EXPECT_EQ(expectedColors[index].v, colors(index)->v);
358 uint8_t armingFlags = 0;
359 uint16_t flightModeFlags = 0;
360 int16_t rcCommand[4];
361 int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT];
362 uint32_t rcModeActivationMask;
364 batteryState_e getBatteryState(void) {
368 void ws2811LedStripInit(void) {}
369 void ws2811UpdateStrip(void) {}
371 void setLedValue(int index, const uint8_t value) {
376 void setLedHsv(int index, const hsvColor_t *color) {
381 void getLedHsv(int index, hsvColor_t *color) {
387 void scaleLedValue(int index, const uint8_t scalePercent) {
389 UNUSED(scalePercent);
392 void setStripColor(const hsvColor_t *color) {
396 void setStripColors(const hsvColor_t *colors) {
400 bool isWS2811LedStripReady(void) { return false; }
402 void delay(uint32_t ms)
408 uint32_t micros(void) { return 0; }
409 bool shouldSoundBatteryAlarm(void) { return false; }
410 bool feature(uint32_t mask) {
415 void tfp_sprintf(char *, char*, ...) { }
417 int scaleRange(int x, int srcMin, int srcMax, int destMin, int destMax) {
427 bool rcModeIsActive(boxId_e modeId) { return rcModeActivationMask & (1 << modeId); }
428 bool failsafeIsActive() { return false; }
429 bool rxIsReceivingSignal() { return true; }
430 bool sensors(uint32_t mask) { UNUSED(mask); return true; }
431 uint8_t calculateBatteryCapacityRemainingPercentage(void) { return 40; }