diff --git a/embedded8266/ccconfig.h b/embedded8266/ccconfig.h index 299949e..b32d2a6 100644 --- a/embedded8266/ccconfig.h +++ b/embedded8266/ccconfig.h @@ -6,7 +6,7 @@ #define HPABUFFSIZE 512 #define CCEMBEDDED -#define NUM_LIN_LEDS 255 +#define NUM_LIN_LEDS 541 #define DFREQ 16000 #define memcpy ets_memcpy @@ -30,6 +30,7 @@ #define COLORCHORD_OUTPUT_DRIVER CCS.gCOLORCHORD_OUTPUT_DRIVER #define COLORCHORD_ACTIVE CCS.gCOLORCHORD_ACTIVE #define INITIAL_AMP CCS.gINITIAL_AMP +#define LED_DRIVER_MODE CCS.gLED_DRIVER_MODE //We are not enabling these for the ESP8266 port. #define LIN_WRAPAROUND 0 @@ -55,6 +56,7 @@ struct CCSettings uint16_t gUSE_NUM_LIN_LEDS; // = NUM_LIN_LEDS uint16_t gCOLORCHORD_ACTIVE; uint16_t gCOLORCHORD_OUTPUT_DRIVER; + uint16_t gLED_DRIVER_MODE; uint16_t gINITIAL_AMP; }; diff --git a/embedded8266/esp82xx b/embedded8266/esp82xx index b0c4a01..a08b471 160000 --- a/embedded8266/esp82xx +++ b/embedded8266/esp82xx @@ -1 +1 @@ -Subproject commit b0c4a01a4a344054f70b936d448fd0fd6c15ad20 +Subproject commit a08b47184b3fcf04172ecc0b6a1aee9c90e5d92d diff --git a/embedded8266/image.elf-0x00000.bin b/embedded8266/image.elf-0x00000.bin index cc74d6c..fcf1e8d 100644 Binary files a/embedded8266/image.elf-0x00000.bin and b/embedded8266/image.elf-0x00000.bin differ diff --git a/embedded8266/user.cfg b/embedded8266/user.cfg index 2b0562e..9463bb5 100644 --- a/embedded8266/user.cfg +++ b/embedded8266/user.cfg @@ -15,7 +15,7 @@ ESP_GCC_VERS = 4.8.5 #SDK = $(HOME)/esp8266/esp_iot_sdk_v1.5.2 PAGE_SCRIPTS = main.js -FWBURNFLAGS = -b 2000000 +FWBURNFLAGS = -b 1500000 OPTS += -DUSE_OPTIMIZE_PRINTF OPTS += -DMFS_PAGE_OFFSET=$(MFS_PAGE_OFFSET) @@ -28,6 +28,7 @@ OPTS += -DDISABLE_NET_REFLASH #OPTS += -DVERIFY_FLASH_WRITE #OPTS += -DDEBUG #OPTS += -DFREQ=12500 +OPTS += -DSOFTAP_CHANNEL=6 STRIPPED_LIBGCC=YES diff --git a/embedded8266/user/custom_commands.c b/embedded8266/user/custom_commands.c index 8fb9a7b..c06e65b 100644 --- a/embedded8266/user/custom_commands.c +++ b/embedded8266/user/custom_commands.c @@ -11,28 +11,28 @@ extern volatile uint8_t sounddata[]; extern volatile uint16_t soundhead; -#define CONFIGURABLES 18 //(plus1) +#define CONFIGURABLES 19 //(plus1) struct SaveLoad { - uint8_t configs[CONFIGURABLES]; - uint8_t SaveLoadKey; //Must be 0xaa to be valid. + uint16_t configs[CONFIGURABLES]; + uint16_t SaveLoadKey; //Must be 0xaa to be valid. } settings; struct CCSettings CCS; -uint16_t gConfigDefaults[CONFIGURABLES] = { 0, 6, 1, 2, 3, 4, 7, 4, 2, 80, 64, 12, 15, NUM_LIN_LEDS, 1, 0, 16, 0 }; +uint16_t gConfigDefaults[CONFIGURABLES] = { 0, 6, 1, 2, 3, 4, 7, 4, 2, 80, 64, 12, 15, NUM_LIN_LEDS, 1, 0, 16, 0, 0 }; uint16_t * gConfigurables[CONFIGURABLES] = { &CCS.gROOT_NOTE_OFFSET, &CCS.gDFTIIR, &CCS.gFUZZ_IIR_BITS, &CCS.gFILTER_BLUR_PASSES, &CCS.gSEMIBITSPERBIN, &CCS.gMAX_JUMP_DISTANCE, &CCS.gMAX_COMBINE_DISTANCE, &CCS.gAMP_1_IIR_BITS, &CCS.gAMP_2_IIR_BITS, &CCS.gMIN_AMP_FOR_NOTE, &CCS.gMINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR, &CCS.gNOTE_FINAL_AMP, - &CCS.gNERF_NOTE_PORP, &CCS.gUSE_NUM_LIN_LEDS, &CCS.gCOLORCHORD_ACTIVE, &CCS.gCOLORCHORD_OUTPUT_DRIVER, &CCS.gINITIAL_AMP, 0 }; + &CCS.gNERF_NOTE_PORP, &CCS.gUSE_NUM_LIN_LEDS, &CCS.gCOLORCHORD_ACTIVE, &CCS.gCOLORCHORD_OUTPUT_DRIVER, &CCS.gINITIAL_AMP, &CCS.gLED_DRIVER_MODE, 0 }; char * gConfigurableNames[CONFIGURABLES] = { "gROOT_NOTE_OFFSET", "gDFTIIR", "gFUZZ_IIR_BITS", "gFILTER_BLUR_PASSES", "gSEMIBITSPERBIN", "gMAX_JUMP_DISTANCE", "gMAX_COMBINE_DISTANCE", "gAMP_1_IIR_BITS", "gAMP_2_IIR_BITS", "gMIN_AMP_FOR_NOTE", "gMINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR", "gNOTE_FINAL_AMP", - "gNERF_NOTE_PORP", "gUSE_NUM_LIN_LEDS", "gCOLORCHORD_ACTIVE", "gCOLORCHORD_OUTPUT_DRIVER", "gINITIAL_AMP", 0 }; + "gNERF_NOTE_PORP", "gUSE_NUM_LIN_LEDS", "gCOLORCHORD_ACTIVE", "gCOLORCHORD_OUTPUT_DRIVER", "gINITIAL_AMP", "gLED_DRIVER_MODE", 0 }; void ICACHE_FLASH_ATTR CustomStart( ) { diff --git a/embedded8266/user/user_main.c b/embedded8266/user/user_main.c index fb76c57..6ed9c5b 100644 --- a/embedded8266/user/user_main.c +++ b/embedded8266/user/user_main.c @@ -62,7 +62,7 @@ static void NewFrame() break; }; - ws2812_push( ledOut, USE_NUM_LIN_LEDS * 3 ); + ws2812_push( ledOut, USE_NUM_LIN_LEDS * 3, LED_DRIVER_MODE ); } os_event_t procTaskQueue[procTaskQueueLen]; @@ -151,7 +151,7 @@ static void ICACHE_FLASH_ATTR myTimer(void *arg) // printf( "%d/%d\n",soundtail,soundhead ); // printf( "%d/%d\n",soundtail,soundhead ); // uint8_t ledout[] = { 0x00, 0xff, 0xaa, 0x00, 0xff, 0xaa, }; -// ws2812_push( ledout, 6 ); +// ws2812_push( ledout, 6, LED_DRIVER_MODE ); } @@ -162,7 +162,7 @@ static void ICACHE_FLASH_ATTR udpserver_recv(void *arg, char *pusrdata, unsigned // uint8_t buffer[MAX_FRAME]; // uint8_t ledout[] = { 0x00, 0xff, 0xaa, 0x00, 0xff, 0xaa, }; uart0_sendStr("X"); - ws2812_push( pusrdata+3, len ); + ws2812_push( pusrdata+3, len, LED_DRIVER_MODE ); } void ICACHE_FLASH_ATTR charrx( uint8_t c ) @@ -216,6 +216,7 @@ void ICACHE_FLASH_ATTR user_init(void) os_timer_arm(&some_timer, 100, 1); //Set GPIO16 for Input +#if 0 WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC and rtc_gpio0 connection @@ -224,6 +225,9 @@ void ICACHE_FLASH_ATTR user_init(void) WRITE_PERI_REG(RTC_GPIO_ENABLE, READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe); //out disable +#endif + + system_update_cpu_freq(SYS_CPU_160MHZ); InitColorChord(); //Init colorchord diff --git a/embedded8266/user/ws2812_i2s.c b/embedded8266/user/ws2812_i2s.c index f2e018b..fb41186 100644 --- a/embedded8266/user/ws2812_i2s.c +++ b/embedded8266/user/ws2812_i2s.c @@ -45,6 +45,13 @@ Extra copyright info: //Creates an I2S SR of 93,750 Hz, or 3 MHz Bitclock (.333us/sample) // 12000000L/(div*bestbck*2) //It is likely you could speed this up a little. +#define LUXETRON + +#ifdef LUXETRON +#define INVERT +#define WS_I2S_BCK 14 +#define WS_I2S_DIV 5 +#else #ifdef WS2812_THREE_SAMPLE #define WS_I2S_BCK 22 //Seems to work as low as 19, but is shakey at 18. @@ -55,6 +62,7 @@ Extra copyright info: #else #error You need to either define WS2812_THREE_SAMPLE or WS2812_FOUR_SAMPLE #endif +#endif #ifndef i2c_bbpll #define i2c_bbpll 0x67 @@ -239,11 +247,13 @@ union sdio_slave_status //static unsigned int i2sBuf[I2SDMABUFCNT][I2SDMABUFLEN]; //I2S DMA buffer descriptors //static struct sdio_queue i2sBufDesc[I2SDMABUFCNT]; -static struct sdio_queue i2sBufDescOut; +static struct sdio_queue i2sBufDescOut0; +static struct sdio_queue i2sBufDescOut1; +static struct sdio_queue i2sBufDescOut2; static struct sdio_queue i2sBufDescZeroes; static unsigned int i2sZeroes[32]; -static unsigned int i2sBlock[WS_BLOCKSIZE/4]; +static unsigned int i2sBlock[(WS_BLOCKSIZE0 + WS_BLOCKSIZE1 + WS_BLOCKSIZE2)/4]; //Queue which contains empty DMA buffers //DMA underrun counter @@ -290,14 +300,32 @@ void ICACHE_FLASH_ATTR ws2812_init() SET_PERI_REG_MASK(SLC_RX_DSCR_CONF,SLC_INFOR_NO_REPLACE|SLC_TOKEN_NO_REPLACE); CLEAR_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_FILL_EN|SLC_RX_EOF_MODE | SLC_RX_FILL_MODE); - i2sBufDescOut.owner = 1; - i2sBufDescOut.eof = 1; - i2sBufDescOut.sub_sof = 0; - i2sBufDescOut.datalen = WS_BLOCKSIZE; //Size (in bytes) - i2sBufDescOut.blocksize = WS_BLOCKSIZE; //Size (in bytes) - i2sBufDescOut.buf_ptr=(uint32_t)&i2sBlock[0]; - i2sBufDescOut.unused=0; - i2sBufDescOut.next_link_ptr=(uint32_t)&i2sBufDescZeroes; //At the end, just redirect the DMA to the zero buffer. + i2sBufDescOut0.owner = 1; + i2sBufDescOut0.eof = 1; + i2sBufDescOut0.sub_sof = 0; + i2sBufDescOut0.datalen = WS_BLOCKSIZE0; //Size (in bytes) + i2sBufDescOut0.blocksize = WS_BLOCKSIZE0; //Size (in bytes) + i2sBufDescOut0.buf_ptr=(uint32_t)&i2sBlock[0]; + i2sBufDescOut0.unused=0; + i2sBufDescOut0.next_link_ptr=(uint32_t)&i2sBufDescOut1; //At the end, just redirect the DMA to the zero buffer. + + i2sBufDescOut1.owner = 1; + i2sBufDescOut1.eof = 1; + i2sBufDescOut1.sub_sof = 0; + i2sBufDescOut1.datalen = WS_BLOCKSIZE1; //Size (in bytes) + i2sBufDescOut1.blocksize = WS_BLOCKSIZE1; //Size (in bytes) + i2sBufDescOut1.buf_ptr=(uint32_t)&i2sBlock[WS_BLOCKSIZE0/4]; + i2sBufDescOut1.unused=0; + i2sBufDescOut1.next_link_ptr=(uint32_t)&i2sBufDescOut2; //At the end, just redirect the DMA to the zero buffer. + + i2sBufDescOut2.owner = 1; + i2sBufDescOut2.eof = 1; + i2sBufDescOut2.sub_sof = 0; + i2sBufDescOut2.datalen = WS_BLOCKSIZE2; //Size (in bytes) + i2sBufDescOut2.blocksize = WS_BLOCKSIZE2; //Size (in bytes) + i2sBufDescOut2.buf_ptr=(uint32_t)&i2sBlock[(WS_BLOCKSIZE1+WS_BLOCKSIZE0)/4]; + i2sBufDescOut2.unused=0; + i2sBufDescOut2.next_link_ptr=(uint32_t)&i2sBufDescZeroes; //At the end, just redirect the DMA to the zero buffer. i2sBufDescZeroes.owner = 1; i2sBufDescZeroes.eof = 1; @@ -306,16 +334,24 @@ void ICACHE_FLASH_ATTR ws2812_init() i2sBufDescZeroes.blocksize = 32; i2sBufDescZeroes.buf_ptr=(uint32_t)&i2sZeroes[0]; i2sBufDescZeroes.unused=0; - i2sBufDescZeroes.next_link_ptr=(uint32_t)&i2sBufDescOut; + i2sBufDescZeroes.next_link_ptr=(uint32_t)&i2sBufDescOut0; for( x = 0; x < 32; x++ ) { +#ifdef INVERT + i2sZeroes[x] = 0xffffffff; +#else i2sZeroes[x] = 0x00; +#endif } - for( x = 0; x < WS_BLOCKSIZE/4; x++ ) + for( x = 0; x < (WS_BLOCKSIZE0+WS_BLOCKSIZE1+WS_BLOCKSIZE2)/4; x++ ) { +#ifdef INVERT i2sBlock[x] = 0x00000000;//(x == 0 || x == 999)?0xaa:0x00; +#else + i2sBlock[x] = 0xffffffff;//(x == 0 || x == 999)?0xaa:0x00; +#endif /* uint16_t * tt = (uint16_t*)&i2sBlock[x]; (*(tt+0)) = 0xA0F0; @@ -328,7 +364,7 @@ void ICACHE_FLASH_ATTR ws2812_init() // SET_PERI_REG_MASK(SLC_TX_LINK, ((uint32)&i2sBufDescZeroes) & SLC_TXLINK_DESCADDR_MASK); //any random desc is OK, we don't use TX but it needs something valid CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK); - SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)&i2sBufDescOut) & SLC_RXLINK_DESCADDR_MASK); + SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)&i2sBufDescOut0) & SLC_RXLINK_DESCADDR_MASK); #if USE_2812_INTERRUPTS @@ -418,6 +454,14 @@ static const uint16_t bitpatterns[16] = { }; #elif defined(WS2812_FOUR_SAMPLE) +#ifdef INVERT +static const uint16_t bitpatterns[16] = { + ~0b1000100010001000, ~0b1000100010001100, ~0b1000100011001000, ~0b1000100011001100, + ~0b1000110010001000, ~0b1000110010001100, ~0b1000110011001000, ~0b1000110011001100, + ~0b1100100010001000, ~0b1100100010001100, ~0b1100100011001000, ~0b1100100011001100, + ~0b1100110010001000, ~0b1100110010001100, ~0b1100111011001000, ~0b1100110011001100, +}; +#else //Tricky, send out WS2812 bits with coded pulses, one nibble, then the other. static const uint16_t bitpatterns[16] = { 0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110, @@ -426,14 +470,17 @@ static const uint16_t bitpatterns[16] = { 0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, }; #endif +#endif -void ws2812_push( uint8_t * buffer, uint16_t buffersize ) +void ws2812_push( uint8_t * buffer, uint16_t buffersize, int driver_mode ) { uint16_t place; // while( !ws2812_dma_complete ); #ifdef WS2812_THREE_SAMPLE + if( driver_mode ) return; //Not supported in three-sample mode. + uint8_t * bufferpl = (uint8_t*)&i2sBlock[0]; // buffersize += 3; @@ -484,20 +531,76 @@ void ws2812_push( uint8_t * buffer, uint16_t buffersize ) while( bufferpl < &((uint8_t*)i2sBlock)[WS_BLOCKSIZE] ) *(bufferpl++) = 0; #elif defined(WS2812_FOUR_SAMPLE) - uint16_t * bufferpl = (uint16_t*)&i2sBlock[0]; - if( buffersize * 4 > WS_BLOCKSIZE ) return; - for( place = 0; place < buffersize; place++ ) + if( driver_mode ) { - uint8_t btosend = buffer[place]; - *(bufferpl++) = bitpatterns[(btosend&0x0f)]; - *(bufferpl++) = bitpatterns[(btosend>>4)&0x0f]; + uint16_t * bufferpl = (uint16_t*)&i2sBlock[0]; + int strips = (buffersize / 3) / 18; + int strip; + int led; + int side; + for( side = 0; side < 2; side++ ) + for( strip = 0; strip < strips; strip++ ) + { + int byte = (side | (strip<<1)) + 2; + *(bufferpl++) = bitpatterns[(byte&0x0f)]; + *(bufferpl++) = 0xffff; + *(bufferpl++) = 0xffff; + *(bufferpl++) = bitpatterns[(byte>>4)&0x0f]; + + + for( led = 0; led < 9; led++ ) + { + int inled; + if( side == 0 ) + { + inled = strip * 18 + led + 9; + } + else + { + inled = strip * 18 + 8 - led; + } + + + int g = buffer[inled*3+0]; + int r = buffer[inled*3+1]; + int b = buffer[inled*3+2]; + + int y = 0; //R G R B + + *(bufferpl++) = bitpatterns[(y&0x0f)]; + *(bufferpl++) = bitpatterns[(y>>4)&0x0f]; + *(bufferpl++) = bitpatterns[(g&0x0f)]; + *(bufferpl++) = bitpatterns[(g>>4)&0x0f]; + *(bufferpl++) = bitpatterns[(r&0x0f)]; + *(bufferpl++) = bitpatterns[(r>>4)&0x0f]; + *(bufferpl++) = bitpatterns[(b&0x0f)]; + *(bufferpl++) = bitpatterns[(b>>4)&0x0f]; + } + *(bufferpl++) = 0x0000; + *(bufferpl++) = 0xffff; + } + while( bufferpl != (uint16_t*)&i2sBlock[(WS_BLOCKSIZE0+WS_BLOCKSIZE1+WS_BLOCKSIZE2)/4] ) + *(bufferpl++) = 0xffff; } + else + { + uint16_t * bufferpl = (uint16_t*)&i2sBlock[0]; + + if( buffersize * 4 > WS_BLOCKSIZE0 + WS_BLOCKSIZE1 + WS_BLOCKSIZE2 ) return; + + for( place = 0; place < buffersize; place++ ) + { + uint8_t btosend = buffer[place]; + *(bufferpl++) = bitpatterns[(btosend&0x0f)]; + *(bufferpl++) = bitpatterns[(btosend>>4)&0x0f]; + } + } + #endif #if USE_2812_INTERRUPTS - uint16_t leftover = buffersize & 0x1f; if( leftover ) leftover = 32 - leftover; for( place = 0; place < leftover; place++ ) @@ -510,18 +613,42 @@ void ws2812_push( uint8_t * buffer, uint16_t buffersize ) uint16_t sizeout_words = buffersize * 2; - i2sBufDescOut.owner = 1; - i2sBufDescOut.eof = 1; - i2sBufDescOut.sub_sof = 0; - i2sBufDescOut.datalen = sizeout_words*2; //Size (in bytes) - i2sBufDescOut.blocksize = sizeout_words*2; //Size (in bytes) - i2sBufDescOut.buf_ptr = (uint32_t)&i2sBlock[0]; - i2sBufDescOut.unused = 0; - i2sBufDescOut.next_link_ptr=(uint32_t)&i2sBufDescZeroes; //At the end, just redirect the DMA to the zero buffer. + int firstsize = sizeout_words, secondsize = 0; + if( sizeout_words > WS_BLOCKSIZE0 ) + { + secondsize = firstsize - (WS_BLOCKSIZE0/4); + firstsize = WS_BLOCKSIZE0/4; + } + i2sBufDescOut0.owner = 1; + i2sBufDescOut0.eof = 1; + i2sBufDescOut0.sub_sof = 0; + i2sBufDescOut0.datalen = sizeout_words*2; //Size (in bytes) + i2sBufDescOut0.blocksize = sizeout_words*2; //Size (in bytes) + i2sBufDescOut0.buf_ptr = (uint32_t)&i2sBlock[0]; + i2sBufDescOut0.unused = 0; + i2sBufDescOut0.next_link_ptr=(uint32_t)&i2sBufDescOut1; //At the end, just redirect the DMA to the zero buffer. + + i2sBufDescOut1.owner = 1; + i2sBufDescOut1.eof = 1; + i2sBufDescOut1.sub_sof = 0; + i2sBufDescOut1.datalen = sizeout_words*2; //Size (in bytes) + i2sBufDescOut1.blocksize = sizeout_words*2; //Size (in bytes) + i2sBufDescOut1.buf_ptr = (uint32_t)&i2sBlock[WS_BLOCKSIZE0/4]; + i2sBufDescOut1.unused = 0; + i2sBufDescOut1.next_link_ptr=(uint32_t)&i2sBufDescOut2; //At the end, just redirect the DMA to the zero buffer. + + i2sBufDescOut2.owner = 1; + i2sBufDescOut2.eof = 1; + i2sBufDescOut2.sub_sof = 0; + i2sBufDescOut2.datalen = sizeout_words*2; //Size (in bytes) + i2sBufDescOut2.blocksize = sizeout_words*2; //Size (in bytes) + i2sBufDescOut2.buf_ptr = (uint32_t)&i2sBlock[(WS_BLOCKSIZE0+WS_BLOCKSIZE1)/4]; + i2sBufDescOut2.unused = 0; + i2sBufDescOut2.next_link_ptr=(uint32_t)&i2sBufDescZeroes; //At the end, just redirect the DMA to the zero buffer. SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_STOP); CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK); - SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)&i2sBufDescOut) & SLC_RXLINK_DESCADDR_MASK); + SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)&i2sBufDescOut0) & SLC_RXLINK_DESCADDR_MASK); SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START); #endif diff --git a/embedded8266/user/ws2812_i2s.h b/embedded8266/user/ws2812_i2s.h index c0276e6..0115a6e 100644 --- a/embedded8266/user/ws2812_i2s.h +++ b/embedded8266/user/ws2812_i2s.h @@ -15,7 +15,9 @@ //NOTE: Blocksize MUST be divisible by 4. Cannot exceed 4092 //Each LED takes up 12 block bytes in WS2812_FOUR_SAMPLE //Or 9 block bytes in WS2812_THREE_SAMPLE -#define WS_BLOCKSIZE 4000 +#define WS_BLOCKSIZE0 4000 +#define WS_BLOCKSIZE1 4000 +#define WS_BLOCKSIZE2 4000 //You can either have 3 or 4 samples per bit for WS2812s. //3 sample can't go quite as fast as 4. @@ -28,7 +30,9 @@ //#define WS2812_FOUR_SAMPLE void ICACHE_FLASH_ATTR ws2812_init(); -void ws2812_push( uint8_t * buffer, uint16_t buffersize ); //Buffersize = Nr LEDs * 3 +void ws2812_push( uint8_t * buffer, uint16_t buffersize, int led_mode ); //Buffersize = Nr LEDs * 3 +//led_mode = 0 for WS2812B +//led_mode = 1 for luxehedron #endif