Subversion Repositories libOLED

Rev

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