SSD1306 OLED display driver  1.7.22
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  SCharInfo char_info = {};
426  uint8_t gotoNewLine = 1;
427  if (ch != '\n')
428  {
429  uint16_t unicode;
430  unicode = ssd1306_unicode16FromUtf8(ch);
431  if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
432  ssd1306_getCharBitmap(unicode, &char_info);
433  gotoNewLine = (ssd1306_cursorX > (ssd1306_lcd.width - char_info.width));
434  }
435  if ( gotoNewLine )
436  {
437  ssd1306_cursorX = 0;
438  ssd1306_cursorY += s_fixedFont.h.height;
439  if ( ssd1306_cursorY > ssd1306_lcd.height - s_fixedFont.h.height )
440  {
441  ssd1306_cursorY = 0;
442  }
443  ssd1306_clearBlock(0, ssd1306_cursorY >> 3, ssd1306_lcd.width, s_fixedFont.h.height);
444  if (ch == '\n')
445  {
446  return 0;
447  }
448  }
449  ssd1306_drawBitmap( ssd1306_cursorX,
450  ssd1306_cursorY >> 3,
451  char_info.width,
452  char_info.height,
453  char_info.glyph );
454  ssd1306_cursorX += char_info.width + char_info.spacing;
455  return 1;
456 }
457 
458 size_t ssd1306_print(const char ch[])
459 {
460  size_t n = 0;
461  while (*ch)
462  {
463  n += ssd1306_write(*ch);
464  ch++;
465  }
466  return n;
467 }
468 
469 uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
470 {
471  uint8_t i, j=0;
473  while(ch[j] != '\0')
474  {
475  uint8_t ldata;
476  uint8_t c = ch[j] - 32;
477  if ( c > 224 )
478  {
479  c = 0;
480  }
481  if(x > ssd1306_lcd.width - 6)
482  {
483  x=0;
484  y++;
485  }
486  ldata = 0;
487  for(i=0;i<6;i++)
488  {
489  uint8_t data;
490  if ( style == STYLE_NORMAL )
491  {
492  data = pgm_read_byte(&s_font6x8[c*6+i]);
493  }
494  else if ( style == STYLE_BOLD )
495  {
496  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
497  data = temp | ldata;
498  ldata = temp;
499  }
500  else
501  {
502  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
503  data = (temp & 0xF0) | ldata;
504  ldata = (temp & 0x0F);
505  }
506  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
507  }
508  x += 6;
509  j++;
510  }
511  ssd1306_intf.stop();
512  return j;
513 }
514 
515 uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
516 {
517  uint8_t i, j=0;
518  uint8_t text_index = 0;
519  uint8_t odd = 0;
520  uint8_t x = xpos;
521  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
522  for(;;)
523  {
524  uint8_t c;
525  uint8_t ldata;
526  if( (x > ssd1306_lcd.width-12) || (ch[j] == '\0') )
527  {
528  x = xpos;
529  y++;
530  if (y >= (ssd1306_lcd.height >> 3))
531  {
532  break;
533  }
534  if (odd)
535  {
536  text_index = j;
537  if (ch[j] == '\0')
538  {
539  break;
540  }
541  }
542  else
543  {
544  j = text_index;
545  }
546  odd = !odd;
547  ssd1306_intf.stop();
548  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
549  }
550  c = ch[j] - 32;
551  if ( c > 224 )
552  {
553  c = 0;
554  }
555  ldata = 0;
556  for(i=0;i<6;i++)
557  {
558  uint8_t data;
559  if ( style == STYLE_NORMAL )
560  {
561  data = pgm_read_byte(&s_font6x8[c*6+i]);
562  }
563  else if ( style == STYLE_BOLD )
564  {
565  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
566  data = temp | ldata;
567  ldata = temp;
568  }
569  else
570  {
571  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
572  data = (temp & 0xF0) | ldata;
573  ldata = (temp & 0x0F);
574  }
575  if (odd) data >>= 4;
576  data = ((data & 0x01) ? 0x03: 0x00) |
577  ((data & 0x02) ? 0x0C: 0x00) |
578  ((data & 0x04) ? 0x30: 0x00) |
579  ((data & 0x08) ? 0xC0: 0x00);
580  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
581  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
582  }
583  x += 12;
584  j++;
585  }
586  ssd1306_intf.stop();
587  return j;
588 }
589 
590 uint8_t ssd1306_charF6x8_eol(uint8_t left,
591  uint8_t y,
592  const char ch[],
593  EFontStyle style,
594  uint8_t right)
595 {
596  uint8_t len = ssd1306_printFixed(left, y<<3, ch, style);
597  uint8_t text_end_pos = len * 6 + left;
598  if (text_end_pos <= right)
599  {
600  ssd1306_clearBlock(text_end_pos, y, right - text_end_pos + 1, 8);
601  }
602  return len;
603 }
604 
605 void ssd1306_putPixel(uint8_t x, uint8_t y)
606 {
607  ssd1306_lcd.set_block(x, y >> 3, 1);
608  ssd1306_lcd.send_pixels1((1 << (y & 0x07))^s_ssd1306_invertByte);
609  ssd1306_intf.stop();
610 }
611 
612 void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
613 {
614  ssd1306_lcd.set_block(x, y >> 3, 1);
615  ssd1306_lcd.send_pixels1(pixels^s_ssd1306_invertByte);
616  ssd1306_intf.stop();
617 }
618 
619 void ssd1306_putPixel_delayed(uint8_t x, uint8_t y, uint8_t complete)
620 {
621  static uint8_t lx = 0, ly = 0xFF;
622  static uint8_t pixels = 0;
623  if ((lx != x) || ((ly & 0xF8) != (y & 0xF8)) || (complete))
624  {
625  if (ly != 0xFF)
626  {
627  ssd1306_putPixels( lx, ly, pixels );
628  }
629  pixels = 0;
630  ly = 0xFF;
631  }
632  if ( !complete )
633  {
634  pixels |= (1 << (y & 0x07));
635  lx = x; ly = y;
636  }
637 }
638 
639 void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
640 {
641  lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
642  lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
643  lcduint_t err = 0;
644  if (dy > dx)
645  {
646  if (y1 > y2)
647  {
648  ssd1306_swap_data(x1, x2, uint8_t);
649  ssd1306_swap_data(y1, y2, uint8_t);
650  }
651  for(; y1<=y2; y1++)
652  {
653  err += dx;
654  if (err >= dy)
655  {
656  err -= dy;
657  x1 < x2 ? x1++: x1--;
658  }
659  ssd1306_putPixel_delayed( x1, y1, 0 );
660  }
661  ssd1306_putPixel_delayed( 0, 0, 1 );
662  }
663  else
664  {
665  if (x1 > x2)
666  {
667  ssd1306_swap_data(x1, x2, uint8_t);
668  ssd1306_swap_data(y1, y2, uint8_t);
669  }
670  for(; x1<=x2; x1++)
671  {
672  err += dy;
673  if (err >= dx)
674  {
675  err -= dx;
676  if (y1 < y2) y1++; else y1--;
677  }
678  ssd1306_putPixel( x1, y1 );
679  }
680  }
681 }
682 
683 void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
684 {
685  ssd1306_lcd.set_block(x1, y1 >> 3, x2 - x1 + 1);
686  for (uint8_t x = x1; x <= x2; x++)
687  {
688  ssd1306_lcd.send_pixels1((1 << (y1 & 0x07))^s_ssd1306_invertByte);
689  }
690  ssd1306_intf.stop();
691 }
692 
693 void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
694 {
695  uint8_t topPage = y1 >> 3;
696  uint8_t bottomPage = y2 >> 3;
697  uint8_t height = y2-y1;
698  uint8_t y;
699  ssd1306_lcd.set_block(x1, topPage, 1);
700  if (topPage == bottomPage)
701  {
702  ssd1306_lcd.send_pixels1( ((0xFF >> (0x07 - height)) << (y1 & 0x07))^s_ssd1306_invertByte );
703  ssd1306_intf.stop();
704  return;
705  }
706  ssd1306_lcd.send_pixels1( (0xFF << (y1 & 0x07))^s_ssd1306_invertByte );
707  for ( y = (topPage + 1); y <= (bottomPage - 1); y++)
708  {
710  ssd1306_lcd.send_pixels1( 0xFF^s_ssd1306_invertByte );
711  }
713  ssd1306_lcd.send_pixels1( (0xFF >> (0x07 - (y2 & 0x07)))^s_ssd1306_invertByte );
714  ssd1306_intf.stop();
715 }
716 
717 void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
718 {
719  ssd1306_drawHLine(x1+1, y1, x2-1);
720  ssd1306_drawHLine(x1+1, y2, x2-1);
721  ssd1306_drawVLine(x1, y1, y2);
722  ssd1306_drawVLine(x2, y1, y2);
723 }
724 
725 void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
726 {
727  uint8_t j;
728  ssd1306_lcd.set_block(x, y >> 3, w);
729  for(j=(h >> 3); j>0; j--)
730  {
732  buf+=w;
734  }
735  ssd1306_intf.stop();
736 }
737 
738 void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
739 {
740  uint8_t i, j;
741  ssd1306_lcd.set_block(x, y, w);
742  for(j=(h >> 3); j>0; j--)
743  {
744  for(i=w;i>0;i--)
745  {
746  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^*buf++);
747  }
749  }
750  ssd1306_intf.stop();
751 }
752 
753 void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
754 {
755  uint8_t i, j;
756  uint8_t remainder = (ssd1306_lcd.width - x) < w ? (w + x - ssd1306_lcd.width): 0;
757  w -= remainder;
758  ssd1306_lcd.set_block(x, y, w);
759  for(j=(h >> 3); j>0; j--)
760  {
761  for(i=w;i>0;i--)
762  {
763  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^pgm_read_byte(buf++));
764  }
765  buf += remainder;
767  }
768  ssd1306_intf.stop();
769 }
770 
771 void ssd1306_drawBitmap1_4(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
772 {
773  uint8_t i, j, k;
774  ssd1306_lcd.set_block(x, y>>3, w);
775  uint8_t y_offset = (y & 0x07);
776  uint8_t x_offset = (x & 0x01);
777  for( j = 0; j < ((h + 7 + y_offset) >> 3); j++)
778  {
779  for( i = 0; i < w / 2 + x_offset; i++)
780  {
781  for( k = 0; k < 8; k++)
782  {
783  if ((j*8 + k - y_offset < h) && (k >= y_offset || j != 0))
784  {
785  uint8_t data = (i < w / 2) ? pgm_read_byte( &buf[ i + (j * 8 + k - y_offset) * w / 2 ] ) : 0x00;
786  if ( x_offset )
787  {
788  data <<= 4;
789  if ( i > 0) data |= pgm_read_byte( &buf[ i + (j * 8 + k - y_offset) * w / 2 - 1] ) >> 4;
790  }
791  ssd1306_lcd.send_pixels8( data );
792  }
793  else
794  {
795  ssd1306_lcd.send_pixels8( 0x00 );
796  }
797  }
798  }
800  }
801  ssd1306_intf.stop();
802 }
803 
804 void ssd1306_drawXBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
805 {
806  uint8_t i, j;
807  lcduint_t pitch = (w + 7) >> 3;
808  ssd1306_lcd.set_block(x, y, w);
809  for(j=(h >> 3); j>0; j--)
810  {
811  uint8_t bit = 0;
812  for(i=w;i>0;i--)
813  {
814  uint8_t data = 0;
815  for (uint8_t k = 0; k<8; k++)
816  {
817  data |= ( ((pgm_read_byte(&buf[k*pitch]) >> bit) & 0x01) << k );
818  }
819  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^data);
820  bit++;
821  if (bit >= 8)
822  {
823  buf++;
824  bit=0;
825  }
826  }
827  if (bit)
828  {
829  buf++;
830  }
831  buf += pitch * 7;
833  }
834  ssd1306_intf.stop();
835 }
836 
837 void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
838 {
839  lcduint_t origin_width = w;
840  uint8_t offset = y & 0x07;
841  uint8_t complexFlag = 0;
842  uint8_t mainFlag = 1;
843  uint8_t max_pages;
844  uint8_t pages;
845  lcduint_t i, j;
846  if (y + (lcdint_t)h <= 0) return;
847  if (y >= ssd1306_lcd.height) return;
848  if (x + (lcdint_t)w <= 0) return;
849  if (x >= ssd1306_lcd.width) return;
850  if (y < 0)
851  {
852  buf += ((lcduint_t)((-y) + 7) >> 3) * w;
853  h += y;
854  y = 0;
855  complexFlag = 1;
856  }
857  if (x < 0)
858  {
859  buf += -x;
860  w += x;
861  x = 0;
862  }
863  max_pages = (lcduint_t)(h + 15 - offset) >> 3;
864  if ((lcduint_t)((lcduint_t)y + h) > (lcduint_t)ssd1306_lcd.height)
865  {
866  h = (lcduint_t)(ssd1306_lcd.height - (lcduint_t)y);
867  }
868  if ((lcduint_t)((lcduint_t)x + w) > (lcduint_t)ssd1306_lcd.width)
869  {
870  w = (lcduint_t)(ssd1306_lcd.width - (lcduint_t)x);
871  }
872  pages = ((y + h - 1) >> 3) - (y >> 3) + 1;
873 
874  ssd1306_lcd.set_block(x, y >> 3, w);
875  for(j=0; j < pages; j++)
876  {
877  if ( j == max_pages - 1 ) mainFlag = !offset;
878  for( i=w; i > 0; i--)
879  {
880  uint8_t data = 0;
881  if ( mainFlag ) data |= (pgm_read_byte(buf) << offset);
882  if ( complexFlag ) data |= (pgm_read_byte(buf - origin_width) >> (8 - offset));
883  buf++;
884  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^data);
885  }
886  buf += origin_width - w;
887  complexFlag = offset;
889  }
890  ssd1306_intf.stop();
891 }
892 
893 
894 void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
895 {
896  uint8_t i, j;
897  ssd1306_lcd.set_block(x, y, w);
898  for(j=(h >> 3); j>0; j--)
899  {
900  for(i=w;i>0;i--)
901  {
902  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
903  }
905  }
906  ssd1306_intf.stop();
907 }
908 
909 void ssd1306_fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
910 {
911  uint8_t templ = ssd1306_color^s_ssd1306_invertByte;
912  if (x1 > x2) return;
913  if (y1 > y2) return;
914  if ((lcduint_t)x2 >= ssd1306_displayWidth()) x2 = (lcdint_t)ssd1306_displayWidth() - 1;
915  if ((lcduint_t)y2 >= ssd1306_displayHeight()) y2 = (lcdint_t)ssd1306_displayHeight() - 1;
916  uint8_t bank1 = (y1 >> 3);
917  uint8_t bank2 = (y2 >> 3);
918  ssd1306_lcd.set_block(x1, bank1, x2 - x1 + 1);
919  for (uint8_t bank = bank1; bank<=bank2; bank++)
920  {
921  uint8_t mask = 0xFF;
922  if (bank1 == bank2)
923  {
924  mask = (mask >> ((y1 & 7) + 7 - (y2 & 7))) << (y1 & 7);
925  }
926  else if (bank1 == bank)
927  {
928  mask = (mask << (y1 & 7));
929  }
930  else if (bank2 == bank)
931  {
932  mask = (mask >> (7 - (y2 & 7)));
933  }
934  for (uint8_t x=x1; x<=x2; x++)
935  {
936  ssd1306_lcd.send_pixels1(templ & mask);
937  }
939  }
940  ssd1306_intf.stop();
941 }
942 
943 
944 void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
945 {
946  uint8_t i;
947  ssd1306_lcd.set_block(x,y,w);
948  for(i=0;i<w;i++)
949  {
950  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^pgm_read_byte(&sprite[i]));
951  }
952  ssd1306_intf.stop();
953 }
954 
955 
957 {
958  uint8_t offsety = sprite->y & 0x7;
959  if (sprite->y < ssd1306_lcd.height)
960  {
961  ssd1306_lcd.set_block(sprite->x, sprite->y >> 3, sprite->w);
962  for (uint8_t i=0; i < sprite->w; i++)
963  {
964  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte^(pgm_read_byte( &sprite->data[i] ) << offsety) );
965  }
966  ssd1306_intf.stop();
967  }
968  if (offsety && (sprite->y + 8 < ssd1306_lcd.height))
969  {
970  ssd1306_lcd.set_block(sprite->x, (sprite->y >> 3) + 1, sprite->w);
971  for (uint8_t i=0; i < sprite->w; i++)
972  {
973  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte^(pgm_read_byte( &sprite->data[i] ) >> (8 - offsety)) );
974  }
975  ssd1306_intf.stop();
976  }
977  sprite->lx = sprite->x;
978  sprite->ly = sprite->y;
979 }
980 
981 
983 {
984  uint8_t posy = sprite->y >> 3;
985  uint8_t offsety = sprite->y & 0x7;
986  ssd1306_lcd.set_block(sprite->x, posy, sprite->w);
987  for (uint8_t i=sprite->w; i > 0; i--)
988  {
989  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
990  }
991  ssd1306_intf.stop();
992  if (offsety)
993  {
994  ssd1306_lcd.set_block(sprite->x, posy + 1, sprite->w);
995  for (uint8_t i=sprite->w; i > 0; i--)
996  {
997  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
998  }
999  }
1000  ssd1306_intf.stop();
1001 }
1002 
1003 
1005 {
1006  uint8_t y1 = sprite->ly >> 3;
1007  uint8_t y2 = (sprite->ly + 7) >> 3;
1008  if (sprite->ly < sprite->y)
1009  y2 = min(y2, (uint8_t)((sprite->y >> 3) - 1));
1010  else if (sprite->y + 8 > sprite->ly)
1011  y1 = max(y1, (sprite->ly + 7) >> 3);
1012  for(uint8_t y = y1; y <= y2; y++)
1013  {
1014  ssd1306_lcd.set_block(sprite->lx, y, sprite->w);
1015  for(uint8_t x = sprite->w; x > 0; x--)
1016  {
1017  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
1018  }
1019  ssd1306_intf.stop();
1020  }
1021  if (sprite->lx != sprite->x)
1022  {
1023  uint8_t x1 = sprite->lx;
1024  uint8_t x2 = sprite->lx + sprite->w - 1;
1025  if (sprite->x < sprite->lx)
1026  x1 = max(x1, sprite->x + sprite->w);
1027  else
1028  x2 = min((uint8_t)(sprite->x - 1), x2);
1029  for(uint8_t y = sprite->ly >> 3; y <= (sprite->ly + 7) >> 3; y++)
1030  {
1031  ssd1306_lcd.set_block(x1, y, x2 - x1 + 1 );
1032  for(uint8_t x = x2 - x1 + 1; x > 0; x--)
1033  {
1034  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
1035  }
1036  ssd1306_intf.stop();
1037  }
1038  }
1039 }
1040 
1041 SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
1042 {
1043  return (SPRITE){x,y,w,x,y,data,NULL};
1044 }
1045 
1046 void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
1047 {
1048  sprite->data = data;
1049 }
1050 
1052 {
1053  s_ssd1306_invertByte = 0xFF;
1054 }
1055 
1057 {
1058  s_ssd1306_invertByte = 0x00;
1059 }
1060 
1061 void ssd1306_setFont6x8(const uint8_t * progmemFont)
1062 {
1063  s_font6x8 = progmemFont + 4;
1064 }
1065 
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:738
void ssd1306_drawBitmap1_4(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:771
lcduint_t ssd1306_displayWidth(void)
uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:469
void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
Definition: ssd1306_1bit.c:612
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:804
void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: ssd1306_1bit.c:639
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:956
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:717
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(* send_pixels8)(uint8_t data)
Sends RGB pixel encoded in 3-3-2 format to OLED driver. Sends RGB pixel encoded in 3-3-2 format to OL...
Definition: lcd_common.h:142
void ssd1306_eraseTrace(SPRITE *sprite)
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:753
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:837
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:458
uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:515
void ssd1306_setFont6x8(const uint8_t *progmemFont)
void ssd1306_eraseSprite(SPRITE *sprite)
Definition: ssd1306_1bit.c:982
void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
Definition: ssd1306_1bit.c:693
void ssd1306_fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: ssd1306_1bit.c:909
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:944
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:683
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:894
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:590
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:725
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:605
size_t ssd1306_write(uint8_t ch)
Prints single character to display at current cursor position.
Definition: ssd1306_1bit.c:418