Subversion Repositories libOLED

Rev

Rev 11 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 mjames 1
/*
2
 * displayclass.cpp
3
 *
4
 *  Created on: 31 Oct 2020
5
 *      Author: mike
6
 */
7
 
8
#include "libOLED/displayclass.H"
9
 
10
#include <cstring>
11
#include <cstdlib>
12
namespace
13
{
14
  uint8_t const SSD1306_SETCONTRAST = 0x81;
15
  uint8_t const SSD1306_DISPLAYALLON_RESUME = 0xA4;
16
  uint8_t const SSD1306_DISPLAYALLON = 0xA5;
17
  uint8_t const SSD1306_NORMALDISPLAY = 0xA6;
18
  uint8_t const SSD1306_INVERTDISPLAY = 0xA7;
19
  uint8_t const SSD1306_DISPLAYOFF = 0xAE;
20
  uint8_t const SSD1306_DISPLAYON = 0xAF;
21
 
22
  uint8_t const SSD1306_SETDISPLAYOFFSET = 0xD3;
23
  uint8_t const SSD1306_SETCOMPINS = 0xDA;
24
 
25
  uint8_t const SSD1306_SETVCOMDETECT = 0xDB;
26
 
27
  uint8_t const SSD1306_SETDISPLAYCLOCKDIV = 0xD5;
28
  uint8_t const SSD1306_SETPRECHARGE = 0xD9;
29
 
30
  uint8_t const SSD1306_SETMULTIPLEX = 0xA8;
31
 
32
  uint8_t const SSD1306_SETLOWCOLUMN = 0x00;
33
  uint8_t const SSD1306_SETHIGHCOLUMN = 0x10;
34
 
35
  uint8_t const SSD1306_SETSTARTLINE = 0x40;
36
 
37
  uint8_t const SSD1306_MEMORYMODE = 0x20;
38
  uint8_t const SSD1306_COLUMNADDR = 0x21;
39
  uint8_t const SSD1306_PAGEADDR = 0x22;
40
 
41
  uint8_t const SSD1306_COMSCANINC = 0xC0;
42
  uint8_t const SSD1306_COMSCANDEC = 0xC8;
43
 
44
  uint8_t const SSD1306_SEGREMAP = 0xA0;
45
 
46
  uint8_t const SSD1306_CHARGEPUMP = 0x8D;
47
 
48
  uint8_t const SSD1306_EXTERNALVCC = 0x1;
49
  uint8_t const SSD1306_SWITCHCAPVCC = 0x2;
50
 
11 mjames 51
  // Scrolling #defines
2 mjames 52
  uint8_t const SSD1306_ACTIVATE_SCROLL = 0x2F;
53
  uint8_t const SSD1306_DEACTIVATE_SCROLL = 0x2E;
54
  uint8_t const SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3;
55
  uint8_t const SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26;
56
  uint8_t const SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27;
57
  uint8_t const SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29;
58
  uint8_t const SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A;
59
 
11 mjames 60
  template <class T>
61
  void
62
  swap(T &x, T &y)
63
  {
64
    T temp = x;
65
    x = y;
66
    y = temp;
67
  }
2 mjames 68
 
11 mjames 69
  template <class T>
70
  T abs(T x)
71
  {
72
    return x < 0 ? -x : x;
73
  }
2 mjames 74
 
75
}
76
// provided to allow a destructor to destroy something not deleted
77
// this is only OK because destructors shouldnt be needed
11 mjames 78
void operator delete(void *data, unsigned int f)
6 mjames 79
{
11 mjames 80
  (void)data;
81
  (void)f;
6 mjames 82
}
2 mjames 83
 
84
// provided to implement an "error handler" on pure virtual
6 mjames 85
extern "C" void
11 mjames 86
__cxa_pure_virtual()
2 mjames 87
{
6 mjames 88
  while (1)
89
    ;
2 mjames 90
}
91
 
11 mjames 92
display_t::display_t(int const width, int const height, int const ramwidth,
93
                     uint8_t *const data) : m_width(width), m_height(height), m_ramwidth(ramwidth), m_cursor_x(0), m_cursor_y(0), m_rotation(0), m_colour(WHITE), m_data(data)
2 mjames 94
{
95
}
96
 
11 mjames 97
display_t::~display_t()
2 mjames 98
{
99
}
100
 
7 mjames 101
void display_t::reset()
102
{
103
  oledReset();
104
}
105
 
11 mjames 106
void display_t::init()
2 mjames 107
{
108
  uint8_t const vccstate = SSD1306_EXTERNALVCC;
109
 
11 mjames 110
  oledSetCD(0);
2 mjames 111
 
112
  // Init sequence for 128x32 or 128x64  OLED module
11 mjames 113
  oledWrite(SSD1306_DISPLAYOFF);         // 0xAE
114
  oledWrite(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
115
  oledWrite(0x80);                       // the suggested ratio 0x80
116
  oledWrite(SSD1306_SETMULTIPLEX);       // 0xA8
117
  oledWrite(m_height - 1);
118
  oledWrite(SSD1306_SETDISPLAYOFFSET);   // 0xD3
119
  oledWrite(0x0);                        // no offset
120
  oledWrite(SSD1306_SETSTARTLINE | 0x0); // line #0
121
  oledWrite(SSD1306_CHARGEPUMP);         // 0x8D
122
  oledWrite(vccstate == SSD1306_EXTERNALVCC ? 0x10 : 0x14);
123
  oledWrite(SSD1306_MEMORYMODE); // 0x20
124
  oledWrite(0x00);               // 0x0 act like ks0108
125
  oledWrite(SSD1306_SEGREMAP | 0x1);
126
  oledWrite(SSD1306_COMSCANDEC);
127
  oledWrite(SSD1306_SETCOMPINS); // 0xDA
128
  oledWrite(m_height == 32 ? 0x02 : 0x12);
129
  oledWrite(SSD1306_SETCONTRAST); // 0x81
130
  oledWrite(vccstate == SSD1306_EXTERNALVCC ? 0x9F : 0xCF);
131
  oledWrite(SSD1306_SETPRECHARGE); // 0xd9
132
  oledWrite(vccstate == SSD1306_EXTERNALVCC ? 0x22 : 0xF1);
133
  oledWrite(SSD1306_SETVCOMDETECT); // 0xDB
134
  oledWrite(0x40);
135
  oledWrite(SSD1306_DISPLAYALLON_RESUME); // 0xA4
136
  oledWrite(SSD1306_NORMALDISPLAY);       // 0xA6
2 mjames 137
 
11 mjames 138
  oledWrite(SSD1306_DISPLAYON); //--turn on oled panel
2 mjames 139
 
11 mjames 140
  clearDisplay();
2 mjames 141
}
142
 
143
uint8_t
11 mjames 144
display_t::getRotation(void)
2 mjames 145
{
146
  return m_rotation;
147
}
148
 
149
int16_t
11 mjames 150
display_t::width(void)
2 mjames 151
{
152
  switch (m_rotation)
11 mjames 153
  {
154
  case 0:
155
    return m_width;
156
    break;
157
  case 1:
158
    return m_width;
159
    break;
160
  case 2:
161
    return m_height;
162
    break;
163
  case 3:
164
    return -m_width;
165
    break;
166
  }
2 mjames 167
  return 0;
168
}
169
 
170
int16_t
11 mjames 171
display_t::height(void)
2 mjames 172
{
173
  switch (m_rotation)
11 mjames 174
  {
175
  case 0:
176
    return m_height;
177
    break;
178
  case 1:
179
    return m_height;
180
    break;
181
  case 2:
182
    return m_width;
183
    break;
184
  case 3:
185
    return -m_height;
186
    break;
187
  }
2 mjames 188
  return 0;
189
}
190
 
191
// the most basic function, set a single pixel
11 mjames 192
void display_t::drawPixel(int16_t x, int16_t y, bool pixel)
2 mjames 193
{
194
  if ((x < 0) || (x >= m_width) || (y < 0) || (y >= m_height))
195
    return;
196
 
197
  // check rotation, move pixel around if necessary
198
  switch (m_rotation)
11 mjames 199
  {
200
  case 1:
201
    swap(x, y);
202
    x = m_width - x - 1;
203
    break;
204
  case 2:
205
    x = m_width - x - 1;
206
    y = m_height - y - 1;
207
    break;
208
  case 3:
209
    swap(x, y);
210
    y = m_height - y - 1;
211
    break;
212
  }
2 mjames 213
 
214
  // x is which column
7 mjames 215
  //  BLACK,  and 0,             invert 0
216
  //  WHITE,   and 0,            invert 1
217
  //  OVERLAY, and 1 (preserve) , invert 0/
218
  // INVERT,  and 1, (preserve) , invert 1
219
 
220
  switch (m_colour)
11 mjames 221
  {
222
  case BLACK:
223
  case WHITE:
224
    m_data[x + (y / 8) * m_width] &= ~(1 << (y & 7));
225
    break;
226
  default:
227
    break;
228
  }
7 mjames 229
  uint8_t pixData = 0;
230
  switch (m_colour)
11 mjames 231
  {
232
  case BLACK:
233
    pixData = pixel ? 0 : 1;
234
    break;
235
  case WHITE:
236
  case OVERLAY:
237
  case INVERT:
238
    pixData = pixel ? 1 : 0;
239
    break;
240
  }
7 mjames 241
 
242
  m_data[x + (y / 8) * m_width] ^= (pixData << (y & 7));
2 mjames 243
}
244
 
11 mjames 245
void display_t::invertDisplay(uint8_t i)
2 mjames 246
{
11 mjames 247
  oledSetCD(0);
248
  oledWrite(i ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY);
2 mjames 249
}
250
 
251
// startscrollright
252
// Activate a right handed scroll for rows start through stop
253
// Hint, the display is 16 rows tall. To scroll the whole display, run:
254
// display.scrollright(0x00, 0x0F)
11 mjames 255
void display_t::startscrollright(uint8_t start, uint8_t stop)
2 mjames 256
{
11 mjames 257
  oledSetCD(0);
258
  oledWrite(SSD1306_RIGHT_HORIZONTAL_SCROLL);
259
  oledWrite(0X00);
260
  oledWrite(start);
261
  oledWrite(0X00);
262
  oledWrite(stop);
263
  oledWrite(0X00);
264
  oledWrite(0XFF);
265
  oledWrite(SSD1306_ACTIVATE_SCROLL);
2 mjames 266
}
267
 
268
// startscrollleft
269
// Activate a right handed scroll for rows start through stop
270
// Hint, the display is 16 rows tall. To scroll the whole display, run:
271
// display.scrollright(0x00, 0x0F)
11 mjames 272
void display_t::startscrollleft(uint8_t start, uint8_t stop)
2 mjames 273
{
11 mjames 274
  oledSetCD(0);
275
  oledWrite(SSD1306_LEFT_HORIZONTAL_SCROLL);
276
  oledWrite(0X00);
277
  oledWrite(start);
278
  oledWrite(0X00);
279
  oledWrite(stop);
280
  oledWrite(0X00);
281
  oledWrite(0XFF);
282
  oledWrite(SSD1306_ACTIVATE_SCROLL);
2 mjames 283
}
284
 
285
// startscrolldiagright
286
// Activate a diagonal scroll for rows start through stop
287
// Hint, the display is 16 rows tall. To scroll the whole display, run:
288
// display.scrollright(0x00, 0x0F)
11 mjames 289
void display_t::startscrolldiagright(uint8_t start, uint8_t stop)
2 mjames 290
{
11 mjames 291
  oledSetCD(0);
292
  oledWrite(SSD1306_SET_VERTICAL_SCROLL_AREA);
293
  oledWrite(0X00);
294
  oledWrite(m_height);
295
  oledWrite(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
296
  oledWrite(0X00);
297
  oledWrite(start);
298
  oledWrite(0X00);
299
  oledWrite(stop);
300
  oledWrite(0X01);
301
  oledWrite(SSD1306_ACTIVATE_SCROLL);
2 mjames 302
}
303
 
304
// startscrolldiagleft
305
// Activate a diagonal scroll for rows start through stop
306
// Hint, the display is 16 rows tall. To scroll the whole display, run:
307
// display.scrollright(0x00, 0x0F)
11 mjames 308
void display_t::startscrolldiagleft(uint8_t start, uint8_t stop)
2 mjames 309
{
11 mjames 310
  oledSetCD(0);
311
  oledWrite(SSD1306_SET_VERTICAL_SCROLL_AREA);
312
  oledWrite(0X00);
313
  oledWrite(m_height);
314
  oledWrite(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
315
  oledWrite(0X00);
316
  oledWrite(start);
317
  oledWrite(0X00);
318
  oledWrite(stop);
319
  oledWrite(0X01);
320
  oledWrite(SSD1306_ACTIVATE_SCROLL);
2 mjames 321
}
322
 
11 mjames 323
void display_t::stopscroll(void)
2 mjames 324
{
11 mjames 325
  oledSetCD(0);
326
  oledWrite(SSD1306_DEACTIVATE_SCROLL);
2 mjames 327
}
328
 
13 mjames 329
 
11 mjames 330
void display_t::dim(uint8_t contrast)
2 mjames 331
{
332
 
333
  // the range of contrast to too small to be really useful
334
  // it is useful to dim the display
335
 
11 mjames 336
  oledSetCD(0);
337
  oledWrite(SSD1306_SETCONTRAST);
338
  oledWrite(contrast);
2 mjames 339
}
340
 
11 mjames 341
void display_t::display(void)
2 mjames 342
{
11 mjames 343
  oledSetCD(0);
2 mjames 344
  // select entire display as window to write into
11 mjames 345
  oledWrite(SSD1306_COLUMNADDR);
346
  oledWrite(0);              // Column start address (0 = reset)
347
  oledWrite(m_ramwidth - 1); // Column end address (127 = reset)
2 mjames 348
 
11 mjames 349
  oledWrite(SSD1306_PAGEADDR);
350
  oledWrite(0);                        // Page start address (0 = reset)
351
  oledWrite((m_height == 64) ? 7 : 3); // Page end address
2 mjames 352
 
353
  int row;
354
 
355
  int col = m_ramwidth == 132 ? 2 : 0;
356
  for (row = 0; row < m_height / 8; row++)
11 mjames 357
  {
358
    oledSetCD(0);
359
    // set the cursor to
360
    oledWrite(0xB0 + row);        // set page address
361
    oledWrite(col & 0xf);         // set lower column address
362
    oledWrite(0x10 | (col >> 4)); // set higher column address
2 mjames 363
 
11 mjames 364
    oledSetCD(1);
365
    oledWrite(m_data + row * m_width, m_width);
366
  }
2 mjames 367
}
368
 
369
// clear everything
11 mjames 370
void display_t::clearDisplay(colour_t colour)
2 mjames 371
{
7 mjames 372
  switch (colour)
11 mjames 373
  {
374
  case WHITE:
375
  case OVERLAY:
376
    memset(m_data, 255, dataSize(m_width, m_height));
377
    break;
378
  case BLACK:
379
    memset(m_data, 0, dataSize(m_width, m_height));
380
    break;
381
  case INVERT:
382
    for (size_t i = 0; i < dataSize(m_width, m_height); i++)
383
      m_data[i] ^= 255;
384
    break;
385
  }
2 mjames 386
}
387
 
11 mjames 388
void display_t::drawRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2,
389
                              colour_t color)
6 mjames 390
{
391
  for (int16_t x = x1; x <= x2; x++)
392
    for (int16_t y = y1; y < y2; y++)
11 mjames 393
    {
394
      switch (color)
6 mjames 395
      {
11 mjames 396
      case BLACK:
397
        m_data[x + (y / 8) * m_width] &= ~(1 << (y & 7));
398
        break;
6 mjames 399
 
11 mjames 400
      default:
401
      case WHITE:
402
      case OVERLAY:
403
        m_data[x + (y / 8) * m_width] |= (1 << (y & 7));
404
        break;
6 mjames 405
 
11 mjames 406
      case INVERT:
407
        m_data[x + (y / 8) * m_width] ^= (1 << (y & 7));
408
        break;
6 mjames 409
      }
11 mjames 410
    }
6 mjames 411
}
412
 
2 mjames 413
/* using Bresenham draw algorithm */
11 mjames 414
void display_t::drawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2,
415
                         colour_t colour, int8_t pattern)
2 mjames 416
{
11 mjames 417
  int16_t x, y, dx, dy,  // deltas
418
      dx2, dy2,          // scaled deltas
419
      ix, iy,            // increase rate on the x and y axis
420
      err;               // the error term
421
  int8_t patt = pattern; // drawing pattern bit mask 1= solid 10= dots , 111000 equal dot/dash
8 mjames 422
 
11 mjames 423
  uint16_t i; // looping variable
8 mjames 424
 
425
  setPixelMode(colour);
426
 
2 mjames 427
  // identify the first pixel
428
  x = x1;
429
  y = y1;
430
 
431
  // difference between starting and ending points
432
  dx = x2 - x1;
433
  dy = y2 - y1;
434
 
435
  // calculate direction of the vector and store in ix and iy
436
  if (dx >= 0)
437
    ix = 1;
438
 
439
  if (dx < 0)
11 mjames 440
  {
441
    ix = -1;
442
    dx = abs(dx);
443
  }
2 mjames 444
 
445
  if (dy >= 0)
446
    iy = 1;
447
 
448
  if (dy < 0)
11 mjames 449
  {
450
    iy = -1;
451
    dy = abs(dy);
452
  }
2 mjames 453
 
454
  // scale deltas and store in dx2 and dy2
455
  dx2 = dx * 2;
456
  dy2 = dy * 2;
457
 
11 mjames 458
  // all  variables are set and it's time to enter the main loop.
2 mjames 459
 
11 mjames 460
  if (dx > dy) // dx is the major axis
461
  {
462
    // initialize the error term
463
    err = dy2 - dx;
464
 
465
    for (i = 0; i <= dx; i++)
2 mjames 466
    {
11 mjames 467
      // draw pattern based on using pattern as a sequential bit mask.
468
      if (patt & 1)
469
        drawPixel(x, y, 1);
470
      patt = (patt <= 1) ? pattern : patt >> 1;
2 mjames 471
 
11 mjames 472
      if (err >= 0)
473
      {
474
        err -= dx2;
475
        y += iy;
476
      }
477
      err += dy2;
478
      x += ix;
2 mjames 479
    }
11 mjames 480
  }
2 mjames 481
 
11 mjames 482
  else // dy is the major axis
483
  {
484
    // initialize the error term
485
    err = dx2 - dy;
486
 
487
    for (i = 0; i <= dy; i++)
2 mjames 488
    {
11 mjames 489
      // draw pattern based on using pattern as a sequential bit mask.
490
      if (patt & 1)
491
        drawPixel(x, y, 1);
492
      patt = (patt <= 1) ? pattern : patt >> 1;
493
      if (err >= 0)
494
      {
495
        err -= dy2;
496
        x += ix;
497
      }
498
      err += dx2;
499
      y += iy;
2 mjames 500
    }
11 mjames 501
  }
2 mjames 502
}