added fadeIn, faceOut and shift to ws2812 module (#1343)

* added fadeIn, faceOut and shift to ws2812 module

* improvements to rotate, unified fade method

shift renamed to rotate and usage of more efficient memory operations.
fadeIn and fadeOut unified into fade method with optional parameter for direction.

* rename method to "shift" with optional mode parameter
This commit is contained in:
Konrad Hübner 2016-06-10 22:23:37 +02:00 committed by Arnim Läuger
parent 7dd89dd15e
commit 500bbceded
2 changed files with 118 additions and 10 deletions

View File

@ -6,9 +6,16 @@
#include "c_string.h" #include "c_string.h"
#include "user_interface.h" #include "user_interface.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "osapi.h"
#define CANARY_VALUE 0x32383132 #define CANARY_VALUE 0x32383132
#define FADE_IN 1
#define FADE_OUT 0
#define SHIFT_LOGICAL 0
#define SHIFT_CIRCULAR 1
typedef struct { typedef struct {
int canary; int canary;
int size; int size;
@ -151,20 +158,96 @@ static int ws2812_buffer_fill(lua_State* L) {
static int ws2812_buffer_fade(lua_State* L) { static int ws2812_buffer_fade(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
const int fade = luaL_checkinteger(L, 2); const int fade = luaL_checkinteger(L, 2);
unsigned direction = luaL_optinteger( L, 3, FADE_OUT );
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected"); luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number"); luaL_argcheck(L, fade > 0, 2, "fade value should be a strict positive number");
uint8_t * p = &buffer->values[0]; uint8_t * p = &buffer->values[0];
int val = 0;
int i; int i;
for(i = 0; i < buffer->size * buffer->colorsPerLed; i++) for(i = 0; i < buffer->size * buffer->colorsPerLed; i++)
{ {
*p++ /= fade; if (direction == FADE_OUT)
{
*p++ /= fade;
}
else
{
// as fade in can result in value overflow, an int is used to perform the check afterwards
val = *p * fade;
if (val > 255) val = 255;
*p++ = val;
}
} }
return 0; return 0;
} }
static int ws2812_buffer_shift(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
const int shiftValue = luaL_checkinteger(L, 2);
const unsigned shift_type = luaL_optinteger( L, 3, SHIFT_LOGICAL );
luaL_argcheck(L, buffer && buffer->canary == CANARY_VALUE, 1, "ws2812.buffer expected");
luaL_argcheck(L, shiftValue > 0-buffer->size && shiftValue < buffer->size, 2, "shifting more elements than buffer size");
int shift = shiftValue >= 0 ? shiftValue : -shiftValue;
// check if we want to shift at all
if (shift == 0)
{
return 0;
}
uint8_t * tmp_pixels = luaM_malloc(L, buffer->colorsPerLed * sizeof(uint8_t) * shift);
int i,j;
size_t shift_len, remaining_len;
// calculate length of shift section and remaining section
shift_len = shift*buffer->colorsPerLed;
remaining_len = (buffer->size-shift)*buffer->colorsPerLed;
if (shiftValue > 0)
{
// Store the values which are moved out of the array (last n pixels)
c_memcpy(tmp_pixels, &buffer->values[(buffer->size-shift)*buffer->colorsPerLed], shift_len);
// Move pixels to end
os_memmove(&buffer->values[shift*buffer->colorsPerLed], &buffer->values[0], remaining_len);
// Fill beginning with temp data
if (shift_type == SHIFT_LOGICAL)
{
c_memset(&buffer->values[0], 0, shift_len);
}
else
{
c_memcpy(&buffer->values[0], tmp_pixels, shift_len);
}
}
else
{
// Store the values which are moved out of the array (last n pixels)
c_memcpy(tmp_pixels, &buffer->values[0], shift_len);
// Move pixels to end
os_memmove(&buffer->values[0], &buffer->values[shift*buffer->colorsPerLed], remaining_len);
// Fill beginning with temp data
if (shift_type == SHIFT_LOGICAL)
{
c_memset(&buffer->values[(buffer->size-shift)*buffer->colorsPerLed], 0, shift_len);
}
else
{
c_memcpy(&buffer->values[(buffer->size-shift)*buffer->colorsPerLed], tmp_pixels, shift_len);
}
}
// Free memory
luaM_free(L, tmp_pixels);
return 0;
}
static int ws2812_buffer_get(lua_State* L) { static int ws2812_buffer_get(lua_State* L) {
ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1); ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
const int led = luaL_checkinteger(L, 2) - 1; const int led = luaL_checkinteger(L, 2) - 1;
@ -252,12 +335,13 @@ static int ws2812_buffer_write(lua_State* L) {
static const LUA_REG_TYPE ws2812_buffer_map[] = static const LUA_REG_TYPE ws2812_buffer_map[] =
{ {
{ LSTRKEY( "fade" ), LFUNCVAL( ws2812_buffer_fade )}, { LSTRKEY( "fade" ), LFUNCVAL( ws2812_buffer_fade )},
{ LSTRKEY( "fill" ), LFUNCVAL( ws2812_buffer_fill )}, { LSTRKEY( "shift" ), LFUNCVAL( ws2812_buffer_shift )},
{ LSTRKEY( "get" ), LFUNCVAL( ws2812_buffer_get )}, { LSTRKEY( "fill" ), LFUNCVAL( ws2812_buffer_fill )},
{ LSTRKEY( "set" ), LFUNCVAL( ws2812_buffer_set )}, { LSTRKEY( "get" ), LFUNCVAL( ws2812_buffer_get )},
{ LSTRKEY( "size" ), LFUNCVAL( ws2812_buffer_size )}, { LSTRKEY( "set" ), LFUNCVAL( ws2812_buffer_set )},
{ LSTRKEY( "write" ), LFUNCVAL( ws2812_buffer_write )}, { LSTRKEY( "size" ), LFUNCVAL( ws2812_buffer_size )},
{ LSTRKEY( "write" ), LFUNCVAL( ws2812_buffer_write )},
{ LSTRKEY( "__index" ), LROVAL ( ws2812_buffer_map )}, { LSTRKEY( "__index" ), LROVAL ( ws2812_buffer_map )},
{ LNILKEY, LNILVAL} { LNILKEY, LNILVAL}
}; };
@ -267,6 +351,10 @@ static const LUA_REG_TYPE ws2812_map[] =
{ LSTRKEY( "write" ), LFUNCVAL( ws2812_writegrb )}, { LSTRKEY( "write" ), LFUNCVAL( ws2812_writegrb )},
{ LSTRKEY( "newBuffer" ), LFUNCVAL( ws2812_new_buffer )}, { LSTRKEY( "newBuffer" ), LFUNCVAL( ws2812_new_buffer )},
{ LSTRKEY( "init" ), LFUNCVAL( ws2812_init )}, { LSTRKEY( "init" ), LFUNCVAL( ws2812_init )},
{ LSTRKEY( "FADE_IN" ), LNUMVAL( FADE_IN ) },
{ LSTRKEY( "FADE_OUT" ),LNUMVAL( FADE_OUT ) },
{ LSTRKEY( "SHIFT_LOGICAL" ),LNUMVAL( SHIFT_LOGICAL ) },
{ LSTRKEY( "SHIFT_CIRCULAR" ),LNUMVAL( SHIFT_CIRCULAR ) },
{ LNILKEY, LNILVAL} { LNILKEY, LNILVAL}
}; };

View File

@ -135,13 +135,14 @@ The number of given bytes must match the number of bytesPerLed of the buffer
buffer:fill(0, 0, 0) -- fill the buffer with black for a RGB strip buffer:fill(0, 0, 0) -- fill the buffer with black for a RGB strip
``` ```
## ws2812.buffer:fade() ## ws2812.buffer:fade()
Divide each byte of each led by the given value. Useful for a fading effect Fade in or out. Defaults to out. Multiply or divide each byte of each led with/by the given value. Useful for a fading effect.
#### Syntax #### Syntax
`buffer:fade(value)` `buffer:fade(value [, direction])`
#### Parameters #### Parameters
- `value` value by which divide each byte - `value` value by which to divide or multiply each byte
- `direction` ws2812.FADE\_IN or ws2812.FADE\_OUT. Defaults to ws2812.FADE\_OUT
#### Returns #### Returns
`nil` `nil`
@ -149,7 +150,26 @@ Divide each byte of each led by the given value. Useful for a fading effect
#### Example #### Example
```lua ```lua
buffer:fade(2) buffer:fade(2)
buffer:fade(2, ws2812.FADE_IN)
``` ```
## ws2812.buffer:shift()
Shift the content of the buffer in positive or negative direction. This allows simple animation effects.
#### Syntax
`buffer:shift(value [, mode])`
#### Parameters
- `value` number of pixels by which to rotate the buffer. Positive values rotate forwards, negative values backwards.
- `mode` is the shift mode to use. Can be one of `ws2812.SHIFT_LOGICAL` or `ws2812.SHIFT_CIRCULAR`. In case of SHIFT\_LOGICAL, the freed pixels are set to 0 (off). In case of SHIFT\_CIRCULAR, the buffer is treated like a ring buffer, inserting the pixels falling out on one end again on the other end. Defaults to SHIFT\_LOGICAL.
#### Returns
`nil`
#### Example
```lua
buffer:shift(3)
```
## ws2812.buffer:write() ## ws2812.buffer:write()
Output the buffer to the led strip Output the buffer to the led strip