Browse Source

port u8g2 module from esp32 platform

devsaurus 6 years ago
parent
commit
87bb96dfbe

+ 6 - 6
Makefile

@@ -308,11 +308,11 @@ endif
 
 
 $(OBJODIR)/%.o: %.c
-	@mkdir -p $(OBJODIR);
+	@mkdir -p $(dir $@);
 	$(CC) $(if $(findstring $<,$(DSRCS)),$(DFLAGS),$(CFLAGS)) $(COPTS_$(*F)) -o $@ -c $<
 
 $(OBJODIR)/%.d: %.c
-	@mkdir -p $(OBJODIR);
+	@mkdir -p $(dir $@);
 	@echo DEPEND: $(CC) -M $(CFLAGS) $<
 	@set -e; rm -f $@; \
 	$(CC) -M $(CFLAGS) $< > $@.$$$$; \
@@ -331,22 +331,22 @@ $(OBJODIR)/%.d: %.cpp
 	rm -f $@.$$$$
 
 $(OBJODIR)/%.o: %.s
-	@mkdir -p $(OBJODIR);
+	@mkdir -p $(dir $@);
 	$(CC) $(CFLAGS) -o $@ -c $<
 
 $(OBJODIR)/%.d: %.s
-	@mkdir -p $(OBJODIR); \
+	@mkdir -p $(dir $@); \
 	set -e; rm -f $@; \
 	$(CC) -M $(CFLAGS) $< > $@.$$$$; \
 	sed 's,\($*\.o\)[ :]*,$(OBJODIR)/\1 $@ : ,g' < $@.$$$$ > $@; \
 	rm -f $@.$$$$
 
 $(OBJODIR)/%.o: %.S
-	@mkdir -p $(OBJODIR);
+	@mkdir -p $(dir $@);
 	$(CC) $(CFLAGS) -D__ASSEMBLER__ -o $@ -c $<
 
 $(OBJODIR)/%.d: %.S
-	@mkdir -p $(OBJODIR); \
+	@mkdir -p $(dir $@); \
 	set -e; rm -f $@; \
 	$(CC) -M $(CFLAGS) $< > $@.$$$$; \
 	sed 's,\($*\.o\)[ :]*,$(OBJODIR)/\1 $@ : ,g' < $@.$$$$ > $@; \

+ 2 - 0
app/Makefile

@@ -38,6 +38,7 @@ SUBDIRS= 					\
 	lua 					\
 	lwip 					\
 	task 					\
+	u8g2lib					\
 	smart 					\
 	modules 				\
 	spiffs 					\
@@ -68,6 +69,7 @@ COMPONENTS_eagle.app.v6 = 			\
 	libc/liblibc.a 				\
 	lua/liblua.a 				\
 	lwip/liblwip.a 				\
+	u8g2lib/u8g2lib.a			\
 	smart/smart.a 				\
 	spiffs/spiffs.a 			\
 	fatfs/libfatfs.a			\

+ 14 - 0
app/include/u8g2_displays.h

@@ -0,0 +1,14 @@
+
+#ifndef _U8G2_DISPLAYS_H
+#define _U8G2_DISPLAYS_H
+
+#define U8G2_DISPLAY_TABLE_ENTRY(function, binding)
+
+#define U8G2_DISPLAY_TABLE_I2C \
+  U8G2_DISPLAY_TABLE_ENTRY(u8g2_Setup_ssd1306_i2c_128x64_noname_f, ssd1306_i2c_128x64_noname) \
+
+#define U8G2_DISPLAY_TABLE_SPI \
+  U8G2_DISPLAY_TABLE_ENTRY(u8g2_Setup_ssd1306_128x64_noname_f, ssd1306_128x64_noname) \
+
+
+#endif /* _U8G2_DISPLAYS_H */

+ 12 - 0
app/include/u8g2_fonts.h

@@ -0,0 +1,12 @@
+
+#ifndef _U8G2_FONTS_H
+#define _U8G2_FONTS_H
+
+#define U8G2_FONT_TABLE_ENTRY(font)
+
+#define U8G2_FONT_TABLE \
+  U8G2_FONT_TABLE_ENTRY(font_6x10_tf) \
+  U8G2_FONT_TABLE_ENTRY(font_unifont_t_symbols) \
+
+
+#endif /* _U8G2_FONTS_H */

+ 1 - 0
app/include/user_modules.h

@@ -65,6 +65,7 @@
 #define LUA_USE_MODULES_TMR
 //#define LUA_USE_MODULES_TSL2561
 #define LUA_USE_MODULES_UART
+//#define LUA_USE_MODULES_U8G2
 //#define LUA_USE_MODULES_UCG
 //#define LUA_USE_MODULES_WEBSOCKET
 #define LUA_USE_MODULES_WIFI

+ 1 - 0
app/modules/Makefile

@@ -43,6 +43,7 @@ INCLUDES += -I ./
 INCLUDES += -I ../libc
 INCLUDES += -I ../coap
 INCLUDES += -I ../mqtt
+INCLUDES += -I ../u8g2lib/u8g2/src/clib
 INCLUDES += -I ../ucglib
 INCLUDES += -I ../lua
 INCLUDES += -I ../pcm

+ 805 - 0
app/modules/u8g2.c

@@ -0,0 +1,805 @@
+// Module for binding the u8g2 library
+// Note: This file is intended to be shared between esp8266 and esp32 platform
+
+#include "module.h"
+#include "lauxlib.h"
+
+#define U8X8_USE_PINS
+#include "u8g2.h"
+#include "u8x8_nodemcu_hal.h"
+
+#include "u8g2_displays.h"
+#include "u8g2_fonts.h"
+
+#ifdef ESP_PLATFORM
+#include "spi_common.h"
+
+#include "sdkconfig.h"
+#endif
+
+#ifndef CONFIG_LUA_MODULE_U8G2
+// ignore unused functions if u8g2 module will be skipped anyhow
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+
+typedef struct {
+  int font_ref;
+  int host_ref;
+  u8g2_nodemcu_t u8g2;
+} u8g2_ud_t;
+
+#define GET_U8G2() \
+  u8g2_ud_t *ud = (u8g2_ud_t *)luaL_checkudata( L, 1, "u8g2.display" ); \
+  u8g2_t *u8g2 = (u8g2_t *)(&(ud->u8g2));
+
+static int lu8g2_clearBuffer( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_ClearBuffer( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_drawBox( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  int w = luaL_checkint( L, ++stack );
+  int h = luaL_checkint( L, ++stack );
+
+  u8g2_DrawBox( u8g2, x, y, w, h );
+
+  return 0;
+}
+
+static int lu8g2_drawCircle( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x0  = luaL_checkint( L, ++stack );
+  int y0  = luaL_checkint( L, ++stack );
+  int rad = luaL_checkint( L, ++stack );
+  int opt = luaL_optint( L, ++stack, U8G2_DRAW_ALL );
+
+  u8g2_DrawCircle( u8g2, x0, y0, rad, opt );
+
+  return 0;
+}
+
+static int lu8g2_drawDisc( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x0  = luaL_checkint( L, ++stack );
+  int y0  = luaL_checkint( L, ++stack );
+  int rad = luaL_checkint( L, ++stack );
+  int opt = luaL_optint( L, ++stack, U8G2_DRAW_ALL );
+
+  u8g2_DrawDisc( u8g2, x0, y0, rad, opt );
+
+  return 0;
+}
+
+static int lu8g2_drawEllipse( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x0  = luaL_checkint( L, ++stack );
+  int y0  = luaL_checkint( L, ++stack );
+  int rx  = luaL_checkint( L, ++stack );
+  int ry  = luaL_checkint( L, ++stack );
+  int opt = luaL_optint( L, ++stack, U8G2_DRAW_ALL );
+
+  u8g2_DrawEllipse( u8g2, x0, y0, rx, ry, opt );
+
+  return 0;
+}
+
+static int lu8g2_drawFilledEllipse( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x0  = luaL_checkint( L, ++stack );
+  int y0  = luaL_checkint( L, ++stack );
+  int rx  = luaL_checkint( L, ++stack );
+  int ry  = luaL_checkint( L, ++stack );
+  int opt = luaL_optint( L, ++stack, U8G2_DRAW_ALL );
+
+  u8g2_DrawFilledEllipse( u8g2, x0, y0, rx, ry, opt );
+
+  return 0;
+}
+
+static int lu8g2_drawFrame( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  int w = luaL_checkint( L, ++stack );
+  int h = luaL_checkint( L, ++stack );
+
+  u8g2_DrawFrame( u8g2, x, y, w, h );
+
+  return 0;
+}
+
+static int lu8g2_drawGlyph( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x   = luaL_checkint( L, ++stack );
+  int y   = luaL_checkint( L, ++stack );
+  int enc = luaL_checkint( L, ++stack );
+
+  u8g2_DrawGlyph( u8g2, x, y, enc );
+
+  return 0;
+}
+
+static int lu8g2_drawHLine( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  int w = luaL_checkint( L, ++stack );
+
+  u8g2_DrawHLine( u8g2, x, y, w );
+
+  return 0;
+}
+
+static int lu8g2_drawLine( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x0 = luaL_checkint( L, ++stack );
+  int y0 = luaL_checkint( L, ++stack );
+  int x1 = luaL_checkint( L, ++stack );
+  int y1 = luaL_checkint( L, ++stack );
+
+  u8g2_DrawLine( u8g2, x0, y0, x1, y1 );
+
+  return 0;
+}
+
+static int lu8g2_drawPixel( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+
+  u8g2_DrawPixel( u8g2, x, y );
+
+  return 0;
+}
+
+static int lu8g2_drawRBox( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  int w = luaL_checkint( L, ++stack );
+  int h = luaL_checkint( L, ++stack );
+  int r = luaL_checkint( L, ++stack );
+
+  u8g2_DrawRBox( u8g2, x, y, w, h, r );
+
+  return 0;
+}
+
+static int lu8g2_drawRFrame( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  int w = luaL_checkint( L, ++stack );
+  int h = luaL_checkint( L, ++stack );
+  int r = luaL_checkint( L, ++stack );
+
+  u8g2_DrawRFrame( u8g2, x, y, w, h, r );
+
+  return 0;
+}
+
+static int lu8g2_drawStr( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  const char *str = luaL_checkstring( L, ++stack );
+
+  u8g2_DrawStr( u8g2, x, y, str );
+
+  return 0;
+}
+
+static int lu8g2_drawTriangle( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x0 = luaL_checkint( L, ++stack );
+  int y0 = luaL_checkint( L, ++stack );
+  int x1 = luaL_checkint( L, ++stack );
+  int y1 = luaL_checkint( L, ++stack );
+  int x2 = luaL_checkint( L, ++stack );
+  int y2 = luaL_checkint( L, ++stack );
+
+  u8g2_DrawTriangle( u8g2, x0, y0, x1, y1, x2, y2 );
+
+  return 0;
+}
+
+static int lu8g2_drawUTF8( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  const char *str = luaL_checkstring( L, ++stack );
+
+  u8g2_DrawUTF8( u8g2, x, y, str );
+
+  return 0;
+}
+
+static int lu8g2_drawVLine( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  int h = luaL_checkint( L, ++stack );
+
+  u8g2_DrawVLine( u8g2, x, y, h );
+
+  return 0;
+}
+
+static int lu8g2_drawXBM( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int x = luaL_checkint( L, ++stack );
+  int y = luaL_checkint( L, ++stack );
+  int w = luaL_checkint( L, ++stack );
+  int h = luaL_checkint( L, ++stack );
+  size_t len;
+  const char *bitmap = luaL_checklstring( L, ++stack, &len );
+
+  u8g2_DrawXBM( u8g2, x, y, w, h, (uint8_t *)bitmap );
+
+  return 0;
+}
+
+static int lu8g2_getAscent( lua_State *L )
+{
+  GET_U8G2();
+
+  lua_pushinteger( L, u8g2_GetAscent( u8g2 ) );
+  return 1;
+}
+
+static int lu8g2_getDescent( lua_State *L )
+{
+  GET_U8G2();
+
+  lua_pushinteger( L, u8g2_GetDescent( u8g2 ) );
+  return 1;
+}
+
+static int lu8g2_getStrWidth( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  const char *s = luaL_checkstring( L, ++stack );
+
+  lua_pushinteger( L, u8g2_GetStrWidth( u8g2, s ) );
+  return 1;
+}
+
+static int lu8g2_getUTF8Width( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  const char *s = luaL_checkstring( L, ++stack );
+
+  lua_pushinteger( L, u8g2_GetUTF8Width( u8g2, s ) );
+  return 1;
+}
+
+static int lu8g2_sendBuffer( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_SendBuffer( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_setBitmapMode( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int is_transparent = luaL_checkint( L, ++stack );
+
+  u8g2_SetBitmapMode( u8g2, is_transparent );
+
+  return 0;
+}
+
+static int lu8g2_setContrast( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int value = luaL_checkint( L, ++stack );
+
+  u8g2_SetContrast( u8g2, value );
+
+  return 0;
+}
+
+static int lu8g2_setDisplayRotation( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  const u8g2_cb_t *u8g2_cb = (u8g2_cb_t *)lua_touserdata( L, ++stack );
+
+  u8g2_SetDisplayRotation( u8g2, u8g2_cb );
+
+  return 0;
+}
+
+static int lu8g2_setDrawColor( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int col = luaL_checkint( L, ++stack );
+
+  u8g2_SetDrawColor( u8g2, col );
+
+  return 0;
+}
+
+static int lu8g2_setFlipMode( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int is_enable = luaL_checkint( L, ++stack );
+
+  u8g2_SetFlipMode( u8g2, is_enable );
+
+  return 0;
+}
+
+static int lu8g2_setFont( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  const uint8_t *font = NULL;
+
+  luaL_unref( L, LUA_REGISTRYINDEX, ud->font_ref );
+  ud->font_ref = LUA_NOREF;
+
+  if (lua_islightuserdata( L, ++stack )) {
+    font = (const uint8_t *)lua_touserdata( L, stack );
+
+  } else if (lua_isstring( L, stack )) {
+    // ref the font string to safe it in case the string variable gets gc'ed
+    lua_pushvalue( L, stack );
+    ud->font_ref = luaL_ref( L, LUA_REGISTRYINDEX );
+
+    size_t len;
+    font = (const uint8_t *)luaL_checklstring( L, stack, &len );
+
+  }
+  luaL_argcheck( L, font != NULL, stack, "invalid font" );
+
+  u8g2_SetFont( u8g2, font );
+
+  return 0;
+}
+
+static int lu8g2_setFontDirection( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int dir = luaL_checkint( L, ++stack );
+
+  u8g2_SetFontDirection( u8g2, dir );
+
+  return 0;
+}
+
+static int lu8g2_setFontMode( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int is_transparent = luaL_checkint( L, ++stack );
+
+  u8g2_SetFontMode( u8g2, is_transparent );
+
+  return 0;
+}
+
+static int lu8g2_setFontPosBaseline( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_SetFontPosBaseline( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_setFontPosBottom( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_SetFontPosBottom( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_setFontPosTop( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_SetFontPosTop( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_setFontPosCenter( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_SetFontPosCenter( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_setFontRefHeightAll( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_SetFontRefHeightAll( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_setFontRefHeightExtendedText( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_SetFontRefHeightExtendedText( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_setFontRefHeightText( lua_State *L )
+{
+  GET_U8G2();
+
+  u8g2_SetFontRefHeightText( u8g2 );
+
+  return 0;
+}
+
+static int lu8g2_setPowerSave( lua_State *L )
+{
+  GET_U8G2();
+  int stack = 1;
+
+  int is_enable = luaL_checkint( L, ++stack );
+
+  u8g2_SetPowerSave( u8g2, is_enable );
+
+  return 0;
+}
+
+
+static const LUA_REG_TYPE lu8g2_display_map[] = {
+  { LSTRKEY( "clearBuffer" ),        LFUNCVAL( lu8g2_clearBuffer ) },
+  { LSTRKEY( "drawBox" ),            LFUNCVAL( lu8g2_drawBox ) },
+  { LSTRKEY( "drawCircle" ),         LFUNCVAL( lu8g2_drawCircle ) },
+  { LSTRKEY( "drawDisc" ),           LFUNCVAL( lu8g2_drawDisc ) },
+  { LSTRKEY( "drawEllipse" ),        LFUNCVAL( lu8g2_drawEllipse ) },
+  { LSTRKEY( "drawFilledEllipse" ),  LFUNCVAL( lu8g2_drawFilledEllipse ) },
+  { LSTRKEY( "drawFrame" ),          LFUNCVAL( lu8g2_drawFrame ) },
+  { LSTRKEY( "drawGlyph" ),          LFUNCVAL( lu8g2_drawGlyph ) },
+  { LSTRKEY( "drawHLine" ),          LFUNCVAL( lu8g2_drawHLine ) },
+  { LSTRKEY( "drawLine" ),           LFUNCVAL( lu8g2_drawLine ) },
+  { LSTRKEY( "drawPixel" ),          LFUNCVAL( lu8g2_drawPixel ) },
+  { LSTRKEY( "drawRBox" ),           LFUNCVAL( lu8g2_drawRBox ) },
+  { LSTRKEY( "drawRFrame" ),         LFUNCVAL( lu8g2_drawRFrame ) },
+  { LSTRKEY( "drawStr" ),            LFUNCVAL( lu8g2_drawStr ) },
+  { LSTRKEY( "drawTriangle" ),       LFUNCVAL( lu8g2_drawTriangle ) },
+  { LSTRKEY( "drawUTF8" ),           LFUNCVAL( lu8g2_drawUTF8 ) },
+  { LSTRKEY( "drawVLine" ),          LFUNCVAL( lu8g2_drawVLine ) },
+  { LSTRKEY( "drawXBM" ),            LFUNCVAL( lu8g2_drawXBM ) },
+  { LSTRKEY( "getAscent" ),          LFUNCVAL( lu8g2_getAscent ) },
+  { LSTRKEY( "getDescent" ),         LFUNCVAL( lu8g2_getDescent ) },
+  { LSTRKEY( "getStrWidth" ),        LFUNCVAL( lu8g2_getStrWidth ) },
+  { LSTRKEY( "getUTF8Width" ),       LFUNCVAL( lu8g2_getUTF8Width ) },
+  { LSTRKEY( "sendBuffer" ),         LFUNCVAL( lu8g2_sendBuffer ) },
+  { LSTRKEY( "setBitmapMode" ),      LFUNCVAL( lu8g2_setBitmapMode ) },
+  { LSTRKEY( "setContrast" ),        LFUNCVAL( lu8g2_setContrast ) },
+  { LSTRKEY( "setDisplayRotation" ), LFUNCVAL( lu8g2_setDisplayRotation ) },
+  { LSTRKEY( "setDrawColor" ),       LFUNCVAL( lu8g2_setDrawColor ) },
+  { LSTRKEY( "setFlipMode" ),        LFUNCVAL( lu8g2_setFlipMode ) },
+  { LSTRKEY( "setFont" ),            LFUNCVAL( lu8g2_setFont ) },
+  { LSTRKEY( "setFontDirection" ),   LFUNCVAL( lu8g2_setFontDirection ) },
+  { LSTRKEY( "setFontMode" ),        LFUNCVAL( lu8g2_setFontMode ) },
+  { LSTRKEY( "setFontPosBaseline" ), LFUNCVAL( lu8g2_setFontPosBaseline ) },
+  { LSTRKEY( "setFontPosBottom" ),   LFUNCVAL( lu8g2_setFontPosBottom ) },
+  { LSTRKEY( "setFontPosTop" ),      LFUNCVAL( lu8g2_setFontPosTop ) },
+  { LSTRKEY( "setFontPosCenter" ),   LFUNCVAL( lu8g2_setFontPosCenter ) },
+  { LSTRKEY( "setFontRefHeightAll" ),          LFUNCVAL( lu8g2_setFontRefHeightAll ) },
+  { LSTRKEY( "setFontRefHeightExtendedText" ), LFUNCVAL( lu8g2_setFontRefHeightExtendedText ) },
+  { LSTRKEY( "setFontRefHeightText" ),         LFUNCVAL( lu8g2_setFontRefHeightText ) },
+  { LSTRKEY( "setPowerSave" ),       LFUNCVAL( lu8g2_setPowerSave ) },
+  //{ LSTRKEY( "__gc" ),    LFUNCVAL( lu8g2_display_free ) },
+  { LSTRKEY( "__index" ), LROVAL( lu8g2_display_map ) },
+  {LNILKEY, LNILVAL}
+};
+
+
+uint8_t u8x8_d_overlay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+
+typedef void (*display_setup_fn_t)(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+
+// ***************************************************************************
+// Device constructors
+//
+// I2C based devices will use this function template to implement the Lua binding.
+//
+static int ldisplay_i2c( lua_State *L, display_setup_fn_t setup_fn )
+{
+  int stack = 0;
+
+  int id = -1;
+  int i2c_addr = -1;
+  int rfb_cb_ref = LUA_NOREF;
+
+  if (lua_type( L, ++stack) == LUA_TNUMBER) {
+    /* hardware display connected */
+    id = luaL_checkint( L, stack );
+    i2c_addr = luaL_checkint( L, ++stack );
+    luaL_argcheck( L, i2c_addr >= 0 && i2c_addr <= 0x7f, stack, "invalid i2c address" );
+  } else
+    stack--;
+  if (lua_isfunction( L, ++stack )) {
+    lua_pushvalue( L, stack );
+    rfb_cb_ref = luaL_ref( L, LUA_REGISTRYINDEX );
+  }
+  if (id < 0 && rfb_cb_ref == LUA_NOREF)
+    return luaL_error( L, "wrong args" );
+
+  u8g2_ud_t *ud = (u8g2_ud_t *)lua_newuserdata( L, sizeof( u8g2_ud_t ) );
+  u8g2_nodemcu_t *ext_u8g2 = &(ud->u8g2);
+  ud->font_ref = LUA_NOREF;
+  ud->host_ref = LUA_NOREF;
+  /* the i2c driver id is forwarded in the hal member */
+  ext_u8g2->hal = id >= 0 ? (void *)id : NULL;
+
+  u8g2_t *u8g2 = (u8g2_t *)ext_u8g2;
+  u8x8_t *u8x8 = (u8x8_t *)u8g2;
+
+  setup_fn( u8g2, U8G2_R0, u8x8_byte_nodemcu_i2c, u8x8_gpio_and_delay_nodemcu );
+
+  /* prepare overlay data */
+  if (rfb_cb_ref != LUA_NOREF) {
+    ext_u8g2->overlay.template_display_cb = u8x8->display_cb;
+    ext_u8g2->overlay.hardware_display_cb = NULL;
+    ext_u8g2->overlay.rfb_cb_ref = LUA_NOREF;
+    u8x8->display_cb = u8x8_d_overlay;
+  }
+  if (id >= 0) {
+    /* hardware device specific initialization */
+    u8x8_SetI2CAddress( u8x8, i2c_addr );
+    ext_u8g2->overlay.hardware_display_cb = ext_u8g2->overlay.template_display_cb;
+  }
+
+  u8g2_InitDisplay( (u8g2_t *)u8g2 );
+  u8g2_ClearDisplay( (u8g2_t *)u8g2 );
+  u8g2_SetPowerSave( (u8g2_t *)u8g2, 0 );
+
+  if (rfb_cb_ref != LUA_NOREF) {
+    /* finally enable rfb display driver */
+    ext_u8g2->overlay.rfb_cb_ref = rfb_cb_ref;
+  }
+
+  /* set its metatable */
+  luaL_getmetatable(L, "u8g2.display");
+  lua_setmetatable(L, -2);
+
+  return 1;
+}
+//
+// SPI based devices will use this function template to implement the Lua binding.
+//
+static int ldisplay_spi( lua_State *L, display_setup_fn_t setup_fn )
+{
+  int stack = 0;
+
+#ifndef ESP_PLATFORM
+  typedef struct {
+    int host;
+  } lspi_host_t;
+  lspi_host_t host_elem;
+  lspi_host_t *host = &host_elem;
+#else
+  lspi_host_t *host = NULL;
+#endif
+  int host_ref = LUA_NOREF;
+  int cs = -1;
+  int dc = -1;
+  int res = -1;
+  int rfb_cb_ref = LUA_NOREF;
+  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 = TRUE;
+  } else if (lua_type( L, stack ) == LUA_TNUMBER) {
+    host->host = luaL_checkint( L, stack );
+    get_spi_pins = TRUE;
+  } else {
+    get_spi_pins = FALSE;
+    stack--;
+  }
+
+  if (get_spi_pins) {
+    cs = luaL_checkint( L, ++stack );
+    dc = luaL_checkint( L, ++stack );
+    res = luaL_optint( L, ++stack, -1 );
+  }
+
+  if (lua_isfunction( L, ++stack )) {
+    lua_pushvalue( L, stack );
+    rfb_cb_ref = luaL_ref( L, LUA_REGISTRYINDEX );
+  }
+  if (!host && rfb_cb_ref == LUA_NOREF)
+    return luaL_error( L, "wrong args" );
+
+  u8g2_ud_t *ud = (u8g2_ud_t *)lua_newuserdata( L, sizeof( u8g2_ud_t ) );
+  u8g2_nodemcu_t *ext_u8g2 = &(ud->u8g2);
+  ud->font_ref = LUA_NOREF;
+  ud->host_ref = host_ref;
+  /* the spi host id is forwarded in the hal member */
+  ext_u8g2->hal = host ? (void *)(host->host) : NULL;
+
+  u8g2_t *u8g2 = (u8g2_t *)ext_u8g2;
+  u8x8_t *u8x8 = (u8x8_t *)u8g2;
+
+  setup_fn( u8g2, U8G2_R0, u8x8_byte_nodemcu_spi, u8x8_gpio_and_delay_nodemcu );
+
+  /* prepare overlay data */
+  if (rfb_cb_ref != LUA_NOREF) {
+    ext_u8g2->overlay.template_display_cb = u8x8->display_cb;
+    ext_u8g2->overlay.hardware_display_cb = NULL;
+    ext_u8g2->overlay.rfb_cb_ref = LUA_NOREF;
+    u8x8->display_cb = u8x8_d_overlay;
+  }
+  if (host) {
+    /* hardware specific device initialization */
+    u8x8_SetPin( u8x8, U8X8_PIN_CS, cs );
+    u8x8_SetPin( u8x8, U8X8_PIN_DC, dc );
+    if (res >= 0)
+      u8x8_SetPin( u8x8, U8X8_PIN_RESET, res );
+    ext_u8g2->overlay.hardware_display_cb = ext_u8g2->overlay.template_display_cb;
+  }
+
+  u8g2_InitDisplay( (u8g2_t *)u8g2 );
+  u8g2_ClearDisplay( (u8g2_t *)u8g2 );
+  u8g2_SetPowerSave( (u8g2_t *)u8g2, 0 );
+
+  if (rfb_cb_ref != LUA_NOREF) {
+    /* finally enable rfb display driver */
+    ext_u8g2->overlay.rfb_cb_ref = rfb_cb_ref;
+  }
+
+  /* set its metatable */
+  luaL_getmetatable(L, "u8g2.display");
+  lua_setmetatable(L, -2);
+
+  return 1;
+}
+//
+//
+#undef U8G2_DISPLAY_TABLE_ENTRY
+#define U8G2_DISPLAY_TABLE_ENTRY(function, binding) \
+  static int l ## binding( lua_State *L )           \
+  {                                                 \
+    return ldisplay_i2c( L, function );             \
+  }
+//
+// Unroll the display table and insert binding functions for I2C based displays.
+U8G2_DISPLAY_TABLE_I2C
+//
+//
+#undef U8G2_DISPLAY_TABLE_ENTRY
+#define U8G2_DISPLAY_TABLE_ENTRY(function, binding) \
+  static int l ## binding( lua_State *L )           \
+  {                                                 \
+    return ldisplay_spi( L, function );             \
+  }
+//
+// Unroll the display table and insert binding functions for SPI based displays.
+U8G2_DISPLAY_TABLE_SPI
+//
+
+
+#undef U8G2_FONT_TABLE_ENTRY
+#undef U8G2_DISPLAY_TABLE_ENTRY
+#define U8G2_DISPLAY_TABLE_ENTRY(function, binding) \
+  { LSTRKEY( #binding ),           LFUNCVAL( l ## binding ) },
+
+static const LUA_REG_TYPE lu8g2_map[] = {
+  U8G2_DISPLAY_TABLE_I2C
+  U8G2_DISPLAY_TABLE_SPI
+  //
+  // Register fonts
+#define U8G2_FONT_TABLE_ENTRY(font) \
+  { LSTRKEY( #font ),              LUDATA( (void *)(u8g2_ ## font) ) },
+  U8G2_FONT_TABLE
+  //
+  { LSTRKEY( "DRAW_UPPER_RIGHT" ), LNUMVAL( U8G2_DRAW_UPPER_RIGHT ) },
+  { LSTRKEY( "DRAW_UPPER_LEFT" ),  LNUMVAL( U8G2_DRAW_UPPER_LEFT ) },
+  { LSTRKEY( "DRAW_LOWER_RIGHT" ), LNUMVAL( U8G2_DRAW_LOWER_RIGHT ) },
+  { LSTRKEY( "DRAW_LOWER_LEFT" ),  LNUMVAL( U8G2_DRAW_LOWER_LEFT ) },
+  { LSTRKEY( "DRAW_ALL" ),         LNUMVAL( U8G2_DRAW_ALL ) },
+  { LSTRKEY( "R0" ),               LUDATA( (void *)U8G2_R0 ) },
+  { LSTRKEY( "R1" ),               LUDATA( (void *)U8G2_R1 ) },
+  { LSTRKEY( "R2" ),               LUDATA( (void *)U8G2_R2 ) },
+  { LSTRKEY( "R3" ),               LUDATA( (void *)U8G2_R3 ) },
+  { LSTRKEY( "MIRROR" ),           LUDATA( (void *)U8G2_MIRROR ) },
+  {LNILKEY, LNILVAL}
+};
+
+int luaopen_u8g2( lua_State *L ) {
+  luaL_rometatable(L, "u8g2.display", (void *)lu8g2_display_map);
+  return 0;
+}
+
+NODEMCU_MODULE(U8G2, "u8g2", lu8g2_map, luaopen_u8g2);

+ 1 - 0
app/platform/Makefile

@@ -43,6 +43,7 @@ INCLUDES += -I ./
 INCLUDES += -I ../spiffs
 INCLUDES += -I ../libc
 INCLUDES += -I ../lua
+INCLUDES += -I ../u8g2lib/u8g2/src/clib
 PDIR := ../$(PDIR)
 sinclude $(PDIR)Makefile
 

+ 283 - 0
app/platform/u8x8_nodemcu_hal.c

@@ -0,0 +1,283 @@
+
+#include <string.h>
+#include "c_stdlib.h"
+
+#include "platform.h"
+
+#define U8X8_USE_PINS
+#include "u8x8_nodemcu_hal.h"
+
+
+uint8_t u8x8_gpio_and_delay_nodemcu(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint32_t temp;
+
+  switch(msg)
+  {
+  case U8X8_MSG_GPIO_AND_DELAY_INIT:  // called once during init phase of u8g2/u8x8
+                                      // can be used to setup pins
+    for (int idx = 0; idx < U8X8_PIN_OUTPUT_CNT; idx++) {
+      if (u8x8->pins[idx] != U8X8_PIN_NONE) {
+        // configure pin as output
+        if (idx == U8X8_PIN_I2C_CLOCK || idx == U8X8_PIN_I2C_DATA) {
+          platform_gpio_mode( u8x8->pins[idx], PLATFORM_GPIO_OPENDRAIN, PLATFORM_GPIO_PULLUP );
+        } else {
+          platform_gpio_mode( u8x8->pins[idx], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
+        }
+      }
+    }
+    break;
+
+  case U8X8_MSG_DELAY_NANO:           // delay arg_int * 1 nano second
+    os_delay_us( 1 );
+    break;    
+
+  case U8X8_MSG_DELAY_100NANO:        // delay arg_int * 100 nano seconds
+    temp = arg_int * 100;
+    temp /= 1000;
+    os_delay_us( temp > 0 ? temp : 1 );
+    break;
+
+  case U8X8_MSG_DELAY_10MICRO:        // delay arg_int * 10 micro seconds
+    os_delay_us( arg_int * 10 );
+    break;
+
+  case U8X8_MSG_DELAY_MILLI:          // delay arg_int * 1 milli second
+    os_delay_us( arg_int * 1000 );
+    break;
+
+  case U8X8_MSG_DELAY_I2C:                // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
+    temp = 5000 / arg_int;                // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
+    temp /= 1000;
+    os_delay_us( temp > 0 ? temp : 1 );
+    break;
+
+  case U8X8_MSG_GPIO_D0:              // D0 or SPI clock pin: Output level in arg_int
+  //case U8X8_MSG_GPIO_SPI_CLOCK:
+    break;
+  case U8X8_MSG_GPIO_D1:              // D1 or SPI data pin: Output level in arg_int
+  //case U8X8_MSG_GPIO_SPI_DATA:
+    break;
+  case U8X8_MSG_GPIO_D2:              // D2 pin: Output level in arg_int
+    break;
+  case U8X8_MSG_GPIO_D3:              // D3 pin: Output level in arg_int
+    break;
+  case U8X8_MSG_GPIO_D4:              // D4 pin: Output level in arg_int
+    break;
+  case U8X8_MSG_GPIO_D5:              // D5 pin: Output level in arg_int
+    break;
+  case U8X8_MSG_GPIO_D6:              // D6 pin: Output level in arg_int
+    break;
+  case U8X8_MSG_GPIO_D7:              // D7 pin: Output level in arg_int
+    break;
+  case U8X8_MSG_GPIO_E:               // E/WR pin: Output level in arg_int
+    break;
+  case U8X8_MSG_GPIO_CS:              // CS (chip select) pin: Output level in arg_int
+    platform_gpio_write( u8x8_GetPinValue( u8x8, msg ), arg_int );
+    break;
+  case U8X8_MSG_GPIO_DC:              // DC (data/cmd, A0, register select) pin: Output level in arg_int
+    platform_gpio_write( u8x8_GetPinValue( u8x8, msg ), arg_int );
+    break;
+  case U8X8_MSG_GPIO_RESET:           // Reset pin: Output level in arg_int
+    if (u8x8_GetPinValue( u8x8, msg ) != U8X8_PIN_NONE)
+      platform_gpio_write( u8x8_GetPinValue(u8x8, msg), arg_int );
+    break;
+  case U8X8_MSG_GPIO_CS1:             // CS1 (chip select) pin: Output level in arg_int
+    break;
+  case U8X8_MSG_GPIO_CS2:             // CS2 (chip select) pin: Output level in arg_int
+    break;
+
+  case U8X8_MSG_GPIO_I2C_CLOCK:       // arg_int=0: Output low at I2C clock pin
+                                      // arg_int=1: Input dir with pullup high for I2C clock pin
+    // for SW comm routine
+    platform_gpio_write( u8x8_GetPinValue( u8x8, msg ), arg_int );
+    break;
+
+  case U8X8_MSG_GPIO_I2C_DATA:        // arg_int=0: Output low at I2C data pin
+                                      // arg_int=1: Input dir with pullup high for I2C data pin
+    // for SW comm routine
+    platform_gpio_write( u8x8_GetPinValue( u8x8, msg ), arg_int );
+    break;
+
+  case U8X8_MSG_GPIO_MENU_SELECT:
+  case U8X8_MSG_GPIO_MENU_NEXT:
+  case U8X8_MSG_GPIO_MENU_PREV:
+  case U8X8_MSG_GPIO_MENU_HOME:
+    u8x8_SetGPIOResult( u8x8, /* get menu select pin state */ 0 );
+    break;
+  default:
+    u8x8_SetGPIOResult( u8x8, 1 ); // default return value
+    break;
+  }
+  return 1;
+}
+
+
+// static variables containing info about the i2c link
+// TODO: move to user space in u8x8_t once available
+typedef struct {
+  uint8_t id;
+} hal_i2c_t;
+
+uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t *data;
+  hal_i2c_t *hal = ((u8g2_nodemcu_t *)u8x8)->hal;
+ 
+  switch(msg) {
+  case U8X8_MSG_BYTE_SEND:
+    if (hal->id == 0) {
+      data = (uint8_t *)arg_ptr;
+      
+      while( arg_int > 0 ) {
+        platform_i2c_send_byte( 0, *data );
+        data++;
+        arg_int--;
+      }
+
+    } else {
+      // invalid id
+      return 0;
+    }
+
+    break;
+
+  case U8X8_MSG_BYTE_INIT:
+    {
+      // the hal member initially contains the i2c id
+      int id = (int)hal;
+      if (!(hal = c_malloc( sizeof ( hal_i2c_t ) )))
+        return 0;
+      hal->id = id;
+      ((u8g2_nodemcu_t *)u8x8)->hal = hal;
+    }
+    break;
+
+  case U8X8_MSG_BYTE_SET_DC:
+    break;
+
+  case U8X8_MSG_BYTE_START_TRANSFER:
+    if (hal->id == 0) {
+      platform_i2c_send_start( 0 );
+      platform_i2c_send_address( 0, u8x8_GetI2CAddress(u8x8), PLATFORM_I2C_DIRECTION_TRANSMITTER );
+
+    } else {
+      // invalid id
+      return 0;
+    }
+    break;
+
+  case U8X8_MSG_BYTE_END_TRANSFER:
+    if (hal->id == 0) {
+      platform_i2c_send_stop( 0 );
+
+    } else {
+      // invalid id
+      return 0;
+    }
+    break;
+
+  default:
+    return 0;
+  }
+
+  return 1;
+}
+
+
+// static variables containing info about the spi link
+// TODO: move to user space in u8x8_t once available
+typedef struct {
+  uint8_t host;
+  //spi_device_handle_t device;
+  uint8_t last_dc;
+  struct {
+    uint8_t *data;
+    size_t size, used;
+  } buffer;
+} hal_spi_t;
+
+static void flush_buffer_spi( hal_spi_t *hal )
+{
+  if (hal->buffer.used > 0) {
+    platform_spi_blkwrite( hal->host, hal->buffer.used, hal->buffer.data );
+
+    hal->buffer.used = 0;
+  }
+}
+
+uint8_t u8x8_byte_nodemcu_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  hal_spi_t *hal = ((u8g2_nodemcu_t *)u8x8)->hal;
+ 
+  switch(msg) {
+  case U8X8_MSG_BYTE_INIT:
+    {
+      /* disable chipselect */
+      u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_disable_level );
+
+      // the hal member initially contains the spi host id
+      int host = (int)hal;
+      if (!(hal = c_malloc( sizeof ( hal_spi_t ) )))
+        return 0;
+      hal->host = host;
+      ((u8g2_nodemcu_t *)u8x8)->hal = hal;
+
+      hal->last_dc = 0;
+    }
+    break;
+
+  case U8X8_MSG_BYTE_SET_DC:
+    if (hal->last_dc != arg_int)
+      flush_buffer_spi( hal );
+
+    u8x8_gpio_SetDC( u8x8, arg_int );
+    hal->last_dc = arg_int;
+    break;
+
+  case U8X8_MSG_BYTE_START_TRANSFER:
+    hal->buffer.size = 256;
+    if (!(hal->buffer.data = (uint8_t *)c_malloc( hal->buffer.size )))
+      return 0;
+    hal->buffer.used = 0;
+
+    u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_enable_level );
+    break;
+
+  case U8X8_MSG_BYTE_SEND:
+    if (!hal->buffer.data)
+      return 0;
+
+    while (hal->buffer.size - hal->buffer.used < arg_int) {
+      hal->buffer.size *= 2;
+      uint8_t *tmp;
+      if (!(tmp = (uint8_t *)c_malloc( hal->buffer.size ))) {
+        c_free( hal->buffer.data );
+        hal->buffer.data = NULL;
+        return 0;
+      }
+      os_memcpy( tmp, hal->buffer.data, hal->buffer.used );
+      c_free( hal->buffer.data );
+      hal->buffer.data = tmp;
+    }
+    os_memcpy( hal->buffer.data + hal->buffer.used, arg_ptr, arg_int );
+    hal->buffer.used += arg_int;
+    break;
+
+  case U8X8_MSG_BYTE_END_TRANSFER:
+    if (!hal->buffer.data)
+      return 0;
+
+    flush_buffer_spi( hal );
+
+    u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_disable_level );
+
+    c_free( hal->buffer.data );
+    break;
+
+  default:
+    return 0;
+  }
+
+  return 1;
+}

+ 26 - 0
app/platform/u8x8_nodemcu_hal.h

@@ -0,0 +1,26 @@
+
+#ifndef _U8X8_NODEMCU_HAL_H
+#define _U8X8_NODEMCU_HAL_H
+
+#include "u8g2.h"
+
+
+// extend standard u8g2_t struct with info that's needed in the communication callbacks
+typedef struct {
+  u8g2_t u8g2;
+  void *hal;
+
+  // elements for the overlay display driver
+  struct {
+    u8x8_msg_cb hardware_display_cb, template_display_cb;
+    int rfb_cb_ref;
+    uint8_t fb_update_ongoing;
+  } overlay;
+} u8g2_nodemcu_t;
+
+
+uint8_t u8x8_gpio_and_delay_nodemcu(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_byte_nodemcu_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+
+#endif  /* _U8X8_NODEMCU_HAL_H */

+ 50 - 0
app/u8g2lib/Makefile

@@ -0,0 +1,50 @@
+
+#############################################################
+# Required variables for each makefile
+# Discard this section from all parent makefiles
+# Expected variables (with automatic defaults):
+#   CSRCS (all "C" files in the dir)
+#   SUBDIRS (all subdirs with a Makefile)
+#   GEN_LIBS - list of libs to be generated ()
+#   GEN_IMAGES - list of images to be generated ()
+#   COMPONENTS_xxx - a list of libs/objs in the form
+#     subdir/lib to be extracted and rolled up into
+#     a generated lib/image xxx.a ()
+#
+ifndef PDIR
+GEN_LIBS = u8g2lib.a
+endif
+
+STD_CFLAGS=-std=gnu11 -Wimplicit
+
+#############################################################
+# Configuration i.e. compile options etc.
+# Target specific stuff (defines etc.) goes in here!
+# Generally values applying to a tree are captured in the
+#   makefile at its root level - these are then overridden
+#   for a subtree within the makefile rooted therein
+#
+DEFINES += -DU8X8_USE_PINS
+
+#############################################################
+# Recursion Magic - Don't touch this!!
+#
+# Each subtree potentially has an include directory
+#   corresponding to the common APIs applicable to modules
+#   rooted at that subtree. Accordingly, the INCLUDE PATH
+#   of a module can only contain the include directories up
+#   its parent path, and not its siblings
+#
+# Required for each makefile to inherit from the parent
+#
+
+CSRCS := $(wildcard u8g2/src/clib/*.c *.c)
+
+INCLUDES := $(INCLUDES) -I $(PDIR)include
+INCLUDES += -I u8g2/src/clib
+INCLUDES += -I ../libc
+INCLUDES += -I ../lua
+INCLUDES += -I ../platform
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile
+

+ 185 - 0
app/u8g2lib/u8x8_d_fbrle.c

@@ -0,0 +1,185 @@
+
+// Note: This file is intended to be shared between esp8266 and esp32 platform
+
+#include "u8x8.h"
+#include "lauxlib.h"
+
+#include "u8x8_nodemcu_hal.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static const u8x8_display_info_t u8x8_fbrle_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 0,
+  /* pre_chip_disable_wait_ns = */ 0,
+  /* reset_pulse_width_ms = */ 0,
+  /* post_reset_wait_ms = */ 0,
+  /* sda_setup_time_ns = */ 0,
+  /* sck_pulse_width_ns = */ 0,
+  /* sck_clock_hz = */ 0,
+  /* spi_mode = */ 0,
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 0,
+  /* write_pulse_width_ns = */ 0,
+  /* tile_width = */ 16,
+  /* tile_hight = */ 8,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 64
+};
+
+static int bit_at( uint8_t *buf, int line, int x )
+{
+  return buf[x] & (1 << line) ? 1 : 0;
+}
+
+struct fbrle_item
+{
+  uint8_t start_x;
+  uint8_t len;
+};
+
+struct fbrle_line
+{
+  uint8_t num_valid;
+  struct fbrle_item items[0];
+};
+
+static uint8_t u8x8_d_fbrle(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  u8g2_nodemcu_t *ext_u8g2 = (u8g2_nodemcu_t *)u8x8;
+
+  switch(msg)
+  {
+  case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+    // forward to template display driver
+    return ext_u8g2->overlay.template_display_cb(u8x8, msg, arg_int, arg_ptr);
+
+  case U8X8_MSG_DISPLAY_INIT:
+    //u8x8_d_helper_display_init(u8x8);
+    ext_u8g2->overlay.fb_update_ongoing = 0;
+    break;
+
+  case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+  case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+    break;
+
+#ifdef U8X8_WITH_SET_CONTRAST
+  case U8X8_MSG_DISPLAY_SET_CONTRAST:
+    break;
+#endif
+
+  case U8X8_MSG_DISPLAY_REFRESH:
+    ext_u8g2->overlay.fb_update_ongoing = 0;
+    break;
+    
+  case U8X8_MSG_DISPLAY_DRAW_TILE:
+    if (ext_u8g2->overlay.fb_update_ongoing == 0) {
+      // tell rfb callback that a new framebuffer starts
+      if (ext_u8g2->overlay.rfb_cb_ref != LUA_NOREF) {
+        // fire callback with nil argument
+        lua_State *L = lua_getstate();
+        lua_rawgeti( L, LUA_REGISTRYINDEX, ext_u8g2->overlay.rfb_cb_ref );
+        lua_pushnil( L );
+        lua_call( L, 1, 0 );
+      }
+      // and note ongoing framebuffer update
+      ext_u8g2->overlay.fb_update_ongoing = 1;
+    }
+
+    {
+      // TODO: transport tile_y, needs structural change!
+      uint8_t tile_x = ((u8x8_tile_t *)arg_ptr)->x_pos;
+      tile_x *= 8;
+      tile_x += u8x8->x_offset;
+      uint8_t tile_w = ((u8x8_tile_t *)arg_ptr)->cnt * 8;
+
+      size_t fbrle_line_size = sizeof( struct fbrle_line ) + sizeof( struct fbrle_item ) * (tile_w/2);
+      int num_lines = 8; /*arg_val / (xwidth/8);*/
+      uint8_t *buf = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+
+      struct fbrle_line *fbrle_line;
+      if (!(fbrle_line = (struct fbrle_line *)malloc( fbrle_line_size ))) {
+        break;
+      }
+
+      for (int line = 0; line < num_lines; line++) {
+        int start_run = -1;
+        fbrle_line->num_valid = 0;
+
+        for (int x = tile_x; x < tile_x+tile_w; x++) {
+          if (bit_at( buf, line, x ) == 0) {
+            if (start_run >= 0) {
+              // inside run, end it and enter result
+              fbrle_line->items[fbrle_line->num_valid].start_x = start_run;
+              fbrle_line->items[fbrle_line->num_valid++].len = x - start_run;
+              //NODE_ERR( "         line: %d x: %d len: %d\n", line, start_run, x - start_run );
+              start_run = -1;
+            }
+          } else {
+            if (start_run < 0) {
+              // outside run, start it
+              start_run = x;
+            }
+          }
+
+          if (fbrle_line->num_valid >= tile_w/2) break;
+        }
+
+        // active run?
+        if (start_run >= 0 && fbrle_line->num_valid < tile_w/2) {
+          fbrle_line->items[fbrle_line->num_valid].start_x = start_run;
+          fbrle_line->items[fbrle_line->num_valid++].len = tile_w - start_run;
+        }
+
+        // line done, trigger callback
+        if (ext_u8g2->overlay.rfb_cb_ref != LUA_NOREF) {
+          lua_State *L = lua_getstate();
+
+          lua_rawgeti( L, LUA_REGISTRYINDEX, ext_u8g2->overlay.rfb_cb_ref );
+          lua_pushlstring( L, (const char *)fbrle_line, fbrle_line_size );
+          lua_call( L, 1, 0 );
+        }
+      }
+
+      free( fbrle_line );
+    }
+    break;
+
+  default:
+    return 0;
+    break;
+  }
+
+  return 1;
+}
+
+uint8_t u8x8_d_overlay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t res = 1;
+  u8g2_nodemcu_t *ext_u8g2 = (u8g2_nodemcu_t *)u8x8;
+
+  switch(msg)
+  {
+  case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+    // only call for hardware display
+    if (ext_u8g2->overlay.hardware_display_cb)
+      return ext_u8g2->overlay.hardware_display_cb(u8x8, msg, arg_int, arg_ptr);
+    break;
+
+  default:
+    // forward all messages first to hardware display and then to fbrle
+    if (ext_u8g2->overlay.hardware_display_cb)
+      res = ext_u8g2->overlay.hardware_display_cb(u8x8, msg, arg_int, arg_ptr);
+    u8x8_d_fbrle(u8x8, msg, arg_int, arg_ptr);
+    break;
+  }
+
+  return res;
+}

+ 263 - 0
lua_examples/u8g2/graphics_test.lua

@@ -0,0 +1,263 @@
+-- ***************************************************************************
+-- Graphics Test
+--
+-- This script executes several features of u8glib to test their Lua bindings.
+--
+-- Note: It is prepared for SSD1306-based displays. Select your connectivity
+--       type by calling either init_i2c_display() or init_spi_display() at
+--       the bottom of this file.
+--
+-- ***************************************************************************
+
+-- setup I2c and connect display
+function init_i2c_display()
+    -- SDA and SCL can be assigned freely to available GPIOs
+    local sda = 5 -- GPIO14
+    local scl = 6 -- GPIO12
+    local sla = 0x3c
+    i2c.setup(0, sda, scl, i2c.SLOW)
+    disp = u8g2.ssd1306_i2c_128x64_noname(0, sla)
+end
+
+-- setup SPI and connect display
+function init_spi_display()
+    -- Hardware SPI CLK  = GPIO14
+    -- Hardware SPI MOSI = GPIO13
+    -- Hardware SPI MISO = GPIO12 (not used)
+    -- Hardware SPI /CS  = GPIO15 (not used)
+    -- CS, D/C, and RES can be assigned freely to available GPIOs
+    local cs  = 8 -- GPIO15, pull-down 10k to GND
+    local dc  = 4 -- GPIO2
+    local res = 0 -- GPIO16
+
+    spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
+    -- we won't be using the HSPI /CS line, so disable it again
+    gpio.mode(8, gpio.INPUT, gpio.PULLUP)
+
+    disp = u8g2.ssd1306_128x64_noname(1, cs, dc, res)
+end
+
+
+function u8g2_prepare()
+  disp:setFont(u8g2.font_6x10_tf)
+  disp:setFontRefHeightExtendedText()
+  disp:setDrawColor(1)
+  disp:setFontPosTop()
+  disp:setFontDirection(0)
+end
+
+
+function u8g2_box_frame(a)
+  disp:drawStr( 0, 0, "drawBox")
+  disp:drawBox(5,10,20,10)
+  disp:drawBox(10+a,15,30,7)
+  disp:drawStr( 0, 30, "drawFrame")
+  disp:drawFrame(5,10+30,20,10)
+  disp:drawFrame(10+a,15+30,30,7)
+end
+
+function u8g2_disc_circle(a)
+  disp:drawStr( 0, 0, "drawDisc")
+  disp:drawDisc(10,18,9)
+  disp:drawDisc(24+a,16,7)
+  disp:drawStr( 0, 30, "drawCircle")
+  disp:drawCircle(10,18+30,9)
+  disp:drawCircle(24+a,16+30,7)
+end
+
+function u8g2_r_frame(a)
+  disp:drawStr( 0, 0, "drawRFrame/Box")
+  disp:drawRFrame(5, 10,40,30, a+1)
+  disp:drawRBox(50, 10,25,40, a+1)
+end
+
+function u8g2_string(a)
+  disp:setFontDirection(0)
+  disp:drawStr(30+a,31, " 0")
+  disp:setFontDirection(1)
+  disp:drawStr(30,31+a, " 90")
+  disp:setFontDirection(2)
+  disp:drawStr(30-a,31, " 180")
+  disp:setFontDirection(3)
+  disp:drawStr(30,31-a, " 270")
+end
+
+function u8g2_line(a)
+  disp:drawStr( 0, 0, "drawLine")
+  disp:drawLine(7+a, 10, 40, 55)
+  disp:drawLine(7+a*2, 10, 60, 55)
+  disp:drawLine(7+a*3, 10, 80, 55)
+  disp:drawLine(7+a*4, 10, 100, 55)
+end
+
+function u8g2_triangle(a)
+  local offset = a
+  disp:drawStr( 0, 0, "drawTriangle")
+  disp:drawTriangle(14,7, 45,30, 10,40)
+  disp:drawTriangle(14+offset,7-offset, 45+offset,30-offset, 57+offset,10-offset)
+  disp:drawTriangle(57+offset*2,10, 45+offset*2,30, 86+offset*2,53)
+  disp:drawTriangle(10+offset,40+offset, 45+offset,30+offset, 86+offset,53+offset)
+end
+
+function u8g2_ascii_1()
+  disp:drawStr( 0, 0, "ASCII page 1")
+  for y = 0, 5 do
+    for x = 0, 15 do
+      disp:drawStr(x*7, y*10+10, string.char(y*16 + x + 32))
+    end
+  end
+end
+
+function u8g2_ascii_2()
+  disp:drawStr( 0, 0, "ASCII page 2")
+  for y = 0, 5 do
+    for x = 0, 15 do
+      disp:drawStr(x*7, y*10+10, string.char(y*16 + x + 160))
+    end
+  end
+end
+
+function u8g2_extra_page(a)
+  disp:drawStr( 0, 0, "Unicode")
+  disp:setFont(u8g2.font_unifont_t_symbols)
+  disp:setFontPosTop()
+  disp:drawUTF8(0, 24, "☀ ☁")
+  if a <= 3 then
+    disp:drawUTF8(a*3, 36, "☂")
+  else
+    disp:drawUTF8(a*3, 36, "☔")
+  end
+end
+
+cross_width = 24
+cross_height = 24
+cross_bits = string.char(
+  0x00, 0x18, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x42, 0x00, 
+  0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 
+  0xC0, 0x00, 0x03, 0x38, 0x3C, 0x1C, 0x06, 0x42, 0x60, 0x01, 0x42, 0x80, 
+  0x01, 0x42, 0x80, 0x06, 0x42, 0x60, 0x38, 0x3C, 0x1C, 0xC0, 0x00, 0x03, 
+  0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 
+  0x00, 0x42, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x18, 0x00)
+
+cross_fill_width = 24
+cross_fill_height = 24
+cross_fill_bits = string.char(
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x64, 0x00, 0x26, 
+  0x84, 0x00, 0x21, 0x08, 0x81, 0x10, 0x08, 0x42, 0x10, 0x10, 0x3C, 0x08, 
+  0x20, 0x00, 0x04, 0x40, 0x00, 0x02, 0x80, 0x00, 0x01, 0x80, 0x18, 0x01, 
+  0x80, 0x18, 0x01, 0x80, 0x00, 0x01, 0x40, 0x00, 0x02, 0x20, 0x00, 0x04, 
+  0x10, 0x3C, 0x08, 0x08, 0x42, 0x10, 0x08, 0x81, 0x10, 0x84, 0x00, 0x21, 
+  0x64, 0x00, 0x26, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
+
+cross_block_width = 14
+cross_block_height = 14
+cross_block_bits = string.char(
+  0xFF, 0x3F, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 
+  0xC1, 0x20, 0xC1, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 
+  0x01, 0x20, 0xFF, 0x3F)
+
+function u8g2_bitmap_overlay(a)
+  local frame_size = 28
+
+  disp:drawStr(0, 0, "Bitmap overlay")
+
+  disp:drawStr(0, frame_size + 12, "Solid / transparent")
+  disp:setBitmapMode(0) -- solid
+  disp:drawFrame(0, 10, frame_size, frame_size)
+  disp:drawXBM(2, 12, cross_width, cross_height, cross_bits)
+  if bit.band(a, 4) > 0 then
+    disp:drawXBM(7, 17, cross_block_width, cross_block_height, cross_block_bits)
+  end
+
+  disp:setBitmapMode(1) -- transparent
+  disp:drawFrame(frame_size + 5, 10, frame_size, frame_size)
+  disp:drawXBM(frame_size + 7, 12, cross_width, cross_height, cross_bits)
+  if bit.band(a, 4) then
+    disp:drawXBM(frame_size + 12, 17, cross_block_width, cross_block_height, cross_block_bits)
+  end
+end
+
+function u8g2_bitmap_modes(transparent)
+  local frame_size = 24
+
+  disp:drawBox(0, frame_size * 0.5, frame_size * 5, frame_size)
+  disp:drawStr(frame_size * 0.5, 50, "Black")
+  disp:drawStr(frame_size * 2, 50, "White")
+  disp:drawStr(frame_size * 3.5, 50, "XOR")
+  
+  if transparent == 0 then
+    disp:setBitmapMode(0) -- solid
+    disp:drawStr(0, 0, "Solid bitmap")
+  else
+    disp:setBitmapMode(1) -- transparent
+    disp:drawStr(0, 0, "Transparent bitmap")
+  end
+  disp:setDrawColor(0) -- Black
+  disp:drawXBM(frame_size * 0.5, 24, cross_width, cross_height, cross_bits)
+  disp:setDrawColor(1) -- White
+  disp:drawXBM(frame_size * 2, 24, cross_width, cross_height, cross_bits)
+  disp:setDrawColor(2) -- XOR
+  disp:drawXBM(frame_size * 3.5, 24, cross_width, cross_height, cross_bits)
+end
+
+
+function draw()
+  u8g2_prepare()
+
+  local d3 = bit.rshift(draw_state, 3)
+  local d7 = bit.band(draw_state, 7)
+
+  if d3 == 0 then
+    u8g2_box_frame(d7)
+  elseif d3 == 1 then
+    u8g2_disc_circle(d7)
+  elseif d3 == 2 then
+    u8g2_r_frame(d7)
+  elseif d3 == 3 then
+    u8g2_string(d7)
+  elseif d3 == 4 then
+    u8g2_line(d7)
+  elseif d3 == 5 then
+    u8g2_triangle(d7)
+  elseif d3 == 6 then
+    u8g2_ascii_1()
+  elseif d3 == 7 then
+    u8g2_ascii_2()
+  elseif d3 == 8 then
+    u8g2_extra_page(d7)
+  elseif d3 == 9 then
+    u8g2_bitmap_modes(0)
+  elseif d3 == 10 then
+    u8g2_bitmap_modes(1)
+  elseif d3 == 11 then
+    u8g2_bitmap_overlay(d7)
+  end
+end
+
+
+function loop()
+  -- picture loop  
+  disp:clearBuffer()
+  draw()
+  disp:sendBuffer()
+  
+  -- increase the state
+  draw_state = draw_state + 1
+  if draw_state >= 12*8 then
+    draw_state = 0
+  end
+
+  -- delay between each frame
+  loop_tmr:start()
+end
+
+
+draw_state = 0
+loop_tmr = tmr.create()
+loop_tmr:register(100, tmr.ALARM_SEMI, loop)
+
+init_i2c_display()
+--init_spi_display()
+
+print("--- Starting Graphics Test ---")
+loop_tmr:start()

+ 0 - 115
lua_examples/u8glib/u8g_bitmaps.lua

@@ -1,115 +0,0 @@
--- ***************************************************************************
--- Bitmaps Test
---
--- This script executes the bitmap features of u8glib to test their Lua
--- integration.
---
--- Note: It is prepared for SSD1306-based displays. Select your connectivity
---       type by calling either init_i2c_display() or init_spi_display() at
---       the bottom of this file.
---
--- ***************************************************************************
-
--- setup I2c and connect display
-function init_i2c_display()
-     -- SDA and SCL can be assigned freely to available GPIOs
-     local sda = 5 -- GPIO14
-     local scl = 6 -- GPIO12
-     local sla = 0x3c
-     i2c.setup(0, sda, scl, i2c.SLOW)
-     disp = u8g.ssd1306_128x64_i2c(sla)
-end
-
--- setup SPI and connect display
-function init_spi_display()
-     -- Hardware SPI CLK  = GPIO14
-     -- Hardware SPI MOSI = GPIO13
-     -- Hardware SPI MISO = GPIO12 (not used)
-     -- Hardware SPI /CS  = GPIO15 (not used)
-     -- CS, D/C, and RES can be assigned freely to available GPIOs
-     local cs  = 8 -- GPIO15, pull-down 10k to GND
-     local dc  = 4 -- GPIO2
-     local res = 0 -- GPIO16
-
-     spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
-     -- we won't be using the HSPI /CS line, so disable it again
-     gpio.mode(8, gpio.INPUT, gpio.PULLUP)
-
-     disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
-end
-
-
-function xbm_picture()
-     disp:setFont(u8g.font_6x10)
-     disp:drawStr( 0, 10, "XBM picture")
-
-     disp:drawXBM( 0, 20, 38, 24, xbm_data )
-end
-
-function bitmap_picture(state)
-     disp:setFont(u8g.font_6x10)
-     disp:drawStr( 0, 10, "Bitmap picture")
-
-     disp:drawBitmap( 0 + (state * 10), 20 + (state * 4), 1, 8, bm_data )
-end
-
--- the draw() routine
-function draw(draw_state)
-     local component = bit.rshift(draw_state, 3)
-
-     if (component == 0) then
-          xbm_picture(bit.band(draw_state, 7))
-     elseif (component == 1) then
-          bitmap_picture(bit.band(draw_state, 7))
-     end
-end
-
-
-function draw_loop()
-    -- Draws one page and schedules the next page, if there is one
-    local function draw_pages()
-        draw(draw_state)
-        if disp:nextPage() then
-            node.task.post(draw_pages)
-        else
-            node.task.post(bitmap_test)
-        end
-    end
-    -- Restart the draw loop and start drawing pages
-    disp:firstPage()
-    node.task.post(draw_pages)
-end
-
-function bitmap_test()
-
-    if (draw_state <= 7 + 1*8) then
-        draw_state = draw_state + 1
-    else
-        print("--- Restarting Bitmap Test ---")
-        draw_state = 1
-    end
-
-    print("Heap: " .. node.heap())
-    -- retrigger draw_loop
-    node.task.post(draw_loop)
-
-end
-
-draw_state = 1
-
-init_i2c_display()
---init_spi_display()
-
--- read XBM picture
-file.open("u8glib_logo.xbm", "r")
-xbm_data = file.read()
-file.close()
-
--- read Bitmap picture
-file.open("u8g_rook.bm", "r")
-bm_data = file.read()
-file.close()
-
-
-print("--- Starting Bitmap Test ---")
-node.task.post(draw_loop)

+ 0 - 73
lua_examples/u8glib/u8g_drawloop.lua

@@ -1,73 +0,0 @@
-------------------------------------------------------------------------------
--- u8glib example which shows how to implement the draw loop without causing
--- timeout issues with the WiFi stack. This is done by drawing one page at
--- a time, allowing the ESP SDK to do its house keeping between the page
--- draws.
---
--- This example assumes you have an SSD1306 display connected to pins 4 and 5
--- using I2C and that the profont22r is compiled into the firmware.
--- Please edit the init_display function to match your setup.
---  
--- Example:
--- dofile("u8g_drawloop.lua")
-------------------------------------------------------------------------------
-
-local disp
-local font
-
-function init_display()
-  local sda = 4
-  local sdl = 5
-  local sla = 0x3c
-  i2c.setup(0,sda,sdl, i2c.SLOW)
-  disp = u8g.ssd1306_128x64_i2c(sla)
-  font = u8g.font_profont22r
-end
-
-local function setLargeFont()
-  disp:setFont(font)
-  disp:setFontRefHeightExtendedText()
-  disp:setDefaultForegroundColor()
-  disp:setFontPosTop()
-end
-
--- Start the draw loop with the draw implementation in the provided function callback
-function updateDisplay(func)
-  -- Draws one page and schedules the next page, if there is one
-  local function drawPages()
-    func()
-    if (disp:nextPage() == true) then
-      node.task.post(drawPages)
-    end
-  end
-  -- Restart the draw loop and start drawing pages
-  disp:firstPage()
-  node.task.post(drawPages)
-end
-
-function drawHello()
-  setLargeFont()
-  disp:drawStr(30,22, "Hello")
-end
-
-function drawWorld()
-  setLargeFont()
-  disp:drawStr(30,22, "World")
-end
-
-local drawDemo = { drawHello, drawWorld }
-
-function demoLoop()
-  -- Start the draw loop with one of the demo functions
-  local f = table.remove(drawDemo,1)  
-  updateDisplay(f)
-  table.insert(drawDemo,f)
-end
-
--- Initialise the display
-init_display()
-
--- Draw demo page immediately and then schedule an update every 5 seconds.
--- To test your own drawXYZ function, disable the next two lines and call updateDisplay(drawXYZ) instead.
-demoLoop()
-tmr.alarm(4, 5000, 1, demoLoop)

+ 0 - 177
lua_examples/u8glib/u8g_graphics_test.lua

@@ -1,177 +0,0 @@
--- ***************************************************************************
--- Graphics Test
---
--- This script executes several features of u8glib to test their Lua bindings.
---
--- Note: It is prepared for SSD1306-based displays. Select your connectivity
---       type by calling either init_i2c_display() or init_spi_display() at
---       the bottom of this file.
---
--- ***************************************************************************
-
--- setup I2c and connect display
-function init_i2c_display()
-    -- SDA and SCL can be assigned freely to available GPIOs
-    local sda = 5 -- GPIO14
-    local scl = 6 -- GPIO12
-    local sla = 0x3c
-    i2c.setup(0, sda, scl, i2c.SLOW)
-    disp = u8g.ssd1306_128x64_i2c(sla)
-end
-
--- setup SPI and connect display
-function init_spi_display()
-    -- Hardware SPI CLK  = GPIO14
-    -- Hardware SPI MOSI = GPIO13
-    -- Hardware SPI MISO = GPIO12 (not used)
-    -- Hardware SPI /CS  = GPIO15 (not used)
-    -- CS, D/C, and RES can be assigned freely to available GPIOs
-    local cs  = 8 -- GPIO15, pull-down 10k to GND
-    local dc  = 4 -- GPIO2
-    local res = 0 -- GPIO16
-
-    spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
-    -- we won't be using the HSPI /CS line, so disable it again
-    gpio.mode(8, gpio.INPUT, gpio.PULLUP)
-
-    disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
-end
-
-
--- graphic test components
-function prepare()
-    disp:setFont(u8g.font_6x10)
-    disp:setFontRefHeightExtendedText()
-    disp:setDefaultForegroundColor()
-    disp:setFontPosTop()
-end
-
-function box_frame(a)
-    disp:drawStr(0, 0, "drawBox")
-    disp:drawBox(5, 10, 20, 10)
-    disp:drawBox(10+a, 15, 30, 7)
-    disp:drawStr(0, 30, "drawFrame")
-    disp:drawFrame(5, 10+30, 20, 10)
-    disp:drawFrame(10+a, 15+30, 30, 7)
-end
-
-function disc_circle(a)
-    disp:drawStr(0, 0, "drawDisc")
-    disp:drawDisc(10, 18, 9)
-    disp:drawDisc(24+a, 16, 7)
-    disp:drawStr(0, 30, "drawCircle")
-    disp:drawCircle(10, 18+30, 9)
-    disp:drawCircle(24+a, 16+30, 7)
-end
-
-function r_frame(a)
-    disp:drawStr(0, 0, "drawRFrame/Box")
-    disp:drawRFrame(5, 10, 40, 30, a+1)
-    disp:drawRBox(50, 10, 25, 40, a+1)
-end
-
-function stringtest(a)
-    disp:drawStr(30+a, 31, " 0")
-    disp:drawStr90(30, 31+a, " 90")
-    disp:drawStr180(30-a, 31, " 180")
-    disp:drawStr270(30, 31-a, " 270")
-end
-
-function line(a)
-    disp:drawStr(0, 0, "drawLine")
-    disp:drawLine(7+a, 10, 40, 55)
-    disp:drawLine(7+a*2, 10, 60, 55)
-    disp:drawLine(7+a*3, 10, 80, 55)
-    disp:drawLine(7+a*4, 10, 100, 55)
-end
-
-function triangle(a)
-    local offset = a
-    disp:drawStr(0, 0, "drawTriangle")
-    disp:drawTriangle(14,7, 45,30, 10,40)
-    disp:drawTriangle(14+offset,7-offset, 45+offset,30-offset, 57+offset,10-offset)
-    disp:drawTriangle(57+offset*2,10, 45+offset*2,30, 86+offset*2,53)
-    disp:drawTriangle(10+offset,40+offset, 45+offset,30+offset, 86+offset,53+offset)
-end
-
-function ascii_1()
-    local x, y, s
-    disp:drawStr(0, 0, "ASCII page 1")
-    for y = 0, 5, 1 do
-        for x = 0, 15, 1 do
-            s = y*16 + x + 32
-            disp:drawStr(x*7, y*10+10, string.char(s))
-        end
-    end
-end
-
-function extra_page(a)
-    disp:drawStr(0, 12, "setScale2x2")
-    disp:setScale2x2()
-    disp:drawStr(0, 6+a, "setScale2x2")
-    disp:undoScale()
-end
-
-
--- the draw() routine
-function draw(draw_state)
-    local component = bit.rshift(draw_state, 3)
-
-    prepare()
-
-    if (component == 0) then
-        box_frame(bit.band(draw_state, 7))
-    elseif (component == 1) then
-        disc_circle(bit.band(draw_state, 7))
-    elseif (component == 2) then
-        r_frame(bit.band(draw_state, 7))
-    elseif (component == 3) then
-        stringtest(bit.band(draw_state, 7))
-    elseif (component == 4) then
-        line(bit.band(draw_state, 7))
-    elseif (component == 5) then
-        triangle(bit.band(draw_state, 7))
-    elseif (component == 6) then
-        ascii_1()
-    elseif (component == 7) then
-        extra_page(bit.band(draw_state, 7))
-    end
-end
-
-function draw_loop()
-    -- Draws one page and schedules the next page, if there is one
-    local function draw_pages()
-        draw(draw_state)
-        if disp:nextPage() then
-            node.task.post(draw_pages)
-        else
-            node.task.post(graphics_test)
-        end
-    end
-    -- Restart the draw loop and start drawing pages
-    disp:firstPage()
-    node.task.post(draw_pages)
-end
-
-function graphics_test()
-
-    if (draw_state <= 7 + 8*8) then
-        draw_state = draw_state + 1
-    else
-        print("--- Restarting Graphics Test ---")
-        draw_state = 0
-    end
-
-    print("Heap: " .. node.heap())
-    -- retrigger draw_loop
-    node.task.post(draw_loop)
-
-end
-
-draw_state = 0
-
-init_i2c_display()
---init_spi_display()
-
-print("--- Starting Graphics Test ---")
-node.task.post(draw_loop)

BIN
lua_examples/u8glib/u8g_rook.bm


+ 0 - 97
lua_examples/u8glib/u8g_rotation.lua

@@ -1,97 +0,0 @@
--- ***************************************************************************
--- Rotation Test
---
--- This script executes the rotation features of u8glib to test their Lua
--- integration.
---
--- Note: It is prepared for SSD1306-based displays. Select your connectivity
---       type by calling either init_i2c_display() or init_spi_display() at
---       the bottom of this file.
---
--- ***************************************************************************
-
--- setup I2c and connect display
-function init_i2c_display()
-     -- SDA and SCL can be assigned freely to available GPIOs
-     local sda = 5 -- GPIO14
-     local scl = 6 -- GPIO12
-     local sla = 0x3c
-     i2c.setup(0, sda, scl, i2c.SLOW)
-     disp = u8g.ssd1306_128x64_i2c(sla)
-end
-
--- setup SPI and connect display
-function init_spi_display()
-     -- Hardware SPI CLK  = GPIO14
-     -- Hardware SPI MOSI = GPIO13
-     -- Hardware SPI MISO = GPIO12 (not used)
-     -- Hardware SPI /CS  = GPIO15 (not used)
-     -- CS, D/C, and RES can be assigned freely to available GPIOs
-     local cs  = 8 -- GPIO15, pull-down 10k to GND
-     local dc  = 4 -- GPIO2
-     local res = 0 -- GPIO16
-
-     spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
-     -- we won't be using the HSPI /CS line, so disable it again
-     gpio.mode(8, gpio.INPUT, gpio.PULLUP)
-
-     disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
-end
-
-
--- the draw() routine
-function draw()
-     disp:setFont(u8g.font_6x10)
-     disp:drawStr( 0+0, 20+0, "Hello!")
-     disp:drawStr( 0+2, 20+16, "Hello!")
-
-     disp:drawBox(0, 0, 3, 3)
-     disp:drawBox(disp:getWidth()-6, 0, 6, 6)
-     disp:drawBox(disp:getWidth()-9, disp:getHeight()-9, 9, 9)
-     disp:drawBox(0, disp:getHeight()-12, 12, 12)
-end
-
-
-function rotate()
-     if (next_rotation < tmr.now() / 1000) then
-          if (dir == 0) then
-               disp:undoRotation()
-          elseif (dir == 1) then
-               disp:setRot90()
-          elseif (dir == 2) then
-               disp:setRot180()
-          elseif (dir == 3) then
-               disp:setRot270()
-          end
-
-          dir = dir + 1
-          dir = bit.band(dir, 3)
-          -- schedule next rotation step in 1000ms
-          next_rotation = tmr.now() / 1000 + 1000
-     end
-end
-
-function rotation_test()
-     print("--- Starting Rotation Test ---")
-     dir = 0
-     next_rotation = 0
-
-     local loopcnt
-     for loopcnt = 1, 100, 1 do
-          rotate()
-
-          disp:firstPage()
-          repeat
-               draw(draw_state)
-          until disp:nextPage() == false
-
-          tmr.delay(100000)
-          tmr.wdclr()
-     end
-
-     print("--- Rotation Test done ---")
-end
-
---init_i2c_display()
-init_spi_display()
-rotation_test()

BIN
lua_examples/u8glib/u8glib_logo.xbm