Advertisement
Guest User

Untitled

a guest
Nov 29th, 2022
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 91.47 KB | None | 0 0
  1. /*
  2. * Modifications and additions Copyright (c) 2020, 2021 Russ Hughes
  3. *
  4. * This file licensed under the MIT License and incorporates work covered by
  5. * the following copyright and permission notice:
  6. *
  7. * The MIT License (MIT)
  8. *
  9. * Copyright (c) 2019 Ivan Belokobylskiy
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. */
  29.  
  30. #define __ST7789_VERSION__ "0.2.1"
  31. #include <stdlib.h>
  32. #include <math.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include "py/obj.h"
  36. #include "py/objstr.h"
  37. #include "py/objmodule.h"
  38. #include "py/runtime.h"
  39. #include "py/builtin.h"
  40. #include "py/mphal.h"
  41. #include "extmod/machine_spi.h"
  42.  
  43. #include "mpfile.h"
  44. #include "st7789.h"
  45. #include "jpg/tjpgd565.h"
  46. #include "png/pngle.h"
  47.  
  48. #define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
  49. #define _swap_bytes(val) ((((val) >> 8) & 0x00FF) | (((val) << 8) & 0xFF00))
  50.  
  51. #define ABS(N) (((N) < 0) ? (-(N)) : (N))
  52. #define mp_hal_delay_ms(delay) (mp_hal_delay_us(delay * 1000))
  53.  
  54. #define CS_LOW() \
  55. { \
  56. if (self->cs) { \
  57. mp_hal_pin_write(self->cs, 0); \
  58. } \
  59. }
  60.  
  61. #define CS_HIGH() \
  62. { \
  63. if (self->cs) { \
  64. mp_hal_pin_write(self->cs, 1); \
  65. } \
  66. }
  67.  
  68. #define DC_LOW() (mp_hal_pin_write(self->dc, 0))
  69. #define DC_HIGH() (mp_hal_pin_write(self->dc, 1))
  70.  
  71. #define RESET_LOW() \
  72. { \
  73. if (self->reset) \
  74. mp_hal_pin_write(self->reset, 0); \
  75. }
  76.  
  77. #define RESET_HIGH() \
  78. { \
  79. if (self->reset) \
  80. mp_hal_pin_write(self->reset, 1); \
  81. }
  82.  
  83. //
  84. // Default st7789 and st7735 display orientation tables
  85. // can be overridden during init(), madctl values
  86. // will be combined with color_mode
  87. //
  88.  
  89. // { madctl, width, height, colstart, rowstart }
  90.  
  91. st7789_rotation_t ORIENTATIONS_240x320[4] = {
  92. {0x00, 240, 320, 0, 0},
  93. {0x60, 320, 240, 0, 0},
  94. {0xc0, 240, 320, 0, 0},
  95. {0xa0, 320, 240, 0, 0}
  96. };
  97.  
  98. st7789_rotation_t ORIENTATIONS_170x320[4] = {
  99. {0x00, 170, 320, 35, 0},
  100. {0x60, 320, 170, 0, 35},
  101. {0xc0, 170, 320, 35, 0},
  102. {0xa0, 320, 170, 0, 35}
  103. };
  104.  
  105. st7789_rotation_t ORIENTATIONS_240x240[4] = {
  106. {0x00, 240, 240, 0, 0},
  107. {0x60, 240, 240, 0, 0},
  108. {0xc0, 240, 240, 0, 80},
  109. {0xa0, 240, 240, 80, 0}
  110. };
  111.  
  112. st7789_rotation_t ORIENTATIONS_135x240[4] = {
  113. {0x00, 135, 240, 52, 40},
  114. {0x60, 240, 135, 40, 53},
  115. {0xc0, 135, 240, 53, 40},
  116. {0xa0, 240, 135, 40, 52}
  117. };
  118.  
  119. st7789_rotation_t ORIENTATIONS_128x160[4] = {
  120. {0x00, 128, 160, 0, 0},
  121. {0x60, 160, 128, 0, 0},
  122. {0xc0, 128, 160, 0, 0},
  123. {0xa0, 160, 128, 0, 0}
  124. };
  125.  
  126. st7789_rotation_t ORIENTATIONS_80x160[4] = {
  127. {0x00, 80, 160, 26, 1},
  128. {0x60, 160, 80, 1, 26},
  129. {0xc0, 80, 160, 26, 1},
  130. {0xa0, 160, 80, 1, 26}
  131. };
  132.  
  133. st7789_rotation_t ORIENTATIONS_128x128[4] = {
  134. {0x00, 128, 128, 2, 1},
  135. {0x60, 128, 128, 1, 2},
  136. {0xc0, 128, 128, 2, 3},
  137. {0xa0, 128, 128, 3, 2}
  138. };
  139.  
  140. STATIC void write_spi(mp_obj_base_t *spi_obj, const uint8_t *buf, int len) {
  141. #ifdef MP_OBJ_TYPE_GET_SLOT
  142. mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(spi_obj->type, protocol);
  143. #else
  144. mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)spi_obj->type->protocol;
  145. #endif
  146. spi_p->transfer(spi_obj, len, buf, NULL);
  147. }
  148.  
  149. STATIC void st7789_ST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
  150. (void)kind;
  151. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  152. mp_printf(print, "<ST7789 width=%u, height=%u, spi=%p>", self->width, self->height, self->spi_obj);
  153. }
  154.  
  155. STATIC void write_cmd(st7789_ST7789_obj_t *self, uint8_t cmd, const uint8_t *data, int len) {
  156. CS_LOW()
  157. if (cmd) {
  158. DC_LOW();
  159. write_spi(self->spi_obj, &cmd, 1);
  160. }
  161. if (len > 0) {
  162. DC_HIGH();
  163. write_spi(self->spi_obj, data, len);
  164. }
  165. CS_HIGH()
  166. }
  167.  
  168. STATIC void set_window(st7789_ST7789_obj_t *self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
  169. if (x0 > x1 || x1 >= self->width) {
  170. return;
  171. }
  172. if (y0 > y1 || y1 >= self->height) {
  173. return;
  174. }
  175.  
  176. if (self->bounding) {
  177. if (x0 < self->min_x) {
  178. self->min_x = x0;
  179. }
  180. if (x1 > self->max_x) {
  181. self->max_x = x1;
  182. }
  183. if (y0 < self->min_y) {
  184. self->min_y = y0;
  185. }
  186. if (y1 > self->max_y) {
  187. self->max_y = y1;
  188. }
  189. }
  190.  
  191. uint8_t bufx[4] = {(x0 + self->colstart) >> 8, (x0 + self->colstart) & 0xFF, (x1 + self->colstart) >> 8, (x1 + self->colstart) & 0xFF};
  192. uint8_t bufy[4] = {(y0 + self->rowstart) >> 8, (y0 + self->rowstart) & 0xFF, (y1 + self->rowstart) >> 8, (y1 + self->rowstart) & 0xFF};
  193. write_cmd(self, ST7789_CASET, bufx, 4);
  194. write_cmd(self, ST7789_RASET, bufy, 4);
  195. write_cmd(self, ST7789_RAMWR, NULL, 0);
  196. }
  197.  
  198. STATIC void fill_color_buffer(mp_obj_base_t *spi_obj, uint16_t color, int length) {
  199. const int buffer_pixel_size = 128;
  200. int chunks = length / buffer_pixel_size;
  201. int rest = length % buffer_pixel_size;
  202. uint16_t color_swapped = _swap_bytes(color);
  203. uint16_t buffer[buffer_pixel_size]; // 128 pixels
  204.  
  205. // fill buffer with color data
  206.  
  207. for (int i = 0; i < length && i < buffer_pixel_size; i++) {
  208. buffer[i] = color_swapped;
  209. }
  210. if (chunks) {
  211. for (int j = 0; j < chunks; j++) {
  212. write_spi(spi_obj, (uint8_t *)buffer, buffer_pixel_size * 2);
  213. }
  214. }
  215. if (rest) {
  216. write_spi(spi_obj, (uint8_t *)buffer, rest * 2);
  217. }
  218. }
  219.  
  220. int mod(int x, int m) {
  221. int r = x % m;
  222. return (r < 0) ? r + m : r;
  223. }
  224.  
  225. void draw_pixel(st7789_ST7789_obj_t *self, int16_t x, int16_t y, uint16_t color) {
  226. if ((self->options & OPTIONS_WRAP)) {
  227. if ((self->options & OPTIONS_WRAP_H) && ((x >= self->width) || (x < 0))) {
  228. x = mod(x, self->width);
  229. }
  230. if ((self->options & OPTIONS_WRAP_V) && ((y >= self->height) || (y < 0))) {
  231. y = mod(y, self->height);
  232. }
  233. }
  234.  
  235. if ((x < self->width) && (y < self->height) && (x >= 0) && (y >= 0)) {
  236. uint8_t hi = color >> 8, lo = color & 0xff;
  237. set_window(self, x, y, x, y);
  238. DC_HIGH();
  239. CS_LOW();
  240. write_spi(self->spi_obj, &hi, 1);
  241. write_spi(self->spi_obj, &lo, 1);
  242. CS_HIGH();
  243. }
  244. }
  245.  
  246. void fast_hline(st7789_ST7789_obj_t *self, int16_t x, int16_t y, int16_t w, uint16_t color) {
  247. if ((self->options & OPTIONS_WRAP) == 0) {
  248. if (y >= 0 && self->width > x && self->height > y) {
  249. if (0 > x) {
  250. w += x;
  251. x = 0;
  252. }
  253.  
  254. if (self->width < x + w) {
  255. w = self->width - x;
  256. }
  257.  
  258. if (w > 0) {
  259. int16_t x2 = x + w - 1;
  260. set_window(self, x, y, x2, y);
  261. DC_HIGH();
  262. CS_LOW();
  263. fill_color_buffer(self->spi_obj, color, w);
  264. CS_HIGH();
  265. }
  266. }
  267. } else {
  268. for (int d = 0; d < w; d++) {
  269. draw_pixel(self, x + d, y, color);
  270. }
  271. }
  272. }
  273.  
  274. STATIC void fast_vline(st7789_ST7789_obj_t *self, int16_t x, int16_t y, int16_t h, uint16_t color) {
  275. if ((self->options & OPTIONS_WRAP) == 0) {
  276. if (x >= 0 && self->width > x && self->height > y) {
  277. if (0 > y) {
  278. h += y;
  279. y = 0;
  280. }
  281.  
  282. if (self->height < y + h) {
  283. h = self->height - y;
  284. }
  285.  
  286. if (h > 0) {
  287. int16_t y2 = y + h - 1;
  288.  
  289. set_window(self, x, y, x, y2);
  290. DC_HIGH();
  291. CS_LOW();
  292. fill_color_buffer(self->spi_obj, color, h);
  293. CS_HIGH();
  294. }
  295. }
  296. } else {
  297. for (int d = 0; d < h; d++) {
  298. draw_pixel(self, x, y + d, color);
  299. }
  300. }
  301. }
  302.  
  303. STATIC mp_obj_t st7789_ST7789_hard_reset(mp_obj_t self_in) {
  304. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  305.  
  306. CS_LOW();
  307. RESET_HIGH();
  308. mp_hal_delay_ms(50);
  309. RESET_LOW();
  310. mp_hal_delay_ms(50);
  311. RESET_HIGH();
  312. mp_hal_delay_ms(150);
  313. CS_HIGH();
  314. return mp_const_none;
  315. }
  316. STATIC MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_hard_reset_obj, st7789_ST7789_hard_reset);
  317.  
  318. STATIC mp_obj_t st7789_ST7789_soft_reset(mp_obj_t self_in) {
  319. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  320.  
  321. write_cmd(self, ST7789_SWRESET, NULL, 0);
  322. mp_hal_delay_ms(150);
  323. return mp_const_none;
  324. }
  325. STATIC MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_soft_reset_obj, st7789_ST7789_soft_reset);
  326.  
  327. STATIC mp_obj_t st7789_ST7789_sleep_mode(mp_obj_t self_in, mp_obj_t value) {
  328. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  329. if (mp_obj_is_true(value)) {
  330. write_cmd(self, ST7789_SLPIN, NULL, 0);
  331. } else {
  332. write_cmd(self, ST7789_SLPOUT, NULL, 0);
  333. }
  334. return mp_const_none;
  335. }
  336. STATIC MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_sleep_mode_obj, st7789_ST7789_sleep_mode);
  337.  
  338. STATIC mp_obj_t st7789_ST7789_inversion_mode(mp_obj_t self_in, mp_obj_t value) {
  339. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  340.  
  341. self->inversion = mp_obj_is_true(value);
  342. if (self->inversion) {
  343. write_cmd(self, ST7789_INVON, NULL, 0);
  344. } else {
  345. write_cmd(self, ST7789_INVOFF, NULL, 0);
  346. }
  347. return mp_const_none;
  348. }
  349. STATIC MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_inversion_mode_obj, st7789_ST7789_inversion_mode);
  350.  
  351. STATIC mp_obj_t st7789_ST7789_fill_rect(size_t n_args, const mp_obj_t *args) {
  352. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  353. mp_int_t x = mp_obj_get_int(args[1]);
  354. mp_int_t y = mp_obj_get_int(args[2]);
  355. mp_int_t w = mp_obj_get_int(args[3]);
  356. mp_int_t h = mp_obj_get_int(args[4]);
  357. mp_int_t color = mp_obj_get_int(args[5]);
  358.  
  359. uint16_t right = x + w - 1;
  360. uint16_t bottom = y + h - 1;
  361.  
  362. if (x < self->width && y < self->height) {
  363. if (right > self->width) {
  364. right = self->width;
  365. }
  366.  
  367. if (bottom > self->height) {
  368. bottom = self->height;
  369. }
  370.  
  371. set_window(self, x, y, right, bottom);
  372. DC_HIGH();
  373. CS_LOW();
  374. fill_color_buffer(self->spi_obj, color, w * h);
  375. CS_HIGH();
  376. }
  377. return mp_const_none;
  378. }
  379. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_fill_rect_obj, 6, 6, st7789_ST7789_fill_rect);
  380.  
  381. STATIC mp_obj_t st7789_ST7789_fill(mp_obj_t self_in, mp_obj_t _color) {
  382. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  383. mp_int_t color = mp_obj_get_int(_color);
  384.  
  385. set_window(self, 0, 0, self->width - 1, self->height - 1);
  386. DC_HIGH();
  387. CS_LOW();
  388. fill_color_buffer(self->spi_obj, color, self->width * self->height);
  389. CS_HIGH();
  390.  
  391. return mp_const_none;
  392. }
  393. STATIC MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_fill_obj, st7789_ST7789_fill);
  394.  
  395. STATIC mp_obj_t st7789_ST7789_pixel(size_t n_args, const mp_obj_t *args) {
  396. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  397. mp_int_t x = mp_obj_get_int(args[1]);
  398. mp_int_t y = mp_obj_get_int(args[2]);
  399. mp_int_t color = mp_obj_get_int(args[3]);
  400.  
  401. draw_pixel(self, x, y, color);
  402.  
  403. return mp_const_none;
  404. }
  405. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_pixel_obj, 4, 4, st7789_ST7789_pixel);
  406.  
  407. STATIC void line(st7789_ST7789_obj_t *self, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t color) {
  408. bool steep = ABS(y1 - y0) > ABS(x1 - x0);
  409. if (steep) {
  410. _swap_int16_t(x0, y0);
  411. _swap_int16_t(x1, y1);
  412. }
  413.  
  414. if (x0 > x1) {
  415. _swap_int16_t(x0, x1);
  416. _swap_int16_t(y0, y1);
  417. }
  418.  
  419. int16_t dx = x1 - x0, dy = ABS(y1 - y0);
  420. int16_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0;
  421.  
  422. if (y0 < y1) {
  423. ystep = 1;
  424. }
  425.  
  426. // Split into steep and not steep for FastH/V separation
  427. if (steep) {
  428. for (; x0 <= x1; x0++) {
  429. dlen++;
  430. err -= dy;
  431. if (err < 0) {
  432. err += dx;
  433. if (dlen == 1) {
  434. draw_pixel(self, y0, xs, color);
  435. } else {
  436. fast_vline(self, y0, xs, dlen, color);
  437. }
  438. dlen = 0;
  439. y0 += ystep;
  440. xs = x0 + 1;
  441. }
  442. }
  443. if (dlen) {
  444. fast_vline(self, y0, xs, dlen, color);
  445. }
  446. } else {
  447. for (; x0 <= x1; x0++) {
  448. dlen++;
  449. err -= dy;
  450. if (err < 0) {
  451. err += dx;
  452. if (dlen == 1) {
  453. draw_pixel(self, xs, y0, color);
  454. } else {
  455. fast_hline(self, xs, y0, dlen, color);
  456. }
  457. dlen = 0;
  458. y0 += ystep;
  459. xs = x0 + 1;
  460. }
  461. }
  462. if (dlen) {
  463. fast_hline(self, xs, y0, dlen, color);
  464. }
  465. }
  466. }
  467.  
  468. STATIC mp_obj_t st7789_ST7789_line(size_t n_args, const mp_obj_t *args) {
  469. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  470. mp_int_t x0 = mp_obj_get_int(args[1]);
  471. mp_int_t y0 = mp_obj_get_int(args[2]);
  472. mp_int_t x1 = mp_obj_get_int(args[3]);
  473. mp_int_t y1 = mp_obj_get_int(args[4]);
  474. mp_int_t color = mp_obj_get_int(args[5]);
  475.  
  476. line(self, x0, y0, x1, y1, color);
  477.  
  478. return mp_const_none;
  479. }
  480. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_line_obj, 6, 6, st7789_ST7789_line);
  481.  
  482. STATIC mp_obj_t st7789_ST7789_blit_buffer(size_t n_args, const mp_obj_t *args) {
  483. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  484. mp_buffer_info_t buf_info;
  485. mp_get_buffer_raise(args[1], &buf_info, MP_BUFFER_READ);
  486. mp_int_t x = mp_obj_get_int(args[2]);
  487. mp_int_t y = mp_obj_get_int(args[3]);
  488. mp_int_t w = mp_obj_get_int(args[4]);
  489. mp_int_t h = mp_obj_get_int(args[5]);
  490.  
  491. set_window(self, x, y, x + w - 1, y + h - 1);
  492. DC_HIGH();
  493. CS_LOW();
  494.  
  495. const int buf_size = 256;
  496. int limit = MIN(buf_info.len, w * h * 2);
  497. int chunks = limit / buf_size;
  498. int rest = limit % buf_size;
  499. int i = 0;
  500. for (; i < chunks; i++) {
  501. write_spi(self->spi_obj, (const uint8_t *)buf_info.buf + i * buf_size, buf_size);
  502. }
  503. if (rest) {
  504. write_spi(self->spi_obj, (const uint8_t *)buf_info.buf + i * buf_size, rest);
  505. }
  506. CS_HIGH();
  507.  
  508. return mp_const_none;
  509. }
  510. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_blit_buffer_obj, 6, 6, st7789_ST7789_blit_buffer);
  511.  
  512. STATIC mp_obj_t st7789_ST7789_draw(size_t n_args, const mp_obj_t *args) {
  513. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  514. char single_char_s[] = {0, 0};
  515. const char *s;
  516.  
  517. mp_obj_module_t *hershey = MP_OBJ_TO_PTR(args[1]);
  518.  
  519. if (mp_obj_is_int(args[2])) {
  520. mp_int_t c = mp_obj_get_int(args[2]);
  521. single_char_s[0] = c & 0xff;
  522. s = single_char_s;
  523. } else {
  524. s = mp_obj_str_get_str(args[2]);
  525. }
  526.  
  527. mp_int_t x = mp_obj_get_int(args[3]);
  528. mp_int_t y = mp_obj_get_int(args[4]);
  529.  
  530. mp_int_t color = (n_args > 5) ? mp_obj_get_int(args[5]) : WHITE;
  531.  
  532. mp_float_t scale = 1.0;
  533. if (n_args > 6) {
  534. if (mp_obj_is_float(args[6])) {
  535. scale = mp_obj_float_get(args[6]);
  536. }
  537. if (mp_obj_is_int(args[6])) {
  538. scale = (mp_float_t)mp_obj_get_int(args[6]);
  539. }
  540. }
  541.  
  542. mp_obj_dict_t *dict = MP_OBJ_TO_PTR(hershey->globals);
  543. mp_obj_t *index_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_INDEX));
  544. mp_buffer_info_t index_bufinfo;
  545. mp_get_buffer_raise(index_data_buff, &index_bufinfo, MP_BUFFER_READ);
  546. uint8_t *index = index_bufinfo.buf;
  547.  
  548. mp_obj_t *font_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_FONT));
  549. mp_buffer_info_t font_bufinfo;
  550. mp_get_buffer_raise(font_data_buff, &font_bufinfo, MP_BUFFER_READ);
  551. int8_t *font = font_bufinfo.buf;
  552.  
  553. int16_t from_x = x;
  554. int16_t from_y = y;
  555. int16_t to_x = x;
  556. int16_t to_y = y;
  557. int16_t pos_x = x;
  558. int16_t pos_y = y;
  559. bool penup = true;
  560. char c;
  561. int16_t ii;
  562.  
  563. while ((c = *s++)) {
  564. if (c >= 32 && c <= 127) {
  565. ii = (c - 32) * 2;
  566.  
  567. int16_t offset = index[ii] | (index[ii + 1] << 8);
  568. int16_t length = font[offset++];
  569. int16_t left = (int)(scale * (font[offset++] - 0x52) + 0.5);
  570. int16_t right = (int)(scale * (font[offset++] - 0x52) + 0.5);
  571. int16_t width = right - left;
  572.  
  573. if (length) {
  574. int16_t i;
  575. for (i = 0; i < length; i++) {
  576. if (font[offset] == ' ') {
  577. offset += 2;
  578. penup = true;
  579. continue;
  580. }
  581.  
  582. int16_t vector_x = (int)(scale * (font[offset++] - 0x52) + 0.5);
  583. int16_t vector_y = (int)(scale * (font[offset++] - 0x52) + 0.5);
  584.  
  585. if (!i || penup) {
  586. from_x = pos_x + vector_x - left;
  587. from_y = pos_y + vector_y;
  588. } else {
  589. to_x = pos_x + vector_x - left;
  590. to_y = pos_y + vector_y;
  591.  
  592. line(self, from_x, from_y, to_x, to_y, color);
  593. from_x = to_x;
  594. from_y = to_y;
  595. }
  596. penup = false;
  597. }
  598. }
  599. pos_x += width;
  600. }
  601. }
  602.  
  603. return mp_const_none;
  604. }
  605. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_draw_obj, 5, 7, st7789_ST7789_draw);
  606.  
  607. STATIC mp_obj_t st7789_ST7789_draw_len(size_t n_args, const mp_obj_t *args) {
  608. char single_char_s[] = {0, 0};
  609. const char *s;
  610.  
  611. mp_obj_module_t *hershey = MP_OBJ_TO_PTR(args[1]);
  612.  
  613. if (mp_obj_is_int(args[2])) {
  614. mp_int_t c = mp_obj_get_int(args[2]);
  615. single_char_s[0] = c & 0xff;
  616. s = single_char_s;
  617. } else {
  618. s = mp_obj_str_get_str(args[2]);
  619. }
  620.  
  621. mp_float_t scale = 1.0;
  622. if (n_args > 3) {
  623. if (mp_obj_is_float(args[3])) {
  624. scale = mp_obj_float_get(args[3]);
  625. }
  626. if (mp_obj_is_int(args[3])) {
  627. scale = (mp_float_t)mp_obj_get_int(args[3]);
  628. }
  629. }
  630.  
  631. mp_obj_dict_t *dict = MP_OBJ_TO_PTR(hershey->globals);
  632. mp_obj_t *index_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_INDEX));
  633. mp_buffer_info_t index_bufinfo;
  634. mp_get_buffer_raise(index_data_buff, &index_bufinfo, MP_BUFFER_READ);
  635. uint8_t *index = index_bufinfo.buf;
  636.  
  637. mp_obj_t *font_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_FONT));
  638. mp_buffer_info_t font_bufinfo;
  639. mp_get_buffer_raise(font_data_buff, &font_bufinfo, MP_BUFFER_READ);
  640. int8_t *font = font_bufinfo.buf;
  641.  
  642. int16_t print_width = 0;
  643. char c;
  644. int16_t ii;
  645.  
  646. while ((c = *s++)) {
  647. if (c >= 32 && c <= 127) {
  648. ii = (c - 32) * 2;
  649.  
  650. int16_t offset = (index[ii] | (index[ii + 1] << 8)) + 1;
  651. int16_t left = font[offset++] - 0x52;
  652. int16_t right = font[offset++] - 0x52;
  653. int16_t width = right - left;
  654. print_width += width;
  655. }
  656. }
  657.  
  658. return mp_obj_new_int((int)(print_width * scale + 0.5));
  659. }
  660. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_draw_len_obj, 3, 4, st7789_ST7789_draw_len);
  661.  
  662. STATIC uint32_t bs_bit = 0;
  663. uint8_t *bitmap_data = NULL;
  664.  
  665. STATIC uint8_t get_color(uint8_t bpp) {
  666. uint8_t color = 0;
  667. int i;
  668.  
  669. for (i = 0; i < bpp; i++) {
  670. color <<= 1;
  671. color |= (bitmap_data[bs_bit / 8] & 1 << (7 - (bs_bit % 8))) > 0;
  672. bs_bit++;
  673. }
  674. return color;
  675. }
  676.  
  677. STATIC mp_obj_t dict_lookup(mp_obj_t self_in, mp_obj_t index) {
  678. mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
  679. mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);
  680. if (elem == NULL) {
  681. return NULL;
  682. } else {
  683. return elem->value;
  684. }
  685. }
  686.  
  687. STATIC mp_obj_t st7789_ST7789_write_len(size_t n_args, const mp_obj_t *args) {
  688. mp_obj_module_t *font = MP_OBJ_TO_PTR(args[1]);
  689. mp_obj_dict_t *dict = MP_OBJ_TO_PTR(font->globals);
  690. mp_obj_t widths_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_WIDTHS));
  691. mp_buffer_info_t widths_bufinfo;
  692. mp_get_buffer_raise(widths_data_buff, &widths_bufinfo, MP_BUFFER_READ);
  693. const uint8_t *widths_data = widths_bufinfo.buf;
  694.  
  695. uint16_t print_width = 0;
  696.  
  697. mp_obj_t map_obj = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_MAP));
  698. GET_STR_DATA_LEN(map_obj, map_data, map_len);
  699. GET_STR_DATA_LEN(args[2], str_data, str_len);
  700. const byte *s = str_data, *top = str_data + str_len;
  701.  
  702. while (s < top) {
  703. unichar ch;
  704. ch = utf8_get_char(s);
  705. s = utf8_next_char(s);
  706.  
  707. const byte *map_s = map_data, *map_top = map_data + map_len;
  708. uint16_t char_index = 0;
  709.  
  710. while (map_s < map_top) {
  711. unichar map_ch;
  712. map_ch = utf8_get_char(map_s);
  713. map_s = utf8_next_char(map_s);
  714.  
  715. if (ch == map_ch) {
  716. print_width += widths_data[char_index];
  717. break;
  718. }
  719. char_index++;
  720. }
  721. }
  722.  
  723. return mp_obj_new_int(print_width);
  724. }
  725. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_write_len_obj, 3, 3, st7789_ST7789_write_len);
  726.  
  727. //
  728. // write(font_module, s, x, y[, fg, bg, background_tuple, fill])
  729. // background_tuple (bitmap_buffer, width, height)
  730. //
  731.  
  732. STATIC mp_obj_t st7789_ST7789_write(size_t n_args, const mp_obj_t *args) {
  733. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  734. mp_obj_module_t *font = MP_OBJ_TO_PTR(args[1]);
  735.  
  736. mp_int_t x = mp_obj_get_int(args[3]);
  737. mp_int_t y = mp_obj_get_int(args[4]);
  738. mp_int_t fg_color;
  739. mp_int_t bg_color;
  740.  
  741. fg_color = (n_args > 5) ? _swap_bytes(mp_obj_get_int(args[5])) : _swap_bytes(WHITE);
  742. bg_color = (n_args > 6) ? _swap_bytes(mp_obj_get_int(args[6])) : _swap_bytes(BLACK);
  743.  
  744. mp_obj_t *tuple_data = NULL;
  745. size_t tuple_len = 0;
  746.  
  747. mp_buffer_info_t background_bufinfo;
  748. uint16_t background_width = 0;
  749. uint16_t background_height = 0;
  750. uint16_t *background_data = NULL;
  751.  
  752. if (n_args > 7) {
  753. mp_obj_tuple_get(args[7], &tuple_len, &tuple_data);
  754. if (tuple_len > 2) {
  755. mp_get_buffer_raise(tuple_data[0], &background_bufinfo, MP_BUFFER_READ);
  756. background_data = background_bufinfo.buf;
  757. background_width = mp_obj_get_int(tuple_data[1]);
  758. background_height = mp_obj_get_int(tuple_data[2]);
  759. }
  760. }
  761.  
  762. bool fill = (n_args > 8) ? mp_obj_is_true(args[8]) : false;
  763.  
  764. mp_obj_dict_t *dict = MP_OBJ_TO_PTR(font->globals);
  765. const uint8_t bpp = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_BPP)));
  766. const uint8_t height = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_HEIGHT)));
  767. const uint8_t offset_width = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_OFFSET_WIDTH)));
  768. const uint8_t max_width = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_MAX_WIDTH)));
  769.  
  770. mp_obj_t widths_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_WIDTHS));
  771. mp_buffer_info_t widths_bufinfo;
  772. mp_get_buffer_raise(widths_data_buff, &widths_bufinfo, MP_BUFFER_READ);
  773. const uint8_t *widths_data = widths_bufinfo.buf;
  774.  
  775. mp_obj_t offsets_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_OFFSETS));
  776. mp_buffer_info_t offsets_bufinfo;
  777. mp_get_buffer_raise(offsets_data_buff, &offsets_bufinfo, MP_BUFFER_READ);
  778. const uint8_t *offsets_data = offsets_bufinfo.buf;
  779.  
  780. mp_obj_t bitmaps_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_BITMAPS));
  781. mp_buffer_info_t bitmaps_bufinfo;
  782. mp_get_buffer_raise(bitmaps_data_buff, &bitmaps_bufinfo, MP_BUFFER_READ);
  783. bitmap_data = bitmaps_bufinfo.buf;
  784.  
  785. // allocate buffer large enough the the widest character in the font
  786. // if a buffer was not specified during the driver init.
  787.  
  788. size_t buf_size = max_width * height * 2;
  789. if (self->buffer_size == 0) {
  790. self->i2c_buffer = m_malloc(buf_size);
  791. }
  792.  
  793. // if fill is set, and background bitmap data is available copy the background
  794. // bitmap data into the buffer. The background buffer must be the size of the
  795. // widest character in the font.
  796.  
  797. if (fill && background_data && self->i2c_buffer) {
  798. memcpy(self->i2c_buffer, background_data, background_width * background_height * 2);
  799. }
  800.  
  801. uint16_t print_width = 0;
  802. mp_obj_t map_obj = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_MAP));
  803. GET_STR_DATA_LEN(map_obj, map_data, map_len);
  804. GET_STR_DATA_LEN(args[2], str_data, str_len);
  805. const byte *s = str_data, *top = str_data + str_len;
  806. while (s < top) {
  807. unichar ch;
  808. ch = utf8_get_char(s);
  809. s = utf8_next_char(s);
  810.  
  811. const byte *map_s = map_data, *map_top = map_data + map_len;
  812. uint16_t char_index = 0;
  813.  
  814. while (map_s < map_top) {
  815. unichar map_ch;
  816. map_ch = utf8_get_char(map_s);
  817. map_s = utf8_next_char(map_s);
  818.  
  819. if (ch == map_ch) {
  820. uint8_t width = widths_data[char_index];
  821.  
  822. bs_bit = 0;
  823. switch (offset_width) {
  824. case 1:
  825. bs_bit = offsets_data[char_index * offset_width];
  826. break;
  827.  
  828. case 2:
  829. bs_bit = (offsets_data[char_index * offset_width] << 8) +
  830. (offsets_data[char_index * offset_width + 1]);
  831. break;
  832.  
  833. case 3:
  834. bs_bit = (offsets_data[char_index * offset_width] << 16) +
  835. (offsets_data[char_index * offset_width + 1] << 8) +
  836. (offsets_data[char_index * offset_width + 2]);
  837. break;
  838. }
  839.  
  840. uint16_t buffer_width = (fill) ? max_width : width;
  841.  
  842. uint16_t color = 0;
  843. for (uint16_t yy = 0; yy < height; yy++) {
  844. for (uint16_t xx = 0; xx < width; xx++) {
  845. if (background_data && (xx <= background_width && yy <= background_height)) {
  846. if (get_color(bpp) == bg_color) {
  847. color = background_data[(yy * background_width + xx)];
  848. } else {
  849. color = fg_color;
  850. }
  851. } else {
  852. color = get_color(bpp) ? fg_color : bg_color;
  853. }
  854. self->i2c_buffer[yy * buffer_width + xx] = color;
  855. }
  856. }
  857.  
  858. uint32_t data_size = buffer_width * height * 2;
  859. uint16_t x2 = x + buffer_width - 1;
  860. uint16_t y2 = y + height - 1;
  861. if (x2 < self->width) {
  862. set_window(self, x, y, x2, y2);
  863. DC_HIGH();
  864. CS_LOW();
  865. write_spi(self->spi_obj, (uint8_t *)self->i2c_buffer, data_size);
  866. CS_HIGH();
  867. print_width += width;
  868. }
  869. x += width;
  870. break;
  871. }
  872. char_index++;
  873. }
  874. }
  875.  
  876. if (self->buffer_size == 0) {
  877. m_free(self->i2c_buffer);
  878. }
  879.  
  880. return mp_obj_new_int(print_width);
  881. }
  882. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_write_obj, 5, 9, st7789_ST7789_write);
  883.  
  884. STATIC mp_obj_t st7789_ST7789_bitmap(size_t n_args, const mp_obj_t *args) {
  885. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  886.  
  887. mp_obj_module_t *bitmap = MP_OBJ_TO_PTR(args[1]);
  888. mp_int_t x = mp_obj_get_int(args[2]);
  889. mp_int_t y = mp_obj_get_int(args[3]);
  890.  
  891. mp_int_t idx;
  892. if (n_args > 4) {
  893. idx = mp_obj_get_int(args[4]);
  894. } else {
  895. idx = 0;
  896. }
  897.  
  898. mp_obj_dict_t *dict = MP_OBJ_TO_PTR(bitmap->globals);
  899. const uint16_t height = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_HEIGHT)));
  900. const uint16_t width = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_WIDTH)));
  901. uint16_t bitmaps = 0;
  902. const uint8_t bpp = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_BPP)));
  903. mp_obj_t *palette_arg = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_PALETTE));
  904. mp_obj_t *palette = NULL;
  905. size_t palette_len = 0;
  906.  
  907. mp_map_elem_t *elem = dict_lookup(bitmap->globals, MP_OBJ_NEW_QSTR(MP_QSTR_BITMAPS));
  908. if (elem) {
  909. bitmaps = mp_obj_get_int(elem);
  910. }
  911.  
  912. mp_obj_get_array(palette_arg, &palette_len, &palette);
  913.  
  914. mp_obj_t *bitmap_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_BITMAP));
  915. mp_buffer_info_t bufinfo;
  916.  
  917. mp_get_buffer_raise(bitmap_data_buff, &bufinfo, MP_BUFFER_READ);
  918. bitmap_data = bufinfo.buf;
  919.  
  920. size_t buf_size = width * height * 2;
  921. if (self->buffer_size == 0) {
  922. self->i2c_buffer = m_malloc(buf_size);
  923. }
  924.  
  925. size_t ofs = 0;
  926. bs_bit = 0;
  927. if (bitmaps) {
  928. if (idx < bitmaps) {
  929. bs_bit = height * width * bpp * idx;
  930. } else {
  931. mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("index out of range"));
  932. }
  933. }
  934.  
  935. for (int yy = 0; yy < height; yy++) {
  936. for (int xx = 0; xx < width; xx++) {
  937. self->i2c_buffer[ofs++] = mp_obj_get_int(palette[get_color(bpp)]);
  938. }
  939. }
  940.  
  941. uint16_t x1 = x + width - 1;
  942. if (x1 < self->width) {
  943. set_window(self, x, y, x1, y + height - 1);
  944. DC_HIGH();
  945. CS_LOW();
  946. write_spi(self->spi_obj, (uint8_t *)self->i2c_buffer, buf_size);
  947. CS_HIGH();
  948. }
  949.  
  950. if (self->buffer_size == 0) {
  951. m_free(self->i2c_buffer);
  952. }
  953. return mp_const_none;
  954. }
  955.  
  956. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_bitmap_obj, 4, 5, st7789_ST7789_bitmap);
  957.  
  958. STATIC mp_obj_t st7789_ST7789_text(size_t n_args, const mp_obj_t *args) {
  959. char single_char_s[2] = {0, 0};
  960. const char *str;
  961.  
  962. // extract arguments
  963. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  964. mp_obj_module_t *font = MP_OBJ_TO_PTR(args[1]);
  965.  
  966. if (mp_obj_is_int(args[2])) {
  967. mp_int_t c = mp_obj_get_int(args[2]);
  968. single_char_s[0] = c & 0xff;
  969. str = single_char_s;
  970. } else {
  971. str = mp_obj_str_get_str(args[2]);
  972. }
  973.  
  974. mp_int_t x0 = mp_obj_get_int(args[3]);
  975. mp_int_t y0 = mp_obj_get_int(args[4]);
  976.  
  977. mp_obj_dict_t *dict = MP_OBJ_TO_PTR(font->globals);
  978. const uint8_t width = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_WIDTH)));
  979. const uint8_t height = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_HEIGHT)));
  980. const uint8_t first = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_FIRST)));
  981. const uint8_t last = mp_obj_get_int(mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_LAST)));
  982.  
  983. mp_obj_t font_data_buff = mp_obj_dict_get(dict, MP_OBJ_NEW_QSTR(MP_QSTR_FONT));
  984. mp_buffer_info_t bufinfo;
  985. mp_get_buffer_raise(font_data_buff, &bufinfo, MP_BUFFER_READ);
  986. const uint8_t *font_data = bufinfo.buf;
  987.  
  988. mp_int_t fg_color;
  989. mp_int_t bg_color;
  990.  
  991. if (n_args > 5) {
  992. fg_color = _swap_bytes(mp_obj_get_int(args[5]));
  993. } else {
  994. fg_color = _swap_bytes(WHITE);
  995. }
  996.  
  997. if (n_args > 6) {
  998. bg_color = _swap_bytes(mp_obj_get_int(args[6]));
  999. } else {
  1000. bg_color = _swap_bytes(BLACK);
  1001. }
  1002.  
  1003. uint8_t wide = width / 8;
  1004. size_t buf_size = width * height * 2;
  1005.  
  1006. if (self->buffer_size == 0) {
  1007. self->i2c_buffer = m_malloc(buf_size);
  1008. }
  1009.  
  1010. if (self->i2c_buffer) {
  1011. uint8_t chr;
  1012. while ((chr = *str++)) {
  1013. if (chr >= first && chr <= last) {
  1014. uint16_t buf_idx = 0;
  1015. uint16_t chr_idx = (chr - first) * (height * wide);
  1016. for (uint8_t line = 0; line < height; line++) {
  1017. for (uint8_t line_byte = 0; line_byte < wide; line_byte++) {
  1018. uint8_t chr_data = font_data[chr_idx];
  1019. for (uint8_t bit = 8; bit; bit--) {
  1020. if (chr_data >> (bit - 1) & 1) {
  1021. self->i2c_buffer[buf_idx] = fg_color;
  1022. } else {
  1023. self->i2c_buffer[buf_idx] = bg_color;
  1024. }
  1025. buf_idx++;
  1026. }
  1027. chr_idx++;
  1028. }
  1029. }
  1030. uint16_t x1 = x0 + width - 1;
  1031. if (x1 < self->width) {
  1032. set_window(self, x0, y0, x1, y0 + height - 1);
  1033. DC_HIGH();
  1034. CS_LOW();
  1035. write_spi(self->spi_obj, (uint8_t *)self->i2c_buffer, buf_size);
  1036. CS_HIGH();
  1037. }
  1038. x0 += width;
  1039. }
  1040. }
  1041. if (self->buffer_size == 0) {
  1042. m_free(self->i2c_buffer);
  1043. }
  1044. }
  1045. return mp_const_none;
  1046. }
  1047.  
  1048. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_text_obj, 5, 7, st7789_ST7789_text);
  1049.  
  1050. // 0=Portrait, 1=Landscape, 2=Reverse Portrait (180), 3=Reverse Landscape (180)
  1051.  
  1052. STATIC void set_rotation(st7789_ST7789_obj_t *self) {
  1053. uint8_t madctl_value = self->color_order;
  1054.  
  1055. if (self->rotation > self->rotations_len) {
  1056. mp_raise_msg_varg(
  1057. &mp_type_RuntimeError,
  1058. MP_ERROR_TEXT("Invalid rotation value %d > %d"), self->rotation, self->rotations_len);
  1059. }
  1060.  
  1061. st7789_rotation_t *rotations = self->rotations;
  1062. if (rotations == NULL) {
  1063. if (self->display_width == 240 && self->display_height == 320) {
  1064. rotations = ORIENTATIONS_240x320;
  1065. } else if (self->display_width == 170 && self->display_height == 320) {
  1066. rotations = ORIENTATIONS_170x320;
  1067. } else if (self->display_width == 240 && self->display_height == 240) {
  1068. rotations = ORIENTATIONS_240x240;
  1069. } else if (self->display_width == 135 && self->display_height == 240) {
  1070. rotations = ORIENTATIONS_135x240;
  1071. } else if (self->display_width == 128 && self->display_height == 160) {
  1072. rotations = ORIENTATIONS_128x160;
  1073. } else if (self->display_width == 80 && self->display_height == 160) {
  1074. rotations = ORIENTATIONS_80x160;
  1075. } else if (self->display_width == 128 && self->display_height == 128) {
  1076. rotations = ORIENTATIONS_128x128;
  1077. }
  1078. }
  1079.  
  1080. if (rotations) {
  1081. st7789_rotation_t *rotation = &rotations[self->rotation];
  1082. madctl_value |= rotation->madctl;
  1083. self->width = rotation->width;
  1084. self->height = rotation->height;
  1085. self->colstart = rotation->colstart;
  1086. self->rowstart = rotation->rowstart;
  1087. }
  1088.  
  1089. self->madctl = madctl_value & 0xff;
  1090. self->min_x = self->width;
  1091. self->min_y = self->height;
  1092. self->max_x = 0;
  1093. self->max_y = 0;
  1094.  
  1095. const uint8_t madctl[] = {madctl_value};
  1096. write_cmd(self, ST7789_MADCTL, madctl, 1);
  1097. }
  1098.  
  1099. STATIC mp_obj_t st7789_ST7789_rotation(mp_obj_t self_in, mp_obj_t value) {
  1100. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  1101. mp_int_t rotation = mp_obj_get_int(value) % 4;
  1102. self->rotation = rotation;
  1103. set_rotation(self);
  1104. return mp_const_none;
  1105. }
  1106. STATIC MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_rotation_obj, st7789_ST7789_rotation);
  1107.  
  1108. STATIC mp_obj_t st7789_ST7789_width(mp_obj_t self_in) {
  1109. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  1110. return mp_obj_new_int(self->width);
  1111. }
  1112. STATIC MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_width_obj, st7789_ST7789_width);
  1113.  
  1114. STATIC mp_obj_t st7789_ST7789_height(mp_obj_t self_in) {
  1115. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  1116. return mp_obj_new_int(self->height);
  1117. }
  1118. STATIC MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_height_obj, st7789_ST7789_height);
  1119.  
  1120. STATIC mp_obj_t st7789_ST7789_vscrdef(size_t n_args, const mp_obj_t *args) {
  1121. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1122. mp_int_t tfa = mp_obj_get_int(args[1]);
  1123. mp_int_t vsa = mp_obj_get_int(args[2]);
  1124. mp_int_t bfa = mp_obj_get_int(args[3]);
  1125.  
  1126. uint8_t buf[6] = {(tfa) >> 8, (tfa) & 0xFF, (vsa) >> 8, (vsa) & 0xFF, (bfa) >> 8, (bfa) & 0xFF};
  1127. write_cmd(self, ST7789_VSCRDEF, buf, 6);
  1128.  
  1129. return mp_const_none;
  1130. }
  1131. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_vscrdef_obj, 4, 4, st7789_ST7789_vscrdef);
  1132.  
  1133. STATIC mp_obj_t st7789_ST7789_vscsad(mp_obj_t self_in, mp_obj_t vssa_in) {
  1134. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  1135. mp_int_t vssa = mp_obj_get_int(vssa_in);
  1136.  
  1137. uint8_t buf[2] = {(vssa) >> 8, (vssa) & 0xFF};
  1138. write_cmd(self, ST7789_VSCSAD, buf, 2);
  1139.  
  1140. return mp_const_none;
  1141. }
  1142. STATIC MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_vscsad_obj, st7789_ST7789_vscsad);
  1143.  
  1144. STATIC void custom_init(st7789_ST7789_obj_t *self) {
  1145. size_t init_len;
  1146. mp_obj_t *init_list;
  1147.  
  1148. mp_obj_get_array(self->custom_init, &init_len, &init_list);
  1149.  
  1150. for (int idx = 0; idx < init_len; idx++) {
  1151. size_t init_cmd_len;
  1152. mp_obj_t *init_cmd;
  1153. mp_obj_get_array(init_list[idx], &init_cmd_len, &init_cmd);
  1154. mp_buffer_info_t init_cmd_data_info;
  1155. if (mp_get_buffer(init_cmd[0], &init_cmd_data_info, MP_BUFFER_READ)) {
  1156. uint8_t *init_cmd_data = (uint8_t *)init_cmd_data_info.buf;
  1157.  
  1158. if (init_cmd_data_info.len > 1) {
  1159. write_cmd(self, init_cmd_data[0], &init_cmd_data[1], init_cmd_data_info.len - 1);
  1160. } else {
  1161. write_cmd(self, init_cmd_data[0], NULL, 0);
  1162. }
  1163. mp_hal_delay_ms(10);
  1164.  
  1165. // check for delay
  1166. if (init_cmd_len > 1) {
  1167. mp_int_t delay = mp_obj_get_int(init_cmd[1]);
  1168. if (delay > 0) {
  1169. mp_hal_delay_ms(delay);
  1170. }
  1171. }
  1172. }
  1173. }
  1174. }
  1175.  
  1176. STATIC mp_obj_t st7789_ST7789_init(mp_obj_t self_in) {
  1177. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  1178.  
  1179. st7789_ST7789_hard_reset(self_in);
  1180.  
  1181. if (self->custom_init == MP_OBJ_NULL) {
  1182. st7789_ST7789_soft_reset(self_in);
  1183. write_cmd(self, ST7789_SLPOUT, NULL, 0);
  1184.  
  1185. const uint8_t color_mode[] = {COLOR_MODE_65K | COLOR_MODE_16BIT};
  1186. write_cmd(self, ST7789_COLMOD, color_mode, 1);
  1187. mp_hal_delay_ms(10);
  1188.  
  1189. if (self->inversion) {
  1190. write_cmd(self, ST7789_INVON, NULL, 0);
  1191. } else {
  1192. write_cmd(self, ST7789_INVOFF, NULL, 0);
  1193. }
  1194.  
  1195. write_cmd(self, ST7789_NORON, NULL, 0);
  1196. mp_hal_delay_ms(10);
  1197.  
  1198. write_cmd(self, ST7789_DISPON, NULL, 0);
  1199. mp_hal_delay_ms(150);
  1200.  
  1201. } else {
  1202. custom_init(self);
  1203. }
  1204.  
  1205. set_rotation(self);
  1206. mp_hal_delay_ms(10);
  1207.  
  1208. const mp_obj_t args[] = {
  1209. self_in,
  1210. mp_obj_new_int(0),
  1211. mp_obj_new_int(0),
  1212. mp_obj_new_int(self->width),
  1213. mp_obj_new_int(self->height),
  1214. mp_obj_new_int(BLACK)
  1215. };
  1216.  
  1217. st7789_ST7789_fill_rect(6, args);
  1218.  
  1219. if (self->backlight) {
  1220. mp_hal_pin_write(self->backlight, 1);
  1221. }
  1222.  
  1223. return mp_const_none;
  1224. }
  1225. STATIC MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_init_obj, st7789_ST7789_init);
  1226.  
  1227. STATIC mp_obj_t st7789_ST7789_on(mp_obj_t self_in) {
  1228. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  1229.  
  1230. if (self->backlight) {
  1231. mp_hal_pin_write(self->backlight, 1);
  1232. mp_hal_delay_ms(10);
  1233. }
  1234.  
  1235. return mp_const_none;
  1236. }
  1237. STATIC MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_on_obj, st7789_ST7789_on);
  1238.  
  1239. STATIC mp_obj_t st7789_ST7789_off(mp_obj_t self_in) {
  1240. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
  1241.  
  1242. if (self->backlight) {
  1243. mp_hal_pin_write(self->backlight, 0);
  1244. mp_hal_delay_ms(10);
  1245. }
  1246.  
  1247. return mp_const_none;
  1248. }
  1249. STATIC MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_off_obj, st7789_ST7789_off);
  1250.  
  1251. STATIC mp_obj_t st7789_ST7789_hline(size_t n_args, const mp_obj_t *args) {
  1252. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1253. mp_int_t x = mp_obj_get_int(args[1]);
  1254. mp_int_t y = mp_obj_get_int(args[2]);
  1255. mp_int_t w = mp_obj_get_int(args[3]);
  1256. mp_int_t color = mp_obj_get_int(args[4]);
  1257.  
  1258. fast_hline(self, x, y, w, color);
  1259.  
  1260. return mp_const_none;
  1261. }
  1262. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_hline_obj, 5, 5, st7789_ST7789_hline);
  1263.  
  1264. STATIC mp_obj_t st7789_ST7789_vline(size_t n_args, const mp_obj_t *args) {
  1265. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1266. mp_int_t x = mp_obj_get_int(args[1]);
  1267. mp_int_t y = mp_obj_get_int(args[2]);
  1268. mp_int_t w = mp_obj_get_int(args[3]);
  1269. mp_int_t color = mp_obj_get_int(args[4]);
  1270.  
  1271. fast_vline(self, x, y, w, color);
  1272.  
  1273. return mp_const_none;
  1274. }
  1275. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_vline_obj, 5, 5, st7789_ST7789_vline);
  1276.  
  1277. // Circle/Fill_Circle by https://github.com/c-logic
  1278. // https://github.com/russhughes/st7789_mpy/pull/46
  1279. // https://github.com/c-logic/st7789_mpy.git patch-1
  1280.  
  1281. STATIC mp_obj_t st7789_ST7789_circle(size_t n_args, const mp_obj_t *args) {
  1282. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1283. mp_int_t xm = mp_obj_get_int(args[1]);
  1284. mp_int_t ym = mp_obj_get_int(args[2]);
  1285. mp_int_t r = mp_obj_get_int(args[3]);
  1286. mp_int_t color = mp_obj_get_int(args[4]);
  1287.  
  1288. mp_int_t f = 1 - r;
  1289. mp_int_t ddF_x = 1;
  1290. mp_int_t ddF_y = -2 * r;
  1291. mp_int_t x = 0;
  1292. mp_int_t y = r;
  1293.  
  1294. draw_pixel(self, xm, ym + r, color);
  1295. draw_pixel(self, xm, ym - r, color);
  1296. draw_pixel(self, xm + r, ym, color);
  1297. draw_pixel(self, xm - r, ym, color);
  1298. while (x < y) {
  1299. if (f >= 0) {
  1300. y -= 1;
  1301. ddF_y += 2;
  1302. f += ddF_y;
  1303. }
  1304. x += 1;
  1305. ddF_x += 2;
  1306. f += ddF_x;
  1307. draw_pixel(self, xm + x, ym + y, color);
  1308. draw_pixel(self, xm - x, ym + y, color);
  1309. draw_pixel(self, xm + x, ym - y, color);
  1310. draw_pixel(self, xm - x, ym - y, color);
  1311. draw_pixel(self, xm + y, ym + x, color);
  1312. draw_pixel(self, xm - y, ym + x, color);
  1313. draw_pixel(self, xm + y, ym - x, color);
  1314. draw_pixel(self, xm - y, ym - x, color);
  1315. }
  1316. return mp_const_none;
  1317. }
  1318.  
  1319. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_circle_obj, 5, 5, st7789_ST7789_circle);
  1320.  
  1321. // Circle/Fill_Circle by https://github.com/c-logic
  1322. // https://github.com/russhughes/st7789_mpy/pull/46
  1323. // https://github.com/c-logic/st7789_mpy.git patch-1
  1324.  
  1325. STATIC mp_obj_t st7789_ST7789_fill_circle(size_t n_args, const mp_obj_t *args) {
  1326. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1327. mp_int_t xm = mp_obj_get_int(args[1]);
  1328. mp_int_t ym = mp_obj_get_int(args[2]);
  1329. mp_int_t r = mp_obj_get_int(args[3]);
  1330. mp_int_t color = mp_obj_get_int(args[4]);
  1331.  
  1332. mp_int_t f = 1 - r;
  1333. mp_int_t ddF_x = 1;
  1334. mp_int_t ddF_y = -2 * r;
  1335. mp_int_t x = 0;
  1336. mp_int_t y = r;
  1337.  
  1338. fast_vline(self, xm, ym - y, 2 * y + 1, color);
  1339.  
  1340. while (x < y) {
  1341. if (f >= 0) {
  1342. y -= 1;
  1343. ddF_y += 2;
  1344. f += ddF_y;
  1345. }
  1346. x += 1;
  1347. ddF_x += 2;
  1348. f += ddF_x;
  1349. fast_vline(self, xm + x, ym - y, 2 * y + 1, color);
  1350. fast_vline(self, xm + y, ym - x, 2 * x + 1, color);
  1351. fast_vline(self, xm - x, ym - y, 2 * y + 1, color);
  1352. fast_vline(self, xm - y, ym - x, 2 * x + 1, color);
  1353. }
  1354. return mp_const_none;
  1355. }
  1356.  
  1357. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_fill_circle_obj, 5, 5, st7789_ST7789_fill_circle);
  1358.  
  1359. STATIC mp_obj_t st7789_ST7789_rect(size_t n_args, const mp_obj_t *args) {
  1360. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1361. mp_int_t x = mp_obj_get_int(args[1]);
  1362. mp_int_t y = mp_obj_get_int(args[2]);
  1363. mp_int_t w = mp_obj_get_int(args[3]);
  1364. mp_int_t h = mp_obj_get_int(args[4]);
  1365. mp_int_t color = mp_obj_get_int(args[5]);
  1366.  
  1367. fast_hline(self, x, y, w, color);
  1368. fast_vline(self, x, y, h, color);
  1369. fast_hline(self, x, y + h - 1, w, color);
  1370. fast_vline(self, x + w - 1, y, h, color);
  1371. return mp_const_none;
  1372. }
  1373.  
  1374. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_rect_obj, 6, 6, st7789_ST7789_rect);
  1375.  
  1376. STATIC mp_obj_t st7789_ST7789_madctl(size_t n_args, const mp_obj_t *args) {
  1377. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1378.  
  1379. if (n_args == 2) {
  1380. mp_int_t madctl_value = mp_obj_get_int(args[1]) & 0xff;
  1381. const uint8_t madctl[] = {madctl_value};
  1382. write_cmd(self, ST7789_MADCTL, madctl, 1);
  1383. self->madctl = madctl_value & 0xff;
  1384. }
  1385. return mp_obj_new_int(self->madctl);
  1386. }
  1387.  
  1388. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_madctl_obj, 1, 2, st7789_ST7789_madctl);
  1389.  
  1390. STATIC mp_obj_t st7789_ST7789_offset(size_t n_args, const mp_obj_t *args) {
  1391. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1392. mp_int_t colstart = mp_obj_get_int(args[1]);
  1393. mp_int_t rowstart = mp_obj_get_int(args[2]);
  1394.  
  1395. self->colstart = colstart;
  1396. self->rowstart = rowstart;
  1397.  
  1398. return mp_const_none;
  1399. }
  1400. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_offset_obj, 3, 3, st7789_ST7789_offset);
  1401.  
  1402. STATIC uint16_t color565(uint8_t r, uint8_t g, uint8_t b) {
  1403. return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
  1404. }
  1405.  
  1406. STATIC mp_obj_t st7789_color565(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
  1407. return MP_OBJ_NEW_SMALL_INT(color565(
  1408. (uint8_t)mp_obj_get_int(r),
  1409. (uint8_t)mp_obj_get_int(g),
  1410. (uint8_t)mp_obj_get_int(b)));
  1411. }
  1412. STATIC MP_DEFINE_CONST_FUN_OBJ_3(st7789_color565_obj, st7789_color565);
  1413.  
  1414. STATIC void map_bitarray_to_rgb565(uint8_t const *bitarray, uint8_t *buffer, int length, int width,
  1415. uint16_t color, uint16_t bg_color) {
  1416. int row_pos = 0;
  1417. for (int i = 0; i < length; i++) {
  1418. uint8_t byte = bitarray[i];
  1419. for (int bi = 7; bi >= 0; bi--) {
  1420. uint8_t b = byte & (1 << bi);
  1421. uint16_t cur_color = b ? color : bg_color;
  1422. *buffer = (cur_color & 0xff00) >> 8;
  1423. buffer++;
  1424. *buffer = cur_color & 0xff;
  1425. buffer++;
  1426.  
  1427. row_pos++;
  1428. if (row_pos >= width) {
  1429. row_pos = 0;
  1430. break;
  1431. }
  1432. }
  1433. }
  1434. }
  1435.  
  1436. STATIC mp_obj_t st7789_map_bitarray_to_rgb565(size_t n_args, const mp_obj_t *args) {
  1437. mp_buffer_info_t bitarray_info;
  1438. mp_buffer_info_t buffer_info;
  1439.  
  1440. mp_get_buffer_raise(args[1], &bitarray_info, MP_BUFFER_READ);
  1441. mp_get_buffer_raise(args[2], &buffer_info, MP_BUFFER_WRITE);
  1442. mp_int_t width = mp_obj_get_int(args[3]);
  1443. mp_int_t color = mp_obj_get_int(args[4]);
  1444. mp_int_t bg_color = mp_obj_get_int(args[5]);
  1445. map_bitarray_to_rgb565(bitarray_info.buf, buffer_info.buf, bitarray_info.len, width, color, bg_color);
  1446. return mp_const_none;
  1447. }
  1448. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_map_bitarray_to_rgb565_obj, 3, 6, st7789_map_bitarray_to_rgb565);
  1449.  
  1450. //
  1451. // jpg routines
  1452. //
  1453.  
  1454. #define JPG_MODE_FAST (0)
  1455. #define JPG_MODE_SLOW (1)
  1456.  
  1457. // User defined device identifier
  1458. typedef struct {
  1459. mp_file_t *fp; // File pointer for input function
  1460. uint8_t *fbuf; // Pointer to the frame buffer for output function
  1461. unsigned int wfbuf; // Width of the frame buffer [pix]
  1462. unsigned int left; // jpg crop left column
  1463. unsigned int top; // jpg crop top row
  1464. unsigned int right; // jpg crop right column
  1465. unsigned int bottom; // jpg crop bottom row
  1466.  
  1467. st7789_ST7789_obj_t *self; // display object
  1468.  
  1469. // for buffer input function
  1470. uint8_t *data;
  1471. unsigned int dataIdx;
  1472. unsigned int dataLen;
  1473.  
  1474. } IODEV;
  1475.  
  1476. static unsigned int buffer_in_func( // Returns number of bytes read (zero on error)
  1477. JDEC *jd, // Decompression object
  1478. uint8_t *buff, // Pointer to the read buffer (null to remove data)
  1479. unsigned int nbyte) { // Number of bytes to read/remove
  1480. IODEV *dev = (IODEV *)jd->device;
  1481.  
  1482. if (dev->dataIdx + nbyte > dev->dataLen) {
  1483. nbyte = dev->dataLen - dev->dataIdx;
  1484. }
  1485.  
  1486. if (buff) {
  1487. memcpy(buff, (uint8_t *)(dev->data + dev->dataIdx), nbyte);
  1488. }
  1489.  
  1490. dev->dataIdx += nbyte;
  1491. return nbyte;
  1492. }
  1493.  
  1494. //
  1495. // file input function
  1496. //
  1497.  
  1498. static unsigned int file_in_func( // Returns number of bytes read (zero on error)
  1499. JDEC *jd, // Decompression object
  1500. uint8_t *buff, // Pointer to the read buffer (null to remove data)
  1501. unsigned int nbyte) { // Number of bytes to read/remove
  1502. IODEV *dev = (IODEV *)jd->device; // Device identifier for the session (5th argument of jd_prepare function)
  1503. unsigned int nread;
  1504.  
  1505. // Read data from input stream
  1506. if (buff) {
  1507. nread = (unsigned int)mp_readinto(dev->fp, buff, nbyte);
  1508. return nread;
  1509. }
  1510.  
  1511. // Remove data from input stream if buff was NULL
  1512. mp_seek(dev->fp, nbyte, SEEK_CUR);
  1513. return 0;
  1514. }
  1515.  
  1516. //
  1517. // fast output function
  1518. //
  1519.  
  1520. static int out_fast( // 1:Ok, 0:Aborted
  1521. JDEC *jd, // Decompression object
  1522. void *bitmap, // Bitmap data to be output
  1523. JRECT *rect) { // Rectangular region of output image
  1524. IODEV *dev = (IODEV *)jd->device;
  1525. uint8_t *src, *dst;
  1526. uint16_t y, bws, bwd;
  1527.  
  1528. // Copy the decompressed RGB rectangular to the frame buffer (assuming RGB565)
  1529. src = (uint8_t *)bitmap;
  1530. dst = dev->fbuf + 2 * (rect->top * dev->wfbuf + rect->left); // Left-top of destination rectangular
  1531. bws = 2 * (rect->right - rect->left + 1); // Width of source rectangular [byte]
  1532. bwd = 2 * dev->wfbuf; // Width of frame buffer [byte]
  1533. for (y = rect->top; y <= rect->bottom; y++) {
  1534. memcpy(dst, src, bws); // Copy a line
  1535. src += bws;
  1536. dst += bwd; // Next line
  1537. }
  1538.  
  1539. return 1; // Continue to decompress
  1540. }
  1541.  
  1542. //
  1543. // Slow output function: draw each
  1544. //
  1545.  
  1546. static int out_slow( // 1:Ok, 0:Aborted
  1547. JDEC *jd, // Decompression object
  1548. void *bitmap, // Bitmap data to be output
  1549. JRECT *rect) { // Rectangular region of output image
  1550. IODEV *dev = (IODEV *)jd->device;
  1551. st7789_ST7789_obj_t *self = dev->self;
  1552.  
  1553. uint8_t *src, *dst;
  1554. uint16_t y;
  1555. uint16_t wx2 = (rect->right - rect->left + 1) * 2;
  1556. uint16_t h = rect->bottom - rect->top + 1;
  1557.  
  1558. // Copy the decompressed RGB rectangular to the frame buffer (assuming RGB565)
  1559. src = (uint8_t *)bitmap;
  1560. dst = dev->fbuf; // Left-top of destination rectangular
  1561. for (y = rect->top; y <= rect->bottom; y++) {
  1562. memcpy(dst, src, wx2); // Copy a line
  1563. src += wx2;
  1564. dst += wx2; // Next line
  1565. }
  1566.  
  1567. // blit buffer to display
  1568.  
  1569. set_window(
  1570. self,
  1571. rect->left + jd->x_offs,
  1572. rect->top + jd->y_offs,
  1573. rect->right + jd->x_offs,
  1574. rect->bottom + jd->y_offs);
  1575.  
  1576. DC_HIGH();
  1577. CS_LOW();
  1578. write_spi(self->spi_obj, (uint8_t *)dev->fbuf, wx2 * h);
  1579. CS_HIGH();
  1580.  
  1581. return 1; // Continue to decompress
  1582. }
  1583.  
  1584. //
  1585. // Draw jpg from a file at x, y using a fast mode or slow mode
  1586. //
  1587.  
  1588. STATIC mp_obj_t st7789_ST7789_jpg(size_t n_args, const mp_obj_t *args) {
  1589. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1590. static unsigned int (*input_func)(JDEC *, uint8_t *, unsigned int) = NULL;
  1591. mp_buffer_info_t bufinfo;
  1592. IODEV devid;
  1593.  
  1594. if (mp_obj_is_type(args[1], &mp_type_bytes)) {
  1595. mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
  1596. devid.dataIdx = 0;
  1597. devid.data = bufinfo.buf;
  1598. devid.dataLen = bufinfo.len;
  1599. input_func = buffer_in_func;
  1600. self->fp = MP_OBJ_NULL;
  1601. } else {
  1602. const char *filename = mp_obj_str_get_str(args[1]);
  1603. self->fp = mp_open(filename, "rb");
  1604. devid.fp = self->fp;
  1605. input_func = file_in_func;
  1606. devid.data = MP_OBJ_NULL;
  1607. devid.dataLen = 0;
  1608. }
  1609.  
  1610. mp_int_t x = mp_obj_get_int(args[2]);
  1611. mp_int_t y = mp_obj_get_int(args[3]);
  1612.  
  1613. mp_int_t mode;
  1614.  
  1615. if (n_args > 4) {
  1616. mode = mp_obj_get_int(args[4]);
  1617. } else {
  1618. mode = JPG_MODE_FAST;
  1619. }
  1620.  
  1621. int (*outfunc)(JDEC *, void *, JRECT *);
  1622.  
  1623. JRESULT res; // Result code of TJpgDec API
  1624. JDEC jdec; // Decompression object
  1625. self->work = (void *)m_malloc(3100); // Pointer to the work area
  1626. size_t bufsize;
  1627.  
  1628. if (input_func && (devid.fp || devid.data)) {
  1629. // Prepare to decompress
  1630. res = jd_prepare(&jdec, input_func, self->work, 3100, &devid);
  1631. if (res == JDR_OK) {
  1632. // Initialize output device
  1633. if (mode == JPG_MODE_FAST) {
  1634. bufsize = 2 * jdec.width * jdec.height;
  1635. outfunc = out_fast;
  1636. } else {
  1637. bufsize = 2 * jdec.msx * 8 * jdec.msy * 8;
  1638. outfunc = out_slow;
  1639. jdec.x_offs = x;
  1640. jdec.y_offs = y;
  1641. }
  1642. if (self->buffer_size && (bufsize > self->buffer_size)) {
  1643. mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("buffer too small. %ld bytes required."), (long)bufsize);
  1644. }
  1645.  
  1646. if (self->buffer_size == 0) {
  1647. self->i2c_buffer = m_malloc(bufsize);
  1648. }
  1649.  
  1650. if (!self->i2c_buffer) {
  1651. mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("out of memory"));
  1652. }
  1653.  
  1654. devid.fbuf = (uint8_t *)self->i2c_buffer;
  1655. devid.wfbuf = jdec.width;
  1656. devid.self = self;
  1657. res = jd_decomp(&jdec, outfunc, 0); // Start to decompress with 1/1 scaling
  1658. if (res == JDR_OK) {
  1659. if (mode == JPG_MODE_FAST) {
  1660. set_window(self, x, y, x + jdec.width - 1, y + jdec.height - 1);
  1661. DC_HIGH();
  1662. CS_LOW();
  1663. write_spi(self->spi_obj, (uint8_t *)self->i2c_buffer, bufsize);
  1664. CS_HIGH();
  1665. }
  1666. } else {
  1667. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("jpg decompress failed."));
  1668. }
  1669. if (self->buffer_size == 0) {
  1670. m_free(self->i2c_buffer); // Discard frame buffer
  1671. self->i2c_buffer = MP_OBJ_NULL;
  1672. }
  1673. devid.fbuf = MP_OBJ_NULL;
  1674. } else {
  1675. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("jpg prepare failed."));
  1676. }
  1677.  
  1678. if (self->fp) {
  1679. mp_close(self->fp);
  1680. self->fp = MP_OBJ_NULL;
  1681. }
  1682. }
  1683. m_free(self->work); // Discard work area
  1684. return mp_const_none;
  1685. }
  1686. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_jpg_obj, 4, 5, st7789_ST7789_jpg);
  1687.  
  1688. //
  1689. // output function for jpg_decode
  1690. //
  1691.  
  1692. static int out_crop( // 1:Ok, 0:Aborted
  1693. JDEC *jd, // Decompression object
  1694. void *bitmap, // Bitmap data to be output
  1695. JRECT *rect) { // Rectangular region of output image
  1696. IODEV *dev = (IODEV *)jd->device;
  1697.  
  1698. if (
  1699. dev->left <= rect->right &&
  1700. dev->right >= rect->left &&
  1701. dev->top <= rect->bottom &&
  1702. dev->bottom >= rect->top) {
  1703. uint16_t left = MAX(dev->left, rect->left);
  1704. uint16_t top = MAX(dev->top, rect->top);
  1705. uint16_t right = MIN(dev->right, rect->right);
  1706. uint16_t bottom = MIN(dev->bottom, rect->bottom);
  1707. uint16_t dev_width = dev->right - dev->left + 1;
  1708. uint16_t rect_width = rect->right - rect->left + 1;
  1709. uint16_t width = (right - left + 1) * 2;
  1710. uint16_t row;
  1711.  
  1712. for (row = top; row <= bottom; row++) {
  1713. memcpy(
  1714. (uint16_t *)dev->fbuf + ((row - dev->top) * dev_width) + left - dev->left,
  1715. (uint16_t *)bitmap + ((row - rect->top) * rect_width) + left - rect->left,
  1716. width);
  1717. }
  1718. }
  1719. return 1; // Continue to decompress
  1720. }
  1721.  
  1722. //
  1723. // Decode a jpg file and return it or a portion of it as a tuple containing
  1724. // a blittable buffer, the width and height of the buffer.
  1725. //
  1726.  
  1727. STATIC mp_obj_t st7789_ST7789_jpg_decode(size_t n_args, const mp_obj_t *args) {
  1728. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1729.  
  1730. static unsigned int (*input_func)(JDEC *, uint8_t *, unsigned int) = NULL;
  1731. mp_buffer_info_t bufinfo;
  1732. IODEV devid;
  1733.  
  1734. if (mp_obj_is_type(args[1], &mp_type_bytes)) {
  1735. mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
  1736. devid.dataIdx = 0;
  1737. devid.data = bufinfo.buf;
  1738. devid.dataLen = bufinfo.len;
  1739. input_func = buffer_in_func;
  1740. self->fp = MP_OBJ_NULL;
  1741. } else {
  1742. const char *filename = mp_obj_str_get_str(args[1]);
  1743. self->fp = mp_open(filename, "rb");
  1744. devid.fp = self->fp;
  1745. input_func = file_in_func;
  1746. devid.data = MP_OBJ_NULL;
  1747. devid.dataLen = 0;
  1748. }
  1749. mp_int_t x = 0, y = 0, width = 0, height = 0;
  1750.  
  1751. if (n_args == 2 || n_args == 6) {
  1752. if (n_args == 6) {
  1753. x = mp_obj_get_int(args[2]);
  1754. y = mp_obj_get_int(args[3]);
  1755. width = mp_obj_get_int(args[4]);
  1756. height = mp_obj_get_int(args[5]);
  1757. }
  1758.  
  1759. self->work = (void *)m_malloc(3100); // Pointer to the work area
  1760.  
  1761. JRESULT res; // Result code of TJpgDec API
  1762. JDEC jdec; // Decompression object
  1763. size_t bufsize = 0;
  1764.  
  1765. if (input_func && (devid.fp || devid.data)) {
  1766. // Prepare to decompress
  1767. res = jd_prepare(&jdec, input_func, self->work, 3100, &devid);
  1768. if (res == JDR_OK) {
  1769. if (n_args < 6) {
  1770. x = 0;
  1771. y = 0;
  1772. width = jdec.width;
  1773. height = jdec.height;
  1774. }
  1775. // Initialize output device
  1776. devid.left = x;
  1777. devid.top = y;
  1778. devid.right = x + width - 1;
  1779. devid.bottom = y + height - 1;
  1780.  
  1781. bufsize = 2 * width * height;
  1782. self->i2c_buffer = m_malloc(bufsize);
  1783. if (self->i2c_buffer) {
  1784. memset(self->i2c_buffer, 0xBEEF, bufsize);
  1785. } else {
  1786. mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("out of memory"));
  1787. }
  1788.  
  1789. devid.fbuf = (uint8_t *)self->i2c_buffer;
  1790. devid.wfbuf = jdec.width;
  1791. devid.self = self;
  1792. res = jd_decomp(&jdec, out_crop, 0); // Start to decompress with 1/1 scaling
  1793. if (res != JDR_OK) {
  1794. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("jpg decompress failed."));
  1795. }
  1796.  
  1797. } else {
  1798. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("jpg prepare failed."));
  1799. }
  1800. if (self->fp) {
  1801. mp_close(self->fp);
  1802. self->fp = MP_OBJ_NULL;
  1803. }
  1804. }
  1805. m_free(self->work); // Discard work area
  1806.  
  1807. mp_obj_t result[3] = {
  1808. mp_obj_new_bytearray(bufsize, (mp_obj_t *)self->i2c_buffer),
  1809. mp_obj_new_int(width),
  1810. mp_obj_new_int(height)
  1811. };
  1812.  
  1813. return mp_obj_new_tuple(3, result);
  1814. }
  1815.  
  1816. mp_raise_TypeError(MP_ERROR_TEXT("jpg_decode requires either 2 or 6 arguments"));
  1817. return mp_const_none;
  1818. }
  1819. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_jpg_decode_obj, 2, 6, st7789_ST7789_jpg_decode);
  1820.  
  1821. //
  1822. // PNG Routines using the pngle library from https://github.com/kikuchan/pngle
  1823. // licensed under the MIT License
  1824. //
  1825.  
  1826. typedef struct _PNG_USER_DATA {
  1827. st7789_ST7789_obj_t *self;
  1828. uint16_t top; // draw png starting at this row
  1829. uint16_t left; // draw png starting at this column
  1830. uint16_t pixels; // number of pixels that fit in buffer (must be a multiple of width)
  1831. uint16_t rows; // number of rows that fit in buffer (or png height if < rows)
  1832. uint16_t pixel; // index to current pixel in buffer
  1833. uint16_t row; // current row
  1834. uint16_t col; // current column
  1835. uint16_t *buffer; // pointer to current pixel in buffer
  1836. } PNG_USER_DATA;
  1837.  
  1838. void pngle_on_draw(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]) {
  1839. PNG_USER_DATA *user_data = pngle_get_user_data(pngle);
  1840. st7789_ST7789_obj_t *self = user_data->self;
  1841. pngle_ihdr_t *ihdr = pngle_get_ihdr(pngle);
  1842. size_t buf_size = self->buffer_size;
  1843.  
  1844. uint16_t color = _swap_bytes(color565(rgba[0], rgba[1], rgba[2])); // rgba[3] transparency
  1845.  
  1846. // initialize the user_data structure and optionally allocate line buffer on the first call
  1847. if (user_data->pixels == 0) {
  1848. // if no existing buffer, create one to hold a complete line
  1849. if (self->buffer_size == 0) {
  1850. buf_size = ihdr->width * 2;
  1851. self->i2c_buffer = m_malloc(buf_size);
  1852. if (!self->i2c_buffer) {
  1853. mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("out of memory"));
  1854. }
  1855. } else {
  1856. // check if existing buffer is large enough
  1857. if (self->buffer_size < buf_size) {
  1858. mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("buffer too small. %zu bytes required."), buf_size);
  1859. }
  1860. }
  1861.  
  1862. user_data->rows = (buf_size / ihdr->width >> 1);
  1863. if (user_data->rows > ihdr->height) {
  1864. user_data->rows = ihdr->height;
  1865. }
  1866.  
  1867. user_data->pixels = ihdr->width * user_data->rows;
  1868. user_data->pixel = 0;
  1869. user_data->row = 0;
  1870. user_data->col = 0;
  1871. user_data->buffer = self->i2c_buffer;
  1872. }
  1873.  
  1874. // check if the buffer needs to flushed to the display
  1875. if (user_data->pixels == user_data->pixel) {
  1876. set_window(
  1877. self,
  1878. user_data->left,
  1879. user_data->top,
  1880. user_data->left + ihdr->width - 1,
  1881. y - 1);
  1882.  
  1883. DC_HIGH();
  1884. CS_LOW();
  1885. write_spi(self->spi_obj, (uint8_t *)self->i2c_buffer, user_data->pixels * 2);
  1886. CS_HIGH();
  1887.  
  1888. user_data->pixel = 0;
  1889. user_data->col = 0;
  1890. user_data->row = 0;
  1891. user_data->top += user_data->rows;
  1892. user_data->buffer = self->i2c_buffer;
  1893. }
  1894.  
  1895. *user_data->buffer++ = color;
  1896. user_data->pixel++;
  1897.  
  1898. user_data->col++;
  1899. if (user_data->col == ihdr->width - 1) {
  1900. user_data->col = 0;
  1901. user_data->row++;
  1902. }
  1903. }
  1904.  
  1905. void pngle_on_draw_transparent(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]) {
  1906. PNG_USER_DATA *user_data = pngle_get_user_data(pngle);
  1907. st7789_ST7789_obj_t *self = user_data->self;
  1908. pngle_ihdr_t *ihdr = pngle_get_ihdr(pngle);
  1909. size_t buf_size = self->buffer_size;
  1910.  
  1911. uint16_t color = _swap_bytes(color565(rgba[0], rgba[1], rgba[2]));
  1912. bool transp = (rgba[3] == 0);
  1913.  
  1914. // initialize the user_data structure and optionally allocate line buffer on the first call
  1915. if (user_data->pixels == 0) {
  1916. // if no existing buffer, create one to hold a complete line
  1917. if (self->buffer_size == 0) {
  1918. buf_size = ihdr->width * 2;
  1919. self->i2c_buffer = m_malloc(buf_size);
  1920. if (!self->i2c_buffer) {
  1921. mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("out of memory"));
  1922. }
  1923. } else {
  1924. // check if existing buffer is large enough
  1925. if (self->buffer_size < buf_size) {
  1926. mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("buffer too small. %zu bytes required."), buf_size);
  1927. }
  1928. }
  1929.  
  1930. user_data->rows = (buf_size / ihdr->width >> 1);
  1931. if (user_data->rows > ihdr->height) {
  1932. user_data->rows = ihdr->height;
  1933. }
  1934.  
  1935. user_data->pixels = ihdr->width * user_data->rows;
  1936. user_data->pixel = 0;
  1937. user_data->row = y;
  1938. user_data->col = x;
  1939. user_data->buffer = self->i2c_buffer;
  1940. }
  1941.  
  1942. // check if the buffer needs to flushed to the display
  1943.  
  1944. if ((transp || y != user_data->row) && user_data->pixel) {
  1945. set_window(
  1946. self,
  1947. user_data->left + user_data->col,
  1948. user_data->top + user_data->row,
  1949. user_data->left + user_data->col + user_data->pixel - 1,
  1950. user_data->top + user_data->row);
  1951.  
  1952. DC_HIGH();
  1953. CS_LOW();
  1954. write_spi(self->spi_obj, (uint8_t *)self->i2c_buffer, user_data->pixel * 2);
  1955. CS_HIGH();
  1956.  
  1957. user_data->pixel = 0;
  1958. user_data->col = x;
  1959. user_data->row = y;
  1960. user_data->buffer = self->i2c_buffer;
  1961. }
  1962.  
  1963. if (!transp) {
  1964. if (user_data->pixel == 0) {
  1965. user_data->col = x;
  1966. user_data->row = y;
  1967. }
  1968.  
  1969. *user_data->buffer++ = color;
  1970. user_data->pixel++;
  1971. }
  1972. }
  1973.  
  1974. #define PNG_FILE_BUFFER_SIZE 256
  1975.  
  1976. STATIC mp_obj_t st7789_ST7789_png(size_t n_args, const mp_obj_t *args) {
  1977. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  1978.  
  1979. const char *filename = mp_obj_str_get_str(args[1]);
  1980. mp_int_t x = mp_obj_get_int(args[2]);
  1981. mp_int_t y = mp_obj_get_int(args[3]);
  1982. bool transparency = (n_args > 4) ? mp_obj_is_true(args[4]) : false;
  1983.  
  1984. char buf[PNG_FILE_BUFFER_SIZE];
  1985. int len, remain = 0;
  1986.  
  1987. PNG_USER_DATA user_data = {
  1988. self, y, x, 0, 0, 0, 0, 0, NULL
  1989. };
  1990.  
  1991. // allocate new pngle_t and store in self to protect memory from gc
  1992. self->work = pngle_new(self);
  1993. pngle_t *pngle = (pngle_t *)self->work;
  1994. pngle_set_user_data(pngle, (void *)&user_data);
  1995.  
  1996. if (transparency) {
  1997. pngle_set_draw_callback(pngle, pngle_on_draw_transparent);
  1998. } else {
  1999. pngle_set_draw_callback(pngle, pngle_on_draw);
  2000. }
  2001.  
  2002. self->fp = mp_open(filename, "rb");
  2003.  
  2004. while ((len = mp_readinto(self->fp, buf + remain, PNG_FILE_BUFFER_SIZE - remain)) > 0) {
  2005. int fed = pngle_feed(pngle, buf, remain + len);
  2006. if (fed < 0) {
  2007. mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("png decompress failed: %s"), pngle_error(pngle));
  2008. }
  2009. remain = remain + len - fed;
  2010. if (remain > 0) {
  2011. memmove(buf, buf + fed, remain);
  2012. }
  2013. }
  2014.  
  2015. // flush any remaining pixels to the display
  2016. if (user_data.pixel) {
  2017. pngle_ihdr_t *ihdr = pngle_get_ihdr(pngle);
  2018. set_window(
  2019. self,
  2020. user_data.left,
  2021. user_data.top,
  2022. user_data.left + ihdr->width - 1,
  2023. user_data.top + user_data.row - 1);
  2024.  
  2025. DC_HIGH();
  2026. CS_LOW();
  2027. write_spi(self->spi_obj, (uint8_t *)self->i2c_buffer, user_data.pixel * 2);
  2028. CS_HIGH();
  2029. }
  2030.  
  2031. // free dynamic buffer
  2032. if (self->buffer_size == 0) {
  2033. m_free(self->i2c_buffer);
  2034. self->i2c_buffer = NULL;
  2035. }
  2036.  
  2037. mp_close(self->fp);
  2038. pngle_destroy(pngle);
  2039. self->work = NULL;
  2040. return mp_const_none;
  2041. }
  2042. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_png_obj, 4, 5, st7789_ST7789_png);
  2043.  
  2044. //
  2045. // Return the center of a polygon as an (x, y) tuple
  2046. //
  2047.  
  2048. STATIC mp_obj_t st7789_ST7789_polygon_center(size_t n_args, const mp_obj_t *args) {
  2049. size_t poly_len;
  2050. mp_obj_t *polygon;
  2051. mp_obj_get_array(args[1], &poly_len, &polygon);
  2052.  
  2053. mp_float_t sum = 0.0;
  2054. int vsx = 0;
  2055. int vsy = 0;
  2056.  
  2057. if (poly_len > 0) {
  2058. for (int idx = 0; idx < poly_len; idx++) {
  2059. size_t point_from_poly_len;
  2060. mp_obj_t *point_from_poly;
  2061. mp_obj_get_array(polygon[idx], &point_from_poly_len, &point_from_poly);
  2062. if (point_from_poly_len < 2) {
  2063. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2064. }
  2065.  
  2066. mp_int_t v1x = mp_obj_get_int(point_from_poly[0]);
  2067. mp_int_t v1y = mp_obj_get_int(point_from_poly[1]);
  2068.  
  2069. mp_obj_get_array(polygon[(idx + 1) % poly_len], &point_from_poly_len, &point_from_poly);
  2070. if (point_from_poly_len < 2) {
  2071. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2072. }
  2073.  
  2074. mp_int_t v2x = mp_obj_get_int(point_from_poly[0]);
  2075. mp_int_t v2y = mp_obj_get_int(point_from_poly[1]);
  2076.  
  2077. mp_float_t cross = v1x * v2y - v1y * v2x;
  2078. sum += cross;
  2079. vsx += (int)((v1x + v2x) * cross);
  2080. vsy += (int)((v1y + v2y) * cross);
  2081. }
  2082.  
  2083. mp_float_t z = 1.0 / (3.0 * sum);
  2084. vsx = (int)(vsx * z);
  2085. vsy = (int)(vsy * z);
  2086. } else {
  2087. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2088. }
  2089.  
  2090. mp_obj_t center[2] = {mp_obj_new_int(vsx), mp_obj_new_int(vsy)};
  2091. return mp_obj_new_tuple(2, center);
  2092. }
  2093. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_polygon_center_obj, 2, 2, st7789_ST7789_polygon_center);
  2094.  
  2095. //
  2096. // RotatePolygon: Rotate a polygon around a center point angle radians
  2097. //
  2098.  
  2099. STATIC void RotatePolygon(Polygon *polygon, Point center, mp_float_t angle) {
  2100. if (polygon->length == 0) {
  2101. return; /* reject null polygons */
  2102.  
  2103. }
  2104. mp_float_t cosAngle = MICROPY_FLOAT_C_FUN(cos)(angle);
  2105. mp_float_t sinAngle = MICROPY_FLOAT_C_FUN(sin)(angle);
  2106.  
  2107. for (int i = 0; i < polygon->length; i++) {
  2108. mp_float_t dx = (polygon->points[i].x - center.x);
  2109. mp_float_t dy = (polygon->points[i].y - center.y);
  2110.  
  2111. polygon->points[i].x = center.x + (int)0.5 + (dx * cosAngle - dy * sinAngle);
  2112. polygon->points[i].y = center.y + (int)0.5 + (dx * sinAngle + dy * cosAngle);
  2113. }
  2114. }
  2115.  
  2116. //
  2117. // public-domain code by Darel Rex Finley, 2007
  2118. // https://alienryderflex.com/polygon_fill/
  2119. //
  2120.  
  2121. #define MAX_POLY_CORNERS 32
  2122. STATIC void PolygonFill(st7789_ST7789_obj_t *self, Polygon *polygon, Point location, uint16_t color) {
  2123. int nodes, nodeX[MAX_POLY_CORNERS], pixelY, i, j, swap;
  2124.  
  2125. int minX = INT_MAX;
  2126. int maxX = INT_MIN;
  2127. int minY = INT_MAX;
  2128. int maxY = INT_MIN;
  2129.  
  2130. for (i = 0; i < polygon->length; i++) {
  2131. if (polygon->points[i].x < minX) {
  2132. minX = (int)polygon->points[i].x;
  2133. }
  2134.  
  2135. if (polygon->points[i].x > maxX) {
  2136. maxX = (int)polygon->points[i].x;
  2137. }
  2138.  
  2139. if (polygon->points[i].y < minY) {
  2140. minY = (int)polygon->points[i].y;
  2141. }
  2142.  
  2143. if (polygon->points[i].y > maxY) {
  2144. maxY = (int)polygon->points[i].y;
  2145. }
  2146. }
  2147.  
  2148. // Loop through the rows
  2149. for (pixelY = minY; pixelY < maxY; pixelY++) {
  2150. // Build a list of nodes.
  2151. nodes = 0;
  2152. j = polygon->length - 1;
  2153. for (i = 0; i < polygon->length; i++) {
  2154. if ((polygon->points[i].y < pixelY && polygon->points[j].y >= pixelY) ||
  2155. (polygon->points[j].y < pixelY && polygon->points[i].y >= pixelY)) {
  2156. if (nodes < MAX_POLY_CORNERS) {
  2157. nodeX[nodes++] = (int)(polygon->points[i].x +
  2158. (pixelY - polygon->points[i].y) /
  2159. (polygon->points[j].y - polygon->points[i].y) *
  2160. (polygon->points[j].x - polygon->points[i].x));
  2161. } else {
  2162. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon too complex increase MAX_POLY_CORNERS."));
  2163. }
  2164. }
  2165. j = i;
  2166. }
  2167.  
  2168. // Sort the nodes, via a simple “Bubble” sort.
  2169. i = 0;
  2170. while (i < nodes - 1) {
  2171. if (nodeX[i] > nodeX[i + 1]) {
  2172. swap = nodeX[i];
  2173. nodeX[i] = nodeX[i + 1];
  2174. nodeX[i + 1] = swap;
  2175. if (i) {
  2176. i--;
  2177. }
  2178. } else {
  2179. i++;
  2180. }
  2181. }
  2182.  
  2183. // Fill the pixels between node pairs.
  2184. for (i = 0; i < nodes; i += 2) {
  2185. if (nodeX[i] >= maxX) {
  2186. break;
  2187. }
  2188.  
  2189. if (nodeX[i + 1] > minX) {
  2190. if (nodeX[i] < minX) {
  2191. nodeX[i] = minX;
  2192. }
  2193.  
  2194. if (nodeX[i + 1] > maxX) {
  2195. nodeX[i + 1] = maxX;
  2196. }
  2197.  
  2198. fast_hline(self, (int)location.x + nodeX[i], (int)location.y + pixelY, nodeX[i + 1] - nodeX[i] + 1, color);
  2199. }
  2200. }
  2201. }
  2202. }
  2203.  
  2204. STATIC mp_obj_t st7789_ST7789_polygon(size_t n_args, const mp_obj_t *args) {
  2205. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  2206.  
  2207. size_t poly_len;
  2208. mp_obj_t *polygon;
  2209. mp_obj_get_array(args[1], &poly_len, &polygon);
  2210.  
  2211. self->work = NULL;
  2212.  
  2213. if (poly_len > 0) {
  2214. mp_int_t x = mp_obj_get_int(args[2]);
  2215. mp_int_t y = mp_obj_get_int(args[3]);
  2216. mp_int_t color = mp_obj_get_int(args[4]);
  2217.  
  2218. mp_float_t angle = 0.0f;
  2219. if (n_args > 5 && mp_obj_is_float(args[5])) {
  2220. angle = mp_obj_float_get(args[5]);
  2221. }
  2222.  
  2223. mp_int_t cx = 0;
  2224. mp_int_t cy = 0;
  2225.  
  2226. if (n_args > 6) {
  2227. cx = mp_obj_get_int(args[6]);
  2228. cy = mp_obj_get_int(args[7]);
  2229. }
  2230.  
  2231. self->work = m_malloc(poly_len * sizeof(Point));
  2232. if (self->work) {
  2233. Point *point = (Point *)self->work;
  2234.  
  2235. for (int idx = 0; idx < poly_len; idx++) {
  2236. size_t point_from_poly_len;
  2237. mp_obj_t *point_from_poly;
  2238. mp_obj_get_array(polygon[idx], &point_from_poly_len, &point_from_poly);
  2239. if (point_from_poly_len < 2) {
  2240. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2241. }
  2242.  
  2243. mp_int_t px = mp_obj_get_int(point_from_poly[0]);
  2244. mp_int_t py = mp_obj_get_int(point_from_poly[1]);
  2245. point[idx].x = px;
  2246. point[idx].y = py;
  2247. }
  2248.  
  2249. Point center;
  2250. center.x = cx;
  2251. center.y = cy;
  2252.  
  2253. Polygon polygon;
  2254. polygon.length = poly_len;
  2255. polygon.points = self->work;
  2256.  
  2257. if (angle > 0) {
  2258. RotatePolygon(&polygon, center, angle);
  2259. }
  2260.  
  2261. for (int idx = 1; idx < poly_len; idx++) {
  2262. line(
  2263. self,
  2264. (int)point[idx - 1].x + x,
  2265. (int)point[idx - 1].y + y,
  2266. (int)point[idx].x + x,
  2267. (int)point[idx].y + y, color);
  2268. }
  2269.  
  2270. m_free(self->work);
  2271. self->work = NULL;
  2272. } else {
  2273. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2274. }
  2275. } else {
  2276. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2277. }
  2278.  
  2279. return mp_const_none;
  2280. }
  2281. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_polygon_obj, 4, 8, st7789_ST7789_polygon);
  2282.  
  2283. //
  2284. // filled convex polygon
  2285. //
  2286.  
  2287. STATIC mp_obj_t st7789_ST7789_fill_polygon(size_t n_args, const mp_obj_t *args) {
  2288. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  2289.  
  2290. size_t poly_len;
  2291. mp_obj_t *polygon;
  2292. mp_obj_get_array(args[1], &poly_len, &polygon);
  2293.  
  2294. self->work = NULL;
  2295.  
  2296. if (poly_len > 0) {
  2297. mp_int_t x = mp_obj_get_int(args[2]);
  2298. mp_int_t y = mp_obj_get_int(args[3]);
  2299. mp_int_t color = mp_obj_get_int(args[4]);
  2300.  
  2301. mp_float_t angle = 0.0f;
  2302. if (n_args > 5) {
  2303. angle = mp_obj_float_get(args[5]);
  2304. }
  2305.  
  2306. mp_int_t cx = 0;
  2307. mp_int_t cy = 0;
  2308.  
  2309. if (n_args > 6) {
  2310. cx = mp_obj_get_int(args[6]);
  2311. cy = mp_obj_get_int(args[7]);
  2312. }
  2313.  
  2314. self->work = m_malloc(poly_len * sizeof(Point));
  2315. if (self->work) {
  2316. Point *point = (Point *)self->work;
  2317.  
  2318. for (int idx = 0; idx < poly_len; idx++) {
  2319. size_t point_from_poly_len;
  2320. mp_obj_t *point_from_poly;
  2321. mp_obj_get_array(polygon[idx], &point_from_poly_len, &point_from_poly);
  2322. if (point_from_poly_len < 2) {
  2323. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2324. }
  2325.  
  2326. point[idx].x = mp_obj_get_int(point_from_poly[0]);
  2327. point[idx].y = mp_obj_get_int(point_from_poly[1]);
  2328. }
  2329.  
  2330. Point center = {cx, cy};
  2331. Polygon polygon = {poly_len, self->work};
  2332.  
  2333. if (angle != 0) {
  2334. RotatePolygon(&polygon, center, angle);
  2335. }
  2336.  
  2337. Point location = {x, y};
  2338. PolygonFill(self, &polygon, location, color);
  2339.  
  2340. m_free(self->work);
  2341. self->work = NULL;
  2342. } else {
  2343. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2344. }
  2345.  
  2346. } else {
  2347. mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Polygon data error"));
  2348. }
  2349.  
  2350. return mp_const_none;
  2351. }
  2352. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_fill_polygon_obj, 4, 8, st7789_ST7789_fill_polygon);
  2353.  
  2354. STATIC mp_obj_t st7789_ST7789_bounding(size_t n_args, const mp_obj_t *args) {
  2355. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  2356.  
  2357. mp_obj_t bounds[4] = {
  2358. mp_obj_new_int(self->min_x),
  2359. mp_obj_new_int(self->min_y),
  2360. (n_args > 2 && mp_obj_is_true(args[2])) ? mp_obj_new_int(self->max_x - self->min_x + 1) : mp_obj_new_int(self->max_x),
  2361. (n_args > 2 && mp_obj_is_true(args[2])) ? mp_obj_new_int(self->max_y - self->min_y + 1) : mp_obj_new_int(self->max_y)
  2362. };
  2363.  
  2364. if (n_args > 1) {
  2365. if (mp_obj_is_true(args[1])) {
  2366. self->bounding = 1;
  2367. } else {
  2368. self->bounding = 0;
  2369. }
  2370.  
  2371. self->min_x = self->width;
  2372. self->min_y = self->height;
  2373. self->max_x = 0;
  2374. self->max_y = 0;
  2375. }
  2376. return mp_obj_new_tuple(4, bounds);
  2377. }
  2378. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_bounding_obj, 1, 3, st7789_ST7789_bounding);
  2379.  
  2380. STATIC mp_obj_t st7789_ST7789_draw40(size_t n_args, const mp_obj_t *args) {
  2381. st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  2382. int pixelRatio = 40;
  2383. int pixelSize = 240 / pixelRatio;
  2384. int currentPixelX = 0;
  2385. int currentPixelY = 0;
  2386.  
  2387. mp_obj_t argsFORTHING[] = {
  2388. self,
  2389. mp_obj_new_int(0),
  2390. mp_obj_new_int(0),
  2391. mp_obj_new_int(pixelSize),
  2392. mp_obj_new_int(pixelSize),
  2393. mp_obj_new_int(BLACK)
  2394. };
  2395.  
  2396. for(int i = 1; i < (pixelRatio*pixelRatio) + 1; i++){
  2397. mp_int_t value = mp_obj_get_int(args[i]);
  2398.  
  2399. if(value == 1){
  2400. argsFORTHING[1] = mp_obj_new_int(currentPixelX);
  2401. argsFORTHING[2] = mp_obj_new_int(currentPixelY);
  2402. argsFORTHING[5] = mp_obj_new_int(WHITE);
  2403.  
  2404. st7789_ST7789_fill_rect(6, argsFORTHING);
  2405. }
  2406. if(value == 0){
  2407. argsFORTHING[1] = mp_obj_new_int(currentPixelX);
  2408. argsFORTHING[2] = mp_obj_new_int(currentPixelY);
  2409. argsFORTHING[5] = mp_obj_new_int(BLACK);
  2410.  
  2411. st7789_ST7789_fill_rect(6, argsFORTHING);
  2412. }
  2413.  
  2414. currentPixelX += pixelSize;
  2415.  
  2416. if(currentPixelX == 240){
  2417. currentPixelX = 0;
  2418. currentPixelY += pixelSize;
  2419. }
  2420. }
  2421. return mp_const_none;
  2422. }
  2423. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_draw40_obj, 1601, 1601, st7789_ST7789_draw40);
  2424.  
  2425. STATIC const mp_rom_map_elem_t st7789_ST7789_locals_dict_table[] = {
  2426. {MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&st7789_ST7789_write_obj)},
  2427. {MP_ROM_QSTR(MP_QSTR_write_len), MP_ROM_PTR(&st7789_ST7789_write_len_obj)},
  2428. {MP_ROM_QSTR(MP_QSTR_hard_reset), MP_ROM_PTR(&st7789_ST7789_hard_reset_obj)},
  2429. {MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&st7789_ST7789_soft_reset_obj)},
  2430. {MP_ROM_QSTR(MP_QSTR_sleep_mode), MP_ROM_PTR(&st7789_ST7789_sleep_mode_obj)},
  2431. {MP_ROM_QSTR(MP_QSTR_inversion_mode), MP_ROM_PTR(&st7789_ST7789_inversion_mode_obj)},
  2432. {MP_ROM_QSTR(MP_QSTR_map_bitarray_to_rgb565), MP_ROM_PTR(&st7789_map_bitarray_to_rgb565_obj)},
  2433. {MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&st7789_ST7789_init_obj)},
  2434. {MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&st7789_ST7789_on_obj)},
  2435. {MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&st7789_ST7789_off_obj)},
  2436. {MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&st7789_ST7789_pixel_obj)},
  2437. {MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&st7789_ST7789_line_obj)},
  2438. {MP_ROM_QSTR(MP_QSTR_blit_buffer), MP_ROM_PTR(&st7789_ST7789_blit_buffer_obj)},
  2439. {MP_ROM_QSTR(MP_QSTR_draw), MP_ROM_PTR(&st7789_ST7789_draw_obj)},
  2440. {MP_ROM_QSTR(MP_QSTR_draw_len), MP_ROM_PTR(&st7789_ST7789_draw_len_obj)},
  2441. {MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&st7789_ST7789_bitmap_obj)},
  2442. {MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&st7789_ST7789_fill_rect_obj)},
  2443. {MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&st7789_ST7789_fill_obj)},
  2444. {MP_ROM_QSTR(MP_QSTR_hline), MP_ROM_PTR(&st7789_ST7789_hline_obj)},
  2445. {MP_ROM_QSTR(MP_QSTR_vline), MP_ROM_PTR(&st7789_ST7789_vline_obj)},
  2446. {MP_ROM_QSTR(MP_QSTR_fill_circle), MP_ROM_PTR(&st7789_ST7789_fill_circle_obj)},
  2447. {MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&st7789_ST7789_circle_obj)},
  2448. {MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&st7789_ST7789_rect_obj)},
  2449. {MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&st7789_ST7789_text_obj)},
  2450. {MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&st7789_ST7789_rotation_obj)},
  2451. {MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&st7789_ST7789_width_obj)},
  2452. {MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&st7789_ST7789_height_obj)},
  2453. {MP_ROM_QSTR(MP_QSTR_vscrdef), MP_ROM_PTR(&st7789_ST7789_vscrdef_obj)},
  2454. {MP_ROM_QSTR(MP_QSTR_vscsad), MP_ROM_PTR(&st7789_ST7789_vscsad_obj)},
  2455. {MP_ROM_QSTR(MP_QSTR_madctl), MP_ROM_PTR(&st7789_ST7789_madctl_obj)},
  2456. {MP_ROM_QSTR(MP_QSTR_offset), MP_ROM_PTR(&st7789_ST7789_offset_obj)},
  2457. {MP_ROM_QSTR(MP_QSTR_jpg), MP_ROM_PTR(&st7789_ST7789_jpg_obj)},
  2458. {MP_ROM_QSTR(MP_QSTR_jpg_decode), MP_ROM_PTR(&st7789_ST7789_jpg_decode_obj)},
  2459. {MP_ROM_QSTR(MP_QSTR_png), MP_ROM_PTR(&st7789_ST7789_png_obj)},
  2460. {MP_ROM_QSTR(MP_QSTR_polygon_center), MP_ROM_PTR(&st7789_ST7789_polygon_center_obj)},
  2461. {MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&st7789_ST7789_polygon_obj)},
  2462. {MP_ROM_QSTR(MP_QSTR_fill_polygon), MP_ROM_PTR(&st7789_ST7789_fill_polygon_obj)},
  2463. {MP_ROM_QSTR(MP_QSTR_bounding), MP_ROM_PTR(&st7789_ST7789_bounding_obj)},
  2464. {MP_ROM_QSTR(MP_QSTR_draw40), MP_ROM_PTR(&st7789_ST7789_draw40_obj)},
  2465. };
  2466. STATIC MP_DEFINE_CONST_DICT(st7789_ST7789_locals_dict, st7789_ST7789_locals_dict_table);
  2467. /* methods end */
  2468.  
  2469. #ifdef MP_OBJ_TYPE_GET_SLOT
  2470.  
  2471. MP_DEFINE_CONST_OBJ_TYPE(
  2472. st7789_ST7789_type,
  2473. MP_QSTR_ST7789,
  2474. MP_TYPE_FLAG_NONE,
  2475. print, st7789_ST7789_print,
  2476. make_new, st7789_ST7789_make_new,
  2477. locals_dict, (mp_obj_dict_t *)&st7789_ST7789_locals_dict);
  2478.  
  2479. #else
  2480.  
  2481. const mp_obj_type_t st7789_ST7789_type = {
  2482. {&mp_type_type},
  2483. .name = MP_QSTR_ST7789,
  2484. .print = st7789_ST7789_print,
  2485. .make_new = st7789_ST7789_make_new,
  2486. .locals_dict = (mp_obj_dict_t *)&st7789_ST7789_locals_dict,
  2487. };
  2488.  
  2489. #endif
  2490.  
  2491. mp_obj_t st7789_ST7789_make_new(const mp_obj_type_t *type,
  2492. size_t n_args,
  2493. size_t n_kw,
  2494. const mp_obj_t *all_args) {
  2495. enum {
  2496. ARG_spi,
  2497. ARG_width,
  2498. ARG_height,
  2499. ARG_reset,
  2500. ARG_dc,
  2501. ARG_cs,
  2502. ARG_backlight,
  2503. ARG_rotations,
  2504. ARG_rotation,
  2505. ARG_custom_init,
  2506. ARG_color_order,
  2507. ARG_inversion,
  2508. ARG_options,
  2509. ARG_buffer_size
  2510. };
  2511. static const mp_arg_t allowed_args[] = {
  2512. {MP_QSTR_spi, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL}},
  2513. {MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0}},
  2514. {MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0}},
  2515. {MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
  2516. {MP_QSTR_dc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
  2517. {MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
  2518. {MP_QSTR_backlight, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
  2519. {MP_QSTR_rotations, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
  2520. {MP_QSTR_rotation, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
  2521. {MP_QSTR_custom_init, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
  2522. {MP_QSTR_color_order, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ST7789_MADCTL_RGB}},
  2523. {MP_QSTR_inversion, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true}},
  2524. {MP_QSTR_options, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
  2525. {MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
  2526. };
  2527. mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
  2528. mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
  2529.  
  2530. // create new object
  2531. st7789_ST7789_obj_t *self = m_new_obj(st7789_ST7789_obj_t);
  2532. self->base.type = &st7789_ST7789_type;
  2533.  
  2534. // set parameters
  2535. mp_obj_base_t *spi_obj = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[ARG_spi].u_obj);
  2536. self->spi_obj = spi_obj;
  2537. self->display_width = args[ARG_width].u_int;
  2538. self->width = args[ARG_width].u_int;
  2539. self->display_height = args[ARG_height].u_int;
  2540. self->height = args[ARG_height].u_int;
  2541.  
  2542. self->rotations = NULL;
  2543. self->rotations_len = 4;
  2544.  
  2545. if (args[ARG_rotations].u_obj != MP_OBJ_NULL) {
  2546. size_t len;
  2547. mp_obj_t *rotations_array = MP_OBJ_NULL;
  2548. mp_obj_get_array(args[ARG_rotations].u_obj, &len, &rotations_array);
  2549. self->rotations_len = len;
  2550. self->rotations = m_new(st7789_rotation_t, self->rotations_len);
  2551. for (int i = 0; i < self->rotations_len; i++) {
  2552. mp_obj_t *rotation_tuple = NULL;
  2553. size_t rotation_tuple_len = 0;
  2554.  
  2555. mp_obj_tuple_get(rotations_array[i], &rotation_tuple_len, &rotation_tuple);
  2556. if (rotation_tuple_len != 5) {
  2557. mp_raise_ValueError(MP_ERROR_TEXT("rotations tuple must have 5 elements"));
  2558. }
  2559.  
  2560. self->rotations[i].madctl = mp_obj_get_int(rotation_tuple[0]);
  2561. self->rotations[i].width = mp_obj_get_int(rotation_tuple[1]);
  2562. self->rotations[i].height = mp_obj_get_int(rotation_tuple[2]);
  2563. self->rotations[i].colstart = mp_obj_get_int(rotation_tuple[3]);
  2564. self->rotations[i].rowstart = mp_obj_get_int(rotation_tuple[4]);
  2565. }
  2566. }
  2567.  
  2568. self->rotation = args[ARG_rotation].u_int % self->rotations_len;
  2569. self->custom_init = args[ARG_custom_init].u_obj;
  2570. self->color_order = args[ARG_color_order].u_int;
  2571. self->inversion = args[ARG_inversion].u_bool;
  2572. self->options = args[ARG_options].u_int & 0xff;
  2573. self->buffer_size = args[ARG_buffer_size].u_int;
  2574.  
  2575. if (self->buffer_size) {
  2576. self->i2c_buffer = m_malloc(self->buffer_size);
  2577. } else {
  2578. self->i2c_buffer = NULL;
  2579. }
  2580.  
  2581. if (args[ARG_dc].u_obj == MP_OBJ_NULL) {
  2582. mp_raise_ValueError(MP_ERROR_TEXT("must specify dc pin"));
  2583. }
  2584.  
  2585. if (args[ARG_reset].u_obj != MP_OBJ_NULL) {
  2586. self->reset = mp_hal_get_pin_obj(args[ARG_reset].u_obj);
  2587. } else {
  2588. self->reset = 0;
  2589. }
  2590.  
  2591. self->dc = mp_hal_get_pin_obj(args[ARG_dc].u_obj);
  2592.  
  2593. if (args[ARG_cs].u_obj != MP_OBJ_NULL) {
  2594. self->cs = mp_hal_get_pin_obj(args[ARG_cs].u_obj);
  2595. } else {
  2596. self->cs = 0;
  2597. }
  2598.  
  2599. if (args[ARG_backlight].u_obj != MP_OBJ_NULL) {
  2600. self->backlight = mp_hal_get_pin_obj(args[ARG_backlight].u_obj);
  2601. } else {
  2602. self->backlight = 0;
  2603. }
  2604.  
  2605. self->bounding = 0;
  2606. self->min_x = self->display_width;
  2607. self->min_y = self->display_height;
  2608. self->max_x = 0;
  2609. self->max_y = 0;
  2610.  
  2611. return MP_OBJ_FROM_PTR(self);
  2612. }
  2613.  
  2614. STATIC const mp_map_elem_t st7789_module_globals_table[] = {
  2615. {MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789)},
  2616. {MP_ROM_QSTR(MP_QSTR_color565), (mp_obj_t)&st7789_color565_obj},
  2617. {MP_ROM_QSTR(MP_QSTR_map_bitarray_to_rgb565), (mp_obj_t)&st7789_map_bitarray_to_rgb565_obj},
  2618. {MP_ROM_QSTR(MP_QSTR_ST7789), (mp_obj_t)&st7789_ST7789_type},
  2619. {MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(BLACK)},
  2620. {MP_ROM_QSTR(MP_QSTR_BLUE), MP_ROM_INT(BLUE)},
  2621. {MP_ROM_QSTR(MP_QSTR_RED), MP_ROM_INT(RED)},
  2622. {MP_ROM_QSTR(MP_QSTR_GREEN), MP_ROM_INT(GREEN)},
  2623. {MP_ROM_QSTR(MP_QSTR_CYAN), MP_ROM_INT(CYAN)},
  2624. {MP_ROM_QSTR(MP_QSTR_MAGENTA), MP_ROM_INT(MAGENTA)},
  2625. {MP_ROM_QSTR(MP_QSTR_YELLOW), MP_ROM_INT(YELLOW)},
  2626. {MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(WHITE)},
  2627. {MP_ROM_QSTR(MP_QSTR_FAST), MP_ROM_INT(JPG_MODE_FAST)},
  2628. {MP_ROM_QSTR(MP_QSTR_SLOW), MP_ROM_INT(JPG_MODE_SLOW)},
  2629. {MP_ROM_QSTR(MP_QSTR_MADCTL_MY), MP_ROM_INT(ST7789_MADCTL_MY)},
  2630. {MP_ROM_QSTR(MP_QSTR_MADCTL_MX), MP_ROM_INT(ST7789_MADCTL_MX)},
  2631. {MP_ROM_QSTR(MP_QSTR_MADCTL_MV), MP_ROM_INT(ST7789_MADCTL_MV)},
  2632. {MP_ROM_QSTR(MP_QSTR_MADCTL_ML), MP_ROM_INT(ST7789_MADCTL_ML)},
  2633. {MP_ROM_QSTR(MP_QSTR_MADCTL_MH), MP_ROM_INT(ST7789_MADCTL_MH)},
  2634. {MP_ROM_QSTR(MP_QSTR_RGB), MP_ROM_INT(ST7789_MADCTL_RGB)},
  2635. {MP_ROM_QSTR(MP_QSTR_BGR), MP_ROM_INT(ST7789_MADCTL_BGR)},
  2636. {MP_ROM_QSTR(MP_QSTR_WRAP), MP_ROM_INT(OPTIONS_WRAP)},
  2637. {MP_ROM_QSTR(MP_QSTR_WRAP_H), MP_ROM_INT(OPTIONS_WRAP_H)},
  2638. {MP_ROM_QSTR(MP_QSTR_WRAP_V), MP_ROM_INT(OPTIONS_WRAP_V)}
  2639. };
  2640.  
  2641. STATIC MP_DEFINE_CONST_DICT(mp_module_st7789_globals, st7789_module_globals_table);
  2642.  
  2643. const mp_obj_module_t mp_module_st7789 = {
  2644. .base = {&mp_type_module},
  2645. .globals = (mp_obj_dict_t *)&mp_module_st7789_globals,
  2646. };
  2647.  
  2648. // use the following for older versions of MicroPython
  2649.  
  2650. #if MICROPY_VERSION >= 0x011300 // MicroPython 1.19 or later
  2651. MP_REGISTER_MODULE(MP_QSTR_st7789, mp_module_st7789);
  2652. #else
  2653. MP_REGISTER_MODULE(MP_QSTR_st7789, mp_module_st7789, MODULE_ST7789_ENABLE);
  2654. #endif
  2655.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement