2019-07-21 23:58:21 +02:00
# include <stdlib.h>
# include <string.h>
2015-12-09 22:35:50 +01:00
# include "lauxlib.h"
2016-01-26 23:14:19 +01:00
# include "module.h"
# include "platform.h"
2015-12-09 22:35:50 +01:00
# include "user_interface.h"
2021-01-07 00:35:34 +01:00
# include "pixbuf.h"
2015-12-09 22:35:50 +01:00
# define NOP asm volatile(" nop \n\t")
static inline void apa102_send_byte ( uint32_t data_pin , uint32_t clock_pin , uint8_t byte ) {
int i ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( byte & 0x80 ) {
GPIO_OUTPUT_SET ( data_pin , PLATFORM_GPIO_HIGH ) ; // Set pin high
} else {
GPIO_OUTPUT_SET ( data_pin , PLATFORM_GPIO_LOW ) ; // Set pin low
}
GPIO_OUTPUT_SET ( clock_pin , PLATFORM_GPIO_HIGH ) ; // Set pin high
byte < < = 1 ;
NOP ;
NOP ;
GPIO_OUTPUT_SET ( clock_pin , PLATFORM_GPIO_LOW ) ; // Set pin low
NOP ;
NOP ;
}
}
static void apa102_send_buffer ( uint32_t data_pin , uint32_t clock_pin , uint32_t * buf , uint32_t nbr_frames ) {
int i ;
// Send 32-bit Start Frame that's all 0x00
apa102_send_byte ( data_pin , clock_pin , 0x00 ) ;
apa102_send_byte ( data_pin , clock_pin , 0x00 ) ;
apa102_send_byte ( data_pin , clock_pin , 0x00 ) ;
apa102_send_byte ( data_pin , clock_pin , 0x00 ) ;
// Send 32-bit LED Frames
for ( i = 0 ; i < nbr_frames ; i + + ) {
uint8_t * byte = ( uint8_t * ) buf + + ;
// Set the first 3 bits of that byte to 1.
// This makes the lua interface easier to use since you
// don't have to worry about creating invalid LED Frames.
byte [ 0 ] | = 0xE0 ;
apa102_send_byte ( data_pin , clock_pin , byte [ 0 ] ) ;
apa102_send_byte ( data_pin , clock_pin , byte [ 1 ] ) ;
apa102_send_byte ( data_pin , clock_pin , byte [ 2 ] ) ;
apa102_send_byte ( data_pin , clock_pin , byte [ 3 ] ) ;
}
// Send 32-bit End Frames
uint32_t required_postamble_frames = ( nbr_frames + 1 ) / 2 ;
for ( i = 0 ; i < required_postamble_frames ; i + + ) {
apa102_send_byte ( data_pin , clock_pin , 0xFF ) ;
apa102_send_byte ( data_pin , clock_pin , 0xFF ) ;
apa102_send_byte ( data_pin , clock_pin , 0xFF ) ;
apa102_send_byte ( data_pin , clock_pin , 0xFF ) ;
}
}
// Lua: apa102.write(data_pin, clock_pin, "string")
// Byte quads in the string are interpreted as (brightness, B, G, R) values.
// Only the first 5 bits of the brightness value is actually used (0-31).
// This function does not corrupt your buffer.
//
// apa102.write(1, 3, string.char(31, 0, 255, 0)) uses GPIO5 for DATA and GPIO0 for CLOCK and sets the first LED green, with the brightness 31 (out of 0-32)
// apa102.write(5, 6, string.char(255, 0, 0, 255):rep(10)) uses GPIO14 for DATA and GPIO12 for CLOCK and sets ten LED to red, with the brightness 31 (out of 0-32).
// Brightness values are clamped to 0-31.
static int apa102_write ( lua_State * L ) {
uint8_t data_pin = luaL_checkinteger ( L , 1 ) ;
MOD_CHECK_ID ( gpio , data_pin ) ;
uint32_t alt_data_pin = pin_num [ data_pin ] ;
uint8_t clock_pin = luaL_checkinteger ( L , 2 ) ;
MOD_CHECK_ID ( gpio , clock_pin ) ;
uint32_t alt_clock_pin = pin_num [ clock_pin ] ;
2021-01-07 00:35:34 +01:00
const char * buf ;
uint32_t nbr_frames ;
switch ( lua_type ( L , 3 ) ) {
case LUA_TSTRING : {
size_t buf_len ;
buf = luaL_checklstring ( L , 3 , & buf_len ) ;
nbr_frames = buf_len / 4 ;
break ;
}
2021-02-14 08:41:17 +01:00
# ifdef LUA_USE_MODULES_PIXBUF
2021-01-07 00:35:34 +01:00
case LUA_TUSERDATA : {
pixbuf * buffer = pixbuf_from_lua_arg ( L , 3 ) ;
luaL_argcheck ( L , buffer - > nchan = = 4 , 3 , " Pixbuf not 4-channel " ) ;
buf = ( const char * ) buffer - > values ;
nbr_frames = buffer - > npix ;
break ;
}
2021-02-14 08:41:17 +01:00
# endif
2021-01-07 00:35:34 +01:00
default :
return luaL_argerror ( L , 3 , " String or pixbuf expected " ) ;
}
2015-12-09 22:35:50 +01:00
// Initialize the output pins
platform_gpio_mode ( data_pin , PLATFORM_GPIO_OUTPUT , PLATFORM_GPIO_FLOAT ) ;
GPIO_OUTPUT_SET ( alt_data_pin , PLATFORM_GPIO_HIGH ) ; // Set pin high
platform_gpio_mode ( clock_pin , PLATFORM_GPIO_OUTPUT , PLATFORM_GPIO_FLOAT ) ;
GPIO_OUTPUT_SET ( alt_clock_pin , PLATFORM_GPIO_LOW ) ; // Set pin low
// Send the buffers
apa102_send_buffer ( alt_data_pin , alt_clock_pin , ( uint32_t * ) buf , ( uint32_t ) nbr_frames ) ;
return 0 ;
}
2020-04-27 02:13:38 +02:00
LROT_BEGIN ( apa102 , NULL , 0 )
2019-05-08 13:08:20 +02:00
LROT_FUNCENTRY ( write , apa102_write )
2020-04-27 02:13:38 +02:00
LROT_END ( apa102 , NULL , 0 )
2019-05-08 13:08:20 +02:00
2015-12-09 22:35:50 +01:00
2020-04-27 02:13:38 +02:00
NODEMCU_MODULE ( APA102 , " apa102 " , apa102 , NULL ) ;