SSD1306 OLED display driver  1.7.6
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-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 
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 const uint8_t *s_font6x8 = &ssd1306xled_font6x8[4];
42 extern lcduint_t ssd1306_cursorX;
43 extern lcduint_t ssd1306_cursorY;
45 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
46 extern uint8_t g_ssd1306_unicode;
47 #endif
48 
49 void ssd1306_fillScreen(uint8_t fill_Data)
50 {
51  fill_Data ^= s_ssd1306_invertByte;
52  ssd1306_lcd.set_block(0, 0, 0);
53  for(uint8_t m=(ssd1306_lcd.height >> 3); m>0; m--)
54  {
55  for(uint8_t n=ssd1306_lcd.width; n>0; n--)
56  {
57  ssd1306_lcd.send_pixels1(fill_Data);
58  }
60  }
62 }
63 
65 {
66  ssd1306_lcd.set_block(0, 0, 0);
67  for(uint8_t m=(ssd1306_lcd.height >> 3); m>0; m--)
68  {
69  for(uint8_t n=ssd1306_lcd.width; n>0; n--)
70  {
71  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
72  }
74  }
76 }
77 
78 uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
79 {
80  uint8_t i, j=0;
81  uint8_t text_index = 0;
82  uint8_t page_offset = 0;
83  uint8_t x = xpos;
84  y >>= 3;
85  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
86  for(;;)
87  {
88  uint8_t ldata;
89  if( (x > ssd1306_lcd.width - s_fixedFont.h.width) || (ch[j] == '\0') )
90  {
91  x = xpos;
92  y++;
93  if (y >= (ssd1306_lcd.height >> 3))
94  {
95  break;
96  }
97  page_offset++;
98  if (page_offset == s_fixedFont.pages)
99  {
100  text_index = j;
101  page_offset = 0;
102  if (ch[j] == '\0')
103  {
104  break;
105  }
106  }
107  else
108  {
109  j = text_index;
110  }
111  ssd1306_intf.stop();
112  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
113  }
114  const uint8_t * glyph_ptr;
115 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
116  if (g_ssd1306_unicode)
117  {
118  uint16_t unicode;
119  do
120  {
121  unicode = ssd1306_unicode16FromUtf8(ch[j]);
122  j++;
123  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
124  glyph_ptr = ssd1306_getU16CharGlyph( unicode );
125  }
126  else
127 #endif
128  {
129  glyph_ptr = ssd1306_getCharGlyph( ch[j] );
130  j++;
131  }
132  ldata = 0;
133  glyph_ptr += page_offset * s_fixedFont.h.width;
134  for( i=s_fixedFont.h.width; i>0; i--)
135  {
136  uint8_t data;
137  if ( style == STYLE_NORMAL )
138  {
139  data = pgm_read_byte(glyph_ptr);
140  }
141  else if ( style == STYLE_BOLD )
142  {
143  uint8_t temp = pgm_read_byte(glyph_ptr);
144  data = temp | ldata;
145  ldata = temp;
146  }
147  else
148  {
149  uint8_t temp = pgm_read_byte(glyph_ptr + 1);
150  data = (temp & 0xF0) | ldata;
151  ldata = (temp & 0x0F);
152  }
153  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
154  glyph_ptr++;
155  }
156  x += s_fixedFont.h.width;
157  }
158  ssd1306_intf.stop();
159  return j;
160 }
161 
162 uint8_t ssd1306_printFixed2x(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 << 1)) || (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 << 1))
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 >> 1)) * 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  if (page_offset & 1) data >>= 4;
227  data = ((data & 0x01) ? 0x03: 0x00) |
228  ((data & 0x02) ? 0x0C: 0x00) |
229  ((data & 0x04) ? 0x30: 0x00) |
230  ((data & 0x08) ? 0xC0: 0x00);
231  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
232  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
233  offset++;
234  }
235  x += (s_fixedFont.h.width << 1);
236  j++;
237  }
238  ssd1306_intf.stop();
239  return j;
240 }
241 
242 
243 uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
244 {
245  uint8_t i, j=0;
246  uint8_t text_index = 0;
247  uint8_t page_offset = 0;
248  uint8_t x = xpos;
249  y >>= 3;
250  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
251  for(;;)
252  {
253  uint8_t ldata;
254  if( (x > ssd1306_lcd.width - (s_fixedFont.h.width << factor)) || (ch[j] == '\0') )
255  {
256  x = xpos;
257  y++;
258  if (y >= (ssd1306_lcd.height >> 3))
259  {
260  break;
261  }
262  page_offset++;
263  if (page_offset == (s_fixedFont.pages << factor))
264  {
265  text_index = j;
266  page_offset = 0;
267  if (ch[j] == '\0')
268  {
269  break;
270  }
271  }
272  else
273  {
274  j = text_index;
275  }
276  ssd1306_intf.stop();
277  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
278  }
279  const uint8_t *glyph_ptr;
280 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
281  if (g_ssd1306_unicode)
282  {
283  uint16_t unicode;
284  do
285  {
286  unicode = ssd1306_unicode16FromUtf8(ch[j]);
287  j++;
288  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
289  glyph_ptr = ssd1306_getU16CharGlyph( unicode );
290  }
291  else
292 #endif
293  {
294  glyph_ptr = ssd1306_getCharGlyph( ch[j] );
295  j++;
296  }
297  ldata = 0;
298  glyph_ptr += (page_offset >> factor) * s_fixedFont.h.width;
299  for( i=s_fixedFont.h.width; i>0; i--)
300  {
301  uint8_t data;
302  if ( style == STYLE_NORMAL )
303  {
304  data = pgm_read_byte(glyph_ptr);
305  }
306  else if ( style == STYLE_BOLD )
307  {
308  uint8_t temp = pgm_read_byte(glyph_ptr);
309  data = temp | ldata;
310  ldata = temp;
311  }
312  else
313  {
314  uint8_t temp = pgm_read_byte(glyph_ptr+1);
315  data = (temp & 0xF0) | ldata;
316  ldata = (temp & 0x0F);
317  }
318  if ( factor > 0 )
319  {
320  uint8_t accum = 0;
321  uint8_t mask = ~((0xFF) << (1<<factor));
322  // N=0 -> right shift is always 0
323  // N=1 -> right shift goes through 0, 4
324  // N=2 -> right shift goes through 0, 2, 4, 6
325  // N=3 -> right shift goes through 0, 1, 2, 3, 4, 5, 6, 7
326  data >>= ((page_offset & ((1<<factor) - 1))<<(3-factor));
327  for (uint8_t idx = 0; idx < 1<<(3-factor); idx++)
328  {
329  accum |= (((data>>idx) & 0x01) ? (mask<<(idx<<factor)) : 0);
330  }
331  data = accum;
332  }
333  for (uint8_t z=(1<<factor); z>0; z--)
334  {
335  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
336  }
337  glyph_ptr++;
338  }
339  x += (s_fixedFont.h.width << factor);
340  }
341  ssd1306_intf.stop();
342  return j;
343 }
344 
345 size_t ssd1306_write(uint8_t ch)
346 {
347  if (ch == '\r')
348  {
349  ssd1306_cursorX = 0;
350  return 0;
351  }
352  else if ( (ssd1306_cursorX > ssd1306_lcd.width - s_fixedFont.h.width) || (ch == '\n') )
353  {
354  ssd1306_cursorX = 0;
355  ssd1306_cursorY += s_fixedFont.h.height;
356  if ( ssd1306_cursorY > ssd1306_lcd.height - s_fixedFont.h.height )
357  {
358  ssd1306_cursorY = 0;
359  }
360  ssd1306_clearBlock(0, ssd1306_cursorY >> 3, ssd1306_lcd.width, s_fixedFont.h.height);
361  if (ch == '\n')
362  {
363  return 0;
364  }
365  }
366  const uint8_t *glyph_ptr;
367 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
368  if (g_ssd1306_unicode)
369  {
370  uint16_t unicode = ssd1306_unicode16FromUtf8(ch);
371  if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
372  glyph_ptr = ssd1306_getU16CharGlyph( unicode );
373  }
374  else
375 #endif
376  {
377  glyph_ptr = ssd1306_getCharGlyph( ch );
378  }
379  ssd1306_drawBitmap( ssd1306_cursorX,
380  ssd1306_cursorY >> 3,
381  s_fixedFont.h.width,
382  s_fixedFont.h.height,
383  glyph_ptr );
384  ssd1306_cursorX += s_fixedFont.h.width;
385  return 1;
386 }
387 
388 size_t ssd1306_print(const char ch[])
389 {
390  size_t n = 0;
391  while (*ch)
392  {
393  n += ssd1306_write(*ch);
394  ch++;
395  }
396  return n;
397 }
398 
399 uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
400 {
401  uint8_t i, j=0;
403  while(ch[j] != '\0')
404  {
405  uint8_t ldata;
406  uint8_t c = ch[j] - 32;
407  if ( c > 224 )
408  {
409  c = 0;
410  }
411  if(x > ssd1306_lcd.width - 6)
412  {
413  x=0;
414  y++;
415  }
416  ldata = 0;
417  for(i=0;i<6;i++)
418  {
419  uint8_t data;
420  if ( style == STYLE_NORMAL )
421  {
422  data = pgm_read_byte(&s_font6x8[c*6+i]);
423  }
424  else if ( style == STYLE_BOLD )
425  {
426  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
427  data = temp | ldata;
428  ldata = temp;
429  }
430  else
431  {
432  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
433  data = (temp & 0xF0) | ldata;
434  ldata = (temp & 0x0F);
435  }
436  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
437  }
438  x += 6;
439  j++;
440  }
441  ssd1306_intf.stop();
442  return j;
443 }
444 
445 uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
446 {
447  uint8_t i, j=0;
448  uint8_t text_index = 0;
449  uint8_t odd = 0;
450  uint8_t x = xpos;
451  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
452  for(;;)
453  {
454  uint8_t c;
455  uint8_t ldata;
456  if( (x > ssd1306_lcd.width-12) || (ch[j] == '\0') )
457  {
458  x = xpos;
459  y++;
460  if (y >= (ssd1306_lcd.height >> 3))
461  {
462  break;
463  }
464  if (odd)
465  {
466  text_index = j;
467  if (ch[j] == '\0')
468  {
469  break;
470  }
471  }
472  else
473  {
474  j = text_index;
475  }
476  odd = !odd;
477  ssd1306_intf.stop();
478  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
479  }
480  c = ch[j] - 32;
481  if ( c > 224 )
482  {
483  c = 0;
484  }
485  ldata = 0;
486  for(i=0;i<6;i++)
487  {
488  uint8_t data;
489  if ( style == STYLE_NORMAL )
490  {
491  data = pgm_read_byte(&s_font6x8[c*6+i]);
492  }
493  else if ( style == STYLE_BOLD )
494  {
495  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
496  data = temp | ldata;
497  ldata = temp;
498  }
499  else
500  {
501  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
502  data = (temp & 0xF0) | ldata;
503  ldata = (temp & 0x0F);
504  }
505  if (odd) data >>= 4;
506  data = ((data & 0x01) ? 0x03: 0x00) |
507  ((data & 0x02) ? 0x0C: 0x00) |
508  ((data & 0x04) ? 0x30: 0x00) |
509  ((data & 0x08) ? 0xC0: 0x00);
510  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
511  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
512  }
513  x += 12;
514  j++;
515  }
516  ssd1306_intf.stop();
517  return j;
518 }
519 
520 uint8_t ssd1306_charF6x8_eol(uint8_t left,
521  uint8_t y,
522  const char ch[],
523  EFontStyle style,
524  uint8_t right)
525 {
526  uint8_t len = ssd1306_charF6x8(left, y, ch, style);
527  uint8_t text_end_pos = len * 6 + left;
528  if (text_end_pos <= right)
529  {
530  ssd1306_clearBlock(text_end_pos, y, right - text_end_pos + 1, 8);
531  }
532  return len;
533 }
534 
535 void ssd1306_putPixel(uint8_t x, uint8_t y)
536 {
537  ssd1306_lcd.set_block(x, y >> 3, 1);
538  ssd1306_lcd.send_pixels1((1 << (y & 0x07))^s_ssd1306_invertByte);
539  ssd1306_intf.stop();
540 }
541 
542 void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
543 {
544  ssd1306_lcd.set_block(x, y >> 3, 1);
545  ssd1306_lcd.send_pixels1(pixels^s_ssd1306_invertByte);
546  ssd1306_intf.stop();
547 }
548 
549 void ssd1306_putPixel_delayed(uint8_t x, uint8_t y, uint8_t complete)
550 {
551  static uint8_t lx = 0, ly = 0xFF;
552  static uint8_t pixels = 0;
553  if ((lx != x) || ((ly & 0xF8) != (y & 0xF8)) || (complete))
554  {
555  if (ly != 0xFF)
556  {
557  ssd1306_putPixels( lx, ly, pixels );
558  }
559  pixels = 0;
560  ly = 0xFF;
561  }
562  if ( !complete )
563  {
564  pixels |= (1 << (y & 0x07));
565  lx = x; ly = y;
566  }
567 }
568 
569 void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
570 {
571  lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
572  lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
573  lcduint_t err = 0;
574  if (dy > dx)
575  {
576  if (y1 > y2)
577  {
578  ssd1306_swap_data(x1, x2, uint8_t);
579  ssd1306_swap_data(y1, y2, uint8_t);
580  }
581  for(; y1<=y2; y1++)
582  {
583  err += dx;
584  if (err >= dy)
585  {
586  err -= dy;
587  x1 < x2 ? x1++: x1--;
588  }
589  ssd1306_putPixel_delayed( x1, y1, 0 );
590  }
591  ssd1306_putPixel_delayed( 0, 0, 1 );
592  }
593  else
594  {
595  if (x1 > x2)
596  {
597  ssd1306_swap_data(x1, x2, uint8_t);
598  ssd1306_swap_data(y1, y2, uint8_t);
599  }
600  for(; x1<=x2; x1++)
601  {
602  err += dy;
603  if (err >= dx)
604  {
605  err -= dx;
606  if (y1 < y2) y1++; else y1--;
607  }
608  ssd1306_putPixel( x1, y1 );
609  }
610  }
611 }
612 
613 void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
614 {
615  ssd1306_lcd.set_block(x1, y1 >> 3, x2 - x1 + 1);
616  for (uint8_t x = x1; x <= x2; x++)
617  {
618  ssd1306_lcd.send_pixels1((1 << (y1 & 0x07))^s_ssd1306_invertByte);
619  }
620  ssd1306_intf.stop();
621 }
622 
623 void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
624 {
625  uint8_t topPage = y1 >> 3;
626  uint8_t bottomPage = y2 >> 3;
627  uint8_t height = y2-y1;
628  uint8_t y;
629  ssd1306_lcd.set_block(x1, topPage, 1);
630  if (topPage == bottomPage)
631  {
632  ssd1306_lcd.send_pixels1( ((0xFF >> (0x07 - height)) << (y1 & 0x07))^s_ssd1306_invertByte );
633  ssd1306_intf.stop();
634  return;
635  }
636  ssd1306_lcd.send_pixels1( (0xFF << (y1 & 0x07))^s_ssd1306_invertByte );
637  for ( y = (topPage + 1); y <= (bottomPage - 1); y++)
638  {
640  ssd1306_lcd.send_pixels1( 0xFF^s_ssd1306_invertByte );
641  }
643  ssd1306_lcd.send_pixels1( (0xFF >> (0x07 - (y2 & 0x07)))^s_ssd1306_invertByte );
644  ssd1306_intf.stop();
645 }
646 
647 void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
648 {
649  ssd1306_drawHLine(x1+1, y1, x2-1);
650  ssd1306_drawHLine(x1+1, y2, x2-1);
651  ssd1306_drawVLine(x1, y1, y2);
652  ssd1306_drawVLine(x2, y1, y2);
653 }
654 
655 void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
656 {
657  uint8_t j;
658  ssd1306_lcd.set_block(x, y >> 3, w);
659  for(j=(h >> 3); j>0; j--)
660  {
662  buf+=w;
664  }
665  ssd1306_intf.stop();
666 }
667 
668 void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
669 {
670  uint8_t i, j;
671  ssd1306_lcd.set_block(x, y, w);
672  for(j=(h >> 3); j>0; j--)
673  {
674  for(i=w;i>0;i--)
675  {
676  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^*buf++);
677  }
679  }
680  ssd1306_intf.stop();
681 }
682 
683 void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
684 {
685  uint8_t i, j;
686  uint8_t remainder = (ssd1306_lcd.width - x) < w ? (w + x - ssd1306_lcd.width): 0;
687  w -= remainder;
688  ssd1306_lcd.set_block(x, y, w);
689  for(j=(h >> 3); j>0; j--)
690  {
691  for(i=w;i>0;i--)
692  {
693  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^pgm_read_byte(buf++));
694  }
695  buf += remainder;
697  }
698  ssd1306_intf.stop();
699 }
700 
701 void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
702 {
703  lcduint_t origin_width = w;
704  uint8_t offset = y & 0x07;
705  uint8_t complexFlag = 0;
706  uint8_t mainFlag = 1;
707  uint8_t max_pages;
708  uint8_t pages;
709  lcduint_t i, j;
710  if (y + (lcdint_t)h <= 0) return;
711  if (y >= ssd1306_lcd.height) return;
712  if (x + (lcdint_t)w <= 0) return;
713  if (x >= ssd1306_lcd.width) return;
714  if (y < 0)
715  {
716  buf += ((lcduint_t)((-y) + 7) >> 3) * w;
717  h += y;
718  y = 0;
719  complexFlag = 1;
720  }
721  if (x < 0)
722  {
723  buf += -x;
724  w += x;
725  x = 0;
726  }
727  max_pages = (lcduint_t)(h + 15 - offset) >> 3;
728  if ((lcduint_t)((lcduint_t)y + h) > (lcduint_t)ssd1306_lcd.height)
729  {
730  h = (lcduint_t)(ssd1306_lcd.height - (lcduint_t)y);
731  }
732  if ((lcduint_t)((lcduint_t)x + w) > (lcduint_t)ssd1306_lcd.width)
733  {
734  w = (lcduint_t)(ssd1306_lcd.width - (lcduint_t)x);
735  }
736  pages = ((y + h - 1) >> 3) - (y >> 3) + 1;
737 
738  ssd1306_lcd.set_block(x, y >> 3, w);
739  for(j=0; j < pages; j++)
740  {
741  if ( j == max_pages - 1 ) mainFlag = !offset;
742  for( i=w; i > 0; i--)
743  {
744  uint8_t data = 0;
745  if ( mainFlag ) data |= (pgm_read_byte(buf) << offset);
746  if ( complexFlag ) data |= (pgm_read_byte(buf - origin_width) >> (8 - offset));
747  buf++;
748  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^data);
749  }
750  buf += origin_width - w;
751  complexFlag = offset;
753  }
754  ssd1306_intf.stop();
755 }
756 
757 
758 void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
759 {
760  uint8_t i, j;
761  ssd1306_lcd.set_block(x, y, w);
762  for(j=(h >> 3); j>0; j--)
763  {
764  for(i=w;i>0;i--)
765  {
766  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
767  }
769  }
770  ssd1306_intf.stop();
771 }
772 
773 
774 void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
775 {
776  uint8_t i;
777  ssd1306_lcd.set_block(x,y,w);
778  for(i=0;i<w;i++)
779  {
780  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^pgm_read_byte(&sprite[i]));
781  }
782  ssd1306_intf.stop();
783 }
784 
785 
787 {
788  uint8_t offsety = sprite->y & 0x7;
789  if (sprite->y < ssd1306_lcd.height)
790  {
791  ssd1306_lcd.set_block(sprite->x, sprite->y >> 3, sprite->w);
792  for (uint8_t i=0; i < sprite->w; i++)
793  {
794  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte^(pgm_read_byte( &sprite->data[i] ) << offsety) );
795  }
796  ssd1306_intf.stop();
797  }
798  if (offsety && (sprite->y + 8 < ssd1306_lcd.height))
799  {
800  ssd1306_lcd.set_block(sprite->x, (sprite->y >> 3) + 1, sprite->w);
801  for (uint8_t i=0; i < sprite->w; i++)
802  {
803  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte^(pgm_read_byte( &sprite->data[i] ) >> (8 - offsety)) );
804  }
805  ssd1306_intf.stop();
806  }
807  sprite->lx = sprite->x;
808  sprite->ly = sprite->y;
809 }
810 
811 
813 {
814  uint8_t posy = sprite->y >> 3;
815  uint8_t offsety = sprite->y & 0x7;
816  ssd1306_lcd.set_block(sprite->x, posy, sprite->w);
817  for (uint8_t i=sprite->w; i > 0; i--)
818  {
819  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
820  }
821  ssd1306_intf.stop();
822  if (offsety)
823  {
824  ssd1306_lcd.set_block(sprite->x, posy + 1, sprite->w);
825  for (uint8_t i=sprite->w; i > 0; i--)
826  {
827  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
828  }
829  }
830  ssd1306_intf.stop();
831 }
832 
833 
835 {
836  uint8_t y1 = sprite->ly >> 3;
837  uint8_t y2 = (sprite->ly + 7) >> 3;
838  if (sprite->ly < sprite->y)
839  y2 = min(y2, (uint8_t)((sprite->y >> 3) - 1));
840  else if (sprite->y + 8 > sprite->ly)
841  y1 = max(y1, (sprite->ly + 7) >> 3);
842  for(uint8_t y = y1; y <= y2; y++)
843  {
844  ssd1306_lcd.set_block(sprite->lx, y, sprite->w);
845  for(uint8_t x = sprite->w; x > 0; x--)
846  {
847  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
848  }
849  ssd1306_intf.stop();
850  }
851  if (sprite->lx != sprite->x)
852  {
853  uint8_t x1 = sprite->lx;
854  uint8_t x2 = sprite->lx + sprite->w - 1;
855  if (sprite->x < sprite->lx)
856  x1 = max(x1, sprite->x + sprite->w);
857  else
858  x2 = min((uint8_t)(sprite->x - 1), x2);
859  for(uint8_t y = sprite->ly >> 3; y <= (sprite->ly + 7) >> 3; y++)
860  {
861  ssd1306_lcd.set_block(x1, y, x2 - x1 + 1 );
862  for(uint8_t x = x2 - x1 + 1; x > 0; x--)
863  {
864  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
865  }
866  ssd1306_intf.stop();
867  }
868  }
869 }
870 
871 SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
872 {
873  return (SPRITE){x,y,w,x,y,data,NULL};
874 }
875 
876 void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
877 {
878  sprite->data = data;
879 }
880 
882 {
883  s_ssd1306_invertByte = 0xFF;
884 }
885 
887 {
888  s_ssd1306_invertByte = 0x00;
889 }
890 
891 void ssd1306_setFont6x8(const uint8_t * progmemFont)
892 {
893  s_font6x8 = progmemFont + 4;
894 }
895 
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:668
uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:399
void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
Definition: ssd1306_1bit.c:542
void ssd1306_positiveMode()
Definition: ssd1306_1bit.c:886
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)
Definition: ssd1306_1bit.c:871
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:162
void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: ssd1306_1bit.c:569
uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
Definition: ssd1306_1bit.c:78
void ssd1306_drawSprite(SPRITE *sprite)
Definition: ssd1306_1bit.c:786
uint8_t width
width in pixels
void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: ssd1306_1bit.c:647
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:49
unsigned int lcduint_t
Definition: io.h:65
void ssd1306_eraseTrace(SPRITE *sprite)
Definition: ssd1306_1bit.c:834
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:683
const PROGMEM uint8_t ssd1306xled_font6x8[]
Definition: ssd1306_fonts.c:41
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:701
uint8_t ascii_offset
ascii offset
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:32
size_t ssd1306_print(const char ch[])
Prints null-terminated string to display at current cursor position.
Definition: ssd1306_1bit.c:388
uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:445
void ssd1306_eraseSprite(SPRITE *sprite)
Definition: ssd1306_1bit.c:812
void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
Definition: ssd1306_1bit.c:623
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
void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
Definition: ssd1306_1bit.c:774
SFixedFontInfo s_fixedFont
Definition: tiler.h:44
SFontHeaderRecord h
record, containing information on font
uint8_t x
draw position X on the screen
uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
Definition: ssd1306_1bit.c:243
uint8_t w
sprite width
void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
Definition: ssd1306_1bit.c:613
#define SSD1306_MORE_CHARS_REQUIRED
Definition: ssd1306_fonts.h:44
void(* next_page)(void)
Definition: lcd_common.h:122
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:758
void ssd1306_setFont6x8(const uint8_t *progmemFont)
Definition: ssd1306_1bit.c:891
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:520
void ssd1306_clearScreen()
Definition: ssd1306_1bit.c:64
void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
Definition: ssd1306_1bit.c:876
EFontStyle
void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:655
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()
Definition: ssd1306_1bit.c:881
void ssd1306_putPixel(uint8_t x, uint8_t y)
Definition: ssd1306_1bit.c:535
size_t ssd1306_write(uint8_t ch)
Prints single character to display at current cursor position.
Definition: ssd1306_1bit.c:345