Subversion Repositories libOLED

Rev

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