LCDGFX LCD display driver  1.0.2
This library is developed to control SSD1306/SSD1325/SSD1327/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
ssd1306_4bit.inl
1 /*
2  MIT License
3 
4  Copyright (c) 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 
25 #include "lcd_hal/io.h"
26 
27 extern uint8_t s_ssd1306_invertByte;
28 
30 //
31 // COMMON GRAPHICS
32 //
34 
35 //template class NanoDisplayOps4<I>;
36 
37 //template <class I>
38 //void NanoDisplayOps4<I>::printFixed(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style)
39 //{
40 // m_cursorX = xpos;
41 // m_cursorY = y;
42 // m_fontStyle = style;
43 // print( ch );
44 //}
45 
47 //
48 // 4-BIT GRAPHICS
49 //
51 
52 template <class I>
54 {
55  this->m_intf.startBlock(x, y, 0);
56  this->m_intf.send( (this->m_color & 0x0F) << (4*(x & 1)) );
57  this->m_intf.endBlock();
58 }
59 
60 template <class I>
62 {
63  uint8_t data = 0;
64  this->m_intf.startBlock(x1, y1, 0);
65  while (x1 < x2)
66  {
67  data |= (this->m_color & 0x0F) << (4*(x1 & 1));
68  if ( x1 & 1 )
69  {
70  this->m_intf.send( data );
71  data = 0;
72  }
73  x1++;
74  }
75  if (x1 & 1)
76  {
77  this->m_intf.send( data );
78  }
79  this->m_intf.endBlock();
80 }
81 
82 template <class I>
84 {
85  this->m_intf.startBlock(x1, y1, 1);
86  while (y1<=y2)
87  {
88  this->m_intf.send( (this->m_color & 0x0F) << (4*(x1 & 1)) );
89  y1++;
90  }
91  this->m_intf.endBlock();
92 }
93 
94 template <class I>
96 {
97  if (y1 > y2)
98  {
99  ssd1306_swap_data(y1, y2, lcdint_t);
100  }
101  if (x1 > x2)
102  {
103  ssd1306_swap_data(x1, x2, lcdint_t);
104  }
105  this->m_intf.startBlock(x1, y1, x2 - x1 + 1);
106  uint32_t count = (x2 - x1 + 1) * (y2 - y1 + 1);
107  while (count > 1)
108  {
109  this->m_intf.send( this->m_color );
110  count -= 2;
111  }
112  this->m_intf.endBlock();
113 }
114 
115 template <class I>
116 void NanoDisplayOps4<I>::fill(uint16_t color)
117 {
118  this->m_intf.startBlock(0, 0, 0);
119  uint32_t count = (uint32_t)this->m_w * (uint32_t)this->m_h / 2;
120  while (count > 0)
121  {
122  this->m_intf.send( color );
123  count --;
124  }
125  this->m_intf.endBlock();
126 }
127 
128 template <class I>
130 {
131  fill( 0x00 );
132 }
133 
134 template <class I>
135 void NanoDisplayOps4<I>::drawXBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
136 {
137  // TODO:
138 }
139 
140 template <class I>
141 void NanoDisplayOps4<I>::drawBitmap1(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
142 {
143  uint8_t bit = 1;
144  uint8_t blackColor = s_ssd1306_invertByte ? (this->m_color | (this->m_color << 4)) : 0x00;
145  uint8_t color = s_ssd1306_invertByte ? 0x00 : (this->m_color | (this->m_color << 4));
146  this->m_intf.startBlock(xpos, ypos, w);
147  while (h--)
148  {
149  lcduint_t wx;
150  uint8_t pixels = 0;
151  for (wx = xpos; wx < xpos + (lcdint_t)w; wx++)
152  {
153  uint8_t data = pgm_read_byte( bitmap );
154  uint8_t mask = wx & 0x01 ? 0xF0 : 0x0F;
155  if ( data & bit )
156  pixels |= color & mask;
157  else
158  pixels |= blackColor & mask;
159  bitmap++;
160  if ( wx & 0x01 )
161  {
162  this->m_intf.send( pixels );
163  pixels = 0;
164  }
165  }
166  if ( wx & 0x01 )
167  {
168  this->m_intf.send( pixels );
169  }
170  bit <<= 1;
171  if ( bit == 0 )
172  {
173  bit = 1;
174  }
175  else
176  {
177  bitmap -= w;
178  }
179  }
180  this->m_intf.endBlock();
181 }
182 
183 template <class I>
184 void NanoDisplayOps4<I>::drawBitmap4(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
185 {
186  this->m_intf.startBlock(x, y, w);
187  for (lcdint_t _y = y; _y < y + h; _y++)
188  {
189  uint8_t data = 0;
190  for (lcdint_t _x = x; _x < x + w; _x++)
191  {
192  uint8_t bmp = pgm_read_byte( bitmap );
193  if ( (_x - x) & 1 ) bmp >>=4; else bmp &= 0x0F;
194  data |= bmp << (4 * (_x & 1));
195  if ( (_x - x) & 1 )
196  {
197  bitmap++;
198  }
199  if ( _x & 1 )
200  {
201  this->m_intf.send( data );
202  data = 0;
203  }
204  }
205  if ( (x + w) & 1 )
206  {
207  this->m_intf.send( data );
208  }
209  }
210  this->m_intf.endBlock();
211 }
212 
213 template <class I>
214 void NanoDisplayOps4<I>::drawBitmap8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
215 {
216  this->m_intf.startBlock(x, y, w);
217  uint32_t count = (w) * (h);
218  while (count > 1)
219  {
220  uint8_t data1 = pgm_read_byte( bitmap++ );
221  uint8_t data2 = pgm_read_byte( bitmap++ );
222  this->m_intf.send( RGB8_TO_GRAY4(data1) | RGB8_TO_GRAY4(data2) << 4 );
223  count -= 2;
224  }
225  this->m_intf.endBlock();
226 }
227 
228 template <class I>
230 {
231  // NOT IMPLEMENTED
232 }
233 
234 template <class I>
235 void NanoDisplayOps4<I>::drawBuffer1(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *buffer)
236 {
237  uint8_t bit = 1;
238  uint8_t blackColor = s_ssd1306_invertByte ? (this->m_color | (this->m_color << 4)) : 0x00;
239  uint8_t color = s_ssd1306_invertByte ? 0x00 : (this->m_color | (this->m_color << 4));
240  this->m_intf.startBlock(xpos, ypos, w);
241  while (h--)
242  {
243  lcduint_t wx = w;
244  uint8_t pixels = 0;
245  while ( wx-- )
246  {
247  uint8_t data = *buffer;
248  uint8_t mask = wx & 0x01 ? 0xF0 : 0x0F;
249  if ( data & bit )
250  pixels |= color & mask;
251  else
252  pixels |= blackColor & mask;
253  if ( ( wx & 0x01 ) == 0x00 )
254  {
255  this->m_intf.send( pixels );
256  pixels = 0;
257  }
258  buffer++;
259  }
260  bit <<= 1;
261  if ( bit == 0 )
262  {
263  bit = 1;
264  }
265  else
266  {
267  buffer -= w;
268  }
269  }
270  this->m_intf.endBlock();
271 }
272 
273 template <class I>
275 {
276  this->drawBuffer1( x, y, w, h, buf );
277 }
278 
279 template <class I>
280 void NanoDisplayOps4<I>::drawBuffer4(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer)
281 {
282  this->m_intf.startBlock(x, y, w);
283  for (lcdint_t _y = y; _y < y + h; _y++)
284  {
285  uint8_t data = 0;
286  for (lcdint_t _x = x; _x < x + w; _x++)
287  {
288  uint8_t bmp = *buffer;
289  if ( (_x - x) & 1 ) bmp >>=4; else bmp &= 0x0F;
290  data |= bmp << (4 * (_x & 1));
291  if ( (_x - x) & 1 )
292  {
293  buffer++;
294  }
295  if ( _x & 1 )
296  {
297  this->m_intf.send( data );
298  data = 0;
299  }
300  }
301  if ( (x + w) & 1 )
302  {
303  this->m_intf.send( data );
304  }
305  }
306  this->m_intf.endBlock();
307 }
308 
309 template <class I>
310 void NanoDisplayOps4<I>::drawBuffer8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer)
311 {
312  this->m_intf.startBlock(x, y, w);
313  uint32_t count = (w) * (h);
314  while (count > 1)
315  {
316  uint8_t data1 = *buffer; buffer++;
317  uint8_t data2 = *buffer; buffer++;
318  this->m_intf.send( RGB8_TO_GRAY4(data1) | RGB8_TO_GRAY4(data2) << 4 );
319  count -= 2;
320  }
321  this->m_intf.endBlock();
322 }
323 
324 template <class I>
326 {
327  // NOT IMPLEMENTED
328 }
329 
330 template <class I>
332 {
333  uint16_t unicode = this->m_font->unicode16FromUtf8(c);
334  if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
335  SCharInfo char_info;
336  this->m_font->getCharBitmap(unicode, &char_info);
337  uint8_t mode = this->m_textMode;
338  for (uint8_t i = 0; i<(this->m_fontStyle == STYLE_BOLD ? 2: 1); i++)
339  {
340  this->drawBitmap1(this->m_cursorX + i,
341  this->m_cursorY,
342  char_info.width,
343  char_info.height,
344  char_info.glyph );
345  this->m_textMode |= CANVAS_MODE_TRANSPARENT;
346  }
347  this->m_textMode = mode;
348  this->m_cursorX += (lcdint_t)(char_info.width + char_info.spacing);
349  if ( ( (this->m_textMode & CANVAS_TEXT_WRAP_LOCAL) &&
350  (this->m_cursorX > ((lcdint_t)this->m_w - (lcdint_t)this->m_font->getHeader().width) ) )
351  || ( (this->m_textMode & CANVAS_TEXT_WRAP) &&
352  (this->m_cursorX > ((lcdint_t)this->m_w - (lcdint_t)this->m_font->getHeader().width)) ) )
353  {
354  this->m_cursorY += (lcdint_t)this->m_font->getHeader().height;
355  this->m_cursorX = 0;
356  if ( (this->m_textMode & CANVAS_TEXT_WRAP_LOCAL) &&
357  (this->m_cursorY > ((lcdint_t)this->m_h - (lcdint_t)this->m_font->getHeader().height)) )
358  {
359  this->m_cursorY = 0;
360  }
361  }
362  return 1;
363 }
364 
365 template <class I>
366 size_t NanoDisplayOps4<I>::write(uint8_t c)
367 {
368  if (c == '\n')
369  {
370  this->m_cursorY += (lcdint_t)this->m_font->getHeader().height;
371  this->m_cursorX = 0;
372  }
373  else if (c == '\r')
374  {
375  // skip non-printed char
376  }
377  else
378  {
379  return printChar( c );
380  }
381  return 1;
382 }
383 
384 template <class I>
385 void NanoDisplayOps4<I>::printFixed(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style)
386 {
387  // TODO: fontstyle not supported
388  // m_fontStyle = style;
389  this->m_cursorX = xpos;
390  this->m_cursorY = y;
391  while (*ch)
392  {
393  this->write(*ch);
394  ch++;
395  }
396 }
397 
void fill(uint16_t color)
void drawHLine(lcdint_t x1, lcdint_t y1, lcdint_t x2)
uint8_t height
char height in pixels
Definition: canvas_types.h:145
uint8_t lcduint_t
Definition: canvas_types.h:81
void drawXBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
void putPixel(lcdint_t x, lcdint_t y) __attribute__((noinline))
void drawVLine(lcdint_t x1, lcdint_t y1, lcdint_t y2)
void drawBuffer4(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer) __attribute__((noinline))
int8_t lcdint_t
Definition: canvas_types.h:79
#define SSD1306_MORE_CHARS_REQUIRED
Definition: canvas_types.h:43
void printFixed(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style=STYLE_NORMAL) __attribute__((noinline))
void drawBuffer8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer)
void drawBitmap4(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap) __attribute__((noinline))
Draws 4-bit gray-color bitmap in color buffer. Draws 4-bit gray-color bitmap in color buffer...
void drawBitmap8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
Draws 8-bit color bitmap in color buffer. Draws 8-bit color bitmap in color buffer.
uint8_t printChar(uint8_t c)
void drawBuffer16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *buffer) __attribute__((noinline))
size_t write(uint8_t c) __attribute__((noinline))
void drawBitmap16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
uint8_t width
char width in pixels
Definition: canvas_types.h:144
#define RGB8_TO_GRAY4(rgb)
Definition: canvas_types.h:61
void drawBuffer1Fast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer)
void fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__((noinline))
const uint8_t * glyph
char data, located in progmem.
Definition: canvas_types.h:147
void drawBitmap1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap) __attribute__((noinline))
Draws monochrome bitmap in color buffer using color, specified via setColor() method Draws monochrome...
void drawBuffer1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buffer) __attribute__((noinline))
uint8_t spacing
additional spaces after char in pixels
Definition: canvas_types.h:146
EFontStyle
Definition: canvas_types.h:90
#define ssd1306_swap_data(a, b, type)
Definition: io.h:102