SSD1306 OLED display driver  1.4.6
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;
29 extern SFixedFontInfo s_fixedFont;
30 
31 #define YADDR(y) (((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::drawSprite(uint8_t x, uint8_t y, const uint8_t sprite[])
425 {
426  uint8_t i;
427  for(i=0;i<8;i++)
428  {
429  if (x>=m_w) { x++; continue; }
430  uint8_t d = sprite[i];
431  if (uint8_t(y) < m_h)
432  m_bytes[YADDR(y) + x] |= (d << (y & 0x7));
433  if ((uint8_t)(y+8) < m_h)
434  m_bytes[YADDR((uint8_t)(y + 8)) + x] |= (d >> (8 - (y & 0x7)));
435  x++;
436  }
437 };
438 
440 {
441  uint8_t i;
442  for(i = 0; i < sprite->w; i++)
443  {
444  if ((sprite->x + i) >= m_w) { continue; }
445  uint8_t d = pgm_read_byte(&sprite->data[i]);
446  if (sprite->y < m_h)
447  m_bytes[YADDR(sprite->y) + sprite->x + i] |= (d << (sprite->y & 0x7));
448  if (uint8_t(sprite->y + 8) < m_h)
449  m_bytes[YADDR(uint8_t(sprite->y + 8)) + sprite->x + i] |= (d >> (8 - (sprite->y & 0x7)));
450  }
451 }
452 
453 void NanoCanvas::blt(uint8_t x, uint8_t y)
454 {
455  ssd1306_drawBuffer(x, y, m_w, m_h, m_bytes);
456 }
457 
459 {
460  for(uint16_t i=0; i< static_cast<uint16_t>(m_w) * (m_h >> 3); i++)
461  m_bytes[i] = ~m_bytes[i];
462 }
463 
465 {
466  for (uint8_t y=0; y<(m_h>>3); y++)
467  for (uint8_t x=0; x<m_w>>1; x++)
468  {
469  uint8_t temp = m_bytes[YADDR(y) + x];
470  m_bytes[YADDR(y) + x] = m_bytes[YADDR(y) + m_w - x -1];
471  m_bytes[YADDR(y) + m_w - x -1] = temp;
472  }
473 }
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 drawSpritePgm(uint8_t x, uint8_t y, const uint8_t sprite[])
Definition: nano_gfx.cpp:408
void drawSprite(uint8_t x, uint8_t y, const uint8_t sprite[])
Definition: nano_gfx.cpp:424
void invert()
Definition: nano_gfx.cpp:458
void printFixed(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style=STYLE_NORMAL)
Definition: nano_gfx.cpp:245
void flipH()
Definition: nano_gfx.cpp:464
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
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306.c:625
uint8_t w
sprite width
void blt(uint8_t x, uint8_t y)
Definition: nano_gfx.cpp:453
void putPixel(uint8_t x, uint8_t y)
Definition: nano_gfx.cpp:34
const uint8_t * data
font chars bits
EFontStyle
uint8_t pages
height in pages
void drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
Definition: nano_gfx.cpp:47
void printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style=STYLE_NORMAL)
Definition: nano_gfx.cpp:322