Browse Source

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
Konrad Hübner 8 years ago
parent
commit
500bbceded
2 changed files with 118 additions and 10 deletions
  1. 95 7
      app/modules/ws2812.c
  2. 23 3
      docs/en/modules/ws2812.md

+ 95 - 7
app/modules/ws2812.c

@@ -6,9 +6,16 @@
 #include "c_string.h"
 #include "user_interface.h"
 #include "driver/uart.h"
+#include "osapi.h"
 
 #define CANARY_VALUE 0x32383132
 
+#define FADE_IN  1
+#define FADE_OUT 0
+#define SHIFT_LOGICAL  0
+#define SHIFT_CIRCULAR 1
+
+
 typedef struct {
   int canary;
   int size;
@@ -151,20 +158,96 @@ static int ws2812_buffer_fill(lua_State* L) {
 static int ws2812_buffer_fade(lua_State* L) {
   ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 1);
   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, fade > 0, 2, "fade value should be a strict positive number");
 
   uint8_t * p = &buffer->values[0];
+  int val = 0;
   int 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;
 }
 
+
+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) {
   ws2812_buffer * buffer = (ws2812_buffer*)lua_touserdata(L, 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[] =
 {
-  { LSTRKEY( "fade" ),  LFUNCVAL( ws2812_buffer_fade )},
-  { LSTRKEY( "fill" ),  LFUNCVAL( ws2812_buffer_fill )},
-  { LSTRKEY( "get" ),   LFUNCVAL( ws2812_buffer_get )},
-  { LSTRKEY( "set" ),   LFUNCVAL( ws2812_buffer_set )},
-  { LSTRKEY( "size" ),  LFUNCVAL( ws2812_buffer_size )},
-  { LSTRKEY( "write" ), LFUNCVAL( ws2812_buffer_write )},
+  { LSTRKEY( "fade" ),    LFUNCVAL( ws2812_buffer_fade )},
+  { LSTRKEY( "shift" ),  LFUNCVAL( ws2812_buffer_shift )},
+  { LSTRKEY( "fill" ),    LFUNCVAL( ws2812_buffer_fill )},
+  { LSTRKEY( "get" ),     LFUNCVAL( ws2812_buffer_get )},
+  { LSTRKEY( "set" ),     LFUNCVAL( ws2812_buffer_set )},
+  { LSTRKEY( "size" ),    LFUNCVAL( ws2812_buffer_size )},
+  { LSTRKEY( "write" ),   LFUNCVAL( ws2812_buffer_write )},
   { LSTRKEY( "__index" ), LROVAL ( ws2812_buffer_map )},
   { LNILKEY, LNILVAL}
 };
@@ -267,6 +351,10 @@ static const LUA_REG_TYPE ws2812_map[] =
   { LSTRKEY( "write" ), LFUNCVAL( ws2812_writegrb )},
   { LSTRKEY( "newBuffer" ), LFUNCVAL( ws2812_new_buffer )},
   { 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}
 };
 

+ 23 - 3
docs/en/modules/ws2812.md

@@ -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
 ```
 ## 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
-`buffer:fade(value)`
+`buffer:fade(value [, direction])`
 
 #### 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
 `nil`
@@ -149,7 +150,26 @@ Divide each byte of each led by the given value. Useful for a fading effect
 #### Example
 ```lua
 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()
 Output the buffer to the led strip