u8g2: add rfb support
This commit is contained in:
parent
b3eaba86e4
commit
64f8ac2876
|
@ -569,96 +569,173 @@ static const LUA_REG_TYPE lu8g2_display_map[] = {
|
|||
};
|
||||
|
||||
|
||||
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;
|
||||
|
||||
lspi_host_t *host = NULL;
|
||||
int host_ref = LUA_NOREF;
|
||||
int cs = -1;
|
||||
int dc = -1;
|
||||
int res = -1;
|
||||
int rfb_cb_ref = LUA_NOREF;
|
||||
|
||||
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 );
|
||||
|
||||
cs = luaL_checkint( L, ++stack );
|
||||
dc = luaL_checkint( L, ++stack );
|
||||
res = luaL_optint( L, ++stack, -1 );
|
||||
} else
|
||||
stack--;
|
||||
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 ) \
|
||||
{ \
|
||||
int stack = 0; \
|
||||
\
|
||||
int id = luaL_checkint( L, ++stack ); \
|
||||
\
|
||||
int i2c_addr = luaL_checkint( L, ++stack ); \
|
||||
luaL_argcheck( L, i2c_addr >= 0 && i2c_addr <= 0x7f, stack, "invalid i2c address" ); \
|
||||
\
|
||||
u8g2_ud_t *ud = (u8g2_ud_t *)lua_newuserdata( L, sizeof( u8g2_ud_t ) ); \
|
||||
u8g2_nodemcu_t *u8g2 = &(ud->u8g2); \
|
||||
ud->font_ref = LUA_NOREF; \
|
||||
ud->host_ref = LUA_NOREF; \
|
||||
/* the i2c driver id is forwarded in the hal member */ \
|
||||
u8g2->hal = (void *)id; \
|
||||
\
|
||||
function( (u8g2_t *)u8g2, U8G2_R0, u8x8_byte_nodemcu_i2c, u8x8_gpio_and_delay_nodemcu ); \
|
||||
u8x8_SetI2CAddress( (u8x8_t *)u8g2, i2c_addr ); \
|
||||
\
|
||||
u8g2_InitDisplay( (u8g2_t *)u8g2 ); \
|
||||
u8g2_ClearDisplay( (u8g2_t *)u8g2 ); \
|
||||
u8g2_SetPowerSave( (u8g2_t *)u8g2, 0 ); \
|
||||
\
|
||||
/* set its metatable */ \
|
||||
luaL_getmetatable(L, "u8g2.display"); \
|
||||
lua_setmetatable(L, -2); \
|
||||
\
|
||||
return 1; \
|
||||
#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
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
// SPI based devices will use this function template to implement the Lua binding.
|
||||
#undef U8G2_DISPLAY_TABLE_ENTRY
|
||||
#define U8G2_DISPLAY_TABLE_ENTRY(function, binding) \
|
||||
static int l ## binding( lua_State *L ) \
|
||||
{ \
|
||||
int stack = 0; \
|
||||
\
|
||||
lspi_host_t *host = (lspi_host_t *)luaL_checkudata( L, ++stack, "spi.master" ); \
|
||||
/* reference host object to avoid automatic gc */ \
|
||||
lua_pushvalue( L, stack ); \
|
||||
int host_ref = luaL_ref( L, LUA_REGISTRYINDEX ); \
|
||||
\
|
||||
int cs = luaL_checkint( L, ++stack ); \
|
||||
int dc = luaL_checkint( L, ++stack ); \
|
||||
int res = luaL_optint( L, ++stack, -1 ); \
|
||||
\
|
||||
u8g2_ud_t *ud = (u8g2_ud_t *)lua_newuserdata( L, sizeof( u8g2_ud_t ) ); \
|
||||
u8g2_nodemcu_t *u8g2 = &(ud->u8g2); \
|
||||
ud->font_ref = LUA_NOREF; \
|
||||
ud->host_ref = host_ref; \
|
||||
/* the spi host id is forwarded in the hal member */ \
|
||||
u8g2->hal = (void *)(host->host); \
|
||||
\
|
||||
function( (u8g2_t *)u8g2, U8G2_R0, u8x8_byte_nodemcu_spi, u8x8_gpio_and_delay_nodemcu ); \
|
||||
u8x8_SetPin( (u8x8_t *)u8g2, U8X8_PIN_CS, cs ); \
|
||||
u8x8_SetPin( (u8x8_t *)u8g2, U8X8_PIN_DC, dc ); \
|
||||
if (res >= 0) \
|
||||
u8x8_SetPin( (u8x8_t *)u8g2, U8X8_PIN_RESET, res ); \
|
||||
\
|
||||
u8g2_InitDisplay( (u8g2_t *)u8g2 ); \
|
||||
u8g2_ClearDisplay( (u8g2_t *)u8g2 ); \
|
||||
u8g2_SetPowerSave( (u8g2_t *)u8g2, 0 ); \
|
||||
\
|
||||
/* set its metatable */ \
|
||||
luaL_getmetatable(L, "u8g2.display"); \
|
||||
lua_setmetatable(L, -2); \
|
||||
\
|
||||
return 1; \
|
||||
#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
|
||||
|
|
|
@ -9,6 +9,13 @@
|
|||
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;
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
COMPONENT_SRCDIRS:=u8g2/src/clib
|
||||
COMPONENT_SRCDIRS:=u8g2/src/clib .
|
||||
COMPONENT_ADD_INCLUDEDIRS:=u8g2/src/clib
|
||||
CPPFLAGS+=-DU8X8_USE_PINS
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
|
||||
#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;
|
||||
}
|
|
@ -120,11 +120,12 @@ Initialize a display via I²C.
|
|||
- `u8g2.uc1611_i2c_ea_dogxl240()`
|
||||
|
||||
#### Syntax
|
||||
`u8g2.ssd1306_i2c_128x64_noname(id, address)`
|
||||
`u8g2.ssd1306_i2c_128x64_noname(id, address[, cb_fn])`
|
||||
|
||||
#### Parameters
|
||||
- `id` i2c interface id, see [i2c module](i2c.md)
|
||||
- `address` I²C slave address of display (unshifted)
|
||||
- `cb_fn` optional callback function, see [Framebuffer callback](#framebuffer-callback)
|
||||
|
||||
#### Returns
|
||||
u8g2 display object
|
||||
|
@ -184,12 +185,13 @@ Initialize a display via Hardware SPI.
|
|||
- `u8g2.uc1701_mini12864()`
|
||||
|
||||
#### Syntax
|
||||
`u8g2.ssd1306_128x64_noname(cs, dc[, res])`
|
||||
`u8g2.ssd1306_128x64_noname(cs, dc[, [res][, cb_fn]])`
|
||||
|
||||
#### Parameters
|
||||
- `cs` GPIO pin for CS
|
||||
- `dc` GPIO pin for DC
|
||||
- `res` GPIO pin for RES, none if omitted
|
||||
- `cb_fn` optional callback function, see [Framebuffer callback](#framebuffer-callback)
|
||||
|
||||
#### Returns
|
||||
u8g2 display object
|
||||
|
@ -205,6 +207,31 @@ bus = spi.master(spi.HSPI, {sclk=sclk, mosi=mosi})
|
|||
disp = u8g2.ssd1306_128x64_noname(bus, cs, dc, res)
|
||||
```
|
||||
|
||||
## Framebuffer callback
|
||||
Each display type can be initialized to provide the framebuffer contents in run-length encoded format to a Lua callback. This mode is enabled when a callback function is specified for the setup function. Hardware display and framebuffer callback can be operated in parallel. If the callback function is the only parameter then no signals for a hardware display are generated, leaving a virtual display.
|
||||
|
||||
The callback function can be used to process the framebuffer line by line. It's called with either `nil` as parameter to indicate the start of a new frame or with a string containing a line of the framebuffer with run-length encoding. First byte in the string specifies how many pairs of (x, len) follow, while each pair defines the start (leftmost x-coordinate) and length of a sequence of lit pixels. All other pixels in the line are dark.
|
||||
|
||||
```lua
|
||||
n = struct.unpack("B", rle_line)
|
||||
print(n.." pairs")
|
||||
for i = 0,n-1 do
|
||||
print(string.format(" x: %d len: %d", struct.unpack("BB", rle_line, 1+1 + i*2)))
|
||||
end
|
||||
```
|
||||
|
||||
#### Syntax
|
||||
```lua
|
||||
u8g2.ssd1306_i2c_128x64_noname(id, address[, cb_fn])
|
||||
u8g2.ssd1306_i2c_128x64_noname(cb_fn)
|
||||
u8g2.ssd1306_128x64_noname(cs, dc[, [res][, cb_fn]])
|
||||
u8g2.ssd1306_128x64_noname(cb_fn)
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
- `id`, `address`, `cs`, `dc`, `res` see above
|
||||
- `cb_fn([rle_line])` callback function. `rle_line` is a string containing a run-length encoded framebuffer line, or `nil` to indicate start of frame.
|
||||
|
||||
## Constants
|
||||
Constants for various functions.
|
||||
|
||||
|
|
Loading…
Reference in New Issue