// Module for U8glib //#include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "platform.h" #include "auxmods.h" #include "lrotable.h" //#include "c_string.h" //#include "c_stdlib.h" #include "u8g.h" typedef struct lu8g_userdata { uint8_t i2c_addr; u8g_t u8g; } lu8g_userdata_t; // Lua: u8g.setup( self, id ) static int lu8g_setup( lua_State *L ) { unsigned id = luaL_checkinteger( L, 2 ); //MOD_CHECK_ID( u8g, id ); if (id == 0) return luaL_error( L, "ID 0 not supported!" ); return 0; } // ------------------------------------------------------------ // comm functions // #define I2C_SLA 0x3c #define I2C_CMD_MODE 0x000 #define I2C_DATA_MODE 0x040 #define ESP_I2C_ID 0 static uint8_t do_i2c_start(uint8_t id, uint8_t sla) { platform_i2c_send_start( id ); // ignore return value -> tolerate missing ACK platform_i2c_send_address( id, sla, PLATFORM_I2C_DIRECTION_TRANSMITTER ); return 1; } static uint8_t u8g_com_esp8266_ssd_start_sequence(u8g_t *u8g) { /* are we requested to set the a0 state? */ if ( u8g->pin_list[U8G_PI_SET_A0] == 0 ) return 1; /* setup bus, might be a repeated start */ if ( do_i2c_start( ESP_I2C_ID, I2C_SLA ) == 0 ) return 0; if ( u8g->pin_list[U8G_PI_A0_STATE] == 0 ) { // ignore return value -> tolerate missing ACK platform_i2c_send_byte( ESP_I2C_ID, I2C_CMD_MODE ); } else { platform_i2c_send_byte( ESP_I2C_ID, I2C_DATA_MODE ); } u8g->pin_list[U8G_PI_SET_A0] = 0; return 1; } uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { switch(msg) { case U8G_COM_MSG_INIT: // we assume that the i2c bus was already initialized //u8g_i2c_init(u8g->pin_list[U8G_PI_I2C_OPTION]); break; case U8G_COM_MSG_STOP: break; case U8G_COM_MSG_RESET: /* Currently disabled, but it could be enable. Previous restrictions have been removed */ /* u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val); */ break; case U8G_COM_MSG_CHIP_SELECT: u8g->pin_list[U8G_PI_A0_STATE] = 0; u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again, also forces start condition */ if ( arg_val == 0 ) { /* disable chip, send stop condition */ platform_i2c_send_stop( ESP_I2C_ID ); } else { /* enable, do nothing: any byte writing will trigger the i2c start */ } break; case U8G_COM_MSG_WRITE_BYTE: //u8g->pin_list[U8G_PI_SET_A0] = 1; if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 ) return platform_i2c_stop( ESP_I2C_ID ), 0; if ( platform_i2c_send_byte( ESP_I2C_ID, arg_val) == 0 ) return platform_i2c_send_stop( ESP_I2C_ID ), 0; // platform_i2c_send_stop( ESP_I2C_ID ); break; case U8G_COM_MSG_WRITE_SEQ: //u8g->pin_list[U8G_PI_SET_A0] = 1; if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 ) return platform_i2c_send_stop( ESP_I2C_ID ), 0; { register uint8_t *ptr = arg_ptr; while( arg_val > 0 ) { // ignore return value -> tolerate missing ACK if ( platform_i2c_send_byte( ESP_I2C_ID, *ptr++) == 0 ) ; //return platform_i2c_send_stop( ESP_I2C_ID ), 0; arg_val--; } } // platform_i2c_send_stop( ESP_I2C_ID ); break; case U8G_COM_MSG_WRITE_SEQ_P: //u8g->pin_list[U8G_PI_SET_A0] = 1; if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 ) return platform_i2c_send_stop( ESP_I2C_ID ), 0; { register uint8_t *ptr = arg_ptr; while( arg_val > 0 ) { // ignore return value -> tolerate missing ACK if ( platform_i2c_send_byte( ESP_I2C_ID, u8g_pgm_read(ptr) ) == 0 ) ; //return 0; ptr++; arg_val--; } } // platform_i2c_send_stop( ESP_I2C_ID ); break; case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */ u8g->pin_list[U8G_PI_A0_STATE] = arg_val; u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again */ break; } return 1; } // device constructors // Lua: speed = u8g.ssd1306_128x64_i2c( i2c_addr ) static int lu8g_ssd1306_128x64_i2c( lua_State *L ) { unsigned addr = luaL_checkinteger( L, 1 ); if (addr == 0) return luaL_error( L, "i2c address required" ); lu8g_userdata_t *userdata = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) ); userdata->i2c_addr = (uint8_t)addr; u8g_InitI2C( &(userdata->u8g), &u8g_dev_ssd1306_128x64_i2c, U8G_I2C_OPT_NONE); // set its metatable luaL_getmetatable(L, "u8g.display"); lua_setmetatable(L, -2); return 1; } // Module function map #define MIN_OPT_LEVEL 2 #include "lrodefs.h" static const LUA_REG_TYPE lu8g_display_map[] = { { LSTRKEY( "setup" ), LFUNCVAL( lu8g_setup ) }, #if LUA_OPTIMIZE_MEMORY > 0 { LSTRKEY( "__index" ), LROVAL ( lu8g_display_map ) }, #endif { LNILKEY, LNILVAL } }; const LUA_REG_TYPE lu8g_map[] = { { LSTRKEY( "ssd1306_128x64_i2c" ), LFUNCVAL ( lu8g_ssd1306_128x64_i2c ) }, #if LUA_OPTIMIZE_MEMORY > 0 { LSTRKEY( "__metatable" ), LROVAL( lu8g_map ) }, #endif { LNILKEY, LNILVAL } }; LUALIB_API int ICACHE_FLASH_ATTR luaopen_u8g( lua_State *L ) { #if LUA_OPTIMIZE_MEMORY > 0 luaL_rometatable(L, "u8g.display", (void *)lu8g_display_map); // create metatable return 0; #else // #if LUA_OPTIMIZE_MEMORY > 0 int n; luaL_register( L, AUXLIB_U8G, lu8g_map ); // Set it as its own metatable lua_pushvalue( L, -1 ); lua_setmetatable( L, -2 ); // Module constants // MOD_REG_NUMBER( L, "TCP", TCP ); // create metatable luaL_newmetatable(L, "u8g.display"); // metatable.__index = metatable lua_pushliteral(L, "__index"); lua_pushvalue(L,-2); lua_rawset(L,-3); // Setup the methods inside metatable luaL_register( L, NULL, u8g_display_map ); return 1; #endif // #if LUA_OPTIMIZE_MEMORY > 0 }