FabGL
ESP32 Display Controller and Graphics Library
SSD1306Controller.cpp
1 /*
2  Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3  Copyright (c) 2019-2020 Fabrizio Di Vittorio.
4  All rights reserved.
5 
6  This file is part of FabGL Library.
7 
8  FabGL is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  FabGL is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with FabGL. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 
23 #ifdef ARDUINO
24 
25 
26 #include <string.h>
27 
28 #include "freertos/FreeRTOS.h"
29 #include "freertos/task.h"
30 
31 #include "fabutils.h"
32 #include "SSD1306Controller.h"
33 
34 
35 
36 
37 #define SSD1306_I2C_TIMEOUT 100 // ms
38 #define SSD1306_I2C_FREQUENCY 400000
39 
40 #define SSD1306_UPDATETASK_STACK 1024
41 #define SSD1306_UPDATETASK_PRIORITY 5
42 
43 #define SSD1306_BACKGROUND_PRIMITIVE_TIMEOUT 10000 // uS
44 
45 
46 #define SSD1306_SETLOWCOLUMN 0x00
47 #define SSD1306_SETHIGHCOLUMN 0x10
48 #define SSD1306_MEMORYMODE 0x20
49 #define SSD1306_COLUMNADDR 0x21
50 #define SSD1306_PAGEADDR 0x22
51 #define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
52 #define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
53 #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
54 #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A
55 #define SSD1306_DEACTIVATE_SCROLL 0x2E
56 #define SSD1306_ACTIVATE_SCROLL 0x2F
57 #define SSD1306_SETSTARTLINE 0x40
58 #define SSD1306_SETCONTRAST 0x81
59 #define SSD1306_CHARGEPUMP 0x8D
60 #define SSD1306_SEGREMAP 0xA0
61 #define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3
62 #define SSD1306_DISPLAYALLON_RESUME 0xA4
63 #define SSD1306_DISPLAYALLON 0xA5
64 #define SSD1306_NORMALDISPLAY 0xA6
65 #define SSD1306_INVERTDISPLAY 0xA7
66 #define SSD1306_SETMULTIPLEX 0xA8
67 #define SSD1306_DISPLAYOFF 0xAE
68 #define SSD1306_DISPLAYON 0xAF
69 #define SSD1306_COMSCANINC 0xC0
70 #define SSD1306_COMSCANDEC 0xC8
71 #define SSD1306_SETDISPLAYOFFSET 0xD3
72 #define SSD1306_SETDISPLAYCLOCKDIV 0xD5
73 #define SSD1306_SETPRECHARGE 0xD9
74 #define SSD1306_SETCOMPINS 0xDA
75 #define SSD1306_SETVCOMDETECT 0xDB
76 
77 
78 #define SSD1306_SETPIXEL(x, y) (m_screenBuffer[(x) + ((y) >> 3) * m_viewPortWidth] |= (1 << ((y) & 7)))
79 #define SSD1306_CLEARPIXEL(x, y) (m_screenBuffer[(x) + ((y) >> 3) * m_viewPortWidth] &= ~(1 << ((y) & 7)))
80 #define SSD1306_INVERTPIXEL(x, y) (m_screenBuffer[(x) + ((y) >> 3) * m_viewPortWidth] ^= (1 << ((y) & 7)))
81 
82 #define SSD1306_SETPIXELCOLOR(x, y, color) { if ((color)) SSD1306_SETPIXEL((x), (y)); else SSD1306_CLEARPIXEL((x), (y)); }
83 
84 #define SSD1306_GETPIXEL(x, y) ((m_screenBuffer[(x) + ((y) >> 3) * m_viewPortWidth] >> ((y) & 7)) & 1)
85 
86 
87 namespace fabgl {
88 
89 
90 inline uint8_t RGB888toMono(RGB888 const & rgb)
91 {
92  return rgb.R > 0 || rgb.G > 0 || rgb.B > 0 ? 1 : 0;
93 }
94 
95 
96 inline uint8_t RGBA2222toMono(uint8_t rgba2222)
97 {
98  return (rgba2222 & 0x3f) ? 1 : 0;
99 }
100 
101 
102 inline uint8_t RGBA8888toMono(RGBA8888 const & rgba)
103 {
104  return rgba.R > 0 || rgba.G > 0 || rgba.B > 0 ? 1 : 0;
105 }
106 
107 
108 inline uint8_t preparePixel(RGB888 const & rgb)
109 {
110  return RGB888toMono(rgb);
111 }
112 
113 
114 
115 SSD1306Controller::SSD1306Controller()
116  : m_i2c(nullptr),
117  m_screenBuffer(nullptr),
118  m_updateTaskHandle(nullptr),
119  m_updateTaskRunning(false),
120  m_orientation(SSD1306Orientation::Normal)
121 {
122 }
123 
124 
125 SSD1306Controller::~SSD1306Controller()
126 {
127  end();
128 }
129 
130 
131 void SSD1306Controller::begin(I2C * i2c, int address, gpio_num_t resetGPIO)
132 {
133  m_i2c = i2c;
134  m_i2cAddress = address;
135  m_resetGPIO = resetGPIO;
136 }
137 
138 
140 {
141  auto i2c = new I2C;
142  i2c->begin(GPIO_NUM_4, GPIO_NUM_15);
143  begin(i2c);
144 }
145 
146 
147 void SSD1306Controller::end()
148 {
149  if (m_updateTaskHandle)
150  vTaskDelete(m_updateTaskHandle);
151  m_updateTaskHandle = nullptr;
152 
153  free(m_screenBuffer);
154  m_screenBuffer = nullptr;
155 }
156 
157 
158 void SSD1306Controller::setResolution(char const * modeline, int viewPortWidth, int viewPortHeight, bool doubleBuffered)
159 {
160  char label[32];
161  int pos = 0, swidth, sheight;
162  int count = sscanf(modeline, "\"%[^\"]\" %d %d %n", label, &swidth, &sheight, &pos);
163  if (count != 3 || pos == 0)
164  return; // invalid modeline
165 
166  m_screenWidth = swidth;
167  m_screenHeight = sheight;
168  m_screenCol = 0;
169  m_screenRow = 0;
170 
171  // inform base class about screen size
172  setScreenSize(m_screenWidth, m_screenHeight);
173 
174  setDoubleBuffered(doubleBuffered);
175 
176  m_viewPortWidth = viewPortWidth < 0 ? m_screenWidth : viewPortWidth;
177  m_viewPortHeight = viewPortHeight < 0 ? m_screenHeight : viewPortHeight;
178 
179  resetPaintState();
180 
181  SSD1306_hardReset();
182 
183  if (!SSD1306_softReset())
184  return;
185 
186  allocScreenBuffer();
187 
188  // setup update task
189  xTaskCreate(&updateTaskFunc, "", SSD1306_UPDATETASK_STACK, this, SSD1306_UPDATETASK_PRIORITY, &m_updateTaskHandle);
190 
191  // allows updateTaskFunc() to run
192  m_updateTaskFuncSuspended = 0;
193 }
194 
195 
197 {
198  if (value != m_screenCol) {
199  m_screenCol = iclamp(value, 0, m_viewPortWidth - m_screenWidth);
200  sendRefresh();
201  }
202 }
203 
204 
206 {
207  if (value != m_screenRow) {
208  m_screenRow = iclamp(value, 0, m_viewPortHeight - m_screenHeight);
209  sendRefresh();
210  }
211 }
212 
213 
214 void SSD1306Controller::sendRefresh()
215 {
216  Primitive p(PrimitiveCmd::Refresh, Rect(0, 0, m_viewPortWidth - 1, m_viewPortHeight - 1));
217  addPrimitive(p);
218 }
219 
220 
221 bool SSD1306Controller::SSD1306_sendData(uint8_t * buf, int count, uint8_t ctrl)
222 {
223  int bufSize = m_i2c->getMaxBufferLength();
224  uint8_t sbuf[bufSize];
225  sbuf[0] = ctrl;
226  while (count > 0) {
227  int bToSend = imin(bufSize - 1, count);
228  memcpy(&sbuf[1], buf, bToSend);
229  if (!m_i2c->write(m_i2cAddress, sbuf, bToSend + 1, SSD1306_I2C_FREQUENCY, SSD1306_I2C_TIMEOUT))
230  return false;
231  count -= bToSend;
232  buf += bToSend;
233  ets_delay_us(2); // delay 2uS (standing to SSD1306 doc should be 1.3uS, before new transmission can start)
234  }
235  return true;
236 }
237 
238 
239 bool SSD1306Controller::SSD1306_sendCmd(uint8_t c)
240 {
241  return SSD1306_sendData(&c, 1, 0x00);
242 }
243 
244 
245 bool SSD1306Controller::SSD1306_sendCmd(uint8_t c1, uint8_t c2)
246 {
247  uint8_t buf[2] = { c1, c2 };
248  return SSD1306_sendData(buf, 2, 0x00);
249 }
250 
251 
252 bool SSD1306Controller::SSD1306_sendCmd(uint8_t c1, uint8_t c2, uint8_t c3)
253 {
254  uint8_t buf[3] = { c1, c2, c3 };
255  return SSD1306_sendData(buf, 3, 0x00);
256 }
257 
258 
259 // hard reset SSD1306
260 void SSD1306Controller::SSD1306_hardReset()
261 {
262  if (m_resetGPIO != GPIO_UNUSED) {
263  configureGPIO(m_resetGPIO, GPIO_MODE_OUTPUT);
264  gpio_set_level(m_resetGPIO, 1);
265  vTaskDelay(1 / portTICK_PERIOD_MS);
266  gpio_set_level(m_resetGPIO, 0);
267  vTaskDelay(10 / portTICK_PERIOD_MS);
268  gpio_set_level(m_resetGPIO, 1);
269  }
270 }
271 
272 
273 // soft reset SSD1306
274 bool SSD1306Controller::SSD1306_softReset()
275 {
276  SSD1306_sendCmd(SSD1306_DISPLAYOFF);
277  SSD1306_sendCmd(SSD1306_SETDISPLAYCLOCKDIV, 0x80);
278  SSD1306_sendCmd(SSD1306_SETMULTIPLEX, m_screenHeight - 1);
279  SSD1306_sendCmd(SSD1306_SETDISPLAYOFFSET, 0);
280  SSD1306_sendCmd(SSD1306_SETSTARTLINE);
281  SSD1306_sendCmd(SSD1306_CHARGEPUMP, 0x14); // 0x14 = SWITCHCAPVCC, 0x10 = EXTERNALVCC
282  SSD1306_sendCmd(SSD1306_MEMORYMODE, 0b100); // 0b100 = page addressing mode
283  setupOrientation();
284  if (m_screenHeight == 64) {
285  SSD1306_sendCmd(SSD1306_SETCOMPINS, 0x12);
286  SSD1306_sendCmd(SSD1306_SETCONTRAST, 0xCF); // max: 0xCF = SWITCHCAPVCC, 0x9F = EXTERNALVCC
287  } else if (m_screenHeight == 32) {
288  SSD1306_sendCmd(SSD1306_SETCOMPINS, 0x02);
289  SSD1306_sendCmd(SSD1306_SETCONTRAST, 0x8F);
290  }
291  SSD1306_sendCmd(SSD1306_SETPRECHARGE, 0xF1); // 0xF1 = SWITCHCAPVCC, 0x22 = EXTERNALVCC
292  SSD1306_sendCmd(SSD1306_SETVCOMDETECT, 0x40);
293  SSD1306_sendCmd(SSD1306_DISPLAYALLON_RESUME);
294  SSD1306_sendCmd(SSD1306_NORMALDISPLAY);
295  SSD1306_sendCmd(SSD1306_DEACTIVATE_SCROLL);
296  return SSD1306_sendCmd(SSD1306_DISPLAYON);
297 }
298 
299 
300 void SSD1306Controller::setupOrientation()
301 {
302  switch (m_orientation) {
304  SSD1306_sendCmd(SSD1306_SEGREMAP | 0x1);
305  SSD1306_sendCmd(SSD1306_COMSCANDEC);
306  break;
308  SSD1306_sendCmd(SSD1306_SEGREMAP | 0x0);
309  SSD1306_sendCmd(SSD1306_COMSCANDEC);
310  break;
312  SSD1306_sendCmd(SSD1306_SEGREMAP | 0x1);
313  SSD1306_sendCmd(SSD1306_COMSCANINC);
314  break;
316  SSD1306_sendCmd(SSD1306_SEGREMAP | 0x0);
317  SSD1306_sendCmd(SSD1306_COMSCANINC);
318  break;
319  }
320 }
321 
322 
324 {
325  m_orientation = value;
326  setupOrientation();
327  sendRefresh();
328 }
329 
330 
331 void SSD1306Controller::SSD1306_sendScreenBuffer(Rect updateRect)
332 {
333  // align visible screen row to page (steps of 8 rows)
334  const int screenRow = m_screenRow & ~7;
335 
336  // visible area
337  const Rect scrRect = Rect(m_screenCol, screenRow, m_screenCol + m_screenWidth - 1, screenRow + m_screenHeight - 1);
338 
339  // align rectangle to update to pages (0, 8, 16...)
340  updateRect.Y1 &= ~7;
341  updateRect.Y2 = (updateRect.Y2 + 7) & ~7;
342 
343  // does the visible area intersect with area to update?
344  if (scrRect.intersects(updateRect)) {
345 
346  // intersection between visible area and rectangle to update
347  Rect r = updateRect.intersection(scrRect);
348 
349  // horizontal screen update limits
350  const int screenX1 = r.X1 - m_screenCol;
351  const int screenX2 = r.X2 - m_screenCol;
352 
353  // send one page (8 rows) at the time
354  for (int y = r.Y1; y <= r.Y2; y += 8) {
355  int screenY = y - screenRow;
356  if (screenY >= 0) {
357  int page = screenY >> 3;
358  if (!(SSD1306_sendCmd(SSD1306_PAGEADDR, page, page) && SSD1306_sendCmd(SSD1306_COLUMNADDR, screenX1, screenX2)))
359  break; // address selection failed, try with next page
360  SSD1306_sendData(m_screenBuffer + r.X1 + (y >> 3) * m_viewPortWidth, r.width(), 0x40);
361  }
362  }
363 
364  }
365 }
366 
367 
369 {
370  SSD1306_sendCmd(value ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY);
371 }
372 
373 
374 void SSD1306Controller::allocScreenBuffer()
375 {
376  m_screenBuffer = (uint8_t*) malloc(m_viewPortWidth * m_viewPortHeight / 8);
377  memset(m_screenBuffer, 0, m_viewPortWidth * m_viewPortHeight / 8);
378 }
379 
380 
381 void SSD1306Controller::updateTaskFunc(void * pvParameters)
382 {
383  SSD1306Controller * ctrl = (SSD1306Controller*) pvParameters;
384 
385  while (true) {
386 
387  ctrl->waitForPrimitives();
388 
389  // primitive processing blocked?
390  if (ctrl->m_updateTaskFuncSuspended > 0)
391  ulTaskNotifyTake(true, portMAX_DELAY); // yes, wait for a notify
392 
393  ctrl->m_updateTaskRunning = true;
394 
395  Rect updateRect = Rect(SHRT_MAX, SHRT_MAX, SHRT_MIN, SHRT_MIN);
396 
397  int64_t startTime = ctrl->backgroundPrimitiveTimeoutEnabled() ? esp_timer_get_time() : 0;
398  do {
399 
400  Primitive prim;
401  if (ctrl->getPrimitive(&prim) == false)
402  break;
403 
404  ctrl->execPrimitive(prim, updateRect, false);
405 
406  if (ctrl->m_updateTaskFuncSuspended > 0)
407  break;
408 
409  } while (!ctrl->backgroundPrimitiveTimeoutEnabled() || (startTime + SSD1306_BACKGROUND_PRIMITIVE_TIMEOUT > esp_timer_get_time()));
410 
411  ctrl->showSprites(updateRect);
412 
413  ctrl->m_updateTaskRunning = false;
414 
415  if (!ctrl->isDoubleBuffered())
416  ctrl->SSD1306_sendScreenBuffer(updateRect);
417  }
418 }
419 
420 
421 
423 {
424  ++m_updateTaskFuncSuspended;
425  while (m_updateTaskRunning)
426  taskYIELD();
427 }
428 
429 
431 {
432  m_updateTaskFuncSuspended = tmax(0, m_updateTaskFuncSuspended - 1);
433  if (m_updateTaskFuncSuspended == 0)
434  xTaskNotifyGive(m_updateTaskHandle); // resume updateTaskFunc()
435 }
436 
437 
438 void SSD1306Controller::setPixelAt(PixelDesc const & pixelDesc, Rect & updateRect)
439 {
440  genericSetPixelAt(pixelDesc, updateRect,
441  [&] (RGB888 const & color) { return preparePixel(color); },
442  [&] (int X, int Y, uint8_t pattern) { SSD1306_SETPIXELCOLOR(X, Y, pattern); }
443  );
444 }
445 
446 
447 // coordinates are absolute values (not relative to origin)
448 // line clipped on current absolute clipping rectangle
449 void SSD1306Controller::absDrawLine(int X1, int Y1, int X2, int Y2, RGB888 color)
450 {
451  genericAbsDrawLine(X1, Y1, X2, Y2, color,
452  [&] (RGB888 const & color) { return preparePixel(color); },
453  [&] (int Y, int X1, int X2, uint8_t pattern) { rawFillRow(Y, X1, X2, pattern); },
454  [&] (int Y, int X1, int X2) { rawInvertRow(Y, X1, X2); },
455  [&] (int X, int Y, uint8_t pattern) { SSD1306_SETPIXELCOLOR(X, Y, pattern); },
456  [&] (int X, int Y) { SSD1306_INVERTPIXEL(X, Y); }
457  );
458 }
459 
460 
461 // parameters not checked
462 void SSD1306Controller::rawFillRow(int y, int x1, int x2, uint8_t pattern)
463 {
464  if (pattern) {
465  for (; x1 <= x2; ++x1)
466  SSD1306_SETPIXEL(x1, y);
467  } else {
468  for (; x1 <= x2; ++x1)
469  SSD1306_CLEARPIXEL(x1, y);
470  }
471 }
472 
473 
474 // parameters not checked
475 void SSD1306Controller::rawFillRow(int y, int x1, int x2, RGB888 color)
476 {
477  rawFillRow(y, x1, x2, preparePixel(color));
478 }
479 
480 
481 // parameters not checked
482 void SSD1306Controller::rawInvertRow(int y, int x1, int x2)
483 {
484  for (; x1 <= x2; ++x1)
485  SSD1306_INVERTPIXEL(x1, y);
486 }
487 
488 
489 void SSD1306Controller::drawEllipse(Size const & size, Rect & updateRect)
490 {
491  genericDrawEllipse(size, updateRect,
492  [&] (RGB888 const & color) { return preparePixel(color); },
493  [&] (int X, int Y, uint8_t pattern) { SSD1306_SETPIXELCOLOR(X, Y, pattern); }
494  );
495 }
496 
497 
498 void SSD1306Controller::clear(Rect & updateRect)
499 {
500  hideSprites(updateRect);
501  uint8_t pattern = preparePixel(getActualBrushColor());
502  memset(m_screenBuffer, (pattern ? 255 : 0), m_viewPortWidth * m_viewPortHeight / 8);
503 }
504 
505 
506 void SSD1306Controller::VScroll(int scroll, Rect & updateRect)
507 {
508  genericVScroll(scroll, updateRect,
509  [&] (int x1, int x2, int srcY, int dstY) { rawCopyRow(x1, x2, srcY, dstY); }, // rawCopyRow
510  [&] (int y, int x1, int x2, RGB888 color) { rawFillRow(y, x1, x2, color); } // rawFillRow
511  );
512 }
513 
514 
515 void SSD1306Controller::HScroll(int scroll, Rect & updateRect)
516 {
517  genericHScroll(scroll, updateRect,
518  [&] (RGB888 const & color) { return preparePixel(color); }, // preparePixel
519  [&] (int y) { return y; }, // rawGetRow
520  [&] (int y, int x) { return SSD1306_GETPIXEL(x, y); }, // rawGetPixelInRow
521  [&] (int y, int x, int pattern) { SSD1306_SETPIXELCOLOR(x, y, pattern); } // rawSetPixelInRow
522  );
523 }
524 
525 
526 void SSD1306Controller::drawGlyph(Glyph const & glyph, GlyphOptions glyphOptions, RGB888 penColor, RGB888 brushColor, Rect & updateRect)
527 {
528  genericDrawGlyph(glyph, glyphOptions, penColor, brushColor, updateRect,
529  [&] (RGB888 const & color) { return preparePixel(color); },
530  [&] (int y) { return y; },
531  [&] (int y, int x, uint8_t pattern) { SSD1306_SETPIXELCOLOR(x, y, pattern); }
532  );
533 }
534 
535 
536 void SSD1306Controller::rawCopyRow(int x1, int x2, int srcY, int dstY)
537 {
538  for (; x1 <= x2; ++x1) {
539  uint8_t c = SSD1306_GETPIXEL(x1, srcY);
540  SSD1306_SETPIXELCOLOR(x1, dstY, c);
541  }
542 }
543 
544 
545 void SSD1306Controller::invertRect(Rect const & rect, Rect & updateRect)
546 {
547  genericInvertRect(rect, updateRect,
548  [&] (int Y, int X1, int X2) { rawInvertRow(Y, X1, X2); }
549  );
550 }
551 
552 
553 void SSD1306Controller::swapFGBG(Rect const & rect, Rect & updateRect)
554 {
555  invertRect(rect, updateRect);
556 }
557 
558 
559 // supports overlapping of source and dest rectangles
560 void SSD1306Controller::copyRect(Rect const & source, Rect & updateRect)
561 {
562  genericCopyRect(source, updateRect,
563  [&] (int y) { return y; },
564  [&] (int y, int x) { return SSD1306_GETPIXEL(x, y); },
565  [&] (int y, int x, uint8_t pattern) { SSD1306_SETPIXELCOLOR(x, y, pattern); }
566  );
567 }
568 
569 
570 // no bounds check is done!
571 void SSD1306Controller::readScreen(Rect const & rect, RGB888 * destBuf)
572 {
573  for (int y = rect.Y1; y <= rect.Y2; ++y)
574  for (int x = rect.X1; x <= rect.X2; ++x, ++destBuf)
575  *destBuf = SSD1306_GETPIXEL(x, y) ? RGB888(255, 255, 255) : RGB888(0, 0, 0);
576 }
577 
578 
579 void SSD1306Controller::rawDrawBitmap_Native(int destX, int destY, Bitmap const * bitmap, int X1, int Y1, int XCount, int YCount)
580 {
581  genericRawDrawBitmap_Native(destX, destY, (uint8_t*) bitmap->data, bitmap->width, X1, Y1, XCount, YCount,
582  [&] (int y) { return y; }, // rawGetRow
583  [&] (int y, int x, uint8_t src) { SSD1306_SETPIXELCOLOR(x, y, src); } // rawSetPixelInRow
584  );
585 }
586 
587 
588 void SSD1306Controller::rawDrawBitmap_Mask(int destX, int destY, Bitmap const * bitmap, void * saveBackground, int X1, int Y1, int XCount, int YCount)
589 {
590  uint8_t foregroundColor = RGB888toMono(bitmap->foregroundColor);
591  genericRawDrawBitmap_Mask(destX, destY, bitmap, (uint8_t*)saveBackground, X1, Y1, XCount, YCount,
592  [&] (int y) { return y; }, // rawGetRow
593  [&] (int y, int x) { return SSD1306_GETPIXEL(x, y); }, // rawGetPixelInRow
594  [&] (int y, int x) { SSD1306_SETPIXELCOLOR(x, y, foregroundColor); } // rawSetPixelInRow
595  );
596 }
597 
598 
599 void SSD1306Controller::rawDrawBitmap_RGBA2222(int destX, int destY, Bitmap const * bitmap, void * saveBackground, int X1, int Y1, int XCount, int YCount)
600 {
601  genericRawDrawBitmap_RGBA2222(destX, destY, bitmap, (uint8_t*)saveBackground, X1, Y1, XCount, YCount,
602  [&] (int y) { return y; }, // rawGetRow
603  [&] (int y, int x) { return SSD1306_GETPIXEL(x, y); }, // rawGetPixelInRow
604  [&] (int y, int x, uint8_t src) { SSD1306_SETPIXELCOLOR(x, y, RGBA2222toMono(src)); } // rawSetPixelInRow
605  );
606 }
607 
608 
609 void SSD1306Controller::rawDrawBitmap_RGBA8888(int destX, int destY, Bitmap const * bitmap, void * saveBackground, int X1, int Y1, int XCount, int YCount)
610 {
611  genericRawDrawBitmap_RGBA8888(destX, destY, bitmap, (uint8_t*)saveBackground, X1, Y1, XCount, YCount,
612  [&] (int y) { return y; }, // rawGetRow
613  [&] (int y, int x) { return SSD1306_GETPIXEL(x, y); }, // rawGetPixelInRow
614  [&] (int y, int x, RGBA8888 const & src) { SSD1306_SETPIXELCOLOR(x, y, RGBA8888toMono(src)); } // rawSetPixelInRow
615  );
616 }
617 
618 
619 void SSD1306Controller::swapBuffers()
620 {
621  // nothing to do, we just send current view port to the device
622  SSD1306_sendScreenBuffer(Rect(0, 0, getViewPortWidth() - 1, getViewPortHeight() - 1));
623 }
624 
625 
626 
627 
628 } // end of namespace
629 
630 
631 
632 #endif // #ifdef ARDUINO
int16_t X2
Definition: fabutils.h:150
Represents a 24 bit RGB color.
int16_t Y1
Definition: fabutils.h:193
void invert(bool value)
Inverts display colors.
void begin()
Initializes SSD1306.
int16_t Y2
Definition: fabutils.h:151
void setOrientation(SSD1306Orientation value)
Set display orientation and rotation.
int getMaxBufferLength()
Returns maximum size of read and write buffers.
Definition: tsi2c.h:139
void setResolution(char const *modeline, int viewPortWidth=-1, int viewPortHeight=-1, bool doubleBuffered=false)
Sets SSD1306 resolution and viewport size.
int16_t Y1
Definition: fabutils.h:149
int getViewPortHeight()
Determines vertical size of the viewport.
int16_t Y
bool begin(gpio_num_t SDAGPIO, gpio_num_t SCLGPIO)
Initializes I2C instance associating GPIOs to I2C signals.
Definition: tsi2c.cpp:62
void setScreenCol(int value)
Set initial left column of the viewport.
I2C class allows multiple tasks to communicate with I2C devices, serializing read/write jobs...
Definition: tsi2c.h:76
int16_t X1
Definition: fabutils.h:148
int16_t X1
Definition: fabutils.h:192
void resumeBackgroundPrimitiveExecution()
Resumes drawings after suspendBackgroundPrimitiveExecution().
This file contains some utility classes and functions.
Definition: canvas.cpp:31
SSD1306Orientation
This enum defines SSD1306 orientation.
int16_t Y2
Definition: fabutils.h:195
void setScreenRow(int value)
Set initial top row of the viewport.
Represents a rectangle.
Definition: fabutils.h:191
int getViewPortWidth()
Determines horizontal size of the viewport.
int16_t X
void suspendBackgroundPrimitiveExecution()
Suspends drawings.
int16_t X2
Definition: fabutils.h:194
bool write(int address, uint8_t *buffer, int size, int frequency=100000, int timeOutMS=50)
Sends a buffer to I2C bus.
Definition: tsi2c.cpp:99
This file contains fabgl::SSD1306Controller definition.
int screenRow()
Gets initial top row of the viewport.