Browse Source

eboled: Sparkfun OLED Block Improvements

Signed-off-by: Tyler Gibson <tgibson@microsoft.com>
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
Tyler Gibson 9 years ago
parent
commit
14a3924fb2
4 changed files with 798 additions and 102 deletions
  1. 118
    19
      examples/javascript/eboled.js
  2. 435
    71
      src/lcd/eboled.cxx
  3. 221
    12
      src/lcd/eboled.h
  4. 24
    0
      src/lcd/license.txt

+ 118
- 19
examples/javascript/eboled.js View File

@@ -5,6 +5,9 @@
5 5
  * Author: Jon Trulson <jtrulson@ics.com>
6 6
  * Copyright (c) 2015 Intel Corporation.
7 7
  *
8
+ * Author: Tyler Gibson <tgibson@microsoft.com>
9
+ * Copyright (c) 2015 Microsoft Corporation.
10
+ *
8 11
  * Permission is hereby granted, free of charge, to any person obtaining
9 12
  * a copy of this software and associated documentation files (the
10 13
  * "Software"), to deal in the Software without restriction, including
@@ -25,27 +28,123 @@
25 28
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 29
  */
27 30
 
28
-function exit()
29
-{
30
-    lcd = null;
31
-    lcdObj.cleanUp();
32
-    lcdObj = null;
33
-    process.exit(0);
34
-}
35
-
36
-// Load i2clcd module
37 31
 var lcdObj = require('jsupm_i2clcd');
32
+var oled = new lcdObj.EBOLED();
38 33
 
39
-var lcd = new lcdObj.EBOLED();
40
-
41
-lcd.clear();
42
-lcd.setCursor(2, 0);
43
-lcd.write("Hello");
44
-lcd.setCursor(3, 5);
45
-lcd.write("World!");
46
-
47
-console.log("Sleeping for 5 seconds...");
48
-setTimeout(exit, 5000);
34
+var sample = 0;
35
+var samples = 13;
49 36
 
37
+function exit()
38
+{
39
+  oled = null;
40
+  lcdObj.cleanUp();
41
+  lcdObj = null;
42
+  process.exit(0);
43
+}
50 44
 
45
+setInterval( function()
46
+{
47
+  if(sample>samples)
48
+  {
49
+    exit();
50
+  }
51
+  oled.clearScreenBuffer();
52
+  runSample(sample++);
53
+  oled.refresh();
54
+}, 1500);
51 55
 
56
+function runSample(sample)
57
+{
58
+  switch(sample) {
59
+    case 0:
60
+      // x/y coords are 0 based, using 1 here for padding.
61
+      oled.setCursor(1,1);
62
+      // nowrap = 0, wrapping = 1
63
+      oled.setTextWrap(1);
64
+      oled.write("HELLO WORLD! Mixed with #123 and y's, g's and q's.");
65
+      break;
66
+    case 1:
67
+      oled.setCursor(12, 1);
68
+      //multiply text size, only integers
69
+      oled.setTextSize(3);
70
+      oled.write("BOO!");
71
+      oled.setTextSize(1);
72
+      break;
73
+    case 2:
74
+      oled.drawRectangleFilled(0,0,48,9);
75
+      oled.setCursor(1,1);
76
+      // 0=Black, 1=White, 2=Xor (Toggle)
77
+      oled.setTextColor(2);
78
+      oled.write("Cutout");
79
+      break;
80
+    case 3:
81
+      var total = Math.random()*100;
82
+      for(var stars=0; stars<total; stars++ )
83
+        oled.drawPixel(Math.floor(Math.random()*63), Math.floor(Math.random()*47), 1);
84
+      break;
85
+    case 4:
86
+      for(var burst=0; burst<12; burst++)
87
+        oled.drawLine(31, 24, Math.floor(Math.random()*63), Math.floor(Math.random()*47), 1);
88
+      break;
89
+    case 5:
90
+      var lastPeak = 24;
91
+      for(var peak=0; peak < 64; peak++)
92
+      {
93
+        var thisPeak = Math.abs(lastPeak + Math.floor(Math.random()*(-6) + Math.random()*6));
94
+        oled.drawLine(peak, thisPeak, peak, 47, 1);
95
+        lastPeak = thisPeak;
96
+      }
97
+      break;
98
+    case 6:
99
+      for(var y=0; y<47; y++)
100
+      {
101
+        oled.drawLineHorizontal(0,y+1,63,2);
102
+        oled.refresh();
103
+        oled.drawLineHorizontal(0,y,63,2);
104
+      }
105
+      break;
106
+    case 7:
107
+      var eqbarHeights = [ Math.floor(Math.random()*32),
108
+                           Math.floor(Math.random()*32),
109
+                           Math.floor(Math.random()*32),
110
+                           Math.floor(Math.random()*32),
111
+                           Math.floor(Math.random()*32),
112
+                           Math.floor(Math.random()*32),
113
+                           Math.floor(Math.random()*32) ];
114
+      var begin = Date.now();
115
+      while(Date.now()-begin < 2000)
116
+      {
117
+        oled.clearScreenBuffer();
118
+        for(var eqbar=0; eqbar<7; eqbar++)
119
+        {
120
+          oled.drawRectangleFilled(eqbar*9, 49 - eqbarHeights[eqbar], 8, eqbarHeights[eqbar], 1);
121
+          eqbarHeights[eqbar] = eqbarHeights[eqbar] + Math.random()*(-2) + Math.random()*2;
122
+          if(eqbarHeights[eqbar]<0)
123
+            eqbarHeights[eqbar] = 1;
124
+        }
125
+        oled.refresh();
126
+      }
127
+      oled.clear();
128
+      break;
129
+    case 8:
130
+      oled.drawRoundedRectangle(8, 8, 48, 16, 4, 1);
131
+      oled.setCursor(12, 16);
132
+      oled.write("Cancel");
133
+      break;
134
+    case 9:
135
+      oled.drawTriangle(2, 2, 52, 7, 17, 37, 1);
136
+      break;
137
+    case 10:
138
+      oled.drawTriangleFilled(2, 2, 52, 7, 17, 37, 1);
139
+      break;
140
+    case 11:
141
+      oled.drawCircle(32, 24, 14, 1);
142
+      break;
143
+    case 12:
144
+      oled.drawCircleFilled(32, 24, 14, 1);
145
+      break;
146
+    case 13:
147
+      oled.fillScreen(1);
148
+      break;
149
+  }
150
+}

+ 435
- 71
src/lcd/eboled.cxx View File

@@ -2,6 +2,9 @@
2 2
  * Author: Jon Trulson <jtrulson@ics.com>
3 3
  * Copyright (c) 2015 Intel Corporation.
4 4
  *
5
+ * Author: Tyler Gibson <tgibson@microsoft.com>
6
+ * Copyright (c) 2015 Microsoft Corporation.
7
+ *
5 8
  * Permission is hereby granted, free of charge, to any person obtaining
6 9
  * a copy of this software and associated documentation files (the
7 10
  * "Software"), to deal in the Software without restriction, including
@@ -29,15 +32,23 @@
29 32
 using namespace upm;
30 33
 using namespace std;
31 34
 
32
-EBOLED::EBOLED(int spi, int CD, int reset) : 
35
+static uint16_t screenBuffer[BUFFER_SIZE];
36
+
37
+EBOLED::EBOLED(int spi, int CD, int reset) :
33 38
   m_spi(spi), m_gpioCD(CD), m_gpioRST(reset)
34 39
 {
35 40
   m_name = "EBOLED";
36
-  
41
+  m_textColor = COLOR_WHITE;
42
+  m_textWrap = 0;
43
+  m_textSize = 1;
44
+  m_cursorX = 0;
45
+  m_cursorY = 0;
46
+
37 47
   m_gpioCD.dir(mraa::DIR_OUT);
38 48
   m_gpioRST.dir(mraa::DIR_OUT);
39 49
 
40
-  m_spi.frequency(1000000);
50
+  //1000000 is standard.
51
+  m_spi.frequency(10000000);
41 52
 
42 53
   // reset the device
43 54
   m_gpioRST.write(1);
@@ -53,40 +64,48 @@ EBOLED::EBOLED(int spi, int CD, int reset) :
53 64
 
54 65
   command(CMD_SETMULTIPLEX);
55 66
   command(0x2f);
56
-  
67
+
57 68
   command(CMD_SETDISPLAYOFFSET);
58 69
   command(0x0);                 // no offset
59
-  
70
+
60 71
   command(CMD_SETSTARTLINE | 0x0); // line #0
61
-  
72
+
62 73
   command(CMD_CHARGEPUMP);      // enable charge pump
63 74
   command(0x14);
64
-  
75
+
65 76
   command(CMD_NORMALDISPLAY);
66 77
   command(CMD_DISPLAYALLONRESUME);
67
-  
78
+
68 79
   command(CMD_SEGREMAP | 0x1);  // reverse mapping (SEG0==COL127)
69 80
   command(CMD_COMSCANDEC);
70
-  
81
+
71 82
   command(CMD_SETCOMPINS);      // custom COM PIN mapping
72 83
   command(0x12);
73
-  
84
+
74 85
   command(CMD_SETCONTRAST);
75 86
   command(0x8f);
76
-  
87
+
77 88
   command(CMD_SETPRECHARGE);
78 89
   command(0xf1);
79
-  
90
+
80 91
   command(CMD_SETVCOMDESELECT);
81 92
   command(0x40);
82
-  
93
+
83 94
   command(CMD_DISPLAYON);
84
-  
85 95
 
86 96
   usleep(4500);
87
-  
88
-  clear();
89
-  setAddressingMode(PAGE);
97
+
98
+  setAddressingMode(HORIZONTAL);
99
+
100
+  //Set Page Address range, required for horizontal addressing mode.
101
+  command(CMD_SETPAGEADDRESS); // triple-byte cmd
102
+  command(0x00); //Initial page address
103
+  command(0x05); //Final page address
104
+
105
+  //Set Column Address range, required for horizontal addressing mode.
106
+  command(CMD_SETCOLUMNADDRESS); // triple-byte cmd
107
+  command(0x20); // this display has a horizontal offset of 20 columns
108
+  command(0x5f); // 64 columns wide - 0 based 63 offset
90 109
 }
91 110
 
92 111
 EBOLED::~EBOLED()
@@ -94,68 +113,117 @@ EBOLED::~EBOLED()
94 113
   clear();
95 114
 }
96 115
 
97
-mraa::Result EBOLED::draw(uint8_t* bdata, int bytes)
116
+mraa::Result EBOLED::refresh()
98 117
 {
99
-  mraa::Result error = mraa::SUCCESS;
100
-
101
-  setAddressingMode(HORIZONTAL);
102
-
103
-  command(CMD_SETCOLUMNADDRESS); // triple-byte cmd
104
-  command(0x20); // this display has a horizontal offset of 20 columns
105
-  command(0x20 + 0x40); // 64 columns wide
118
+  mraa::Result error = mraa::SUCCESS;;
106 119
 
107
-  for (int idx = 0; idx < bytes; idx++)
108
-    error = data(bdata[idx]);
109
-
110
-  // reset addressing mode
111
-  setAddressingMode(PAGE);
120
+  m_gpioCD.write(1);            // data mode
121
+  for(int i=0; i<BUFFER_SIZE; i++)
122
+  {
123
+    error = data(screenBuffer[i]);
124
+    if(error != MRAA_SUCCESS)
125
+      return error;
126
+  }
112 127
 
113 128
   return error;
114 129
 }
115 130
 
116
-mraa::Result EBOLED::write(std::string msg)
131
+mraa::Result EBOLED::write (std::string msg)
117 132
 {
118
-  mraa::Result error = mraa::SUCCESS;
133
+  int len = msg.length();
134
+  uint8_t temp_cursorX = m_cursorX;
135
+  for (int idx = 0; idx < len; idx++)
136
+  {
137
+    if (msg[idx] == '\n')
138
+    {
139
+      m_cursorY += m_textSize * 9;
140
+      temp_cursorX = m_cursorX;
141
+    }
142
+    else if (msg[idx] == '\r')
143
+    {
144
+      // skip em
145
+    }
146
+    else
147
+    {
148
+      drawChar(temp_cursorX, m_cursorY, msg[idx], m_textColor, m_textSize);
149
+      temp_cursorX += m_textSize * 6;
150
+
151
+      //textColor used to avoid wrapping if COLOR_BLACK is set.
152
+      if (m_textWrap && (m_textColor > OLED_WIDTH - temp_cursorX - 6))
153
+      {
154
+        m_cursorY += m_textSize * 9;
155
+        temp_cursorX = m_cursorX;
156
+      }
157
+    }
158
+  }
159
+  return mraa::SUCCESS;;
160
+}
119 161
 
120
-  setAddressingMode(PAGE);
121
-  for (std::string::size_type i = 0; i < msg.size(); ++i)
122
-    error = writeChar(msg[i]);
162
+mraa::Result EBOLED::setCursor (int row, int column) {
163
+  m_cursorX = column;
164
+  m_cursorY = row;
165
+  return mraa::SUCCESS;;
166
+}
123 167
 
124
-  return error;
168
+void EBOLED::setTextColor (uint8_t textColor) {
169
+  m_textColor   = textColor;
125 170
 }
126 171
 
127
-mraa::Result EBOLED::setCursor(int row, int column)
128
-{
129
-  mraa::Result error = mraa::SUCCESS;
172
+void EBOLED::setTextSize (uint8_t size) {
173
+  m_textSize = (size > 0) ? size : 1;
174
+}
130 175
 
131
-  // set page address
132
-  error = command(CMD_SETPAGESTARTADDR | (row & 0x07));
176
+void EBOLED::setTextWrap (uint8_t wrap) {
177
+  m_textWrap = wrap;
178
+}
133 179
 
134
-  // set column address
135
-  error = command(CMD_SETLOWCOLUMN | (column & 0x0f));
136
-  // ediblock oled starts at col 20 apparently...
137
-  error = command(CMD_SETHIGHCOLUMN | ((column >> 4) & 0x0f) + 0x02);
180
+void EBOLED::drawChar (uint8_t x, uint8_t y, uint8_t data, uint8_t color, uint8_t size) {
181
+  if( (x >= OLED_WIDTH)            || // Clip right
182
+      (y >= OLED_HEIGHT)           || // Clip bottom
183
+      ((x + 6 * size - 1) < 0)  || // Clip left
184
+      ((y + 8 * size - 1) < 0))    // Clip top
185
+  return;
138 186
 
139
-  return error;
187
+  if (data < 0x20 || data > 0x7F) {
188
+    data = 0x20; // space
189
+  }
190
+
191
+  for (int8_t i=0; i<6; i++ ) {
192
+    uint8_t line;
193
+    if (i == 6)
194
+      line = 0x0;
195
+    else
196
+    {
197
+      //32 offset to align standard ASCII range to index
198
+      line = BasicFont[data - 32][i+1];
199
+      for (int8_t j = 0; j<8; j++)
200
+      {
201
+        if (line & 0x1)
202
+        {
203
+          if (size == 1) // default size
204
+            drawPixel(x+i, y+j, color);
205
+          else
206
+            drawRectangleFilled(x+(i*size), y+(j*size), size, size, color); // big size
207
+        }
208
+        line >>= 1;
209
+      }
210
+    }
211
+  }
140 212
 }
141 213
 
142 214
 mraa::Result EBOLED::clear()
143 215
 {
144
-  mraa::Result error = mraa::SUCCESS;
145
-  uint8_t columnIdx, rowIdx;
146
-  
147
-  for (rowIdx = 0; rowIdx < 8; rowIdx++)
148
-    {
149
-      setCursor(rowIdx, 0);
150
-      
151
-      // clear all columns (8 * 8 pixels per char)
152
-      for (columnIdx = 0; columnIdx < 8; columnIdx++)
153
-        error = writeChar(' ');
154
-    }
155
-  
156
-  home();
157
-  
158
-  return mraa::SUCCESS;
216
+  mraa::Result error = mraa::SUCCESS;;
217
+
218
+  m_gpioCD.write(1);            // data mode
219
+  for(int i=0; i<BUFFER_SIZE; i++)
220
+  {
221
+    error = data(0x0000);
222
+    if(error != MRAA_SUCCESS)
223
+      return error;
224
+  }
225
+
226
+  return mraa::SUCCESS;;
159 227
 }
160 228
 
161 229
 mraa::Result EBOLED::home()
@@ -163,19 +231,310 @@ mraa::Result EBOLED::home()
163 231
   return setCursor(0, 0);
164 232
 }
165 233
 
166
-mraa::Result EBOLED::writeChar(uint8_t value)
234
+void EBOLED::drawPixel(int8_t x, int8_t y, uint8_t color)
167 235
 {
168
-  mraa::Result rv;
236
+  if(x<0 || x>=OLED_WIDTH || y<0 || y>=OLED_HEIGHT)
237
+    return;
238
+
239
+  /* Screenbuffer is uint16 array, but pages are 8bit high so each buffer
240
+   * index is two columns.  This means the index is based on x/2 and
241
+   * OLED_WIDTH/2 = VERT_COLUMNS.
242
+   *
243
+   * Then to set the appropriate bit, we need to shift based on the y
244
+   * offset in relation to the page and then adjust for high/low based
245
+   * on the x position.
246
+  */
247
+
248
+  switch(color)
249
+  {
250
+    case COLOR_XOR:
251
+      screenBuffer[(x/2) + ((y/8) * VERT_COLUMNS)] ^= (1<<(y%8+(x%2 * 8)));
252
+      return;
253
+    case COLOR_WHITE:
254
+      screenBuffer[(x/2) + ((y/8) * VERT_COLUMNS)] |= (1<<(y%8+(x%2 * 8)));
255
+      return;
256
+    case COLOR_BLACK:
257
+      screenBuffer[(x/2) + ((y/8) * VERT_COLUMNS)] &= ~(1<<(y%8+(x%2 * 8)));
258
+      return;
259
+  }
260
+}
261
+
262
+void EBOLED::drawLine(int8_t x0, int8_t y0, int8_t x1, int8_t y1, uint8_t color)
263
+{
264
+  int16_t steep = abs(y1 - y0) > abs(x1 - x0);
169 265
 
170
-  if (value < 0x20 || value > 0x7F) {
171
-    value = 0x20; // space
266
+  if (steep) {
267
+    swap(x0, y0);
268
+    swap(x1, y1);
172 269
   }
173 270
 
174
-  for (uint8_t idx = 0; idx < 8; idx++) {
175
-    rv = data(BasicFont[value - 32][idx]);
271
+  if (x0 > x1) {
272
+    swap(x0, x1);
273
+    swap(y0, y1);
176 274
   }
177 275
 
178
-  return rv;
276
+  int16_t dx, dy;
277
+  dx = x1 - x0;
278
+  dy = abs (y1 - y0);
279
+
280
+  int16_t err = dx / 2;
281
+  int16_t ystep;
282
+
283
+  if (y0 < y1) {
284
+    ystep = 1;
285
+  } else {
286
+    ystep = -1;
287
+  }
288
+
289
+  for (; x0 <= x1; x0++) {
290
+    if (steep) {
291
+      drawPixel(y0, x0, color);
292
+    } else {
293
+      drawPixel(x0, y0, color);
294
+    }
295
+    err -= dy;
296
+    if (err < 0) {
297
+      y0 += ystep;
298
+      err += dx;
299
+    }
300
+  }
301
+}
302
+
303
+void EBOLED::drawLineHorizontal(int8_t x, int8_t y, uint8_t width, uint8_t color)
304
+{
305
+  drawLine(x, y, x+width-1, y, color);
306
+}
307
+
308
+void EBOLED::drawLineVertical(int8_t x, int8_t y, uint8_t height, uint8_t color)
309
+{
310
+  drawLine(x, y, x, y+height-1, color);
311
+}
312
+
313
+void EBOLED::drawRectangle(int8_t x, int8_t y, uint8_t width, uint8_t height, uint8_t color)
314
+{
315
+  drawLineHorizontal(x, y, width, color);
316
+  drawLineHorizontal(x, y+height-1, color);
317
+
318
+  uint8_t innerHeight = height - 2;
319
+  if(innerHeight > 0)
320
+  {
321
+    drawLineVertical(x, y+1, innerHeight, color);
322
+    drawLineVertical(x+width-1, y+1, innerHeight, color);
323
+  }
324
+}
325
+
326
+void EBOLED::drawRoundedRectangle(int8_t x, int8_t y, int8_t width, int8_t height, int16_t radius, uint8_t color) {
327
+  // smarter version
328
+  drawLineHorizontal(x+radius  , y         , width-2*radius,  color); // Top
329
+  drawLineHorizontal(x+radius  , y+height-1, width-2*radius,  color); // Bottom
330
+  drawLineVertical(  x         , y+radius  , height-2*radius, color); // Left
331
+  drawLineVertical(  x+width-1 , y+radius  , height-2*radius, color); // Right
332
+  // draw four corners
333
+  drawRoundCorners(x+radius        , y+radius         , radius, 1, color);
334
+  drawRoundCorners(x+width-radius-1, y+radius         , radius, 2, color);
335
+  drawRoundCorners(x+width-radius-1, y+height-radius-1, radius, 4, color);
336
+  drawRoundCorners(x+radius        , y+height-radius-1, radius, 8, color);
337
+}
338
+
339
+void EBOLED::drawRectangleFilled(int8_t x, int8_t y, uint8_t width, uint8_t height, uint8_t color)
340
+{
341
+  for (uint8_t i=x; i<x+width; i++) {
342
+    drawLineVertical(i, y, height, color);
343
+  }
344
+}
345
+
346
+void EBOLED::drawTriangle(int8_t x0, int8_t y0, int8_t x1, int8_t y1, int8_t x2, int8_t y2, uint8_t color)
347
+{
348
+  drawLine(x0, y0, x1, y1, color);
349
+  drawLine(x1, y1, x2, y2, color);
350
+  drawLine(x2, y2, x0, y0, color);
351
+}
352
+
353
+void EBOLED::drawTriangleFilled ( int8_t x0, int8_t y0, int8_t x1, int8_t y1, int8_t x2, int8_t y2, uint8_t color) {
354
+
355
+  int16_t a, b, y, last;
356
+
357
+  // Sort coordinates by Y order (y2 >= y1 >= y0)
358
+  if (y0 > y1) {
359
+    swap(y0, y1); swap(x0, x1);
360
+  }
361
+  if (y1 > y2) {
362
+    swap(y2, y1); swap(x2, x1);
363
+  }
364
+  if (y0 > y1) {
365
+    swap(y0, y1); swap(x0, x1);
366
+  }
367
+
368
+  if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
369
+    a = b = x0;
370
+    if(x1 < a)      a = x1;
371
+    else if(x1 > b) b = x1;
372
+    if(x2 < a)      a = x2;
373
+    else if(x2 > b) b = x2;
374
+    drawLineHorizontal(a, y0, b-a+1, color);
375
+    return;
376
+  }
377
+
378
+  int16_t
379
+    dx01 = x1 - x0,
380
+    dy01 = y1 - y0,
381
+    dx02 = x2 - x0,
382
+    dy02 = y2 - y0,
383
+    dx12 = x2 - x1,
384
+    dy12 = y2 - y1;
385
+  int32_t
386
+    sa   = 0,
387
+    sb   = 0;
388
+
389
+  // For upper part of triangle, find scanline crossings for segments
390
+  // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
391
+  // is included here (and second loop will be skipped, avoiding a /0
392
+  // error there), otherwise scanline y1 is skipped here and handled
393
+  // in the second loop...which also avoids a /0 error here if y0=y1
394
+  // (flat-topped triangle).
395
+  if(y1 == y2) last = y1;   // Include y1 scanline
396
+  else         last = y1-1; // Skip it
397
+
398
+  for(y=y0; y<=last; y++) {
399
+    a   = x0 + sa / dy01;
400
+    b   = x0 + sb / dy02;
401
+    sa += dx01;
402
+    sb += dx02;
403
+    /* longhand:
404
+    a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
405
+    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
406
+    */
407
+    if(a > b) swap(a,b);
408
+    drawLineHorizontal(a, y, b-a+1, color);
409
+  }
410
+
411
+  // For lower part of triangle, find scanline crossings for segments
412
+  // 0-2 and 1-2.  This loop is skipped if y1=y2.
413
+  sa = dx12 * (y - y1);
414
+  sb = dx02 * (y - y0);
415
+  for(; y<=y2; y++) {
416
+    a   = x1 + sa / dy12;
417
+    b   = x0 + sb / dy02;
418
+    sa += dx12;
419
+    sb += dx02;
420
+    /* longhand:
421
+    a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
422
+    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
423
+    */
424
+    if(a > b) swap(a,b);
425
+    drawLineHorizontal(a, y, b-a+1, color);
426
+  }
427
+}
428
+
429
+void EBOLED::drawCircle(int16_t x0, int16_t y0, int16_t radius, uint8_t color)
430
+{
431
+  int16_t f = 1 - radius;
432
+  int16_t ddF_x = 1;
433
+  int16_t ddF_y = -2 * radius;
434
+  int16_t x = 0;
435
+  int16_t y = radius;
436
+
437
+  drawPixel(x0  , y0+radius, color);
438
+  drawPixel(x0  , y0-radius, color);
439
+  drawPixel(x0+radius, y0  , color);
440
+  drawPixel(x0-radius, y0  , color);
441
+
442
+  while (x<y)
443
+  {
444
+    if (f >= 0)
445
+    {
446
+      y--;
447
+      ddF_y += 2;
448
+      f += ddF_y;
449
+    }
450
+    x++;
451
+
452
+    ddF_x += 2;
453
+    f += ddF_x;
454
+
455
+    drawPixel(x0 + x, y0 + y, color);
456
+    drawPixel(x0 - x, y0 + y, color);
457
+    drawPixel(x0 + x, y0 - y, color);
458
+    drawPixel(x0 - x, y0 - y, color);
459
+    drawPixel(x0 + y, y0 + x, color);
460
+    drawPixel(x0 - y, y0 + x, color);
461
+    drawPixel(x0 + y, y0 - x, color);
462
+    drawPixel(x0 - y, y0 - x, color);
463
+  }
464
+}
465
+
466
+void EBOLED::drawRoundCorners( int8_t x0, int8_t y0, int16_t radius, uint8_t cornername, uint8_t color) {
467
+  int16_t f     = 1 - radius;
468
+  int16_t ddF_x = 1;
469
+  int16_t ddF_y = -2 * radius;
470
+  int16_t x     = 0;
471
+  int16_t y     = radius;
472
+
473
+  while (x<y) {
474
+    if (f >= 0) {
475
+      y--;
476
+      ddF_y += 2;
477
+      f     += ddF_y;
478
+    }
479
+    x++;
480
+    ddF_x += 2;
481
+    f     += ddF_x;
482
+    if (cornername & 0x4) {
483
+      drawPixel(x0 + x, y0 + y, color);
484
+      drawPixel(x0 + y, y0 + x, color);
485
+    }
486
+    if (cornername & 0x2) {
487
+      drawPixel(x0 + x, y0 - y, color);
488
+      drawPixel(x0 + y, y0 - x, color);
489
+    }
490
+    if (cornername & 0x8) {
491
+      drawPixel(x0 - y, y0 + x, color);
492
+      drawPixel(x0 - x, y0 + y, color);
493
+    }
494
+    if (cornername & 0x1) {
495
+      drawPixel(x0 - y, y0 - x, color);
496
+      drawPixel(x0 - x, y0 - y, color);
497
+    }
498
+  }
499
+}
500
+
501
+void EBOLED::drawCircleFilled(int8_t x0, int8_t y0, int16_t radius, uint8_t color) {
502
+  drawLineVertical(x0, y0-radius, 2*radius+1, color);
503
+  drawRoundedCornersFilled(x0, y0, radius, 3, 0, color);
504
+}
505
+
506
+void EBOLED::drawRoundedCornersFilled(int8_t x0, int8_t y0, int16_t radius, uint8_t cornername, int16_t delta, uint8_t color) {
507
+
508
+  int16_t f     = 1 - radius;
509
+  int16_t ddF_x = 1;
510
+  int16_t ddF_y = -2 * radius;
511
+  int16_t x     = 0;
512
+  int16_t y     = radius;
513
+
514
+  while (x<y) {
515
+    if (f >= 0) {
516
+      y--;
517
+      ddF_y += 2;
518
+      f     += ddF_y;
519
+    }
520
+    x++;
521
+    ddF_x += 2;
522
+    f     += ddF_x;
523
+
524
+    if (cornername & 0x1) {
525
+      drawLineVertical(x0+x, y0-y, 2*y+1+delta, color);
526
+      drawLineVertical(x0+y, y0-x, 2*x+1+delta, color);
527
+    }
528
+    if (cornername & 0x2) {
529
+      drawLineVertical(x0-x, y0-y, 2*y+1+delta, color);
530
+      drawLineVertical(x0-y, y0-x, 2*x+1+delta, color);
531
+    }
532
+  }
533
+}
534
+
535
+void EBOLED::fillScreen(uint8_t color)
536
+{
537
+  drawRectangleFilled(0, 0, OLED_WIDTH-1, OLED_HEIGHT-1, color);
179 538
 }
180 539
 
181 540
 mraa::Result EBOLED::setAddressingMode(displayAddressingMode mode)
@@ -195,9 +554,14 @@ mraa::Result EBOLED::command(uint8_t cmd)
195 554
   return mraa::SUCCESS;
196 555
 }
197 556
 
198
-mraa::Result EBOLED::data(uint8_t data)
557
+mraa::Result EBOLED::data(uint16_t data)
199 558
 {
200
-  m_gpioCD.write(1);            // data mode
201
-  m_spi.writeByte(data);
559
+  m_spi.write_word(data);
202 560
   return mraa::SUCCESS;
203 561
 }
562
+
563
+void EBOLED::clearScreenBuffer()
564
+{
565
+  for(int i=0; i<BUFFER_SIZE;i++)
566
+    screenBuffer[i] = 0x0000;
567
+}

+ 221
- 12
src/lcd/eboled.h View File

@@ -2,6 +2,12 @@
2 2
  * Author: Jon Trulson <jtrulson@ics.com>
3 3
  * Copyright (c) 2015 Intel Corporation.
4 4
  *
5
+ * Author: Tyler Gibson <tgibson@microsoft.com>
6
+ * Copyright (c) 2015 Microsoft Corporation.
7
+ *
8
+ * Credits to Adafruit.
9
+ * Based on Adafruit ST7735 library, see original license in license.txt file.
10
+ *
5 11
  * Permission is hereby granted, free of charge, to any person obtaining
6 12
  * a copy of this software and associated documentation files (the
7 13
  * "Software"), to deal in the Software without restriction, including
@@ -35,6 +41,8 @@
35 41
 #define EBOLED_DEFAULT_CD      36
36 42
 #define EBOLED_DEFAULT_RESET   48
37 43
 
44
+#define swap(a, b) { uint8_t t = a; a = b; b = t; }
45
+
38 46
 namespace upm
39 47
 {
40 48
   /**
@@ -60,6 +68,15 @@ namespace upm
60 68
    *
61 69
    * @snippet eboled.cxx Interesting
62 70
    */
71
+
72
+  const uint8_t COLOR_WHITE     = 0x01;
73
+  const uint8_t COLOR_BLACK     = 0x00;
74
+  const uint8_t COLOR_XOR       = 0x02;
75
+  const uint8_t OLED_WIDTH      = 0x40; // 64 pixels
76
+  const uint8_t VERT_COLUMNS    = 0x20; // half width for hi/lo 16bit writes.
77
+  const uint8_t OLED_HEIGHT     = 0x30; // 48 pixels
78
+  const int     BUFFER_SIZE     = 192;
79
+
63 80
   class EBOLED : public LCD
64 81
   {
65 82
     // SSD commands
@@ -73,7 +90,7 @@ namespace upm
73 90
       CMD_SETPAGEADDRESS        = 0x22,
74 91
       CMD_SETSTARTLINE          = 0x40, // 0x40 - 0x7f
75 92
       CMD_SETCONTRAST           = 0x81,
76
-      CMD_CHARGEPUMP            = 0x8d, 
93
+      CMD_CHARGEPUMP            = 0x8d,
77 94
       CMD_SEGREMAP              = 0xa0,
78 95
       CMD_DISPLAYALLONRESUME    = 0xa4,
79 96
       CMD_DISPLAYALLON          = 0xa5,
@@ -102,28 +119,28 @@ namespace upm
102 119
      * @param reset reset pin
103 120
      * @param address the slave address the lcd is registered on
104 121
      */
105
-    EBOLED(int spi=EBOLED_DEFAULT_SPI_BUS, int CD=EBOLED_DEFAULT_CD, 
122
+    EBOLED(int spi=EBOLED_DEFAULT_SPI_BUS, int CD=EBOLED_DEFAULT_CD,
106 123
            int reset=EBOLED_DEFAULT_RESET);
107
-    
124
+
108 125
     /**
109 126
      * EBOLED Destructor
110 127
      */
111 128
     ~EBOLED();
112 129
 
113 130
     /**
114
-     * Draw an image, see examples/python/make_oled_pic.py for an
115
-     * explanation on how the pixels are mapped to bytes
131
+     * Draw the buffer to screen, see examples/python/make_oled_pic.py for an
132
+     * explanation on how the pixels are mapped to bytes.
116 133
      *
117 134
      * @param data the buffer to write
118 135
      * @param bytes the number of bytes to write
119 136
      * @return result of operation
120 137
      */
121
-    mraa::Result draw(uint8_t* data, int bytes);
138
+    mraa::Result refresh();
122 139
 
123 140
     /**
124 141
      * Write a string to LCD
125 142
      *
126
-     * @param msg the std::string to write to display, note only ascii 
143
+     * @param msg the std::string to write to display, note only ascii
127 144
      * chars are supported
128 145
      * @return result of operation
129 146
      */
@@ -132,12 +149,45 @@ namespace upm
132 149
     /**
133 150
      * Set cursor to a coordinate
134 151
      *
135
-     * @param row the row to set cursor to.  This device supports 6 rows.
136
-     * @param column the column to set cursor to. This device support
137
-     * 64 columns
152
+     * @param y Axis on the vertical scale. This device supports 6 rows.
153
+     * @param x Axis on the horizontal scale This device supports 64 columns
154
+     *
138 155
      * @return result of operation
139 156
      */
140
-    mraa::Result setCursor(int row, int column);
157
+    mraa::Result setCursor (int row, int column);
158
+
159
+    /**
160
+      * Sets a text color for a message
161
+      *
162
+      * @param textColor Font color: COLOR_WHITE, COLOR_BLACK or COLOR_XOR
163
+      */
164
+    void setTextColor (uint8_t textColor);
165
+
166
+    /**
167
+      * Sets the size of the font
168
+      *
169
+      * @param size Font size
170
+      */
171
+    void setTextSize (uint8_t size);
172
+
173
+    /**
174
+      * Wraps a printed message
175
+      *
176
+      * @param wrap True (1) or false (0)
177
+      */
178
+    void setTextWrap (uint8_t wrap);
179
+
180
+    /**
181
+      * Write a single character to the screen.
182
+      *
183
+      * @param x Axis on the horizontal scale
184
+      * @param y Axis on the vertical scale
185
+      * @param data Character to write
186
+      * @param color Character color
187
+      * @param bg Character background color
188
+      * @param size Size of the font
189
+      */
190
+    void drawChar (uint8_t x, uint8_t y, uint8_t data, uint8_t color, uint8_t size);
141 191
 
142 192
     /**
143 193
      * Clear display
@@ -146,6 +196,8 @@ namespace upm
146 196
      */
147 197
     mraa::Result clear();
148 198
 
199
+    void clearScreenBuffer();
200
+
149 201
     /**
150 202
      * Return to coordinate 0,0
151 203
      *
@@ -153,9 +205,160 @@ namespace upm
153 205
      */
154 206
     mraa::Result home();
155 207
 
208
+    /**
209
+     * Write a single pixel to the screen buffer.
210
+     * Can do an specific color write or toggle (xor) a pixel.
211
+     *
212
+     * @param x the x position of the pixel
213
+     * @param y the y position of the pixel
214
+     * @param color pixel is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
215
+     */
216
+    void drawPixel (int8_t x, int8_t y, uint8_t color=COLOR_WHITE);
217
+
218
+    /**
219
+     * Draw a line to the screen buffer.
220
+     *
221
+     * @param x0 the x position of the beginning of the line
222
+     * @param y0 the y position of the beginning of the line
223
+     * @param x1 the x position of the end of the line
224
+     * @param y1 the y position of the end of the line
225
+     * @param color line is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
226
+     */
227
+    void drawLine (int8_t x0, int8_t y0, int8_t x1, int8_t y1, uint8_t color = COLOR_WHITE);
228
+
229
+    /**
230
+     * Draw a horizontal line to the screen buffer.
231
+     *
232
+     * @param x the x position of the beginning of the line
233
+     * @param y the y position of the beginning of the line
234
+     * @param width is the horizontal length of the line
235
+     * @param color line is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
236
+     */
237
+    void drawLineHorizontal (int8_t x, int8_t y, uint8_t width, uint8_t color = COLOR_WHITE);
238
+
239
+    /**
240
+     * Draw a vertical line to the screen buffer.
241
+     *
242
+     * @param x the x position of the beginning of the line
243
+     * @param y the y position of the beginning of the line
244
+     * @param width is the vertical length of the line
245
+     * @param color line is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
246
+     */
247
+    void drawLineVertical (int8_t x, int8_t y, uint8_t height, uint8_t color = COLOR_WHITE);
248
+
249
+    /**
250
+     * Draw a rectangle to the screen buffer.
251
+     *
252
+     * @param x the left edge
253
+     * @param y the top edge
254
+     * @param width sets the right edge
255
+     * @param height bottom edge
256
+     * @param color outline is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
257
+     */
258
+    void drawRectangle (int8_t x, int8_t y, uint8_t width, uint8_t height, uint8_t color = COLOR_WHITE);
259
+
260
+    /**
261
+     * Draw a rectangle with rounded corners to the screen buffer.
262
+     *
263
+     * @param x the left edge
264
+     * @param y the top edge
265
+     * @param width sets the right edge
266
+     * @param height bottom edge
267
+     * @param radius of the rounded corners
268
+     * @param color outline is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
269
+     */
270
+    void drawRoundedRectangle(int8_t x, int8_t y, int8_t width, int8_t height, int16_t radius, uint8_t color);
271
+
272
+    /**
273
+     * Draw a filled rectangle to the screen buffer.
274
+     *
275
+     * @param x the left edge
276
+     * @param y the top edge
277
+     * @param width sets the right edge
278
+     * @param height bottom edge
279
+     * @param color fill color is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
280
+     */
281
+    void drawRectangleFilled (int8_t x, int8_t y, uint8_t width, uint8_t height, uint8_t color = COLOR_WHITE);
282
+
283
+    /**
284
+     * Draw a triangle to the screen buffer.
285
+     *
286
+     * @param x0 the x coordinate of the first corner
287
+     * @param y0 the y coordinate of the first corner
288
+     * @param x1 the x coordinate of the second corner
289
+     * @param y1 the y coordinate of the second corner
290
+     * @param x2 the x coordinate of the third corner
291
+     * @param y2 the y coordinate of the third corner
292
+     * @param color outline is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
293
+     */
294
+    void drawTriangle (int8_t x0, int8_t y0, int8_t x1, int8_t y1, int8_t x2, int8_t y2, uint8_t color = COLOR_WHITE);
295
+
296
+    /**
297
+     * Draw a filled triangle to the screen buffer.
298
+     *
299
+     * @param x0 the x coordinate of the first corner
300
+     * @param y0 the y coordinate of the first corner
301
+     * @param x1 the x coordinate of the second corner
302
+     * @param y1 the y coordinate of the second corner
303
+     * @param x2 the x coordinate of the third corner
304
+     * @param y2 the y coordinate of the third corner
305
+     * @param color fill color is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
306
+     */
307
+    void drawTriangleFilled ( int8_t x0, int8_t y0, int8_t x1, int8_t y1, int8_t x2, int8_t y2, uint8_t color);
308
+
309
+    /**
310
+     * Draw a circle to the screen buffer.
311
+     *
312
+     * @param x0 the x coordinate of the circle's center
313
+     * @param y0 the y coordinate of the circle's center
314
+     * @param radius the radius of the circle
315
+     * @param color outline is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
316
+     */
317
+    void drawCircle (int16_t x0, int16_t y0, int16_t radius, uint8_t color = COLOR_WHITE);
318
+
319
+    /**
320
+     * Draw a quarter circle arc to the screen buffer.
321
+     *
322
+     * @param x0 the x coordinate of the arc's center
323
+     * @param y0 the y coordinate of the arc's center
324
+     * @param radius the radius of the arc
325
+     * @param cornername denotes which of the 4 quarters to draw - 1,2,4,8
326
+     * @param color outline is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
327
+     */
328
+    void drawRoundCorners( int8_t x0, int8_t y0, int16_t radius, uint8_t cornername, uint8_t color);
329
+
330
+    /**
331
+     * Draw a filled circle to the screen buffer.
332
+     *
333
+     * @param x0 the x coordinate of the circle's center
334
+     * @param y0 the y coordinate of the circle's center
335
+     * @param radius the radius of the circle
336
+     * @param color outline is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
337
+     */
338
+    void drawCircleFilled(int8_t x0, int8_t y0, int16_t radius, uint8_t color);
339
+
340
+    /**
341
+     * Draw a quarter pie to the screen buffer.
342
+     *
343
+     * @param x0 the x coordinate of the arc's center
344
+     * @param y0 the y coordinate of the arc's center
345
+     * @param radius the radius of the arc
346
+     * @param cornername denotes which of the 4 quarters to draw - 1,2,4,8
347
+     * @param color fill color is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
348
+     */
349
+    void drawRoundedCornersFilled(int8_t x0, int8_t y0, int16_t radius, uint8_t cornername, int16_t delta, uint8_t color);
350
+
351
+    /**
352
+     * Fill the screen buffer with specified color.
353
+     *
354
+     * @param color fill color is COLOR_WHITE, COLOR_BLACK or COLOR_XOR
355
+     */
356
+    void fillScreen (uint8_t color=COLOR_WHITE);
357
+
358
+
156 359
   protected:
157 360
     mraa::Result command(uint8_t cmd);
158
-    mraa::Result data(uint8_t data);
361
+    mraa::Result data(uint16_t data);
159 362
     mraa::Result writeChar(uint8_t value);
160 363
     mraa::Result setAddressingMode(displayAddressingMode mode);
161 364
 
@@ -164,5 +367,11 @@ namespace upm
164 367
     mraa::Gpio m_gpioRST;       // reset pin
165 368
 
166 369
     mraa::Spi m_spi;
370
+
371
+    uint8_t m_cursorX;
372
+    uint8_t m_cursorY;
373
+    uint8_t m_textSize;
374
+    uint8_t m_textColor;
375
+    uint8_t m_textWrap;
167 376
   };
168 377
 }

+ 24
- 0
src/lcd/license.txt View File

@@ -0,0 +1,24 @@
1
+Software License Agreement (BSD License)
2
+
3
+Copyright (c) 2012 Adafruit Industries.  All rights reserved.
4
+
5
+Redistribution and use in source and binary forms, with or without
6
+modification, are permitted provided that the following conditions are met:
7
+
8
+- Redistributions of source code must retain the above copyright notice,
9
+  this list of conditions and the following disclaimer.
10
+- Redistributions in binary form must reproduce the above copyright notice,
11
+  this list of conditions and the following disclaimer in the documentation
12
+  and/or other materials provided with the distribution.
13
+
14
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
+POSSIBILITY OF SUCH DAMAGE.