// Module for Ucglib #include "module.h" #include "lauxlib.h" #include "ucg.h" #include "ucg_nodemcu_hal.h" #include "ucg_config.h" #ifdef ESP_PLATFORM // ESP32 #include "spi_common.h" #include "sdkconfig.h" #endif #ifndef CONFIG_NODEMCU_CMODULE_UCG // ignore unused functions if ucg module will be skipped anyhow #pragma GCC diagnostic ignored "-Wunused-function" #endif typedef struct { ucg_nodemcu_t ucg; ucg_dev_fnptr dev_cb; ucg_dev_fnptr ext_cb; // For Print() function ucg_int_t tx, ty; uint8_t tdir; int font_ref; int host_ref; } ucg_ud_t; // shorthand macro for the ucg structure inside the userdata #define GET_UCG() \ ucg_ud_t *ud = (ucg_ud_t *)luaL_checkudata( L, 1, "ucg.display" ); \ ucg_t *ucg = (ucg_t *)(&(ud->ucg)); // helper function: retrieve given number of integer arguments static void lucg_get_int_args( lua_State *L, uint8_t stack, uint8_t num, ucg_int_t *args) { while (num-- > 0) { *args++ = luaL_checkinteger( L, stack++ ); } } // Lua: ucg.begin( self, fontmode ) static int lucg_begin( lua_State *L ) { GET_UCG(); ucg_Init( ucg, ud->dev_cb, ud->ext_cb, ucg_com_nodemcu_hw_spi ); ucg_int_t fontmode = luaL_checkinteger( L, 2 ); ucg_SetFontMode( ucg, fontmode ); return 0; } // Lua: ucg.clearScreen( self ) static int lucg_clearScreen( lua_State *L ) { GET_UCG(); ucg_ClearScreen( ucg ); return 0; } // Lua: ucg.draw90Line( self, x, y, len, dir, col_idx ) static int lucg_draw90Line( lua_State *L ) { GET_UCG(); ucg_int_t args[5]; lucg_get_int_args( L, 2, 5, args ); ucg_Draw90Line( ucg, args[0], args[1], args[2], args[3], args[4] ); return 0; } // Lua: ucg.drawBox( self, x, y, w, h ) static int lucg_drawBox( lua_State *L ) { GET_UCG(); ucg_int_t args[4]; lucg_get_int_args( L, 2, 4, args ); ucg_DrawBox( ucg, args[0], args[1], args[2], args[3] ); return 0; } // Lua: ucg.drawCircle( self, x0, y0, rad, option ) static int lucg_drawCircle( lua_State *L ) { GET_UCG(); ucg_int_t args[4]; lucg_get_int_args( L, 2, 4, args ); ucg_DrawCircle( ucg, args[0], args[1], args[2], args[3] ); return 0; } // Lua: ucg.drawDisc( self, x0, y0, rad, option ) static int lucg_drawDisc( lua_State *L ) { GET_UCG(); ucg_int_t args[4]; lucg_get_int_args( L, 2, 4, args ); ucg_DrawDisc( ucg, args[0], args[1], args[2], args[3] ); return 0; } // Lua: ucg.drawFrame( self, x, y, w, h ) static int lucg_drawFrame( lua_State *L ) { GET_UCG(); ucg_int_t args[4]; lucg_get_int_args( L, 2, 4, args ); ucg_DrawFrame( ucg, args[0], args[1], args[2], args[3] ); return 0; } // Lua: ucg.drawGradientBox( self, x, y, w, h ) static int lucg_drawGradientBox( lua_State *L ) { GET_UCG(); ucg_int_t args[4]; lucg_get_int_args( L, 2, 4, args ); ucg_DrawGradientBox( ucg, args[0], args[1], args[2], args[3] ); return 0; } // Lua: width = ucg.drawGlyph( self, x, y, dir, encoding ) static int lucg_drawGlyph( lua_State *L ) { GET_UCG(); ucg_int_t args[3]; lucg_get_int_args( L, 2, 3, args ); const char *c = luaL_checkstring( L, (1+3) + 1 ); if (c == NULL) return 0; lua_pushinteger( L, ucg_DrawGlyph( ucg, args[0], args[1], args[2], *c ) ); return 1; } // Lua: ucg.drawGradientLine( self, x, y, len, dir ) static int lucg_drawGradientLine( lua_State *L ) { GET_UCG(); ucg_int_t args[4]; lucg_get_int_args( L, 2, 4, args ); ucg_DrawGradientLine( ucg, args[0], args[1], args[2], args[3] ); return 0; } // Lua: ucg.drawHLine( self, x, y, len ) static int lucg_drawHLine( lua_State *L ) { GET_UCG(); ucg_int_t args[3]; lucg_get_int_args( L, 2, 3, args ); ucg_DrawHLine( ucg, args[0], args[1], args[2] ); return 0; } // Lua: ucg.drawLine( self, x1, y1, x2, y2 ) static int lucg_drawLine( lua_State *L ) { GET_UCG(); ucg_int_t args[4]; lucg_get_int_args( L, 2, 4, args ); ucg_DrawLine( ucg, args[0], args[1], args[2], args[3] ); return 0; } // Lua: ucg.drawPixel( self, x, y ) static int lucg_drawPixel( lua_State *L ) { GET_UCG(); ucg_int_t args[2]; lucg_get_int_args( L, 2, 2, args ); ucg_DrawPixel( ucg, args[0], args[1] ); return 0; } // Lua: ucg.drawRBox( self, x, y, w, h, r ) static int lucg_drawRBox( lua_State *L ) { GET_UCG(); ucg_int_t args[5]; lucg_get_int_args( L, 2, 5, args ); ucg_DrawRBox( ucg, args[0], args[1], args[2], args[3], args[4] ); return 0; } // Lua: ucg.drawRFrame( self, x, y, w, h, r ) static int lucg_drawRFrame( lua_State *L ) { GET_UCG(); ucg_int_t args[5]; lucg_get_int_args( L, 2, 5, args ); ucg_DrawRFrame( ucg, args[0], args[1], args[2], args[3], args[4] ); return 0; } // Lua: width = ucg.drawString( self, x, y, dir, str ) static int lucg_drawString( lua_State *L ) { GET_UCG(); ucg_int_t args[3]; lucg_get_int_args( L, 2, 3, args ); const char *s = luaL_checkstring( L, (1+3) + 1 ); if (s == NULL) return 0; lua_pushinteger( L, ucg_DrawString( ucg, args[0], args[1], args[2], s ) ); return 1; } // Lua: ucg.drawTetragon( self, x0, y0, x1, y1, x2, y2, x3, y3 ) static int lucg_drawTetragon( lua_State *L ) { GET_UCG(); ucg_int_t args[8]; lucg_get_int_args( L, 2, 8, args ); ucg_DrawTetragon( ucg, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7] ); return 0; } // Lua: ucg.drawTriangle( self, x0, y0, x1, y1, x2, y2 ) static int lucg_drawTriangle( lua_State *L ) { GET_UCG(); ucg_int_t args[6]; lucg_get_int_args( L, 2, 6, args ); ucg_DrawTriangle( ucg, args[0], args[1], args[2], args[3], args[4], args[5] ); return 0; } // Lua: ucg.drawVLine( self, x, y, len ) static int lucg_drawVLine( lua_State *L ) { GET_UCG(); ucg_int_t args[3]; lucg_get_int_args( L, 2, 3, args ); ucg_DrawVLine( ucg, args[0], args[1], args[2] ); return 0; } // Lua: height = ucg.getFontAscent( self ) static int lucg_getFontAscent( lua_State *L ) { GET_UCG(); lua_pushinteger( L, ucg_GetFontAscent( ucg ) ); return 1; } // Lua: height = ucg.getFontDescent( self ) static int lucg_getFontDescent( lua_State *L ) { GET_UCG(); lua_pushinteger( L, ucg_GetFontDescent( ucg ) ); return 1; } // Lua: height = ucg.getHeight( self ) static int lucg_getHeight( lua_State *L ) { GET_UCG(); lua_pushinteger( L, ucg_GetHeight( ucg ) ); return 1; } // Lua: width = ucg.getStrWidth( self, string ) static int lucg_getStrWidth( lua_State *L ) { GET_UCG(); const char *s = luaL_checkstring( L, 2 ); if (s == NULL) return 0; lua_pushinteger( L, ucg_GetStrWidth( ucg, s ) ); return 1; } // Lua: width = ucg.getWidth( self ) static int lucg_getWidth( lua_State *L ) { GET_UCG(); lua_pushinteger( L, ucg_GetWidth( ucg ) ); return 1; } // Lua: ucg.setClipRange( self, x, y, w, h ) static int lucg_setClipRange( lua_State *L ) { GET_UCG(); ucg_int_t args[4]; lucg_get_int_args( L, 2, 4, args ); ucg_SetClipRange( ucg, args[0], args[1], args[2], args[3] ); return 0; } // Lua: ucg.setColor( self, [idx], r, g, b ) static int lucg_setColor( lua_State *L ) { GET_UCG(); ucg_int_t args[3]; lucg_get_int_args( L, 2, 3, args ); ucg_int_t opt = luaL_optint( L, (1+3) + 1, -1 ); if (opt < 0) { ucg_SetColor( ucg, 0, args[0], args[1], args[2] ); } else { ucg_SetColor( ucg, args[0], args[1], args[2], opt ); } return 0; } // Lua: ucg.setFont( self, font ) static int lucg_setFont( lua_State *L ) { GET_UCG(); ucg_fntpgm_uint8_t *font = (ucg_fntpgm_uint8_t *)lua_touserdata( L, 2 ); if (font != NULL) ucg_SetFont( ucg, font ); else luaL_argerror(L, 2, "font data expected"); return 0; } // Lua: ucg.print( self, str ) static int lucg_print( lua_State *L ) { GET_UCG(); const char *s = luaL_checkstring( L, 2 ); if (s == NULL) return 0; while (*s) { ucg_int_t delta; delta = ucg_DrawGlyph(ucg, ud->tx, ud->ty, ud->tdir, *(s++)); switch(ud->tdir) { case 0: ud->tx += delta; break; case 1: ud->ty += delta; break; case 2: ud->tx -= delta; break; default: case 3: ud->ty -= delta; break; } } return 0; } // Lua: ucg.setFontMode( self, fontmode ) static int lucg_setFontMode( lua_State *L ) { GET_UCG(); ucg_int_t fontmode = luaL_checkinteger( L, 2 ); ucg_SetFontMode( ucg, fontmode ); return 0; } // Lua: ucg.setFontPosBaseline( self ) static int lucg_setFontPosBaseline( lua_State *L ) { GET_UCG(); ucg_SetFontPosBaseline( ucg ); return 0; } // Lua: ucg.setFontPosBottom( self ) static int lucg_setFontPosBottom( lua_State *L ) { GET_UCG(); ucg_SetFontPosBottom( ucg ); return 0; } // Lua: ucg.setFontPosCenter( self ) static int lucg_setFontPosCenter( lua_State *L ) { GET_UCG(); ucg_SetFontPosCenter( ucg ); return 0; } // Lua: ucg.setFontPosTop( self ) static int lucg_setFontPosTop( lua_State *L ) { GET_UCG(); ucg_SetFontPosTop( ucg ); return 0; } // Lua: ucg.setMaxClipRange( self ) static int lucg_setMaxClipRange( lua_State *L ) { GET_UCG(); ucg_SetMaxClipRange( ucg ); return 0; } // Lua: ucg.setPrintPos( self, x, y ) static int lucg_setPrintPos( lua_State *L ) { GET_UCG(); (void)ucg; ucg_int_t args[2]; lucg_get_int_args( L, 2, 2, args ); ud->tx = args[0]; ud->ty = args[1]; return 0; } // Lua: ucg.setPrintDir( self, dir ) static int lucg_setPrintDir( lua_State *L ) { GET_UCG(); (void)ucg; ud->tdir = luaL_checkinteger( L, 2 ); return 0; } // Lua: ucg.setRotate90( self ) static int lucg_setRotate90( lua_State *L ) { GET_UCG(); ucg_SetRotate90( ucg ); return 0; } // Lua: ucg.setRotate180( self ) static int lucg_setRotate180( lua_State *L ) { GET_UCG(); ucg_SetRotate180( ucg ); return 0; } // Lua: ucg.setRotate270( self ) static int lucg_setRotate270( lua_State *L ) { GET_UCG(); ucg_SetRotate270( ucg ); return 0; } // Lua: ucg.setScale2x2( self ) static int lucg_setScale2x2( lua_State *L ) { GET_UCG(); ucg_SetScale2x2( ucg ); return 0; } // Lua: ucg.undoRotate( self ) static int lucg_undoRotate( lua_State *L ) { GET_UCG(); ucg_UndoRotate( ucg ); return 0; } // Lua: ucg.undoScale( self ) static int lucg_undoScale( lua_State *L ) { GET_UCG(); ucg_UndoScale( ucg ); return 0; } // device destructor static int lucg_close_display( lua_State *L ) { return 0; } // *************************************************************************** // Device constructors // // static int ldisplay_hw_spi( lua_State *L, ucg_dev_fnptr device, ucg_dev_fnptr extension ) { int stack = 0; #ifndef ESP_PLATFORM // ESP8266 typedef struct { int host; } lspi_host_t; lspi_host_t host_elem; lspi_host_t *host = &host_elem; #else // ESP32 lspi_host_t *host = NULL; #endif int host_ref = LUA_NOREF; int cs = -1; int dc = -1; int res = -1; int get_spi_pins; if (lua_type( L, ++stack ) == LUA_TUSERDATA) { host = (lspi_host_t *)luaL_checkudata( L, stack, "spi.master" ); /* reference host object to avoid automatic gc */ lua_pushvalue( L, stack ); host_ref = luaL_ref( L, LUA_REGISTRYINDEX ); get_spi_pins = 1; } else if (lua_type( L, stack ) == LUA_TNUMBER) { host->host = luaL_checkint( L, stack ); get_spi_pins = 1; } else { get_spi_pins = 0; stack--; } if (get_spi_pins) { cs = luaL_checkint( L, ++stack ); dc = luaL_checkint( L, ++stack ); res = luaL_optint( L, ++stack, -1 ); } ucg_ud_t *ud = (ucg_ud_t *) lua_newuserdata( L, sizeof( ucg_ud_t ) ); ucg_nodemcu_t *ext_ucg = &(ud->ucg); ud->font_ref = LUA_NOREF; ud->host_ref = host_ref; ext_ucg->hal = host ? (void *)(host->host) : NULL; ucg_t *ucg = (ucg_t *)ext_ucg; /* do a dummy init so that something usefull is part of the ucg structure */ ucg_Init( ucg, ucg_dev_default_cb, ucg_ext_none, (ucg_com_fnptr)0 ); /* reset cursor position */ ud->tx = 0; ud->ty = 0; ud->tdir = 0; /* default direction */ uint8_t i; for( i = 0; i < UCG_PIN_COUNT; i++ ) ucg->pin_list[i] = UCG_PIN_VAL_NONE; ud->dev_cb = device; ud->ext_cb = extension; if (res >= 0) ucg->pin_list[UCG_PIN_RST] = res; ucg->pin_list[UCG_PIN_CD] = dc; ucg->pin_list[UCG_PIN_CS] = cs; /* set its metatable */ luaL_getmetatable(L, "ucg.display"); lua_setmetatable(L, -2); return 1; } #undef UCG_DISPLAY_TABLE_ENTRY #define UCG_DISPLAY_TABLE_ENTRY(binding, device, extension) \ static int l ## binding( lua_State *L ) \ { \ return ldisplay_hw_spi( L, device, extension ); \ } // // Unroll the display table and insert binding functions. UCG_DISPLAY_TABLE // // *************************************************************************** // Module function map LROT_BEGIN(lucg_display) LROT_FUNCENTRY( begin, lucg_begin ) LROT_FUNCENTRY( clearScreen, lucg_clearScreen ) LROT_FUNCENTRY( draw90Line, lucg_draw90Line ) LROT_FUNCENTRY( drawBox, lucg_drawBox ) LROT_FUNCENTRY( drawCircle, lucg_drawCircle ) LROT_FUNCENTRY( drawDisc, lucg_drawDisc ) LROT_FUNCENTRY( drawFrame, lucg_drawFrame ) LROT_FUNCENTRY( drawGlyph, lucg_drawGlyph ) LROT_FUNCENTRY( drawGradientBox, lucg_drawGradientBox ) LROT_FUNCENTRY( drawGradientLine, lucg_drawGradientLine ) LROT_FUNCENTRY( drawHLine, lucg_drawHLine ) LROT_FUNCENTRY( drawLine, lucg_drawLine ) LROT_FUNCENTRY( drawPixel, lucg_drawPixel ) LROT_FUNCENTRY( drawRBox, lucg_drawRBox ) LROT_FUNCENTRY( drawRFrame, lucg_drawRFrame ) LROT_FUNCENTRY( drawString, lucg_drawString ) LROT_FUNCENTRY( drawTetragon, lucg_drawTetragon ) LROT_FUNCENTRY( drawTriangle, lucg_drawTriangle ) LROT_FUNCENTRY( drawVLine, lucg_drawVLine ) LROT_FUNCENTRY( getFontAscent, lucg_getFontAscent ) LROT_FUNCENTRY( getFontDescent, lucg_getFontDescent ) LROT_FUNCENTRY( getHeight, lucg_getHeight ) LROT_FUNCENTRY( getStrWidth, lucg_getStrWidth ) LROT_FUNCENTRY( getWidth, lucg_getWidth ) LROT_FUNCENTRY( print, lucg_print ) LROT_FUNCENTRY( setClipRange, lucg_setClipRange ) LROT_FUNCENTRY( setColor, lucg_setColor ) LROT_FUNCENTRY( setFont, lucg_setFont ) LROT_FUNCENTRY( setFontMode, lucg_setFontMode ) LROT_FUNCENTRY( setFontPosBaseline, lucg_setFontPosBaseline ) LROT_FUNCENTRY( setFontPosBottom, lucg_setFontPosBottom ) LROT_FUNCENTRY( setFontPosCenter, lucg_setFontPosCenter ) LROT_FUNCENTRY( setFontPosTop, lucg_setFontPosTop ) LROT_FUNCENTRY( setMaxClipRange, lucg_setMaxClipRange ) LROT_FUNCENTRY( setPrintDir, lucg_setPrintDir ) LROT_FUNCENTRY( setPrintPos, lucg_setPrintPos ) LROT_FUNCENTRY( setRotate90, lucg_setRotate90 ) LROT_FUNCENTRY( setRotate180, lucg_setRotate180 ) LROT_FUNCENTRY( setRotate270, lucg_setRotate270 ) LROT_FUNCENTRY( setScale2x2, lucg_setScale2x2 ) LROT_FUNCENTRY( undoClipRange, lucg_setMaxClipRange ) LROT_FUNCENTRY( undoRotate, lucg_undoRotate ) LROT_FUNCENTRY( undoScale, lucg_undoScale ) LROT_FUNCENTRY( __gc, lucg_close_display ) LROT_TABENTRY( __index, lucg_display ) LROT_END(lucg_display, NULL, 0) LROT_BEGIN(lucg) #undef UCG_DISPLAY_TABLE_ENTRY #define UCG_DISPLAY_TABLE_ENTRY(binding, device, extension) LROT_FUNCENTRY( binding, l ## binding ) UCG_DISPLAY_TABLE // Register fonts #undef UCG_FONT_TABLE_ENTRY #define UCG_FONT_TABLE_ENTRY(font) LROT_LUDENTRY( font, (void *)(ucg_ ## font) ) UCG_FONT_TABLE // Font modes LROT_NUMENTRY( FONT_MODE_TRANSPARENT, UCG_FONT_MODE_TRANSPARENT ) LROT_NUMENTRY( FONT_MODE_SOLID, UCG_FONT_MODE_SOLID ) // Options for circle/ disc drawing LROT_NUMENTRY( DRAW_UPPER_RIGHT, UCG_DRAW_UPPER_RIGHT ) LROT_NUMENTRY( DRAW_UPPER_LEFT, UCG_DRAW_UPPER_LEFT ) LROT_NUMENTRY( DRAW_LOWER_RIGHT, UCG_DRAW_LOWER_RIGHT ) LROT_NUMENTRY( DRAW_LOWER_LEFT, UCG_DRAW_LOWER_LEFT ) LROT_NUMENTRY( DRAW_ALL, UCG_DRAW_ALL ) LROT_TABENTRY( __metatable, lucg ) LROT_END(lucg, NULL, 0) int luaopen_ucg( lua_State *L ) { luaL_rometatable(L, "ucg.display", (void *)lucg_display_map); // create metatable return 0; } NODEMCU_MODULE(UCG, "ucg", lucg, luaopen_ucg);