SSD1306 OLED display driver  1.5.0
This library is developed to control SSD1306/SSD1331 RGB i2c/spi OLED displays and spi PCD8544 LED display
nano_gfx.cpp
1 /*
2  MIT License
3 
4  Copyright (c) 2016-2018, 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 "nano_gfx.h"
26 #include "ssd1306.h"
27 
28 extern const uint8_t *s_font6x8;
30 
31 #define YADDR(y) (static_cast<uint16_t>((y) >> 3) << m_p)
32 #define BADDR(b) ((b) << m_p)
33 
34 void NanoCanvas::putPixel(uint8_t x, uint8_t y)
35 {
36  if ((x>=m_w) || (y>=m_h)) return;
37  if (m_invertByte)
38  {
39  m_bytes[YADDR(y) + x] &= ((1 << (y & 0x7))^m_invertByte);
40  }
41  else
42  {
43  m_bytes[YADDR(y) + x] |= (1 << (y & 0x7));
44  }
45 };
46 
47 void NanoCanvas::drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
48 {
49  if (y1 >= m_h) return;
50  if (x2 < x1) x1 = 0;
51  if (x1 >= m_w) return;
52  if (x2 >= m_w) x2 = m_w - 1;
53  for(uint8_t x = x1; x<=x2; x++)
54  m_bytes[YADDR(y1) + x] |= (1 << (y1 & 0x7));
55 };
56 
57 void NanoCanvas::drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
58 {
59  if (x1 >= m_w) return;
60  if (y2 < y1) y1 = 0;
61  if (y1 >= m_h) return;
62  if (y2 >= m_h) y2 = m_h - 1;
63  for(uint8_t y = y1; y<=y2; y++)
64  m_bytes[YADDR(y) + x1] |= (1 << (y & 0x7));
65 };
66 
67 void NanoCanvas::drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
68 {
69  drawHLine(x1, y1, x2);
70  drawHLine(x1, y2, x2);
71  drawVLine(x1, y1, y2);
72  drawVLine(x2, y1, y2);
73 };
74 
75 
76 void NanoCanvas::fillRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t templ)
77 {
78  templ ^= m_invertByte;
79  if ((x1 < x2) && (x1 >= m_w)) return;
80  if ((y1 < y2) && (y1 >= m_h)) return;
81  if (x1 > x2) x1 = 0;
82  if (y1 > y2) y1 = 0;
83  if (x2 >= m_w) x2 = m_w -1;
84  if (y2 >= m_h) y2 = m_h -1;
85  uint8_t bank1 = (y1 >> 3);
86  uint8_t bank2 = (y2 >> 3);
87  for (uint8_t bank = bank1; bank<=bank2; bank++)
88  {
89  uint8_t mask = 0xFF;
90  if (bank1 == bank2)
91  {
92  mask = (mask >> ((y1 & 7) + 7 - (y2 & 7))) << (y1 & 7);
93  }
94  else if (bank1 == bank)
95  {
96  mask = (mask << (y1 & 7));
97  }
98  else if (bank2 == bank)
99  {
100  mask = (mask >> (7 - (y2 & 7)));
101  }
102  for (uint8_t x=x1; x<=x2; x++)
103  {
104  m_bytes[BADDR(bank) + x] &= ~mask;
105  m_bytes[BADDR(bank) + x] |= (templ & mask);
106  }
107  }
108 };
109 
110 
112 {
113  for(uint16_t i=0; i< static_cast<uint16_t>(m_w) * (m_h >> 3); i++)
114  {
115  m_bytes[i] = m_invertByte;
116  }
117 }
118 
119 
120 void NanoCanvas::charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
121 {
122  uint8_t i, j, topMask, bottomMask;
123  if (y>=m_h) return;
124  j = 0;
125  topMask = (0xFF >> (8 - (y & 0x7)));
126  bottomMask = (0xFF << (y & 0x7));
127  while(ch[j] != '\0')
128  {
129  uint8_t c = ch[j] - 32;
130  uint8_t ldata = 0;
131  for(i=0;i<6;i++)
132  {
133  if (x>=m_w) return;
134  uint8_t data;
135  if ( style == STYLE_NORMAL )
136  {
137  data = pgm_read_byte(&s_font6x8[c*6+i]);
138  }
139  else if ( style == STYLE_BOLD )
140  {
141  data = pgm_read_byte(&s_font6x8[c*6+i]);
142  uint8_t temp = data | ldata;
143  ldata = data;
144  data = temp;
145  }
146  else
147  {
148  data = pgm_read_byte(&s_font6x8[c*6+i + 1]);
149  uint8_t temp = (data & 0xF0) | ldata;
150  ldata = (data & 0x0F);
151  data = temp;
152  }
153  m_bytes[YADDR(y) + x] &= topMask;
154  m_bytes[YADDR(y) + x] |= (data << (y & 0x7));
155  if (y+8 < m_h)
156  {
157  m_bytes[YADDR(y) + m_w + x] &= bottomMask;
158  m_bytes[YADDR(y) + m_w + x] |= (data >> (8 - (y & 0x7)));
159  }
160  x++;
161  }
162  j++;
163  }
164 }
165 
166 void NanoCanvas::charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
167 {
168  uint8_t i, j = 0;
169  uint8_t text_index = 0;
170  uint8_t odd = 0;
171  uint8_t x = xpos;
172  uint8_t topMask, bottomMask;
173  if ( y >= m_h ) return;
174  topMask = (0xFF >> (8 - (y & 0x7)));
175  bottomMask = (0xFF << (y & 0x7));
176  for(;;)
177  {
178  if( ( x > m_w - 12 ) || ( ch[j] == '\0' ) )
179  {
180  x = xpos;
181  y += 8;
182  if (y > (m_h - 8))
183  {
184  break;
185  }
186  if (odd)
187  {
188  text_index = j;
189  if (ch[j] == '\0')
190  {
191  break;
192  }
193  }
194  else
195  {
196  j = text_index;
197  }
198  odd = !odd;
199  }
200  uint8_t c = ch[j] - 32;
201  uint8_t ldata = 0;
202  for( i=0; i<6; i++)
203  {
204  uint8_t data;
205  if ( style == STYLE_NORMAL )
206  {
207  data = pgm_read_byte(&s_font6x8[c*6+i]);
208  }
209  else if ( style == STYLE_BOLD )
210  {
211  data = pgm_read_byte(&s_font6x8[c*6+i]);
212  uint8_t temp = data | ldata;
213  ldata = data;
214  data = temp;
215  }
216  else
217  {
218  data = pgm_read_byte(&s_font6x8[c*6+i + 1]);
219  uint8_t temp = (data & 0xF0) | ldata;
220  ldata = (data & 0x0F);
221  data = temp;
222  }
223  if (odd) data >>= 4;
224  data = ((data & 0x01) ? 0x03: 0x00) |
225  ((data & 0x02) ? 0x0C: 0x00) |
226  ((data & 0x04) ? 0x30: 0x00) |
227  ((data & 0x08) ? 0xC0: 0x00);
228 
229  for (uint8_t n=2; n>0; n--)
230  {
231  m_bytes[YADDR(y) + x] &= topMask;
232  m_bytes[YADDR(y) + x] |= (data << (y & 0x7));
233  if (y+8 < m_h)
234  {
235  m_bytes[YADDR(y) + m_w + x] &= bottomMask;
236  m_bytes[YADDR(y) + m_w + x] |= (data >> (8 - (y & 0x7)));
237  }
238  x++;
239  }
240  }
241  j++;
242  }
243 }
244 
245 void NanoCanvas::printFixed(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
246 {
247  uint8_t i, j = 0;
248  uint8_t text_index = 0;
249  uint8_t page_offset = 0;
250  uint8_t x = xpos;
251  uint8_t topMask, bottomMask;
252  if ( y >= m_h ) return;
253  topMask = (0xFF >> (8 - (y & 0x7)));
254  bottomMask = (0xFF << (y & 0x7));
255  for(;;)
256  {
257  if( ( x > m_w - s_fixedFont.width ) || ( ch[j] == '\0' ) )
258  {
259  x = xpos;
260  y += 8;
261  if (y > (m_h - 8))
262  {
263  break;
264  }
265  page_offset++;
266  if (page_offset == s_fixedFont.pages)
267  {
268  text_index = j;
269  page_offset = 0;
270  if (ch[j] == '\0')
271  {
272  break;
273  }
274  }
275  else
276  {
277  j = text_index;
278  }
279  }
280  uint8_t c = ch[j] - 32;
281  if ( c > 224 )
282  {
283  c = 0;
284  }
285  uint8_t ldata = 0;
286  uint16_t offset = (c * s_fixedFont.pages + page_offset) * s_fixedFont.width;
287  for( i=0; i<s_fixedFont.width; i++)
288  {
289  uint8_t data;
290  if ( style == STYLE_NORMAL )
291  {
292  data = pgm_read_byte(&s_fixedFont.data[offset]);
293  }
294  else if ( style == STYLE_BOLD )
295  {
296  data = pgm_read_byte(&s_fixedFont.data[offset]);
297  uint8_t temp = data | ldata;
298  ldata = data;
299  data = temp;
300  }
301  else
302  {
303  data = pgm_read_byte(&s_fixedFont.data[offset + 1]);
304  uint8_t temp = (data & 0xF0) | ldata;
305  ldata = (data & 0x0F);
306  data = temp;
307  }
308  m_bytes[YADDR(y) + x] &= topMask;
309  m_bytes[YADDR(y) + x] |= (data << (y & 0x7));
310  if (y + 8 < m_h)
311  {
312  m_bytes[YADDR(y) + m_w + x] &= bottomMask;
313  m_bytes[YADDR(y) + m_w + x] |= (data >> (8 - (y & 0x7)));
314  }
315  offset++;
316  x++;
317  }
318  j++;
319  }
320 }
321 
322 void NanoCanvas::printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
323 {
324  uint8_t i, j = 0;
325  uint8_t text_index = 0;
326  uint8_t page_offset = 0;
327  uint8_t x = xpos;
328  uint8_t topMask, bottomMask;
329  if ( y >= m_h ) return;
330  topMask = (0xFF >> (8 - (y & 0x7)));
331  bottomMask = (0xFF << (y & 0x7));
332  for(;;)
333  {
334  if( ( x > m_w - (s_fixedFont.width<<1) ) || ( ch[j] == '\0' ) )
335  {
336  x = xpos;
337  y += 8;
338  if (y > (m_h - 8))
339  {
340  break;
341  }
342  page_offset++;
343  if (page_offset == (s_fixedFont.pages<<1))
344  {
345  text_index = j;
346  page_offset = 0;
347  if (ch[j] == '\0')
348  {
349  break;
350  }
351  }
352  else
353  {
354  j = text_index;
355  }
356  }
357  uint8_t c = ch[j] - 32;
358  if ( c > 224 )
359  {
360  c = 0;
361  }
362  uint8_t ldata = 0;
363  uint16_t offset = (c * s_fixedFont.pages + (page_offset >> 1)) * s_fixedFont.width;
364  for( i=0; i<s_fixedFont.width; i++)
365  {
366  uint8_t data;
367  if ( style == STYLE_NORMAL )
368  {
369  data = pgm_read_byte(&s_fixedFont.data[offset]);
370  }
371  else if ( style == STYLE_BOLD )
372  {
373  data = pgm_read_byte(&s_fixedFont.data[offset]);
374  uint8_t temp = data | ldata;
375  ldata = data;
376  data = temp;
377  }
378  else
379  {
380  data = pgm_read_byte(&s_fixedFont.data[offset + 1]);
381  uint8_t temp = (data & 0xF0) | ldata;
382  ldata = (data & 0x0F);
383  data = temp;
384  }
385  if (page_offset & 1) data >>= 4;
386  data = ((data & 0x01) ? 0x03: 0x00) |
387  ((data & 0x02) ? 0x0C: 0x00) |
388  ((data & 0x04) ? 0x30: 0x00) |
389  ((data & 0x08) ? 0xC0: 0x00);
390 
391  for (uint8_t n=2; n>0; n--)
392  {
393  m_bytes[YADDR(y) + x] &= topMask;
394  m_bytes[YADDR(y) + x] |= (data << (y & 0x7));
395  if (y+8 < m_h)
396  {
397  m_bytes[YADDR(y) + m_w + x] &= bottomMask;
398  m_bytes[YADDR(y) + m_w + x] |= (data >> (8 - (y & 0x7)));
399  }
400  x++;
401  }
402  offset++;
403  }
404  j++;
405  }
406 }
407 
408 void NanoCanvas::drawSpritePgm(uint8_t x, uint8_t y, const uint8_t sprite[])
409 {
410  uint8_t i;
411  for(i=0;i<8;i++)
412  {
413  if (x >= m_w) { x++; continue; }
414  uint8_t d = pgm_read_byte(&sprite[i]);
415  if (y < m_h)
416  m_bytes[YADDR(y) + x] |= (d << (y & 0x7));
417  if ((uint8_t)(y + 8) < m_h)
418  m_bytes[YADDR((uint8_t)(y + 8)) + x] |= (d >> (8 - (y & 0x7)));
419  x++;
420  }
421 };
422 
423 
424 void NanoCanvas::drawBitmap(uint8_t startX, uint8_t startY, uint8_t w, uint8_t h, const uint8_t *buf)
425 {
426  uint8_t x,y;
427  for(y=0;y<h;y+=8)
428  {
429  for(x=0;x<w;x++)
430  {
431  uint8_t scrX = startX + x;
432  if (scrX >= m_w) continue;
433  uint8_t d = pgm_read_byte(&buf[x + static_cast<uint16_t>(y>>3) * w]);
434  uint8_t scrY = y + startY;
435  scrX = x + startX;
436  if (scrY < m_h)
437  m_bytes[YADDR(scrY) + scrX] |= (d << (scrY & 0x7));
438  scrY+=8;
439  if (scrY < m_h)
440  m_bytes[YADDR(scrY) + scrX] |= (d >> (8 - (scrY & 0x7)));
441  }
442  }
443 }
444 
445 
446 void NanoCanvas::drawSprite(uint8_t x, uint8_t y, const uint8_t sprite[])
447 {
448  uint8_t i;
449  for(i=0;i<8;i++)
450  {
451  if (x>=m_w) { x++; continue; }
452  uint8_t d = sprite[i];
453  if (uint8_t(y) < m_h)
454  m_bytes[YADDR(y) + x] |= (d << (y & 0x7));
455  if ((uint8_t)(y+8) < m_h)
456  m_bytes[YADDR((uint8_t)(y + 8)) + x] |= (d >> (8 - (y & 0x7)));
457  x++;
458  }
459 };
460 
462 {
463  uint8_t i;
464  for(i = 0; i < sprite->w; i++)
465  {
466  if ((sprite->x + i) >= m_w) { continue; }
467  uint8_t d = pgm_read_byte(&sprite->data[i]);
468  if (sprite->y < m_h)
469  m_bytes[YADDR(sprite->y) + sprite->x + i] |= (d << (sprite->y & 0x7));
470  if (uint8_t(sprite->y + 8) < m_h)
471  m_bytes[YADDR(uint8_t(sprite->y + 8)) + sprite->x + i] |= (d >> (8 - (sprite->y & 0x7)));
472  }
473 }
474 
475 void NanoCanvas::blt(uint8_t x, uint8_t y)
476 {
477  ssd1306_drawBuffer(x, y, m_w, m_h, m_bytes);
478 }
479 
481 {
482  for(uint16_t i=0; i< static_cast<uint16_t>(m_w) * (m_h >> 3); i++)
483  m_bytes[i] = ~m_bytes[i];
484 }
485 
487 {
488  for (uint8_t y=0; y<(m_h>>3); y++)
489  for (uint8_t x=0; x<m_w>>1; x++)
490  {
491  uint8_t temp = m_bytes[YADDR(y) + x];
492  m_bytes[YADDR(y) + x] = m_bytes[YADDR(y) + m_w - x -1];
493  m_bytes[YADDR(y) + m_w - x -1] = temp;
494  }
495 }
496 
498 // SPRITE OBJECT
500 
501 void SPRITE::setPos(uint8_t x, uint8_t y)
502 {
503  this->x = x;
504  this->y = y;
505 }
506 
508 {
509  ssd1306_drawSprite(this);
510 }
511 
513 {
514  ssd1306_eraseTrace(this);
515 }
516 
518 {
519  ssd1306_eraseSprite(this);
520 }
void charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style=STYLE_NORMAL)
Definition: nano_gfx.cpp:120
void charF12x16(uint8_t x, uint8_t y, const char ch[], EFontStyle style=STYLE_NORMAL)
Definition: nano_gfx.cpp:166
void fillRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t templ)
Definition: nano_gfx.cpp:76
void clear()
Definition: nano_gfx.cpp:111
const uint8_t * data
Pointer to PROGMEM data, representing sprite image.
void ssd1306_eraseSprite(SPRITE *sprite)
void drawSpritePgm(uint8_t x, uint8_t y, const uint8_t sprite[])
Definition: nano_gfx.cpp:408
void ssd1306_drawSprite(SPRITE *sprite)
void drawSprite(uint8_t x, uint8_t y, const uint8_t sprite[])
Definition: nano_gfx.cpp:446
void invert()
Definition: nano_gfx.cpp:480
void printFixed(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style=STYLE_NORMAL)
Definition: nano_gfx.cpp:245
SFixedFontInfo s_fixedFont
Definition: tiler.h:39
void eraseTrace()
Definition: nano_gfx.cpp:512
void flipH()
Definition: nano_gfx.cpp:486
void erase()
Definition: nano_gfx.cpp:517
void draw()
Definition: nano_gfx.cpp:507
void setPos(uint8_t x, uint8_t y)
Definition: nano_gfx.cpp:501
void drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
Definition: nano_gfx.cpp:57
uint8_t y
draw position Y on the screen
void drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: nano_gfx.cpp:67
uint8_t width
width in pixels
uint8_t x
draw position X on the screen
uint8_t w
sprite width
void blt(uint8_t x, uint8_t y)
Definition: nano_gfx.cpp:475
void ssd1306_eraseTrace(SPRITE *sprite)
void putPixel(uint8_t x, uint8_t y)
Definition: nano_gfx.cpp:34
void drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: nano_gfx.cpp:424
const uint8_t * data
font chars bits
EFontStyle
uint8_t pages
height in pages (each page height is 8-pixels)
void drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
Definition: nano_gfx.cpp:47
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
void printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style=STYLE_NORMAL)
Definition: nano_gfx.cpp:322