ws2801.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #include "module.h"
  2. #include "lauxlib.h"
  3. #include "platform.h"
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "osapi.h"
  7. #include "pixbuf.h"
  8. /**
  9. * Code is based on https://github.com/CHERTS/esp8266-devkit/blob/master/Espressif/examples/EspLightNode/user/ws2801.c
  10. * and provides a similar api as the ws2812 module.
  11. * The current implementation allows the caller to use
  12. * any combination of GPIO0, GPIO2, GPIO4, GPIO5 as clock and data.
  13. */
  14. #define PIN_CLK_DEFAULT 0
  15. #define PIN_DATA_DEFAULT 2
  16. static uint32_t ws2801_bit_clk;
  17. static uint32_t ws2801_bit_data;
  18. static void ws2801_byte(uint8_t n) {
  19. uint8_t bitmask;
  20. for (bitmask = 0x80; bitmask !=0 ; bitmask >>= 1) {
  21. if (n & bitmask) {
  22. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, ws2801_bit_data);
  23. } else {
  24. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_data);
  25. }
  26. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, ws2801_bit_clk);
  27. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_clk);
  28. }
  29. }
  30. static void ws2801_color(uint8_t r, uint8_t g, uint8_t b) {
  31. ws2801_byte(r);
  32. ws2801_byte(g);
  33. ws2801_byte(b);
  34. }
  35. static void ws2801_strip(uint8_t const * data, uint16_t len) {
  36. while (len--) {
  37. ws2801_byte(*(data++));
  38. }
  39. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_data);
  40. }
  41. static void enable_pin_mux(int pin) {
  42. // The API only supports setting PERIPHS_IO_MUX on GPIO 0, 2, 4, 5
  43. switch (pin) {
  44. case 0:
  45. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
  46. break;
  47. case 2:
  48. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  49. break;
  50. case 4:
  51. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
  52. break;
  53. case 5:
  54. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
  55. break;
  56. default:
  57. break;
  58. }
  59. }
  60. /* Lua: ws2801.init(pin_clk, pin_data)
  61. * Sets up the GPIO pins
  62. *
  63. * ws2801.init(0, 2) uses GPIO0 as clock and GPIO2 as data.
  64. * This is the default behavior.
  65. */
  66. static int ICACHE_FLASH_ATTR ws2801_init_lua(lua_State* L) {
  67. uint32_t pin_clk;
  68. uint32_t pin_data;
  69. uint32_t func_gpio_clk;
  70. uint32_t func_gpio_data;
  71. if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
  72. // Use default pins if the input is omitted
  73. pin_clk = PIN_CLK_DEFAULT;
  74. pin_data = PIN_DATA_DEFAULT;
  75. } else {
  76. pin_clk = luaL_checkinteger(L, 1);
  77. pin_data = luaL_checkinteger(L, 2);
  78. }
  79. ws2801_bit_clk = 1 << pin_clk;
  80. ws2801_bit_data = 1 << pin_data;
  81. os_delay_us(10);
  82. //Set GPIO pins to output mode
  83. enable_pin_mux(pin_clk);
  84. enable_pin_mux(pin_data);
  85. //Set both GPIOs low low
  86. gpio_output_set(0, ws2801_bit_clk | ws2801_bit_data, ws2801_bit_clk | ws2801_bit_data, 0);
  87. os_delay_us(10);
  88. }
  89. /* Lua: ws2801.write(pin, "string")
  90. * Byte triples in the string are interpreted as R G B values.
  91. * This function does not corrupt your buffer.
  92. *
  93. * ws2801.write(string.char(255, 0, 0)) sets the first LED red.
  94. * ws2801.write(string.char(0, 0, 255):rep(10)) sets ten LEDs blue.
  95. * ws2801.write(string.char(0, 255, 0, 255, 255, 255)) first LED green, second LED white.
  96. */
  97. static int ICACHE_FLASH_ATTR ws2801_writergb(lua_State* L) {
  98. size_t length;
  99. const uint8_t *values;
  100. switch(lua_type(L,1)) {
  101. case LUA_TSTRING:
  102. values = (const uint8_t*) luaL_checklstring(L, 1, &length);
  103. break;
  104. case LUA_TUSERDATA: {
  105. pixbuf *buffer = pixbuf_from_lua_arg(L, 1);
  106. luaL_argcheck(L, buffer->nchan == 3, 1, "Pixbuf not 3-channel");
  107. values = buffer->values;
  108. length = pixbuf_size(buffer);
  109. break;
  110. }
  111. default:
  112. return luaL_argerror(L, 1, "pixbuf or string expected");
  113. }
  114. os_delay_us(10);
  115. ets_intr_lock();
  116. ws2801_strip(values, length);
  117. ets_intr_unlock();
  118. return 0;
  119. }
  120. LROT_BEGIN(ws2801, NULL, 0)
  121. LROT_FUNCENTRY( write, ws2801_writergb )
  122. LROT_FUNCENTRY( init, ws2801_init_lua )
  123. LROT_END(ws2801, NULL, 0)
  124. NODEMCU_MODULE(WS2801, "ws2801", ws2801, NULL);