SSD1306 OLED display driver  1.7.20
This library is developed to control SSD1306/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
ssd1306_1bit.c
1 /*
2  MIT License
3 
4  Copyright (c) 2016-2019, 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 
28 
29 #include "ssd1306.h"
30 #include "ssd1306_fonts.h"
31 #include "lcd/lcd_common.h"
32 #include "intf/i2c/ssd1306_i2c.h"
33 #include "intf/spi/ssd1306_spi.h"
34 #include "intf/ssd1306_interface.h"
35 #include "ssd1306_hal/io.h"
36 
37 // TODO: remove
38 #include "lcd/ssd1306_commands.h"
39 
40 uint8_t s_ssd1306_invertByte = 0x00000000;
41 extern uint16_t ssd1306_color;
42 const uint8_t *s_font6x8 = &ssd1306xled_font6x8[4];
43 extern lcduint_t ssd1306_cursorX;
44 extern lcduint_t ssd1306_cursorY;
46 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
47 extern uint8_t g_ssd1306_unicode;
48 #endif
49 
50 void ssd1306_fillScreen(uint8_t fill_Data)
51 {
52  fill_Data ^= s_ssd1306_invertByte;
53  ssd1306_lcd.set_block(0, 0, 0);
54  for(uint8_t m=(ssd1306_lcd.height >> 3); m>0; m--)
55  {
56  for(uint8_t n=ssd1306_lcd.width; n>0; n--)
57  {
58  ssd1306_lcd.send_pixels1(fill_Data);
59  }
61  }
63 }
64 
66 {
67  ssd1306_lcd.set_block(0, 0, 0);
68  for(uint8_t m=(ssd1306_lcd.height >> 3); m>0; m--)
69  {
70  for(uint8_t n=ssd1306_lcd.width; n>0; n--)
71  {
72  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
73  }
75  }
77 }
78 
79 uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
80 {
81  uint8_t i, j=0;
82  uint8_t text_index = 0;
83  uint8_t page_offset = 0;
84  uint8_t x = xpos;
85  y >>= 3;
86  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
87  for(;;)
88  {
89  uint8_t ldata;
90  if ((x > ssd1306_lcd.width - s_fixedFont.h.width) || (ch[j] == '\0'))
91  {
92  x = xpos;
93  y++;
94  if (y >= (ssd1306_lcd.height >> 3))
95  {
96  break;
97  }
98  page_offset++;
99  if (page_offset == s_fixedFont.pages)
100  {
101  text_index = j;
102  page_offset = 0;
103  if (ch[j] == '\0')
104  {
105  break;
106  }
107  }
108  else
109  {
110  j = text_index;
111  }
112  ssd1306_intf.stop();
113  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
114  }
115  uint16_t unicode;
116  do
117  {
118  unicode = ssd1306_unicode16FromUtf8(ch[j]);
119  j++;
120  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
121  SCharInfo char_info;
122  ssd1306_getCharBitmap(unicode, &char_info);
123  ldata = 0;
124  x += char_info.width + char_info.spacing;
125  if (char_info.height > page_offset * 8)
126  {
127  char_info.glyph += page_offset * char_info.width;
128  for( i = char_info.width; i>0; i--)
129  {
130  uint8_t data;
131  if ( style == STYLE_NORMAL )
132  {
133  data = pgm_read_byte(&char_info.glyph[0]);
134  }
135  else if ( style == STYLE_BOLD )
136  {
137  uint8_t temp = pgm_read_byte(&char_info.glyph[0]);
138  data = temp | ldata;
139  ldata = temp;
140  }
141  else
142  {
143  uint8_t temp = pgm_read_byte(&char_info.glyph[1]);
144  data = (temp & 0xF0) | ldata;
145  ldata = (temp & 0x0F);
146  }
147  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
148  char_info.glyph++;
149  }
150  }
151  else
152  {
153  char_info.spacing += char_info.width;
154  }
155  for (i = 0; i < char_info.spacing; i++)
156  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
157  }
158  ssd1306_intf.stop();
159  return j;
160 }
161 
162 uint8_t ssd1306_printFixed_oldStyle(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
163 {
164  uint8_t i, j=0;
165  uint8_t text_index = 0;
166  uint8_t page_offset = 0;
167  uint8_t x = xpos;
168  y >>= 3;
169  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
170  for(;;)
171  {
172  uint8_t c;
173  uint8_t ldata;
174  uint16_t offset;
175  if( (x > ssd1306_lcd.width - s_fixedFont.h.width) || (ch[j] == '\0') )
176  {
177  x = xpos;
178  y++;
179  if (y >= (ssd1306_lcd.height >> 3))
180  {
181  break;
182  }
183  page_offset++;
184  if (page_offset == s_fixedFont.pages)
185  {
186  text_index = j;
187  page_offset = 0;
188  if (ch[j] == '\0')
189  {
190  break;
191  }
192  }
193  else
194  {
195  j = text_index;
196  }
197  ssd1306_intf.stop();
198  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
199  }
200  c = ch[j];
201  if ( c >= s_fixedFont.h.ascii_offset )
202  {
203  c -= s_fixedFont.h.ascii_offset;
204  }
205  ldata = 0;
206  offset = (c * s_fixedFont.pages + page_offset) * s_fixedFont.h.width;
207  for( i=s_fixedFont.h.width; i>0; i--)
208  {
209  uint8_t data;
210  if ( style == STYLE_NORMAL )
211  {
212  data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
213  }
214  else if ( style == STYLE_BOLD )
215  {
216  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset]);
217  data = temp | ldata;
218  ldata = temp;
219  }
220  else
221  {
222  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset + 1]);
223  data = (temp & 0xF0) | ldata;
224  ldata = (temp & 0x0F);
225  }
226  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
227  offset++;
228  }
229  x += s_fixedFont.h.width;
230  j++;
231  }
232  ssd1306_intf.stop();
233  return j;
234 }
235 
236 uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
237 {
238  uint8_t i, j=0;
239  uint8_t text_index = 0;
240  uint8_t page_offset = 0;
241  uint8_t x = xpos;
242  y >>= 3;
243  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
244  for(;;)
245  {
246  uint8_t c;
247  uint8_t ldata;
248  uint16_t offset;
249  if( (x > ssd1306_lcd.width - (s_fixedFont.h.width << 1)) || (ch[j] == '\0') )
250  {
251  x = xpos;
252  y++;
253  if (y >= (ssd1306_lcd.height >> 3))
254  {
255  break;
256  }
257  page_offset++;
258  if (page_offset == (s_fixedFont.pages << 1))
259  {
260  text_index = j;
261  page_offset = 0;
262  if (ch[j] == '\0')
263  {
264  break;
265  }
266  }
267  else
268  {
269  j = text_index;
270  }
271  ssd1306_intf.stop();
272  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
273  }
274  c = ch[j];
275  if ( c >= 32 )
276  {
277  c -= 32;
278  }
279  ldata = 0;
280  offset = (c * s_fixedFont.pages + (page_offset >> 1)) * s_fixedFont.h.width;
281  for( i=s_fixedFont.h.width; i>0; i--)
282  {
283  uint8_t data;
284  if ( style == STYLE_NORMAL )
285  {
286  data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
287  }
288  else if ( style == STYLE_BOLD )
289  {
290  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset]);
291  data = temp | ldata;
292  ldata = temp;
293  }
294  else
295  {
296  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset + 1]);
297  data = (temp & 0xF0) | ldata;
298  ldata = (temp & 0x0F);
299  }
300  if (page_offset & 1) data >>= 4;
301  data = ((data & 0x01) ? 0x03: 0x00) |
302  ((data & 0x02) ? 0x0C: 0x00) |
303  ((data & 0x04) ? 0x30: 0x00) |
304  ((data & 0x08) ? 0xC0: 0x00);
305  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
306  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
307  offset++;
308  }
309  x += (s_fixedFont.h.width << 1);
310  j++;
311  }
312  ssd1306_intf.stop();
313  return j;
314 }
315 
316 
317 uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
318 {
319  uint8_t i, j=0;
320  uint8_t text_index = 0;
321  uint8_t page_offset = 0;
322  uint8_t x = xpos;
323  y >>= 3;
324  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
325  for(;;)
326  {
327  uint8_t ldata;
328  if( (x > ssd1306_lcd.width - (s_fixedFont.h.width << factor)) || (ch[j] == '\0') )
329  {
330  x = xpos;
331  y++;
332  if (y >= (ssd1306_lcd.height >> 3))
333  {
334  break;
335  }
336  page_offset++;
337  if (page_offset == (s_fixedFont.pages << factor))
338  {
339  text_index = j;
340  page_offset = 0;
341  if (ch[j] == '\0')
342  {
343  break;
344  }
345  }
346  else
347  {
348  j = text_index;
349  }
350  ssd1306_intf.stop();
351  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
352  }
353  uint16_t unicode;
354  do
355  {
356  unicode = ssd1306_unicode16FromUtf8(ch[j]);
357  j++;
358  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
359  SCharInfo char_info;
360  ssd1306_getCharBitmap(unicode, &char_info);
361  ldata = 0;
362  x += ((char_info.width + char_info.spacing) << factor);
363  if (char_info.height > (page_offset >> factor) * 8)
364  {
365  char_info.glyph += (page_offset >> factor) * char_info.width;
366  for( i=char_info.width; i>0; i--)
367  {
368  uint8_t data;
369  if ( style == STYLE_NORMAL )
370  {
371  data = pgm_read_byte(char_info.glyph);
372  }
373  else if ( style == STYLE_BOLD )
374  {
375  uint8_t temp = pgm_read_byte(char_info.glyph);
376  data = temp | ldata;
377  ldata = temp;
378  }
379  else
380  {
381  uint8_t temp = pgm_read_byte(char_info.glyph+1);
382  data = (temp & 0xF0) | ldata;
383  ldata = (temp & 0x0F);
384  }
385  if ( factor > 0 )
386  {
387  uint8_t accum = 0;
388  uint8_t mask = ~((0xFF) << (1<<factor));
389  // N=0 -> right shift is always 0
390  // N=1 -> right shift goes through 0, 4
391  // N=2 -> right shift goes through 0, 2, 4, 6
392  // N=3 -> right shift goes through 0, 1, 2, 3, 4, 5, 6, 7
393  data >>= ((page_offset & ((1<<factor) - 1))<<(3-factor));
394  for (uint8_t idx = 0; idx < 1<<(3-factor); idx++)
395  {
396  accum |= (((data>>idx) & 0x01) ? (mask<<(idx<<factor)) : 0);
397  }
398  data = accum;
399  }
400  for (uint8_t z=(1<<factor); z>0; z--)
401  {
402  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
403  }
404  char_info.glyph++;
405  }
406  }
407  else
408  {
409  char_info.spacing += char_info.width;
410  }
411  for (i = 0; i < (char_info.spacing << factor); i++)
412  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
413  }
414  ssd1306_intf.stop();
415  return j;
416 }
417 
418 size_t ssd1306_write(uint8_t ch)
419 {
420  if (ch == '\r')
421  {
422  ssd1306_cursorX = 0;
423  return 0;
424  }
425  else if ( (ssd1306_cursorX > ssd1306_lcd.width - s_fixedFont.h.width) || (ch == '\n') )
426  {
427  ssd1306_cursorX = 0;
428  ssd1306_cursorY += s_fixedFont.h.height;
429  if ( ssd1306_cursorY > ssd1306_lcd.height - s_fixedFont.h.height )
430  {
431  ssd1306_cursorY = 0;
432  }
433  ssd1306_clearBlock(0, ssd1306_cursorY >> 3, ssd1306_lcd.width, s_fixedFont.h.height);
434  if (ch == '\n')
435  {
436  return 0;
437  }
438  }
439  uint16_t unicode = ssd1306_unicode16FromUtf8(ch);
440  if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
441  SCharInfo char_info;
442  ssd1306_getCharBitmap(unicode, &char_info);
443  ssd1306_drawBitmap( ssd1306_cursorX,
444  ssd1306_cursorY >> 3,
445  char_info.width,
446  char_info.height,
447  char_info.glyph );
448  ssd1306_cursorX += char_info.width + char_info.spacing;
449  return 1;
450 }
451 
452 size_t ssd1306_print(const char ch[])
453 {
454  size_t n = 0;
455  while (*ch)
456  {
457  n += ssd1306_write(*ch);
458  ch++;
459  }
460  return n;
461 }
462 
463 uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
464 {
465  uint8_t i, j=0;
467  while(ch[j] != '\0')
468  {
469  uint8_t ldata;
470  uint8_t c = ch[j] - 32;
471  if ( c > 224 )
472  {
473  c = 0;
474  }
475  if(x > ssd1306_lcd.width - 6)
476  {
477  x=0;
478  y++;
479  }
480  ldata = 0;
481  for(i=0;i<6;i++)
482  {
483  uint8_t data;
484  if ( style == STYLE_NORMAL )
485  {
486  data = pgm_read_byte(&s_font6x8[c*6+i]);
487  }
488  else if ( style == STYLE_BOLD )
489  {
490  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
491  data = temp | ldata;
492  ldata = temp;
493  }
494  else
495  {
496  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
497  data = (temp & 0xF0) | ldata;
498  ldata = (temp & 0x0F);
499  }
500  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
501  }
502  x += 6;
503  j++;
504  }
505  ssd1306_intf.stop();
506  return j;
507 }
508 
509 uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
510 {
511  uint8_t i, j=0;
512  uint8_t text_index = 0;
513  uint8_t odd = 0;
514  uint8_t x = xpos;
515  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
516  for(;;)
517  {
518  uint8_t c;
519  uint8_t ldata;
520  if( (x > ssd1306_lcd.width-12) || (ch[j] == '\0') )
521  {
522  x = xpos;
523  y++;
524  if (y >= (ssd1306_lcd.height >> 3))
525  {
526  break;
527  }
528  if (odd)
529  {
530  text_index = j;
531  if (ch[j] == '\0')
532  {
533  break;
534  }
535  }
536  else
537  {
538  j = text_index;
539  }
540  odd = !odd;
541  ssd1306_intf.stop();
542  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
543  }
544  c = ch[j] - 32;
545  if ( c > 224 )
546  {
547  c = 0;
548  }
549  ldata = 0;
550  for(i=0;i<6;i++)
551  {
552  uint8_t data;
553  if ( style == STYLE_NORMAL )
554  {
555  data = pgm_read_byte(&s_font6x8[c*6+i]);
556  }
557  else if ( style == STYLE_BOLD )
558  {
559  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
560  data = temp | ldata;
561  ldata = temp;
562  }
563  else
564  {
565  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
566  data = (temp & 0xF0) | ldata;
567  ldata = (temp & 0x0F);
568  }
569  if (odd) data >>= 4;
570  data = ((data & 0x01) ? 0x03: 0x00) |
571  ((data & 0x02) ? 0x0C: 0x00) |
572  ((data & 0x04) ? 0x30: 0x00) |
573  ((data & 0x08) ? 0xC0: 0x00);
574  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
575  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
576  }
577  x += 12;
578  j++;
579  }
580  ssd1306_intf.stop();
581  return j;
582 }
583 
584 uint8_t ssd1306_charF6x8_eol(uint8_t left,
585  uint8_t y,
586  const char ch[],
587  EFontStyle style,
588  uint8_t right)
589 {
590  uint8_t len = ssd1306_printFixed(left, y<<3, ch, style);
591  uint8_t text_end_pos = len * 6 + left;
592  if (text_end_pos <= right)
593  {
594  ssd1306_clearBlock(text_end_pos, y, right - text_end_pos + 1, 8);
595  }
596  return len;
597 }
598 
599 void ssd1306_putPixel(uint8_t x, uint8_t y)
600 {
601  ssd1306_lcd.set_block(x, y >> 3, 1);
602  ssd1306_lcd.send_pixels1((1 << (y & 0x07))^s_ssd1306_invertByte);
603  ssd1306_intf.stop();
604 }
605 
606 void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
607 {
608  ssd1306_lcd.set_block(x, y >> 3, 1);
609  ssd1306_lcd.send_pixels1(pixels^s_ssd1306_invertByte);
610  ssd1306_intf.stop();
611 }
612 
613 void ssd1306_putPixel_delayed(uint8_t x, uint8_t y, uint8_t complete)
614 {
615  static uint8_t lx = 0, ly = 0xFF;
616  static uint8_t pixels = 0;
617  if ((lx != x) || ((ly & 0xF8) != (y & 0xF8)) || (complete))
618  {
619  if (ly != 0xFF)
620  {
621  ssd1306_putPixels( lx, ly, pixels );
622  }
623  pixels = 0;
624  ly = 0xFF;
625  }
626  if ( !complete )
627  {
628  pixels |= (1 << (y & 0x07));
629  lx = x; ly = y;
630  }
631 }
632 
633 void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
634 {
635  lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
636  lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
637  lcduint_t err = 0;
638  if (dy > dx)
639  {
640  if (y1 > y2)
641  {
642  ssd1306_swap_data(x1, x2, uint8_t);
643  ssd1306_swap_data(y1, y2, uint8_t);
644  }
645  for(; y1<=y2; y1++)
646  {
647  err += dx;
648  if (err >= dy)
649  {
650  err -= dy;
651  x1 < x2 ? x1++: x1--;
652  }
653  ssd1306_putPixel_delayed( x1, y1, 0 );
654  }
655  ssd1306_putPixel_delayed( 0, 0, 1 );
656  }
657  else
658  {
659  if (x1 > x2)
660  {
661  ssd1306_swap_data(x1, x2, uint8_t);
662  ssd1306_swap_data(y1, y2, uint8_t);
663  }
664  for(; x1<=x2; x1++)
665  {
666  err += dy;
667  if (err >= dx)
668  {
669  err -= dx;
670  if (y1 < y2) y1++; else y1--;
671  }
672  ssd1306_putPixel( x1, y1 );
673  }
674  }
675 }
676 
677 void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
678 {
679  ssd1306_lcd.set_block(x1, y1 >> 3, x2 - x1 + 1);
680  for (uint8_t x = x1; x <= x2; x++)
681  {
682  ssd1306_lcd.send_pixels1((1 << (y1 & 0x07))^s_ssd1306_invertByte);
683  }
684  ssd1306_intf.stop();
685 }
686 
687 void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
688 {
689  uint8_t topPage = y1 >> 3;
690  uint8_t bottomPage = y2 >> 3;
691  uint8_t height = y2-y1;
692  uint8_t y;
693  ssd1306_lcd.set_block(x1, topPage, 1);
694  if (topPage == bottomPage)
695  {
696  ssd1306_lcd.send_pixels1( ((0xFF >> (0x07 - height)) << (y1 & 0x07))^s_ssd1306_invertByte );
697  ssd1306_intf.stop();
698  return;
699  }
700  ssd1306_lcd.send_pixels1( (0xFF << (y1 & 0x07))^s_ssd1306_invertByte );
701  for ( y = (topPage + 1); y <= (bottomPage - 1); y++)
702  {
704  ssd1306_lcd.send_pixels1( 0xFF^s_ssd1306_invertByte );
705  }
707  ssd1306_lcd.send_pixels1( (0xFF >> (0x07 - (y2 & 0x07)))^s_ssd1306_invertByte );
708  ssd1306_intf.stop();
709 }
710 
711 void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
712 {
713  ssd1306_drawHLine(x1+1, y1, x2-1);
714  ssd1306_drawHLine(x1+1, y2, x2-1);
715  ssd1306_drawVLine(x1, y1, y2);
716  ssd1306_drawVLine(x2, y1, y2);
717 }
718 
719 void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
720 {
721  uint8_t j;
722  ssd1306_lcd.set_block(x, y >> 3, w);
723  for(j=(h >> 3); j>0; j--)
724  {
726  buf+=w;
728  }
729  ssd1306_intf.stop();
730 }
731 
732 void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
733 {
734  uint8_t i, j;
735  ssd1306_lcd.set_block(x, y, w);
736  for(j=(h >> 3); j>0; j--)
737  {
738  for(i=w;i>0;i--)
739  {
740  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^*buf++);
741  }
743  }
744  ssd1306_intf.stop();
745 }
746 
747 void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
748 {
749  uint8_t i, j;
750  uint8_t remainder = (ssd1306_lcd.width - x) < w ? (w + x - ssd1306_lcd.width): 0;
751  w -= remainder;
752  ssd1306_lcd.set_block(x, y, w);
753  for(j=(h >> 3); j>0; j--)
754  {
755  for(i=w;i>0;i--)
756  {
757  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^pgm_read_byte(buf++));
758  }
759  buf += remainder;
761  }
762  ssd1306_intf.stop();
763 }
764 
765 void ssd1306_drawXBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
766 {
767  uint8_t i, j;
768  lcduint_t pitch = (w + 7) >> 3;
769  ssd1306_lcd.set_block(x, y, w);
770  for(j=(h >> 3); j>0; j--)
771  {
772  uint8_t bit = 0;
773  for(i=w;i>0;i--)
774  {
775  uint8_t data = 0;
776  for (uint8_t k = 0; k<8; k++)
777  {
778  data |= ( ((pgm_read_byte(&buf[k*pitch]) >> bit) & 0x01) << k );
779  }
780  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^data);
781  bit++;
782  if (bit >= 8)
783  {
784  buf++;
785  bit=0;
786  }
787  }
788  if (bit)
789  {
790  buf++;
791  }
792  buf += pitch * 7;
794  }
795  ssd1306_intf.stop();
796 }
797 
798 void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
799 {
800  lcduint_t origin_width = w;
801  uint8_t offset = y & 0x07;
802  uint8_t complexFlag = 0;
803  uint8_t mainFlag = 1;
804  uint8_t max_pages;
805  uint8_t pages;
806  lcduint_t i, j;
807  if (y + (lcdint_t)h <= 0) return;
808  if (y >= ssd1306_lcd.height) return;
809  if (x + (lcdint_t)w <= 0) return;
810  if (x >= ssd1306_lcd.width) return;
811  if (y < 0)
812  {
813  buf += ((lcduint_t)((-y) + 7) >> 3) * w;
814  h += y;
815  y = 0;
816  complexFlag = 1;
817  }
818  if (x < 0)
819  {
820  buf += -x;
821  w += x;
822  x = 0;
823  }
824  max_pages = (lcduint_t)(h + 15 - offset) >> 3;
825  if ((lcduint_t)((lcduint_t)y + h) > (lcduint_t)ssd1306_lcd.height)
826  {
827  h = (lcduint_t)(ssd1306_lcd.height - (lcduint_t)y);
828  }
829  if ((lcduint_t)((lcduint_t)x + w) > (lcduint_t)ssd1306_lcd.width)
830  {
831  w = (lcduint_t)(ssd1306_lcd.width - (lcduint_t)x);
832  }
833  pages = ((y + h - 1) >> 3) - (y >> 3) + 1;
834 
835  ssd1306_lcd.set_block(x, y >> 3, w);
836  for(j=0; j < pages; j++)
837  {
838  if ( j == max_pages - 1 ) mainFlag = !offset;
839  for( i=w; i > 0; i--)
840  {
841  uint8_t data = 0;
842  if ( mainFlag ) data |= (pgm_read_byte(buf) << offset);
843  if ( complexFlag ) data |= (pgm_read_byte(buf - origin_width) >> (8 - offset));
844  buf++;
845  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^data);
846  }
847  buf += origin_width - w;
848  complexFlag = offset;
850  }
851  ssd1306_intf.stop();
852 }
853 
854 
855 void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
856 {
857  uint8_t i, j;
858  ssd1306_lcd.set_block(x, y, w);
859  for(j=(h >> 3); j>0; j--)
860  {
861  for(i=w;i>0;i--)
862  {
863  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
864  }
866  }
867  ssd1306_intf.stop();
868 }
869 
870 void ssd1306_fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
871 {
872  uint8_t templ = ssd1306_color^s_ssd1306_invertByte;
873  if (x1 > x2) return;
874  if (y1 > y2) return;
875  if ((lcduint_t)x2 >= ssd1306_displayWidth()) x2 = (lcdint_t)ssd1306_displayWidth() - 1;
876  if ((lcduint_t)y2 >= ssd1306_displayHeight()) y2 = (lcdint_t)ssd1306_displayHeight() - 1;
877  uint8_t bank1 = (y1 >> 3);
878  uint8_t bank2 = (y2 >> 3);
879  ssd1306_lcd.set_block(x1, bank1, x2 - x1 + 1);
880  for (uint8_t bank = bank1; bank<=bank2; bank++)
881  {
882  uint8_t mask = 0xFF;
883  if (bank1 == bank2)
884  {
885  mask = (mask >> ((y1 & 7) + 7 - (y2 & 7))) << (y1 & 7);
886  }
887  else if (bank1 == bank)
888  {
889  mask = (mask << (y1 & 7));
890  }
891  else if (bank2 == bank)
892  {
893  mask = (mask >> (7 - (y2 & 7)));
894  }
895  for (uint8_t x=x1; x<=x2; x++)
896  {
897  ssd1306_lcd.send_pixels1(templ & mask);
898  }
900  }
901  ssd1306_intf.stop();
902 }
903 
904 
905 void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
906 {
907  uint8_t i;
908  ssd1306_lcd.set_block(x,y,w);
909  for(i=0;i<w;i++)
910  {
911  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^pgm_read_byte(&sprite[i]));
912  }
913  ssd1306_intf.stop();
914 }
915 
916 
918 {
919  uint8_t offsety = sprite->y & 0x7;
920  if (sprite->y < ssd1306_lcd.height)
921  {
922  ssd1306_lcd.set_block(sprite->x, sprite->y >> 3, sprite->w);
923  for (uint8_t i=0; i < sprite->w; i++)
924  {
925  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte^(pgm_read_byte( &sprite->data[i] ) << offsety) );
926  }
927  ssd1306_intf.stop();
928  }
929  if (offsety && (sprite->y + 8 < ssd1306_lcd.height))
930  {
931  ssd1306_lcd.set_block(sprite->x, (sprite->y >> 3) + 1, sprite->w);
932  for (uint8_t i=0; i < sprite->w; i++)
933  {
934  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte^(pgm_read_byte( &sprite->data[i] ) >> (8 - offsety)) );
935  }
936  ssd1306_intf.stop();
937  }
938  sprite->lx = sprite->x;
939  sprite->ly = sprite->y;
940 }
941 
942 
944 {
945  uint8_t posy = sprite->y >> 3;
946  uint8_t offsety = sprite->y & 0x7;
947  ssd1306_lcd.set_block(sprite->x, posy, sprite->w);
948  for (uint8_t i=sprite->w; i > 0; i--)
949  {
950  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
951  }
952  ssd1306_intf.stop();
953  if (offsety)
954  {
955  ssd1306_lcd.set_block(sprite->x, posy + 1, sprite->w);
956  for (uint8_t i=sprite->w; i > 0; i--)
957  {
958  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
959  }
960  }
961  ssd1306_intf.stop();
962 }
963 
964 
966 {
967  uint8_t y1 = sprite->ly >> 3;
968  uint8_t y2 = (sprite->ly + 7) >> 3;
969  if (sprite->ly < sprite->y)
970  y2 = min(y2, (uint8_t)((sprite->y >> 3) - 1));
971  else if (sprite->y + 8 > sprite->ly)
972  y1 = max(y1, (sprite->ly + 7) >> 3);
973  for(uint8_t y = y1; y <= y2; y++)
974  {
975  ssd1306_lcd.set_block(sprite->lx, y, sprite->w);
976  for(uint8_t x = sprite->w; x > 0; x--)
977  {
978  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
979  }
980  ssd1306_intf.stop();
981  }
982  if (sprite->lx != sprite->x)
983  {
984  uint8_t x1 = sprite->lx;
985  uint8_t x2 = sprite->lx + sprite->w - 1;
986  if (sprite->x < sprite->lx)
987  x1 = max(x1, sprite->x + sprite->w);
988  else
989  x2 = min((uint8_t)(sprite->x - 1), x2);
990  for(uint8_t y = sprite->ly >> 3; y <= (sprite->ly + 7) >> 3; y++)
991  {
992  ssd1306_lcd.set_block(x1, y, x2 - x1 + 1 );
993  for(uint8_t x = x2 - x1 + 1; x > 0; x--)
994  {
995  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
996  }
997  ssd1306_intf.stop();
998  }
999  }
1000 }
1001 
1002 SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
1003 {
1004  return (SPRITE){x,y,w,x,y,data,NULL};
1005 }
1006 
1007 void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
1008 {
1009  sprite->data = data;
1010 }
1011 
1013 {
1014  s_ssd1306_invertByte = 0xFF;
1015 }
1016 
1018 {
1019  s_ssd1306_invertByte = 0x00;
1020 }
1021 
1022 void ssd1306_setFont6x8(const uint8_t * progmemFont)
1023 {
1024  s_font6x8 = progmemFont + 4;
1025 }
1026 
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:732
lcduint_t ssd1306_displayWidth(void)
uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:463
void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
Definition: ssd1306_1bit.c:606
uint8_t height
char height in pixels
void ssd1306_positiveMode()
const uint8_t * data
Pointer to PROGMEM data, representing sprite image.
SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
const uint8_t * primary_table
font chars bits
uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:236
void ssd1306_drawXBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:765
void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: ssd1306_1bit.c:633
uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
Definition: ssd1306_1bit.c:79
void ssd1306_drawSprite(SPRITE *sprite)
Definition: ssd1306_1bit.c:917
uint8_t width
width in pixels
int lcdint_t
Definition: io.h:63
void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: ssd1306_1bit.c:711
void(* set_block)(lcduint_t x, lcduint_t y, lcduint_t w)
Sets block in RAM of lcd display controller to write data to.
Definition: lcd_common.h:114
void ssd1306_fillScreen(uint8_t fill_Data)
Definition: ssd1306_1bit.c:50
unsigned int lcduint_t
Definition: io.h:65
void ssd1306_eraseTrace(SPRITE *sprite)
Definition: ssd1306_1bit.c:965
void(* send_pixels_buffer1)(const uint8_t *buffer, uint16_t len)
Definition: lcd_common.h:135
void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:747
const PROGMEM uint8_t ssd1306xled_font6x8[]
Definition: ssd1306_fonts.c:42
void(* send_pixels1)(uint8_t data)
Definition: lcd_common.h:128
uint8_t height
height in pixels
void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:798
uint8_t ascii_offset
ascii offset
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:33
size_t ssd1306_print(const char ch[])
Prints null-terminated string to display at current cursor position.
Definition: ssd1306_1bit.c:452
uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:509
void ssd1306_setFont6x8(const uint8_t *progmemFont)
void ssd1306_eraseSprite(SPRITE *sprite)
Definition: ssd1306_1bit.c:943
void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
Definition: ssd1306_1bit.c:687
void ssd1306_fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: ssd1306_1bit.c:870
ssd1306_interface_t ssd1306_intf
#define max(a, b)
uint8_t y
draw position Y on the screen
#define min(a, b)
lcduint_t height
Definition: lcd_common.h:97
uint8_t width
char width in pixels
void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
Definition: ssd1306_1bit.c:905
SFixedFontInfo s_fixedFont
Definition: tiler.h:44
SFontHeaderRecord h
record, containing information on font
uint8_t x
draw position X on the screen
const uint8_t * glyph
char data, located in progmem.
uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
Definition: ssd1306_1bit.c:317
uint8_t w
sprite width
void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
Definition: ssd1306_1bit.c:677
lcduint_t ssd1306_displayHeight(void)
void(* next_page)(void)
Definition: lcd_common.h:122
uint8_t spacing
additional spaces after char in pixels
uint8_t lx
last draw position X on the screen
void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
Definition: ssd1306_1bit.c:855
void ssd1306_getCharBitmap(uint16_t unicode, SCharInfo *info)
returns char data for currently set (active) font.
lcduint_t width
Definition: lcd_common.h:94
uint8_t ssd1306_charF6x8_eol(uint8_t left, uint8_t y, const char ch[], EFontStyle style, uint8_t right)
Definition: ssd1306_1bit.c:584
void ssd1306_clearScreen()
Definition: ssd1306_1bit.c:65
void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
#define SSD1306_MORE_CHARS_REQUIRED
EFontStyle
void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:719
uint8_t pages
height in pages (each page height is 8-pixels)
#define ssd1306_swap_data(a, b, type)
Definition: io.h:69
uint8_t ly
last draw position Y on the screen
void ssd1306_negativeMode()
void ssd1306_putPixel(uint8_t x, uint8_t y)
Definition: ssd1306_1bit.c:599
size_t ssd1306_write(uint8_t ch)
Prints single character to display at current cursor position.
Definition: ssd1306_1bit.c:418