boothifier/z_old/LEDStrip.cpp

473 lines
14 KiB
C++

#include "LEDStrip.h"
#include "driver/i2s.h"
#include <Arduino.h>
#include "HSVTable.h"
static const char* tag = "LEDStrip";
LEDSTRIP::LEDSTRIP(int port, int size, int pin, LED_ORDER ledOrder, int shift, int offset)
{
this->port = port;
this->size = size;
this->shift = shift;
this->offset = offset;
this->effSize = this->size - this->offset;
this->ledOrder = ledOrder;
// create pixel array and buffer array
pixels = new rgbpixel_t[size];
out_buffer_size = size * PIXEL_SIZE;
out_buffer = new uint8_t[out_buffer_size + RESET_BUFFER_SIZE];
reset_buffer = &out_buffer[out_buffer_size + 1]; // pointer to reset buffer section
active_out_buffer = &out_buffer[0] + (offset * PIXEL_SIZE); // start of the first active
// initialize buffer
memset(pixels, 0, this->size * sizeof(rgbpixel_t));
memset(out_buffer, 0, out_buffer_size + RESET_BUFFER_SIZE);
dma_frame_size = I2S_TX_DMA_BUFF_SIZE;
if((size * PIXEL_SIZE) < I2S_TX_DMA_BUFF_SIZE) {
dma_frame_size = size * PIXEL_SIZE;
}
// Although the buffer can be smaller than total buffer size it will require more cpu interrupts
// So this provides for the entire size rounded up to the closes buffer chunk (I2S_TX_DMA_BUFF_SIZE)
int dma_buff_count = 1 + ((out_buffer_size + RESET_BUFFER_SIZE + 2) / I2S_TX_DMA_BUFF_SIZE);
// install driver
i2s_driver_config_t i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_8BIT,
.channel_format = i2s_channel_fmt_t(I2S_CHANNEL_FMT_RIGHT_LEFT),
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2, // high interrupt priority,
//.intr_alloc_flags = ESP_INTR_FLAG_LOWMED, // high interrupt priority,
.dma_buf_count = dma_buff_count, //
.dma_buf_len = I2S_TX_DMA_BUFF_SIZE,
.use_apll = true
}; // possibly needed for accuracy
//i2sEventQueue = xQueueCreate(8, sizeof(i2s_event_t));
esp_err_t err = i2s_driver_install((i2s_port_t)port, &i2s_config, 8, &i2sEventQueue);
if(err){
if(err == ESP_ERR_INVALID_ARG) {ESP_LOGE(tag, "I2S driver error: Parameter error");}
else if(err == ESP_ERR_NO_MEM) {ESP_LOGE(tag, "I2S driver error: Out of Memory");}
else if(err == ESP_ERR_INVALID_STATE) {ESP_LOGE(tag, "I2S driver error: Port is in use");}
}
else{
i2s_pin_config_t pin_config = {.bck_io_num = I2S_PIN_NO_CHANGE,
.ws_io_num = I2S_PIN_NO_CHANGE,
.data_out_num = pin,
.data_in_num = I2S_PIN_NO_CHANGE };
ESP_LOGV(tag, "I2S port pin configured....");
err = i2s_set_pin((i2s_port_t)port, &pin_config);
if(err){
if(err == ESP_ERR_INVALID_ARG) {ESP_LOGE(tag, "I2S driver error: Parameter error");}
else if(err == ESP_FAIL) {ESP_LOGE(tag, "I2S driver error: IO error");}
}
else{
ESP_LOGV(tag, "I2S pin config success!");
}
}
}
#if(HIGH_RES_BIT_RATE == 1)
static const uint8_t bitpatterns[2] = {0b11000000, 0b11111100};
void LEDSTRIP::updateBuff(void) {
uint8_t* buff = active_out_buffer;
for (uint16_t i = 0; i < this->effSize; i++)
{
uint8_t red = pixels[i].red >> powerDiv;
uint8_t grn = pixels[i].grn >> powerDiv;
uint8_t blu = pixels[i].blu >> powerDiv;
*buff++ = bitpatterns[red >> 7 & 0x01];
*buff++ = bitpatterns[red >> 6 & 0x01];
*buff++ = bitpatterns[red >> 5 & 0x01];
*buff++ = bitpatterns[red >> 4 & 0x01];
*buff++ = bitpatterns[red >> 3 & 0x01];
*buff++ = bitpatterns[red >> 2 & 0x01];
*buff++ = bitpatterns[red >> 1 & 0x01];
*buff++ = bitpatterns[red & 0x01];
*buff++ = bitpatterns[grn >> 7 & 0x01];
*buff++ = bitpatterns[grn >> 6 & 0x01];
*buff++ = bitpatterns[grn >> 5 & 0x01];
*buff++ = bitpatterns[grn >> 4 & 0x01];
*buff++ = bitpatterns[grn >> 3 & 0x01];
*buff++ = bitpatterns[grn >> 2 & 0x01];
*buff++ = bitpatterns[grn >> 1 & 0x01];
*buff++ = bitpatterns[grn & 0x01];
*buff++ = bitpatterns[blu >> 7 & 0x01];
*buff++ = bitpatterns[blu >> 6 & 0x01];
*buff++ = bitpatterns[blu >> 5 & 0x01];
*buff++ = bitpatterns[blu >> 4 & 0x01];
*buff++ = bitpatterns[blu >> 3 & 0x01];
*buff++ = bitpatterns[blu >> 2 & 0x01];
*buff++ = bitpatterns[blu >> 1 & 0x01];
*buff++ = bitpatterns[blu & 0x01];
}
*buff++ = 0;
}
#else
static const uint16_t bitpatterns[4] = {0x88, 0x8e, 0xe8, 0xee};
void LEDSTRIP::updateBuff(void)
{
uint8_t* buff = active_out_buffer;
switch(this->ledOrder){
case ORDER_RGB:
for (uint16_t i = 0; i < this->effSize; i++)
{
uint8_t red = pixels[i].red >> powerDiv;
uint8_t grn = pixels[i].grn >> powerDiv;
uint8_t blu = pixels[i].blu >> powerDiv;
*buff++ = bitpatterns[red >> 6 & 0x03];
*buff++ = bitpatterns[red >> 4 & 0x03];
*buff++ = bitpatterns[red >> 2 & 0x03];
*buff++ = bitpatterns[red & 0x03];
*buff++ = bitpatterns[grn >> 6 & 0x03];
*buff++ = bitpatterns[grn >> 4 & 0x03];
*buff++ = bitpatterns[grn >> 2 & 0x03];
*buff++ = bitpatterns[grn & 0x03];
*buff++ = bitpatterns[blu >> 6 & 0x03];
*buff++ = bitpatterns[blu >> 4 & 0x03];
*buff++ = bitpatterns[blu >> 2 & 0x03];
*buff++ = bitpatterns[blu & 0x03];
}
break;
case ORDER_RBG:
for (uint16_t i = 0; i < this->size; i++)
{
uint8_t red = pixels[i].red >> powerDiv;
uint8_t grn = pixels[i].grn >> powerDiv;
uint8_t blu = pixels[i].blu >> powerDiv;
*buff++ = bitpatterns[red >> 6 & 0x03];
*buff++ = bitpatterns[red >> 4 & 0x03];
*buff++ = bitpatterns[red >> 2 & 0x03];
*buff++ = bitpatterns[red & 0x03];
*buff++ = bitpatterns[blu >> 6 & 0x03];
*buff++ = bitpatterns[blu >> 4 & 0x03];
*buff++ = bitpatterns[blu >> 2 & 0x03];
*buff++ = bitpatterns[blu & 0x03];
*buff++ = bitpatterns[grn >> 6 & 0x03];
*buff++ = bitpatterns[grn >> 4 & 0x03];
*buff++ = bitpatterns[grn >> 2 & 0x03];
*buff++ = bitpatterns[grn & 0x03];
}
break;
case ORDER_GRB:
for (uint16_t i = 0; i < this->size; i++)
{
uint8_t red = pixels[i].red >> powerDiv;
uint8_t grn = pixels[i].grn >> powerDiv;
uint8_t blu = pixels[i].blu >> powerDiv;
*buff++ = bitpatterns[grn >> 6 & 0x03];
*buff++ = bitpatterns[grn >> 4 & 0x03];
*buff++ = bitpatterns[grn >> 2 & 0x03];
*buff++ = bitpatterns[grn & 0x03];
*buff++ = bitpatterns[red >> 6 & 0x03];
*buff++ = bitpatterns[red >> 4 & 0x03];
*buff++ = bitpatterns[red >> 2 & 0x03];
*buff++ = bitpatterns[red & 0x03];
*buff++ = bitpatterns[blu >> 6 & 0x03];
*buff++ = bitpatterns[blu >> 4 & 0x03];
*buff++ = bitpatterns[blu >> 2 & 0x03];
*buff++ = bitpatterns[blu & 0x03];
}
break;
case ORDER_GBR:
for (uint16_t i = 0; i < this->size; i++)
{
uint8_t red = pixels[i].red >> powerDiv;
uint8_t grn = pixels[i].grn >> powerDiv;
uint8_t blu = pixels[i].blu >> powerDiv;
*buff++ = bitpatterns[grn >> 6 & 0x03];
*buff++ = bitpatterns[grn >> 4 & 0x03];
*buff++ = bitpatterns[grn >> 2 & 0x03];
*buff++ = bitpatterns[grn & 0x03];
*buff++ = bitpatterns[blu >> 6 & 0x03];
*buff++ = bitpatterns[blu >> 4 & 0x03];
*buff++ = bitpatterns[blu >> 2 & 0x03];
*buff++ = bitpatterns[blu & 0x03];
*buff++ = bitpatterns[red >> 6 & 0x03];
*buff++ = bitpatterns[red >> 4 & 0x03];
*buff++ = bitpatterns[red >> 2 & 0x03];
*buff++ = bitpatterns[red & 0x03];
}
break;
case ORDER_BRG:
for (uint16_t i = 0; i < this->size; i++)
{
uint8_t red = pixels[i].red >> powerDiv;
uint8_t grn = pixels[i].grn >> powerDiv;
uint8_t blu = pixels[i].blu >> powerDiv;
*buff++ = bitpatterns[blu >> 6 & 0x03];
*buff++ = bitpatterns[blu >> 4 & 0x03];
*buff++ = bitpatterns[blu >> 2 & 0x03];
*buff++ = bitpatterns[blu & 0x03];
*buff++ = bitpatterns[red >> 6 & 0x03];
*buff++ = bitpatterns[red >> 4 & 0x03];
*buff++ = bitpatterns[red >> 2 & 0x03];
*buff++ = bitpatterns[red & 0x03];
*buff++ = bitpatterns[grn >> 6 & 0x03];
*buff++ = bitpatterns[grn >> 4 & 0x03];
*buff++ = bitpatterns[grn >> 2 & 0x03];
*buff++ = bitpatterns[grn & 0x03];
}
break;
default: //ORDER_BGR:
for (uint16_t i = 0; i < this->size; i++)
{
uint8_t red = pixels[i].red >> powerDiv;
uint8_t grn = pixels[i].grn >> powerDiv;
uint8_t blu = pixels[i].blu >> powerDiv;
*buff++ = bitpatterns[blu >> 6 & 0x03];
*buff++ = bitpatterns[blu >> 4 & 0x03];
*buff++ = bitpatterns[blu >> 2 & 0x03];
*buff++ = bitpatterns[blu & 0x03];
*buff++ = bitpatterns[grn >> 6 & 0x03];
*buff++ = bitpatterns[grn >> 4 & 0x03];
*buff++ = bitpatterns[grn >> 2 & 0x03];
*buff++ = bitpatterns[grn & 0x03];
*buff++ = bitpatterns[red >> 6 & 0x03];
*buff++ = bitpatterns[red >> 4 & 0x03];
*buff++ = bitpatterns[red >> 2 & 0x03];
*buff++ = bitpatterns[red & 0x03];
}
break;
}
}
#endif
void LEDSTRIP::show(bool update)
{
if(update){ updateBuff(); };
//i2s_stop((i2s_port_t)this->port);
i2s_start((i2s_port_t)this->port);
i2s_zero_dma_buffer((i2s_port_t)this->port);
i2s_write_data(out_buffer, out_buffer_size + RESET_BUFFER_SIZE);
/*
i2s_event_t i2s_event;
while(1){
if(xQueueReceive(i2sEventQueue, &i2s_event, 100)){
if(i2s_event.type == I2S_EVENT_TX_DONE) { break;}
}else{
break;
}
}
*/
}
void LEDSTRIP::setPowerDiv(uint8_t div){
if(div < 0){div = 0;}
if(div > 4){div = 4;}
powerDiv = div;
}
// Function to write data to the I2S buffer
void LEDSTRIP::i2s_write_data(const void *data, size_t len)
{
size_t bytesWritten = 0;
while (bytesWritten < len) {
size_t bytesToWrite = len - bytesWritten;
size_t written = 0;
esp_err_t err = i2s_write(I2S_NUM_0, (const char*)data + bytesWritten, bytesToWrite, &written, portMAX_DELAY);
if (err != ESP_OK) {
// Handle error
ESP_LOGE(tag, "i2s send error: %d", err);
break;
}
bytesWritten += written;
}
}
inline int LEDSTRIP::calcIndex(int index)
{
//int x = (index + shift) % effSize;
//if(x < 0) { // convert nex index to positive range
// x += effSize;
//}
//return x + offset;
int x = (index + shift) % effSize;
x = (x < 0) ? (x + effSize) : x;
return (x + offset) % effSize;
}
void LEDSTRIP::setPixel(int index, rgbpixel_t& col)
{
pixels[calcIndex(index)] = col;
}
void LEDSTRIP::setPixel(int index, const rgbpixel_t col)
{
pixels[calcIndex(index)] = col;
}
/*
void LEDSTRIP::setPixel(int index, rgbpixel_t col, uint8_t scale)
{
uint16_t n = scale + 1;
uint8_t r = (col.red * n) >> 8;
uint8_t g = (col.grn * n) >> 8;
uint8_t b = (col.blu * n) >> 8;
pixels[calcIndex(index)] = {r, g, b};
}
*/
void LEDSTRIP::setPixelRaw(int index, rgbpixel_t& col){
pixels[index] = col;
}
void LEDSTRIP::setPixelMirrored(int index, rgbpixel_t col)
{
pixels[calcIndex(index)] = col;
pixels[calcIndex(-index-1)] = col;
}
rgbpixel_t LEDSTRIP::getPixel(int index)
{
return pixels[calcIndex(index)];
}
void LEDSTRIP::rotatePixels(LED_DIR dir)
{
// store the shifted out pixels
rgbpixel_t tPix;
if(dir == DIR_FWD){
tPix = pixels[size -1];
for(int i=size-1; i > offset; i--){
pixels[i] = pixels[i-1];
}
pixels[offset] = tPix;
}else{
tPix = pixels[offset];
for(int i=offset; i < size-1; i++){
pixels[i] = pixels[i+1];
}
pixels[size-1] = tPix;
}
}
void LEDSTRIP::shiftPixels(int numPixels, LED_DIR dir)
{
// Calculate the shift direction and absolute shift count
int shiftDir = (dir == DIR_FWD) ? 1 : -1;
int absShiftCount = (numPixels % this->effSize) * shiftDir;
// Shift the pixels by swapping them in place using circular buffering
for (int i = 0; i < this->effSize; i++) {
rgbpixel_t temp = pixels[i];
int j = i;
while (true) {
int k = j + absShiftCount;
if (k < 0) {
k += this->effSize;
} else if (k >= this->effSize) {
k -= this->effSize;
}
if (k == i) {
break;
}
pixels[j] = pixels[k];
j = k;
}
pixels[j] = temp;
// Check if we have completed a cycle
if (j == i + absShiftCount) {
break;
}
}
}
void scalePixel(rgbpixel_t& pix, uint8_t _scale)
{
uint16_t n = _scale + 1;
pix.red = (pix.red * n) >> 8;
pix.grn = (pix.grn * n) >> 8;
pix.blu = (pix.blu * n) >> 8;
}
void linearizePixel(rgbpixel_t& pix){
pix.red = ((int)pix.red * (int)pix.red ) >> 8;
pix.grn = ((int)pix.grn * (int)pix.grn ) >> 8;
pix.blu = ((int)pix.blu * (int)pix.blu ) >> 8;
}
void PixelFadeToBlack(rgbpixel_t& pix, uint8_t fadeValue) {
pix.red = (pix.red <= 8) ? 0 : pix.red - ((pix.red * fadeValue)>>8);
pix.grn = (pix.grn <= 8) ? 0 : pix.grn - ((pix.grn * fadeValue)>>8);
pix.blu = (pix.blu <= 8) ? 0 : pix.blu - ((pix.blu * fadeValue)>>8);
}
void LEDSTRIP::zeroPixels(void)
{
for(int i=0; i < this->size; i++){
pixels[i] = {0,0,0};
}
}
void LEDSTRIP::fill(rgbpixel_t color, int startIndex, int count)
{
int endIndex = startIndex + count;
for (int i = startIndex; i < endIndex; i++) {
pixels[calcIndex(i)] = color;
}
}
// a factor of 0=no changer, factor=255 newCol replaces 100%
void LEDSTRIP::transitionPixel(int index, rgbpixel_t& newCol, uint8_t factor)
{
int i = calcIndex(index);
int f = factor + 1;
pixels[i].red = (pixels[i].red * (256 - f) + newCol.red * f) >> 8;
pixels[i].grn = (pixels[i].grn * (256 - f) + newCol.grn * f) >> 8;
pixels[i].blu = (pixels[i].blu * (256 - f) + newCol.blu * f) >> 8;
}
LED_ORDER getRGBOrder(const char* order){
if(strcmp(order, "rgb")==0){ return ORDER_RGB; }
if(strcmp(order, "rbg")==0){ return ORDER_RBG; }
if(strcmp(order, "grb")==0){ return ORDER_GRB; }
if(strcmp(order, "gbr")==0){ return ORDER_GBR; }
if(strcmp(order, "brg")==0){ return ORDER_BRG; }
if(strcmp(order, "bgr")==0){ return ORDER_BGR; }
else{ return ORDER_GRB; }
}