LCDGFX LCD display driver  1.1.5
This library is developed to control SSD1306/SSD1325/SSD1327/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
ssd1306_16bit.inl
1 /*
2  MIT License
3 
4  Copyright (c) 2018-2021, Alexey Dynda
5 
6  Permission is hereby granted, free of charge, to any person obtaining a copy
7  of this software and associated documentation files (the "Software"), to deal
8  in the Software without restriction, including without limitation the rights
9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  copies of the Software, and to permit persons to whom the Software is
11  furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in all
14  copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  SOFTWARE.
23 */
24 
25 #include "lcd_hal/io.h"
26 
27 #if 0
28 void ssd1306_setRgbColor16(uint8_t r, uint8_t g, uint8_t b)
29 {
30  ssd1306_color = RGB_COLOR16(r,g,b);
31 }
32 
33 static void ssd1306_drawBufferPitch16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, lcduint_t pitch, const uint8_t *data)
34 {
35  ssd1306_lcd.set_block(x, y, w);
36  while (h--)
37  {
38  lcduint_t line = w << 1;
39  while (line--)
40  {
41  ssd1306_intf.send( *data );
42  data++;
43  }
44  data += pitch - (w << 1);
45  }
46  ssd1306_intf.stop();
47 }
48 
49 void ssd1306_drawBufferFast16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *data)
50 {
51  ssd1306_drawBufferPitch16(x, y, w, h, w<<1, data);
52 }
53 
54 void ssd1306_drawBufferEx16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, lcduint_t pitch, const uint8_t *data)
55 {
56  ssd1306_drawBufferPitch16( x, y, w, h, pitch, data );
57 }
58 
59 void ssd1306_putColorPixel16(lcdint_t x, lcdint_t y, uint16_t color)
60 {
61  ssd1306_lcd.set_block(x, y, 0);
62  ssd1306_lcd.send_pixels16( color );
63  ssd1306_intf.stop();
64 }
65 
66 void ssd1306_drawBitmap16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
67 {
68  ssd1306_lcd.set_block(xpos, ypos, w);
69  uint32_t count = (w) * (h);
70  while (count--)
71  {
72  ssd1306_lcd.send_pixels16( (pgm_read_byte( &bitmap[0] ) << 8) | pgm_read_byte( &bitmap[1] ) );
73  bitmap += 2;
74  }
75  ssd1306_intf.stop();
76 }
77 
78 void ssd1306_clearBlock16(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
79 {
80  ssd1306_lcd.set_block(x, y, w);
81  uint32_t count = w * h;
82  while (count--)
83  {
84  ssd1306_lcd.send_pixels16( 0x0000 );
85  }
86  ssd1306_intf.stop();
87 }
88 
89 void ssd1306_setCursor16(lcduint_t x, lcduint_t y)
90 {
91  ssd1306_cursorX = x;
92  ssd1306_cursorY = y;
93 }
94 
95 void ssd1306_printChar16(uint8_t c)
96 {
97  uint16_t unicode = ssd1306_unicode16FromUtf8(c);
98  if (unicode == SSD1306_MORE_CHARS_REQUIRED) return;
99  SCharInfo char_info;
100  ssd1306_getCharBitmap(unicode, &char_info);
101  ssd1306_drawMonoBitmap16(ssd1306_cursorX,
102  ssd1306_cursorY,
103  char_info.width,
104  char_info.height,
105  char_info.glyph );
106 }
107 
108 size_t ssd1306_write16(uint8_t ch)
109 {
110  if (ch == '\r')
111  {
112  ssd1306_cursorX = 0;
113  return 0;
114  }
115  else if ( (ssd1306_cursorX > ssd1306_lcd.width - m_font->getHeader().width) || (ch == '\n') )
116  {
117  ssd1306_cursorX = 0;
118  ssd1306_cursorY += m_font->getHeader().height;
119  if ( ssd1306_cursorY > ssd1306_lcd.height - m_font->getHeader().height )
120  {
121  ssd1306_cursorY = 0;
122  }
123  ssd1306_clearBlock16(0, ssd1306_cursorY, ssd1306_lcd.width, m_font->getHeader().height);
124  if (ch == '\n')
125  {
126  return 0;
127  }
128  }
129  uint16_t unicode = m_font->unicode16FromUtf8(ch);
130  if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
131  SCharInfo char_info;
132  m_font->getCharBitmap(unicode, &char_info);
133  ssd1306_drawMonoBitmap16( ssd1306_cursorX,
134  ssd1306_cursorY,
135  char_info.width,
136  char_info.height,
137  char_info.glyph);
138  ssd1306_cursorX += char_info.width + char_info.spacing;
139  return 1;
140 }
141 
142 size_t ssd1306_print16(const char ch[])
143 {
144  size_t n = 0;
145  while (*ch)
146  {
147  n += ssd1306_write16(*ch);
148  ch++;
149  }
150  return n;
151 }
152 
153 uint8_t ssd1306_printFixed16(lcdint_t x, lcdint_t y, const char *ch, EFontStyle style)
154 {
155  ssd1306_cursorX = x;
156  ssd1306_cursorY = y;
157  return ssd1306_print16(ch);
158 }
159 
160 #endif
161 
163 //
164 // 16-BIT GRAPHICS
165 //
167 
168 template <class I> void NanoDisplayOps16<I>::putPixel(lcdint_t x, lcdint_t y)
169 {
170  this->m_intf.startBlock(x, y, 0);
171  this->m_intf.send(this->m_color >> 8);
172  this->m_intf.send(this->m_color & 0xFF);
173  this->m_intf.endBlock();
174 }
175 
176 template <class I> void NanoDisplayOps16<I>::drawHLine(lcdint_t x1, lcdint_t y1, lcdint_t x2)
177 {
178  this->m_intf.startBlock(x1, y1, 0);
179  while ( x1 < x2 )
180  {
181  this->m_intf.send(this->m_color >> 8);
182  this->m_intf.send(this->m_color & 0xFF);
183  x1++;
184  }
185  this->m_intf.endBlock();
186 }
187 
188 template <class I> void NanoDisplayOps16<I>::drawVLine(lcdint_t x1, lcdint_t y1, lcdint_t y2)
189 {
190  this->m_intf.startBlock(x1, y1, 1);
191  while ( y1 <= y2 )
192  {
193  this->m_intf.send(this->m_color >> 8);
194  this->m_intf.send(this->m_color & 0xFF);
195  y1++;
196  }
197  this->m_intf.endBlock();
198 }
199 
200 template <class I> void NanoDisplayOps16<I>::fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
201 {
202  if ( y1 > y2 )
203  {
204  ssd1306_swap_data(y1, y2, lcdint_t);
205  }
206  if ( x1 > x2 )
207  {
208  ssd1306_swap_data(x1, x2, lcdint_t);
209  }
210  this->m_intf.startBlock(x1, y1, x2 - x1 + 1);
211  uint16_t count = (x2 - x1 + 1) * (y2 - y1 + 1);
212  while ( count-- )
213  {
214  this->m_intf.send(this->m_color >> 8);
215  this->m_intf.send(this->m_color & 0xFF);
216  }
217  this->m_intf.endBlock();
218 }
219 
220 template <class I> void NanoDisplayOps16<I>::fill(uint16_t color)
221 {
222  this->m_intf.startBlock(0, 0, 0);
223  uint32_t count = (uint32_t)this->m_w * (uint32_t)this->m_h;
224  while ( count-- )
225  {
226  this->m_intf.send(color >> 8);
227  this->m_intf.send(color & 0xFF);
228  }
229  this->m_intf.endBlock();
230 }
231 
232 template <class I> void NanoDisplayOps16<I>::clear()
233 {
234  fill(0x00);
235 }
236 
237 template <class I>
239 {
240  // TODO:
241 }
242 
243 template <class I>
244 void NanoDisplayOps16<I>::drawBitmap1(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
245 {
246  uint8_t bit = 1;
247  uint16_t blackColor = this->m_bgColor;
248  uint16_t color = this->m_color;
249  this->m_intf.startBlock(xpos, ypos, w);
250  while ( h-- )
251  {
252  lcduint_t wx = w;
253  while ( wx-- )
254  {
255  uint8_t data = pgm_read_byte(bitmap);
256  if ( data & bit )
257  {
258  this->m_intf.send(color >> 8);
259  this->m_intf.send(color & 0xFF);
260  }
261  else
262  {
263  this->m_intf.send(blackColor >> 8);
264  this->m_intf.send(blackColor & 0xFF);
265  }
266  bitmap++;
267  }
268  bit <<= 1;
269  if ( bit == 0 )
270  {
271  bit = 1;
272  }
273  else
274  {
275  bitmap -= w;
276  }
277  }
278  this->m_intf.endBlock();
279 }
280 
281 template <class I>
283 {
284  // NOT IMPLEMENTED
285 }
286 
287 template <class I>
289 {
290  this->m_intf.startBlock(x, y, w);
291  uint32_t count = (w) * (h);
292  while ( count-- )
293  {
294  uint16_t color = RGB8_TO_RGB16(pgm_read_byte(bitmap));
295  this->m_intf.send(color >> 8);
296  this->m_intf.send(color & 0xFF);
297  bitmap++;
298  }
299  this->m_intf.endBlock();
300 }
301 
302 template <class I>
304 {
305  this->m_intf.startBlock(x, y, w);
306  uint32_t count = (w) * (h);
307  while ( count-- )
308  {
309  this->m_intf.send(pgm_read_byte(&bitmap[0]));
310  this->m_intf.send(pgm_read_byte(&bitmap[1]));
311  bitmap += 2;
312  }
313  this->m_intf.endBlock();
314 }
315 
316 template <class I>
317 void NanoDisplayOps16<I>::drawBuffer1(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *buffer)
318 {
319  uint8_t bit = 1;
320  uint16_t blackColor = this->m_bgColor;
321  uint16_t color = this->m_color;
322  this->m_intf.startBlock(xpos, ypos, w);
323  while ( h-- )
324  {
325  lcduint_t wx = w;
326  while ( wx-- )
327  {
328  uint8_t data = *buffer;
329  if ( data & bit )
330  {
331  this->m_intf.send(color >> 8);
332  this->m_intf.send(color & 0xFF);
333  }
334  else
335  {
336  this->m_intf.send(blackColor >> 8);
337  this->m_intf.send(blackColor & 0xFF);
338  }
339  buffer++;
340  }
341  bit <<= 1;
342  if ( bit == 0 )
343  {
344  bit = 1;
345  }
346  else
347  {
348  buffer -= w;
349  }
350  }
351  this->m_intf.endBlock();
352 }
353 
354 template <class I>
356 {
357  this->drawBuffer1(x, y, w, h, buf);
358 }
359 
360 template <class I>
362 {
363  // NOT IMPLEMENTED
364 }
365 
366 template <class I>
368 {
369  this->m_intf.startBlock(x, y, w);
370  uint32_t count = (w) * (h);
371  while ( count-- )
372  {
373  uint16_t color = RGB8_TO_RGB16((*buffer));
374  this->m_intf.send(color >> 8);
375  this->m_intf.send(color & 0xFF);
376  buffer++;
377  }
378  this->m_intf.endBlock();
379 }
380 
381 template <class I>
383 {
384  this->m_intf.startBlock(x, y, w);
385  uint32_t count = (w) * (h);
386  while ( count-- )
387  {
388  this->m_intf.send(buffer[0]);
389  this->m_intf.send(buffer[1]);
390  buffer += 2;
391  }
392  this->m_intf.endBlock();
393 }
394 
395 template <class I> uint8_t NanoDisplayOps16<I>::printChar(uint8_t c)
396 {
397  uint16_t unicode = this->m_font->unicode16FromUtf8(c);
398  if ( unicode == SSD1306_MORE_CHARS_REQUIRED )
399  return 0;
400  SCharInfo char_info;
401  this->m_font->getCharBitmap(unicode, &char_info);
402  uint8_t mode = this->m_textMode;
403  for ( uint8_t i = 0; i < (this->m_fontStyle == STYLE_BOLD ? 2 : 1); i++ )
404  {
405  this->drawBitmap1(this->m_cursorX + i, this->m_cursorY, char_info.width, char_info.height, char_info.glyph);
406  this->m_textMode |= CANVAS_MODE_TRANSPARENT;
407  }
408  this->m_textMode = mode;
409  if ( char_info.height < (lcdint_t)this->m_font->getHeader().height )
410  {
411  this->invertColors();
412  this->fillRect(this->m_cursorX, this->m_cursorY + char_info.height, this->m_cursorX + char_info.width - 1,
413  this->m_cursorY + (lcdint_t)this->m_font->getHeader().height - 1);
414  this->invertColors();
415  }
416  this->m_cursorX += (lcdint_t)(char_info.width + char_info.spacing);
417  if ( char_info.spacing > 0 )
418  {
419  this->invertColors();
420  this->fillRect(this->m_cursorX - char_info.spacing, this->m_cursorY, this->m_cursorX - 1,
421  this->m_cursorY + (lcdint_t)this->m_font->getHeader().height - 1);
422  this->invertColors();
423  }
424  if ( ((this->m_textMode & CANVAS_TEXT_WRAP_LOCAL) &&
425  (this->m_cursorX > ((lcdint_t)this->m_w - (lcdint_t)this->m_font->getHeader().width))) ||
426  ((this->m_textMode & CANVAS_TEXT_WRAP) &&
427  (this->m_cursorX > ((lcdint_t)this->m_w - (lcdint_t)this->m_font->getHeader().width))) )
428  {
429  this->m_cursorY += (lcdint_t)this->m_font->getHeader().height;
430  this->m_cursorX = 0;
431  if ( (this->m_textMode & CANVAS_TEXT_WRAP_LOCAL) &&
432  (this->m_cursorY > ((lcdint_t)this->m_h - (lcdint_t)this->m_font->getHeader().height)) )
433  {
434  this->m_cursorY = 0;
435  }
436  }
437  return 1;
438 }
439 
440 template <class I> size_t NanoDisplayOps16<I>::write(uint8_t c)
441 {
442  if ( c == '\n' )
443  {
444  this->m_cursorY += (lcdint_t)this->m_font->getHeader().height;
445  this->m_cursorX = 0;
446  }
447  else if ( c == '\r' )
448  {
449  // skip non-printed char
450  }
451  else
452  {
453  return printChar(c);
454  }
455  return 1;
456 }
457 
458 template <class I> void NanoDisplayOps16<I>::printFixed(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style)
459 {
460  // TODO: fontstyle not supported
461  // m_fontStyle = style;
462  this->m_cursorX = xpos;
463  this->m_cursorY = y;
464  while ( *ch )
465  {
466  this->write(*ch);
467  ch++;
468  }
469 }
470 
471 template <class I>
472 void NanoDisplayOps16<I>::printFixedN(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style, uint8_t factor)
473 {
474  uint8_t i, j = 0;
475  uint8_t text_index = 0;
476  uint8_t page_offset = 0;
477  uint8_t x = xpos;
478  for ( ;; )
479  {
480  uint8_t ldata;
481  if ( (x > this->m_w - (this->m_font->getHeader().width << factor)) || (ch[j] == '\0') )
482  {
483  x = xpos;
484  y += 8;
485  if ( y >= this->m_h )
486  {
487  break;
488  }
489  page_offset++;
490  if ( page_offset == (this->m_font->getPages() << factor) )
491  {
492  text_index = j;
493  page_offset = 0;
494  if ( ch[j] == '\0' )
495  {
496  break;
497  }
498  }
499  else
500  {
501  j = text_index;
502  }
503  }
504  uint16_t unicode;
505  do
506  {
507  unicode = this->m_font->unicode16FromUtf8(ch[j]);
508  j++;
509  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
510  SCharInfo char_info;
511  this->m_font->getCharBitmap(unicode, &char_info);
512  ldata = 0;
513  if ( char_info.height > (page_offset >> factor) * 8 )
514  {
515  char_info.glyph += (page_offset >> factor) * char_info.width;
516  for ( i = char_info.width; i > 0; i-- )
517  {
518  uint8_t data;
519  if ( style == STYLE_NORMAL )
520  {
521  data = pgm_read_byte(char_info.glyph);
522  }
523  else if ( style == STYLE_BOLD )
524  {
525  uint8_t temp = pgm_read_byte(char_info.glyph);
526  data = temp | ldata;
527  ldata = temp;
528  }
529  else
530  {
531  uint8_t temp = pgm_read_byte(char_info.glyph + 1);
532  data = (temp & 0xF0) | ldata;
533  ldata = (temp & 0x0F);
534  }
535  if ( factor > 0 )
536  {
537  uint8_t accum = 0;
538  uint8_t mask = ~((0xFF) << (1 << factor));
539  // N=0 -> right shift is always 0
540  // N=1 -> right shift goes through 0, 4
541  // N=2 -> right shift goes through 0, 2, 4, 6
542  // N=3 -> right shift goes through 0, 1, 2, 3, 4, 5, 6, 7
543  data >>= ((page_offset & ((1 << factor) - 1)) << (3 - factor));
544  for ( uint8_t idx = 0; idx < 1 << (3 - factor); idx++ )
545  {
546  accum |= (((data >> idx) & 0x01) ? (mask << (idx << factor)) : 0);
547  }
548  data = accum;
549  }
550  this->m_intf.startBlock(x, y, (1 << factor));
551  for ( uint8_t b = 0; b < 8; b++ )
552  {
553  uint16_t color = (data & (1 << b)) ? this->m_color : this->m_bgColor;
554  for ( uint8_t z = (1 << factor); z > 0; z-- )
555  {
556  this->m_intf.send(color >> 8);
557  this->m_intf.send(color & 0xFF);
558  }
559  }
560  this->m_intf.endBlock();
561  x += (1 << factor);
562  char_info.glyph++;
563  }
564  }
565  else
566  {
567  char_info.spacing += char_info.width;
568  x += (char_info.width << factor);
569  }
570  this->m_intf.startBlock(x, y, (char_info.spacing << factor));
571  for ( uint8_t b = 0; b < 8; b++ )
572  {
573  uint16_t color = this->m_bgColor;
574  for ( i = 0; i < (char_info.spacing << factor); i++ )
575  {
576  this->m_intf.send(color >> 8);
577  this->m_intf.send(color & 0xFF);
578  }
579  }
580  x += (char_info.spacing << factor);
581  this->m_intf.endBlock();
582  }
583 }
uint8_t printChar(uint8_t c)
uint8_t height
char height in pixels
Definition: canvas_types.h:144
uint8_t lcduint_t
Definition: canvas_types.h:79
#define RGB_COLOR16(r, g, b)
Definition: canvas_types.h:64
void drawVLine(lcdint_t x1, lcdint_t y1, lcdint_t y2)
void drawHLine(lcdint_t x1, lcdint_t y1, lcdint_t x2)
size_t write(uint8_t c) __attribute__((noinline))
int8_t lcdint_t
Definition: canvas_types.h:77
#define SSD1306_MORE_CHARS_REQUIRED
Definition: canvas_types.h:43
void drawBitmap8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
Draws 8-bit color bitmap in color buffer. Draws 8-bit color bitmap in color buffer.
#define RGB8_TO_RGB16(c)
Definition: canvas_types.h:67
void printFixedN(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style, uint8_t factor) __attribute__((noinline))
void drawBuffer1Fast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer)
uint8_t width
char width in pixels
Definition: canvas_types.h:143
const uint8_t * glyph
char data, located in progmem.
Definition: canvas_types.h:146
void fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__((noinline))
void drawBuffer16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *buffer) __attribute__((noinline))
void drawBuffer8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer)
void drawBuffer1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer) __attribute__((noinline))
void printFixed(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style=STYLE_NORMAL) __attribute__((noinline))
void putPixel(lcdint_t x, lcdint_t y) __attribute__((noinline))
uint8_t spacing
additional spaces after char in pixels
Definition: canvas_types.h:145
EFontStyle
Definition: canvas_types.h:88
void drawXBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
void drawBitmap1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap) __attribute__((noinline))
Draws monochrome bitmap in color buffer using color, specified via setColor() method Draws monochrome...
void drawBuffer4(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer) __attribute__((noinline))
void drawBitmap16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
void drawBitmap4(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap) __attribute__((noinline))
Draws 4-bit gray-color bitmap in color buffer. Draws 4-bit gray-color bitmap in color buffer...
#define ssd1306_swap_data(a, b, type)
Definition: io.h:114
void fill(uint16_t color)