1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-19 14:25:20 +03:00

Update LED strip code to allow configurable LED strips.

See documentation for details.
This commit is contained in:
Dominic Clifton 2014-09-14 21:40:20 +01:00
parent 3ef769bf7b
commit 6ce5736990
17 changed files with 983 additions and 236 deletions

View file

@ -33,7 +33,13 @@ CXXFLAGS += -g -Wall -Wextra -pthread -ggdb -O0
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
TESTS = battery_unittest flight_imu_unittest gps_conversion_unittest telemetry_hott_unittest rc_controls_unittest
TESTS = \
battery_unittest \
flight_imu_unittest \
gps_conversion_unittest \
telemetry_hott_unittest \
rc_controls_unittest \
ledstrip_unittest
# All Google Test headers. Usually you shouldn't change this
# definition.
@ -153,3 +159,16 @@ rc_controls_unittest :$(OBJECT_DIR)/io/rc_controls.o $(OBJECT_DIR)/rc_controls_u
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $(OBJECT_DIR)/$@
$(OBJECT_DIR)/io/ledstrip.o : $(USER_DIR)/io/ledstrip.c $(USER_DIR)/io/ledstrip.h $(GTEST_HEADERS)
@mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(TEST_CFLAGS) -c $(USER_DIR)/io/ledstrip.c -o $@
$(OBJECT_DIR)/ledstrip_unittest.o : $(TEST_DIR)/ledstrip_unittest.cc \
$(USER_DIR)/io/ledstrip.h $(GTEST_HEADERS)
@mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(TEST_CFLAGS) -c $(TEST_DIR)/ledstrip_unittest.cc -o $@
ledstrip_unittest :$(OBJECT_DIR)/io/ledstrip.o $(OBJECT_DIR)/ledstrip_unittest.o $(OBJECT_DIR)/gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $(OBJECT_DIR)/$@

View file

@ -0,0 +1,322 @@
/*
* This file is part of Cleanflight.
*
* Cleanflight is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cleanflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <limits.h>
#include "common/axis.h"
#include "flight/flight.h"
#include "sensors/battery.h"
#include "config/runtime_config.h"
#include "config/config.h"
#include "drivers/light_ws2811strip.h"
#include "io/ledstrip.h"
#include "unittest_macros.h"
#include "gtest/gtest.h"
extern ledConfig_t *ledConfigs;
extern uint8_t highestYValueForNorth;
extern uint8_t lowestYValueForSouth;
extern uint8_t highestXValueForWest;
extern uint8_t lowestXValueForEast;
extern uint8_t ledGridWidth;
extern uint8_t ledGridHeight;
void determineLedStripDimensions(void);
void determineOrientationLimits(void);
ledConfig_t systemLedConfigs[MAX_LED_STRIP_LENGTH];
TEST(LedStripTest, parseLedStripConfig)
{
/*
* 0..5 - rear right cluster, 0..2 rear 3..5 right
* 6..11 - front right cluster, 6..8 rear, 9..11 front
* 12..15 - front center cluster
* 16..21 - front left cluster, 16..18 front, 19..21 rear
* 22..27 - rear left cluster, 22..24 left, 25..27 rear
*/
// given
static const ledConfig_t expectedLedStripConfig[WS2811_LED_STRIP_LENGTH] = {
{ CALCULATE_LED_XY( 9, 9), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY(10, 10), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY(11, 11), LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY(11, 11), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY(10, 10), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 9, 9), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY(10, 5), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY(11, 4), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY(12, 3), LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY(12, 2), LED_DIRECTION_NORTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY(11, 1), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY(10, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 7, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 6, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 5, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 4, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 2, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 2), LED_DIRECTION_NORTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 3), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 4), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 2, 5), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 2, 9), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 1, 10), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 11), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 11), LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 10), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 2, 9), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
};
// and
const char *ledStripConfigCommands[] = {
// Spider quad
// right rear cluster
"9,9:S:FB",
"10,10:S:FB",
"11,11:S:IA",
"11,11:E:IA",
"10,10:E:F",
"9,9:E:F",
// right front cluster
"10,5:S:F",
"11,4:S:F",
"12,3:S:IA",
"12,2:N:IA",
"11,1:N:F",
"10,0:N:F",
// center front cluster
"7,0:N:FB",
"6,0:N:FB",
"5,0:N:FB",
"4,0:N:FB",
// left front cluster
"2,0:N:F",
"1,1:N:F",
"0,2:N:IA",
"0,3:W:IA",
"1,4:W:F",
"2,5:W:F",
// left rear cluster
"2,9:W:F",
"1,10:W:F",
"0,11:W:IA",
"0,11:S:IA",
"1,10:S:FB",
"2,9:S:FB"
};
// and
memset(&systemLedConfigs, 0, sizeof(systemLedConfigs));
ledConfigs = systemLedConfigs;
// and
bool ok = false;
// when
for (uint8_t index = 0; index < (sizeof(ledStripConfigCommands) / sizeof(ledStripConfigCommands[0])); index++) {
ok |= parseLedStripConfig(index, ledStripConfigCommands[index]);
}
// then
EXPECT_EQ(true, ok);
EXPECT_EQ(28, ledCount);
// and
for (uint8_t index = 0; index < WS2811_LED_STRIP_LENGTH; index++) {
printf("iteration: %d\n", index);
EXPECT_EQ(expectedLedStripConfig[index].xy, ledConfigs[index].xy);
EXPECT_EQ(expectedLedStripConfig[index].flags, ledConfigs[index].flags);
}
// then
EXPECT_EQ(13, ledGridWidth);
EXPECT_EQ(12, ledGridHeight);
// then
EXPECT_EQ(5, highestXValueForWest);
EXPECT_EQ(7, lowestXValueForEast);
EXPECT_EQ(5, highestYValueForNorth);
EXPECT_EQ(6, lowestYValueForSouth);
}
TEST(LedStripTest, smallestGridWithCenter)
{
// given
memset(&systemLedConfigs, 0, sizeof(systemLedConfigs));
ledConfigs = systemLedConfigs;
// and
static const ledConfig_t testLedConfigs[] = {
{ CALCULATE_LED_XY( 2, 2), LED_DIRECTION_SOUTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 2, 1), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 2, 0), LED_DIRECTION_NORTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 0, 0), LED_DIRECTION_NORTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 1), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 0, 2), LED_DIRECTION_SOUTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 2), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }
};
memcpy(&systemLedConfigs, &testLedConfigs, sizeof(testLedConfigs));
// when
determineLedStripDimensions();
// then
EXPECT_EQ(3, ledGridWidth);
EXPECT_EQ(3, ledGridHeight);
// when
determineOrientationLimits();
// then
EXPECT_EQ(0, highestXValueForWest);
EXPECT_EQ(2, lowestXValueForEast);
EXPECT_EQ(0, highestYValueForNorth);
EXPECT_EQ(2, lowestYValueForSouth);
}
TEST(LedStripTest, smallestGrid)
{
// given
memset(&systemLedConfigs, 0, sizeof(systemLedConfigs));
ledConfigs = systemLedConfigs;
// and
static const ledConfig_t testLedConfigs[] = {
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_SOUTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 1, 0), LED_DIRECTION_NORTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 0), LED_DIRECTION_NORTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 1), LED_DIRECTION_SOUTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
};
memcpy(&systemLedConfigs, &testLedConfigs, sizeof(testLedConfigs));
// when
determineLedStripDimensions();
// then
EXPECT_EQ(2, ledGridWidth);
EXPECT_EQ(2, ledGridHeight);
// when
determineOrientationLimits();
// then
EXPECT_EQ(0, highestXValueForWest);
EXPECT_EQ(1, lowestXValueForEast);
EXPECT_EQ(0, highestYValueForNorth);
EXPECT_EQ(1, lowestYValueForSouth);
}
/*
{ CALCULATE_LED_XY( 1, 14), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 13), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 12), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 11), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 10), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 9), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 8), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 0, 7), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 0, 6), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 0, 5), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 4), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 3), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 2), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 1), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 2, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 3, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 4, 1), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 4, 2), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 4, 3), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 4), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 5), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 6), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 4, 7), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 4, 8), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 4, 9), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 10), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 11), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 12), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 4, 13), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 3, 14), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
*/
uint8_t armingFlags = 0;
uint16_t flightModeFlags = 0;
int16_t rcCommand[4];
void ws2811UpdateStrip(void) {}
void setLedColor(uint16_t index, const rgbColor24bpp_t *color) {
UNUSED(index);
UNUSED(color);
}
void setLedBrightness(uint16_t index, const uint8_t scalePercent) {
UNUSED(index);
UNUSED(scalePercent);
}
void setStripColor(const rgbColor24bpp_t *color) {
UNUSED(color);
}
void setStripColors(const rgbColor24bpp_t *colors) {
UNUSED(colors);
}
bool isWS2811LedStripReady(void) { return false; }
void delay(uint32_t ms)
{
UNUSED(ms);
return;
}
uint32_t micros(void) { return 0; }
bool shouldSoundBatteryAlarm(void) { return false; }
bool feature(uint32_t mask) {
UNUSED(mask);
return false;
}
void tfp_sprintf(char *, char*, ...) { };

View file

@ -20,6 +20,7 @@
#define BARO
#define GPS
#define TELEMETRY
#define LED_STRIP
#define SERIAL_PORT_COUNT 4