PageRenderTime 28ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/oled.c

https://gitlab.com/ondrejsika-other/hww
C | 406 lines | 297 code | 43 blank | 66 comment | 49 complexity | c8f8373ed9386e7bdee0020412c6a0a7 MD5 | raw file
  1. /*
  2. * This file is part of the TREZOR project.
  3. *
  4. * Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
  5. *
  6. * This library is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this library. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <libopencm3/stm32/gpio.h>
  20. #include <libopencm3/stm32/spi.h>
  21. #include <string.h>
  22. #include "oled.h"
  23. #include "util.h"
  24. #define OLED_SETCONTRAST 0x81
  25. #define OLED_DISPLAYALLON_RESUME 0xA4
  26. #define OLED_DISPLAYALLON 0xA5
  27. #define OLED_NORMALDISPLAY 0xA6
  28. #define OLED_INVERTDISPLAY 0xA7
  29. #define OLED_DISPLAYOFF 0xAE
  30. #define OLED_DISPLAYON 0xAF
  31. #define OLED_SETDISPLAYOFFSET 0xD3
  32. #define OLED_SETCOMPINS 0xDA
  33. #define OLED_SETVCOMDETECT 0xDB
  34. #define OLED_SETDISPLAYCLOCKDIV 0xD5
  35. #define OLED_SETPRECHARGE 0xD9
  36. #define OLED_SETMULTIPLEX 0xA8
  37. #define OLED_SETLOWCOLUMN 0x00
  38. #define OLED_SETHIGHCOLUMN 0x10
  39. #define OLED_SETSTARTLINE 0x40
  40. #define OLED_MEMORYMODE 0x20
  41. #define OLED_COMSCANINC 0xC0
  42. #define OLED_COMSCANDEC 0xC8
  43. #define OLED_SEGREMAP 0xA0
  44. #define OLED_CHARGEPUMP 0x8D
  45. #define SPI_BASE SPI1
  46. #define OLED_DC_PORT GPIOB
  47. #define OLED_DC_PIN GPIO0 // PB0 | Data/Command
  48. #define OLED_CS_PORT GPIOA
  49. #define OLED_CS_PIN GPIO4 // PA4 | SPI Select
  50. #define OLED_RST_PORT GPIOB
  51. #define OLED_RST_PIN GPIO1 // PB1 | Reset display
  52. /* TREZOR has a display of size OLED_WIDTH x OLED_HEIGHT (128x64).
  53. * The contents of this display are buffered in _oledbuffer. This is
  54. * an array of OLED_WIDTH * OLED_HEIGHT/8 bytes. At byte y*OLED_WIDTH + x
  55. * it stores the column of pixels from (x,8y) to (x,8y+7); the LSB stores
  56. * the top most pixel. The pixel (0,0) is the top left corner of the
  57. * display.
  58. */
  59. /* Macros to manipulate a single pixel in _oledbuffer:
  60. * OLED_BUFSET(X,Y) sets pixel X,Y (white)
  61. * OLED_BUFCLR(X,Y) clears pixel X,Y (black)
  62. * OLED_BUFTGL(X,Y) toggles pixel X,Y (inverts it)
  63. */
  64. #define OLED_BUFSET(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] |= (1 << (7 - (Y)%8))
  65. #define OLED_BUFCLR(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] &= ~(1 << (7 - (Y)%8))
  66. #define OLED_BUFTGL(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] ^= (1 << (7 - (Y)%8))
  67. static uint8_t _oledbuffer[OLED_BUFSIZE];
  68. static bool is_debug_mode = 0;
  69. /*
  70. * Send a block of data via the SPI bus.
  71. */
  72. inline void SPISend(uint32_t base, uint8_t *data, int len)
  73. {
  74. int i;
  75. delay(400);
  76. for (i = 0; i < len; i++) {
  77. spi_send(base, data[i]);
  78. }
  79. delay(800);
  80. }
  81. /*
  82. * Initialize the display.
  83. */
  84. void oledInit()
  85. {
  86. static uint8_t s[25] = {
  87. OLED_DISPLAYOFF,
  88. OLED_SETDISPLAYCLOCKDIV,
  89. 0x80,
  90. OLED_SETMULTIPLEX,
  91. 0x3F, // 128x64
  92. OLED_SETDISPLAYOFFSET,
  93. 0x00,
  94. OLED_SETSTARTLINE | 0x00,
  95. OLED_CHARGEPUMP,
  96. 0x14,
  97. OLED_MEMORYMODE,
  98. 0x00,
  99. OLED_SEGREMAP | 0x01,
  100. OLED_COMSCANDEC,
  101. OLED_SETCOMPINS,
  102. 0x12, // 128x64
  103. OLED_SETCONTRAST,
  104. 0xCF,
  105. OLED_SETPRECHARGE,
  106. 0xF1,
  107. OLED_SETVCOMDETECT,
  108. 0x40,
  109. OLED_DISPLAYALLON_RESUME,
  110. OLED_NORMALDISPLAY,
  111. OLED_DISPLAYON
  112. };
  113. gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD
  114. gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
  115. // Reset the LCD
  116. gpio_set(OLED_RST_PORT, OLED_RST_PIN);
  117. delay(40);
  118. gpio_clear(OLED_RST_PORT, OLED_RST_PIN);
  119. delay(400);
  120. gpio_set(OLED_RST_PORT, OLED_RST_PIN);
  121. // init
  122. gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select
  123. SPISend(SPI_BASE, s, 25);
  124. gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
  125. oledClear();
  126. oledRefresh();
  127. }
  128. /*
  129. * Clears the display buffer (sets all pixels to black)
  130. */
  131. void oledClear()
  132. {
  133. memset(_oledbuffer, 0, sizeof(_oledbuffer));
  134. }
  135. /*
  136. * Refresh the display. This copies the buffer to the display to show the
  137. * contents. This must be called after every operation to the buffer to
  138. * make the change visible. All other operations only change the buffer
  139. * not the content of the display.
  140. */
  141. void oledRefresh()
  142. {
  143. static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00};
  144. // draw triangle in upper right corner
  145. if (is_debug_mode) {
  146. OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0);
  147. OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1);
  148. OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2);
  149. OLED_BUFTGL(OLED_WIDTH - 2, 3); OLED_BUFTGL(OLED_WIDTH - 1, 3);
  150. OLED_BUFTGL(OLED_WIDTH - 1, 4);
  151. }
  152. gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select
  153. SPISend(SPI_BASE, s, 3);
  154. gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
  155. gpio_set(OLED_DC_PORT, OLED_DC_PIN); // set to DATA
  156. gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select
  157. SPISend(SPI_BASE, _oledbuffer, sizeof(_oledbuffer));
  158. gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
  159. gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD
  160. // return it back
  161. if (is_debug_mode) {
  162. OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0);
  163. OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1);
  164. OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2);
  165. OLED_BUFTGL(OLED_WIDTH - 2, 3); OLED_BUFTGL(OLED_WIDTH - 1, 3);
  166. OLED_BUFTGL(OLED_WIDTH - 1, 4);
  167. }
  168. }
  169. const uint8_t *oledGetBuffer()
  170. {
  171. return _oledbuffer;
  172. }
  173. void oledSetDebug(bool set)
  174. {
  175. is_debug_mode = set;
  176. oledRefresh();
  177. }
  178. void oledSetBuffer(uint8_t *buf)
  179. {
  180. memcpy(_oledbuffer, buf, sizeof(_oledbuffer));
  181. }
  182. void oledDrawPixel(int x, int y)
  183. {
  184. if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return;
  185. OLED_BUFSET(x,y);
  186. }
  187. void oledClearPixel(int x, int y)
  188. {
  189. if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return;
  190. OLED_BUFCLR(x,y);
  191. }
  192. void oledDrawChar(int x, int y, char c, int zoom)
  193. {
  194. int char_width;
  195. const uint8_t *char_data;
  196. if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return;
  197. char_width = fontCharWidth(c);
  198. char_data = fontCharData(c);
  199. int xo, yo;
  200. for (xo = 0; xo < char_width; xo++) {
  201. for (yo = 0; yo < FONT_HEIGHT; yo++) {
  202. if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) {
  203. if (zoom <= 1) {
  204. oledDrawPixel(x + xo, y + yo);
  205. } else {
  206. oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1, y + (yo + 1) * zoom - 1, true);
  207. }
  208. }
  209. }
  210. }
  211. }
  212. char oledConvertChar(const char c) {
  213. uint8_t a = c;
  214. if (a < 0x80) return c;
  215. // UTF-8 handling: https://en.wikipedia.org/wiki/UTF-8#Description
  216. // bytes 11xxxxxx are first byte of UTF-8 characters
  217. // bytes 10xxxxxx are successive UTF-8 characters
  218. if (a >= 0xC0) return '_';
  219. return 0;
  220. }
  221. int oledStringWidth(const char *text) {
  222. if (!text) return 0;
  223. int l = 0;
  224. char c;
  225. for (; *text; text++) {
  226. c = oledConvertChar(*text);
  227. if (c) {
  228. l += fontCharWidth(c) + 1;
  229. }
  230. }
  231. return l;
  232. }
  233. void oledDrawString(int x, int y, const char* text)
  234. {
  235. if (!text) return;
  236. int size = 1;
  237. if (*text == 0x01) { // double size
  238. text++;
  239. size = 2;
  240. }
  241. int l = 0;
  242. char c;
  243. for (; *text; text++) {
  244. c = oledConvertChar(*text);
  245. if (c) {
  246. oledDrawChar(x + l, y, c, size);
  247. l += size * (fontCharWidth(c) + 1);
  248. }
  249. }
  250. }
  251. void oledDrawStringCenter(int y, const char* text)
  252. {
  253. int x = ( OLED_WIDTH - oledStringWidth(text) ) / 2;
  254. oledDrawString(x, y, text);
  255. }
  256. void oledDrawStringRight(int x, int y, const char* text)
  257. {
  258. x -= oledStringWidth(text);
  259. oledDrawString(x, y, text);
  260. }
  261. #define min(X,Y) ((X) < (Y) ? (X) : (Y))
  262. void oledDrawBitmap(int x, int y, const BITMAP *bmp)
  263. {
  264. int i, j;
  265. for (i = 0; i < min(bmp->width, OLED_WIDTH - x); i++) {
  266. for (j = 0; j < min(bmp->height, OLED_HEIGHT - y); j++) {
  267. if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) {
  268. OLED_BUFSET(x + i, y + j);
  269. } else {
  270. OLED_BUFCLR(x + i, y + j);
  271. }
  272. }
  273. }
  274. }
  275. void oledInvert(int x1, int y1, int x2, int y2)
  276. {
  277. if ((x1 >= OLED_WIDTH) || (y1 >= OLED_HEIGHT) || (x2 >= OLED_WIDTH) || (y2 >= OLED_HEIGHT)) return;
  278. int x, y;
  279. for (x = x1; x <= x2; x++) {
  280. for (y = y1; y <= y2; y++) {
  281. OLED_BUFTGL(x,y);
  282. }
  283. }
  284. }
  285. /*
  286. * Draw a filled rectangle.
  287. */
  288. void oledBox(int x1, int y1, int x2, int y2, bool set)
  289. {
  290. int x, y;
  291. for (x = x1; x <= x2; x++) {
  292. for (y = y1; y <= y2; y++) {
  293. set ? oledDrawPixel(x, y) : oledClearPixel(x, y);
  294. }
  295. }
  296. }
  297. void oledHLine(int y) {
  298. int x;
  299. for (x = 0; x < OLED_WIDTH; x++) {
  300. oledDrawPixel(x, y);
  301. }
  302. }
  303. /*
  304. * Draw a rectangle frame.
  305. */
  306. void oledFrame(int x1, int y1, int x2, int y2)
  307. {
  308. int x, y;
  309. for (x = x1; x <= x2; x++) {
  310. oledDrawPixel(x, y1);
  311. oledDrawPixel(x, y2);
  312. }
  313. for (y = y1 + 1; y < y2; y++) {
  314. oledDrawPixel(x1, y);
  315. oledDrawPixel(x2, y);
  316. }
  317. }
  318. /*
  319. * Animates the display, swiping the current contents out to the left.
  320. * This clears the display.
  321. */
  322. void oledSwipeLeft(void)
  323. {
  324. int i, j, k;
  325. for (i = 0; i < OLED_WIDTH / 4; i++) {
  326. for (j = 0; j < OLED_HEIGHT / 8; j++) {
  327. for (k = OLED_WIDTH / 4 - 1; k > 0; k--) {
  328. _oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 1 + j * OLED_WIDTH];
  329. _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 2 + j * OLED_WIDTH];
  330. _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 3 + j * OLED_WIDTH];
  331. _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 4 + j * OLED_WIDTH];
  332. }
  333. _oledbuffer[j * OLED_WIDTH] = 0;
  334. _oledbuffer[j * OLED_WIDTH + 1] = 0;
  335. _oledbuffer[j * OLED_WIDTH + 2] = 0;
  336. _oledbuffer[j * OLED_WIDTH + 3] = 0;
  337. }
  338. oledRefresh();
  339. }
  340. }
  341. /*
  342. * Animates the display, swiping the current contents out to the right.
  343. * This clears the display.
  344. */
  345. void oledSwipeRight(void)
  346. {
  347. int i, j, k;
  348. for (i = 0; i < OLED_WIDTH / 4; i++) {
  349. for (j = 0; j < OLED_HEIGHT / 8; j++) {
  350. for (k = 0; k < OLED_WIDTH / 4 - 1; k++) {
  351. _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 4 + j * OLED_WIDTH];
  352. _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 5 + j * OLED_WIDTH];
  353. _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 6 + j * OLED_WIDTH];
  354. _oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 7 + j * OLED_WIDTH];
  355. }
  356. _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 1] = 0;
  357. _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 2] = 0;
  358. _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 3] = 0;
  359. _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 4] = 0;
  360. }
  361. oledRefresh();
  362. }
  363. }