8x8x8 Led Cube driven by 4x PCF8575 for the columns and 1x PCF8574 for the layers

Files at this revision

API Documentation at this revision

Comitter:
Bas
Date:
Thu Nov 01 22:31:54 2012 +0000
Parent:
0:920c5ed65a45
Commit message:
Added several simple graphic functions helping to create animations

Changed in this revision

led_cube.cpp Show annotated file Show diff for this revision Revisions of this file
led_cube.h Show annotated file Show diff for this revision Revisions of this file
diff -r 920c5ed65a45 -r e08a4d27f534 led_cube.cpp
--- a/led_cube.cpp	Sat Sep 08 22:14:10 2012 +0000
+++ b/led_cube.cpp	Thu Nov 01 22:31:54 2012 +0000
@@ -30,7 +30,8 @@
 }
 
 //clear everything
-void LED_CUBE::clear_cube(void){
+void LED_CUBE::clear_cube(void)
+{
     row.WriteByte(0xFF);
     colums_0_1.WriteBytes(0xFF,0xFF);
     colums_2_3.WriteBytes(0xFF,0xFF);
@@ -39,35 +40,555 @@
     clearVoxels();
 }
 
-//set a voxel in my space saver cube array
-void LED_CUBE::setVoxel(unsigned char x, unsigned char y, unsigned char z){
-    cubeData[z*8 + y] |= 0x01<<x;
+//set a voxel in the cube array
+void LED_CUBE::setVoxel(unsigned char x, unsigned char y, unsigned char z)
+{
+    if (inrange(x, y, z))
+        cubeData[z*8 + x] |= 0x01<<y;
 }
 
-//clear a single voxel in my space saver cube array
-void LED_CUBE::clearVoxel(unsigned char x, unsigned char y, unsigned char z){
-    cubeData[z*8 + y] &= ~(0x01<<x);
+//clear a single voxel in the cube array
+void LED_CUBE::clearVoxel(unsigned char x, unsigned char y, unsigned char z)
+{
+    if (inrange(x, y, z))
+        cubeData[z*8 + x] &= ~(0x01<<y);
 }
 
-//return the value of the voxel in my cube array
-unsigned char LED_CUBE::getVoxel(unsigned char x, unsigned char y, unsigned char z){
-    if(cubeData[z*8 + y] & 0x01<<x){
-        return 1;
-    }else{
+//return the value of a single voxel in the cube array
+unsigned char LED_CUBE::getVoxel(unsigned char x, unsigned char y, unsigned char z)
+{
+    if (inrange(x, y, z)) {
+        if(cubeData[z*8 + x] & 0x01<<y) {
+            return 1;
+        } else {
+            return 0;
+        }
+    } else {
         return 0;
     }
 }
 
-void LED_CUBE::copyColumn(unsigned char x, unsigned char y, unsigned char col){
-    for(unsigned char z = 0; z < Zd; z++){
-        if(col&(0x01<<z)){
+void LED_CUBE::copyColumn(unsigned char x, unsigned char y, unsigned char col)
+{
+    for(unsigned char z = 0; z < 8; z++) {
+        if(col&(0x01<<z)) {
             setVoxel(x, y, z);
-        }else{
+        } else {
             clearVoxel(x, y, z);
         }
     }
 }
+
+// In some effect we want to just take bool and write it to a voxel
+// this function calls the apropriate voxel manipulation function.
+void LED_CUBE::alterVoxel(unsigned char x, unsigned char y, unsigned char z, unsigned char state)
+{
+    if (state == 1) {
+        setVoxel(x,y,z);
+    } else {
+        clearVoxel(x,y,z);
+    }
+}
+
+// Flip the state of a voxel.
+// If the voxel is 1, its turned into a 0, and vice versa.
+void LED_CUBE::flipVoxel(unsigned char x, unsigned char y, unsigned char z)
+{
+    if (inrange(x, y, z))
+        cubeData[z*8 + x] ^= (1 << y);
+}
+
+void LED_CUBE::setPlane_x (int x)
+{
+    int z;
+
+    if (x>=0 && x<8) {
+        for (z=0; z<8; z++)
+            cubeData[z*8 + x] = 0xFF;
+    }
+}
+
+void LED_CUBE::clearPlane_x (int x)
+{
+    int z;
+
+    if (x>=0 && x<8) {
+        for (z=0; z<8; z++)
+            cubeData[z*8 + x] = 0x00;
+    }
+}
+
+void LED_CUBE::setPlane_y (int y)
+{
+    int z;
+    int x;
+
+    if (y>=0 && y<8) {
+        for (z=0; z<8; z++) {
+            for (x=0; x<8; x++) {
+                cubeData[z*8 + x] |= (1 << y);
+            }
+        }
+    }
+}
+
+void LED_CUBE::clearPlane_y (int y)
+{
+    int z;
+    int x;
+
+    if (y>=0 && y<8) {
+        for (z=0; z<8; z++) {
+            for (x=0; x<8; x++) {
+                cubeData[z*8 + x] &= ~(1 << y);
+            }
+        }
+    }
+}
+// Sets all voxels along a X/Y plane at a given point
+// on axis Z
+void LED_CUBE::setPlane_z (int z)
+{
+    int i;
+
+    if (z>=0 && z<8) {
+        for (i=0; i<8; i++)
+            cubeData[z*8 + i] = 0xFF;
+    }
+}
+
+// Clears voxels in the same manner as above
+void LED_CUBE::clearPlane_z (int z)
+{
+    int i;
+
+    if (z>=0 && z<8) {
+        for (i=0; i<8; i++)
+            cubeData[z*8 + i] = 0x00;
+    }
+}
+
+void LED_CUBE::setPlane (char axis, unsigned char i)
+{
+    switch (axis) {
+        case AXIS_X:
+            setPlane_x(i);
+            break;
+        case AXIS_Y:
+            setPlane_y(i);
+            break;
+        case AXIS_Z:
+            setPlane_z(i);
+            break;
+    }
+}
+
+void LED_CUBE::clearPlane (char axis, unsigned char i)
+{
+    switch (axis) {
+        case AXIS_X:
+            clearPlane_x(i);
+            break;
+        case AXIS_Y:
+            clearPlane_y(i);
+            break;
+        case AXIS_Z:
+            clearPlane_z(i);
+            break;
+    }
+}
+void LED_CUBE::setSlope_XY(int x1, int y1, int x2, int y2)
+{
+    float slope, offset;
+    int x,y,z;
+
+    if (x1>x2) {
+        int tmp;
+        tmp = x2;
+        x2 = x1;
+        x1 = tmp;
+        tmp = y2;
+        y2 = y1;
+        y1 = tmp;
+    }
+
+    slope=float(y2-y1)/float(x2-x1);
+    offset=-x1*slope +y1;
+
+    if ((x2-x1)>=7) {
+        for(x=0; x<8; x++) {
+            y = floor((x*slope + offset)+0.5);
+            for(z=0; z<8; z++) {
+                setVoxel(x,y,z);
+            }
+        }
+    } else if(x1==x2) {
+        for(y=0; y<8; y++) {
+            for(z=0; z<8; z++) {
+                setVoxel(x1,y,z);
+            }
+        }
+    } else {
+        for(y=0; y<8; y++) {
+            x = floor(((y-offset)/slope)+0.5);
+            for(z=0; z<8; z++) {
+                setVoxel(x,y,z);
+            }
+
+        }
+    }
+}
+
+void LED_CUBE::setSlope_XZ(int x1, int z1, int x2, int z2)
+{
+    float slope, offset;
+    int x,z;
+
+    if (x1>x2) {
+        int tmp;
+        tmp = x2;
+        x2 = x1;
+        x1 = tmp;
+        tmp = z2;
+        z2 = z1;
+        z1 = tmp;
+    }
+
+    slope=float(z2-z1)/float(x2-x1);
+    offset=-x1*slope +z1;
+
+    if ((x2-x1)>=7) {
+        for(x=0; x<8; x++) {
+            z = floor((x*slope + offset)+0.5);
+            cubeData[z*8 + x] = 0xFF;
+
+        }
+    } else if(x1==x2) {
+        for(z=0; z<8; z++) {
+            cubeData[z*8 + x1] = 0xFF;
+
+        }
+    } else {
+        for(z=0; z<8; z++) {
+            x = floor(((z-offset)/slope)+0.5);
+            cubeData[z*8 + x] = 0xFF;
+
+        }
+
+    }
+}
+
+
+void LED_CUBE::setSlope_YZ(int y1, int z1, int y2, int z2)
+{
+    float slope, offset;
+    int x,y,z;
+
+    if (y1>y2) {
+        int tmp;
+        tmp = y2;
+        y2 = y1;
+        y1 = tmp;
+        tmp = z2;
+        z2 = z1;
+        z1 = tmp;
+    }
+
+    slope=float(z2-z1)/float(y2-y1);
+    offset=-y1*slope +z1;
+
+    if ((y2-y1)>=7) {
+        for(y=0; y<8; y++) {
+            z = floor((y*slope + offset)+0.5);
+            for(x=0; x<8; x++) {
+                setVoxel(x,y,z);
+            }
+        }
+    } else if(y1==y2) {
+        for(z=0; z<8; z++) {
+            for(x=0; x<8; x++) {
+                setVoxel(x,y1,z);
+            }
+        }
+    } else {
+        for(z=0; z<8; z++) {
+            y = floor(((z-offset)/slope)+0.5);
+            for(x=0; x<8; x++) {
+                setVoxel(x,y,z);
+            }
+        }
+
+    }
+}
+
 //clear all the voxels in the array
-void LED_CUBE::clearVoxels(void){
+void LED_CUBE::clearVoxels(void)
+{
     memset(cubeData, 0, 64*sizeof(unsigned char));
+}
+
+// Fill a value into all 64 byts of the cube buffer
+// Mostly used for clearing. fill(0xr0)
+// or setting all on. fill(0xff)
+void LED_CUBE::fill (unsigned char pattern)
+{
+    memset(cubeData, pattern, 64*sizeof(unsigned char));
+}
+
+// Draw a box with all walls drawn and all voxels inside set
+void LED_CUBE::box_filled(int x1, int y1, int z1, int x2, int y2, int z2)
+{
+    int ix;
+    int iz;
+
+    argorder(x1, x2, &x1, &x2);
+    argorder(y1, y2, &y1, &y2);
+    argorder(z1, z2, &z1, &z2);
+    for (iz=z1; iz<=z2; iz++) {
+        for (ix=x1; ix<=x2; ix++) {
+            cubeData[iz*8 + ix] |= byteline(y1,y2);
+        }
+    }
+}
+
+// Draw a hollow box with side walls.
+void LED_CUBE::box_walls(int x1, int y1, int z1, int x2, int y2, int z2)
+{
+    int ix;
+    int iz;
+
+    argorder(x1, x2, &x1, &x2);
+    argorder(y1, y2, &y1, &y2);
+    argorder(z1, z2, &z1, &z2);
+    for (iz=z1; iz<=z2; iz++) {
+        for (ix=x1; ix<=x2; ix++) {
+            if (ix == x1 || ix == x2 || iz == z1 || iz == z2) {
+                cubeData[iz*8 + ix] = byteline(y1,y2);
+            } else {
+                cubeData[iz*8 + ix] |= ((0x01 << y1) | (0x01 << y2));
+            }
+        }
+    }
+}
+
+// Draw a wireframe box. This only draws the corners and edges,
+// no walls.
+void LED_CUBE::box_wireframe(int x1, int y1, int z1, int x2, int y2, int z2)
+{
+    int ix;
+    int iz;
+
+    argorder(x1, x2, &x1, &x2);
+    argorder(y1, y2, &y1, &y2);
+    argorder(z1, z2, &z1, &z2);
+    // Lines along Y axis
+    cubeData[z1*8 + x1] |= byteline(y1,y2);
+    cubeData[z1*8 + x2] |= byteline(y1,y2);
+    cubeData[z2*8 + x1] |= byteline(y1,y2);
+    cubeData[z2*8 + x2] |= byteline(y1,y2);
+    // Lines along X axis
+    for (ix=x1; ix<=x2; ix++) {
+        setVoxel(ix,y1,z1);
+        setVoxel(ix,y1,z2);
+        setVoxel(ix,y2,z1);
+        setVoxel(ix,y2,z2);
+    }
+    // Lines along Z axis
+    for (iz=z1; iz<=z2; iz++) {
+        setVoxel(x1,y1,iz);
+        setVoxel(x1,y2,iz);
+        setVoxel(x2,y1,iz);
+        setVoxel(x2,y2,iz);
+    }
+}
+
+// Draw a line between any coordinates in 3d space.
+// Uses integer values for input, so dont expect smooth animations.
+void LED_CUBE::line(int x1, int y1, int z1, int x2, int y2, int z2)
+{
+    float xy;
+    // how many voxels do we move on the y axis for each step on the x axis
+    float xz;
+    // how many voxels do we move on the y axis for each step on the x axis
+    unsigned char x,y,z;
+    // We always want to draw the line from x=0 to x=7.
+    // If x1 is bigget than x2, we need to flip all the values.
+    if (x1>x2) {
+        int tmp;
+        tmp = x2;
+        x2 = x1;
+        x1 = tmp;
+        tmp = y2;
+        y2 = y1;
+        y1 = tmp;
+        tmp = z2;
+        z2 = z1;
+        z1 = tmp;
+    }
+    if (y1>y2) {
+        xy = (float)(y1-y2)/(float)(x2-x1);
+    } else {
+        xy = (float)(y2-y1)/(float)(x2-x1);
+    }
+    if (z1>z2) {
+        xz = (float)(z1-z2)/(float)(x2-x1);
+    } else {
+        xz = (float)(z2-z1)/(float)(x2-x1);
+    }
+    // For each step of x, y increments by:
+    for (x = x1; x<=x2; x++) {
+        y = (xy*(x-x1))+y1;
+        z = (xz*(x-x1))+z1;
+        setVoxel(x,y,z);
+    }
+}
+void LED_CUBE::circle(int xr, int yr, int zr, int d ,char axis)
+{
+    if (d%2) { // odd diameter, place center on half pixels
+// later
+    } else { // use midpoint circle algorithm
+        int r = d/2;
+        int f = 1 - r;
+        int ddF_x = 1;
+        int ddF_y = -2 * r;
+        int x = 0;
+        int y = r;
+
+        setVoxel(xr, yr+r, zr);
+        setVoxel(xr, yr-r, zr);
+        setVoxel(xr+r, yr, zr);
+        setVoxel(xr-r, yr, zr);
+        while (x<y) {
+            if (f >= 0) {
+                y--;
+                ddF_y += 2;
+                f += ddF_y;
+            }
+            x++;
+            ddF_x += 2;
+            f += ddF_x;
+
+            setVoxel(xr + x, yr + y, zr);
+            setVoxel(xr - x, yr + y, zr);
+            setVoxel(xr + x, yr - y, zr);
+            setVoxel(xr - x, yr - y, zr);
+            setVoxel(xr + y, yr + x, zr);
+            setVoxel(xr - y, yr + x, zr);
+            setVoxel(xr + y, yr - x, zr);
+            setVoxel(xr - y, yr - x, zr);
+        }
+    }
+}
+
+void LED_CUBE::CopyBlock(int x1, int y1, int z1, int x2, int y2, int z2, int xc, int yc, int zc)
+{
+    int ix;
+    int iz;
+    int nx;
+    int nz=0;
+    unsigned char tmp_data[64];
+
+    argorder(x1, x2, &x1, &x2);
+    argorder(y1, y2, &y1, &y2);
+    argorder(z1, z2, &z1, &z2);
+
+    for (iz=z1; iz<=z2; iz++) {
+        nx=0;
+        for (ix=x1; ix<=x2; ix++) {
+            //copy block data into tmp array and mask.
+            tmp_data[iz*8 + ix] = cubeData[iz*8 + ix] & byteline(y1,y2);
+            //shift the tmp data to the new y location
+            if (yc >= y1) {
+                tmp_data[iz*8 + ix] = tmp_data[iz*8 + ix] << (yc-y1);
+            } else {
+                tmp_data[iz*8 + ix] = tmp_data[iz*8 + ix] >> (y1-yc);
+            }
+            //alter the cubedata on the new x and z location with the tmp data. use old y location and copy to the new location
+            cubeData[(zc+nz)*8 + xc+nx] = (cubeData[(zc+nz)*8 + xc+nx] & (~byteline(yc,yc+y2-y1))) | tmp_data[iz*8 + ix];
+            nx++;
+        }
+        nz++;
+    }
+}
+
+void LED_CUBE::MoveBlock(int x1, int y1, int z1, int x2, int y2, int z2, int xm, int ym, int zm)
+{
+    int ix;
+    int iz;
+    int nx;
+    int nz=0;
+    unsigned char tmp_data[64];
+
+    argorder(x1, x2, &x1, &x2);
+    argorder(y1, y2, &y1, &y2);
+    argorder(z1, z2, &z1, &z2);
+
+    for (iz=z1; iz<=z2; iz++) {
+        for (ix=x1; ix<=x2; ix++) {
+            //copy block data into tmp array and mask.
+            tmp_data[iz*8 + ix] = cubeData[iz*8 + ix] & byteline(y1,y2);
+            //clear the original voxels
+            cubeData[iz*8 + ix] &= ~byteline(y1,y2);
+            //shift the tmp data to the new y location
+            if (ym >= y1) {
+                tmp_data[iz*8 + ix] = tmp_data[iz*8 + ix] << (ym-y1);
+            } else {
+                tmp_data[iz*8 + ix] = tmp_data[iz*8 + ix] >> (y1-ym);
+            }
+        }
+    }
+
+    for (iz=z1; iz<=z2; iz++) {
+        nx=0;
+        for (ix=x1; ix<=x2; ix++) {
+
+            //alter the cubedata on the new x and z location with the tmp data. use old y location and copy to the new location
+            cubeData[(zm+nz)*8 + xm+nx] = (cubeData[(zm+nz)*8 + xm+nx] & (~byteline(ym,ym+y2-y1))) | tmp_data[iz*8 + ix];
+            nx++;
+        }
+        nz++;
+    }
+}
+
+char LED_CUBE::byteline (int start, int end)
+{
+    char line=0;
+    int bitnr;
+
+    for (bitnr=0; bitnr<8; bitnr++) {
+        if (bitnr>=start && bitnr<=end) {
+            line |= (1<<bitnr);
+        }
+    }
+    return line;
+}
+
+// This function validates that we are drawing inside the cube.
+unsigned char LED_CUBE::inrange(int x, int y, int z)
+{
+    if (x >= 0 && x < 8 && y >= 0 && y < 8 && z >= 0 && z < 8) {
+        return 0x01;
+    } else {
+        // One of the coordinates was outside the cube.
+        return 0x00;
+    }
+}
+
+void LED_CUBE::argorder(int ix1, int ix2, int *ox1, int *ox2)
+{
+    if (ix1>ix2) {
+        int tmp;
+        tmp = ix1;
+        ix1= ix2;
+        ix2 = tmp;
+    }
+    *ox1 = ix1;
+    *ox2 = ix2;
+}
+
+double LED_CUBE::map(double in, double inMin, double inMax, double outMin, double outMax)
+{
+    double out;
+    out = (in-inMin)/(inMax-inMin)*(outMax-outMin) + outMin;
+    return out;
 }
\ No newline at end of file
diff -r 920c5ed65a45 -r e08a4d27f534 led_cube.h
--- a/led_cube.h	Sat Sep 08 22:14:10 2012 +0000
+++ b/led_cube.h	Thu Nov 01 22:31:54 2012 +0000
@@ -1,46 +1,66 @@
-#ifndef __LED_CUBE_H
-#define __LED_CUBE_H
-
-#define VERSION 1.0
-
-#include <mbed.h>
-#include "pcf8574.h"
-#include "pcf8575.h"
-
-#define PI 3.14159
-#define Xd 8
-#define Yd 8
-#define Zd 8
-#define centre 3.5
-#define Vd Xd*Yd*Zd
-
-#define SB(x,n) (x|=(1<<n))
-#define CB(x,n) (x&=~(1<<n))
-#define TB(x,n) (x^=(1<<n))
-#define PB(x,n) do{SB(x,n);CB(x,n);}while(0)
-
-class LED_CUBE
-{
-public:
-    LED_CUBE(I2C* _interface);
-    ~LED_CUBE(void);
-
-    void clear_cube(void);
-    void setVoxel(unsigned char x, unsigned char y, unsigned char z);
-    void clearVoxel(unsigned char x, unsigned char y, unsigned char z);
-    unsigned char getVoxel(unsigned char x, unsigned char y, unsigned char z);
-    void copyColumn(unsigned char x, unsigned char y, unsigned char col);
-    void clearVoxels(void);
-
-private:
-    PCF8574 row;
-    PCF8575 colums_0_1;
-    PCF8575 colums_2_3;
-    PCF8575 colums_4_5;
-    PCF8575 colums_6_7;
-    unsigned char cubeData[64];
-    Ticker duty;
-    void UpdateRow(void);
-
-};
+#ifndef __LED_CUBE_H
+#define __LED_CUBE_H
+
+#define VERSION 1.0
+
+#include <mbed.h>
+#include "pcf8574.h"
+#include "pcf8575.h"
+
+#define AXIS_X 1
+#define AXIS_Y 2
+#define AXIS_Z 3
+#define PI 3.14159265
+#define center 3.5
+#define round(x)     ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
+
+class LED_CUBE
+{
+public:
+    LED_CUBE(I2C* _interface);
+    ~LED_CUBE(void);
+
+    void clear_cube(void);
+    void setVoxel(unsigned char x, unsigned char y, unsigned char z);
+    void clearVoxel(unsigned char x, unsigned char y, unsigned char z);
+    unsigned char getVoxel(unsigned char x, unsigned char y, unsigned char z);
+    void copyColumn(unsigned char x, unsigned char y, unsigned char col);
+    void alterVoxel(unsigned char x, unsigned char y, unsigned char z, unsigned char state);
+    void flipVoxel(unsigned char x, unsigned char y, unsigned char z);
+    void setPlane_x (int x);
+    void clearPlane_x (int x);
+    void setPlane_y (int y);
+    void clearPlane_y (int y);
+    void setPlane_z (int z);
+    void clearPlane_z (int z);
+    void setPlane (char axis, unsigned char i);
+    void clearPlane (char axis, unsigned char i);
+    void setSlope_XY(int x1, int y1, int x2, int y2);
+    void setSlope_XZ(int x1, int z1, int x2, int z2);
+    void setSlope_YZ(int y1, int z1, int y2, int z2);
+    void clearVoxels(void);
+    void fill (unsigned char pattern);
+    void box_filled(int x1, int y1, int z1, int x2, int y2, int z2);
+    void box_walls(int x1, int y1, int z1, int x2, int y2, int z2);
+    void box_wireframe(int x1, int y1, int z1, int x2, int y2, int z2);
+    void line(int x1, int y1, int z1, int x2, int y2, int z2);
+    void circle(int xr, int yr, int zr, int d ,char axis);
+    void CopyBlock(int x1, int y1, int z1, int x2, int y2, int z2, int xc, int yc, int zc);
+    void MoveBlock(int x1, int y1, int z1, int x2, int y2, int z2, int xm, int ym, int zm);
+    void RotateBlock(int x1, int y1, int height, char axis, char dir);
+
+private:
+    PCF8574 row;
+    PCF8575 colums_0_1;
+    PCF8575 colums_2_3;
+    PCF8575 colums_4_5;
+    PCF8575 colums_6_7;
+    unsigned char cubeData[64];
+    Ticker duty;
+    void UpdateRow(void);
+    char byteline (int start, int end);
+    unsigned char inrange(int x, int y, int z);
+    void argorder(int ix1, int ix2, int *ox1, int *ox2);
+    double map(double in, double inMin, double inMax, double outMin, double outMax);
+    };
 #endif
\ No newline at end of file