Subversion Repositories libOLED

Rev

Rev 7 | Rev 11 | 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:
242
      pixData = pixel ? 0 : 1;
2 mjames 243
      break;
8 mjames 244
    case WHITE:
245
    case OVERLAY:
246
    case INVERT:
247
       pixData = pixel ? 1 : 0;
7 mjames 248
      break;
2 mjames 249
    }
7 mjames 250
 
251
  m_data[x + (y / 8) * m_width] ^= (pixData << (y & 7));
252
 
2 mjames 253
}
254
 
255
void
256
display_t::invertDisplay (uint8_t i)
257
{
258
  oledSetCD (0);
259
  oledWrite (i ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY);
260
}
261
 
262
// startscrollright
263
// Activate a right handed scroll for rows start through stop
264
// Hint, the display is 16 rows tall. To scroll the whole display, run:
265
// display.scrollright(0x00, 0x0F)
266
void
267
display_t::startscrollright (uint8_t start, uint8_t stop)
268
{
269
  oledSetCD (0);
270
  oledWrite (SSD1306_RIGHT_HORIZONTAL_SCROLL);
271
  oledWrite (0X00);
272
  oledWrite (start);
273
  oledWrite (0X00);
274
  oledWrite (stop);
275
  oledWrite (0X00);
276
  oledWrite (0XFF);
277
  oledWrite (SSD1306_ACTIVATE_SCROLL);
278
}
279
 
280
// startscrollleft
281
// Activate a right handed scroll for rows start through stop
282
// Hint, the display is 16 rows tall. To scroll the whole display, run:
283
// display.scrollright(0x00, 0x0F)
284
void
285
display_t::startscrollleft (uint8_t start, uint8_t stop)
286
{
287
  oledSetCD (0);
288
  oledWrite (SSD1306_LEFT_HORIZONTAL_SCROLL);
289
  oledWrite (0X00);
290
  oledWrite (start);
291
  oledWrite (0X00);
292
  oledWrite (stop);
293
  oledWrite (0X00);
294
  oledWrite (0XFF);
295
  oledWrite (SSD1306_ACTIVATE_SCROLL);
296
}
297
 
298
// startscrolldiagright
299
// Activate a diagonal scroll for rows start through stop
300
// Hint, the display is 16 rows tall. To scroll the whole display, run:
301
// display.scrollright(0x00, 0x0F)
302
void
303
display_t::startscrolldiagright (uint8_t start, uint8_t stop)
304
{
305
  oledSetCD (0);
306
  oledWrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
307
  oledWrite (0X00);
308
  oledWrite (m_height);
309
  oledWrite (SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
310
  oledWrite (0X00);
311
  oledWrite (start);
312
  oledWrite (0X00);
313
  oledWrite (stop);
314
  oledWrite (0X01);
315
  oledWrite (SSD1306_ACTIVATE_SCROLL);
316
}
317
 
318
// startscrolldiagleft
319
// Activate a diagonal scroll for rows start through stop
320
// Hint, the display is 16 rows tall. To scroll the whole display, run:
321
// display.scrollright(0x00, 0x0F)
322
void
323
display_t::startscrolldiagleft (uint8_t start, uint8_t stop)
324
{
325
  oledSetCD (0);
326
  oledWrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
327
  oledWrite (0X00);
328
  oledWrite (m_height);
329
  oledWrite (SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
330
  oledWrite (0X00);
331
  oledWrite (start);
332
  oledWrite (0X00);
333
  oledWrite (stop);
334
  oledWrite (0X01);
335
  oledWrite (SSD1306_ACTIVATE_SCROLL);
336
}
337
 
338
void
339
display_t::stopscroll (void)
340
{
341
  oledSetCD (0);
342
  oledWrite (SSD1306_DEACTIVATE_SCROLL);
343
}
344
 
345
// Dim the display
346
// dim = true: display is dimmed
347
// dim = false: display is normal
348
void
349
display_t::dim (uint8_t contrast)
350
{
351
 
352
  // the range of contrast to too small to be really useful
353
  // it is useful to dim the display
354
 
355
  oledSetCD (0);
356
  oledWrite (SSD1306_SETCONTRAST);
357
  oledWrite (contrast);
358
}
359
 
360
void
361
display_t::display (void)
362
{
363
  oledSetCD (0);
364
  // select entire display as window to write into
365
  oledWrite (SSD1306_COLUMNADDR);
366
  oledWrite (0);   // Column start address (0 = reset)
367
  oledWrite (m_ramwidth - 1); // Column end address (127 = reset)
368
 
369
  oledWrite (SSD1306_PAGEADDR);
370
  oledWrite (0); // Page start address (0 = reset)
371
  oledWrite ((m_height == 64) ? 7 : 3); // Page end address
372
 
373
  int row;
374
 
375
  int col = m_ramwidth == 132 ? 2 : 0;
376
  for (row = 0; row < m_height / 8; row++)
377
    {
378
      oledSetCD (0);
379
      // set the cursor to
380
      oledWrite (0xB0 + row); //set page address
381
      oledWrite (col & 0xf); //set lower column address
382
      oledWrite (0x10 | (col >> 4)); //set higher column address
383
 
384
      oledSetCD (1);
385
      oledWrite (m_data + row * m_width, m_width);
386
 
387
    }
388
 
389
}
390
 
391
// clear everything
392
void
6 mjames 393
display_t::clearDisplay (colour_t colour)
2 mjames 394
{
7 mjames 395
  switch (colour)
396
    {
397
    case WHITE:
398
    case OVERLAY:
399
      memset (m_data, 255, dataSize (m_width, m_height));
400
      break;
401
    case BLACK:
402
      memset (m_data, 0, dataSize (m_width, m_height));
403
      break;
404
    case INVERT:
405
      for (size_t i = 0; i <  dataSize (m_width, m_height); i++)
406
        m_data[i] ^= 255;
407
      break;
408
    }
409
 
2 mjames 410
}
411
 
7 mjames 412
void
413
display_t::drawRectangle (int16_t x1, int16_t y1, int16_t x2, int16_t y2,
6 mjames 414
                          colour_t color)
415
{
416
  for (int16_t x = x1; x <= x2; x++)
417
    for (int16_t y = y1; y < y2; y++)
418
      {
419
        switch (color)
420
          {
421
          case BLACK:
422
            m_data[x + (y / 8) * m_width] &= ~(1 << (y & 7));
423
            break;
424
 
425
          default:
426
          case WHITE:
7 mjames 427
          case OVERLAY:
6 mjames 428
            m_data[x + (y / 8) * m_width] |= (1 << (y & 7));
429
            break;
430
 
431
          case INVERT:
432
            m_data[x + (y / 8) * m_width] ^= (1 << (y & 7));
433
            break;
434
          }
435
      }
436
}
437
 
2 mjames 438
/* using Bresenham draw algorithm */
439
void
440
display_t::drawLine (int16_t x1, int16_t y1, int16_t x2, int16_t y2,
8 mjames 441
                     colour_t  colour)
2 mjames 442
{
443
  int16_t x, y, dx, dy,    //deltas
444
      dx2, dy2, //scaled deltas
445
      ix, iy,   //increase rate on the x and y axis
446
      err;      //the error term
8 mjames 447
 
448
 
2 mjames 449
  uint16_t i;           //looping variable
450
 
8 mjames 451
  setPixelMode(colour);
452
 
2 mjames 453
  // identify the first pixel
454
  x = x1;
455
  y = y1;
456
 
457
  // difference between starting and ending points
458
  dx = x2 - x1;
459
  dy = y2 - y1;
460
 
461
  // calculate direction of the vector and store in ix and iy
462
  if (dx >= 0)
463
    ix = 1;
464
 
465
  if (dx < 0)
466
    {
467
      ix = -1;
468
      dx = abs (dx);
469
    }
470
 
471
  if (dy >= 0)
472
    iy = 1;
473
 
474
  if (dy < 0)
475
    {
476
      iy = -1;
477
      dy = abs (dy);
478
    }
479
 
480
  // scale deltas and store in dx2 and dy2
481
  dx2 = dx * 2;
482
  dy2 = dy * 2;
483
 
484
// all  variables are set and it's time to enter the main loop.
485
 
486
  if (dx > dy)  // dx is the major axis
487
    {
488
      // initialize the error term
489
      err = dy2 - dx;
490
 
491
      for (i = 0; i <= dx; i++)
492
        {
8 mjames 493
          drawPixel (x, y, 1);
2 mjames 494
          if (err >= 0)
495
            {
496
              err -= dx2;
497
              y += iy;
498
            }
499
          err += dy2;
500
          x += ix;
501
        }
502
    }
503
 
504
  else          // dy is the major axis
505
    {
506
      // initialize the error term
507
      err = dx2 - dy;
508
 
509
      for (i = 0; i <= dy; i++)
510
        {
8 mjames 511
          drawPixel (x, y, 1);
2 mjames 512
          if (err >= 0)
513
            {
514
              err -= dy2;
515
              x += ix;
516
            }
517
          err += dx2;
518
          y += iy;
519
        }
520
    }
521
}
522