A conversion of the excellent Adafruit WS2801 library for Arduino to work on mbed

Dependents:   WiFiDipCortex_Cheerlights

Revision:
3:dfffbd9f8ac6
Parent:
2:2fdaa13896a4
Child:
4:987c91c45188
--- a/Adafruit_WS2801.cpp	Wed Feb 12 22:05:44 2014 +0000
+++ b/Adafruit_WS2801.cpp	Tue Jun 03 15:45:14 2014 +0000
@@ -1,6 +1,7 @@
 #include "mbed.h"
 #include "Adafruit_WS2801.h"
 
+
 // Example to control WS2801-based RGB LED Modules in a strand or strip
 // Written by Adafruit - MIT license
 /*****************************************************************************/
@@ -8,19 +9,22 @@
 SPI spi(p16, p15, p13); // mosi, miso, sclk
 
 // Constructor for use with hardware SPI (specific clock/data pins):
-//Adafruit_WS2801::Adafruit_WS2801(uint16_t n, uint8_t order): clkpin(PTD4), datapin(PTA12)
-//{
-//    rgb_order = order;
-//    alloc(n);
-//    updatePins();
-//}
-
-// Constructor for use with arbitrary clock/data pins:
-Adafruit_WS2801::Adafruit_WS2801(uint16_t n, PinName dpin, PinName cpin, uint8_t order)  : clkpin(cpin), datapin(dpin)
+/*Adafruit_WS2801::Adafruit_WS2801(uint16_t n, uint8_t order): clkpin(PTD4), datapin(PTA12)
 {
     rgb_order = order;
     alloc(n);
-   
+    updatePins();
+}*/
+
+// Constructor for use with arbitrary clock/data pins:
+Adafruit_WS2801::Adafruit_WS2801(int16_t n, PinName dpin, PinName cpin, uint8_t order) 
+    : clkpin(cpin), datapin(dpin)
+{
+    rgb_order = order;
+    alloc(n);
+    width = 1;
+    height = n;
+    hardwareSPI = false;
 //  updatePins(dpin, cpin);
 }
 
@@ -28,12 +32,14 @@
 // assumes configuration where string starts at coordinate 0,0 and continues to w-1,0, w-1,1
 // and on to 0,1, 0,2 and on to w-1,2 and so on. Snaking back and forth till the end.
 // other function calls with provide access to pixels via an x,y coordinate system
-Adafruit_WS2801::Adafruit_WS2801(uint16_t w, uint16_t h, PinName dpin, PinName cpin, uint8_t order)  : clkpin(cpin), datapin(dpin)
+Adafruit_WS2801::Adafruit_WS2801(int16_t w, int16_t h, PinName dpin, PinName cpin, uint8_t order) 
+    : clkpin(cpin), datapin(dpin)
 {
     rgb_order = order;
     alloc(w * h);
     width = w;
     height = h;
+    hardwareSPI = false;
 //  updatePins(dpin, cpin);
 }
 
@@ -42,7 +48,7 @@
 {
     begun   = false;
     numLEDs = ((pixels = (uint8_t *)calloc(n, 3)) != NULL) ? n : 0;
-
+    hardwareSPI = true;
 
 //    for(int bits = 0; bits <= numLEDs*24; bits++) {
 //        spi.write(0x00);
@@ -53,6 +59,23 @@
 //    clkpin = 0;
 }
 
+// Constructor for use with a matrix configuration, specify w, h for size of matrix
+// assumes configuration where string starts at coordinate 0,0 and continues to w-1,0, w-1,1
+// and on to 0,1, 0,2 and on to w-1,2 and so on. Snaking back and forth till the end.
+// other function calls with provide access to pixels via an x,y coordinate system
+/*Adafruit_WS2801::Adafruit_WS2801(uint16_t w, uint16_t h, uint8_t order)
+{
+    rgb_order = order;
+    alloc(w * h);
+    width = w;
+    height = h;
+    hardwareSPI = true;
+//  updatePins(dpin, cpin);
+}
+*/
+
+
+
 // via Michael Vogt/neophob: empty constructor is used when strand length
 // isn't known at compile-time; situations where program config might be
 // read from internal flash memory or an SD card, or arrive via serial
@@ -101,15 +124,16 @@
 
 
 // Change pin assignments post-constructor, using arbitrary pins:
-//void Adafruit_WS2801::updatePins(PinName dpin, PinName cpin)
-//{
+void Adafruit_WS2801::updatePins(PinName dpin, PinName cpin)
+{
     // Note: any prior clock/data pin directions are left as-is and are
     // NOT restored as inputs!
 
-//    datapin     = DigitalOut(dpin);
-//    clkpin      = DigitalOut(cpin);
-//}
+    datapin     = DigitalOut(dpin);
+    clkpin      = DigitalOut(cpin);
+}
 
+// Return the number of LEDs
 uint16_t Adafruit_WS2801::numPixels(void)
 {
     return numLEDs;
@@ -140,7 +164,7 @@
         for(i=0; i<nl3; i++ ) {
             spi.write( pixels[i]);
         }        
-        wait_ms(1); // Data is latched by holding clock pin low for 1 millisecond
+       // wait_ms(1); // Needed????
     } else {
         uint8_t  bit;
 
@@ -179,11 +203,15 @@
 }
 
 // Set pixel color from separate 8-bit R, G, B components using x,y coordinate system:
-void Adafruit_WS2801::setPixelColor(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b)
+void Adafruit_WS2801::setPixelColor(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b)
 {
+    if( x < 0 || x >= width || y < 0 || y >= height )
+        return;         // Dont try to update a pixel that doesnt exist
+
     bool evenRow = ((y % 2) == 0);
     // calculate x offset first
     uint16_t offset = x % width;
+
     if (!evenRow) {
         offset = (width-1) - offset;
     }
@@ -195,7 +223,7 @@
 // Set pixel color from 'packed' 32-bit RGB value:
 void Adafruit_WS2801::setPixelColor(uint16_t n, uint32_t c)
 {
-    if(n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
+    if( n < numLEDs) { // Arrays are 0-indexed, thus NOT '<='
         uint8_t *p = &pixels[n * 3];
         // To keep the show() loop as simple & fast as possible, the
         // internal color representation is native to different pixel
@@ -213,8 +241,11 @@
 }
 
 // Set pixel color from 'packed' 32-bit RGB value using x,y coordinate system:
-void Adafruit_WS2801::setPixelColor(uint16_t x, uint16_t y, uint32_t c)
+void Adafruit_WS2801::setPixelColor(int16_t x, int16_t y, uint32_t c)
 {
+    if( x < 0 || x >= width || y < 0 || y >= height )
+        return;         // Dont try to update a pixel that doesnt exist
+        
     bool evenRow = ((y % 2) == 0);
     // calculate x offset first
     uint16_t offset = x % width;
@@ -242,3 +273,140 @@
 
     return 0; // Pixel # is out of bounds
 }
+
+// bresenham's algorithm - thx wikpedia
+void Adafruit_WS2801::drawLine(int16_t x0, int16_t y0, 
+                int16_t x1, int16_t y1, 
+                uint32_t color) {
+  int16_t steep = abs(y1 - y0) > abs(x1 - x0);
+  if (steep) {
+    ws_swap(x0, y0);
+    ws_swap(x1, y1);
+  }
+
+  if (x0 > x1) {
+    ws_swap(x0, x1);
+    ws_swap(y0, y1);
+  }
+
+  int16_t dx, dy;
+  dx = x1 - x0;
+  dy = abs(y1 - y0);
+
+  int16_t err = dx / 2;
+  int16_t ystep;
+
+  if (y0 < y1) {
+    ystep = 1;
+  } else {
+    ystep = -1;
+  }
+
+  for (; x0<=x1; x0++) {
+    if (steep) {
+      setPixelColor(y0, x0, color);
+    } else {
+      setPixelColor(x0, y0, color);
+    }
+    err -= dy;
+    if (err < 0) {
+      y0 += ystep;
+      err += dx;
+    }
+  }
+}
+
+void Adafruit_WS2801::drawFastVLine(int16_t x, int16_t y, 
+                 int16_t h, uint32_t color) {
+  // stupidest version - update in subclasses if desired!
+  drawLine(x, y, x, y+h-1, color);
+}
+
+
+void Adafruit_WS2801::drawFastHLine(int16_t x, int16_t y, 
+                 int16_t w, uint32_t color) {
+  // stupidest version - update in subclasses if desired!
+  drawLine(x, y, x+w-1, y, color);
+}
+
+
+// draw a rectangle
+void Adafruit_WS2801::drawRect(int16_t x, int16_t y, 
+                int16_t w, int16_t h, uint32_t color) {
+  drawFastHLine(x, y, w, color);
+  drawFastHLine(x, y+h-1, w, color);
+  drawFastVLine(x, y, h, color);
+  drawFastVLine(x+w-1, y, h, color);
+}
+
+// draw a circle outline
+void Adafruit_WS2801::drawCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color) {
+  int16_t f = 1 - r;
+  int16_t ddF_x = 1;
+  int16_t ddF_y = -2 * r;
+  int16_t x = 0;
+  int16_t y = r;
+
+  setPixelColor(x0, y0+r, color);
+  setPixelColor(x0, y0-r, color);
+  setPixelColor(x0+r, y0, color);
+  setPixelColor(x0-r, y0, color);
+
+  while (x<y) {
+    if (f >= 0) {
+      y--;
+      ddF_y += 2;
+      f += ddF_y;
+    }
+    x++;
+    ddF_x += 2;
+    f += ddF_x;
+  
+    setPixelColor(x0 + x, y0 + y, color);
+    setPixelColor(x0 - x, y0 + y, color);
+    setPixelColor(x0 + x, y0 - y, color);
+    setPixelColor(x0 - x, y0 - y, color);
+    setPixelColor(x0 + y, y0 + x, color);
+    setPixelColor(x0 - y, y0 + x, color);
+    setPixelColor(x0 + y, y0 - x, color);
+    setPixelColor(x0 - y, y0 - x, color);
+    
+  }
+}
+/*
+void Adafruit_WS2801::fillCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color) {
+  drawFastVLine(x0, y0-r, 2*r+1, color);
+  fillCircleHelper(x0, y0, r, 3, 0, color);
+}
+
+// used to do circles and roundrects!
+void Adafruit_WS2801::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
+                    uint8_t cornername, int16_t delta, uint32_t color) {
+
+  int16_t f     = 1 - r;
+  int16_t ddF_x = 1;
+  int16_t ddF_y = -2 * r;
+  int16_t x     = 0;
+  int16_t y     = r;
+
+  while (x<y) {
+    if (f >= 0) {
+      y--;
+      ddF_y += 2;
+      f     += ddF_y;
+    }
+    x++;
+    ddF_x += 2;
+    f     += ddF_x;
+
+    if (cornername & 0x1) {
+      drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
+      drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
+    }
+    if (cornername & 0x2) {
+      drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
+      drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
+    }
+  }
+}
+*/