luat_lib_eink.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  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. #define COLORED 0
  24. #define UNCOLORED 1
  25. #define LUAT_LOG_TAG "luat.eink"
  26. // static EPD epd;
  27. static Paint paint;
  28. static unsigned char* frame_buffer = NULL;
  29. // #ifdef econf
  30. // #undef econf
  31. // #endif
  32. eink_conf_t econf = {0};
  33. #define Pin_BUSY (econf.busy_pin)
  34. #define Pin_RES (econf.res_pin)
  35. #define Pin_DC (econf.dc_pin)
  36. #define Pin_CS (econf.cs_pin)
  37. #define SPI_ID (econf.spi_id)
  38. /**
  39. 初始化eink
  40. @api eink.setup(full, spiid)
  41. @int 全屏刷新1,局部刷新0,默认是全屏刷新
  42. @int 所在的spi,默认是0
  43. @return boolean 成功返回true,否则返回false
  44. */
  45. static int l_eink_setup(lua_State *L) {
  46. econf.full_mode = luaL_optinteger(L, 1, 1);
  47. econf.spi_id = luaL_optinteger(L, 2, 0);
  48. econf.busy_pin = luaL_optinteger(L, 3, 18);
  49. econf.res_pin = luaL_optinteger(L, 4, 7);
  50. econf.dc_pin = luaL_optinteger(L, 5, 9);
  51. econf.cs_pin = luaL_optinteger(L, 6, 16);
  52. if (frame_buffer != NULL) {
  53. lua_pushboolean(L, 1);
  54. return 0;
  55. }
  56. luat_spi_t spi_config = {0};
  57. spi_config.bandrate = 2000000U;//luaL_optinteger(L, 1, 2000000U); // 2000000U
  58. spi_config.id = SPI_ID;
  59. spi_config.cs = 255; // 默认无
  60. spi_config.CPHA = 0; // CPHA0
  61. spi_config.CPOL = 0; // CPOL0
  62. spi_config.dataw = 8; // 8bit
  63. spi_config.bit_dict = 1; // MSB=1, LSB=0
  64. spi_config.master = 1; // master=1,slave=0
  65. spi_config.mode = 1; // FULL=1, half=0
  66. //LLOGD("setup GPIO for epd");
  67. luat_gpio_mode(Pin_BUSY, Luat_GPIO_INPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  68. luat_gpio_mode(Pin_RES, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  69. luat_gpio_mode(Pin_DC, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  70. luat_gpio_mode(Pin_CS, Luat_GPIO_OUTPUT, Luat_GPIO_PULLUP, Luat_GPIO_LOW);
  71. int status = luat_spi_setup(&spi_config);
  72. size_t epd_w = 0;
  73. size_t epd_h = 0;
  74. if(status == 0)
  75. {
  76. LLOGD("spi setup complete, now setup epd");
  77. if(econf.full_mode)
  78. status = EPD_Init(1, &epd_w, &epd_h);
  79. else
  80. status = EPD_Init(0, &epd_w, &epd_h);
  81. if (status != 0) {
  82. LLOGD("e-Paper init failed");
  83. return 0;
  84. }
  85. frame_buffer = (unsigned char*)luat_heap_malloc(epd_w * epd_h / 8);
  86. // Paint paint;
  87. Paint_Init(&paint, frame_buffer, epd_w, epd_h);
  88. Paint_Clear(&paint, UNCOLORED);
  89. }
  90. //LLOGD("epd init complete");
  91. lua_pushboolean(L, 1);
  92. return 1;
  93. }
  94. /**
  95. 清除绘图缓冲区
  96. @api eink.clear()
  97. @return nil 无返回值,不会马上刷新到设备
  98. */
  99. static int l_eink_clear(lua_State *L)
  100. {
  101. int colored = luaL_optinteger(L, 1, 1);
  102. Paint_Clear(&paint, colored);
  103. return 0;
  104. }
  105. /**
  106. 设置窗口
  107. @api eink.setWin(width, height, rotate)
  108. @int width 宽度
  109. @int height 高度
  110. @int rotate 显示方向,0/1/2/3, 相当于旋转0度/90度/180度/270度
  111. @return nil 无返回值
  112. */
  113. static int l_eink_setWin(lua_State *L)
  114. {
  115. int width = luaL_checkinteger(L, 1);
  116. int height = luaL_checkinteger(L, 2);
  117. int rotate = luaL_checkinteger(L, 3);
  118. Paint_SetWidth(&paint, width);
  119. Paint_SetHeight(&paint, height);
  120. Paint_SetRotate(&paint, rotate);
  121. return 0;
  122. }
  123. /**
  124. 获取窗口信息
  125. @api eink.getWin()
  126. @return int width 宽
  127. @return int height 高
  128. @return int rotate 旋转方向
  129. */
  130. static int l_eink_getWin(lua_State *L)
  131. {
  132. int width = Paint_GetWidth(&paint);
  133. int height = Paint_GetHeight(&paint);
  134. int rotate = Paint_GetRotate(&paint);
  135. lua_pushinteger(L, width);
  136. lua_pushinteger(L, height);
  137. lua_pushinteger(L, rotate);
  138. return 3;
  139. }
  140. /**
  141. 绘制字符串(仅ASCII)
  142. @api eink.print(x, y, str, colored, font)
  143. @int x坐标
  144. @int y坐标
  145. @string 字符串
  146. @int 默认是0
  147. @font 字体大小,默认12
  148. @return nil 无返回值
  149. */
  150. static int l_eink_print(lua_State *L)
  151. {
  152. size_t len;
  153. int x = luaL_checkinteger(L, 1);
  154. int y = luaL_checkinteger(L, 2);
  155. const char *str = luaL_checklstring(L, 3, &len);
  156. int colored = luaL_optinteger(L, 4, 0);
  157. int font = luaL_optinteger(L, 5, 12);
  158. switch (font)
  159. {
  160. case 8:
  161. Paint_DrawStringAt(&paint, x, y, str, &Font8, colored);
  162. break;
  163. case 12:
  164. Paint_DrawStringAt(&paint, x, y, str, &Font12, colored);
  165. break;
  166. case 16:
  167. Paint_DrawStringAt(&paint, x, y, str, &Font16, colored);
  168. break;
  169. case 20:
  170. Paint_DrawStringAt(&paint, x, y, str, &Font20, colored);
  171. break;
  172. case 24:
  173. Paint_DrawStringAt(&paint, x, y, str, &Font24, colored);
  174. break;
  175. default:
  176. break;
  177. }
  178. return 0;
  179. }
  180. static uint8_t utf8_state;
  181. static uint16_t encoding;
  182. static uint16_t utf8_next(uint8_t b)
  183. {
  184. if ( b == 0 ) /* '\n' terminates the string to support the string list procedures */
  185. return 0x0ffff; /* end of string detected, pending UTF8 is discarded */
  186. if ( utf8_state == 0 )
  187. {
  188. if ( b >= 0xfc ) /* 6 byte sequence */
  189. {
  190. utf8_state = 5;
  191. b &= 1;
  192. }
  193. else if ( b >= 0xf8 )
  194. {
  195. utf8_state = 4;
  196. b &= 3;
  197. }
  198. else if ( b >= 0xf0 )
  199. {
  200. utf8_state = 3;
  201. b &= 7;
  202. }
  203. else if ( b >= 0xe0 )
  204. {
  205. utf8_state = 2;
  206. b &= 15;
  207. }
  208. else if ( b >= 0xc0 )
  209. {
  210. utf8_state = 1;
  211. b &= 0x01f;
  212. }
  213. else
  214. {
  215. /* do nothing, just use the value as encoding */
  216. return b;
  217. }
  218. encoding = b;
  219. return 0x0fffe;
  220. }
  221. else
  222. {
  223. utf8_state--;
  224. /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
  225. encoding<<=6;
  226. b &= 0x03f;
  227. encoding |= b;
  228. if ( utf8_state != 0 )
  229. return 0x0fffe; /* nothing to do yet */
  230. }
  231. return encoding;
  232. }
  233. static void drawFastHLine(Paint* conf,int16_t x, int16_t y, int16_t len, uint16_t color){
  234. Paint_DrawLine(conf,x, y, x+len,y,color);
  235. }
  236. static void drawFastVLine(Paint* conf,int16_t x, int16_t y, int16_t len, uint16_t color){
  237. Paint_DrawLine(conf,x, y, x+len,y,color);
  238. }
  239. static void u8g2_draw_hv_line(u8g2_t *u8g2, int16_t x, int16_t y, int16_t len, uint8_t dir, uint16_t color){
  240. switch(dir)
  241. {
  242. case 0:
  243. drawFastHLine(&paint,x,y,len,color);
  244. break;
  245. case 1:
  246. drawFastVLine(&paint,x,y,len,color);
  247. break;
  248. case 2:
  249. drawFastHLine(&paint,x-len+1,y,len,color);
  250. break;
  251. case 3:
  252. drawFastVLine(&paint,x,y-len+1,len,color);
  253. break;
  254. }
  255. }
  256. static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir) U8X8_NOINLINE;
  257. static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir)
  258. {
  259. switch(dir)
  260. {
  261. case 0:
  262. dx += x;
  263. break;
  264. case 1:
  265. dx -= y;
  266. break;
  267. case 2:
  268. dx -= x;
  269. break;
  270. default:
  271. dx += y;
  272. break;
  273. }
  274. return dx;
  275. }
  276. static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir) U8X8_NOINLINE;
  277. static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir)
  278. {
  279. switch(dir)
  280. {
  281. case 0:
  282. dy += y;
  283. break;
  284. case 1:
  285. dy += x;
  286. break;
  287. case 2:
  288. dy -= y;
  289. break;
  290. default:
  291. dy -= x;
  292. break;
  293. }
  294. return dy;
  295. }
  296. static void u8g2_font_decode_len(u8g2_t *u8g2, uint8_t len, uint8_t is_foreground){
  297. uint8_t cnt; /* total number of remaining pixels, which have to be drawn */
  298. uint8_t rem; /* remaining pixel to the right edge of the glyph */
  299. uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */
  300. /* current is either equal to cnt or equal to rem */
  301. /* local coordinates of the glyph */
  302. uint8_t lx,ly;
  303. /* target position on the screen */
  304. int16_t x, y;
  305. u8g2_font_decode_t *decode = &(u8g2->font_decode);
  306. cnt = len;
  307. /* get the local position */
  308. lx = decode->x;
  309. ly = decode->y;
  310. for(;;){
  311. /* calculate the number of pixel to the right edge of the glyph */
  312. rem = decode->glyph_width;
  313. rem -= lx;
  314. /* calculate how many pixel to draw. This is either to the right edge */
  315. /* or lesser, if not enough pixel are left */
  316. current = rem;
  317. if ( cnt < rem )
  318. current = cnt;
  319. /* now draw the line, but apply the rotation around the glyph target position */
  320. //u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
  321. /* get target position */
  322. x = decode->target_x;
  323. y = decode->target_y;
  324. /* apply rotation */
  325. x = u8g2_add_vector_x(x, lx, ly, decode->dir);
  326. y = u8g2_add_vector_y(y, lx, ly, decode->dir);
  327. /* draw foreground and background (if required) */
  328. if ( current > 0 ) /* avoid drawing zero length lines, issue #4 */
  329. {
  330. if ( is_foreground )
  331. {
  332. u8g2_draw_hv_line(u8g2, x, y, current, decode->dir, decode->fg_color);
  333. }
  334. else if ( decode->is_transparent == 0 )
  335. {
  336. // u8g2_draw_hv_line(u8g2, x, y, current, decode->dir, decode->bg_color);
  337. }
  338. }
  339. /* check, whether the end of the run length code has been reached */
  340. if ( cnt < rem )
  341. break;
  342. cnt -= rem;
  343. lx = 0;
  344. ly++;
  345. }
  346. lx += cnt;
  347. decode->x = lx;
  348. decode->y = ly;
  349. }
  350. static void u8g2_font_setup_decode(u8g2_t *u8g2, const uint8_t *glyph_data)
  351. {
  352. u8g2_font_decode_t *decode = &(u8g2->font_decode);
  353. decode->decode_ptr = glyph_data;
  354. decode->decode_bit_pos = 0;
  355. /* 8 Nov 2015, this is already done in the glyph data search procedure */
  356. /*
  357. decode->decode_ptr += 1;
  358. decode->decode_ptr += 1;
  359. */
  360. decode->glyph_width = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_char_width);
  361. decode->glyph_height = u8g2_font_decode_get_unsigned_bits(decode,u8g2->font_info.bits_per_char_height);
  362. }
  363. static int8_t u8g2_font_decode_glyph(u8g2_t *u8g2, const uint8_t *glyph_data){
  364. uint8_t a, b;
  365. int8_t x, y;
  366. int8_t d;
  367. int8_t h;
  368. u8g2_font_decode_t *decode = &(u8g2->font_decode);
  369. u8g2_font_setup_decode(u8g2, glyph_data);
  370. h = u8g2->font_decode.glyph_height;
  371. x = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_x);
  372. y = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_y);
  373. d = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_delta_x);
  374. if ( decode->glyph_width > 0 )
  375. {
  376. decode->target_x = u8g2_add_vector_x(decode->target_x, x, -(h+y), decode->dir);
  377. decode->target_y = u8g2_add_vector_y(decode->target_y, x, -(h+y), decode->dir);
  378. //u8g2_add_vector(&(decode->target_x), &(decode->target_y), x, -(h+y), decode->dir);
  379. /* reset local x/y position */
  380. decode->x = 0;
  381. decode->y = 0;
  382. /* decode glyph */
  383. for(;;){
  384. a = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_0);
  385. b = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_1);
  386. do{
  387. u8g2_font_decode_len(u8g2, a, 0);
  388. u8g2_font_decode_len(u8g2, b, 1);
  389. } while( u8g2_font_decode_get_unsigned_bits(decode, 1) != 0 );
  390. if ( decode->y >= h )
  391. break;
  392. }
  393. }
  394. return d;
  395. }
  396. const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding);
  397. static int16_t u8g2_font_draw_glyph(u8g2_t *u8g2, int16_t x, int16_t y, uint16_t encoding){
  398. int16_t dx = 0;
  399. u8g2->font_decode.target_x = x;
  400. u8g2->font_decode.target_y = y;
  401. const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, encoding);
  402. if ( glyph_data != NULL ){
  403. dx = u8g2_font_decode_glyph(u8g2, glyph_data);
  404. }
  405. return dx;
  406. }
  407. // // void u8g2_read_font_info(u8g2_font_info_t *font_info, const uint8_t *font);
  408. // uint8_t luat_u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
  409. // const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding);
  410. // uint8_t * font_pix_find(uint16_t e, int font_pix_find);
  411. /**
  412. 绘制字符串,支持中文
  413. @api eink.printcn(x, y, str, colored, font)
  414. @int x坐标
  415. @int y坐标
  416. @string 字符串
  417. @int 默认是0
  418. @font 字体大小,默认12
  419. @return nil 无返回值
  420. */
  421. static int l_eink_printcn(lua_State *L)
  422. {
  423. // size_t len;
  424. // int x = luaL_checkinteger(L, 1);
  425. // int y = luaL_checkinteger(L, 2);
  426. // const char *str = luaL_checklstring(L, 3, &len);
  427. // int colored = luaL_optinteger(L, 4, 0);
  428. // int font_size = luaL_optinteger(L, 5, 12);
  429. // //LLOGD("printcn font_size %d len %d", font_size, len);
  430. // // 解码数据 TODO 使用无u8g2的方案
  431. // u8g2_t *u8g2 = luat_heap_malloc(sizeof(u8g2_t));
  432. // u8g2_Setup_ssd1306_i2c_128x64_noname_f( u8g2, U8G2_R0, u8x8_byte_sw_i2c, luat_u8x8_gpio_and_delay);
  433. // u8g2_InitDisplay(u8g2);
  434. // u8g2_SetPowerSave(u8g2, 0);
  435. // u8g2->u8x8.next_cb = u8x8_utf8_next;
  436. // uint16_t e;
  437. // //u8g2_uint_t delta, sum;
  438. // u8x8_utf8_init(u8g2_GetU8x8(u8g2));
  439. // //sum = 0;
  440. // uint8_t* str2 = (uint8_t*)str;
  441. // for(;;)
  442. // {
  443. // e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str2);
  444. // //LLOGD("chinese >> 0x%04X", e);
  445. // if ( e == 0x0ffff )
  446. // break;
  447. // str2++;
  448. // // if (e != 0x0fffe && e < 0x007e) {
  449. // // char ch[2] = {e, 0};
  450. // // if (font_size == 16)
  451. // // Paint_DrawStringAt(&paint, x, y, ch, &Font16, colored);
  452. // // else if (font_size == 24)
  453. // // Paint_DrawStringAt(&paint, x, y, ch, &Font24, colored);
  454. // // x += font_size;
  455. // // }
  456. // // else
  457. // if ( e != 0x0fffe )
  458. // {
  459. // //delta = u8g2_DrawGlyph(u8g2, x, y, e);
  460. // uint8_t * f = font_pix_find(e, font_size);
  461. // if (f != NULL) {
  462. // // 当前仅支持16p和24p
  463. // int datalen = font_size == 16 ? 32 : 72;
  464. // int xlen = font_size == 16 ? 2 : 3;
  465. // //LLOGD("found FONT DATA 0x%04X datalen=%d xlen=%d", e, datalen, xlen);
  466. // for (size_t i = 0; i < datalen; )
  467. // {
  468. // for (size_t k = 0; k < xlen; k++)
  469. // {
  470. // uint8_t pix = f[i];
  471. // //LLOGD("pix data %02X x+j=%d y+j/2=%d", pix, x, y+i/2);
  472. // for (size_t j = 0; j < 8; j++)
  473. // {
  474. // if ((pix >> (7-j)) & 0x01) {
  475. // Paint_DrawPixel(&paint, x+j+k*8, y+i/xlen, colored);
  476. // }
  477. // }
  478. // i++;
  479. // }
  480. // }
  481. // }
  482. // else {
  483. // LLOGD("NOT found FONT DATA 0x%04X", e);
  484. // }
  485. // if (e <= 0x7E)
  486. // x += font_size / 2;
  487. // else
  488. // {
  489. // x += font_size;
  490. // }
  491. // }
  492. // }
  493. // luat_heap_free(u8g2);
  494. int x, y;
  495. int sz;
  496. const uint8_t* data;
  497. // uint32_t color = FORE_COLOR;
  498. x = luaL_checkinteger(L, 1);
  499. y = luaL_checkinteger(L, 2);
  500. data = (const uint8_t*)luaL_checklstring(L, 3, &sz);
  501. if (sz == 0)
  502. return 0;
  503. u8g2_SetFontMode(&(paint.luat_eink_u8g2), 0);
  504. u8g2_SetFontDirection(&(paint.luat_eink_u8g2), 0);
  505. u8g2_SetFont(&(paint.luat_eink_u8g2), u8g2_font_wqy16_t_gb2312);
  506. uint16_t e;
  507. int16_t delta, sum;
  508. utf8_state = 0;
  509. sum = 0;
  510. for(;;){
  511. e = utf8_next((uint8_t)*data);
  512. if ( e == 0x0ffff )
  513. break;
  514. data++;
  515. if ( e != 0x0fffe ){
  516. delta = u8g2_font_draw_glyph(&(paint.luat_eink_u8g2), x, y, e);
  517. switch(paint.luat_eink_u8g2.font_decode.dir){
  518. case 0:
  519. x += delta;
  520. break;
  521. case 1:
  522. y += delta;
  523. break;
  524. case 2:
  525. x -= delta;
  526. break;
  527. case 3:
  528. y -= delta;
  529. break;
  530. }
  531. sum += delta;
  532. }
  533. }
  534. return 0;
  535. }
  536. /**
  537. 将缓冲区图像输出到屏幕
  538. @api eink.show(x, y)
  539. @int x 输出的x坐标,默认0
  540. @int y 输出的y坐标,默认0
  541. @return nil 无返回值
  542. */
  543. static int l_eink_show(lua_State *L)
  544. {
  545. int x = luaL_optinteger(L, 1, 0);
  546. int y = luaL_optinteger(L, 2, 0);
  547. /* Display the frame_buffer */
  548. //EPD_SetFrameMemory(&epd, frame_buffer, x, y, Paint_GetWidth(&paint), Paint_GetHeight(&paint));
  549. //EPD_DisplayFrame(&epd);
  550. EPD_Clear();
  551. EPD_Display(frame_buffer, NULL);
  552. return 0;
  553. }
  554. /**
  555. 缓冲区绘制线
  556. @api eink.line(x, y, x2, y2, colored)
  557. @int 起点x坐标
  558. @int 起点y坐标
  559. @int 终点x坐标
  560. @int 终点y坐标
  561. @return nil 无返回值
  562. @usage
  563. eink.line(0, 0, 10, 20, 0)
  564. */
  565. static int l_eink_line(lua_State *L)
  566. {
  567. int x = luaL_checkinteger(L, 1);
  568. int y = luaL_checkinteger(L, 2);
  569. int x2 = luaL_checkinteger(L, 3);
  570. int y2 = luaL_checkinteger(L, 4);
  571. int colored = luaL_optinteger(L, 5, 0);
  572. Paint_DrawLine(&paint, x, y, x2, y2, colored);
  573. return 0;
  574. }
  575. /**
  576. 缓冲区绘制矩形
  577. @api eink.rect(x, y, x2, y2, colored, fill)
  578. @int 左上顶点x坐标
  579. @int 左上顶点y坐标
  580. @int 右下顶点x坐标
  581. @int 右下顶点y坐标
  582. @int 默认是0
  583. @int 是否填充,默认是0,不填充
  584. @return nil 无返回值
  585. @usage
  586. eink.rect(0, 0, 10, 20)
  587. eink.rect(0, 0, 10, 20, 1) -- Filled
  588. */
  589. static int l_eink_rect(lua_State *L)
  590. {
  591. int x = luaL_checkinteger(L, 1);
  592. int y = luaL_checkinteger(L, 2);
  593. int x2 = luaL_checkinteger(L, 3);
  594. int y2 = luaL_checkinteger(L, 4);
  595. int colored = luaL_optinteger(L, 5, 0);
  596. int fill = luaL_optinteger(L, 6, 0);
  597. if(fill)
  598. Paint_DrawFilledRectangle(&paint, x, y, x2, y2, colored);
  599. else
  600. Paint_DrawRectangle(&paint, x, y, x2, y2, colored);
  601. return 0;
  602. }
  603. /**
  604. 缓冲区绘制圆形
  605. @api eink.circle(x, y, radius, colored, fill)
  606. @int 圆心x坐标
  607. @int 圆心y坐标
  608. @int 半径
  609. @int 默认是0
  610. @int 是否填充,默认是0,不填充
  611. @return nil 无返回值
  612. @usage
  613. eink.circle(0, 0, 10)
  614. eink.circle(0, 0, 10, 1, 1) -- Filled
  615. */
  616. static int l_eink_circle(lua_State *L)
  617. {
  618. int x = luaL_checkinteger(L, 1);
  619. int y = luaL_checkinteger(L, 2);
  620. int radius = luaL_checkinteger(L, 3);
  621. int colored = luaL_optinteger(L, 4, 0);
  622. int fill = luaL_optinteger(L, 5, 0);
  623. if(fill)
  624. Paint_DrawFilledCircle(&paint, x, y, radius, colored);
  625. else
  626. Paint_DrawCircle(&paint, x, y, radius, colored);
  627. return 0;
  628. }
  629. /**
  630. 缓冲区绘制QRCode
  631. @api eink.qrcode(x, y, str, version)
  632. @int x坐标
  633. @int y坐标
  634. @string 二维码的内容
  635. @int 二维码版本号
  636. @return nil 无返回值
  637. */
  638. static int l_eink_qrcode(lua_State *L)
  639. {
  640. size_t len;
  641. int x = luaL_checkinteger(L, 1);
  642. int y = luaL_checkinteger(L, 2);
  643. const char* str = luaL_checklstring(L, 3, &len);
  644. int version = luaL_checkinteger(L, 4);
  645. // Create the QR code
  646. QRCode qrcode;
  647. uint8_t qrcodeData[qrcode_getBufferSize(version)];
  648. qrcode_initText(&qrcode, qrcodeData, version, 0, str);
  649. for(int i = 0; i < qrcode.size; i++)
  650. {
  651. for (int j = 0; j < qrcode.size; j++)
  652. {
  653. qrcode_getModule(&qrcode, j, i) ? Paint_DrawPixel(&paint, x+j, y+i, COLORED) : Paint_DrawPixel(&paint, x+j, y+i, UNCOLORED);
  654. }
  655. }
  656. return 0;
  657. }
  658. /**
  659. 缓冲区绘制电池
  660. @api eink.bat(x, y, bat)
  661. @int x坐标
  662. @int y坐标
  663. @int 电池电压,单位毫伏
  664. @return nil 无返回值
  665. */
  666. static int l_eink_bat(lua_State *L)
  667. {
  668. int x = luaL_checkinteger(L, 1);
  669. int y = luaL_checkinteger(L, 2);
  670. int bat = luaL_checkinteger(L, 3);
  671. int batnum = 0;
  672. // eink.rect(0, 3, 2, 6)
  673. // eink.rect(2, 0, 20, 9)
  674. // eink.rect(9, 1, 19, 8, 0, 1)
  675. if(bat < 4200 && bat > 4080)batnum = 100;
  676. if(bat < 4080 && bat > 4000)batnum = 90;
  677. if(bat < 4000 && bat > 3930)batnum = 80;
  678. if(bat < 3930 && bat > 3870)batnum = 70;
  679. if(bat < 3870 && bat > 3820)batnum = 60;
  680. if(bat < 3820 && bat > 3790)batnum = 50;
  681. if(bat < 3790 && bat > 3770)batnum = 40;
  682. if(bat < 3770 && bat > 3730)batnum = 30;
  683. if(bat < 3730 && bat > 3700)batnum = 20;
  684. if(bat < 3700 && bat > 3680)batnum = 15;
  685. if(bat < 3680 && bat > 3500)batnum = 10;
  686. if(bat < 3500 && bat > 2500)batnum = 5;
  687. batnum = 20 - (int)(batnum / 5) + 3;
  688. // w外框
  689. Paint_DrawRectangle(&paint, x+0, y+3, x+2, y+6, COLORED);
  690. Paint_DrawRectangle(&paint, x+2, y+0, x+23, y+9, COLORED);
  691. // 3 ~21 100 / 5
  692. Paint_DrawFilledRectangle(&paint, x+batnum, y+1, x+22, y+8, COLORED);
  693. return 0;
  694. }
  695. /**
  696. 缓冲区绘制天气图标
  697. @api eink.weather_icon(x, y, code)
  698. @int x坐标
  699. @int y坐标
  700. @int 天气代号
  701. @return nil 无返回值
  702. */
  703. static int l_eink_weather_icon(lua_State *L)
  704. {
  705. size_t len;
  706. int x = luaL_checkinteger(L, 1);
  707. int y = luaL_checkinteger(L, 2);
  708. int code = luaL_checkinteger(L, 3);
  709. const char* str = luaL_optlstring(L, 4, "nil", &len);
  710. const unsigned char * icon = gImage_999;
  711. if (strcmp(str, "xue") == 0)code = 401;
  712. if (strcmp(str, "lei") == 0)code = 302;
  713. if (strcmp(str, "shachen") == 0)code = 503;
  714. if (strcmp(str, "wu") == 0)code = 501;
  715. if (strcmp(str, "bingbao") == 0)code = 504;
  716. if (strcmp(str, "yun") == 0)code = 103;
  717. if (strcmp(str, "yu") == 0)code = 306;
  718. if (strcmp(str, "yin") == 0)code = 101;
  719. if (strcmp(str, "qing") == 0)code = 100;
  720. // xue、lei、shachen、wu、bingbao、yun、yu、yin、qing
  721. //if(code == 64)
  722. // for(int i = 0; i < 64; i++)
  723. // {
  724. // for (int j = 0; j < 8; j++)
  725. // {
  726. // for (int k = 0; k < 8; k++)
  727. // (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);
  728. // }
  729. // }
  730. switch (code)
  731. {
  732. case 100:icon = gImage_100;break;
  733. case 101:icon = gImage_101;break;
  734. case 102:icon = gImage_102;break;
  735. case 103:icon = gImage_103;break;
  736. case 104:icon = gImage_104;break;
  737. case 200:icon = gImage_200;break;
  738. case 201:icon = gImage_201;break;
  739. case 205:icon = gImage_205;break;
  740. case 208:icon = gImage_208;break;
  741. case 301:icon = gImage_301;break;
  742. case 302:icon = gImage_302;break;
  743. case 303:icon = gImage_303;break;
  744. case 304:icon = gImage_304;break;
  745. case 305:icon = gImage_305;break;
  746. case 306:icon = gImage_306;break;
  747. case 307:icon = gImage_307;break;
  748. case 308:icon = gImage_308;break;
  749. case 309:icon = gImage_309;break;
  750. case 310:icon = gImage_310;break;
  751. case 311:icon = gImage_311;break;
  752. case 312:icon = gImage_312;break;
  753. case 313:icon = gImage_313;break;
  754. case 400:icon = gImage_400;break;
  755. case 401:icon = gImage_401;break;
  756. case 402:icon = gImage_402;break;
  757. case 403:icon = gImage_403;break;
  758. case 404:icon = gImage_404;break;
  759. case 405:icon = gImage_405;break;
  760. case 406:icon = gImage_406;break;
  761. case 407:icon = gImage_407;break;
  762. case 500:icon = gImage_500;break;
  763. case 501:icon = gImage_501;break;
  764. case 502:icon = gImage_502;break;
  765. case 503:icon = gImage_503;break;
  766. case 504:icon = gImage_504;break;
  767. case 507:icon = gImage_507;break;
  768. case 508:icon = gImage_508;break;
  769. case 900:icon = gImage_900;break;
  770. case 901:icon = gImage_901;break;
  771. case 999:icon = gImage_999;break;
  772. default:
  773. break;
  774. }
  775. for(int i = 0; i < 48; i++)
  776. {
  777. for (int j = 0; j < 6; j++)
  778. {
  779. for (int k = 0; k < 8; k++)
  780. (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);
  781. }
  782. }
  783. return 0;
  784. }
  785. /**
  786. 设置墨水屏驱动型号
  787. @api eink.model(m)
  788. @int 型号名称, 例如 eink.model(eink.MODEL_1in54_V2)
  789. @return nil 无返回值
  790. */
  791. static int l_eink_model(lua_State *L) {
  792. EPD_Model(luaL_checkinteger(L, 1));
  793. return 0;
  794. }
  795. #include "rotable.h"
  796. static const rotable_Reg reg_eink[] =
  797. {
  798. { "setup", l_eink_setup, 0},
  799. { "clear", l_eink_clear, 0},
  800. { "setWin", l_eink_setWin, 0},
  801. { "getWin", l_eink_getWin, 0},
  802. { "print", l_eink_print, 0},
  803. { "printcn", l_eink_printcn, 0},
  804. { "show", l_eink_show, 0},
  805. { "rect", l_eink_rect, 0},
  806. { "circle", l_eink_circle, 0},
  807. { "line", l_eink_line, 0},
  808. { "qrcode", l_eink_qrcode, 0},
  809. { "bat", l_eink_bat, 0},
  810. { "weather_icon", l_eink_weather_icon, 0},
  811. { "model", l_eink_model, 0},
  812. { "MODEL_1in02d", NULL, MODEL_1in02d},
  813. { "MODEL_1in54", NULL, MODEL_1in54},
  814. { "MODEL_1in54_V2", NULL, MODEL_1in54_V2},
  815. { "MODEL_1in54b", NULL, MODEL_1in54b},
  816. { "MODEL_1in54b_V2", NULL, MODEL_1in54b_V2},
  817. { "MODEL_1in54c", NULL, MODEL_1in54c},
  818. { "MODEL_1in54f", NULL, MODEL_1in54f},
  819. { "MODEL_2in54b_V3", NULL, MODEL_2in13b_V3},
  820. { "MODEL_2in7", NULL, MODEL_2in7},
  821. { "MODEL_2in7b", NULL, MODEL_2in7b},
  822. { "MODEL_2in9", NULL, MODEL_2in9},
  823. { "MODEL_2in9_V2", NULL, MODEL_2in9_V2},
  824. { "MODEL_2in9bc", NULL, MODEL_2in9bc},
  825. { "MODEL_2in9b_V3", NULL, MODEL_2in9b_V3},
  826. { "MODEL_2in9d", NULL, MODEL_2in9d},
  827. { "MODEL_2in9f", NULL, MODEL_2in9f},
  828. { "MODEL_3in7", NULL, MODEL_3in7},
  829. { NULL, NULL, 0}
  830. };
  831. LUAMOD_API int luaopen_eink( lua_State *L ){
  832. luat_newlib(L, reg_eink);
  833. return 1;
  834. }