Skip to content

Commit b179f30

Browse files
HHHartmannmarcelstoer
authored andcommitted
Fixes for ws2812 and ws2812_effects (#2953)
* clean effects library * Fix several issues in ws2812 and effects * Implement working way of calling shift from callback
1 parent c7d0f83 commit b179f30

8 files changed

+721
-197
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ tools/toolchains/
1616
.project
1717
.settings/
1818
.vscode
19+
.vs
1920

2021
#ignore temp file for build infos
2122
buildinfo.h

app/modules/ws2812.c

+63-58
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@
1616
#define MODE_DUAL 1
1717

1818

19-
20-
21-
22-
2319
// Init UART1 to be able to stream WS2812 data to GPIO2 pin
2420
// If DUAL mode is selected, init UART0 to stream to TXD0 as well
2521
// You HAVE to redirect LUA's output somewhere else
@@ -168,15 +164,15 @@ static int ws2812_write(lua_State* L) {
168164
return 0;
169165
}
170166

171-
static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
167+
static ptrdiff_t posrelat(ptrdiff_t pos, size_t len) {
172168
/* relative string position: negative means back from end */
173169
if (pos < 0) pos += (ptrdiff_t)len + 1;
174-
return (pos >= 0) ? pos : 0;
170+
return MIN(MAX(pos, 1), len);
175171
}
176172

177173
static ws2812_buffer *allocate_buffer(lua_State *L, int leds, int colorsPerLed) {
178174
// Allocate memory
179-
size_t size = sizeof(ws2812_buffer) + colorsPerLed*leds*sizeof(uint8_t);
175+
size_t size = sizeof(ws2812_buffer) + colorsPerLed*leds;
180176
ws2812_buffer * buffer = (ws2812_buffer*)lua_newuserdata(L, size);
181177

182178
// Associate its metatable
@@ -245,17 +241,11 @@ static int ws2812_buffer_fill_lua(lua_State* L) {
245241
return 0;
246242
}
247243

248-
static int ws2812_buffer_fade(lua_State* L) {
249-
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
250-
const int fade = luaL_checkinteger(L, 2);
251-
unsigned direction = luaL_optinteger( L, 3, FADE_OUT );
252-
253-
luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number");
254-
244+
void ws2812_buffer_fade(ws2812_buffer * buffer, int fade, unsigned direction) {
255245
uint8_t * p = &buffer->values[0];
256246
int val = 0;
257247
int i;
258-
for(i = 0; i < buffer->size * buffer->colorsPerLed; i++)
248+
for (i = 0; i < buffer->size * buffer->colorsPerLed; i++)
259249
{
260250
if (direction == FADE_OUT)
261251
{
@@ -269,78 +259,101 @@ static int ws2812_buffer_fade(lua_State* L) {
269259
*p++ = val;
270260
}
271261
}
262+
}
272263

273-
return 0;
264+
static int ws2812_buffer_fade_lua(lua_State* L) {
265+
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
266+
const int fade = luaL_checkinteger(L, 2);
267+
unsigned direction = luaL_optinteger( L, 3, FADE_OUT );
268+
269+
luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number");
270+
271+
ws2812_buffer_fade(buffer, fade, direction);
272+
273+
return 0;
274274
}
275275

276+
int ws2812_buffer_shift(lua_State* L, ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end){
277+
278+
ws2812_buffer_shift_prepare* prepare = ws2812_buffer_get_shift_prepare(L, buffer, shiftValue, shift_type, pos_start, pos_end);
279+
ws2812_buffer_shift_prepared(prepare);
280+
// Free memory
281+
luaM_free(L, prepare);
282+
return 0;
283+
}
276284

277-
int ws2812_buffer_shift(ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end) {
285+
ws2812_buffer_shift_prepare* ws2812_buffer_get_shift_prepare(lua_State* L, ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end){
278286

279287
ptrdiff_t start = posrelat(pos_start, buffer->size);
280288
ptrdiff_t end = posrelat(pos_end, buffer->size);
281-
if (start < 1) start = 1;
282-
if (end > (ptrdiff_t)buffer->size) end = (ptrdiff_t)buffer->size;
283289

284290
start--;
285291
int size = end - start;
286292
size_t offset = start * buffer->colorsPerLed;
287293

288-
//luaL_argcheck(L, shiftValue > 0-size && shiftValue < size, 2, "shifting more elements than buffer size");
294+
luaL_argcheck(L, shiftValue >= 0-size && shiftValue <= size, 2, "shifting more elements than buffer size");
289295

290296
int shift = shiftValue >= 0 ? shiftValue : -shiftValue;
291297

292-
// check if we want to shift at all
293-
if (shift == 0 || size <= 0)
294-
{
295-
return 0;
296-
}
297-
298-
uint8_t * tmp_pixels = malloc(buffer->colorsPerLed * sizeof(uint8_t) * shift);
299-
int i,j;
300298
size_t shift_len, remaining_len;
301299
// calculate length of shift section and remaining section
302300
shift_len = shift*buffer->colorsPerLed;
303301
remaining_len = (size-shift)*buffer->colorsPerLed;
304302

305-
if (shiftValue > 0)
303+
ws2812_buffer_shift_prepare* prepare = luaM_malloc(L, sizeof(ws2812_buffer_shift_prepare) + shift_len);
304+
prepare->offset = offset;
305+
prepare->tmp_pixels = (uint8_t*)(prepare+1);
306+
prepare->shiftValue = shiftValue;
307+
prepare->shift_len = shift_len;
308+
prepare->remaining_len = remaining_len;
309+
prepare->shift_type = shift_type;
310+
prepare->buffer = buffer;
311+
312+
return prepare;
313+
}
314+
315+
void ws2812_buffer_shift_prepared(ws2812_buffer_shift_prepare* prepare) {
316+
317+
// check if we want to shift at all
318+
if (prepare->shift_len == 0 || (prepare->shift_len + prepare->remaining_len) <= 0)
319+
{
320+
return;
321+
}
322+
323+
if (prepare->shiftValue > 0)
306324
{
307325
// Store the values which are moved out of the array (last n pixels)
308-
memcpy(tmp_pixels, &buffer->values[offset + (size-shift)*buffer->colorsPerLed], shift_len);
326+
memcpy(prepare->tmp_pixels, &prepare->buffer->values[prepare->offset + prepare->remaining_len], prepare->shift_len);
309327
// Move pixels to end
310-
os_memmove(&buffer->values[offset + shift*buffer->colorsPerLed], &buffer->values[offset], remaining_len);
328+
os_memmove(&prepare->buffer->values[prepare->offset + prepare->shift_len], &prepare->buffer->values[prepare->offset], prepare->remaining_len);
311329
// Fill beginning with temp data
312-
if (shift_type == SHIFT_LOGICAL)
330+
if (prepare->shift_type == SHIFT_LOGICAL)
313331
{
314-
memset(&buffer->values[offset], 0, shift_len);
332+
memset(&prepare->buffer->values[prepare->offset], 0, prepare->shift_len);
315333
}
316334
else
317335
{
318-
memcpy(&buffer->values[offset], tmp_pixels, shift_len);
336+
memcpy(&prepare->buffer->values[prepare->offset], prepare->tmp_pixels, prepare->shift_len);
319337
}
320338
}
321339
else
322340
{
323341
// Store the values which are moved out of the array (last n pixels)
324-
memcpy(tmp_pixels, &buffer->values[offset], shift_len);
342+
memcpy(prepare->tmp_pixels, &prepare->buffer->values[prepare->offset], prepare->shift_len);
325343
// Move pixels to end
326-
os_memmove(&buffer->values[offset], &buffer->values[offset + shift*buffer->colorsPerLed], remaining_len);
344+
os_memmove(&prepare->buffer->values[prepare->offset], &prepare->buffer->values[prepare->offset + prepare->shift_len], prepare->remaining_len);
327345
// Fill beginning with temp data
328-
if (shift_type == SHIFT_LOGICAL)
346+
if (prepare->shift_type == SHIFT_LOGICAL)
329347
{
330-
memset(&buffer->values[offset + (size-shift)*buffer->colorsPerLed], 0, shift_len);
348+
memset(&prepare->buffer->values[prepare->offset + prepare->remaining_len], 0, prepare->shift_len);
331349
}
332350
else
333351
{
334-
memcpy(&buffer->values[offset + (size-shift)*buffer->colorsPerLed], tmp_pixels, shift_len);
352+
memcpy(&prepare->buffer->values[prepare->offset + prepare->remaining_len], prepare->tmp_pixels, prepare->shift_len);
335353
}
336354
}
337-
// Free memory
338-
free(tmp_pixels);
339-
340-
return 0;
341355
}
342356

343-
344357
static int ws2812_buffer_shift_lua(lua_State* L) {
345358

346359
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
@@ -351,11 +364,10 @@ static int ws2812_buffer_shift_lua(lua_State* L) {
351364
const int pos_end = luaL_optinteger(L, 5, -1);
352365

353366

354-
ws2812_buffer_shift(buffer, shiftValue, shift_type, pos_start, pos_end);
367+
ws2812_buffer_shift(L, buffer, shiftValue, shift_type, pos_start, pos_end);
355368
return 0;
356369
}
357370

358-
359371
static int ws2812_buffer_dump(lua_State* L) {
360372
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
361373

@@ -366,8 +378,7 @@ static int ws2812_buffer_dump(lua_State* L) {
366378

367379
static int ws2812_buffer_replace(lua_State* L) {
368380
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
369-
size_t l = buffer->size;
370-
ptrdiff_t start = posrelat(luaL_optinteger(L, 3, 1), l);
381+
ptrdiff_t start = posrelat(luaL_optinteger(L, 3, 1), buffer->size);
371382

372383
uint8_t *src;
373384
size_t srcLen;
@@ -425,8 +436,8 @@ static int ws2812_buffer_mix(lua_State* L) {
425436
val += (int32_t)(source[src].values[i] * source[src].factor);
426437
}
427438

428-
val += 128; // rounding istead of floor
429-
val >>= 8;
439+
val += 128; // rounding istead of floor
440+
val /= 256; // do not use implemetation dependant right shift
430441

431442
if (val < 0) {
432443
val = 0;
@@ -501,7 +512,7 @@ static int ws2812_buffer_set(lua_State* L) {
501512
// Overflow check
502513
if( buffer->colorsPerLed*led + len > buffer->colorsPerLed*buffer->size )
503514
{
504-
return luaL_error(L, "string size will exceed strip length");
515+
return luaL_error(L, "string size will exceed strip length");
505516
}
506517

507518
memcpy(&buffer->values[buffer->colorsPerLed*led], buf, len);
@@ -531,8 +542,6 @@ static int ws2812_buffer_sub(lua_State* L) {
531542
size_t l = lhs->size;
532543
ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
533544
ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
534-
if (start < 1) start = 1;
535-
if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
536545
if (start <= end) {
537546
ws2812_buffer *result = allocate_buffer(L, end - start + 1, lhs->colorsPerLed);
538547
memcpy(result->values, lhs->values + lhs->colorsPerLed * (start - 1), lhs->colorsPerLed * (end - start + 1));
@@ -591,10 +600,9 @@ static int ws2812_buffer_tostring(lua_State* L) {
591600
return 1;
592601
}
593602

594-
595603
LROT_BEGIN(ws2812_buffer)
596604
LROT_FUNCENTRY( dump, ws2812_buffer_dump )
597-
LROT_FUNCENTRY( fade, ws2812_buffer_fade )
605+
LROT_FUNCENTRY( fade, ws2812_buffer_fade_lua)
598606
LROT_FUNCENTRY( fill, ws2812_buffer_fill_lua )
599607
LROT_FUNCENTRY( get, ws2812_buffer_get )
600608
LROT_FUNCENTRY( replace, ws2812_buffer_replace )
@@ -609,8 +617,6 @@ LROT_BEGIN(ws2812_buffer)
609617
LROT_FUNCENTRY( __tostring, ws2812_buffer_tostring )
610618
LROT_END( ws2812_buffer, ws2812_buffer, LROT_MASK_INDEX )
611619

612-
613-
614620
LROT_BEGIN(ws2812)
615621
LROT_FUNCENTRY( init, ws2812_init )
616622
LROT_FUNCENTRY( newBuffer, ws2812_new_buffer )
@@ -623,7 +629,6 @@ LROT_BEGIN(ws2812)
623629
LROT_NUMENTRY( SHIFT_CIRCULAR, SHIFT_CIRCULAR )
624630
LROT_END( ws2812, NULL, 0 )
625631

626-
627632
int luaopen_ws2812(lua_State *L) {
628633
// TODO: Make sure that the GPIO system is initialized
629634
luaL_rometatable(L, "ws2812.buffer", LROT_TABLEREF(ws2812_buffer));

app/modules/ws2812.h

+24-1
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,39 @@
1717
#define SHIFT_LOGICAL 0
1818
#define SHIFT_CIRCULAR 1
1919

20+
#ifndef MIN
21+
#define MIN(a,b) ((a) < (b) ? (a) : (b))
22+
#endif
23+
#ifndef MAX
24+
#define MAX(a,b) ((a) > (b) ? (a) : (b))
25+
#endif
2026

2127
typedef struct {
2228
int size;
2329
uint8_t colorsPerLed;
2430
uint8_t values[0];
2531
} ws2812_buffer;
2632

33+
typedef struct {
34+
size_t offset;
35+
uint8_t* tmp_pixels;
36+
int shiftValue;
37+
size_t shift_len;
38+
size_t remaining_len;
39+
unsigned shift_type;
40+
ws2812_buffer* buffer;
41+
} ws2812_buffer_shift_prepare;
42+
2743

2844
void ICACHE_RAM_ATTR ws2812_write_data(const uint8_t *pixels, uint32_t length, const uint8_t *pixels2, uint32_t length2);
29-
int ws2812_buffer_shift(ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end);
45+
// To shift the lua_State is needed for error message and memory allocation.
46+
// We also need the shift operation inside a timer callback, where we cannot access the lua_State,
47+
// so This is split up in prepare and the actual call, which can be called multiple times with the same prepare object.
48+
// After being done just luaM_free on the prepare object.
49+
void ws2812_buffer_shift_prepared(ws2812_buffer_shift_prepare* prepare);
50+
ws2812_buffer_shift_prepare* ws2812_buffer_get_shift_prepare(lua_State* L, ws2812_buffer * buffer, int shiftValue, unsigned shift_type, int pos_start, int pos_end);
51+
3052
int ws2812_buffer_fill(ws2812_buffer * buffer, int * colors);
53+
void ws2812_buffer_fade(ws2812_buffer * buffer, int fade, unsigned direction);
3154

3255
#endif /* APP_MODULES_WS2812_H_ */

0 commit comments

Comments
 (0)