10 #include "luat_base.h"
13 #include "luat_zbuff.h"
15 #include "luat_gpio.h"
17 #define LUAT_LOG_TAG "lcd"
21 #include "u8g2_luat_fonts.h"
22 #include "luat_u8g2.h"
24 #include "qrcodegen.h"
26 int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t
*f
, uint8_t cnt
);
27 uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t
*f
, uint8_t cnt
);
29 extern luat_color_t BACK_COLOR
, FORE_COLOR
;
31 extern const luat_lcd_opts_t lcd_opts_custom
;
33 typedef struct lcd_reg
{
35 const luat_lcd_opts_t
*lcd_opts
;
38 static const lcd_reg_t lcd_regs
[] = {
39 {"custom", &lcd_opts_custom
}, //0 固定为第零个
40 {"st7735", &lcd_opts_st7735
},
41 {"st7735v", &lcd_opts_st7735v
},
42 {"st7735s", &lcd_opts_st7735s
},
43 {"st7789", &lcd_opts_st7789
},
44 {"st7796", &lcd_opts_st7796
},
45 {"gc9a01", &lcd_opts_gc9a01
},
46 {"gc9106l", &lcd_opts_gc9106l
},
47 {"gc9306x", &lcd_opts_gc9306x
},
48 {"gc9306", &lcd_opts_gc9306x
}, //gc9306是gc9306x的别名
49 {"ili9341", &lcd_opts_ili9341
},
50 {"ili9486", &lcd_opts_ili9486
},
51 {"nv3037", &lcd_opts_nv3037
},
52 {"", NULL
} // 最后一个必须是空字符串
56 static luat_lcd_conf_t
*default_conf
= NULL
;
57 // static int dft_conf_lua_ref = 0;
60 static void lcd_auto_flush(luat_lcd_conf_t
*conf
) {
61 #ifndef LUAT_USE_LCD_SDL2
62 if (conf
== NULL
|| conf
->buff
== NULL
|| conf
->auto_flush
== 0)
68 luat_color_t lcd_str_fg_color
,lcd_str_bg_color
;
69 luat_lcd_conf_t
*l_lcd_get_default_conf(void) {return default_conf
;}
70 LUAT_WEAK
void luat_lcd_IF_init(luat_lcd_conf_t
* conf
){}
71 LUAT_WEAK
int luat_lcd_init_in_service(luat_lcd_conf_t
* conf
){return -1;}
74 @api lcd.init(tp, args, spi_dev, init_in_service)
75 @string lcd类型,当前支持:<br>st7796<br>st7789<br>st7735<br>st7735v<br>st7735s<br>gc9a01<br>gc9106l<br>gc9306x<br>ili9486<br>custom
76 @table 附加参数,与具体设备有关:<br>pin_pwr(背光)为可选项,可不设置<br>port:spi端口,例如0,1,2...如果为device方式则为"device"<br>pin_dc:lcd数据/命令选择引脚<br>pin_rst:lcd复位引脚<br>pin_pwr:lcd背光引脚 可选项,可不设置<br>direction:lcd屏幕方向 0:0° 1:180° 2:270° 3:90°<br>w:lcd 水平分辨率<br>h:lcd 竖直分辨率<br>xoffset:x偏移(不同屏幕ic 不同屏幕方向会有差异)<br>yoffset:y偏移(不同屏幕ic 不同屏幕方向会有差异)<br>direction0:0°方向命令,(不同屏幕ic会有差异)<br>direction90:90°方向命令,(不同屏幕ic会有差异)<br>direction180:180°方向命令,(不同屏幕ic会有差异)<br>direction270:270°方向命令,(不同屏幕ic会有差异) <br>sleepcmd:睡眠命令,默认0X10<br>wakecmd:唤醒命令,默认0X11 <br>interface_mode lcd模式,默认lcd.WIRE_4_BIT_8_INTERFACE_I
77 @userdata spi设备,当port = "device"时有效
78 @boolean 允许初始化在lcd service里运行,默认是false
80 -- 初始化spi0的st7735s 注意:lcd初始化之前需要先初始化spi
81 spi_lcd = spi.deviceSetup(0,20,0,0,8,2000000,spi.MSB,1,1)
83 lcd.init("st7735s",{port = "device",pin_dc = 17, pin_pwr = 7,pin_rst = 19,direction = 2,w = 160,h = 80,xoffset = 1,yoffset = 26},spi_lcd))
85 static int l_lcd_init(lua_State
* L
) {
87 luat_lcd_conf_t
*conf
= luat_heap_malloc(sizeof(luat_lcd_conf_t
));
89 LLOGE("out of system memory!!!");
92 if (default_conf
!= NULL
) {
93 LLOGD("lcd was inited, skip");
94 lua_pushboolean(L
, 1);
97 #if defined LUAT_USE_LCD_SERVICE
98 uint8_t init_in_service
= 0;
100 if (lua_isboolean(L
, 4)) {
101 init_in_service
= lua_toboolean(L
, 4);
104 memset(conf
, 0, sizeof(luat_lcd_conf_t
)); // 填充0,保证无脏数据
105 conf
->lcd_cs_pin
= LUAT_GPIO_NONE
;
106 conf
->pin_dc
= LUAT_GPIO_NONE
;
107 conf
->pin_pwr
= LUAT_GPIO_NONE
;
108 conf
->interface_mode
= LUAT_LCD_IM_4_WIRE_8_BIT_INTERFACE_I
;
109 if (lua_type(L
, 3) == LUA_TUSERDATA
){
110 // 如果是SPI Device模式, 就可能出现变量为local, 从而在某个时间点被GC掉的可能性
111 conf
->lcd_spi_device
= (luat_spi_device_t
*)lua_touserdata(L
, 3);
113 // 所以, 直接引用之外, 再加上强制引用, 避免被GC
114 // 鉴于LCD不太可能重复初始化, 引用也没什么问题
115 conf
->lcd_spi_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
116 conf
->port
= LUAT_LCD_SPI_DEVICE
;
118 const char* tp
= luaL_checklstring(L
, 1, &len
);
119 int16_t s_index
= -1;//第几个屏幕,-1表示没匹配到
120 for(int i
= 0; i
< 100; i
++){
121 if (strlen(lcd_regs
[i
].name
) == 0)
123 if(strcmp(lcd_regs
[i
].name
,tp
) == 0){
129 LLOGD("ic support: %s",tp
);
130 if (lua_gettop(L
) > 1) {
131 conf
->opts
= (struct luat_lcd_opts
*)lcd_regs
[s_index
].lcd_opts
;
132 lua_settop(L
, 2); // 丢弃多余的参数
134 lua_pushstring(L
, "port");
135 int port
= lua_gettable(L
, 2);
136 if (conf
->port
== LUAT_LCD_SPI_DEVICE
&& port
==LUA_TNUMBER
) {
137 LLOGE("port is not device but find luat_spi_device_t");
139 }else if (conf
->port
!= LUAT_LCD_SPI_DEVICE
&& LUA_TSTRING
== port
){
140 LLOGE("port is device but not find luat_spi_device_t");
142 }else if (LUA_TNUMBER
== port
) {
143 conf
->port
= luaL_checkinteger(L
, -1);
144 }else if (LUA_TSTRING
== port
){
145 conf
->port
= LUAT_LCD_SPI_DEVICE
;
149 lua_pushstring(L
, "pin_dc");
150 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
151 conf
->pin_dc
= luaL_checkinteger(L
, -1);
155 lua_pushstring(L
, "pin_pwr");
156 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
157 conf
->pin_pwr
= luaL_checkinteger(L
, -1);
161 lua_pushstring(L
, "pin_rst");
162 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
163 conf
->pin_rst
= luaL_checkinteger(L
, -1);
167 lua_pushstring(L
, "direction");
168 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
169 conf
->direction
= luaL_checkinteger(L
, -1);
172 lua_pushstring(L
, "direction0");
173 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
174 conf
->opts
->direction0
= luaL_checkinteger(L
, -1);
177 lua_pushstring(L
, "direction90");
178 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
179 conf
->opts
->direction90
= luaL_checkinteger(L
, -1);
182 lua_pushstring(L
, "direction180");
183 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
184 conf
->opts
->direction180
= luaL_checkinteger(L
, -1);
187 lua_pushstring(L
, "direction270");
188 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
189 conf
->opts
->direction270
= luaL_checkinteger(L
, -1);
193 lua_pushstring(L
, "w");
194 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
195 conf
->w
= luaL_checkinteger(L
, -1);
198 lua_pushstring(L
, "h");
199 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
200 conf
->h
= luaL_checkinteger(L
, -1);
203 conf
->buffer_size
= (conf
->w
* conf
->h
) * 2;
205 lua_pushstring(L
, "xoffset");
206 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
207 conf
->xoffset
= luaL_checkinteger(L
, -1);
211 lua_pushstring(L
, "yoffset");
212 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
213 conf
->yoffset
= luaL_checkinteger(L
, -1);
217 lua_pushstring(L
, "sleepcmd");
218 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
219 conf
->opts
->sleep_cmd
= luaL_checkinteger(L
, -1);
223 lua_pushstring(L
, "wakecmd");
224 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
225 conf
->opts
->wakeup_cmd
= luaL_checkinteger(L
, -1);
229 lua_pushstring(L
, "interface_mode");
230 if (LUA_TNUMBER
== lua_gettable(L
, 2)) {
231 conf
->interface_mode
= luaL_checkinteger(L
, -1);
237 unsigned int cmd
= 0;
238 lua_pushstring(L
, "initcmd");
240 if (lua_istable(L
, -1)) {
241 conf
->opts
->init_cmds_len
= lua_rawlen(L
, -1);
242 conf
->opts
->init_cmds
= luat_heap_malloc( conf
->opts
->init_cmds_len
* sizeof(uint16_t));
243 for (size_t i
= 1; i
<= conf
->opts
->init_cmds_len
; i
++){
245 cmd
= luaL_checkinteger(L
, -1);
246 conf
->opts
->init_cmds
[i
-1] = ((cmd
>> 8) & 0xFF00) | (cmd
& 0xFF);
249 }else if(lua_isstring(L
, -1)){
251 const char *fail_name
= luaL_checklstring(L
, -1, &len
);
252 FILE* fd
= (FILE *)luat_fs_fopen(fail_name
, "rb");
253 conf
->opts
->init_cmds_len
= 0;
255 #define INITCMD_BUFF_SIZE 128
256 char init_cmd_buff
[INITCMD_BUFF_SIZE
] ;
257 conf
->opts
->init_cmds
= luat_heap_malloc(sizeof(uint16_t));
259 memset(init_cmd_buff
, 0, INITCMD_BUFF_SIZE
);
260 int readline_len
= luat_fs_readline(init_cmd_buff
, INITCMD_BUFF_SIZE
-1, fd
);
261 if (readline_len
< 1)
263 if (memcmp(init_cmd_buff
, "#", 1)==0){
266 char *token
= strtok(init_cmd_buff
, ",");
267 if (sscanf(token
,"%x",&cmd
) < 1){
270 conf
->opts
->init_cmds_len
= conf
->opts
->init_cmds_len
+ 1;
271 conf
->opts
->init_cmds
= luat_heap_realloc(conf
->opts
->init_cmds
,conf
->opts
->init_cmds_len
* sizeof(uint16_t));
272 conf
->opts
->init_cmds
[conf
->opts
->init_cmds_len
-1]=((cmd
>> 8) & 0xFF00) | (cmd
& 0xFF);;
273 while( token
!= NULL
) {
274 token
= strtok(NULL
, ",");
275 if (sscanf(token
,"%x",&cmd
) < 1){
278 conf
->opts
->init_cmds_len
= conf
->opts
->init_cmds_len
+ 1;
279 conf
->opts
->init_cmds
= luat_heap_realloc(conf
->opts
->init_cmds
,conf
->opts
->init_cmds_len
* sizeof(uint16_t));
280 conf
->opts
->init_cmds
[conf
->opts
->init_cmds_len
-1]=((cmd
>> 8) & 0xFF00) | (cmd
& 0xFF);;
283 conf
->opts
->init_cmds
[conf
->opts
->init_cmds_len
]= 0;
286 LLOGE("init_cmd fail open error");
291 // 默认自动flush,即使没有buff
292 conf
->auto_flush
= 1;
294 #ifdef LUAT_USE_LCD_SDL2
295 extern const luat_lcd_opts_t lcd_opts_sdl2
;
296 conf
->opts
= &lcd_opts_sdl2
;
298 if (conf
->port
== LUAT_LCD_HW_ID_0
) luat_lcd_IF_init(conf
);
299 #if defined LUAT_USE_LCD_SERVICE
300 if (init_in_service
) {
301 ret
= luat_lcd_init_in_service(conf
);
303 ret
= luat_lcd_init(conf
);
307 int ret
= luat_lcd_init(conf
);
310 LLOGE("lcd init fail %d", ret
);
311 luat_heap_free(conf
);
312 lua_pushboolean(L
, 0);
317 u8g2_SetFont(&(conf
->luat_lcd_u8g2
), u8g2_font_opposansm12
);
318 u8g2_SetFontMode(&(conf
->luat_lcd_u8g2
), 0);
319 u8g2_SetFontDirection(&(conf
->luat_lcd_u8g2
), 0);
320 lua_pushboolean(L
, 1);
323 LLOGE("ic not support: %s",tp
);
325 lua_pushboolean(L
, 0);
326 luat_heap_free(conf
);
337 static int l_lcd_close(lua_State
* L
) {
338 int ret
= luat_lcd_close(default_conf
);
339 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
350 static int l_lcd_display_on(lua_State
* L
) {
351 int ret
= luat_lcd_display_on(default_conf
);
352 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
363 static int l_lcd_display_off(lua_State
* L
) {
364 int ret
= luat_lcd_display_off(default_conf
);
365 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
376 static int l_lcd_sleep(lua_State
* L
) {
377 int ret
= luat_lcd_sleep(default_conf
);
378 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
389 static int l_lcd_wakeup(lua_State
* L
) {
390 int ret
= luat_lcd_wakeup(default_conf
);
391 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
402 static int l_lcd_inv_on(lua_State
* L
) {
403 int ret
= luat_lcd_inv_on(default_conf
);
404 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
415 static int l_lcd_inv_off(lua_State
* L
) {
416 int ret
= luat_lcd_inv_off(default_conf
);
417 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
429 static int l_lcd_write_cmd(lua_State
* L
) {
430 int ret
= lcd_write_cmd_data(default_conf
,(uint8_t)luaL_checkinteger(L
, 1), NULL
, 0);
431 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
443 static int l_lcd_write_data(lua_State
* L
) {
444 int ret
= lcd_write_data(default_conf
,(const uint8_t)luaL_checkinteger(L
, 1));
445 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
451 @api lcd.setColor(back,fore)
456 lcd.setColor(0xFFFF,0x0000)
458 static int l_lcd_set_color(lua_State
* L
) {
459 luat_color_t back
,fore
;
460 back
= (luat_color_t
)luaL_checkinteger(L
, 1);
461 fore
= (luat_color_t
)luaL_checkinteger(L
, 2);
462 int ret
= luat_lcd_set_color(back
, fore
);
463 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
467 static int l_lcd_set_direction(lua_State
* L
) {
468 int ret
= luat_lcd_set_direction(default_conf
, (uint8_t)luaL_checkinteger(L
, 1));
469 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
475 @api lcd.draw(x1, y1, x2, y2,color)
483 local buff = zbuff.create({201,1,16},0x001F)
484 lcd.draw(20,30,220,30,buff)
486 static int l_lcd_draw(lua_State
* L
) {
487 int16_t x1
, y1
, x2
, y2
;
489 // luat_color_t *color = NULL;
491 x1
= luaL_checkinteger(L
, 1);
492 y1
= luaL_checkinteger(L
, 2);
493 x2
= luaL_checkinteger(L
, 3);
494 y2
= luaL_checkinteger(L
, 4);
495 if (lua_isinteger(L
, 5)) {
496 // color = (luat_color_t *)luaL_checkstring(L, 5);
497 luat_color_t color
= (luat_color_t
)luaL_checkinteger(L
, 1);
498 ret
= luat_lcd_draw(default_conf
, x1
, y1
, x2
, y2
, &color
);
500 else if (lua_isuserdata(L
, 5)) {
501 buff
= luaL_checkudata(L
, 5, LUAT_ZBUFF_TYPE
);
502 luat_color_t
*color
= (luat_color_t
*)buff
->addr
;
503 ret
= luat_lcd_draw(default_conf
, x1
, y1
, x2
, y2
, color
);
505 else if(lua_isstring(L
, 5)) {
506 luat_color_t
*color
= (luat_color_t
*)luaL_checkstring(L
, 5);
507 ret
= luat_lcd_draw(default_conf
, x1
, y1
, x2
, y2
, color
);
512 lcd_auto_flush(default_conf
);
513 // int ret = luat_lcd_draw(default_conf, x1, y1, x2, y2, color);
514 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
520 @api lcd.clear(color)
526 static int l_lcd_clear(lua_State
* L
) {
528 luat_color_t color
= BACK_COLOR
;
529 if (lua_gettop(L
) > 0)
530 color
= (luat_color_t
)luaL_checkinteger(L
, 1);
531 int ret
= luat_lcd_clear(default_conf
, color
);
532 lcd_auto_flush(default_conf
);
533 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
539 @api lcd.fill(x1, y1, x2, y2,color)
547 lcd.fill(20,30,220,30,0x0000)
549 static int l_lcd_draw_fill(lua_State
* L
) {
550 int16_t x1
, y1
, x2
, y2
;
551 luat_color_t color
= BACK_COLOR
;
552 x1
= luaL_checkinteger(L
, 1);
553 y1
= luaL_checkinteger(L
, 2);
554 x2
= luaL_checkinteger(L
, 3);
555 y2
= luaL_checkinteger(L
, 4);
556 if (lua_gettop(L
) > 4)
557 color
= (luat_color_t
)luaL_checkinteger(L
, 5);
558 int ret
= luat_lcd_draw_fill(default_conf
, x1
, y1
, x2
, y2
, color
);
559 lcd_auto_flush(default_conf
);
560 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
566 @api lcd.drawPoint(x0,y0,color)
571 lcd.drawPoint(20,30,0x001F)
573 static int l_lcd_draw_point(lua_State
* L
) {
575 luat_color_t color
= FORE_COLOR
;
576 x
= luaL_checkinteger(L
, 1);
577 y
= luaL_checkinteger(L
, 2);
578 if (lua_gettop(L
) > 2)
579 color
= (luat_color_t
)luaL_checkinteger(L
, 3);
580 int ret
= luat_lcd_draw_point(default_conf
, x
, y
, color
);
581 lcd_auto_flush(default_conf
);
582 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
588 @api lcd.drawLine(x0,y0,x1,y1,color)
595 lcd.drawLine(20,30,220,30,0x001F)
597 static int l_lcd_draw_line(lua_State
* L
) {
598 int16_t x1
, y1
, x2
, y2
;
599 luat_color_t color
= FORE_COLOR
;
600 x1
= luaL_checkinteger(L
, 1);
601 y1
= luaL_checkinteger(L
, 2);
602 x2
= luaL_checkinteger(L
, 3);
603 y2
= luaL_checkinteger(L
, 4);
604 if (lua_gettop(L
) > 4)
605 color
= (luat_color_t
)luaL_checkinteger(L
, 5);
606 int ret
= luat_lcd_draw_line(default_conf
, x1
, y1
, x2
, y2
, color
);
607 lcd_auto_flush(default_conf
);
608 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
613 从x / y位置(左上边缘)开始绘制一个框
614 @api lcd.drawRectangle(x0,y0,x1,y1,color)
621 lcd.drawRectangle(20,40,220,80,0x001F)
623 static int l_lcd_draw_rectangle(lua_State
* L
) {
624 int16_t x1
, y1
, x2
, y2
;
625 luat_color_t color
= FORE_COLOR
;
626 x1
= luaL_checkinteger(L
, 1);
627 y1
= luaL_checkinteger(L
, 2);
628 x2
= luaL_checkinteger(L
, 3);
629 y2
= luaL_checkinteger(L
, 4);
630 if (lua_gettop(L
) > 4)
631 color
= (luat_color_t
)luaL_checkinteger(L
, 5);
632 int ret
= luat_lcd_draw_rectangle(default_conf
, x1
, y1
, x2
, y2
, color
);
633 lcd_auto_flush(default_conf
);
634 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
640 @api lcd.drawCircle(x0,y0,r,color)
646 lcd.drawCircle(120,120,20,0x001F)
648 static int l_lcd_draw_circle(lua_State
* L
) {
650 luat_color_t color
= FORE_COLOR
;
651 x0
= luaL_checkinteger(L
, 1);
652 y0
= luaL_checkinteger(L
, 2);
653 r
= luaL_checkinteger(L
, 3);
654 if (lua_gettop(L
) > 3)
655 color
= (luat_color_t
)luaL_checkinteger(L
, 4);
656 int ret
= luat_lcd_draw_circle(default_conf
, x0
, y0
, r
, color
);
657 lcd_auto_flush(default_conf
);
658 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
664 @api lcd.drawQrcode(x, y, str, size)
668 @int 显示大小 (注意:二维码生成大小与要显示内容和纠错等级有关,生成版本为1-40(对应 21x21 - 177x177)的不定大小,如果和设置大小不同会自动在指定的区域中间显示二维码,如二维码未显示请查看日志提示)
671 static int l_lcd_drawQrcode(lua_State
*L
)
674 int x
= luaL_checkinteger(L
, 1);
675 int y
= luaL_checkinteger(L
, 2);
676 const char* text
= luaL_checklstring(L
, 3, &len
);
677 int size
= luaL_checkinteger(L
, 4);
678 uint8_t *qrcode
= luat_heap_malloc(qrcodegen_BUFFER_LEN_MAX
);
679 uint8_t *tempBuffer
= luat_heap_malloc(qrcodegen_BUFFER_LEN_MAX
);
680 if (qrcode
== NULL
|| tempBuffer
== NULL
) {
682 luat_heap_free(qrcode
);
684 luat_heap_free(tempBuffer
);
685 LLOGE("qrcode out of memory");
688 bool ok
= qrcodegen_encodeText(text
, tempBuffer
, qrcode
, qrcodegen_Ecc_LOW
,
689 qrcodegen_VERSION_MIN
, qrcodegen_VERSION_MAX
, qrcodegen_Mask_AUTO
, true);
691 int qr_size
= qrcodegen_getSize(qrcode
);
693 LLOGE("size must be greater than qr_size %d",qr_size
);
696 int scale
= size
/ qr_size
;
697 if (!scale
)scale
= 1;
698 int margin
= (size
- qr_size
* scale
) / 2;
699 luat_lcd_draw_fill(default_conf
,x
,y
,x
+size
,y
+size
,BACK_COLOR
);
702 for (int j
= 0; j
< qr_size
; j
++) {
703 for (int i
= 0; i
< qr_size
; i
++) {
704 if (qrcodegen_getModule(qrcode
, i
, j
))
705 luat_lcd_draw_fill(default_conf
,x
+i
*scale
,y
+j
*scale
,x
+(i
+1)*scale
,y
+(j
+1)*scale
,FORE_COLOR
);
709 LLOGE("qrcodegen_encodeText false");
713 luat_heap_free(qrcode
);
715 luat_heap_free(tempBuffer
);
716 lcd_auto_flush(default_conf
);
720 static uint8_t utf8_state
;
721 static uint16_t encoding
;
722 static uint16_t utf8_next(uint8_t b
)
724 if ( b
== 0 ) /* '\n' terminates the string to support the string list procedures */
725 return 0x0ffff; /* end of string detected, pending UTF8 is discarded */
726 if ( utf8_state
== 0 )
728 if ( b
>= 0xfc ) /* 6 byte sequence */
733 else if ( b
>= 0xf8 )
738 else if ( b
>= 0xf0 )
743 else if ( b
>= 0xe0 )
748 else if ( b
>= 0xc0 )
755 /* do nothing, just use the value as encoding */
764 /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
768 if ( utf8_state
!= 0 )
769 return 0x0fffe; /* nothing to do yet */
774 static void u8g2_draw_hv_line(u8g2_t
*u8g2
, int16_t x
, int16_t y
, int16_t len
, uint8_t dir
, uint16_t color
){
778 luat_lcd_draw_hline(default_conf
,x
,y
,len
,color
);
781 luat_lcd_draw_vline(default_conf
,x
,y
,len
,color
);
784 luat_lcd_draw_hline(default_conf
,x
-len
+1,y
,len
,color
);
787 luat_lcd_draw_vline(default_conf
,x
,y
-len
+1,len
,color
);
792 static void u8g2_font_decode_len(u8g2_t
*u8g2
, uint8_t len
, uint8_t is_foreground
){
793 uint8_t cnt
; /* total number of remaining pixels, which have to be drawn */
794 uint8_t rem
; /* remaining pixel to the right edge of the glyph */
795 uint8_t current
; /* number of pixels, which need to be drawn for the draw procedure */
796 /* current is either equal to cnt or equal to rem */
797 /* local coordinates of the glyph */
799 /* target position on the screen */
801 u8g2_font_decode_t
*decode
= &(u8g2
->font_decode
);
803 /* get the local position */
807 /* calculate the number of pixel to the right edge of the glyph */
808 rem
= decode
->glyph_width
;
810 /* calculate how many pixel to draw. This is either to the right edge */
811 /* or lesser, if not enough pixel are left */
815 /* now draw the line, but apply the rotation around the glyph target position */
816 //u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
817 // printf("lx:%d,ly:%d,current:%d, is_foreground:%d \r\n",lx,ly,current, is_foreground);
818 /* get target position */
819 x
= decode
->target_x
;
820 y
= decode
->target_y
;
822 x
= u8g2_add_vector_x(x
, lx
, ly
, decode
->dir
);
823 y
= u8g2_add_vector_y(y
, lx
, ly
, decode
->dir
);
824 /* draw foreground and background (if required) */
825 if ( current
> 0 ) /* avoid drawing zero length lines, issue #4 */
829 u8g2_draw_hv_line(u8g2
, x
, y
, current
, decode
->dir
, lcd_str_fg_color
);
831 // else if ( decode->is_transparent == 0 )
833 // u8g2_draw_hv_line(u8g2, x, y, current, decode->dir, lcd_str_bg_color);
836 /* check, whether the end of the run length code has been reached */
847 static void u8g2_font_setup_decode(u8g2_t
*u8g2
, const uint8_t *glyph_data
)
849 u8g2_font_decode_t
*decode
= &(u8g2
->font_decode
);
850 decode
->decode_ptr
= glyph_data
;
851 decode
->decode_bit_pos
= 0;
853 /* 8 Nov 2015, this is already done in the glyph data search procedure */
855 decode->decode_ptr += 1;
856 decode->decode_ptr += 1;
859 decode
->glyph_width
= u8g2_font_decode_get_unsigned_bits(decode
, u8g2
->font_info
.bits_per_char_width
);
860 decode
->glyph_height
= u8g2_font_decode_get_unsigned_bits(decode
,u8g2
->font_info
.bits_per_char_height
);
863 static int8_t u8g2_font_decode_glyph(u8g2_t
*u8g2
, const uint8_t *glyph_data
){
868 u8g2_font_decode_t
*decode
= &(u8g2
->font_decode
);
869 u8g2_font_setup_decode(u8g2
, glyph_data
);
870 h
= u8g2
->font_decode
.glyph_height
;
871 x
= u8g2_font_decode_get_signed_bits(decode
, u8g2
->font_info
.bits_per_char_x
);
872 y
= u8g2_font_decode_get_signed_bits(decode
, u8g2
->font_info
.bits_per_char_y
);
873 d
= u8g2_font_decode_get_signed_bits(decode
, u8g2
->font_info
.bits_per_delta_x
);
875 if ( decode
->glyph_width
> 0 )
877 decode
->target_x
= u8g2_add_vector_x(decode
->target_x
, x
, -(h
+y
), decode
->dir
);
878 decode
->target_y
= u8g2_add_vector_y(decode
->target_y
, x
, -(h
+y
), decode
->dir
);
879 //u8g2_add_vector(&(decode->target_x), &(decode->target_y), x, -(h+y), decode->dir);
880 /* reset local x/y position */
885 a
= u8g2_font_decode_get_unsigned_bits(decode
, u8g2
->font_info
.bits_per_0
);
886 b
= u8g2_font_decode_get_unsigned_bits(decode
, u8g2
->font_info
.bits_per_1
);
888 u8g2_font_decode_len(u8g2
, a
, 0);
889 u8g2_font_decode_len(u8g2
, b
, 1);
890 } while( u8g2_font_decode_get_unsigned_bits(decode
, 1) != 0 );
891 if ( decode
->y
>= h
)
897 const uint8_t *u8g2_font_get_glyph_data(u8g2_t
*u8g2
, uint16_t encoding
);
898 static int16_t u8g2_font_draw_glyph(u8g2_t
*u8g2
, int16_t x
, int16_t y
, uint16_t encoding
){
900 u8g2
->font_decode
.target_x
= x
;
901 u8g2
->font_decode
.target_y
= y
;
902 const uint8_t *glyph_data
= u8g2_font_get_glyph_data(u8g2
, encoding
);
903 if ( glyph_data
!= NULL
){
904 dx
= u8g2_font_decode_glyph(u8g2
, glyph_data
);
908 extern void luat_u8g2_set_ascii_indentation(uint8_t value
);
911 @api lcd.setFont(font, indentation)
912 @int font lcd.font_XXX 请查阅常量表
913 @int indentation, 等宽字体ascii右侧缩进0~127个pixel,等宽字体的ascii字符可能在右侧有大片空白,用户可以选择删除部分。留空或者超过127则直接删除右半边, 非等宽字体无效
915 -- 设置为字体,对之后的drawStr有效,调用lcd.drawStr前一定要先设置
917 -- 若提示 "only font pointer is allow" , 则代表当前固件不含对应字体, 可使用云编译服务免费定制
918 -- 云编译文档: https://wiki.luatos.com/develop/compile/Cloud_compilation.html
920 -- lcd库的默认字体均以 lcd.font_ 开头
921 lcd.setFont(lcd.font_opposansm12)
922 lcd.drawStr(40,10,"drawStr")
924 lcd.setFont(lcd.font_opposansm12_chinese) -- 具体取值可参考api文档的常量表
925 lcd.drawStr(40,40,"drawStr测试")
927 static int l_lcd_set_font(lua_State
*L
) {
928 if (!lua_islightuserdata(L
, 1)) {
929 LLOGE("only font pointer is allow");
932 const uint8_t *ptr
= (const uint8_t *)lua_touserdata(L
, 1);
934 LLOGE("only font pointer is allow");
937 luat_u8g2_set_ascii_indentation(0xff);
938 u8g2_SetFont(&(default_conf
->luat_lcd_u8g2
), ptr
);
939 if (lua_isinteger(L
, 2)) {
940 int indentation
= luaL_checkinteger(L
, 2);
941 luat_u8g2_set_ascii_indentation(indentation
);
943 lua_pushboolean(L
, 1);
949 @api lcd.drawStr(x,y,str,fg_color)
951 @int y 竖坐标 注意:此(x,y)为左下起始坐标
953 @int fg_color str颜色 注意:此参数可选,如不填写则使用之前设置的颜色,绘制只会绘制字体部分,背景需要自己清除
955 -- 显示之前先设置为中文字体,对之后的drawStr有效
956 lcd.setFont(lcd.font_opposansm12)
957 lcd.drawStr(40,10,"drawStr")
959 lcd.setFont(lcd.font_opposansm16_chinese)
960 lcd.drawStr(40,40,"drawStr测试")
962 static int l_lcd_draw_str(lua_State
* L
) {
966 x
= luaL_checkinteger(L
, 1);
967 y
= luaL_checkinteger(L
, 2);
968 data
= (const uint8_t*)luaL_checklstring(L
, 3, &sz
);
969 lcd_str_fg_color
= (luat_color_t
)luaL_optinteger(L
, 4,FORE_COLOR
);
970 // lcd_str_bg_color = (uint32_t)luaL_optinteger(L, 5,BACK_COLOR);
978 e
= utf8_next((uint8_t)*data
);
983 delta
= u8g2_font_draw_glyph(&(default_conf
->luat_lcd_u8g2
), x
, y
, e
);
984 if (e
< 0x0080) delta
= luat_u8g2_need_ascii_cut(delta
);
985 switch(default_conf
->luat_lcd_u8g2
.font_decode
.dir
){
1001 lcd_auto_flush(default_conf
);
1005 #ifdef LUAT_USE_GTFONT
1007 #include "GT5SLCD2E_1A.h"
1008 extern unsigned int gtfont_draw_w(unsigned char *pBits
,unsigned int x
,unsigned int y
,unsigned int size
,unsigned int widt
,unsigned int high
,int(*point
)(void*),void* userdata
,int mode
);
1009 extern void gtfont_draw_gray_hz(unsigned char *data
,unsigned short x
,unsigned short y
,unsigned short w
,unsigned short h
,unsigned char grade
, unsigned char HB_par
,int(*point
)(void*,uint16_t, uint16_t, uint32_t),void* userdata
,int mode
);
1013 @api lcd.drawGtfontGb2312(str,size,x,y)
1015 @int size 字体大小 (支持16-192号大小字体)
1019 -- 注意, gtfont是额外的字体芯片硬件, 需要外挂在SPI总线才能调用本函数的
1020 lcd.drawGtfontGb2312("啊啊啊",32,0,0)
1024 @api lcd.drawGtfontGbk(str,size,x,y)
1026 @int size 字体大小 (支持16-192号大小字体)
1030 -- 注意, gtfont是额外的字体芯片硬件, 需要外挂在SPI总线才能调用本函数的
1031 lcd.drawGtfontGbk("啊啊啊",32,0,0)
1033 static int l_lcd_draw_gtfont_gbk(lua_State
*L
) {
1034 unsigned char buf
[128];
1037 uint8_t strhigh
,strlow
;
1039 const char *fontCode
= luaL_checklstring(L
, 1,&len
);
1040 unsigned char size
= luaL_checkinteger(L
, 2);
1041 int x
= luaL_checkinteger(L
, 3);
1042 int y
= luaL_checkinteger(L
, 4);
1043 lcd_str_fg_color
= (luat_color_t
)luaL_optinteger(L
, 5,FORE_COLOR
);
1044 // lcd_str_bg_color = (luat_color_t)luaL_optinteger(L, 6,BACK_COLOR);
1046 strhigh
= *fontCode
;
1049 str
= (strhigh
<<8)|strlow
;
1051 int font_size
= get_font(buf
, str
<0x80?VEC_HZ_ASCII_STY
:VEC_BLACK_STY
, str
, size
, size
, size
);
1053 LLOGW("get gtfont error size:%d font_size:%d",size
,font_size
);
1056 gtfont_draw_w(buf
, x
,y
, font_size
,size
, size
,luat_lcd_draw_point
,default_conf
,0);
1060 lcd_auto_flush(default_conf
);
1065 使用gtfont灰度显示gb2312字符串
1066 @api lcd.drawGtfontGb2312Gray(str,size,gray,x,y)
1068 @int size 字体大小 (支持16-192号大小字体)
1069 @int gray 灰度[1阶/2阶/3阶/4阶]
1073 -- 注意, gtfont是额外的字体芯片硬件, 需要外挂在SPI总线才能调用本函数的
1074 lcd.drawGtfontGb2312Gray("啊啊啊",32,4,0,40)
1078 @api lcd.drawGtfontGbkGray(str,size,gray,x,y)
1080 @int size 字体大小 (支持16-192号大小字体)
1081 @int gray 灰度[1阶/2阶/3阶/4阶]
1085 -- 注意, gtfont是额外的字体芯片硬件, 需要外挂在SPI总线才能调用本函数的
1086 lcd.drawGtfontGbkGray("啊啊啊",32,4,0,40)
1088 static int l_lcd_draw_gtfont_gbk_gray(lua_State
* L
) {
1089 unsigned char buf
[2048];
1092 uint8_t strhigh
,strlow
;
1094 const char *fontCode
= luaL_checklstring(L
, 1,&len
);
1095 unsigned char size
= luaL_checkinteger(L
, 2);
1096 unsigned char font_g
= luaL_checkinteger(L
, 3);
1097 int x
= luaL_checkinteger(L
, 4);
1098 int y
= luaL_checkinteger(L
, 5);
1099 lcd_str_fg_color
= (luat_color_t
)luaL_optinteger(L
, 6,FORE_COLOR
);
1100 // lcd_str_bg_color = (luat_color_t)luaL_optinteger(L, 7,BACK_COLOR);
1102 strhigh
= *fontCode
;
1105 str
= (strhigh
<<8)|strlow
;
1107 int font_size
= get_font(buf
, str
<0x80?VEC_HZ_ASCII_STY
:VEC_BLACK_STY
, str
, size
*font_g
, size
*font_g
, size
*font_g
);
1108 if(font_size
!= size
*font_g
){
1109 LLOGW("get gtfont error size:%d font_size:%d",size
,font_size
);
1112 Gray_Process(buf
,size
,size
,font_g
);
1113 gtfont_draw_gray_hz(buf
, x
, y
, size
, size
, font_g
, 1,luat_lcd_draw_point
,default_conf
,0);
1117 lcd_auto_flush(default_conf
);
1121 #ifdef LUAT_USE_GTFONT_UTF8
1122 extern unsigned short unicodetogb2312 ( unsigned short chr
);
1126 @api lcd.drawGtfontUtf8(str,size,x,y)
1128 @int size 字体大小 (支持16-192号大小字体)
1132 lcd.drawGtfontUtf8("啊啊啊",32,0,0)
1134 static int l_lcd_draw_gtfont_utf8(lua_State
*L
) {
1135 unsigned char buf
[128] = {0};
1138 uint8_t strhigh
,strlow
;
1140 const char *fontCode
= luaL_checklstring(L
, 1,&len
);
1141 unsigned char size
= luaL_checkinteger(L
, 2);
1142 int x
= luaL_checkinteger(L
, 3);
1143 int y
= luaL_checkinteger(L
, 4);
1144 lcd_str_fg_color
= (luat_color_t
)luaL_optinteger(L
, 5,FORE_COLOR
);
1145 // lcd_str_bg_color = (luat_color_t)luaL_optinteger(L, 6,BACK_COLOR);
1147 e
= utf8_next((uint8_t)*fontCode
);
1151 if ( e
!= 0x0fffe ){
1152 uint16_t str
= unicodetogb2312(e
);
1154 int font_size
= get_font(buf
, str
<0x80?VEC_HZ_ASCII_STY
:VEC_BLACK_STY
, str
, size
, size
, size
);
1156 LLOGW("get gtfont error size:%d font_size:%d",size
,font_size
);
1159 unsigned int dw
= gtfont_draw_w(buf
, x
,y
, font_size
,size
, size
,luat_lcd_draw_point
,default_conf
,0);
1160 x
+=str
<0x80?dw
:size
;
1163 lcd_auto_flush(default_conf
);
1169 @api lcd.drawGtfontUtf8Gray(str,size,gray,x,y)
1171 @int size 字体大小 (支持16-192号大小字体)
1172 @int gray 灰度[1阶/2阶/3阶/4阶]
1176 lcd.drawGtfontUtf8Gray("啊啊啊",32,4,0,40)
1178 static int l_lcd_draw_gtfont_utf8_gray(lua_State
* L
) {
1179 unsigned char buf
[2048] = {0};
1182 uint8_t strhigh
,strlow
;
1184 const char *fontCode
= luaL_checklstring(L
, 1,&len
);
1185 unsigned char size
= luaL_checkinteger(L
, 2);
1186 unsigned char font_g
= luaL_checkinteger(L
, 3);
1187 int x
= luaL_checkinteger(L
, 4);
1188 int y
= luaL_checkinteger(L
, 5);
1189 lcd_str_fg_color
= (luat_color_t
)luaL_optinteger(L
, 6,FORE_COLOR
);
1190 // lcd_str_bg_color = (luat_color_t)luaL_optinteger(L, 7,BACK_COLOR);
1192 e
= utf8_next((uint8_t)*fontCode
);
1196 if ( e
!= 0x0fffe ){
1197 uint16_t str
= unicodetogb2312(e
);
1198 int font_size
= get_font(buf
, str
<0x80?VEC_HZ_ASCII_STY
:VEC_BLACK_STY
, str
, size
*font_g
, size
*font_g
, size
*font_g
);
1199 if(font_size
!= size
*font_g
){
1200 LLOGW("get gtfont error size:%d font_size:%d",size
,font_size
);
1203 Gray_Process(buf
,size
,size
,font_g
);
1204 gtfont_draw_gray_hz(buf
, x
, y
, size
, size
, font_g
, 1,luat_lcd_draw_point
,default_conf
,0);
1208 lcd_auto_flush(default_conf
);
1212 #endif // LUAT_USE_GTFONT_UTF8
1214 #endif // LUAT_USE_GTFONT
1216 static int l_lcd_set_default(lua_State
*L
) {
1217 if (lua_gettop(L
) == 1) {
1218 default_conf
= lua_touserdata(L
, 1);
1219 lua_pushboolean(L
, 1);
1225 static int l_lcd_get_default(lua_State
*L
) {
1226 if (default_conf
== NULL
)
1228 lua_pushlightuserdata(L
, default_conf
);
1235 @return int 宽, 如果未初始化会返回0
1236 @return int 高, 如果未初始化会返回0
1238 log.info("lcd", "size", lcd.getSize())
1240 static int l_lcd_get_size(lua_State
*L
) {
1241 if (lua_gettop(L
) == 1) {
1242 luat_lcd_conf_t
* conf
= lua_touserdata(L
, 1);
1244 lua_pushinteger(L
, conf
->w
);
1245 lua_pushinteger(L
, conf
->h
);
1249 if (default_conf
== NULL
) {
1250 lua_pushinteger(L
, 0);
1251 lua_pushinteger(L
, 0);
1254 lua_pushinteger(L
, default_conf
->w
);
1255 lua_pushinteger(L
, default_conf
->h
);
1262 @api lcd.drawXbm(x, y, w, h, data)
1269 -- 取模使用PCtoLCD2002软件即可 阴码 逐行 逆向
1270 -- 在(0,0)为左上角,绘制 16x16 "今" 的位图
1271 lcd.drawXbm(0, 0, 16,16, string.char(
1272 0x80,0x00,0x80,0x00,0x40,0x01,0x20,0x02,0x10,0x04,0x48,0x08,0x84,0x10,0x83,0x60,
1273 0x00,0x00,0xF8,0x0F,0x00,0x08,0x00,0x04,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x00
1276 static int l_lcd_drawxbm(lua_State
*L
){
1277 int x
= luaL_checkinteger(L
, 1);
1278 int y
= luaL_checkinteger(L
, 2);
1279 size_t w
= luaL_checkinteger(L
, 3);
1280 size_t h
= luaL_checkinteger(L
, 4);
1282 const char* data
= luaL_checklstring(L
, 5, &len
);
1284 if (h
< 1) return 0; // 行数必须大于0
1285 if (len
*8/h
< w
) return 0; // 起码要填满一行
1288 if (len
!= h
*w1
)return 0;
1289 luat_color_t
* color_w
= luat_heap_malloc(sizeof(luat_color_t
) * w
);
1290 for (size_t b
= 0; b
< h
; b
++){
1293 for (size_t c
= 0; c
< 8; c
++){
1294 if (*data
&(mask
<<c
)){
1295 color_w
[a
]=FORE_COLOR
;
1297 color_w
[a
]=BACK_COLOR
;
1304 luat_lcd_draw(default_conf
, x
, y
+b
, x
+w
-1, y
+b
, color_w
);
1306 luat_heap_free(color_w
);
1307 lcd_auto_flush(default_conf
);
1308 lua_pushboolean(L
, 1);
1312 #ifdef LUAT_USE_TJPGD
1314 #include "tjpgdcnf.h"
1316 #define N_BPP (3 - JD_FORMAT)
1318 /* Session identifier for input/output functions (name, members and usage are as user defined) */
1320 FILE *fp
; /* Input stream */
1325 uint16_t buff
[16*16];
1328 static unsigned int file_in_func (JDEC
* jd
, uint8_t* buff
, unsigned int nbyte
){
1329 IODEV
*dev
= (IODEV
*)jd
->device
; /* Device identifier for the session (5th argument of jd_prepare function) */
1331 /* Read bytes from input stream */
1332 return luat_fs_fread(buff
, 1, nbyte
, dev
->fp
);
1334 /* Remove bytes from input stream */
1335 return luat_fs_fseek(dev
->fp
, nbyte
, SEEK_CUR
) ? 0 : nbyte
;
1339 static int lcd_out_func (JDEC
* jd
, void* bitmap
, JRECT
* rect
){
1340 IODEV
*dev
= (IODEV
*)jd
->device
;
1341 uint16_t* tmp
= (uint16_t*)bitmap
;
1344 uint16_t count
= (rect
->right
- rect
->left
+ 1) * (rect
->bottom
- rect
->top
+ 1);
1345 for (size_t i
= 0; i
< count
; i
++){
1346 if (default_conf
->port
== LUAT_LCD_HW_ID_0
)
1347 dev
->buff
[i
] = tmp
[i
];
1349 dev
->buff
[i
] = ((tmp
[i
] >> 8) & 0xFF)+ ((tmp
[i
] << 8) & 0xFF00);
1352 // LLOGD("jpeg seg %dx%d %dx%d", rect->left, rect->top, rect->right, rect->bottom);
1353 // LLOGD("jpeg seg size %d %d %d", rect->right - rect->left + 1, rect->bottom - rect->top + 1, (rect->right - rect->left + 1) * (rect->bottom - rect->top + 1));
1354 luat_lcd_draw(default_conf
, dev
->x
+ rect
->left
, dev
->y
+ rect
->top
,
1355 dev
->x
+ rect
->right
, dev
->y
+ rect
->bottom
,
1357 return 1; /* Continue to decompress */
1360 static int lcd_draw_jpeg(const char* path
, int xpos
, int ypos
) {
1361 JRESULT res
; /* Result code of TJpgDec API */
1362 JDEC jdec
; /* Decompression object */
1363 void *work
; /* Pointer to the decompressor work area */
1364 #if JD_FASTDECODE == 2
1365 size_t sz_work
= 3500 * 3; /* Size of work area */
1367 size_t sz_work
= 3500; /* Size of work area */
1369 IODEV devid
; /* User defined device identifier */
1371 FILE* fd
= luat_fs_fopen(path
, "r");
1373 LLOGW("no such file %s", path
);
1378 work
= luat_heap_malloc(sz_work
);
1380 LLOGE("out of memory when malloc jpeg decode workbuff");
1383 res
= jd_prepare(&jdec
, file_in_func
, work
, sz_work
, &devid
);
1384 if (res
!= JDR_OK
) {
1385 luat_heap_free(work
);
1387 LLOGW("jd_prepare file %s error %d", path
, res
);
1392 // devid.width = jdec.width;
1393 // devid.height = jdec.height;
1394 res
= jd_decomp(&jdec
, lcd_out_func
, 0);
1395 luat_heap_free(work
);
1397 if (res
!= JDR_OK
) {
1398 LLOGW("jd_decomp file %s error %d", path
, res
);
1402 lcd_auto_flush(default_conf
);
1409 @api lcd.showImage(x, y, file)
1414 lcd.showImage(0,0,"/luadb/logo.jpg")
1416 static int l_lcd_showimage(lua_State
*L
){
1419 int x
= luaL_checkinteger(L
, 1);
1420 int y
= luaL_checkinteger(L
, 2);
1421 const char* input_file
= luaL_checklstring(L
, 3, &size
);
1422 if (memcmp(input_file
+size
-4, ".jpg", 5) == 0 || memcmp(input_file
+size
-4, ".JPG", 5) == 0 || memcmp(input_file
+size
-5, ".jpeg", 6) == 0 || memcmp(input_file
+size
-5, ".JPEG", 6) == 0){
1423 ret
= lcd_draw_jpeg(input_file
, x
, y
);
1424 lua_pushboolean(L
, ret
== 0 ? 1 : 0);
1426 LLOGE("input_file not support");
1427 lua_pushboolean(L
, 0);
1434 主动刷新数据到界面, 仅设置buff且禁用自动属性后使用
1436 @return bool 成功返回true, 否则返回nil/false
1438 -- 本API与 lcd.setupBuff lcd.autoFlush 配合使用
1441 static int l_lcd_flush(lua_State
* L
) {
1442 luat_lcd_conf_t
* conf
= NULL
;
1443 if (lua_gettop(L
) == 1) {
1444 conf
= lua_touserdata(L
, 1);
1447 conf
= default_conf
;
1450 //LLOGW("lcd not init");
1453 if (conf
->buff
== NULL
) {
1454 //LLOGW("lcd without buff, not support flush");
1457 if (conf
->auto_flush
) {
1458 //LLOGI("lcd auto flush is enable, no need for flush");
1461 luat_lcd_flush(conf
);
1462 lua_pushboolean(L
, 1);
1467 设置显示缓冲区, 所需内存大小为 2×宽×高 字节. 请衡量内存需求与业务所需的刷新频次.
1468 @api lcd.setupBuff(conf, onheap)
1469 @userdata conf指针, 不需要传
1470 @bool true使用heap内存, false使用vm内存, 默认使用vm内存, 不需要主动传
1473 -- 初始化lcd的buff缓冲区, 可理解为FrameBuffer区域.
1476 static int l_lcd_setup_buff(lua_State
* L
) {
1477 luat_lcd_conf_t
* conf
= NULL
;
1478 if (lua_gettop(L
) == 1) {
1479 conf
= lua_touserdata(L
, 1);
1482 conf
= default_conf
;
1485 LLOGW("lcd not init");
1488 if (conf
->buff
!= NULL
) {
1489 LLOGW("lcd buff is ok");
1492 if (lua_isboolean(L
, 2) && lua_toboolean(L
, 2)) {
1493 conf
->buff
= luat_heap_malloc(sizeof(luat_color_t
) * conf
->w
* conf
->h
);
1496 conf
->buff
= lua_newuserdata(L
, sizeof(luat_color_t
) * conf
->w
* conf
->h
);
1498 conf
->buff_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
1501 if (conf
->buff
== NULL
) {
1502 LLOGE("lcd buff malloc fail, out of memory?");
1506 conf
->flush_y_min
= conf
->h
;
1507 conf
->flush_y_max
= 0;
1508 // luat_lcd_clear 会将区域扩展到整个屏幕
1509 luat_lcd_clear(default_conf
, BACK_COLOR
);
1510 lua_pushboolean(L
, 1);
1515 设置自动刷新, 需配合lcd.setupBuff使用
1516 @api lcd.autoFlush(enable)
1517 @bool 是否自动刷新,默认为true
1521 lcd.autoFlush(false)
1522 -- 禁止自动更新后, 需要使用 lcd.flush() 主动刷新数据到屏幕
1524 static int l_lcd_auto_flush(lua_State
* L
) {
1525 luat_lcd_conf_t
* conf
= default_conf
;
1527 LLOGW("lcd not init");
1530 conf
->auto_flush
= lua_toboolean(L
, 1);
1531 lua_pushboolean(L
, conf
->auto_flush
);
1537 @api lcd.rgb565(r, g, b, swap)
1538 @int 红色, 0x00 ~ 0xFF
1539 @int 绿色, 0x00 ~ 0xFF
1540 @int 蓝色, 0x00 ~ 0xFF
1541 @bool 是否翻转, true 翻转, false 不翻转. 默认翻转
1544 -- 本API支持多种模式, 参数数量分别是 1, 2, 3, 4
1545 -- 1. 单参数形式, 24bit RGB值, swap = true, 推荐
1546 local red = lcd.rgb565(0xFF0000)
1547 local green = lcd.rgb565(0x00FF00)
1548 local blue = lcd.rgb565(0x0000FF)
1550 -- 2. 两参数形式, 24bit RGB值, 增加swap的设置
1551 local red = lcd.rgb565(0xFF0000, true)
1552 local green = lcd.rgb565(0x00FF00, true)
1553 local blue = lcd.rgb565(0x0000FF, true)
1555 -- 3. 三参数形式, 红/绿/蓝, 各8bit
1556 local red = lcd.rgb565(0xFF, 0x00, 0x00)
1557 local green = lcd.rgb565(0x00, 0xFF, 0x00)
1558 local blue = lcd.rgb565(0x00, 0x00, 0xFF)
1560 -- 4. 四参数形式, 红/绿/蓝, 各8bit, 增加swap的设置
1561 local red = lcd.rgb565(0xFF, 0x00, 0x00, true)
1562 local green = lcd.rgb565(0x00, 0xFF, 0x00, true)
1563 local blue = lcd.rgb565(0x00, 0x00, 0xFF, true)
1565 static int l_lcd_rgb565(lua_State
* L
) {
1566 uint8_t r
=0,g
=0,b
= 0;
1571 top
= lua_gettop(L
);
1572 if (top
== 1 || top
== 2) {
1573 rgb
= luaL_checkinteger(L
, 1);
1574 r
= (uint8_t)((rgb
>> 16 ) & 0xFF);
1575 g
= (uint8_t)((rgb
>> 8 ) & 0xFF);
1576 b
= (uint8_t)((rgb
>> 0 ) & 0xFF);
1577 swap
= (lua_isboolean(L
, 2) && !lua_toboolean(L
, 2)) ? 0U : 1U;
1579 else if (top
== 3 || top
== 4) {
1580 r
= (uint8_t)luaL_checkinteger(L
, 1);
1581 g
= (uint8_t)luaL_checkinteger(L
, 2);
1582 b
= (uint8_t)luaL_checkinteger(L
, 3);
1583 swap
= (lua_isboolean(L
, 4) && !lua_toboolean(L
, 4)) ? 0U : 1U;
1586 LLOGW("unkown args count %d", top
);
1589 dst
= (uint16_t)((r
&0xF8)<<8) | (uint16_t)((g
&0xFC)<<3) | (uint16_t)(b
>>3);
1592 dst
= ((dst
>> 8) & 0xFF) + ((dst
& 0xFF) << 8);
1594 lua_pushinteger(L
, dst
);
1597 #ifdef LUAT_USE_UFONT
1598 #include "luat_ufont.h"
1599 static const int l_lcd_draw_utf8(lua_State
*L
) {
1601 uint32_t letter
= 0;
1602 uint32_t str_offset
;
1604 uint16_t draw_offset
= 0;
1608 luat_font_char_desc_t desc
= {0};
1610 int x
= luaL_checkinteger(L
, 1);
1611 int y
= luaL_checkinteger(L
, 2);
1613 const char* data
= (const char*)luaL_checklstring(L
, 3, &sz
);
1615 lv_font_t
* lfont
= (lv_font_t
*)lua_touserdata(L
, 4);
1616 if (lfont
== NULL
) {
1617 LLOGW("draw without font");
1620 luat_font_header_t
* font
= (luat_font_header_t
*)lfont
->dsc
;
1622 bool draw_bg
= lua_isboolean(L
, 5) ? lua_toboolean(L
, 5) : true;
1627 lua_pushinteger(L
, x
);
1633 LLOGD("NULL font, skip draw");
1635 lua_pushinteger(L
, x
);
1639 if (default_conf
->h
< y
|| default_conf
->w
< x
) {
1640 //LLOGD("draw y %d h % font->line_height %d", y, default_conf->h, font->line_height);
1642 lua_pushinteger(L
, x
);
1646 luat_color_t
* buff
= NULL
;
1648 buff
= luat_heap_malloc(font
->line_height
* font
->line_height
* 2);
1649 // if (buff == NULL)
1652 uint8_t *data_ptr
= data
;
1653 uint8_t utf8_state
= 0;
1654 uint16_t utf8_tmp
= 0;
1655 uint16_t utf8_out
= 0;
1656 luat_color_t color
= FORE_COLOR
;
1657 for (size_t i
= 0; i
< sz
; i
++)
1659 utf8_out
= luat_utf8_next(data
[i
], &utf8_state
, &utf8_tmp
);
1660 if (utf8_out
== 0x0ffff)
1662 if (utf8_out
== 0x0fffe)
1663 continue; // 没读完一个字符,继续下一个循环
1664 letter
= (uint32_t)utf8_out
;
1666 //LLOGD("draw letter %04X", letter);
1667 int ret
= luat_font_get_bitmap(font
, &desc
, letter
);
1669 LLOGD("not such char in font");
1670 draw_offset
+= font
->line_height
/ 2; // 找不到字符, 默认跳过半个字
1675 memset(buff
, 0, font
->line_height
* font
->line_height
* 2);
1676 draw_x
= x
+ draw_offset
;
1677 draw_offset
+= desc
.char_w
;
1678 if (draw_x
>= 0 && draw_x
+ desc
.char_w
<= default_conf
->w
) {
1679 //if (default_conf->buff == NULL) {
1680 for (size_t j
= 0; j
< font
->line_height
; j
++)
1682 //LLOGD("draw char pix line %d", i);
1683 for (size_t k
= 0; k
< desc
.char_w
; k
++)
1685 if ((desc
.data
[offset
/ 8] >> (7 - (offset
% 8))) & 0x01) {
1688 buff
[offset
] = FORE_COLOR
;
1690 luat_lcd_draw_point(default_conf
, draw_x
+ k
, y
+ j
, FORE_COLOR
);
1691 //LLOGD("draw char pix mark %d", offset);
1695 buff
[offset
] = BACK_COLOR
;
1696 //LLOGD("draw char pix offset %d color %04X", offset, FORE_COLOR);
1701 //LLOGD("luat_lcd_draw %d %d %d %d", draw_x, y, draw_x + desc.char_w, y + font->line_height);
1702 luat_lcd_draw(default_conf
, draw_x
, y
, draw_x
+ desc
.char_w
- 1, y
+ font
->line_height
- 1, buff
);
1710 luat_heap_free(buff
);
1712 lcd_auto_flush(default_conf
);
1713 lua_pushinteger(L
, draw_x
+ desc
.char_w
);
1718 #include "rotable2.h"
1719 static const rotable_Reg_t reg_lcd
[] =
1721 { "init", ROREG_FUNC(l_lcd_init
)},
1722 { "clear", ROREG_FUNC(l_lcd_clear
)},
1723 { "fill", ROREG_FUNC(l_lcd_draw_fill
)},
1724 { "drawPoint", ROREG_FUNC(l_lcd_draw_point
)},
1725 { "drawLine", ROREG_FUNC(l_lcd_draw_line
)},
1726 { "drawRectangle", ROREG_FUNC(l_lcd_draw_rectangle
)},
1727 { "drawCircle", ROREG_FUNC(l_lcd_draw_circle
)},
1728 { "drawQrcode", ROREG_FUNC(l_lcd_drawQrcode
)},
1729 { "drawStr", ROREG_FUNC(l_lcd_draw_str
)},
1730 { "flush", ROREG_FUNC(l_lcd_flush
)},
1731 { "setupBuff", ROREG_FUNC(l_lcd_setup_buff
)},
1732 { "autoFlush", ROREG_FUNC(l_lcd_auto_flush
)},
1733 { "setFont", ROREG_FUNC(l_lcd_set_font
)},
1734 { "setDefault", ROREG_FUNC(l_lcd_set_default
)},
1735 { "getDefault", ROREG_FUNC(l_lcd_get_default
)},
1736 { "getSize", ROREG_FUNC(l_lcd_get_size
)},
1737 { "drawXbm", ROREG_FUNC(l_lcd_drawxbm
)},
1738 { "close", ROREG_FUNC(l_lcd_close
)},
1739 { "on", ROREG_FUNC(l_lcd_display_on
)},
1740 { "off", ROREG_FUNC(l_lcd_display_off
)},
1741 { "sleep", ROREG_FUNC(l_lcd_sleep
)},
1742 { "wakeup", ROREG_FUNC(l_lcd_wakeup
)},
1743 { "invon", ROREG_FUNC(l_lcd_inv_on
)},
1744 { "invoff", ROREG_FUNC(l_lcd_inv_off
)},
1745 { "cmd", ROREG_FUNC(l_lcd_write_cmd
)},
1746 { "data", ROREG_FUNC(l_lcd_write_data
)},
1747 { "setColor", ROREG_FUNC(l_lcd_set_color
)},
1748 { "draw", ROREG_FUNC(l_lcd_draw
)},
1749 { "rgb565", ROREG_FUNC(l_lcd_rgb565
)},
1750 #ifdef LUAT_USE_UFONT
1751 { "drawUTF8", ROREG_FUNC(l_lcd_draw_utf8
)},
1753 #ifdef LUAT_USE_TJPGD
1754 { "showImage", ROREG_FUNC(l_lcd_showimage
)},
1756 #ifdef LUAT_USE_GTFONT
1757 { "drawGtfontGb2312", ROREG_FUNC(l_lcd_draw_gtfont_gbk
)},
1758 { "drawGtfontGb2312Gray", ROREG_FUNC(l_lcd_draw_gtfont_gbk_gray
)},
1759 { "drawGtfontGbk", ROREG_FUNC(l_lcd_draw_gtfont_gbk
)},
1760 { "drawGtfontGbkGray", ROREG_FUNC(l_lcd_draw_gtfont_gbk_gray
)},
1761 #ifdef LUAT_USE_GTFONT_UTF8
1762 { "drawGtfontUtf8", ROREG_FUNC(l_lcd_draw_gtfont_utf8
)},
1763 { "drawGtfontUtf8Gray", ROREG_FUNC(l_lcd_draw_gtfont_utf8_gray
)},
1764 #endif // LUAT_USE_GTFONT_UTF8
1765 #endif // LUAT_USE_GTFONT
1767 //@const font_opposansm12 font 12号字体
1768 { "font_opposansm12", ROREG_PTR((void*)u8g2_font_opposansm12
)},
1769 #ifdef USE_U8G2_OPPOSANSM_ENGLISH
1770 //@const font_unifont_t_symbols font 符号字体
1771 { "font_unifont_t_symbols", ROREG_PTR((void*)u8g2_font_unifont_t_symbols
)},
1772 //@const font_open_iconic_weather_6x_t font 天气字体
1773 { "font_open_iconic_weather_6x_t", ROREG_PTR((void*)u8g2_font_open_iconic_weather_6x_t
)},
1775 //@const font_opposansm16 font 16号字体
1776 //@const font_opposansm18 font 18号字体
1777 //@const font_opposansm20 font 20号字体
1778 //@const font_opposansm22 font 22号字体
1779 //@const font_opposansm24 font 24号字体
1780 //@const font_opposansm32 font 32号字体
1781 { "font_opposansm16", ROREG_PTR((void*)u8g2_font_opposansm16
)},
1782 { "font_opposansm18", ROREG_PTR((void*)u8g2_font_opposansm18
)},
1783 { "font_opposansm20", ROREG_PTR((void*)u8g2_font_opposansm20
)},
1784 { "font_opposansm22", ROREG_PTR((void*)u8g2_font_opposansm22
)},
1785 { "font_opposansm24", ROREG_PTR((void*)u8g2_font_opposansm24
)},
1786 { "font_opposansm32", ROREG_PTR((void*)u8g2_font_opposansm32
)},
1788 #ifdef USE_U8G2_OPPOSANSM12_CHINESE
1789 //@const font_opposansm12_chinese font 12号中文字体
1790 { "font_opposansm12_chinese", ROREG_PTR((void*)u8g2_font_opposansm12_chinese
)},
1792 #ifdef USE_U8G2_OPPOSANSM14_CHINESE
1793 //@const font_opposansm14_chinese font 14号中文字体
1794 { "font_opposansm14_chinese", ROREG_PTR((void*)u8g2_font_opposansm14_chinese
)},
1796 #ifdef USE_U8G2_OPPOSANSM16_CHINESE
1797 //@const font_opposansm16_chinese font 16号中文字体
1798 { "font_opposansm16_chinese", ROREG_PTR((void*)u8g2_font_opposansm16_chinese
)},
1800 #ifdef USE_U8G2_OPPOSANSM18_CHINESE
1801 //@const font_opposansm18_chinese font 18号中文字体
1802 { "font_opposansm18_chinese", ROREG_PTR((void*)u8g2_font_opposansm18_chinese
)},
1804 #ifdef USE_U8G2_OPPOSANSM20_CHINESE
1805 //@const font_opposansm20_chinese font 20号中文字体
1806 { "font_opposansm20_chinese", ROREG_PTR((void*)u8g2_font_opposansm20_chinese
)},
1808 #ifdef USE_U8G2_OPPOSANSM22_CHINESE
1809 //@const font_opposansm22_chinese font 22号中文字体
1810 { "font_opposansm22_chinese", ROREG_PTR((void*)u8g2_font_opposansm22_chinese
)},
1812 #ifdef USE_U8G2_OPPOSANSM24_CHINESE
1813 //@const font_opposansm24_chinese font 24号中文字体
1814 { "font_opposansm24_chinese", ROREG_PTR((void*)u8g2_font_opposansm24_chinese
)},
1816 #ifdef USE_U8G2_OPPOSANSM32_CHINESE
1817 //@const font_opposansm32_chinese font 32号中文字体
1818 { "font_opposansm32_chinese", ROREG_PTR((void*)u8g2_font_opposansm32_chinese
)},
1820 #ifdef USE_U8G2_SARASA_ENGLISH
1821 { "font_sarasa_m12_ascii", ROREG_PTR((void*)u8g2_font_sarasa_m12_ascii
)},
1822 { "font_sarasa_m14_ascii", ROREG_PTR((void*)u8g2_font_sarasa_m14_ascii
)},
1823 { "font_sarasa_m16_ascii", ROREG_PTR((void*)u8g2_font_sarasa_m16_ascii
)},
1824 { "font_sarasa_m18_ascii", ROREG_PTR((void*)u8g2_font_sarasa_m18_ascii
)},
1825 { "font_sarasa_m20_ascii", ROREG_PTR((void*)u8g2_font_sarasa_m20_ascii
)},
1826 { "font_sarasa_m22_ascii", ROREG_PTR((void*)u8g2_font_sarasa_m22_ascii
)},
1830 // #ifdef USE_U8G2_SARASA_M8_CHINESE
1831 // { "font_sarasa_m8_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m8_chinese)},
1833 #ifdef USE_U8G2_SARASA_M10_CHINESE
1834 { "font_sarasa_m10_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m10_chinese
)},
1836 #ifdef USE_U8G2_SARASA_M12_CHINESE
1837 { "font_sarasa_m12_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m12_chinese
)},
1839 #ifdef USE_U8G2_SARASA_M14_CHINESE
1840 { "font_sarasa_m14_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m14_chinese
)},
1842 #ifdef USE_U8G2_SARASA_M16_CHINESE
1843 { "font_sarasa_m16_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m16_chinese
)},
1845 #ifdef USE_U8G2_SARASA_M18_CHINESE
1846 { "font_sarasa_m18_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m18_chinese
)},
1848 #ifdef USE_U8G2_SARASA_M20_CHINESE
1849 { "font_sarasa_m20_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m20_chinese
)},
1851 #ifdef USE_U8G2_SARASA_M22_CHINESE
1852 { "font_sarasa_m22_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m22_chinese
)},
1854 #ifdef USE_U8G2_SARASA_M24_CHINESE
1855 { "font_sarasa_m24_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m24_chinese
)},
1857 #ifdef USE_U8G2_SARASA_M26_CHINESE
1858 { "font_sarasa_m26_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m26_chinese
)},
1860 #ifdef USE_U8G2_SARASA_M28_CHINESE
1861 { "font_sarasa_m28_chinese", ROREG_PTR((void*)u8g2_font_sarasa_m28_chinese
)},
1863 { "set_direction", ROREG_FUNC(l_lcd_set_direction
)},
1864 //@const direction_0 int 0°方向命令
1865 { "direction_0", ROREG_INT(0)},
1866 //@const direction_90 int 90°方向命令
1867 { "direction_90", ROREG_INT(1)},
1868 //@const direction_180 int 180°方向命令
1869 { "direction_180", ROREG_INT(2)},
1870 //@const direction_270 int 270°方向命令
1871 { "direction_270", ROREG_INT(3)},
1872 //@const HWID_0 硬件lcd驱动id0 (根据芯片支持选择)
1873 { "HWID_0", ROREG_INT(LUAT_LCD_HW_ID_0
)},
1874 //@const WIRE_3_BIT_9_INTERFACE_I 三线spi 9bit 模式I
1875 { "WIRE_3_BIT_9_INTERFACE_I", ROREG_INT(LUAT_LCD_IM_3_WIRE_9_BIT_INTERFACE_I
)},
1876 //@const WIRE_4_BIT_8_INTERFACE_I 四线spi 8bit 模式I
1877 { "WIRE_4_BIT_8_INTERFACE_I", ROREG_INT(LUAT_LCD_IM_4_WIRE_8_BIT_INTERFACE_I
)},
1878 //@const WIRE_3_BIT_9_INTERFACE_II 三线spi 9bit 模式II
1879 { "WIRE_3_BIT_9_INTERFACE_II", ROREG_INT(LUAT_LCD_IM_3_WIRE_9_BIT_INTERFACE_II
)},
1880 //@const WIRE_4_BIT_8_INTERFACE_II 四线spi 8bit 模式II
1881 { "WIRE_4_BIT_8_INTERFACE_II", ROREG_INT(LUAT_LCD_IM_4_WIRE_8_BIT_INTERFACE_II
)},
1882 //@const DATA_2_LANE int 双通道模式
1883 { "DATA_2_LANE", ROREG_INT(LUAT_LCD_IM_2_DATA_LANE
)},
1884 {NULL
, ROREG_INT(0)}
1887 LUAMOD_API
int luaopen_lcd( lua_State
*L
) {
1888 luat_newlib2(L
, reg_lcd
);