Skip to content

Commit 6363b65

Browse files
authored
NeoPixel Led support (#168)
* ws8212 led * led strip * log on button status led + set home * flashfs fix unfinished log
1 parent cd765d6 commit 6363b65

File tree

11 files changed

+175
-38
lines changed

11 files changed

+175
-38
lines changed

lib/Espfc/src/Blackbox/BlackboxFlashfs.cpp

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ const FlashfsRuntime * flashfsGetRuntime()
2020
return &flashfs;
2121
}
2222

23-
static uint32_t IRAM_ATTR flashfsJournalAddress(size_t index)
23+
static uint32_t IRAM_ATTR flashfsJournalAddress(size_t index, bool getEnd = false)
2424
{
25-
uint32_t base = reinterpret_cast<const esp_partition_t*>(flashfs.partition)->size - FLASHFS_JOURNAL_SIZE;
26-
return base + (index * sizeof(FlashfsJournalItem));
25+
uint32_t journalBase = reinterpret_cast<const esp_partition_t*>(flashfs.partition)->size - FLASHFS_JOURNAL_SIZE;
26+
return journalBase + (index * sizeof(FlashfsJournalItem)) + (getEnd * sizeof(uint32_t));
2727
}
2828

2929
void flashfsJournalLoad(FlashfsJournalItem * data, size_t start, size_t num)
@@ -32,22 +32,6 @@ void flashfsJournalLoad(FlashfsJournalItem * data, size_t start, size_t num)
3232
flashfsReadAbs(flashfsJournalAddress(start), (uint8_t*)data, size);
3333
}
3434

35-
static uint32_t flashfsLogLoad()
36-
{
37-
if(!flashfs.partition) return 0;
38-
39-
uint32_t address = 0;
40-
flashfsJournalLoad(flashfs.journal, 0, FLASHFS_JOURNAL_ITEMS);
41-
for(size_t i = 0; i < FLASHFS_JOURNAL_ITEMS; i++)
42-
{
43-
const auto& it = flashfs.journal[i];
44-
if(it.logEnd == FLASHFS_ERASED_VAL) break;
45-
address = it.logEnd;
46-
flashfs.journalIdx++;
47-
}
48-
return address;
49-
}
50-
5135
static void IRAM_ATTR flashfsLogBegin()
5236
{
5337
uint32_t beginAddr = flashfs.address;
@@ -78,19 +62,55 @@ static void IRAM_ATTR flashfsLogEnd()
7862

7963
if(!flashfs.partition) return;
8064

81-
size_t address = flashfsJournalAddress(idx) + sizeof(uint32_t);
65+
size_t address = flashfsJournalAddress(idx, true);
8266

8367
flashfsWriteAbs(address, (uint8_t*)&endAddr, sizeof(uint32_t));
8468
}
8569

70+
void flashfsJournalFix(FlashfsJournalItem * data, size_t num)
71+
{
72+
uint8_t buff[4];
73+
for(size_t i = 0; i < num; i++)
74+
{
75+
if(data[i].logBegin != FLASHFS_ERASED_VAL && data[i].logEnd == FLASHFS_ERASED_VAL)
76+
{
77+
uint32_t addr = data[i].logBegin;
78+
uint32_t end = flashfsGetSize();
79+
while(addr < end)
80+
{
81+
flashfsReadAbs(addr, buff, 4);
82+
if(*reinterpret_cast<uint32_t*>(&buff[0]) == FLASHFS_ERASED_VAL)
83+
{
84+
flashfs.address = addr;
85+
flashfsLogEnd();
86+
break;
87+
}
88+
addr += 128;
89+
}
90+
break;
91+
}
92+
}
93+
}
94+
8695
int flashfsInit(void)
8796
{
8897
flashfs.partition = Espfc::Device::FlashDevice::findPartition();
8998
if(!flashfs.partition) return 0;
9099

91100
flashfs.buffer = (void*)&buff;
92101
flashfs.journalIdx = 0;
93-
flashfs.address = flashfsLogLoad();
102+
flashfs.address = 0;
103+
104+
flashfsJournalLoad(flashfs.journal, 0, FLASHFS_JOURNAL_ITEMS);
105+
for(size_t i = 0; i < FLASHFS_JOURNAL_ITEMS; i++)
106+
{
107+
const auto& it = flashfs.journal[i];
108+
if(it.logEnd == FLASHFS_ERASED_VAL) break;
109+
flashfs.address = it.logEnd;
110+
flashfs.journalIdx++;
111+
}
112+
flashfsJournalFix(flashfs.journal, FLASHFS_JOURNAL_ITEMS);
113+
94114
return 1;
95115
}
96116

@@ -161,7 +181,7 @@ void IRAM_ATTR flashfsWriteAbs(uint32_t address, const uint8_t *data, unsigned i
161181
esp_partition_write_raw(p, address, data, len);
162182
}
163183

164-
int flashfsReadAbs(uint32_t address, uint8_t *data, unsigned int len)
184+
int IRAM_ATTR flashfsReadAbs(uint32_t address, uint8_t *data, unsigned int len)
165185
{
166186
if(!flashfs.partition) return 0;
167187

lib/Espfc/src/Connect/Cli.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ const Cli::Param * Cli::initialize(ModelConfig& c)
356356
static const char* currentSourceChoices[] = { PSTR("NONE"), PSTR("ADC"), NULL };
357357
static const char* blackboxDevChoices[] = { PSTR("NONE"), PSTR("FLASH"), PSTR("SD_CARD"), PSTR("SERIAL"), NULL };
358358
static const char* blackboxModeChoices[] = { PSTR("NORMAL"), PSTR("TEST"), PSTR("ALWAYS"), NULL };
359+
static const char* ledTypeChoices[] = { PSTR("SIMPLE"), PSTR("STRIP"), NULL };
359360

360361
size_t i = 0;
361362
static const Param params[] = {
@@ -677,6 +678,7 @@ const Cli::Param * Cli::initialize(ModelConfig& c)
677678
#endif
678679
Param(PSTR("pin_buzzer_invert"), &c.buzzer.inverted),
679680
Param(PSTR("pin_led_invert"), &c.led.invert),
681+
Param(PSTR("pin_led_type"), &c.led.type, ledTypeChoices),
680682

681683
#ifdef ESPFC_I2C_0
682684
Param(PSTR("i2c_speed"), &c.i2cSpeed),

lib/Espfc/src/Connect/StatusLed.cpp

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,97 @@
11
#include "StatusLed.hpp"
2+
#include "Target/Target.h"
23
#include <Arduino.h>
34

5+
#ifdef ESPFC_LED_WS2812
6+
#include "driver/i2s.h"
7+
8+
// https://docs.espressif.com/projects/esp-idf/en/v4.4.4/esp32/api-reference/peripherals/i2s.html
9+
// https://github.com/vunam/esp32-i2s-ws2812/blob/master/ws2812.c
10+
11+
static constexpr size_t LED_NUMBER = 1;
12+
static constexpr size_t PIXEL_SIZE = 12; // each colour takes 4 bytes in buffer
13+
static constexpr size_t ZERO_BUFFER = 32;
14+
static constexpr size_t SIZE_BUFFER = LED_NUMBER * PIXEL_SIZE + ZERO_BUFFER;
15+
static constexpr uint32_t SAMPLE_RATE = 93750;
16+
static constexpr i2s_port_t I2S_NUM = I2S_NUM_0;
17+
18+
typedef struct {
19+
uint8_t g;
20+
uint8_t r;
21+
uint8_t b;
22+
} ws2812_pixel_t;
23+
24+
static i2s_config_t i2s_config = {
25+
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
26+
.sample_rate = SAMPLE_RATE,
27+
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
28+
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
29+
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
30+
.intr_alloc_flags = 0,
31+
.dma_buf_count = 2,
32+
.dma_buf_len = SIZE_BUFFER / 2,
33+
.use_apll = false,
34+
.tx_desc_auto_clear = false,
35+
.fixed_mclk = 0,
36+
.mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT,
37+
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
38+
};
39+
40+
static i2s_pin_config_t pin_config = {
41+
.bck_io_num = -1,
42+
.ws_io_num = -1,
43+
.data_out_num = -1,
44+
.data_in_num = -1
45+
};
46+
47+
static uint8_t out_buffer[SIZE_BUFFER] = {0};
48+
49+
static const uint16_t bitpatterns[4] = {0x88, 0x8e, 0xe8, 0xee};
50+
51+
static void ws2812_init(int8_t pin)
52+
{
53+
pin_config.data_out_num = pin;
54+
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
55+
i2s_set_pin(I2S_NUM, &pin_config);
56+
i2s_zero_dma_buffer(I2S_NUM);
57+
std::fill_n(out_buffer, SIZE_BUFFER, 0);
58+
}
59+
60+
static void ws2812_write_pixel(uint8_t * buffer, const ws2812_pixel_t& pixel)
61+
{
62+
*buffer++ = bitpatterns[pixel.g >> 6 & 0x03];
63+
*buffer++ = bitpatterns[pixel.g >> 4 & 0x03];
64+
*buffer++ = bitpatterns[pixel.g >> 2 & 0x03];
65+
*buffer++ = bitpatterns[pixel.g >> 0 & 0x03];
66+
67+
*buffer++ = bitpatterns[pixel.r >> 6 & 0x03];
68+
*buffer++ = bitpatterns[pixel.r >> 4 & 0x03];
69+
*buffer++ = bitpatterns[pixel.r >> 2 & 0x03];
70+
*buffer++ = bitpatterns[pixel.r >> 0 & 0x03];
71+
72+
*buffer++ = bitpatterns[pixel.b >> 6 & 0x03];
73+
*buffer++ = bitpatterns[pixel.b >> 4 & 0x03];
74+
*buffer++ = bitpatterns[pixel.b >> 2 & 0x03];
75+
*buffer++ = bitpatterns[pixel.b >> 0 & 0x03];
76+
}
77+
78+
static void ws2812_update(const ws2812_pixel_t * pixels)
79+
{
80+
size_t bytes_written = 0;
81+
for (size_t i = 0; i < LED_NUMBER; i++)
82+
{
83+
size_t loc = i * PIXEL_SIZE;
84+
ws2812_write_pixel(out_buffer + loc, pixels[i]);
85+
}
86+
i2s_zero_dma_buffer(I2S_NUM);
87+
i2s_write(I2S_NUM, out_buffer, SIZE_BUFFER, &bytes_written, portMAX_DELAY);
88+
}
89+
90+
static const ws2812_pixel_t PIXEL_ON[] = {{0x40, 0x40, 0x80}};
91+
static const ws2812_pixel_t PIXEL_OFF[] = {{0, 0, 0}};
92+
93+
#endif
94+
495
namespace Espfc::Connect
596
{
697

@@ -11,12 +102,20 @@ static int LED_ON_PATTERN[] = {100, 0};
11102

12103
StatusLed::StatusLed() : _pin(-1), _invert(0), _status(LED_OFF), _next(0), _state(LOW), _step(0), _pattern(LED_OFF_PATTERN) {}
13104

14-
void StatusLed::begin(int8_t pin, uint8_t invert)
105+
void StatusLed::begin(int8_t pin, uint8_t type, uint8_t invert)
15106
{
16107
if(pin == -1) return;
108+
17109
_pin = pin;
110+
_type = type;
18111
_invert = invert;
112+
113+
#ifdef ESPFC_LED_WS2812
114+
if(_type == LED_STRIP) ws2812_init(_pin);
115+
if(_type == LED_SIMPLE) pinMode(_pin, OUTPUT);
116+
#else
19117
pinMode(_pin, OUTPUT);
118+
#endif
20119
setStatus(LED_ON, true);
21120
}
22121

@@ -74,7 +173,12 @@ void StatusLed::update()
74173

75174
void StatusLed::_write(uint8_t val)
76175
{
176+
#ifdef ESPFC_LED_WS2812
177+
if(_type == LED_STRIP) ws2812_update(val ? PIXEL_ON : PIXEL_OFF);
178+
if(_type == LED_SIMPLE) digitalWrite(_pin, val ^ _invert);
179+
#else
77180
digitalWrite(_pin, val ^ _invert);
181+
#endif
78182
}
79183

80184
}

lib/Espfc/src/Connect/StatusLed.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,34 @@
55
namespace Espfc::Connect
66
{
77

8+
enum LedType
9+
{
10+
LED_SIMPLE,
11+
LED_STRIP,
12+
};
13+
814
enum LedStatus
915
{
1016
LED_OFF,
1117
LED_OK,
1218
LED_ERROR,
13-
LED_ON
19+
LED_ON,
1420
};
1521

1622
class StatusLed
1723
{
1824

1925
public:
2026
StatusLed();
21-
void begin(int8_t pin, uint8_t invert);
27+
void begin(int8_t pin, uint8_t type, uint8_t invert);
2228
void update();
2329
void setStatus(LedStatus newStatus, bool force = false);
2430

2531
private:
2632
void _write(uint8_t val);
2733
int8_t _pin;
28-
int8_t _invert;
34+
uint8_t _type;
35+
uint8_t _invert;
2936
LedStatus _status;
3037
uint32_t _next;
3138
bool _state;

lib/Espfc/src/Control/Actuator.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,14 @@ void Actuator::updateRescueConfig()
260260

261261
void Actuator::updateLed()
262262
{
263-
if(_model.armingDisabled())
263+
if(_model.isModeActive(MODE_ARMED) || _model.state.mode.isLongClickActive())
264264
{
265-
_model.state.led.setStatus(Connect::LED_ERROR);
265+
if(_model.state.mode.isLongClickActive()) _model.setGpsHome();
266+
_model.state.led.setStatus(Connect::LED_ON);
266267
}
267-
else if(_model.isModeActive(MODE_ARMED) || _model.state.mode.isLongClickActive())
268+
else if(_model.armingDisabled())
268269
{
269-
_model.state.led.setStatus(Connect::LED_ON);
270+
_model.state.led.setStatus(Connect::LED_ERROR);
270271
}
271272
else
272273
{

lib/Espfc/src/Espfc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ int Espfc::load()
1919

2020
int Espfc::begin()
2121
{
22-
_model.state.led.begin(_model.config.pin[PIN_LED_BLINK], _model.config.led.invert);
22+
_model.state.led.begin(_model.config.pin[PIN_LED_BLINK], _model.config.led.type, _model.config.led.invert);
2323

2424
_serial.begin(); // requires _model.load()
2525
//_model.logStorageResult();

lib/Espfc/src/ModelConfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,7 @@ struct GpsConfig
668668
struct LedConfig
669669
{
670670
uint8_t invert = 0;
671+
int8_t type = 0;
671672
};
672673

673674
// persistent data

lib/Espfc/src/Target/TargetESP32s2.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
#define ESPFC_SERIAL_1
2525
#define ESPFC_SERIAL_1_DEV Serial1
2626
#define ESPFC_SERIAL_1_DEV_T HardwareSerial
27-
#define ESPFC_SERIAL_1_TX 16
28-
#define ESPFC_SERIAL_1_RX 15
27+
#define ESPFC_SERIAL_1_TX 17
28+
#define ESPFC_SERIAL_1_RX 16
2929
#define ESPFC_SERIAL_1_FN (SERIAL_FUNCTION_RX_SERIAL)
3030
#define ESPFC_SERIAL_1_BAUD (SERIAL_SPEED_115200)
3131
#define ESPFC_SERIAL_1_BBAUD (SERIAL_SPEED_NONE)
@@ -48,17 +48,17 @@
4848
#define ESPFC_SPI_0_MOSI 11
4949
#define ESPFC_SPI_0_MISO 13
5050

51-
#define ESPFC_SPI_CS_GYRO 8
51+
#define ESPFC_SPI_CS_GYRO 10
5252
#define ESPFC_SPI_CS_BARO 7
5353

5454
#define ESPFC_I2C_0
55-
#define ESPFC_I2C_0_SCL 10
56-
#define ESPFC_I2C_0_SDA 9
55+
#define ESPFC_I2C_0_SCL 9
56+
#define ESPFC_I2C_0_SDA 8
5757
#define ESPFC_I2C_0_SOFT
5858

5959
#define ESPFC_BUZZER_PIN 5
6060
#define ESPFC_BUTTON_PIN -1
61-
#define ESPFC_LED_PIN -1
61+
#define ESPFC_LED_PIN 15
6262

6363
#define ESPFC_ADC_0
6464
#define ESPFC_ADC_0_PIN 1

lib/Espfc/src/Target/TargetEsp32Common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#define ESPFC_WIFI
2222
#define ESPFC_ESPNOW
23+
#define ESPFC_LED_WS2812
2324

2425
namespace Espfc {
2526

lib/betaflight/src/platform.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ float motor_disarmed[MAX_SUPPORTED_MOTORS];
6262
uint32_t targetPidLooptime;
6363
float rcCommand[4];
6464

65-
int32_t GPS_home[2];
65+
int32_t GPS_home[2] = { 0, 0 };
6666
gpsSolutionData_t gpsSol;
6767

6868
const char* const lookupTableMixerType[] = {

0 commit comments

Comments
 (0)