1. Joseph Chiocchi
  2. yrainbowduino

Commits

Joseph Chiocchi  committed 1331697

working code sort of

  • Participants
  • Branches default

Comments (0)

Files changed (12)

File Rainbow_V2_71/Rainbow.h

View file
+#ifndef Rainbow_h
+#define Rainbow_h
+
+//Address of the device. Note: this must be changed and compiled for all unique Rainbowduinos
+#define I2C_DEVICE_ADDRESS 0x05
+
+//=============================================
+//PORTC maps to Arduino analog pins 0 to 5. Pins 6 & 7 are only accessible on the Arduino Mini
+//PORTC - The Port C Data Register - read/write
+
+//pin 23 of the arduino maps to first MBI5169 (blue) SDI input
+#define SH_BIT_SDI   0x01
+
+//pin 24 of the arduino maps to the MBI5169 CLN input
+#define SH_BIT_CLK   0x02
+
+//pin 25 of the arduino maps to the MBI5169 LE input
+#define SH_BIT_LE    0x04
+
+//pin 26 of the arduino maps to the MBI5169 OE input
+#define SH_BIT_OE    0x08
+
+//============================================
+
+//some handy hints, ripped form the arduino forum
+//Setting a bit: byte |= 1 << bit;
+//Clearing a bit: byte &= ~(1 << bit);
+//Toggling a bit: byte ^= 1 << bit;
+//Checking if a bit is set: if (byte & (1 << bit))
+//Checking if a bit is cleared: if (~byte & (1 << bit)) OR if (!(byte & (1 << bit)))
+
+//potential take too long! -> PORTC &=~0x02; PORTC|=0x02
+//Clock input terminal for data shift on rising edge
+#define CLK_RISING  {PORTC &=~ SH_BIT_CLK; PORTC |= SH_BIT_CLK;}
+
+//Data strobe input terminal, Serial data is transfered to the respective latch when LE is high. 
+//The data is latched when LE goes low.
+#define LE_HIGH     {PORTC |= SH_BIT_LE;}
+#define LE_LOW      {PORTC &=~ SH_BIT_LE;}
+
+//Output Enabled, when (active) low, the output drivers are enabled; 
+//when high, all output drivers are turned OFF (blanked).
+#define ENABLE_OE   {PORTC &=~ SH_BIT_OE;}
+#define DISABLE_OE  {PORTC |= SH_BIT_OE;}
+
+#define SHIFT_DATA_1     {PORTC |= SH_BIT_SDI;}
+//potential take too long! -> PORTC&=~0x01
+#define SHIFT_DATA_0     {PORTC &=~ SH_BIT_SDI;}
+
+
+#define open_line0      {PORTB=0x04;}
+#define open_line1      {PORTB=0x02;}
+#define open_line2      {PORTB=0x01;}
+#define open_line3      {PORTD=0x80;}
+#define open_line4      {PORTD=0x40;}
+#define open_line5      {PORTD=0x20;}
+#define open_line6      {PORTD=0x10;}
+#define open_line7      {PORTD=0x08;}
+#define CLOSE_ALL_LINE  {PORTD&=~0xf8; PORTB&=~0x07;}
+
+#endif
+

File Rainbow_V2_71/Rainbow_V2_71.ino

View file
+/*
+ * rainbowduino firmware, Copyright (C) 2010-2011 michael vogt <michu@neophob.com>
+ *  
+ * based on 
+ * -blinkm firmware by thingM
+ * -"daft punk" firmware by Scott C / ThreeFN 
+ * -rngtng firmware by Tobias Bielohlawek -> http://www.rngtng.com
+ *  
+ * needed libraries:
+ * -FlexiTimer (http://github.com/wimleers/flexitimer2)
+ *  
+ * libraries to patch:
+ * Wire: 
+ *  	utility/twi.h: #define TWI_FREQ 400000L (was 100000L)
+ *                     #define TWI_BUFFER_LENGTH 98 (was 32)
+ *  	wire.h: #define BUFFER_LENGTH 98 (was 32)
+ *
+ *
+ * This file is part of neorainbowduino.
+ *
+ * neorainbowduino is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * neorainbowduino is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 	
+ */
+
+#include <Wire.h>
+#include <FlexiTimer2.h>
+
+#include "Rainbow.h"
+
+/*
+A variable should be declared volatile whenever its value can be changed by something beyond the control 
+ of the code section in which it appears, such as a concurrently executing thread. In the Arduino, the 
+ only place that this is likely to occur is in sections of code associated with interrupts, called an 
+ interrupt service routine.
+ */
+
+extern unsigned char buffer[2][96];  //two buffers (backbuffer and frontbuffer)
+
+//interrupt variables
+byte g_line,g_level;
+
+//read from bufCurr, write to !bufCurr
+//volatile   //the display is flickerling, brightness is reduced
+byte g_bufCurr;
+
+//flag to blit image
+volatile byte g_swapNow;
+byte g_circle;
+
+//data marker
+#define START_OF_DATA 0x10
+#define END_OF_DATA 0x20
+
+//FPS
+#define FPS 80.0f
+
+#define BRIGHTNESS_LEVELS 16
+#define LED_LINES 8
+#define CIRCLE BRIGHTNESS_LEVELS*LED_LINES
+
+void setup() {
+  DDRD=0xff;        // Configure ports (see http://www.arduino.cc/en/Reference/PortManipulation): digital pins 0-7 as OUTPUT
+  DDRC=0xff;        // analog pins 0-5 as OUTPUT
+  DDRB=0xff;        // digital pins 8-13 as OUTPUT
+  PORTD=0;          // Configure ports data register (see link above): digital pins 0-7 as READ
+  PORTB=0;          // digital pins 8-13 as READ
+
+  g_level = 0;
+  g_line = 0;
+  g_bufCurr = 0;
+  g_swapNow = 0; 
+  g_circle = 0;
+
+  Wire.begin(I2C_DEVICE_ADDRESS); // join i2c bus as slave
+  Wire.onReceive(receiveEvent);   // define the receive function for receiving data from master
+  // Keep in mind:
+  // While an interrupt routine is running, all other interrupts are blocked. As a result, timers will not work 
+  // in interrupt routines and other functionality may not work as expected
+  // -> if i2c data is receieved our led update timer WILL NOT WORK for a short time, the result
+  // are display errors!
+
+  //redraw screen 80 times/s
+  FlexiTimer2::set(1, 1.0f/(128.f*FPS), displayNextLine);
+  FlexiTimer2::start();                            //start interrupt code
+}
+
+//the mainloop - try to fetch data from the i2c bus and copy it into our buffer
+void loop() {
+  if (Wire.available()>97) { 
+    
+    byte b = Wire.read();
+    if (b != START_OF_DATA) {
+      //handle error, read remaining data until end of data marker (if available)
+      while (Wire.available()>0 && Wire.read()!=END_OF_DATA) {}      
+      return;
+    }
+
+    byte backbuffer = !g_bufCurr;
+    b=0;
+    //read image data (payload) - an image size is exactly 96 bytes
+    while (b<96) { 
+      buffer[backbuffer][b++] = Wire.read();  //recieve whatever is available
+    }
+
+    //read end of data marker
+    if (Wire.read()==END_OF_DATA) {
+        //set the 'we need to blit' flag
+  	g_swapNow = 1;
+    } 
+  }
+}
+
+
+
+//=============HANDLERS======================================
+
+//get data from master - HINT: this is a ISR call!
+//HINT2: do not handle stuff here!! this will NOT work
+//collect only data here and process it in the main loop!
+void receiveEvent(int numBytes) {
+  //do nothing here
+}
+
+
+//============INTERRUPTS======================================
+
+// shift out led colors and swap buffer if needed (back buffer and front buffer) 
+// function: draw whole image for brightness 0, then for brightness 1... this will 
+//           create the brightness effect. 
+//           so this interrupt needs to be called 128 times to draw all pixels (8 lines * 16 brightness levels) 
+//           using a 10khz resolution means, we get 10000/128 = 78.125 frames/s
+// TODO: try to implement an interlaced update at the same rate. 
+void displayNextLine() { 
+  draw_next_line();									// scan the next line in LED matrix level by level. 
+  g_line+=2;	 								        // process all 8 lines of the led matrix 
+  if(g_line==LED_LINES) {
+    g_line=1;
+  }
+  if(g_line>LED_LINES) {								// when have scaned all LED's, back to line 0 and add the level 
+    g_line=0; 
+    g_level++;										// g_level controls the brightness of a pixel. 
+    if (g_level>=BRIGHTNESS_LEVELS) {							// there are 16 levels of brightness (4bit) * 3 colors = 12bit resolution
+      g_level=0; 
+    } 
+  }
+  g_circle++;
+  
+  if (g_circle==CIRCLE) {							// check end of circle - swap only if we're finished drawing a full frame!
+
+    if (g_swapNow==1) {
+      g_swapNow = 0;
+      g_bufCurr = !g_bufCurr;
+    }
+    g_circle = 0;
+  }
+}
+
+
+// scan one line, open the scaning row
+void draw_next_line() {
+  DISABLE_OE						//disable MBI5168 output (matrix output blanked)
+  //enable_row();				                //setup super source driver (trigger the VCC power lane)
+  CLOSE_ALL_LINE					//super source driver, select all outputs off
+  open_line(g_line);
+
+  LE_HIGH							//enable serial input for the MBI5168
+  shift_24_bit();	// feed the leds
+  LE_LOW							//disable serial input for the MBI5168, latch the data
+  
+  ENABLE_OE							//enable MBI5168 output
+}
+
+//open correct output pins, used to setup the "super source driver"
+//PB0 - VCC3, PB1 - VCC2, PB2 - VCC1
+//PD3 - VCC8, PD4 - VCC7, PD5 - VCC6, PD6 - VCC5, PD7 - VCC4
+void enable_row() {
+  if (g_line < 3) {    // Open the line and close others
+    PORTB = (PINB & 0xF8) | 0x04 >> g_line;
+    PORTD =  PIND & 0x07;
+  } else {
+    PORTB =  PINB & 0xF8;
+    PORTD = (PIND & 0x07) | 0x80 >> (g_line - 3);
+  }
+}
+
+// display one line by the color level in buffer
+void shift_24_bit() { 
+  byte color,row,data0,data1,ofs; 
+
+  for (color=0;color<3;color++) {	           	//Color format GRB
+    ofs = color*32+g_line*4;				//calculate offset, each color need 32bytes
+    			
+    for (row=0;row<4;row++) {    
+      
+      data1=buffer[g_bufCurr][ofs]&0x0f;                //get pixel from buffer, one byte = two pixels
+      data0=buffer[g_bufCurr][ofs]>>4;
+      ofs++;
+
+      if(data0>g_level) { 	//is current pixel visible for current level (=brightness)
+        SHIFT_DATA_1		//send high to the MBI5168 serial input (SDI)
+      } 
+      else {
+        SHIFT_DATA_0		//send low to the MBI5168 serial input (SDI)       
+      }
+      CLK_RISING		//send notice to the MBI5168 that serial data should be processed 
+
+      if(data1>g_level) {
+        SHIFT_DATA_1		//send high to the MBI5168 serial input (SDI)
+      } 
+      else {
+        SHIFT_DATA_0		//send low to the MBI5168 serial input (SDI)
+      }
+      CLK_RISING		//send notice to the MBI5168 that serial data should be processed
+    }     
+  }
+}
+
+void open_line(unsigned char line) {    // open the scaning line 
+  switch(line) {
+  case 0: {
+      open_line0
+      break;
+    }
+  case 1: {
+      open_line1
+      break;
+    }
+  case 2: {
+      open_line2
+      break;
+    }
+  case 3: {
+      open_line3
+      break;
+    }
+  case 4: {
+      open_line4
+      break;
+    }
+  case 5: {
+      open_line5
+      break;
+    }
+  case 6: {
+      open_line6
+      break;
+    }
+  case 7: {
+      open_line7
+      break;
+    }
+  }
+}

File Rainbow_V2_71/data.c

View file
+
+//initial image, mark top left pixel
+unsigned char buffer[2][96] = {
+{  
+//green
+66, 17, 18, 52, 51, 32, 2, 52,
+51, 0, 0, 51, 64, 48, 3, 2,
+80, 0, 0, 3, 101, 2, 32, 68,
+96, 50, 35, 6, 67, 2, 32, 88,
+//red
+102, 103, 100, 50, 85, 96, 5, 50,
+69, 0, 0, 67, 48, 80, 6, 2,
+48, 0, 0, 1, 34, 3, 32, 16,
+16, 17, 17, 0, 0, 0, 0, 0,
+//blue
+1, 18, 34, 34, 1, 16, 3, 34,
+0, 0, 0, 50, 0, 16, 3, 3,
+16, 0, 0, 5, 34, 3, 64, 88,
+32, 52, 68, 11, 34, 3, 64, 124
+}, {
+//green
+66, 17, 18, 52, 51, 32, 2, 52,
+51, 0, 0, 51, 64, 48, 3, 2,
+80, 0, 0, 3, 101, 2, 32, 68,
+96, 50, 35, 6, 67, 2, 32, 88,
+//red
+102, 103, 100, 50, 85, 96, 5, 50,
+69, 0, 0, 67, 48, 80, 6, 2,
+48, 0, 0, 1, 34, 3, 32, 16,
+16, 17, 17, 0, 0, 0, 0, 0,
+//blue
+1, 18, 34, 34, 1, 16, 3, 34,
+0, 0, 0, 50, 0, 16, 3, 3,
+16, 0, 0, 5, 34, 3, 64, 88,
+32, 52, 68, 11, 34, 3, 64, 124
+}};

File YolkBox_Rainbowduino_Firmware_v3_0h/Rainbow.h

View file
+#ifndef Rainbow_h
+#define Rainbow_h
+
+#define I2C_DEVICE_ADDRESS 0x10
+
+#define FRONT_BUFFER       bufFront
+#define BACK_BUFFER        bufBack
+
+#define MAX_AUX_BUFFERS    4
+#define MAX_GAMMA_SETS     3
+#define MAX_WIRE_CMD_LEN   20
+
+#define BLACK              0x0, 0x0, 0x0
+#define WHITE              0xF, 0xF, 0xF
+#define BLUE               0x0, 0x0, 0xF
+#define GREEN              0x0, 0xF, 0x0
+#define RED                0xF, 0x0, 0x0
+
+#define G                  0
+#define R                  1
+#define B                  2
+
+//=============================================
+//MBI5168
+#define SH_DIR_OE          DDRC
+#define SH_DIR_SDI         DDRC
+#define SH_DIR_CLK         DDRC
+#define SH_DIR_LE          DDRC
+
+#define SH_BIT_OE          0x08
+#define SH_BIT_SDI         0x01
+#define SH_BIT_CLK         0x02
+#define SH_BIT_LE          0x04
+
+#define SH_PORT_OE         PORTC
+#define SH_PORT_SDI        PORTC
+#define SH_PORT_CLK        PORTC
+#define SH_PORT_LE         PORTC
+//============================================
+#define clk_rising         {SH_PORT_CLK&=~SH_BIT_CLK;SH_PORT_CLK|=SH_BIT_CLK;}
+#define le_high            {SH_PORT_LE|=SH_BIT_LE;}
+#define le_low             {SH_PORT_LE&=~SH_BIT_LE;}
+#define enable_oe          {SH_PORT_OE&=~SH_BIT_OE;}
+#define disable_oe         {SH_PORT_OE|=SH_BIT_OE;}
+
+#define shift_data_1       {SH_PORT_SDI|=SH_BIT_SDI;}
+#define shift_data_0       {SH_PORT_SDI&=~SH_BIT_SDI;}
+
+//============================================
+#define close_all_line	   {PORTD&=~0xf8;PORTB&=~0x07;}
+
+//============================================
+#define CheckRequest       (g8Flag1&0x01)
+#define SetRequest         (g8Flag1|=0x01)
+#define ClrRequest         (g8Flag1&=~0x01)
+
+//==============================================
+#define waitingcmd         0x00
+#define processing         0x01
+#define checking           0x02
+
+#endif

File YolkBox_Rainbowduino_Firmware_v3_0h/WireCommands.h

View file
+/*
+
+  -0- -1- -2- -3- -.- -L-
+
+  'r' CMD [o] [o] ... 0x0     byte0: 'r' identify a Rainbowduino Firmware 3.0 command string
+                              byte1: CMD Hex code of the command
+                              byte2 to ...: [o] Optional parameters for the command CMD (as many byte up to MAX_WIRE_CMD_LEN)
+                              last byte:  0x0 the command string terminator
+                              
+  -CMD- -1- -2- -3-
+  
+  0x00                        RESET
+  
+> 0x10                        swapBuffers();
+> 0x11   X   Y                copyFrontBuffer(X, Y);
+> 0x12   N                    showAuxBuffer(N);
+  0x13   B   N                storeToAuxBuffer(B, N);
+  0x14   N                    getFromAuxBuffer(N);
+  0x19   G                    setGamma(G);    
+
+> 0x20   R   G   B            clearBuffer(R, G, B);
+> 0x21   R   G   B            setPaperColor(R, G, B);
+> 0x22   R   G   B            setInkColor(R, G, B);
+> 0x25                        clearPaper();
+> 0x26   X   Y                drawPixel(X, Y);
+> 0x27   SX  SY  EX  EY       drawLine(SX, SY, EX, EY);
+> 0x28   SX  SY  EX  EY       drawSquare(SX, SY, EX, EY);
+  0x29   OX  OY  RAD          drawCircle(OX, OY, RAD);
+> 0x2A   X   Y   C            printChar(X, Y, C);
+> 0x2B   RW  OFX M            drawRowMask(RW, OFX, M);
+  
+  0x40                        scrollLeft();
+  0x41                        scrollRight();
+  0x42                        scrollUp();
+  0x43                        scrollDown();
+  0x45   L                    insLineLeft(L);
+  0x46   L                    insLineRight(L);
+  0x47   L                    insLineUp(L);
+  0x48   L                    insLineDown(L);
+  
+  0x50                        clearStringBuffer();
+  0x51   C                    charToStringBuffer(C);    (includes termination with /0)
+  0x52   C   C   [...]   /0   wordToStringBuffer(W);    (W = C + C + C + ... + /0)
+  0x55   D                    scrollStringBuffer(D);
+  
+  0x60                        clearColorBuffer();
+  0x61   PR PG PB  IR IG IB   addToColorBuffer(PR, PG, PB, IR, IG, IB);
+  0x62   S                    setColorBufferIterationStep(S);
+  
+*/
+
+#ifndef WireCommands_h
+#define WireCommands_h
+
+#define CMD_NOP               0x00
+
+#define CMD_SWAP_BUF          0x10
+#define CMD_COPY_FRONT_BUF    0x11
+#define CMD_SHOW_AUX_BUF      0x12
+
+#define CMD_CLEAR_BUF         0x20
+#define CMD_SET_PAPER         0x21
+#define CMD_SET_INK           0x22
+#define CMD_CLEAR_PAPER       0x25
+#define CMD_DRAW_PIXEL        0x26
+#define CMD_DRAW_LINE         0x27
+#define CMD_DRAW_SQUARE       0x28
+#define CMD_PRINT_CHAR        0x2A
+#define CMD_DRAW_ROW_MASK     0x2B
+
+#endif

File YolkBox_Rainbowduino_Firmware_v3_0h/YolkBox_Rainbowduino_Firmware_v3_0h.ino

View file
+#include <Wire.h>
+#include <avr/pgmspace.h>
+
+#include "Rainbow.h"
+#include "WireCommands.h"
+
+extern unsigned char dots_color[6][3][8][4];    // define Two Buffs (one for Display ,the other for receive data)
+extern unsigned char GammaTab[3][16];           // define the Gamma value for correct the different LED matrix
+extern unsigned char ASCII_Char[62][8];         // ASCII character table (READ-ONLY, it's stored in PROGMEM space)
+
+unsigned char line, level;                      // used by the low-level rendering function
+unsigned char g8Flag1;                          // NO IDEA AT THE MOMENT (derived from original code)
+
+byte dispGamma;                                 // current gamma-ramp in use (index of GammaTab array)
+byte bufFront, bufBack, bufCurr;                // used for handling the buffers
+
+unsigned char RainbowCMD[MAX_WIRE_CMD_LEN];     // used to store command received via I2C protocol
+byte paperR, paperG, paperB;                    // stores paper (background) color; used by I2C command chains
+byte inkR, inkG, inkB;                          // stores ink (foreground) color; used by I2C command chains
+
+unsigned char State=0;                          // comes from original code
+
+void setup(void) {
+  _init();                // Initialize Ports, Timer and Interrupts
+}
+
+void loop(void) {
+  switch(State) {
+    case waitingcmd:
+    break;
+    
+    case processing:
+      processWireCommand();
+      State=checking;
+    break;
+    
+    case checking:
+      if(CheckRequest) {
+        State=waitingcmd;
+        ClrRequest;
+      }
+      break;
+      
+    default:
+      State=waitingcmd;
+      break;
+  }
+}
+ 
+/*----------------------------------------------------------------------------*/
+/* DRAWING FUNCTIONS                                                          */
+/*----------------------------------------------------------------------------*/
+
+void _initGfx() { // Init the graphic side
+  dispGamma = 1;
+  bufFront = 0;
+  bufBack = 1;
+  bufCurr = 0;    
+}
+
+void setGamma(byte gamma) { // Change the gamma array pointer, used during display rendering
+  if ( gamma < MAX_GAMMA_SETS ) {
+    dispGamma = gamma;
+  }
+}
+
+void drawPixel(int x, int y, byte r, byte g, byte b) {
+  if ( (x>=0 && x<8) && (y>=0 && y<8) ) { // Check if it's in the display range
+    byte mask = 0xF0;
+    if ( !(x % 2) ) { // If x is unpair, shift each color component four bit left
+      r = (r << 4);
+      g = (g << 4);
+      b = (b << 4);
+      mask = 0x0F;
+    }
+  
+    x /= 2;
+    replace_dot(bufBack, x, y, bufBack, x, y, r, g, b, mask);
+  }
+}  
+
+void drawLine(int sx, int sy, int ex, int ey, byte r, byte g, byte b) {
+  int i, lx, ly;
+  
+  lx = abs(ex-sx);
+  ly = abs(ey-sy);
+  
+  if ( lx > ly) {
+    for(i=0; i<=lx; i++) {
+      drawPixel(map(i, 0, lx, sx, ex), map(i, 0, lx, sy, ey), r, g, b);
+    }
+  } else {
+    for(i=0; i<=ly; i++) {
+      drawPixel(map(i, 0, ly, sx, ex), map(i, 0, ly, sy, ey), r, g, b);
+    }
+  }
+}
+
+void drawSquare(int sx, int sy, int ex, int ey, byte r, byte g, byte b) {
+  int i, ly, rw;
+  
+  ly = abs(ey-sy);
+  
+  for(i=0; i<=ly; i++) {
+    rw = map(i, 0, ly, sy, ey);
+    drawLine(sx, rw, ex, rw, r, g, b);
+  }
+}
+
+void printChar(int x, int y, byte r, byte g, byte b, unsigned char ASCII) { // Print a char using array ASCII_Char as font source
+  unsigned char idx;
+  byte bitmask;
+  int row, col;
+  int l;
+
+  if((ASCII > 64) && (ASCII < 91)) idx=ASCII-55; // Convert from ASCII to index of character's array
+  else if((ASCII > 96) && (ASCII < 123)) idx=ASCII-61;
+  else if((ASCII >= '0') && (ASCII <= '9')) idx=ASCII-48;
+  
+  l = 0;  // Counter used to extract each line from the character map
+  for (row=(7+y); row>=y; row--) {    
+    if ( row < 8 && row >= 0 ) { // Check if row is within visible area
+      bitmask = pgm_read_byte(&(ASCII_Char[idx][l]));  // Extract the bitmask for each line of the character
+      drawRowMask(row, x, r, g, b, bitmask);
+     }
+    l++;
+  }
+}
+
+void drawRowMask(int row, int off, byte r, byte g, byte b, byte bitmask) {
+  byte col;
+  
+  if ( (abs(off) < 8) && (row < 8) && (row >= 0) ) {
+    if ( off > 0 ) bitmask = (bitmask << off);  // Shift the bitmask according to x-offset
+    else bitmask = (bitmask >> -off);
+  
+    for (col=0; col<4; col++) {     // Check the first bit of the bitmask
+      if ( bitmask & B00000001 ) {
+        replace_dot(bufBack, col, row, bufBack, col, row, (r << 4), (g << 4), (b << 4), 0x0F);
+      }
+      if ( bitmask & B00000010 ) {  // Check the second bit of the bitmask
+        replace_dot(bufBack, col, row, bufBack, col, row, r, g, b, 0xF0);
+      }
+      bitmask = (bitmask >> 2);     // Shift the bitmask two bits left
+    }
+  }
+}
+
+/* BUFFERS HANDLING */
+
+void swapBuffers() { // Swap Front with Back buffer
+  if ( bufFront > 1 ) { // If we're showing an Aux Buffer
+    bufFront = bufBack;
+    bufBack = !bufBack;
+  } else {
+    bufFront = !bufFront;
+    bufBack = !bufBack;
+  }
+  while(bufCurr != bufFront) {    // Wait for display to change.
+    delayMicroseconds(10);
+  }
+}
+
+void showAuxBuffer(byte n) { // Show an Auxiliary buffer
+  if (n < MAX_AUX_BUFFERS) {
+    bufFront = n+2;
+   while(bufCurr != bufFront) {  // Wait for display to change.
+      delayMicroseconds(10);
+    }
+  }
+}
+
+void storeToAuxBuffer(byte buf, byte n) { // Store the buffer to Aux Buffer #
+  byte x, y;
+  if (n < MAX_AUX_BUFFERS) {
+    n+=2;
+    for (y=0; y<8; y++) {
+      for (x=0; x<4; x++) {
+        dots_color[n][R][y][x]=dots_color[buf][R][y][x];
+        dots_color[n][G][y][x]=dots_color[buf][G][y][x];
+        dots_color[n][B][y][x]=dots_color[buf][B][y][x];
+      }
+    }
+  }
+}
+
+void getFromAuxBuffer(byte n) { // Retrieve Aux Buffer # to Back (not visibile) buffer;
+  byte x, y;
+  
+  if (n < MAX_AUX_BUFFERS) {
+    n+=2;
+    for (y=0; y<8; y++) {
+      for (x=0; x<4; x++) {
+        dots_color[bufBack][R][y][x]=dots_color[n][R][y][x];
+        dots_color[bufBack][G][y][x]=dots_color[n][G][y][x];
+        dots_color[bufBack][B][y][x]=dots_color[n][B][y][x];
+      }
+    }
+  }
+}
+
+void clearBuffer(byte r, byte g, byte b) {  // Clear the Back buffer and fill with selected color
+  byte x, y;
+  r = r | (r << 4);
+  g = g | (g << 4);
+  b = b | (b << 4);
+
+  for (y=0; y<8; y++) {
+    for (x=0; x<4; x++) {
+      dots_color[bufBack][G][y][x]=g;
+      dots_color[bufBack][R][y][x]=r;
+      dots_color[bufBack][B][y][x]=b;
+    }
+  }
+}
+
+void copyFrontBuffer(int x, int y) { // Copy the Front buffer to the Back one, offsetting it by x and y
+  int row, col;
+  int offy, offx;
+  byte t0, t1, t2;
+  for (row=0; row<8; row++) {
+    
+    offy = row-y;
+    if ( offy>=0 && offy<8 ) {
+      for (col=0; col<4; col++) {
+        
+        offx = col+(x/2);
+        if ( offx>=0 && offx<4 ) {
+          if ( !(x%2) ) { // if x-offset is pair, we just need to copy the byte by the offset
+            dots_color[bufBack][R][row][col]=dots_color[bufFront][R][offy][offx];
+            dots_color[bufBack][G][row][col]=dots_color[bufFront][G][offy][offx];
+            dots_color[bufBack][B][row][col]=dots_color[bufFront][B][offy][offx];
+          } else { // if x-offset is unpair, we need to shift each byte by four-bit in the offset direction
+            t0 = dots_color[bufFront][R][offy][offx];
+            t1 = dots_color[bufFront][G][offy][offx];
+            t2 = dots_color[bufFront][B][offy][offx];
+            
+            if ( x >= 0 ) { // if x-offset is positive (and unpair) shift four-bit to the right
+              replace_dot(bufBack, col, row, bufBack, col, row, (t0 >> 4), (t1 >> 4), (t2 >> 4), 0xF0);
+              offx = col+1; // NOTE: I reuse offx variable to avoid initializing a new one. This affect only the 2 lines below.
+              if ( offx < 4) // if it's not the right end side column
+                replace_dot(bufBack, offx, row, bufBack, offx, row, (t0 << 4), (t1 << 4), (t2 << 4), 0x0F);
+            } else { // if x-offset is negative (and unpair) shift four-bit to the left
+              replace_dot(bufBack, col, row, bufBack, col, row, (t0 << 4), (t1 << 4), (t2 << 4), 0x0F);
+              offx = col-1; // NOTE: I reuse offx variable to avoid initializing a new one. This affect only the 2 lines below.
+              if ( offx >= 0) // if it's not the left end side column
+                replace_dot(bufBack, offx, row, bufBack, offx, row, (t0 >> 4), (t1 >> 4), (t2 >> 4), 0xF0);
+            }
+            
+          }
+        }
+        
+      }
+    }
+    
+  }
+}
+
+void replace_dot(byte fromBuf, int fromX, int fromY, byte toBuf, int toX, int toY, byte vR, byte vG, byte vB, byte mask) {
+  // Replace a single dot ( 4 byte ) in toBuf buffer with the value from fromBuf buffer
+  dots_color[toBuf][0][toY][toX]=(vG | (dots_color[fromBuf][0][fromY][fromX] & mask));
+  dots_color[toBuf][1][toY][toX]=(vR | (dots_color[fromBuf][1][fromY][fromX] & mask));
+  dots_color[toBuf][2][toY][toX]=(vB | (dots_color[fromBuf][2][fromY][fromX] & mask));
+}
+
+/*----------------------------------------------------------------------------*/
+/* I2C EVENT HANDLING FUNCTIONS                                               */
+/*----------------------------------------------------------------------------*/
+
+void _initWire() {
+  int i;
+  for (i=0; i<MAX_WIRE_CMD_LEN; i++) {
+    RainbowCMD[i] = 0x00;         // Clear Command Buffer
+  }
+  paperR = 0x0; paperG = 0x0; paperB = 0x0;
+  inkR = 0xF; inkG = 0x0; inkB = 0x0;
+
+  Wire.begin(I2C_DEVICE_ADDRESS); // join I2C bus (address optional for master) 
+  Wire.onReceive(receiveEvent);   // define the receive function for receiving data from master
+  Wire.onRequest(requestEvent);   // define the request function for the request from master
+}
+
+#define CMD_ACKNOWLEDGED  {RainbowCMD[1] = CMD_NOP;}
+
+void processWireCommand() {
+  int x, y, ex, ey;
+  byte n;
+  byte r, g, b;
+  switch(RainbowCMD[1]) {
+    case CMD_SWAP_BUF:
+      CMD_ACKNOWLEDGED;
+      swapBuffers();
+      break;
+    case CMD_COPY_FRONT_BUF:
+      CMD_ACKNOWLEDGED;
+      x = toInt(RainbowCMD[2]); y = toInt(RainbowCMD[3]);
+      copyFrontBuffer(x, y);
+      break;
+    case CMD_SHOW_AUX_BUF:
+      CMD_ACKNOWLEDGED;
+      n = RainbowCMD[2];
+      showAuxBuffer(n);
+      break;
+    case CMD_CLEAR_BUF:
+      CMD_ACKNOWLEDGED;
+      r = RainbowCMD[2]; g = RainbowCMD[3]; b = RainbowCMD[4];
+      clearBuffer(r, g, b);
+      break;
+    case CMD_SET_PAPER:
+      CMD_ACKNOWLEDGED;
+      paperR = RainbowCMD[2]; paperG = RainbowCMD[3]; paperB = RainbowCMD[4];
+      break;
+    case CMD_SET_INK:
+      CMD_ACKNOWLEDGED;
+      inkR = RainbowCMD[2]; inkG = RainbowCMD[3]; inkB = RainbowCMD[4];
+      break;
+    case CMD_CLEAR_PAPER:
+      CMD_ACKNOWLEDGED;
+      clearBuffer(paperR, paperG, paperB);
+      break;
+    case CMD_DRAW_PIXEL:
+      CMD_ACKNOWLEDGED;
+      x = toInt(RainbowCMD[2]); y = toInt(RainbowCMD[3]);
+      drawPixel(x, y, inkR, inkG, inkB);
+      break;
+    case CMD_DRAW_LINE:
+      CMD_ACKNOWLEDGED;
+      x = toInt(RainbowCMD[2]); y = toInt(RainbowCMD[3]);
+      ex = toInt(RainbowCMD[4]); ey = toInt(RainbowCMD[5]);
+      drawLine(x, y, ex, ey, inkR, inkG, inkB);
+      break;
+    case CMD_DRAW_SQUARE:
+      CMD_ACKNOWLEDGED;
+      x = toInt(RainbowCMD[2]); y = toInt(RainbowCMD[3]);
+      ex = toInt(RainbowCMD[4]); ey = toInt(RainbowCMD[5]);
+      drawSquare(x, y, ex, ey, inkR, inkG, inkB);
+      break;
+    case CMD_PRINT_CHAR:
+      CMD_ACKNOWLEDGED;
+      x = toInt(RainbowCMD[2]); y = toInt(RainbowCMD[3]);
+      n = RainbowCMD[4];
+      printChar(x, y, inkR, inkG, inkB, n);
+      break;
+    case CMD_DRAW_ROW_MASK:
+      CMD_ACKNOWLEDGED;
+      y = toInt(RainbowCMD[2]); x = toInt(RainbowCMD[3]);
+      n = RainbowCMD[4];
+      drawRowMask(y, x, inkR, inkG, inkB, n);
+      break;
+  }
+}
+
+void requestEvent(void) { // While processing or checking previous directive, request other commands
+  Wire.write(State); 
+  if ((State==processing) || (State==checking)) SetRequest;
+}
+
+// Adapted from the original code (with minor changes)
+void receiveEvent(int howMany) {
+  unsigned char i=0;
+  while(Wire.available()>0) { 
+    RainbowCMD[i]=Wire.read();
+    if ( i < MAX_WIRE_CMD_LEN) i++;
+  }
+
+  if(RainbowCMD[0]=='r') State=processing;
+  else State=waitingcmd;
+
+}
+
+int toInt(byte b) {
+  return map(b, 0, 255, -128, 127);
+}
+
+/*----------------------------------------------------------------------------*/
+/* LED MATRIX DISPLAY HANDLING                                                */
+/*----------------------------------------------------------------------------*/
+
+void flash_next_line(unsigned char ln, unsigned char lvl) {  // Scan one line
+  disable_oe;
+  close_all_line;
+
+  if(ln < 3) {    // Open the line and close others
+    PORTB  = (PINB & ~0x07) | 0x04 >> ln;
+    PORTD  = (PIND & ~0xF8);
+  } else {
+    PORTB  = (PINB & ~0x07);
+    PORTD  = (PIND & ~0xF8) | 0x80 >> (ln - 3);
+  }
+  
+  shift_24_bit(ln, lvl);
+  enable_oe;
+}
+
+void shift_24_bit(unsigned char ln, unsigned char lvl) {   // Display one line by the color level in buff
+  unsigned char color=0,row=0;
+  unsigned char data0=0,data1=0;
+  
+  le_high;
+  for(color=0;color<3;color++) {   // The color order is G-B-R
+    for(row=0;row<4;row++) {
+      data1=dots_color[bufCurr][color][ln][row]&0x0f;
+      data0=dots_color[bufCurr][color][ln][row]>>4;
+
+      if(data0>lvl) {    //gray scale, 0x0f aways light (original comment, not sure what it means)
+        shift_data_1;
+        clk_rising;
+      } else {
+        shift_data_0;
+        clk_rising;
+      }
+      
+      if(data1>lvl) {
+        shift_data_1;
+        clk_rising;
+      } else {
+        shift_data_0;
+        clk_rising;
+      }
+    }
+  }
+  le_low;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* INIT TIMERS AND INTERRUPT FUNCTIONS                                        */
+/*----------------------------------------------------------------------------*/
+
+void _init(void) {  // define the pin mode
+  DDRD=0xff;        // Configure ports (see http://www.arduino.cc/en/Reference/PortManipulation): digital pins 0-7 as OUTPUT
+  DDRC=0xff;        // analog pins 0-5 as OUTPUT
+  DDRB=0xff;        // digital pins 8-13 as OUTPUT
+  PORTD=0;          // Configure ports data register (see link above): digital pins 0-7 as READ
+  PORTB=0;          // digital pins 8-13 as READ
+
+  level = 0;
+  line = 0;
+  
+  _initWire();      // init I2C communication protocol
+  _initGfx();       // init Graphic
+  
+  init_timer2();    // init the timer for flashing the LED matrix
+}
+
+void init_timer2(void) {                  // Initialize Timer2
+  TCCR2A |= (1 << WGM21) | (1 << WGM20);   
+  TCCR2B |= (1<<CS22);                    // by clk/64
+  TCCR2B &= ~((1<<CS21) | (1<<CS20));     // by clk/64
+  TCCR2B &= ~((1<<WGM21) | (1<<WGM20));   // Use normal mode
+  ASSR |= (0<<AS2);                       // Use internal clock - external clock not used in Arduino
+  TIMSK2 |= (1<<TOIE2) | (0<<OCIE2B);     //Timer2 Overflow Interrupt Enable
+  TCNT2 = GammaTab[dispGamma][0];
+  sei();   
+}
+
+ISR(TIMER2_OVF_vect) {  // Timer2 Service 
+  TCNT2 = GammaTab[dispGamma][level];  // Set the flashing time using gamma value table
+  flash_next_line(line,level);         // flash the next line in LED matrix for the current level.
+  line++;
+
+  if(line > 7) {                // After flashing all LED's lines, go back to line 0 and increase the level
+    line = 0;
+    level++;
+    if(level>15) {              // After flashng all levels, go back to level 0 and, eventually, swaps the buffers
+      level = 0;
+      bufCurr = bufFront;       // do the actual swapping, synced with display refresh.
+    }
+  }
+}
+

File YolkBox_Rainbowduino_Firmware_v3_0h/data.c

View file
+#include <avr/pgmspace.h>
+
+// Gamma tables
+unsigned char GammaTab[3][16]= {
+    {0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7},    // Default linear gamma
+    {0xFF,0xFE,0xFD,0xFC,0xFB,0xF9,0xF7,0xF5,0xF3,0xF0,0xED,0xEA,0xE7,0xE4,0xE1,0xDD},    // Progressive gamma
+    {0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7}     // Undefined
+};
+
+// Display dot buffer
+unsigned char dots_color[6][3][8][4] = {
+//== 0 ================================================
+{
+  { {0x00,0x00,0x00,0x4b}, //green 
+    {0x00,0x00,0x04,0xbf},
+    {0x00,0x00,0x4b,0xff},
+    {0x00,0x04,0xbf,0xff},
+    {0x00,0x4b,0xff,0xff},
+    {0x04,0xbf,0xff,0xff},
+    {0x4b,0xff,0xff,0xff},
+    {0xbf,0xff,0xff,0xfd}
+  },
+  { {0xff,0xfd,0x71,0x00}, //red 
+    {0xff,0xd7,0x10,0x00},
+    {0xfd,0xf1,0x00,0x00},
+    {0xda,0x10,0x00,0x00},
+    {0x71,0x00,0x00,0x01},
+    {0x10,0x00,0x00,0x17},
+    {0x00,0x00,0x01,0x7e},
+    {0x00,0x00,0x17,0xef}
+  },
+  { {0x06,0xef,0xff,0xff}, //blue 
+    {0x6e,0xff,0xff,0xff},
+    {0xef,0xff,0xff,0xfa},
+    {0xff,0xff,0xff,0xa3},
+    {0xff,0xff,0xfa,0x30},
+    {0xff,0xfa,0xa3,0x00},
+    {0xff,0xfa,0x30,0x00},
+    {0xff,0xa3,0x00,0x00}
+  }
+},
+//== 1 =================================================
+{
+  { {0x00,0x00,0x00,0x4b}, //green
+    {0x00,0x00,0x04,0xbf},
+    {0x00,0x00,0x4b,0xff},
+    {0x00,0x04,0xbf,0xff},
+    {0x00,0x4b,0xff,0xff},
+    {0x04,0xbf,0xff,0xff},
+    {0x4b,0xff,0xff,0xff},
+    {0xbf,0xff,0xff,0xfd}
+  },
+  { {0xff,0xfd,0x71,0x00}, //red 
+    {0xff,0xd7,0x10,0x00},
+    {0xfd,0xf1,0x00,0x00},
+    {0xda,0x10,0x00,0x00},
+    {0x71,0x00,0x00,0x01},
+    {0x10,0x00,0x00,0x17},
+    {0x00,0x00,0x01,0x7e},
+    {0x00,0x00,0x17,0xef}
+  },
+  { {0x06,0xef,0xff,0xff}, //blue
+    {0x6e,0xff,0xff,0xff},
+    {0xef,0xff,0xff,0xfa},
+    {0xff,0xff,0xff,0xa3},
+    {0xff,0xff,0xfa,0x30},
+    {0xff,0xfa,0xa3,0x00},
+    {0xff,0xfa,0x30,0x00},
+    {0xff,0xa3,0x00,0x00}
+  }
+ },
+//== 2 == AUX0 =========================================
+ {
+  { {0xff,0xbf,0x00,0x00}, //green
+    {0xff,0xbf,0x00,0x00},
+    {0xff,0xbf,0x00,0x00},
+    {0xff,0xbf,0x00,0x00},
+    {0xff,0xbf,0x00,0x00},
+    {0xff,0xbf,0x00,0x00},
+    {0x01,0x23,0x45,0x67},
+    {0x89,0xab,0xcd,0xef}
+  },
+  { {0xff,0x00,0xff,0x00}, //red
+    {0xff,0x00,0xff,0x00},
+    {0xff,0x00,0xff,0x00},
+    {0xff,0x00,0xff,0x00},
+    {0xff,0x00,0xff,0x00},
+    {0xff,0x00,0xff,0x00},
+    {0x01,0x23,0x45,0x67},
+    {0x89,0xab,0xcd,0xef}
+  },
+  { {0xf0,0xf0,0xd0,0xf0}, //blue 
+    {0xf0,0xf0,0xd0,0xf0},
+    {0xf0,0xf0,0xd0,0xf0},
+    {0xf0,0xf0,0xd0,0xf0},
+    {0xf0,0xf0,0xd0,0xf0},
+    {0xf0,0xf0,0xd0,0xf0},
+    {0x01,0x23,0x45,0x67},
+    {0x89,0xab,0xcd,0xef}
+  }
+ },
+//== 3 == AUX1 =========================================
+ {
+  { {0x00,0x00,0x00,0x00}, //green 
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x12,0x34,0x57},
+    {0x89,0xAB,0xCD,0xEF},
+    {0x01,0x23,0x45,0x67},
+    {0x89,0xAB,0xCD,0xEF},
+  },
+  { {0x00,0x00,0x00,0x00}, //red
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x12,0x34,0x57},
+    {0x89,0xAB,0xCD,0xEF},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x01,0x23,0x45,0x67},
+    {0x89,0xAB,0xCD,0xEF},
+  },
+  { {0x00,0x12,0x34,0x57}, //blue
+    {0x89,0xAB,0xCD,0xEF},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x01,0x23,0x45,0x67},
+    {0x89,0xAB,0xCD,0xEF},
+  }
+ },
+//== 4 == AUX2 =========================================
+ {
+  { {0x00,0x00,0x00,0x4b}, //green
+    {0x00,0x00,0x04,0xbf},
+    {0x00,0x00,0x4b,0xff},
+    {0x00,0x04,0xbf,0xff},
+    {0x00,0x4b,0xff,0xff},
+    {0x04,0xbf,0xff,0xff},
+    {0x4b,0xff,0xff,0xff},
+    {0xbf,0xff,0xff,0xfd}
+  },
+  { {0xff,0xfd,0x71,0x00}, //red
+    {0xff,0xd7,0x10,0x00},
+    {0xfd,0xf1,0x00,0x00},
+    {0xda,0x10,0x00,0x00},
+    {0x71,0x00,0x00,0x01},
+    {0x10,0x00,0x00,0x17},
+    {0x00,0x00,0x01,0x7e},
+    {0x00,0x00,0x17,0xef}
+  },
+  { {0x06,0xef,0xff,0xff}, //blue
+    {0x6e,0xff,0xff,0xff},
+    {0xef,0xff,0xff,0xfa},
+    {0xff,0xff,0xff,0xa3},
+    {0xff,0xff,0xfa,0x30},
+    {0xff,0xfa,0xa3,0x00},
+    {0xff,0xfa,0x30,0x00},
+    {0xff,0xa3,0x00,0x00}
+  }
+ },
+//== 5 == AUX3 =========================================
+ {
+  { {0x00,0x00,0x00,0x00}, //green
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00}
+  },
+  { {0x0f,0xff,0xff,0xff}, //red
+    {0x0f,0xff,0xff,0xff},
+    {0x0f,0xff,0xff,0xff},
+    {0x0f,0xff,0xff,0xff},
+    {0x0f,0xff,0xff,0xff},
+    {0x0f,0xff,0xff,0xff},
+    {0x0f,0xff,0xff,0xff},
+    {0x0f,0xff,0xff,0xff}
+  },
+  { {0x00,0x00,0x00,0x00}, //blue
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00},
+    {0x00,0x00,0x00,0x00}
+  }
+ }
+};
+
+// Internal Font (read-only)
+unsigned char ASCII_Char[62][8] PROGMEM = {
+    {0x0,0x38,0x44,0x4C,0x54,0x64,0x44,0x38},   // 0
+    {0x0,0x38,0x10,0x10,0x10,0x10,0x18,0x10},   // 1
+    {0x0,0x7C,0x8,0x10,0x20,0x40,0x44,0x38},    // 2
+    {0x0,0x38,0x44,0x40,0x20,0x10,0x20,0x7C},   // 3
+    {0x0,0x20,0x20,0x7C,0x24,0x28,0x30,0x20},   // 4
+    {0x0,0x38,0x44,0x40,0x40,0x3C,0x4,0x7C},    // 5
+    {0x0,0x38,0x44,0x44,0x3C,0x4,0x8,0x30},     // 6
+    {0x0,0x8,0x8,0x8,0x10,0x20,0x40,0x7C},      // 7
+    {0x0,0x38,0x44,0x44,0x38,0x44,0x44,0x38},   // 8
+    {0x0,0x18,0x20,0x40,0x78,0x44,0x44,0x38},   // 9
+
+    {0x0,0x44,0x44,0x7C,0x44,0x44,0x28,0x10},   // A
+    {0x0,0x3C,0x44,0x44,0x3C,0x44,0x44,0x3C},   // B   
+    {0x0,0x38,0x44,0x4,0x4,0x4,0x44,0x38},      // C   
+    {0x0,0x1C,0x24,0x44,0x44,0x44,0x24,0x1C},   // D  
+    {0x0,0x7C,0x4,0x4,0x3C,0x4,0x4,0x7C},       // E
+    {0x0,0x4,0x4,0x4,0x3C,0x4,0x4,0x7C},        // F
+    {0x0,0x78,0x44,0x44,0x74,0x4,0x44,0x38},    // G
+    {0x0,0x44,0x44,0x44,0x7C,0x44,0x44,0x44},   // H
+    {0x0,0x38,0x10,0x10,0x10,0x10,0x10,0x38},   // I
+    {0x0,0x18,0x24,0x20,0x20,0x20,0x20,0x70},   // J
+    {0x0,0x44,0x24,0x14,0xC,0x14,0x24,0x44},    // K
+    {0x0,0x7C,0x4,0x4,0x4,0x4,0x4,0x4},         // L
+    {0x0,0x44,0x44,0x44,0x54,0x54,0x6C,0x44},   // M
+    {0x0,0x44,0x44,0x64,0x54,0x4C,0x44,0x44},   // N
+    {0x0,0x38,0x44,0x44,0x44,0x44,0x44,0x38},   // O
+    {0x0,0x4,0x4,0x4,0x3C,0x44,0x44,0x3C},      // P
+    {0x0,0x58,0x24,0x54,0x44,0x44,0x44,0x38},   // Q
+    {0x0,0x44,0x24,0x14,0x3C,0x44,0x44,0x3C},   // R
+    {0x0,0x3C,0x40,0x40,0x38,0x4,0x4,0x78},     // S
+    {0x0,0x10,0x10,0x10,0x10,0x10,0x10,0x7C},   // T
+    {0x0,0x38,0x44,0x44,0x44,0x44,0x44,0x44},   // U   
+    {0x0,0x10,0x28,0x44,0x44,0x44,0x44,0x44},   // V     
+    {0x0,0x28,0x54,0x54,0x54,0x44,0x44,0x44},   // W    
+    {0x0,0x44,0x44,0x28,0x10,0x28,0x44,0x44},   // X   
+    {0x0,0x10,0x10,0x10,0x28,0x44,0x44,0x44},   // Y    
+    {0x0,0x7C,0x4,0x8,0x10,0x20,0x40,0x7C},     // Z
+    
+    {0x0,0x78,0x44,0x78,0x40,0x38,0x0,0x0},     // a   
+    {0x0,0x3C,0x44,0x44,0x4C,0x34,0x4,0x4},     // b    
+    {0x0,0x38,0x44,0x4,0x4,0x38,0x0,0x0},       // c    
+    {0x0,0x78,0x44,0x44,0x64,0x58,0x40,0x40},   // d    
+    {0x0,0x38,0x4,0x7C,0x44,0x38,0x0,0x0},      // e    
+    {0x0,0x8,0x8,0x8,0x1C,0x8,0x48,0x30},       // f    
+    {0x38,0x40,0x78,0x44,0x44,0x78,0x0,0x0},    // g    
+    {0x0,0x44,0x44,0x44,0x4C,0x34,0x4,0x4},     // h   
+    {0x0,0x38,0x10,0x10,0x10,0x18,0x0,0x10},    // i    
+    {0x18,0x24,0x20,0x20,0x20,0x30,0x0,0x20},   // j    
+    {0x0,0x24,0x14,0xC,0x14,0x24,0x4,0x4},      // k    
+    {0x0,0x38,0x10,0x10,0x10,0x10,0x10,0x18},   // l    
+    {0x0,0x44,0x44,0x54,0x54,0x2C,0x0,0x0},     // m   
+    {0x0,0x44,0x44,0x44,0x4C,0x34,0x0,0x0},     // n    
+    {0x0,0x38,0x44,0x44,0x44,0x38,0x0,0x0},     // o    
+    {0x4,0x4,0x3C,0x44,0x44,0x3C,0x0,0x0},      // p    
+    {0x40,0x40,0x58,0x64,0x64,0x58,0x0,0x0},    // q   
+    {0x0,0x4,0x4,0x4,0x4C,0x34,0x0,0x0},        // r    
+    {0x0,0x3C,0x40,0x38,0x4,0x38,0x0,0x0},      // s    
+    {0x0,0x30,0x48,0x8,0x8,0x1C,0x8,0x8},       // t   
+    {0x0,0x58,0x64,0x44,0x44,0x44,0x0,0x0},     // u    
+    {0x0,0x10,0x28,0x44,0x44,0x44,0x0,0x0},     // v   
+    {0x0,0x28,0x54,0x54,0x44,0x44,0x0,0x0},     // w    
+    {0x0,0x44,0x28,0x10,0x28,0x44,0x0,0x0},     // x   
+    {0x38,0x40,0x78,0x44,0x44,0x44,0x0,0x0},    // y   
+    {0x0,0x7C,0x8,0x10,0x20,0x7C,0x0,0x0}       // z
+};

File button_press_arduino/button_press_arduino.ino

View file
+/*
+  Button
+ 
+ Turns on and off a light emitting diode(LED) connected to digital  
+ pin 13, when pressing a pushbutton attached to pin 2. 
+ 
+ 
+ The circuit:
+ * LED attached from pin 13 to ground 
+ * pushbutton attached to pin 2 from +5V
+ * 10K resistor attached to pin 2 from ground
+ 
+ * Note: on most Arduinos there is already an LED on the board
+ attached to pin 13.
+ 
+ 
+ created 2005
+ by DojoDave <http://www.0j0.org>
+ modified 30 Aug 2011
+ by Tom Igoe
+ 
+ This example code is in the public domain.
+ 
+ http://www.arduino.cc/en/Tutorial/Button
+ */
+
+// constants won't change. They're used here to 
+// set pin numbers:
+const int buttonPin = 11;     // the number of the pushbutton pin
+const int ledPin =  13;      // the number of the LED pin
+
+// variables will change:
+int buttonState = 0;         // variable for reading the pushbutton status
+
+void setup() {
+  // initialize the LED pin as an output:
+  pinMode(ledPin, OUTPUT);      
+  // initialize the pushbutton pin as an input:
+  pinMode(buttonPin, INPUT);     
+}
+
+void loop(){
+  // read the state of the pushbutton value:
+  buttonState = digitalRead(buttonPin);
+
+  // check if the pushbutton is pressed.
+  // if it is, the buttonState is HIGH:
+  if (buttonState == HIGH) {     
+    // turn LED on:    
+    digitalWrite(ledPin, HIGH);  
+  } 
+  else {
+    // turn LED off:
+    digitalWrite(ledPin, LOW); 
+  }
+}
+

File neoLed/neoLed.ino

View file
+/*
+ * arduino serial-i2c-gateway, Copyright (C) 2010 michael vogt <michu@neophob.com>
+ *  
+ * based on 
+ * -blinkm firmware by thingM
+ * -"daft punk" firmware by Scott C / ThreeFN 
+ *  
+ * libraries to patch:
+ * Wire: 
+ *  	utility/twi.h: #define TWI_FREQ 400000L (was 100000L)
+ *                    #define TWI_BUFFER_LENGTH 98 (was 32)
+ *  	wire.h: #define BUFFER_LENGTH 98 (was 32)
+ *
+ * This file is part of neorainbowduino.
+ *
+ * neorainbowduino is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * neorainbowduino is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 	
+ */
+
+#include <Wire.h>
+#include "WProgram.h"
+
+extern "C" { 
+#include "utility/twi.h"  // from Wire library, so we can do bus scanning
+}
+
+
+//to draw a frame we need arround 20ms to send an image. the serial baudrate is
+//NOT the bottleneck. 
+#define BAUD_RATE 115200
+
+#define CLEARCOL 51 //00110011
+
+//some magic numberes
+#define CMD_START_BYTE  0x01
+#define CMD_SENDFRAME 0x03
+#define CMD_PING  0x04
+#define CMD_INIT_RAINBOWDUINO 0x05
+#define CMD_SCAN_I2C_BUS 0x06
+
+//8ms is the minimum!
+#define SERIAL_WAIT_TIME_IN_MS 8
+
+//I2C definitions
+#define START_OF_DATA 0x10
+#define END_OF_DATA 0x20
+
+//Static start+end address for i2x scan
+#define START_I2C_SCAN 1
+#define END_I2C_SCAN 101
+
+//this should match RX_BUFFER_SIZE from HardwareSerial.cpp
+byte serInStr[128]; 	 				 // array that will hold the serial input string
+
+//counter for 2000 frames
+//http://www.ftdichip.com/Support/Documents/AppNotes/AN232B-04_DataLatencyFlow.pdf
+//there is a 16ms delay until the buffer is full, here are some measurements
+//time is round trip time from/to java
+//size  errorrate       frames>35ms  time for 2000frames  time/frame  time/frame worstcase
+//5  -> rate: 0.0,      long: 156,   totalTime: 44250     22.13ms
+//8  -> rate: 5.894106, long: 38,    totalTime: 41184     20.59ms     21.83ms
+//16 -> rate: 7.092907, long: 4,     totalTime: 40155     20.07ms     21.48ms
+//32 -> rate: 6.943056, long: 5,     totalTime: 39939     19.97ms     21.36ms
+//62 -> rate: 22.97702, long: 7,     totalTime: 33739     16.89ms     20.58ms
+//64 -> rate: 24.22577, long: 3,     totalTime: 33685     16.84ms     20.89ms
+//-> I use 16b - not the fastest variant but more accurate
+
+#define SERIALBUFFERSIZE 16
+byte serialResonse[SERIALBUFFERSIZE];
+
+byte g_errorCounter;
+
+//send status back to library
+static void sendAck() {
+  serialResonse[0] = 'A';
+  serialResonse[1] = 'K';
+  serialResonse[2] = Serial.available();
+  serialResonse[3] = g_errorCounter;  
+  Serial.write(serialResonse, 4);
+
+  //Clear bufer
+ // Serial.flush();
+}
+
+
+//send an white image to the target rainbowduino
+//contains red led's which describe its i2c addr
+byte send_initial_image(byte i2caddr) {
+  //clear whole buffer
+  memset(serInStr, CLEARCOL, 128);
+
+  //draw i2c addr as led pixels
+  float tail = i2caddr/2.0f;
+  byte tail2 = (byte)(tail);
+  boolean useTail = (tail-(byte)(tail))!=0;			
+
+  //buffer layout: 32b RED, 32b GREEN, 32b BLUE
+  byte ofs=0;
+  for (byte i=0; i<tail2; i++) {
+    serInStr[ofs++]=255;
+  }
+  if (useTail) {
+    serInStr[ofs++]=243;
+  }
+  
+  return BlinkM_sendBuffer(i2caddr, serInStr);
+}
+
+// ripped from http://todbot.com/arduino/sketches/I2CScanner/I2CScanner.pde
+// Scan the I2C bus between addresses from_addr and to_addr.
+// On each address, call the callback function with the address and result.
+// If result==0, address was found, otherwise, address wasn't found
+// (can use result to potentially get other status on the I2C bus, see twi.c)
+// Assumes Wire.begin() has already been called
+// HINT: maximal 14 devices can be scanned!
+void scanI2CBus() {
+  memset(serialResonse, 255, SERIALBUFFERSIZE);
+  serialResonse[0] = CMD_START_BYTE;
+  serialResonse[1] = CMD_SCAN_I2C_BUS;
+
+  byte rc,i=2;
+  byte data = 0; // not used, just an address to feed to twi_writeTo()
+  for (byte addr = START_I2C_SCAN; addr <= END_I2C_SCAN; addr++) {
+  //rc 0 = success
+    digitalWrite(13, HIGH);
+    rc = twi_writeTo(addr, &data, 0, 1);
+    digitalWrite(13, LOW);
+    if (rc==0) {
+      serialResonse[i]=addr;
+      if (i<SERIALBUFFERSIZE) i++;
+    }
+    delayMicroseconds(64);
+  }
+  Serial.write(serialResonse, SERIALBUFFERSIZE);
+  memset(serialResonse, 0, SERIALBUFFERSIZE);
+}
+
+
+void setup() {
+  Wire.begin(1); // join i2c bus (address optional for master)
+  
+  pinMode(13, OUTPUT);
+  memset(serialResonse, 0, SERIALBUFFERSIZE);
+
+  //im your slave and wait for your commands, master!
+  Serial.begin(BAUD_RATE); //Setup high speed Serial
+  Serial.flush();
+}
+
+
+void loop() {
+  //read the serial port and create a string out of what you read
+  g_errorCounter=0;
+
+  digitalWrite(13, LOW);
+  // see if we got a proper command string yet
+  if (readCommand(serInStr) == 0) {
+    //no valid data found
+    //sleep for 250us
+    delayMicroseconds(250);
+    return;
+  }
+  
+  digitalWrite(13, HIGH);
+  
+  //i2c addres of device
+  byte addr    = serInStr[1];
+  //how many bytes we're sending
+  byte sendlen = serInStr[2];
+  //what kind of command we send
+  byte type = serInStr[3];
+  //parameter
+  byte* cmd    = serInStr+5;
+
+  switch (type) {
+    case CMD_SENDFRAME:
+    	//the size of an image must be exactly 96 bytes
+        if (sendlen!=96) {
+          g_errorCounter=100;
+        } else {
+          g_errorCounter = BlinkM_sendBuffer(addr, cmd);    
+        }
+        break;
+    case CMD_PING:
+        //just send the ack!
+        break;
+    case CMD_INIT_RAINBOWDUINO:
+        //send initial image to rainbowduino
+        g_errorCounter = send_initial_image(addr);
+        break;
+    case CMD_SCAN_I2C_BUS:
+    	scanI2CBus();
+    	break;
+    default:
+        //invalid command
+        g_errorCounter=130; 
+        break;
+  }
+        
+  //send ack to library - command processed
+  sendAck();
+    
+}
+
+
+
+//send data via I2C to a client
+static byte BlinkM_sendBuffer(byte addr, byte* cmd) {
+    Wire.beginTransmission(addr);
+    Wire.write(START_OF_DATA);
+    Wire.write(cmd, 96);
+    Wire.write(END_OF_DATA);
+    return Wire.endTransmission();
+}
+
+
+//read a string from the serial and store it in an array
+//you must supply the str array variable
+//returns number of bytes read, or zero if fail
+/* example ping command:
+		cmdfull[0] = START_OF_CMD (marker);
+		cmdfull[1] = addr;
+		cmdfull[2] = 0x01; 
+		cmdfull[3] = CMD_PING;
+		cmdfull[4] = START_OF_DATA (marker);
+		cmdfull[5] = 0x02;
+		cmdfull[6] = END_OF_DATA (marker);
+*/
+#define HEADER_SIZE 5
+byte readCommand(byte *str) {
+  byte b,i,sendlen;
+
+  //wait until we get a CMD_START_BYTE or queue is empty
+  i=0;
+  while (Serial.available()>0 && i==0) {
+    b = Serial.read();
+    if (b == CMD_START_BYTE) {
+      i=1;
+    }
+  }
+
+  if (i==0) {
+    //failed to get data
+    g_errorCounter=101;
+    return 0;    
+  }
+
+//read header  
+  i = SERIAL_WAIT_TIME_IN_MS;
+  while (Serial.available() < HEADER_SIZE-1) {   // wait for the rest
+    delay(1); 
+    if (i-- == 0) {
+      g_errorCounter=102;
+      return 0;        // get out if takes too long
+    }
+  }
+  for (i=1; i<HEADER_SIZE; i++) {
+    str[i] = Serial.read();       // fill it up
+  }
+  
+// --- START HEADER CHECK    
+  //check if data is correct, 0x10 = START_OF_DATA
+  if (str[4] != START_OF_DATA) {
+    g_errorCounter=104;
+    return 0;
+  }
+  
+  //check sendlen, its possible that sendlen is 0!
+  sendlen = str[2];
+// --- END HEADER CHECK
+
+  
+//read data  
+  i = SERIAL_WAIT_TIME_IN_MS;
+  // wait for the final part, +1 for END_OF_DATA
+  while (Serial.available() < sendlen+1) {
+    delay(1); 
+    if( i-- == 0 ) {
+      g_errorCounter=105;
+      return 0;
+    }
+  }
+
+  for (i=HEADER_SIZE; i<HEADER_SIZE+sendlen+1; i++) {
+    str[i] = Serial.read();       // fill it up
+  }
+
+  //check if data is correct, 0x20 = END_OF_DATA
+  if (str[HEADER_SIZE+sendlen] != END_OF_DATA) {
+    g_errorCounter=106;
+    return 0;
+  }
+
+  //return data size (without meta data)
+  return sendlen;
+}
+
+

File yrainbow_master/WireCommands.h

View file
+#ifndef WireCommands_h
+#define WireCommands_h
+
+#define MAX_WIRE_CMD          0x80
+
+#define CMD_NOP               0x00
+
+#define CMD_SWAP_BUF          0x10
+#define CMD_COPY_FRONT_BUF    0x11
+#define CMD_SHOW_AUX_BUF      0x12
+
+#define CMD_CLEAR_BUF         0x20
+#define CMD_SET_PAPER         0x21
+#define CMD_SET_INK           0x22
+#define CMD_CLEAR_PAPER       0x25
+#define CMD_DRAW_PIXEL        0x26
+#define CMD_DRAW_LINE         0x27
+#define CMD_DRAW_SQUARE       0x28
+#define CMD_PRINT_CHAR        0x2A
+#define CMD_DRAW_ROW_MASK     0x2B
+
+extern unsigned char CMD_totalArgs[MAX_WIRE_CMD];
+
+#endif

File yrainbow_master/WireCommunication.c

View file
+#include <avr/pgmspace.h>
+
+#include "WireCommands.h"
+
+// Stores the number of arguments required for each command
+unsigned char CMD_totalArgs[MAX_WIRE_CMD] PROGMEM = {
+//  0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - A - B - C - D - E - F 
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,    // 0 - 0x00 -> 0x0F
+    0,  2,  1,  2,  1,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,    // 1 - 0x10 -> 0x1F
+    3,  3,  3,  0,  0,  0,  2,  4,  4,  0,  3,  3,  0,  0,  0,  0,    // 2 - 0x00 -> 0x2F
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,    // 3 - 0x00 -> 0x3F
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,    // 4 - 0x00 -> 0x4F
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,    // 5 - 0x50 -> 0x5F
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,    // 6 - 0x60 -> 0x6F
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0     // 7 - 0x70 -> 0x7F
+//  0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - A - B - C - D - E - F 
+};
+
+

File yrainbow_master/yrainbow_master.ino

View file
+#include <stdio.h>
+#include <Wire.h>
+#include <avr/pgmspace.h>
+
+#include "WireCommands.h"
+
+void sendCMD(byte address, byte CMD, ... );
+
+unsigned char RainbowCMD[20];
+unsigned char State = 0;  
+unsigned long timeout;
+
+const int buttonPin = 11; 
+
+byte buttonState = 0;
+
+byte remoteAddr = 0x10;
+
+void setup() {
+  Wire.begin();    // join I2C bus (address optional for master)
+ // Serial.begin(9600);
+  
+  RainbowCMD[0] = 'r';
+  
+  sendCMD(0x10, CMD_SET_PAPER, 0, 0, 0);
+  
+  pinMode(buttonPin, INPUT);
+  
+}
+
+void loop() {     // Do some test with Rainbowduino
+//  sendCMD(0x10, CMD_CLEAR_PAPER);
+//
+//  sendCMD(0x10, CMD_SET_INK, 0xD, 0xF, 0);
+//  sendCMD(0x10, CMD_DRAW_SQUARE, toByte(2), toByte(2), toByte(6), toByte(6));
+//
+//  sendCMD(0x10, CMD_SET_INK, 0xF, 0x0, 0);
+//  sendCMD(0x10, CMD_DRAW_LINE,  toByte(2), toByte(2), toByte(6), toByte(6));
+//  sendCMD(0x10, CMD_DRAW_LINE,  toByte(2), toByte(6), toByte(6), toByte(2));
+//
+//  sendCMD(0x10, CMD_SET_INK, 0x0, 0x0, 15);
+//  sendCMD(0x10, CMD_DRAW_PIXEL, toByte(8), toByte(0));
+//  sendCMD(0x10, CMD_PRINT_CHAR, toByte(1), toByte(1), random('1', '9'+1));
+//  sendCMD(0x10, CMD_SWAP_BUF);
+  
+
+
+//  
+//  delay(500);
+//
+//  byte k = 0;
+//  for (k = 0; k < 255; k++) {
+//    sendCMD(0x10, CMD_CLEAR_PAPER);
+//    sendCMD(0x10, CMD_COPY_FRONT_BUF, toByte(0), toByte(-1));
+//    sendCMD(0x10, CMD_DRAW_ROW_MASK, toByte(7), toByte(0), k);
+//    sendCMD(0x10, CMD_SWAP_BUF);
+//  }
+
+  
+//  sendCMD(0x10, CMD_CLEAR_BUF, toByte(random('1', '9'+1)), toByte(random('1', '9'+1)), toByte(random('1', '9'+1)));
+
+//  sendCMD(0x10, CMD_SWAP_BUF);
+
+
+//  sendCMD(0x10, CMD_SWAP_BUF);
+
+  buttonState = digitalRead(buttonPin);
+
+  if (buttonState == HIGH) {
+    
+  sendCMD(0x10, CMD_CLEAR_PAPER);
+  sendCMD(0x10, CMD_SWAP_BUF);
+
+  byte r = toByte(random(0xf));
+  byte g = toByte(random(0xf));
+  byte b = toByte(random(0xf));
+  for (int i = 0 ; i<8 ;i++){
+    for (int j = 0 ; j<8 ; j++){
+        
+      sendCMD(0x10, CMD_SET_INK, r, g, b);
+      sendCMD(0x10, CMD_DRAW_PIXEL, toByte(i), toByte(j));
+    }}
+  sendCMD(0x10, CMD_SWAP_BUF);    
+//  sendCMD(0x10, CMD_SET_PAPER, r, g, b);
+//sendCMD(0x10, CMD_DRAW_SQUARE, toByte(0), toByte(0), toByte(-1), toByte(-1));
+//  sendCMD(0x10, CMD_CLEAR_BUF,r, g, b);
+
+
+  delay(50);
+  }
+}
+
+void sendCMD(byte address, byte CMD, ... ) {
+  int i;
+  unsigned char v;
+  byte t;
+  va_list args;                     // Create a variable argument list
+  va_start(args, CMD);              // Initialize the list using the pointer of the variable next to CMD;
+  
+  RainbowCMD[1] = CMD;              // Stores the command name
+  t = pgm_read_byte(&(CMD_totalArgs[CMD]))+2;  // Retrieve the number of arguments for the command
+  for (i=2; i < t; i++) {
+    v = va_arg(args, int);          // Retrieve the argument from the va_list    
+    RainbowCMD[i] = v;              // Store the argument
+  }
+  
+  sendWireCommand(address, t);      // Transmit the command via I2C
+}
+
+unsigned char toByte(int i) {
+  return map(i, -128, 127, 0, 255);
+}
+
+// ### The following lines are adapted from the original code ###
+
+void sendWireCommand(int Add, byte len) {
+  unsigned char OK=0;
+  unsigned char i,temp;
+  
+  while(!OK)
+  {                          
+    switch (State)
+    { 	
+
+    case 0:                          
+      Wire.beginTransmission(Add);
+      for (i=0; i<len ;i++) Wire.write(RainbowCMD[i]);
+      Wire.endTransmission();    
+      delay(5);   
+      State=1;                      
+      break;
+
+    case 1:
+      Wire.requestFrom(Add,1);   
+      if (Wire.available()>0) 
+        temp=Wire.read();    
+      else {
+        temp=0xFF;
+        timeout++;
+      }
+
+      if ((temp==1)||(temp==2)) State=2;
+      else if (temp==0) State=0;
+
+      if (timeout>5000) {
+        timeout=0;
+        State=0;
+      }
+
+      delay(5);
+      break;
+
+    case 2:
+      OK=1;
+      State=0;
+      break;
+
+    default:
+      State=0;
+      break;
+    }
+  }
+}