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