/* xdrv_52_3_berry_leds.ino - Berry scripting language, native fucnctions Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef USE_BERRY #include #ifdef USE_WS2812 #include enum { ws2812_grb = 1, sk6812_grbw = 2, neopixel_type_end }; typedef NeoPixelBus neopixel_ws2812_grb_t; typedef NeoPixelBus neopixel_sk6812_grbw_t; /*********************************************************************************************\ * Native functions mapped to Berry functions * * import unishox * * \*********************************************************************************************/ extern "C" { // # Native commands // # 00 : ctor // # 01 : begin void -> void // # 02 : show void -> void // # 03 : CanShow void -> bool // # 04 : IsDirty void -> bool // # 05 : Dirty void -> void // # 06 : Pixels void -> bytes() (mapped to the buffer) // # 07 : PixelSize void -> int // # 08 : PixelCount void -> int // # 09 : ClearTo (color:??) -> void // # 10 : SetPixelColor (idx:int, color:??) -> void // # 11 : GetPixelColor (idx:int) -> color:?? // # 20 : RotateLeft (rot:int [, first:int, last:int]) -> void // # 21 : RotateRight (rot:int [, first:int, last:int]) -> void // # 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void // # 23 : ShiftRight (rot:int [, first:int, last:int]) -> void void * be_get_neopixelbus(bvm *vm) { be_getmember(vm, 1, "_p"); void * strip = (void*) be_tocomptr(vm, -1); be_pop(vm, 1); if (strip == nullptr) { be_raise(vm, "internal_error", "neopixelbus object not initialized"); } return strip; } int32_t be_get_leds_type(bvm *vm) { be_getmember(vm, 1, "_t"); int32_t type = be_toint(vm, -1); be_pop(vm, 1); if (type <= 0 || type >= neopixel_type_end) { be_raise(vm, "internal_error", "invalid leds type"); } return type; } int be_neopixelbus_call_native(bvm *vm); int be_neopixelbus_call_native(bvm *vm) { int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 2 && be_isint(vm, 2)) { int32_t cmd = be_toint(vm, 2); if (0 == cmd) { // 00 : ctor (leds:int, gpio:int) -> void if (!(argc >= 6 && be_isint(vm, 3) && be_isint(vm, 4) && be_isint(vm, 5) && be_isint(vm, 6))) { be_raise(vm, "value_error", "bad arguments for neopixelbus:ctor"); } int32_t leds = be_toint(vm, 3); int32_t gpio = be_toint(vm, 4); int32_t neopixel_type = be_toint(vm, 5); int32_t rmt = be_toint(vm, 6); if (neopixel_type < 1) { neopixel_type = 1; } if (neopixel_type >= neopixel_type_end) { neopixel_type = neopixel_type_end - 1; } if (rmt < 0) { rmt = 0; } if (rmt >= MAX_RMT) { rmt = MAX_RMT - 1; } // store type in attribute `_t` be_pushint(vm, neopixel_type); be_setmember(vm, 1, "_t"); be_pop(vm, 1); void * strip = nullptr; switch (neopixel_type) { case ws2812_grb: strip = new neopixel_ws2812_grb_t(leds, gpio, (NeoBusChannel) rmt); break; case sk6812_grbw: strip = new neopixel_sk6812_grbw_t(leds, gpio, (NeoBusChannel) rmt); break; } be_pushcomptr(vm, (void*) strip); be_setmember(vm, 1, "_p"); be_pop(vm, 1); be_pushnil(vm); } else { // all other commands need a valid neopixelbus pointer int32_t leds_type = be_get_leds_type(vm); const void * s = be_get_neopixelbus(vm); // raises an exception if pointer is invalid // initialize all possible variants neopixel_ws2812_grb_t * s_ws2812_grb = (leds_type == ws2812_grb) ? (neopixel_ws2812_grb_t*) s : nullptr; neopixel_sk6812_grbw_t * s_sk6812_grbw = (leds_type == sk6812_grbw) ? (neopixel_sk6812_grbw_t*) s : nullptr; be_pushnil(vm); // push a default `nil` return value switch (cmd) { case 1: // # 01 : begin void -> void if (s_ws2812_grb) s_ws2812_grb->Begin(); if (s_sk6812_grbw) s_sk6812_grbw->Begin(); break; case 2: // # 02 : show void -> void if (s_ws2812_grb) s_ws2812_grb->Show(); if (s_sk6812_grbw) s_sk6812_grbw->Show(); break; case 3: // # 03 : CanShow void -> bool if (s_ws2812_grb) be_pushbool(vm, s_ws2812_grb->CanShow()); if (s_sk6812_grbw) be_pushbool(vm, s_sk6812_grbw->CanShow()); break; case 4: // # 04 : IsDirty void -> bool if (s_ws2812_grb) be_pushbool(vm, s_ws2812_grb->IsDirty()); if (s_sk6812_grbw) be_pushbool(vm, s_sk6812_grbw->IsDirty()); break; case 5: // # 05 : Dirty void -> void if (s_ws2812_grb) s_ws2812_grb->Dirty(); if (s_sk6812_grbw) s_sk6812_grbw->Dirty(); break; case 6: // # 06 : Pixels void -> bytes() (mapped to the buffer) { size_t pixels_bytes; if (s_ws2812_grb) pixels_bytes = s_ws2812_grb->PixelsSize(); if (s_sk6812_grbw) pixels_bytes = s_sk6812_grbw->PixelsSize(); uint8_t * pixels; if (s_ws2812_grb) pixels = s_ws2812_grb->Pixels(); if (s_sk6812_grbw) pixels = s_sk6812_grbw->Pixels(); be_getbuiltin(vm, "bytes"); be_pushcomptr(vm, pixels); be_pushint(vm, pixels_bytes); be_call(vm, 2); be_pop(vm, 2); } break; case 7: // # 07 : PixelSize void -> int if (s_ws2812_grb) be_pushint(vm, s_ws2812_grb->PixelSize()); if (s_sk6812_grbw) be_pushint(vm, s_sk6812_grbw->PixelSize()); break; case 8: // # 08 : PixelCount void -> int if (s_ws2812_grb) be_pushint(vm, s_ws2812_grb->PixelCount()); if (s_sk6812_grbw) be_pushint(vm, s_sk6812_grbw->PixelCount()); break; case 9: // # 09 : ClearTo (color:??) -> void { uint32_t rgbw = be_toint(vm, 3); uint8_t w = (rgbw & 0xFF000000) >> 24; uint8_t r = (rgbw & 0xFF0000) >> 16; uint8_t g = (rgbw & 0xFF00) >> 8; uint8_t b = (rgbw & 0xFF); if (s_ws2812_grb) s_ws2812_grb->ClearTo(RgbColor(r, g, b)); if (s_sk6812_grbw) s_sk6812_grbw->ClearTo(RgbwColor(r, g, b, 0)); } break; case 10: // # 10 : SetPixelColor (idx:int, color:??) -> void { int32_t idx = be_toint(vm, 3); uint32_t rgbw = be_toint(vm, 4); uint8_t w = (rgbw & 0xFF000000) >> 24; uint8_t r = (rgbw & 0xFF0000) >> 16; uint8_t g = (rgbw & 0xFF00) >> 8; uint8_t b = (rgbw & 0xFF); if (s_ws2812_grb) s_ws2812_grb->SetPixelColor(idx, RgbColor(r, g, b)); if (s_sk6812_grbw) s_sk6812_grbw->SetPixelColor(idx, RgbwColor(r, g, b, 0)); } break; case 11: // # 11 : GetPixelColor (idx:int) -> color:?? { int32_t idx = be_toint(vm, 3); RgbColor rgb; if (s_ws2812_grb) { RgbColor rgb = s_ws2812_grb->GetPixelColor(idx); be_pushint(vm, (rgb.R << 16) | (rgb.G << 8) | rgb.B); } if (s_sk6812_grbw) { RgbwColor rgbw = s_sk6812_grbw->GetPixelColor(idx); be_pushint(vm, (rgbw.W << 24) | (rgb.R << 16) | (rgb.G << 8) | rgb.B); } } break; default: break; } } be_return(vm); } be_raise(vm, kTypeError, nullptr); } } #endif // USE_WS2812 #endif // USE_BERRY