1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-14 14:33:07 +01:00

Delete FastLED and implement DMA to SPI for all RGB leds

This commit is contained in:
norbert-walter
2024-09-20 13:25:11 +02:00
parent 5a6801b2d8
commit f611cab14b
91 changed files with 29980 additions and 104 deletions

View File

@@ -0,0 +1,259 @@
uint8_t colorTo3Byte[256][3]=
{
{/*00*/0b10010010,0b01001001,0b00100100,},
{/*01*/0b10010010,0b01001001,0b00100110,},
{/*02*/0b10010010,0b01001001,0b00110100,},
{/*03*/0b10010010,0b01001001,0b00110110,},
{/*04*/0b10010010,0b01001001,0b10100100,},
{/*05*/0b10010010,0b01001001,0b10100110,},
{/*06*/0b10010010,0b01001001,0b10110100,},
{/*07*/0b10010010,0b01001001,0b10110110,},
{/*08*/0b10010010,0b01001101,0b00100100,},
{/*09*/0b10010010,0b01001101,0b00100110,},
{/*10*/0b10010010,0b01001101,0b00110100,},
{/*11*/0b10010010,0b01001101,0b00110110,},
{/*12*/0b10010010,0b01001101,0b10100100,},
{/*13*/0b10010010,0b01001101,0b10100110,},
{/*14*/0b10010010,0b01001101,0b10110100,},
{/*15*/0b10010010,0b01001101,0b10110110,},
{/*16*/0b10010010,0b01101001,0b00100100,},
{/*17*/0b10010010,0b01101001,0b00100110,},
{/*18*/0b10010010,0b01101001,0b00110100,},
{/*19*/0b10010010,0b01101001,0b00110110,},
{/*20*/0b10010010,0b01101001,0b10100100,},
{/*21*/0b10010010,0b01101001,0b10100110,},
{/*22*/0b10010010,0b01101001,0b10110100,},
{/*23*/0b10010010,0b01101001,0b10110110,},
{/*24*/0b10010010,0b01101101,0b00100100,},
{/*25*/0b10010010,0b01101101,0b00100110,},
{/*26*/0b10010010,0b01101101,0b00110100,},
{/*27*/0b10010010,0b01101101,0b00110110,},
{/*28*/0b10010010,0b01101101,0b10100100,},
{/*29*/0b10010010,0b01101101,0b10100110,},
{/*30*/0b10010010,0b01101101,0b10110100,},
{/*31*/0b10010010,0b01101101,0b10110110,},
{/*32*/0b10010011,0b01001001,0b00100100,},
{/*33*/0b10010011,0b01001001,0b00100110,},
{/*34*/0b10010011,0b01001001,0b00110100,},
{/*35*/0b10010011,0b01001001,0b00110110,},
{/*36*/0b10010011,0b01001001,0b10100100,},
{/*37*/0b10010011,0b01001001,0b10100110,},
{/*38*/0b10010011,0b01001001,0b10110100,},
{/*39*/0b10010011,0b01001001,0b10110110,},
{/*40*/0b10010011,0b01001101,0b00100100,},
{/*41*/0b10010011,0b01001101,0b00100110,},
{/*42*/0b10010011,0b01001101,0b00110100,},
{/*43*/0b10010011,0b01001101,0b00110110,},
{/*44*/0b10010011,0b01001101,0b10100100,},
{/*45*/0b10010011,0b01001101,0b10100110,},
{/*46*/0b10010011,0b01001101,0b10110100,},
{/*47*/0b10010011,0b01001101,0b10110110,},
{/*48*/0b10010011,0b01101001,0b00100100,},
{/*49*/0b10010011,0b01101001,0b00100110,},
{/*50*/0b10010011,0b01101001,0b00110100,},
{/*51*/0b10010011,0b01101001,0b00110110,},
{/*52*/0b10010011,0b01101001,0b10100100,},
{/*53*/0b10010011,0b01101001,0b10100110,},
{/*54*/0b10010011,0b01101001,0b10110100,},
{/*55*/0b10010011,0b01101001,0b10110110,},
{/*56*/0b10010011,0b01101101,0b00100100,},
{/*57*/0b10010011,0b01101101,0b00100110,},
{/*58*/0b10010011,0b01101101,0b00110100,},
{/*59*/0b10010011,0b01101101,0b00110110,},
{/*60*/0b10010011,0b01101101,0b10100100,},
{/*61*/0b10010011,0b01101101,0b10100110,},
{/*62*/0b10010011,0b01101101,0b10110100,},
{/*63*/0b10010011,0b01101101,0b10110110,},
{/*64*/0b10011010,0b01001001,0b00100100,},
{/*65*/0b10011010,0b01001001,0b00100110,},
{/*66*/0b10011010,0b01001001,0b00110100,},
{/*67*/0b10011010,0b01001001,0b00110110,},
{/*68*/0b10011010,0b01001001,0b10100100,},
{/*69*/0b10011010,0b01001001,0b10100110,},
{/*70*/0b10011010,0b01001001,0b10110100,},
{/*71*/0b10011010,0b01001001,0b10110110,},
{/*72*/0b10011010,0b01001101,0b00100100,},
{/*73*/0b10011010,0b01001101,0b00100110,},
{/*74*/0b10011010,0b01001101,0b00110100,},
{/*75*/0b10011010,0b01001101,0b00110110,},
{/*76*/0b10011010,0b01001101,0b10100100,},
{/*77*/0b10011010,0b01001101,0b10100110,},
{/*78*/0b10011010,0b01001101,0b10110100,},
{/*79*/0b10011010,0b01001101,0b10110110,},
{/*80*/0b10011010,0b01101001,0b00100100,},
{/*81*/0b10011010,0b01101001,0b00100110,},
{/*82*/0b10011010,0b01101001,0b00110100,},
{/*83*/0b10011010,0b01101001,0b00110110,},
{/*84*/0b10011010,0b01101001,0b10100100,},
{/*85*/0b10011010,0b01101001,0b10100110,},
{/*86*/0b10011010,0b01101001,0b10110100,},
{/*87*/0b10011010,0b01101001,0b10110110,},
{/*88*/0b10011010,0b01101101,0b00100100,},
{/*89*/0b10011010,0b01101101,0b00100110,},
{/*90*/0b10011010,0b01101101,0b00110100,},
{/*91*/0b10011010,0b01101101,0b00110110,},
{/*92*/0b10011010,0b01101101,0b10100100,},
{/*93*/0b10011010,0b01101101,0b10100110,},
{/*94*/0b10011010,0b01101101,0b10110100,},
{/*95*/0b10011010,0b01101101,0b10110110,},
{/*96*/0b10011011,0b01001001,0b00100100,},
{/*97*/0b10011011,0b01001001,0b00100110,},
{/*98*/0b10011011,0b01001001,0b00110100,},
{/*99*/0b10011011,0b01001001,0b00110110,},
{/*100*/0b10011011,0b01001001,0b10100100,},
{/*101*/0b10011011,0b01001001,0b10100110,},
{/*102*/0b10011011,0b01001001,0b10110100,},
{/*103*/0b10011011,0b01001001,0b10110110,},
{/*104*/0b10011011,0b01001101,0b00100100,},
{/*105*/0b10011011,0b01001101,0b00100110,},
{/*106*/0b10011011,0b01001101,0b00110100,},
{/*107*/0b10011011,0b01001101,0b00110110,},
{/*108*/0b10011011,0b01001101,0b10100100,},
{/*109*/0b10011011,0b01001101,0b10100110,},
{/*110*/0b10011011,0b01001101,0b10110100,},
{/*111*/0b10011011,0b01001101,0b10110110,},
{/*112*/0b10011011,0b01101001,0b00100100,},
{/*113*/0b10011011,0b01101001,0b00100110,},
{/*114*/0b10011011,0b01101001,0b00110100,},
{/*115*/0b10011011,0b01101001,0b00110110,},
{/*116*/0b10011011,0b01101001,0b10100100,},
{/*117*/0b10011011,0b01101001,0b10100110,},
{/*118*/0b10011011,0b01101001,0b10110100,},
{/*119*/0b10011011,0b01101001,0b10110110,},
{/*120*/0b10011011,0b01101101,0b00100100,},
{/*121*/0b10011011,0b01101101,0b00100110,},
{/*122*/0b10011011,0b01101101,0b00110100,},
{/*123*/0b10011011,0b01101101,0b00110110,},
{/*124*/0b10011011,0b01101101,0b10100100,},
{/*125*/0b10011011,0b01101101,0b10100110,},
{/*126*/0b10011011,0b01101101,0b10110100,},
{/*127*/0b10011011,0b01101101,0b10110110,},
{/*128*/0b11010010,0b01001001,0b00100100,},
{/*129*/0b11010010,0b01001001,0b00100110,},
{/*130*/0b11010010,0b01001001,0b00110100,},
{/*131*/0b11010010,0b01001001,0b00110110,},
{/*132*/0b11010010,0b01001001,0b10100100,},
{/*133*/0b11010010,0b01001001,0b10100110,},
{/*134*/0b11010010,0b01001001,0b10110100,},
{/*135*/0b11010010,0b01001001,0b10110110,},
{/*136*/0b11010010,0b01001101,0b00100100,},
{/*137*/0b11010010,0b01001101,0b00100110,},
{/*138*/0b11010010,0b01001101,0b00110100,},
{/*139*/0b11010010,0b01001101,0b00110110,},
{/*140*/0b11010010,0b01001101,0b10100100,},
{/*141*/0b11010010,0b01001101,0b10100110,},
{/*142*/0b11010010,0b01001101,0b10110100,},
{/*143*/0b11010010,0b01001101,0b10110110,},
{/*144*/0b11010010,0b01101001,0b00100100,},
{/*145*/0b11010010,0b01101001,0b00100110,},
{/*146*/0b11010010,0b01101001,0b00110100,},
{/*147*/0b11010010,0b01101001,0b00110110,},
{/*148*/0b11010010,0b01101001,0b10100100,},
{/*149*/0b11010010,0b01101001,0b10100110,},
{/*150*/0b11010010,0b01101001,0b10110100,},
{/*151*/0b11010010,0b01101001,0b10110110,},
{/*152*/0b11010010,0b01101101,0b00100100,},
{/*153*/0b11010010,0b01101101,0b00100110,},
{/*154*/0b11010010,0b01101101,0b00110100,},
{/*155*/0b11010010,0b01101101,0b00110110,},
{/*156*/0b11010010,0b01101101,0b10100100,},
{/*157*/0b11010010,0b01101101,0b10100110,},
{/*158*/0b11010010,0b01101101,0b10110100,},
{/*159*/0b11010010,0b01101101,0b10110110,},
{/*160*/0b11010011,0b01001001,0b00100100,},
{/*161*/0b11010011,0b01001001,0b00100110,},
{/*162*/0b11010011,0b01001001,0b00110100,},
{/*163*/0b11010011,0b01001001,0b00110110,},
{/*164*/0b11010011,0b01001001,0b10100100,},
{/*165*/0b11010011,0b01001001,0b10100110,},
{/*166*/0b11010011,0b01001001,0b10110100,},
{/*167*/0b11010011,0b01001001,0b10110110,},
{/*168*/0b11010011,0b01001101,0b00100100,},
{/*169*/0b11010011,0b01001101,0b00100110,},
{/*170*/0b11010011,0b01001101,0b00110100,},
{/*171*/0b11010011,0b01001101,0b00110110,},
{/*172*/0b11010011,0b01001101,0b10100100,},
{/*173*/0b11010011,0b01001101,0b10100110,},
{/*174*/0b11010011,0b01001101,0b10110100,},
{/*175*/0b11010011,0b01001101,0b10110110,},
{/*176*/0b11010011,0b01101001,0b00100100,},
{/*177*/0b11010011,0b01101001,0b00100110,},
{/*178*/0b11010011,0b01101001,0b00110100,},
{/*179*/0b11010011,0b01101001,0b00110110,},
{/*180*/0b11010011,0b01101001,0b10100100,},
{/*181*/0b11010011,0b01101001,0b10100110,},
{/*182*/0b11010011,0b01101001,0b10110100,},
{/*183*/0b11010011,0b01101001,0b10110110,},
{/*184*/0b11010011,0b01101101,0b00100100,},
{/*185*/0b11010011,0b01101101,0b00100110,},
{/*186*/0b11010011,0b01101101,0b00110100,},
{/*187*/0b11010011,0b01101101,0b00110110,},
{/*188*/0b11010011,0b01101101,0b10100100,},
{/*189*/0b11010011,0b01101101,0b10100110,},
{/*190*/0b11010011,0b01101101,0b10110100,},
{/*191*/0b11010011,0b01101101,0b10110110,},
{/*192*/0b11011010,0b01001001,0b00100100,},
{/*193*/0b11011010,0b01001001,0b00100110,},
{/*194*/0b11011010,0b01001001,0b00110100,},
{/*195*/0b11011010,0b01001001,0b00110110,},
{/*196*/0b11011010,0b01001001,0b10100100,},
{/*197*/0b11011010,0b01001001,0b10100110,},
{/*198*/0b11011010,0b01001001,0b10110100,},
{/*199*/0b11011010,0b01001001,0b10110110,},
{/*200*/0b11011010,0b01001101,0b00100100,},
{/*201*/0b11011010,0b01001101,0b00100110,},
{/*202*/0b11011010,0b01001101,0b00110100,},
{/*203*/0b11011010,0b01001101,0b00110110,},
{/*204*/0b11011010,0b01001101,0b10100100,},
{/*205*/0b11011010,0b01001101,0b10100110,},
{/*206*/0b11011010,0b01001101,0b10110100,},
{/*207*/0b11011010,0b01001101,0b10110110,},
{/*208*/0b11011010,0b01101001,0b00100100,},
{/*209*/0b11011010,0b01101001,0b00100110,},
{/*210*/0b11011010,0b01101001,0b00110100,},
{/*211*/0b11011010,0b01101001,0b00110110,},
{/*212*/0b11011010,0b01101001,0b10100100,},
{/*213*/0b11011010,0b01101001,0b10100110,},
{/*214*/0b11011010,0b01101001,0b10110100,},
{/*215*/0b11011010,0b01101001,0b10110110,},
{/*216*/0b11011010,0b01101101,0b00100100,},
{/*217*/0b11011010,0b01101101,0b00100110,},
{/*218*/0b11011010,0b01101101,0b00110100,},
{/*219*/0b11011010,0b01101101,0b00110110,},
{/*220*/0b11011010,0b01101101,0b10100100,},
{/*221*/0b11011010,0b01101101,0b10100110,},
{/*222*/0b11011010,0b01101101,0b10110100,},
{/*223*/0b11011010,0b01101101,0b10110110,},
{/*224*/0b11011011,0b01001001,0b00100100,},
{/*225*/0b11011011,0b01001001,0b00100110,},
{/*226*/0b11011011,0b01001001,0b00110100,},
{/*227*/0b11011011,0b01001001,0b00110110,},
{/*228*/0b11011011,0b01001001,0b10100100,},
{/*229*/0b11011011,0b01001001,0b10100110,},
{/*230*/0b11011011,0b01001001,0b10110100,},
{/*231*/0b11011011,0b01001001,0b10110110,},
{/*232*/0b11011011,0b01001101,0b00100100,},
{/*233*/0b11011011,0b01001101,0b00100110,},
{/*234*/0b11011011,0b01001101,0b00110100,},
{/*235*/0b11011011,0b01001101,0b00110110,},
{/*236*/0b11011011,0b01001101,0b10100100,},
{/*237*/0b11011011,0b01001101,0b10100110,},
{/*238*/0b11011011,0b01001101,0b10110100,},
{/*239*/0b11011011,0b01001101,0b10110110,},
{/*240*/0b11011011,0b01101001,0b00100100,},
{/*241*/0b11011011,0b01101001,0b00100110,},
{/*242*/0b11011011,0b01101001,0b00110100,},
{/*243*/0b11011011,0b01101001,0b00110110,},
{/*244*/0b11011011,0b01101001,0b10100100,},
{/*245*/0b11011011,0b01101001,0b10100110,},
{/*246*/0b11011011,0b01101001,0b10110100,},
{/*247*/0b11011011,0b01101001,0b10110110,},
{/*248*/0b11011011,0b01101101,0b00100100,},
{/*249*/0b11011011,0b01101101,0b00100110,},
{/*250*/0b11011011,0b01101101,0b00110100,},
{/*251*/0b11011011,0b01101101,0b00110110,},
{/*252*/0b11011011,0b01101101,0b10100100,},
{/*253*/0b11011011,0b01101101,0b10100110,},
{/*254*/0b11011011,0b01101101,0b10110100,},
{/*255*/0b11011011,0b01101101,0b10110110,}
};

View File

@@ -0,0 +1,232 @@
#include <FreeRTOS.h>
#include "LedSpiTask.h"
#include "GwHardware.h"
#include "GwApi.h"
#include <driver/spi_master.h>
#include <driver/gpio.h>
#include <esp_rom_gpio.h>
#include <soc/spi_periph.h>
#include "ColorTo3Byte.h"
/*
controlling some WS2812 using SPI
https://controllerstech.com/ws2812-leds-using-spi/
*/
static uint8_t mulcolor(uint8_t f1, uint8_t f2){
uint16_t rt=f1;
rt*=(uint16_t)f2;
return rt >> 8;
}
Color setBrightness(const Color &color,uint8_t brightness){
uint16_t br255=brightness*255;
br255=br255/100;
//very simple for now
Color rt=color;
rt.g=mulcolor(rt.g,br255);
rt.b=mulcolor(rt.b,br255);
rt.r=mulcolor(rt.r,br255);
return rt;
}
static void colorCompTo3Byte(uint8_t comp,uint8_t *buffer){
for (int i=0;i<3;i++){
*(buffer+i)=colorTo3Byte[comp][i];
}
}
//depending on LED strip - handle color order
static size_t ledsToBuffer(int numLeds,const Color *leds,uint8_t *buffer){
uint8_t *p=buffer;
for (int i=0;i<numLeds;i++){
colorCompTo3Byte(leds[i].g,p);
p+=3;
colorCompTo3Byte(leds[i].r,p);
p+=3;
colorCompTo3Byte(leds[i].b,p);
p+=3;
}
return p-buffer;
}
/**
* prepare a GPIO pin to be used as the data line for an led stripe
*/
bool prepareGpio(GwLog *logger, uint8_t pin){
esp_err_t err=gpio_set_direction((gpio_num_t)pin,GPIO_MODE_OUTPUT);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to set gpio mode for %d: %d",pin,(int)err);
return false;
}
err=gpio_set_level((gpio_num_t)pin,0);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to set gpio level for %d: %d",pin,(int)err);
return false;
}
return true;
}
/**
* initialize the SPI bus and add a device for the LED output
* it still does not attach any PINs to the bus
* this will be done later when sending out
* this way we can use one hardware SPI for multiple led stripes
* @param bus : the SPI bus
* @param device: <out> the device handle being filled
* @return false on error
*/
bool prepareSpi(GwLog *logger,spi_host_device_t bus,spi_device_handle_t *device){
spi_bus_config_t buscfg = {
.mosi_io_num = -1,
.miso_io_num = -1,
.sclk_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 0,
.flags=SPICOMMON_BUSFLAG_GPIO_PINS
};
esp_err_t err=spi_bus_initialize(bus,&buscfg,SPI_DMA_CH_AUTO);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to initialize SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err);
return false;
}
spi_device_interface_config_t devcfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = 0,
.duty_cycle_pos = 128,
.cs_ena_pretrans = 0,
.cs_ena_posttrans =0,
.clock_speed_hz = 2500000, //2.5 Mhz
.input_delay_ns =0,
.spics_io_num = -1, //CS pin
.queue_size = 1 //see https://github.com/espressif/esp-idf/issues/9450
};
err=spi_bus_add_device(bus,&devcfg,device);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to add device to SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err);
return false;
}
//slightly speed up the transactions
//as we are the only ones using the bus we can safely acquire it forever
err=spi_device_acquire_bus(*device,portMAX_DELAY);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to acquire SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err);
return false;
}
return true;
}
/**
* send out a set of Color values to a connected led stripe
* this method will block until sen dis complete
* But as the transfer is using DMA the CPU is not busy during the wait time
* @param pin: the IO pin to be used. Will be attached to the SPI device before and deattached after
* @param numLeds: the number of Color values
* @param leds: pointer to the first Color value
* @param bus: the SPI bus
* @param device: the SPI device handle
**/
bool sendToLeds(GwLog *logger, uint8_t pin, int numLeds, Color *leds, spi_host_device_t bus, spi_device_handle_t &device, uint8_t *buffer = NULL)
{
//need to send a long reset before
//as on S3 MOSI is high on idle on older frameworks
//see https://github.com/espressif/esp-idf/issues/13974
const int zeroprefix=80; //3.2us per byte
bool ownsBuffer = false;
size_t bufferSize = numLeds * 3 * 3+zeroprefix;
if (buffer == NULL)
{
ownsBuffer = true;
buffer = (uint8_t *)heap_caps_malloc(bufferSize, MALLOC_CAP_DMA|MALLOC_CAP_32BIT);
if (!buffer)
{
LOG_DEBUG(GwLog::ERROR, "unable to allocate %d bytes of DMA buffer", (int)bufferSize);
return false;
}
}
bool rv = true;
for (int i=0;i<zeroprefix;i++)buffer[i]=0;
ledsToBuffer(numLeds, leds, buffer+zeroprefix);
struct spi_transaction_t ta = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = bufferSize * 8,
.rxlength = 0,
.tx_buffer = buffer};
int64_t now = esp_timer_get_time();
esp_rom_gpio_connect_out_signal(pin, spi_periph_signal[bus].spid_out, false, false);
esp_err_t ret = spi_device_transmit(device, &ta);
esp_rom_gpio_connect_out_signal(pin, SIG_GPIO_OUT_IDX, false, false);
int64_t end = esp_timer_get_time();
if (ret != ESP_OK)
{
LOG_DEBUG(GwLog::ERROR, "unable to send led data: %d", (int)ret);
rv = false;
}
else
{
LOG_DEBUG(GwLog::DEBUG, "successfully send led data for %d leds, %lld us", numLeds, end - now);
}
if (ownsBuffer)
{
heap_caps_free(buffer);
}
return rv;
}
#define EXIT_TASK delay(50);vTaskDelete(NULL);return;
void handleSpiLeds(void *param){
LedTaskData *taskData=(LedTaskData*)param;
GwLog *logger=taskData->api->getLogger();
LOG_DEBUG(GwLog::ERROR,"spi led task initialized");
spi_host_device_t bus=SPI3_HOST;
bool spiValid=false;
LOG_DEBUG(GwLog::ERROR,"SpiLed task started");
if (! prepareGpio(logger,OBP_FLASH_LED)){
EXIT_TASK;
}
if (! prepareGpio(logger,OBP_BACKLIGHT_LED)){
EXIT_TASK;
}
spi_device_handle_t device;
if (! prepareSpi(logger,bus,&device)){
EXIT_TASK;
}
bool first=true;
LedInterface current;
while (true)
{
LedInterface newLeds=taskData->getLedData();
if (first || current.backlightChanged(newLeds) || current.flasChanged(newLeds)){
first=false;
LOG_DEBUG(GwLog::ERROR,"handle SPI leds");
if (current.backlightChanged(newLeds) || first){
LOG_DEBUG(GwLog::ERROR,"setting backlight r=%02d,g=%02d,b=%02d",
newLeds.backlight[0].r,newLeds.backlight[0].g,newLeds.backlight[0].b);
sendToLeds(logger,OBP_BACKLIGHT_LED,newLeds.backlightLen(),newLeds.backlight,bus,device);
}
if (current.flasChanged(newLeds) || first){
LOG_DEBUG(GwLog::ERROR,"setting flashr=%02d,g=%02d,b=%02d",
newLeds.flash[0].r,newLeds.flash[0].g,newLeds.flash[0].b);
sendToLeds(logger,OBP_FLASH_LED,newLeds.flashLen(),newLeds.flash,bus,device);
}
current=newLeds;
}
delay(50);
}
vTaskDelete(NULL);
}
void createSpiLedTask(LedTaskData *param){
xTaskCreate(handleSpiLeds,"handleLeds",4000,param,3,NULL);
}

View File

@@ -0,0 +1,96 @@
#ifndef _GWSPILEDS_H
#define _GWSPILEDS_H
#include "GwSynchronized.h"
#include "GwApi.h"
#include "OBP60Hardware.h"
class Color{
public:
uint8_t r;
uint8_t g;
uint8_t b;
Color():r(0),g(0),b(0){}
Color(uint8_t cr, uint8_t cg,uint8_t cb):
b(cb),g(cg),r(cr){}
Color(const Color &o):b(o.b),g(o.g),r(o.r){}
bool equal(const Color &o) const{
return o.r == r && o.g == g && o.b == b;
}
bool operator == (const Color &other) const{
return equal(other);
}
bool operator != (const Color &other) const{
return ! equal(other);
}
};
static Color COLOR_GREEN=Color(0,255,0);
static Color COLOR_RED=Color(255,0,0);
static Color COLOR_BLUE=Color(0,0,255);
static Color COLOR_WHITE=Color(255,255,255);
static Color COLOR_BLACK=Color(0,0,0);
Color setBrightness(const Color &color,uint8_t brightness);
class LedInterface {
private:
bool equals(const Color *v1, const Color *v2, int num) const{
for (int i=0;i<num;i++){
if (!v1->equal(*v2)) return false;
v1++;
v2++;
}
return true;
}
void set(Color *v,int len, const Color &c){
for (int i=0;i<len;i++){
*v=c;
v++;
}
}
public:
Color flash[NUM_FLASH_LED];
Color backlight[NUM_BACKLIGHT_LED];
int flashLen() const {return NUM_FLASH_LED;}
int backlightLen() const {return NUM_BACKLIGHT_LED;}
bool flasChanged(const LedInterface &other){
return ! equals(flash,other.flash,flashLen());
}
bool backlightChanged(const LedInterface &other){
return ! equals(backlight,other.backlight,backlightLen());
}
void setFlash(const Color &c){
set(flash,flashLen(),c);
}
void setBacklight(const Color &c){
set(backlight,backlightLen(),c);
}
};
class LedTaskData{
private:
SemaphoreHandle_t locker;
LedInterface leds;
long updateCount=0;
public:
GwApi *api=NULL;
LedTaskData(GwApi *api){
locker=xSemaphoreCreateMutex();
this->api=api;
}
void setLedData(const LedInterface &values){
GWSYNCHRONIZED(&locker);
leds=values;
}
LedInterface getLedData(){
GWSYNCHRONIZED(&locker);
return leds;
}
};
//task function
void createSpiLedTask(LedTaskData *param);
#endif

View File

@@ -4,7 +4,6 @@
#define FASTLED_ALL_PINS_HARDWARE_SPI
#define FASTLED_ESP32_SPI_BUS FSPI
#define FASTLED_ESP32_FLASH_LOCK 1
#include <FastLED.h> // Driver for WS2812 RGB LED
#include <PCF8574.h> // Driver for PCF8574 output modul from Horter
#include <Wire.h> // I2C
#include <RTClib.h> // Driver for DS1388 RTC
@@ -60,10 +59,6 @@ GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(){r
// Horter I2C moduls
PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter
// Define the array of leds
CRGB fled[NUM_FLASH_LED]; // Flash LED
CRGB backlight[NUM_BACKLIGHT_LED]; // Backlight
// Global vars
bool blinkingLED = false; // Enable / disable blinking flash LED
bool statusLED = false; // Actual status of flash LED on/off
@@ -71,20 +66,24 @@ bool statusBacklightLED = false;// Actual status of flash LED on/off
int uvDuration = 0; // Under voltage duration in n x 100ms
LedTaskData *ledTaskData=nullptr;
void hardwareInit()
{
// Init power rail 5.0V
setPortPin(OBP_POWER_50, true);
// Init RGB LEDs
FastLED.addLeds<WS2812B, OBP_FLASH_LED, GRB>(fled, NUM_FLASH_LED);
FastLED.addLeds<WS2812B, OBP_BACKLIGHT_LED, GRB>(backlight, NUM_BACKLIGHT_LED);
Wire.begin();
// Init PCF8574 digital outputs
Wire.setClock(I2C_SPEED); // Set I2C clock on 10 kHz
if(pcf8574_Out.begin()){ // Initialize PCF8574
Wire.setClock(I2C_SPEED); // Set I2C clock on 10 kHz
pcf8574_Out.write8(255); // Clear all outputs
}
}
void startLedTask(GwApi *api){
ledTaskData=new LedTaskData(api);
createSpiLedTask(ledTaskData);
}
void setPortPin(uint pin, bool value){
@@ -98,85 +97,48 @@ void togglePortPin(uint pin){
}
// Valid colors see hue
CHSV colorMapping(String colorString){
CHSV color = CHSV(HUE_RED, 255, 255);
if(colorString == "Red"){color = CHSV(HUE_RED, 255, 255);}
if(colorString == "Orange"){color = CHSV(HUE_ORANGE, 255, 255);}
if(colorString == "Yellow"){color = CHSV(HUE_YELLOW, 255, 255);}
if(colorString == "Green"){color = CHSV(HUE_GREEN, 255, 255);}
if(colorString == "Blue"){color = CHSV(HUE_BLUE, 255, 255);}
if(colorString == "Aqua"){color = CHSV(HUE_AQUA, 255, 255);}
if(colorString == "Violet"){color = CHSV(HUE_PURPLE, 255, 255);}
if(colorString == "White"){color = CHSV(HUE_AQUA, 0, 255);}
Color colorMapping(const String &colorString){
Color color = COLOR_RED;
if(colorString == "Orange"){color = Color(255,153,0);}
if(colorString == "Yellow"){color = Color(255,255,0);}
if(colorString == "Green"){color = COLOR_GREEN;}
if(colorString == "Blue"){color = COLOR_BLUE;}
if(colorString == "Aqua"){color = Color(51,102,255);}
if(colorString == "Violet"){color = Color(255,0,102);}
if(colorString == "White"){color = COLOR_WHITE;}
return color;
}
// All defined colors see pixeltypes.h in FastLED lib
void setBacklightLED(uint brightness, CHSV color){
static uint oldbrightness;
static CHSV oldcolor;
// If changed the values then set new values
if(brightness != oldbrightness || color != oldcolor){
FastLED.setBrightness(255); // Brightness for flash LED
color.value = brightness;
backlight[0] = color; // Backlight LEDs on with color
backlight[1] = color;
backlight[2] = color;
backlight[3] = color;
backlight[4] = color;
backlight[5] = color;
FastLED.show();
oldbrightness = brightness;
oldcolor = color;
}
void setBacklightLED(uint brightness, const Color &color){
if (ledTaskData == nullptr) return;
Color nv=setBrightness(color,brightness);
LedInterface current=ledTaskData->getLedData();
current.setBacklight(nv);
ledTaskData->setLedData(current);
}
void toggleBacklightLED(uint brightness, CHSV color){
void toggleBacklightLED(uint brightness, const Color &color){
if (ledTaskData == nullptr) return;
statusBacklightLED = !statusBacklightLED;
FastLED.setBrightness(255); // Brightness for flash LED
if(statusBacklightLED == true){
color.value = brightness;
backlight[0] = color; // Backlight LEDs on with color
backlight[1] = color;
backlight[2] = color;
backlight[3] = color;
backlight[4] = color;
backlight[5] = color;
}
else{
backlight[0] = CHSV(HUE_BLUE, 255, 0); // Backlight LEDs off (blue without britghness)
backlight[1] = CHSV(HUE_BLUE, 255, 0);
backlight[2] = CHSV(HUE_BLUE, 255, 0);
backlight[3] = CHSV(HUE_BLUE, 255, 0);
backlight[4] = CHSV(HUE_BLUE, 255, 0);
backlight[5] = CHSV(HUE_BLUE, 255, 0);
}
FastLED.show();
Color nv=setBrightness(statusBacklightLED?color:COLOR_BLACK,brightness);
LedInterface current=ledTaskData->getLedData();
current.setBacklight(nv);
ledTaskData->setLedData(current);
}
void setFlashLED(bool status){
static bool oldstatus;
if(status == true){
FastLED.setBrightness(255); // Brightness for flash LED
fled[0] = CRGB::Red; // Flash LED on in red
}
else{
fled[0] = CRGB::Black; // Flash LED off
}
FastLED.show();
if (ledTaskData == nullptr) return;
Color c=status?COLOR_RED:COLOR_BLACK;
LedInterface current=ledTaskData->getLedData();
current.setFlash(c);
ledTaskData->setLedData(current);
}
void blinkingFlashLED(){
if(blinkingLED == true){
statusLED = !statusLED; // Toggle LED for each run
if(statusLED == true){
FastLED.setBrightness(255); // Brightness for flash LED
fled[0] = CRGB::Red; // Flash LED on in red
}
else{
fled[0] = CRGB::Black; // Flash LED off
}
FastLED.show();
setFlashLED(statusLED);
}
}

View File

@@ -6,7 +6,7 @@
#define FASTLED_ALL_PINS_HARDWARE_SPI
#define FASTLED_ESP32_SPI_BUS FSPI
#define FASTLED_ESP32_FLASH_LOCK 1
#include <FastLED.h> // Driver for WS2812 RGB LED
#include "LedSpiTask.h"
#include <GxEPD2_BW.h> // E-paper lib V2
// Fonts declarations for display (#inclues see OBP60Extensions.cpp)
@@ -44,9 +44,9 @@ void setPortPin(uint pin, bool value); // Set port pin for extension po
void togglePortPin(uint pin); // Toggle extension port pin
CHSV colorMapping(String colorString); // Color mapping string to CHSV colors
void setBacklightLED(uint brightness, CHSV color);// Set backlight LEDs
void toggleBacklightLED(uint brightness, CHSV color);// Toggle backlight LEDs
Color colorMapping(const String &colorString); // Color mapping string to CHSV colors
void setBacklightLED(uint brightness, const Color &color);// Set backlight LEDs
void toggleBacklightLED(uint brightness,const Color &color);// Toggle backlight LEDs
void setFlashLED(bool status); // Set flash LED
void blinkingFlashLED(); // Blinking function for flash LED
@@ -67,5 +67,6 @@ SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude,
void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor); // Battery graphic with fill level
void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic with fill level
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level
void startLedTask(GwApi *api);
#endif

View File

@@ -72,7 +72,7 @@ void sensorTask(void *param){
// Direction settings for NMEA0183
String nmea0183Mode = api->getConfig()->getConfigItem(api->getConfig()->serialDirection, true)->asString();
api->getLogger()->logDebug(GwLog::LOG, "NMEA0183 Mode is: %s", nmea0183Mode);
api->getLogger()->logDebug(GwLog::LOG, "NMEA0183 Mode is: %s", nmea0183Mode.c_str());
pinMode(OBP_DIRECTION_PIN, OUTPUT);
if (String(nmea0183Mode) == "receive" || String(nmea0183Mode) == "off")
{

View File

@@ -85,7 +85,7 @@ public:
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageApparentWind, %s:%f, %s:%f", name1, value1, name2, value2);
LOG_DEBUG(GwLog::LOG,"Drawing at PageApparentWind, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************

View File

@@ -100,7 +100,7 @@ class PageBME280 : public Page
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageBME280, %s: %f, %s: %f, %s: %f", name1, value1, name2, value2, name3, value3);
LOG_DEBUG(GwLog::LOG,"Drawing at PageBME280, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3);
// Draw page
//***********************************************************

View File

@@ -148,7 +148,7 @@ class PageBattery : public Page
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery, %s: %f, %s: %f, %s: %f, Avg: %d", name1, value1, name2, value2, name3, value3, average);
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery, %s: %f, %s: %f, %s: %f, Avg: %d", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, average);
// Draw page
//***********************************************************

View File

@@ -173,7 +173,7 @@ public:
}
// Logging voltage value
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery2, Type:%s %s:=%f", batType, name1, raw);
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery2, Type:%s %s:=%f", batType.c_str(), name1.c_str(), raw);
// Draw page
//***********************************************************

View File

@@ -86,7 +86,7 @@ public:
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageClock, %s:%f, %s:%f", name1, value1, name2, value2);
LOG_DEBUG(GwLog::LOG,"Drawing at PageClock, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************

View File

@@ -86,7 +86,7 @@ class PageDST810 : public Page
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageDST810, %s: %f, %s: %f, %s: %f, %s: %f", name1, value1, name2, value2, name3, value3, name4, value4);
LOG_DEBUG(GwLog::LOG,"Drawing at PageDST810, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
// Draw page
//***********************************************************

View File

@@ -86,7 +86,7 @@ class PageFourValues : public Page
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageFourValues, %s: %f, %s: %f, %s: %f, %s: %f", name1, value1, name2, value2, name3, value3, name4, value4);
LOG_DEBUG(GwLog::LOG,"Drawing at PageFourValues, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
// Draw page
//***********************************************************

View File

@@ -86,7 +86,7 @@ class PageFourValues2 : public Page
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageFourValues2, %s: %f, %s: %f, %s: %f, %s: %f", name1, value1, name2, value2, name3, value3, name4, value4);
LOG_DEBUG(GwLog::LOG,"Drawing at PageFourValues2, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
// Draw page
//***********************************************************

View File

@@ -80,7 +80,7 @@ public:
}
// Logging voltage value
LOG_DEBUG(GwLog::LOG,"Drawing at PageGenerator, Type:%iW %s:=%f", genPower, name1, value1);
LOG_DEBUG(GwLog::LOG,"Drawing at PageGenerator, Type:%iW %s:=%f", genPower, name1.c_str(), value1);
// Draw page
//***********************************************************

View File

@@ -52,7 +52,7 @@ class PageOneValue : public Page{
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageOneValue, %s: %f", name1, value1);
LOG_DEBUG(GwLog::LOG,"Drawing at PageOneValue, %s: %f", name1.c_str(), value1);
// Draw page
//***********************************************************

View File

@@ -108,7 +108,7 @@ public:
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageRollPitch, %s:%f, %s:%f", name1, value1, name2, value2);
LOG_DEBUG(GwLog::LOG,"Drawing at PageRollPitch, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************

View File

@@ -69,7 +69,7 @@ public:
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageRudderPosition, %s:%f", name1, value1);
LOG_DEBUG(GwLog::LOG,"Drawing at PageRudderPosition, %s:%f", name1.c_str(), value1);
// Draw page
//***********************************************************

View File

@@ -80,7 +80,7 @@ public:
}
// Logging voltage value
LOG_DEBUG(GwLog::LOG,"Drawing at PageSolar, Type:%iW %s:=%f", solPower, name1, value1);
LOG_DEBUG(GwLog::LOG,"Drawing at PageSolar, Type:%iW %s:=%f", solPower, name1.c_str(), value1);
// Draw page
//***********************************************************

View File

@@ -75,7 +75,7 @@ class PageThreeValues : public Page
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageThreeValues, %s: %f, %s: %f, %s: %f", name1, value1, name2, value2, name3, value3);
LOG_DEBUG(GwLog::LOG,"Drawing at PageThreeValues, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3);
// Draw page
//***********************************************************

View File

@@ -64,7 +64,7 @@ class PageTwoValues : public Page
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageTwoValues, %s: %f, %s: %f", name1, value1, name2, value2);
LOG_DEBUG(GwLog::LOG,"Drawing at PageTwoValues, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************

View File

@@ -128,7 +128,7 @@ public:
// Logging voltage value
if (raw == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageVoltage, Type:%s %s:=%f", batType, name1, raw);
LOG_DEBUG(GwLog::LOG,"Drawing at PageVoltage, Type:%s %s:=%f", batType, name1.c_str(), raw);
// Draw page
//***********************************************************

View File

@@ -136,7 +136,7 @@ public:
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageWindRose, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f", name1, value1, name2, value2, name3, value3, name4, value4, name5, value5, name6, value6);
LOG_DEBUG(GwLog::LOG,"Drawing at PageWindRose, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4, name5.c_str(), value5, name6.c_str(), value6);
// Draw page
//***********************************************************

View File

@@ -23,6 +23,8 @@
#include "OBP60QRWiFi.h" // Functions lib for WiFi QR code
#include "OBPSensorTask.h" // Functions lib for sensor data
#include "LedSpiTask.h"
// Global vars
bool initComplete = false; // Initialization complete
int taskRunCounter = 0; // Task couter for loop section
@@ -67,10 +69,10 @@ void OBP60Init(GwApi *api){
setBacklightLED(brightness, colorMapping(backlightColor));
}
if(String(backlightMode) == "Off"){
setBacklightLED(0, CHSV(HUE_BLUE, 255, 0)); // Backlight LEDs off (blue without britghness)
setBacklightLED(0, COLOR_BLACK); // Backlight LEDs off (blue without britghness)
}
if(String(backlightMode) == "Control by Key"){
setBacklightLED(0, CHSV(HUE_BLUE, 255, 0)); // Backlight LEDs off (blue without britghness)
setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
}
// Settings flash LED mode
@@ -279,6 +281,7 @@ void underVoltageDetection(GwApi *api){
void OBP60Task(GwApi *api){
GwLog *logger=api->getLogger();
GwConfigHandler *config=api->getConfig();
startLedTask(api);
PageList allPages;
registerAllPages(allPages);
@@ -409,7 +412,7 @@ void OBP60Task(GwApi *api){
String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString();
String tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asString();
String backlightColor = api->getConfig()->getConfigItem(api->getConfig()->blColor,true)->asString();
CHSV color = colorMapping(backlightColor);
Color color = colorMapping(backlightColor);
uint brightness = 2.55 * uint(api->getConfig()->getConfigItem(api->getConfig()->blBrightness,true)->asInt());
bool uvoltage = api->getConfig()->getConfigItem(api->getConfig()->underVoltage,true)->asBoolean();
@@ -531,7 +534,7 @@ void OBP60Task(GwApi *api){
setBacklightLED(brightness, color);
}
else{
setBacklightLED(0, CHSV(HUE_BLUE, 255, 0)); // Backlight LEDs off (blue without britghness)
setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
}
}

View File

@@ -15,11 +15,10 @@ board = obp60_s3_n16r8 #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production serie
board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
framework = arduino
lib_deps =
${env.lib_deps}
${basedeps.lib_deps}
Wire
SPI
esphome/AsyncTCP-esphome@2.0.1
fastled/FastLED@3.6.0
robtillaart/PCF8574@0.3.9
adafruit/Adafruit Unified Sensor @ 1.1.13
blemasle/MCP23017@2.0.0
@@ -37,7 +36,7 @@ lib_deps =
milesburton/DallasTemperature@3.11.0
signetica/SunRise@2.0.2
build_flags=
-DTIME=$UNIX_TIME
#-DTIME=$UNIX_TIME
-D BOARD_OBP60S3
# -D DISPLAY_GDEW042T2 #old E-Ink display from Waveshare, R10 0.47 ohm
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm