luat_lib_eink.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. /*
  2. @module eink
  3. @summary 墨水屏操作库
  4. @version 1.0
  5. @date 2020.11.14
  6. */
  7. #include "luat_base.h"
  8. #include "luat_log.h"
  9. #include "luat_sys.h"
  10. #include "luat_msgbus.h"
  11. #include "luat_timer.h"
  12. #include "luat_malloc.h"
  13. #include "luat_spi.h"
  14. #include "luat_gpio.h"
  15. // #include "epd1in54.h"
  16. // #include "epd2in9.h"
  17. #include "epd.h"
  18. #include "epdpaint.h"
  19. #include "imagedata.h"
  20. #include "../qrcode/qrcode.h"
  21. #include <stdlib.h>
  22. #include "u8g2.h"
  23. #include "u8g2_luat_fonts.h"
  24. int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cnt);
  25. uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t *f, uint8_t cnt);
  26. #define COLORED 0
  27. #define UNCOLORED 1
  28. #define LUAT_LOG_TAG "eink"
  29. enum
  30. {
  31. font_opposansm8,
  32. font_opposansm10,
  33. font_opposansm12,
  34. font_opposansm16,
  35. font_opposansm18,
  36. font_opposansm20,
  37. font_opposansm22,
  38. font_opposansm24,
  39. font_opposansm32,
  40. font_opposansm12_chinese,
  41. font_opposansm16_chinese,
  42. font_opposansm24_chinese,
  43. font_opposansm32_chinese,
  44. };
  45. static uint32_t eink_str_color;
  46. // static EPD epd;
  47. static Paint paint;
  48. static unsigned char* frame_buffer = NULL;
  49. // #ifdef econf
  50. // #undef econf
  51. // #endif
  52. eink_conf_t econf = {0};
  53. #define Pin_BUSY (econf.busy_pin)
  54. #define Pin_RES (econf.res_pin)
  55. #define Pin_DC (econf.dc_pin)
  56. #define Pin_CS (econf.cs_pin)
  57. #define SPI_ID (econf.spi_id)
  58. /**
  59. 初始化eink
  60. @api eink.setup(full, spiid)
  61. @int 全屏刷新0,局部刷新1,默认是全屏刷新
  62. @int 所在的spi,默认是0
  63. @int Busy 忙信号管脚
  64. @int Reset 复位管脚
  65. @int DC 数据命令选择管脚
  66. @int CS 使能管脚
  67. @return boolean 成功返回true,否则返回false
  68. */
  69. static int l_eink_setup(lua_State *L) {
  70. int status;
  71. econf.full_mode = luaL_optinteger(L, 1, 1);
  72. econf.spi_id = luaL_optinteger(L, 2, 0);
  73. econf.busy_pin = luaL_optinteger(L, 3, 18);
  74. econf.res_pin = luaL_optinteger(L, 4, 7);
  75. econf.dc_pin = luaL_optinteger(L, 5, 9);
  76. econf.cs_pin = luaL_optinteger(L, 6, 16);
  77. if (frame_buffer != NULL) {
  78. lua_pushboolean(L, 1);
  79. return 0;
  80. }
  81. if (lua_type(L, 7) == LUA_TUSERDATA){
  82. LLOGD("luat_spi_device_send");
  83. econf.userdata = (luat_spi_device_t*)lua_touserdata(L, 3);
  84. econf.port = LUAT_EINK_SPI_DEVICE;
  85. luat_gpio_mode(Pin_BUSY, Luat_GPIO_INPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  86. luat_gpio_mode(Pin_RES, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  87. luat_gpio_mode(Pin_DC, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  88. status = 0;
  89. }else{
  90. LLOGD("luat_spi_send");
  91. luat_spi_t spi_config = {0};
  92. spi_config.bandrate = 2000000U;//luaL_optinteger(L, 1, 2000000U); // 2000000U
  93. spi_config.id = SPI_ID;
  94. spi_config.cs = 255; // 默认无
  95. spi_config.CPHA = 0; // CPHA0
  96. spi_config.CPOL = 0; // CPOL0
  97. spi_config.dataw = 8; // 8bit
  98. spi_config.bit_dict = 1; // MSB=1, LSB=0
  99. spi_config.master = 1; // master=1,slave=0
  100. spi_config.mode = 1; // FULL=1, half=0
  101. //LLOGD("setup GPIO for epd");
  102. status = luat_spi_setup(&spi_config);
  103. luat_gpio_mode(Pin_BUSY, Luat_GPIO_INPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  104. luat_gpio_mode(Pin_RES, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  105. luat_gpio_mode(Pin_DC, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  106. luat_gpio_mode(Pin_CS, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  107. }
  108. size_t epd_w = 0;
  109. size_t epd_h = 0;
  110. if(status == 0)
  111. {
  112. LLOGD("spi setup complete, now setup epd");
  113. if(econf.full_mode)
  114. status = EPD_Init(1, &epd_w, &epd_h);
  115. else
  116. status = EPD_Init(0, &epd_w, &epd_h);
  117. if (status != 0) {
  118. LLOGD("e-Paper init failed");
  119. return 0;
  120. }
  121. frame_buffer = (unsigned char*)luat_heap_malloc(epd_w * epd_h / 8);
  122. // Paint paint;
  123. Paint_Init(&paint, frame_buffer, epd_w, epd_h);
  124. Paint_Clear(&paint, UNCOLORED);
  125. }
  126. u8g2_SetFontMode(&(paint.luat_eink_u8g2), 0);
  127. u8g2_SetFontDirection(&(paint.luat_eink_u8g2), 0);
  128. //LLOGD("epd init complete");
  129. lua_pushboolean(L, 1);
  130. return 1;
  131. }
  132. /**
  133. 进入休眠模式,再次使用时需要重新初始化
  134. @api eink.sleep()
  135. @return nil
  136. */
  137. static int l_eink_sleep(lua_State *L)
  138. {
  139. EPD_Sleep();
  140. return 0;
  141. }
  142. /**
  143. 清除绘图缓冲区,默认不会马上刷新到设备
  144. @api eink.clear(color, force)
  145. @number color 可选,默认1。刷屏颜色
  146. @bool force 可选,默认false。如果为true则马上清屏
  147. @return nil 无返回值
  148. */
  149. static int l_eink_clear(lua_State *L)
  150. {
  151. int colored = luaL_optinteger(L, 1, 1);
  152. Paint_Clear(&paint, colored);
  153. if(lua_isboolean(L, 2))
  154. EPD_Clear();
  155. return 0;
  156. }
  157. /**
  158. 设置窗口
  159. @api eink.setWin(width, height, rotate)
  160. @int width 宽度
  161. @int height 高度
  162. @int rotate 显示方向,0/1/2/3, 相当于旋转0度/90度/180度/270度
  163. @return nil 无返回值
  164. */
  165. static int l_eink_setWin(lua_State *L)
  166. {
  167. int width = luaL_checkinteger(L, 1);
  168. int height = luaL_checkinteger(L, 2);
  169. int rotate = luaL_checkinteger(L, 3);
  170. Paint_SetWidth(&paint, width);
  171. Paint_SetHeight(&paint, height);
  172. Paint_SetRotate(&paint, rotate);
  173. return 0;
  174. }
  175. /**
  176. 获取窗口信息
  177. @api eink.getWin()
  178. @return int width 宽
  179. @return int height 高
  180. @return int rotate 旋转方向
  181. */
  182. static int l_eink_getWin(lua_State *L)
  183. {
  184. int width = Paint_GetWidth(&paint);
  185. int height = Paint_GetHeight(&paint);
  186. int rotate = Paint_GetRotate(&paint);
  187. lua_pushinteger(L, width);
  188. lua_pushinteger(L, height);
  189. lua_pushinteger(L, rotate);
  190. return 3;
  191. }
  192. static uint8_t utf8_state;
  193. static uint16_t encoding;
  194. static uint16_t utf8_next(uint8_t b)
  195. {
  196. if ( b == 0 ) /* '\n' terminates the string to support the string list procedures */
  197. return 0x0ffff; /* end of string detected, pending UTF8 is discarded */
  198. if ( utf8_state == 0 )
  199. {
  200. if ( b >= 0xfc ) /* 6 byte sequence */
  201. {
  202. utf8_state = 5;
  203. b &= 1;
  204. }
  205. else if ( b >= 0xf8 )
  206. {
  207. utf8_state = 4;
  208. b &= 3;
  209. }
  210. else if ( b >= 0xf0 )
  211. {
  212. utf8_state = 3;
  213. b &= 7;
  214. }
  215. else if ( b >= 0xe0 )
  216. {
  217. utf8_state = 2;
  218. b &= 15;
  219. }
  220. else if ( b >= 0xc0 )
  221. {
  222. utf8_state = 1;
  223. b &= 0x01f;
  224. }
  225. else
  226. {
  227. /* do nothing, just use the value as encoding */
  228. return b;
  229. }
  230. encoding = b;
  231. return 0x0fffe;
  232. }
  233. else
  234. {
  235. utf8_state--;
  236. /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
  237. encoding<<=6;
  238. b &= 0x03f;
  239. encoding |= b;
  240. if ( utf8_state != 0 )
  241. return 0x0fffe; /* nothing to do yet */
  242. }
  243. return encoding;
  244. }
  245. static void drawFastHLine(Paint* conf,int16_t x, int16_t y, int16_t len, uint16_t color){
  246. Paint_DrawHorizontalLine(conf,x, y, len,color);
  247. }
  248. static void drawFastVLine(Paint* conf,int16_t x, int16_t y, int16_t len, uint16_t color){
  249. Paint_DrawVerticalLine(conf,x, y, len,color);
  250. }
  251. static void u8g2_draw_hv_line(u8g2_t *u8g2, int16_t x, int16_t y, int16_t len, uint8_t dir, uint16_t color){
  252. switch(dir)
  253. {
  254. case 0:
  255. drawFastHLine(&paint,x,y,len,color);
  256. break;
  257. case 1:
  258. drawFastVLine(&paint,x,y,len,color);
  259. break;
  260. case 2:
  261. drawFastHLine(&paint,x-len+1,y,len,color);
  262. break;
  263. case 3:
  264. drawFastVLine(&paint,x,y-len+1,len,color);
  265. break;
  266. }
  267. }
  268. static void u8g2_font_decode_len(u8g2_t *u8g2, uint8_t len, uint8_t is_foreground){
  269. uint8_t cnt; /* total number of remaining pixels, which have to be drawn */
  270. uint8_t rem; /* remaining pixel to the right edge of the glyph */
  271. uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */
  272. /* current is either equal to cnt or equal to rem */
  273. /* local coordinates of the glyph */
  274. uint8_t lx,ly;
  275. /* target position on the screen */
  276. int16_t x, y;
  277. u8g2_font_decode_t *decode = &(u8g2->font_decode);
  278. cnt = len;
  279. /* get the local position */
  280. lx = decode->x;
  281. ly = decode->y;
  282. for(;;){
  283. /* calculate the number of pixel to the right edge of the glyph */
  284. rem = decode->glyph_width;
  285. rem -= lx;
  286. /* calculate how many pixel to draw. This is either to the right edge */
  287. /* or lesser, if not enough pixel are left */
  288. current = rem;
  289. if ( cnt < rem )
  290. current = cnt;
  291. /* now draw the line, but apply the rotation around the glyph target position */
  292. //u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
  293. /* get target position */
  294. x = decode->target_x;
  295. y = decode->target_y;
  296. /* apply rotation */
  297. x = u8g2_add_vector_x(x, lx, ly, decode->dir);
  298. y = u8g2_add_vector_y(y, lx, ly, decode->dir);
  299. /* draw foreground and background (if required) */
  300. if ( current > 0 ) /* avoid drawing zero length lines, issue #4 */
  301. {
  302. if ( is_foreground )
  303. {
  304. u8g2_draw_hv_line(u8g2, x, y, current, decode->dir, eink_str_color);
  305. }
  306. else if ( decode->is_transparent == 0 )
  307. {
  308. // u8g2_draw_hv_line(u8g2, x, y, current, decode->dir, decode->bg_color);
  309. }
  310. }
  311. /* check, whether the end of the run length code has been reached */
  312. if ( cnt < rem )
  313. break;
  314. cnt -= rem;
  315. lx = 0;
  316. ly++;
  317. }
  318. lx += cnt;
  319. decode->x = lx;
  320. decode->y = ly;
  321. }
  322. static void u8g2_font_setup_decode(u8g2_t *u8g2, const uint8_t *glyph_data)
  323. {
  324. u8g2_font_decode_t *decode = &(u8g2->font_decode);
  325. decode->decode_ptr = glyph_data;
  326. decode->decode_bit_pos = 0;
  327. /* 8 Nov 2015, this is already done in the glyph data search procedure */
  328. /*
  329. decode->decode_ptr += 1;
  330. decode->decode_ptr += 1;
  331. */
  332. decode->glyph_width = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_char_width);
  333. decode->glyph_height = u8g2_font_decode_get_unsigned_bits(decode,u8g2->font_info.bits_per_char_height);
  334. }
  335. static int8_t u8g2_font_decode_glyph(u8g2_t *u8g2, const uint8_t *glyph_data){
  336. uint8_t a, b;
  337. int8_t x, y;
  338. int8_t d;
  339. int8_t h;
  340. u8g2_font_decode_t *decode = &(u8g2->font_decode);
  341. u8g2_font_setup_decode(u8g2, glyph_data);
  342. h = u8g2->font_decode.glyph_height;
  343. x = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_x);
  344. y = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_y);
  345. d = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_delta_x);
  346. if ( decode->glyph_width > 0 )
  347. {
  348. decode->target_x = u8g2_add_vector_x(decode->target_x, x, -(h+y), decode->dir);
  349. decode->target_y = u8g2_add_vector_y(decode->target_y, x, -(h+y), decode->dir);
  350. //u8g2_add_vector(&(decode->target_x), &(decode->target_y), x, -(h+y), decode->dir);
  351. /* reset local x/y position */
  352. decode->x = 0;
  353. decode->y = 0;
  354. /* decode glyph */
  355. for(;;){
  356. a = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_0);
  357. b = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_1);
  358. do{
  359. u8g2_font_decode_len(u8g2, a, 0);
  360. u8g2_font_decode_len(u8g2, b, 1);
  361. } while( u8g2_font_decode_get_unsigned_bits(decode, 1) != 0 );
  362. if ( decode->y >= h )
  363. break;
  364. }
  365. }
  366. return d;
  367. }
  368. const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding);
  369. static int16_t u8g2_font_draw_glyph(u8g2_t *u8g2, int16_t x, int16_t y, uint16_t encoding){
  370. int16_t dx = 0;
  371. u8g2->font_decode.target_x = x;
  372. u8g2->font_decode.target_y = y;
  373. const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, encoding);
  374. if ( glyph_data != NULL ){
  375. dx = u8g2_font_decode_glyph(u8g2, glyph_data);
  376. }
  377. return dx;
  378. }
  379. /**
  380. 绘制字符串
  381. @api eink.print(x, y, str, colored, font)
  382. @int x坐标
  383. @int y坐标
  384. @string 字符串
  385. @int 默认是0
  386. @font 字体大小,默认12
  387. @return nil 无返回值
  388. */
  389. static int l_eink_print(lua_State *L)
  390. {
  391. size_t len;
  392. int x = luaL_checkinteger(L, 1);
  393. int y = luaL_checkinteger(L, 2);
  394. const char *str = luaL_checklstring(L, 3, &len);
  395. eink_str_color = luaL_optinteger(L, 4, 0);
  396. int font = luaL_optinteger(L, 5, 12);
  397. switch (font)
  398. {
  399. case font_opposansm8:
  400. LLOGI("font_opposansm8");
  401. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm8);
  402. lua_pushboolean(L, 1);
  403. break;
  404. case font_opposansm10:
  405. LLOGI("font_opposansm10");
  406. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm10);
  407. lua_pushboolean(L, 1);
  408. break;
  409. case font_opposansm12:
  410. LLOGI("font_opposansm12");
  411. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm12);
  412. lua_pushboolean(L, 1);
  413. break;
  414. case font_opposansm16:
  415. LLOGI("font_opposansm16");
  416. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm16);
  417. lua_pushboolean(L, 1);
  418. break;
  419. case font_opposansm18:
  420. LLOGI("font_opposansm18");
  421. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm18);
  422. lua_pushboolean(L, 1);
  423. break;
  424. case font_opposansm20:
  425. LLOGI("font_opposansm20");
  426. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm20);
  427. lua_pushboolean(L, 1);
  428. break;
  429. case font_opposansm22:
  430. LLOGI("font_opposansm22");
  431. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm22);
  432. lua_pushboolean(L, 1);
  433. break;
  434. case font_opposansm24:
  435. LLOGI("font_opposansm24");
  436. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm24);
  437. lua_pushboolean(L, 1);
  438. break;
  439. case font_opposansm32:
  440. LLOGI("font_opposansm32");
  441. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm32);
  442. lua_pushboolean(L, 1);
  443. break;
  444. #if defined USE_U8G2_OPPOSANSM12_CHINESE
  445. case font_opposansm12_chinese:
  446. LLOGI("font_opposansm12_chinese");
  447. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm12_chinese);
  448. lua_pushboolean(L, 1);
  449. break;
  450. #endif
  451. #if defined USE_U8G2_OPPOSANSM16_CHINESE
  452. case font_opposansm16_chinese:
  453. LLOGI("font_opposansm16_chinese");
  454. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm16_chinese);
  455. lua_pushboolean(L, 1);
  456. break;
  457. #endif
  458. #if defined USE_U8G2_OPPOSANSM24_CHINESE
  459. case font_opposansm24_chinese:
  460. LLOGI("font_opposansm24_chinese");
  461. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm24_chinese);
  462. lua_pushboolean(L, 1);
  463. break;
  464. #endif
  465. #if defined USE_U8G2_OPPOSANSM32_CHINESE
  466. case font_opposansm32_chinese:
  467. LLOGI("font_opposansm32_chinese");
  468. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_opposansm32_chinese);
  469. lua_pushboolean(L, 1);
  470. break;
  471. #endif
  472. default:
  473. lua_pushboolean(L, 0);
  474. LLOGI("no font");
  475. break;
  476. }
  477. uint16_t e;
  478. int16_t delta, sum;
  479. utf8_state = 0;
  480. sum = 0;
  481. for(;;){
  482. e = utf8_next((uint8_t)*str);
  483. if ( e == 0x0ffff )
  484. break;
  485. str++;
  486. if ( e != 0x0fffe ){
  487. delta = u8g2_font_draw_glyph(&(paint.luat_eink_u8g2), x, y, e);
  488. switch(paint.luat_eink_u8g2.font_decode.dir){
  489. case 0:
  490. x += delta;
  491. break;
  492. case 1:
  493. y += delta;
  494. break;
  495. case 2:
  496. x -= delta;
  497. break;
  498. case 3:
  499. y -= delta;
  500. break;
  501. }
  502. sum += delta;
  503. }
  504. }
  505. return 0;
  506. }
  507. /**
  508. 将缓冲区图像输出到屏幕
  509. @api eink.show(x, y, noClear)
  510. @int x 输出的x坐标,默认0
  511. @int y 输出的y坐标,默认0
  512. @bool noClear 可选,默认false。如果为true则不进行清屏,直接刷上新内容
  513. @return nil 无返回值
  514. */
  515. static int l_eink_show(lua_State *L)
  516. {
  517. int x = luaL_optinteger(L, 1, 0);
  518. int y = luaL_optinteger(L, 2, 0);
  519. int no_clear = lua_toboolean(L, 3);
  520. /* Display the frame_buffer */
  521. //EPD_SetFrameMemory(&epd, frame_buffer, x, y, Paint_GetWidth(&paint), Paint_GetHeight(&paint));
  522. //EPD_DisplayFrame(&epd);
  523. if(!no_clear)
  524. EPD_Clear();
  525. EPD_Display(frame_buffer, NULL);
  526. return 0;
  527. }
  528. /**
  529. 缓冲区绘制线
  530. @api eink.line(x, y, x2, y2, colored)
  531. @int 起点x坐标
  532. @int 起点y坐标
  533. @int 终点x坐标
  534. @int 终点y坐标
  535. @return nil 无返回值
  536. @usage
  537. eink.line(0, 0, 10, 20, 0)
  538. */
  539. static int l_eink_line(lua_State *L)
  540. {
  541. int x = luaL_checkinteger(L, 1);
  542. int y = luaL_checkinteger(L, 2);
  543. int x2 = luaL_checkinteger(L, 3);
  544. int y2 = luaL_checkinteger(L, 4);
  545. int colored = luaL_optinteger(L, 5, 0);
  546. Paint_DrawLine(&paint, x, y, x2, y2, colored);
  547. return 0;
  548. }
  549. /**
  550. 缓冲区绘制矩形
  551. @api eink.rect(x, y, x2, y2, colored, fill)
  552. @int 左上顶点x坐标
  553. @int 左上顶点y坐标
  554. @int 右下顶点x坐标
  555. @int 右下顶点y坐标
  556. @int 默认是0
  557. @int 是否填充,默认是0,不填充
  558. @return nil 无返回值
  559. @usage
  560. eink.rect(0, 0, 10, 20)
  561. eink.rect(0, 0, 10, 20, 1) -- Filled
  562. */
  563. static int l_eink_rect(lua_State *L)
  564. {
  565. int x = luaL_checkinteger(L, 1);
  566. int y = luaL_checkinteger(L, 2);
  567. int x2 = luaL_checkinteger(L, 3);
  568. int y2 = luaL_checkinteger(L, 4);
  569. int colored = luaL_optinteger(L, 5, 0);
  570. int fill = luaL_optinteger(L, 6, 0);
  571. if(fill)
  572. Paint_DrawFilledRectangle(&paint, x, y, x2, y2, colored);
  573. else
  574. Paint_DrawRectangle(&paint, x, y, x2, y2, colored);
  575. return 0;
  576. }
  577. /**
  578. 缓冲区绘制圆形
  579. @api eink.circle(x, y, radius, colored, fill)
  580. @int 圆心x坐标
  581. @int 圆心y坐标
  582. @int 半径
  583. @int 默认是0
  584. @int 是否填充,默认是0,不填充
  585. @return nil 无返回值
  586. @usage
  587. eink.circle(0, 0, 10)
  588. eink.circle(0, 0, 10, 1, 1) -- Filled
  589. */
  590. static int l_eink_circle(lua_State *L)
  591. {
  592. int x = luaL_checkinteger(L, 1);
  593. int y = luaL_checkinteger(L, 2);
  594. int radius = luaL_checkinteger(L, 3);
  595. int colored = luaL_optinteger(L, 4, 0);
  596. int fill = luaL_optinteger(L, 5, 0);
  597. if(fill)
  598. Paint_DrawFilledCircle(&paint, x, y, radius, colored);
  599. else
  600. Paint_DrawCircle(&paint, x, y, radius, colored);
  601. return 0;
  602. }
  603. /**
  604. 缓冲区绘制QRCode
  605. @api eink.qrcode(x, y, str, version)
  606. @int x坐标
  607. @int y坐标
  608. @string 二维码的内容
  609. @int 二维码版本号 可选1_40 对应21*21到177*177
  610. @return nil 无返回值
  611. */
  612. static int l_eink_qrcode(lua_State *L)
  613. {
  614. size_t len;
  615. int x = luaL_checkinteger(L, 1);
  616. int y = luaL_checkinteger(L, 2);
  617. const char* str = luaL_checklstring(L, 3, &len);
  618. int version = luaL_checkinteger(L, 4);
  619. // Create the QR code
  620. QRCode qrcode;
  621. uint8_t qrcodeData[qrcode_getBufferSize(version)];
  622. qrcode_initText(&qrcode, qrcodeData, version, 0, str);
  623. for(int i = 0; i < qrcode.size; i++)
  624. {
  625. for (int j = 0; j < qrcode.size; j++)
  626. {
  627. qrcode_getModule(&qrcode, j, i) ? Paint_DrawPixel(&paint, x+j, y+i, COLORED) : Paint_DrawPixel(&paint, x+j, y+i, UNCOLORED);
  628. }
  629. }
  630. return 0;
  631. }
  632. /**
  633. 缓冲区绘制电池
  634. @api eink.bat(x, y, bat)
  635. @int x坐标
  636. @int y坐标
  637. @int 电池电压,单位毫伏
  638. @return nil 无返回值
  639. */
  640. static int l_eink_bat(lua_State *L)
  641. {
  642. int x = luaL_checkinteger(L, 1);
  643. int y = luaL_checkinteger(L, 2);
  644. int bat = luaL_checkinteger(L, 3);
  645. int batnum = 0;
  646. // eink.rect(0, 3, 2, 6)
  647. // eink.rect(2, 0, 20, 9)
  648. // eink.rect(9, 1, 19, 8, 0, 1)
  649. if(bat < 4200 && bat > 4080)batnum = 100;
  650. if(bat < 4080 && bat > 4000)batnum = 90;
  651. if(bat < 4000 && bat > 3930)batnum = 80;
  652. if(bat < 3930 && bat > 3870)batnum = 70;
  653. if(bat < 3870 && bat > 3820)batnum = 60;
  654. if(bat < 3820 && bat > 3790)batnum = 50;
  655. if(bat < 3790 && bat > 3770)batnum = 40;
  656. if(bat < 3770 && bat > 3730)batnum = 30;
  657. if(bat < 3730 && bat > 3700)batnum = 20;
  658. if(bat < 3700 && bat > 3680)batnum = 15;
  659. if(bat < 3680 && bat > 3500)batnum = 10;
  660. if(bat < 3500 && bat > 2500)batnum = 5;
  661. batnum = 20 - (int)(batnum / 5) + 3;
  662. // w外框
  663. Paint_DrawRectangle(&paint, x+0, y+3, x+2, y+6, COLORED);
  664. Paint_DrawRectangle(&paint, x+2, y+0, x+23, y+9, COLORED);
  665. // 3 ~21 100 / 5
  666. Paint_DrawFilledRectangle(&paint, x+batnum, y+1, x+22, y+8, COLORED);
  667. return 0;
  668. }
  669. /**
  670. 缓冲区绘制天气图标
  671. @api eink.weather_icon(x, y, code)
  672. @int x坐标
  673. @int y坐标
  674. @int 天气代号
  675. @return nil 无返回值
  676. */
  677. static int l_eink_weather_icon(lua_State *L)
  678. {
  679. size_t len;
  680. int x = luaL_checkinteger(L, 1);
  681. int y = luaL_checkinteger(L, 2);
  682. int code = luaL_checkinteger(L, 3);
  683. const char* str = luaL_optlstring(L, 4, "nil", &len);
  684. const unsigned char * icon = gImage_999;
  685. if (strcmp(str, "xue") == 0)code = 401;
  686. if (strcmp(str, "lei") == 0)code = 302;
  687. if (strcmp(str, "shachen") == 0)code = 503;
  688. if (strcmp(str, "wu") == 0)code = 501;
  689. if (strcmp(str, "bingbao") == 0)code = 504;
  690. if (strcmp(str, "yun") == 0)code = 103;
  691. if (strcmp(str, "yu") == 0)code = 306;
  692. if (strcmp(str, "yin") == 0)code = 101;
  693. if (strcmp(str, "qing") == 0)code = 100;
  694. // xue、lei、shachen、wu、bingbao、yun、yu、yin、qing
  695. //if(code == 64)
  696. // for(int i = 0; i < 64; i++)
  697. // {
  698. // for (int j = 0; j < 8; j++)
  699. // {
  700. // for (int k = 0; k < 8; k++)
  701. // (gImage_103[i*8+j] << k )& 0x80 ? Paint_DrawPixel(&paint, x+j*8+k, y+i, COLORED) : Paint_DrawPixel(&paint, x+j*8+k, y+i, UNCOLORED);
  702. // }
  703. // }
  704. switch (code)
  705. {
  706. case 100:icon = gImage_100;break;
  707. case 101:icon = gImage_101;break;
  708. case 102:icon = gImage_102;break;
  709. case 103:icon = gImage_103;break;
  710. case 104:icon = gImage_104;break;
  711. case 200:icon = gImage_200;break;
  712. case 201:icon = gImage_201;break;
  713. case 205:icon = gImage_205;break;
  714. case 208:icon = gImage_208;break;
  715. case 301:icon = gImage_301;break;
  716. case 302:icon = gImage_302;break;
  717. case 303:icon = gImage_303;break;
  718. case 304:icon = gImage_304;break;
  719. case 305:icon = gImage_305;break;
  720. case 306:icon = gImage_306;break;
  721. case 307:icon = gImage_307;break;
  722. case 308:icon = gImage_308;break;
  723. case 309:icon = gImage_309;break;
  724. case 310:icon = gImage_310;break;
  725. case 311:icon = gImage_311;break;
  726. case 312:icon = gImage_312;break;
  727. case 313:icon = gImage_313;break;
  728. case 400:icon = gImage_400;break;
  729. case 401:icon = gImage_401;break;
  730. case 402:icon = gImage_402;break;
  731. case 403:icon = gImage_403;break;
  732. case 404:icon = gImage_404;break;
  733. case 405:icon = gImage_405;break;
  734. case 406:icon = gImage_406;break;
  735. case 407:icon = gImage_407;break;
  736. case 500:icon = gImage_500;break;
  737. case 501:icon = gImage_501;break;
  738. case 502:icon = gImage_502;break;
  739. case 503:icon = gImage_503;break;
  740. case 504:icon = gImage_504;break;
  741. case 507:icon = gImage_507;break;
  742. case 508:icon = gImage_508;break;
  743. case 900:icon = gImage_900;break;
  744. case 901:icon = gImage_901;break;
  745. case 999:icon = gImage_999;break;
  746. default:
  747. break;
  748. }
  749. for(int i = 0; i < 48; i++)
  750. {
  751. for (int j = 0; j < 6; j++)
  752. {
  753. for (int k = 0; k < 8; k++)
  754. (icon[i*6+j] << k )& 0x80 ? Paint_DrawPixel(&paint, x+j*8+k, y+i, COLORED) : Paint_DrawPixel(&paint, x+j*8+k, y+i, UNCOLORED);
  755. }
  756. }
  757. return 0;
  758. }
  759. /**
  760. 设置墨水屏驱动型号
  761. @api eink.model(m)
  762. @int 型号名称, 例如 eink.model(eink.MODEL_1in54_V2)
  763. @return nil 无返回值
  764. */
  765. static int l_eink_model(lua_State *L) {
  766. EPD_Model(luaL_checkinteger(L, 1));
  767. return 0;
  768. }
  769. #ifdef LUAT_USE_GTFONT
  770. #include "GT5SLCD2E_1A.h"
  771. extern void gtfont_draw_w(unsigned char *pBits,unsigned int x,unsigned int y,unsigned int widt,unsigned int high,int(*point)(void*),void* userdata,int mode);
  772. 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);
  773. static int l_eink_draw_gtfont_gb2312(lua_State *L) {
  774. unsigned char buf[128];
  775. int len;
  776. int i = 0;
  777. uint8_t strhigh,strlow ;
  778. uint16_t str;
  779. const char *fontCode = luaL_checklstring(L, 1,&len);
  780. unsigned char size = luaL_checkinteger(L, 2);
  781. int x = luaL_checkinteger(L, 3);
  782. int y = luaL_checkinteger(L, 4);
  783. while ( i < len){
  784. strhigh = *fontCode;
  785. fontCode++;
  786. strlow = *fontCode;
  787. str = (strhigh<<8)|strlow;
  788. fontCode++;
  789. get_font(buf, 1, str, size, size, size);
  790. gtfont_draw_w(buf , x ,y , size , size,Paint_DrawPixel,&paint,1);
  791. x+=size;
  792. i+=2;
  793. }
  794. return 0;
  795. }
  796. static int l_eink_draw_gtfont_gb2312_gray(lua_State* L) {
  797. unsigned char buf[2048];
  798. int len;
  799. int i = 0;
  800. uint8_t strhigh,strlow ;
  801. uint16_t str;
  802. const char *fontCode = luaL_checklstring(L, 1,&len);
  803. unsigned char size = luaL_checkinteger(L, 2);
  804. unsigned char font_g = luaL_checkinteger(L, 3);
  805. int x = luaL_checkinteger(L, 4);
  806. int y = luaL_checkinteger(L, 5);
  807. while ( i < len){
  808. strhigh = *fontCode;
  809. fontCode++;
  810. strlow = *fontCode;
  811. str = (strhigh<<8)|strlow;
  812. fontCode++;
  813. get_font(buf, 1, str, size*font_g, size*font_g, size*font_g);
  814. Gray_Process(buf,size,size,font_g);
  815. gtfont_draw_gray_hz(buf, x, y, size , size, font_g, 1,Paint_DrawPixel,&paint,1);
  816. x+=size;
  817. i+=2;
  818. }
  819. return 0;
  820. }
  821. #ifdef LUAT_USE_GTFONT_UTF8
  822. extern unsigned short unicodetogb2312 ( unsigned short chr);
  823. static int l_eink_draw_gtfont_utf8(lua_State *L) {
  824. unsigned char buf[128];
  825. int len;
  826. int i = 0;
  827. uint8_t strhigh,strlow ;
  828. uint16_t e,str;
  829. const char *fontCode = luaL_checklstring(L, 1,&len);
  830. unsigned char size = luaL_checkinteger(L, 2);
  831. int x = luaL_checkinteger(L, 3);
  832. int y = luaL_checkinteger(L, 4);
  833. for(;;){
  834. e = utf8_next((uint8_t)*fontCode);
  835. if ( e == 0x0ffff )
  836. break;
  837. fontCode++;
  838. if ( e != 0x0fffe ){
  839. uint16_t str = unicodetogb2312(e);
  840. get_font(buf, 1, str, size, size, size);
  841. gtfont_draw_w(buf , x ,y , size , size,Paint_DrawPixel,&paint,1);
  842. x+=size;
  843. }
  844. }
  845. return 0;
  846. }
  847. static int l_eink_draw_gtfont_utf8_gray(lua_State* L) {
  848. unsigned char buf[2048];
  849. int len;
  850. int i = 0;
  851. uint8_t strhigh,strlow ;
  852. uint16_t e,str;
  853. const char *fontCode = luaL_checklstring(L, 1,&len);
  854. unsigned char size = luaL_checkinteger(L, 2);
  855. unsigned char font_g = luaL_checkinteger(L, 3);
  856. int x = luaL_checkinteger(L, 4);
  857. int y = luaL_checkinteger(L, 5);
  858. for(;;){
  859. e = utf8_next((uint8_t)*fontCode);
  860. if ( e == 0x0ffff )
  861. break;
  862. fontCode++;
  863. if ( e != 0x0fffe ){
  864. uint16_t str = unicodetogb2312(e);
  865. get_font(buf, 1, str, size*font_g, size*font_g, size*font_g);
  866. Gray_Process(buf,size,size,font_g);
  867. gtfont_draw_gray_hz(buf, x, y, size , size, font_g, 1,Paint_DrawPixel,&paint,1);
  868. x+=size;
  869. }
  870. }
  871. return 0;
  872. }
  873. #endif // LUAT_USE_GTFONT_UTF8
  874. #endif // LUAT_USE_GTFONT
  875. static void eink_DrawHXBM(uint16_t x, uint16_t y, uint16_t len, const uint8_t *b){
  876. uint8_t mask;
  877. mask = 1;
  878. while(len > 0) {
  879. if ( *b & mask ) drawFastHLine(&paint, x, y, 1,COLORED);
  880. else drawFastVLine(&paint, x, y, 1,UNCOLORED);
  881. x++;
  882. mask <<= 1;
  883. if ( mask == 0 ){
  884. mask = 1;
  885. b++;
  886. }
  887. len--;
  888. }
  889. }
  890. /*
  891. 绘制位图
  892. @api eink.drawXbm(x, y, w, h, data)
  893. @int X坐标
  894. @int y坐标
  895. @int 位图宽
  896. @int 位图高
  897. @int 位图数据,每一位代表一个像素
  898. @usage
  899. -- 取模使用PCtoLCD2002软件即可
  900. -- 在(0,0)为左上角,绘制 16x16 "今" 的位图
  901. eink.drawXbm(0, 0, 16,16, string.char(
  902. 0x80,0x00,0x80,0x00,0x40,0x01,0x20,0x02,0x10,0x04,0x48,0x08,0x84,0x10,0x83,0x60,
  903. 0x00,0x00,0xF8,0x0F,0x00,0x08,0x00,0x04,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x00
  904. ))
  905. */
  906. static int l_eink_drawXbm(lua_State *L){
  907. int x = luaL_checkinteger(L, 1);
  908. int y = luaL_checkinteger(L, 2);
  909. int w = luaL_checkinteger(L, 3);
  910. int h = luaL_checkinteger(L, 4);
  911. size_t len = 0;
  912. const char* data = luaL_checklstring(L, 5, &len);
  913. if (h < 1) return 0; // 行数必须大于0
  914. if (w < h) return 0; // 起码要填满一行
  915. uint8_t blen;
  916. blen = w;
  917. blen += 7;
  918. blen >>= 3;
  919. while( h > 0 ){
  920. eink_DrawHXBM(x, y, w, (const uint8_t*)data);
  921. data += blen;
  922. y++;
  923. h--;
  924. }
  925. lua_pushboolean(L, 1);
  926. return 1;
  927. }
  928. #include "rotable2.h"
  929. static const rotable_Reg_t reg_eink[] =
  930. {
  931. { "setup", ROREG_FUNC(l_eink_setup)},
  932. { "sleep", ROREG_FUNC(l_eink_sleep)},
  933. { "clear", ROREG_FUNC(l_eink_clear)},
  934. { "setWin", ROREG_FUNC(l_eink_setWin)},
  935. { "getWin", ROREG_FUNC(l_eink_getWin)},
  936. { "print", ROREG_FUNC(l_eink_print)},
  937. { "show", ROREG_FUNC(l_eink_show)},
  938. { "rect", ROREG_FUNC(l_eink_rect)},
  939. { "circle", ROREG_FUNC(l_eink_circle)},
  940. { "line", ROREG_FUNC(l_eink_line)},
  941. { "qrcode", ROREG_FUNC(l_eink_qrcode)},
  942. { "bat", ROREG_FUNC(l_eink_bat)},
  943. { "weather_icon", ROREG_FUNC(l_eink_weather_icon)},
  944. { "model", ROREG_FUNC(l_eink_model)},
  945. { "drawXbm", ROREG_FUNC(l_eink_drawXbm)},
  946. #ifdef LUAT_USE_GTFONT
  947. { "drawGtfontGb2312", ROREG_FUNC(l_eink_draw_gtfont_gb2312)},
  948. { "drawGtfontGb2312Gray", ROREG_FUNC(l_eink_draw_gtfont_gb2312_gray)},
  949. #ifdef LUAT_USE_GTFONT_UTF8
  950. { "drawGtfontUtf8", ROREG_FUNC(l_eink_draw_gtfont_utf8)},
  951. { "drawGtfontUtf8Gray", ROREG_FUNC(l_eink_draw_gtfont_utf8_gray)},
  952. #endif // LUAT_USE_GTFONT_UTF8
  953. #endif // LUAT_USE_GTFONT
  954. { "MODEL_1in02d", ROREG_INT(MODEL_1in02d)},
  955. { "MODEL_1in54", ROREG_INT(MODEL_1in54)},
  956. { "MODEL_1in54_V2", ROREG_INT(MODEL_1in54_V2)},
  957. { "MODEL_1in54b", ROREG_INT(MODEL_1in54b)},
  958. { "MODEL_1in54b_V2", ROREG_INT(MODEL_1in54b_V2)},
  959. { "MODEL_1in54c", ROREG_INT(MODEL_1in54c)},
  960. { "MODEL_1in54f", ROREG_INT(MODEL_1in54f)},
  961. { "MODEL_2in54b_V3", ROREG_INT(MODEL_2in13b_V3)},
  962. { "MODEL_2in7", ROREG_INT(MODEL_2in7)},
  963. { "MODEL_2in7b", ROREG_INT(MODEL_2in7b)},
  964. { "MODEL_2in9", ROREG_INT(MODEL_2in9)},
  965. { "MODEL_2in9_V2", ROREG_INT(MODEL_2in9_V2)},
  966. { "MODEL_2in9bc", ROREG_INT(MODEL_2in9bc)},
  967. { "MODEL_2in9b_V3", ROREG_INT(MODEL_2in9b_V3)},
  968. { "MODEL_2in9d", ROREG_INT(MODEL_2in9d)},
  969. { "MODEL_2in9f", ROREG_INT(MODEL_2in9f)},
  970. { "MODEL_3in7", ROREG_INT(MODEL_3in7)},
  971. { "font_opposansm8", ROREG_INT(font_opposansm8)},
  972. { "font_opposansm10", ROREG_INT(font_opposansm10)},
  973. { "font_opposansm12", ROREG_INT(font_opposansm12)},
  974. { "font_opposansm16", ROREG_INT(font_opposansm16)},
  975. { "font_opposansm18", ROREG_INT(font_opposansm18)},
  976. { "font_opposansm20", ROREG_INT(font_opposansm20)},
  977. { "font_opposansm22", ROREG_INT(font_opposansm22)},
  978. { "font_opposansm24", ROREG_INT(font_opposansm24)},
  979. { "font_opposansm32", ROREG_INT(font_opposansm32)},
  980. { "font_opposansm12_chinese", ROREG_INT(font_opposansm12_chinese)},
  981. { "font_opposansm16_chinese", ROREG_INT(font_opposansm16_chinese)},
  982. { "font_opposansm24_chinese", ROREG_INT(font_opposansm24_chinese)},
  983. { "font_opposansm32_chinese", ROREG_INT(font_opposansm32_chinese)},
  984. { NULL, {}}
  985. };
  986. LUAMOD_API int luaopen_eink( lua_State *L ){
  987. luat_newlib2(L, reg_eink);
  988. return 1;
  989. }