//**************************************************************//
//  Name    : shiftOutCode, 64 outputs                          //
//  Author  : D. Cuartielles                                    //
//  Date    : 8 Jan, 2008                                       //
//  Version : 1.1                                               //
//  Notes   : Code for using 2x32OUTPUTs boards to control      //
//            different devices                                 //
//**************************************************************//

/* Test Srings
 * use these to check the communication from a serial
 * monitor, note I use 'A' as a marker
 0         1         2         3         4         5         6      
 01234567890123456789012345678901234567890123456789012345678901234
 ---------------------------------
 A0000000000000000000000000000000000000000000000000000000000000000
 A1111111111111111111111111111111111111111111111111111111111111111
1
A1000000000000000000000000000000000000000000000000000000000000000  
16
A0000000000000001000000000000000000000000000000000000000000000000
17
A0000000000000000100000000000000000000000000000000000000000000001
32
A0000000000000000000000000000000100000000000000000000000000000010 
33
A0000000000000000000000000000000010000000000000000000000000000000
48
A0000000000000000000000000000000000000000000000010000000000000000
49
A0000000000000000000000000000000000000000000000001000000000000000
64
A0000000000000000000000000000000000000000000000000000000000000001
         
 A1100000000000000000000000000000000000000000000000000000000000000  
 A0000000000000000000000000000000000000000000000000000000000000011
 
 
 
 
 0         1         2         3   
 012345678901234567890123456789012
 ---------------------------------
 A00000000000000000000000000000000
 A11111111111111111111111111111111
 */


//activate if you want feedback on data arrival
#define DEBUG 1
//amount of bits to be captured
#define MAXDATA 32
//timeout to consider communication broken
#define TIMEOUT 4000
//communication marker, 65=A
#define MARKER 65

//Pin connected to ST_CP of 74HC595
int latchPin = 7;
//Pin connected to SH_CP of 74HC595
int clockPin = 6;
//Pin connected to DS of 74HC595
int dataPin = 5;

// data coming in, stored in an array
int dataIn[MAXDATA];

// FUNCTIONS
void resetDataIn() {
  for (int i = 0; i < MAXDATA; i++) {
    dataIn[i] = 0;
  }
}

void sendOut() {
  // 64 outputs is 6 bytes, so we gotta call
  // shiftout 6 times, however, we gotta package
  // data first
  digitalWrite(latchPin, LOW);
  for (int j = 0; j < MAXDATA/8; j++) {
    int theData = 0;
    // note the correction in the data, '0' is ascii 48 and '1' is ascii '49'
    for (int i = 0; i <= 7; i++) 
      theData |= (dataIn[j*8+i]-48)<<i;
    shiftOut(dataPin, clockPin, LSBFIRST, theData);
  }
  digitalWrite(latchPin, HIGH);
}


// readSerialString
// ----------------
// reads a string from the serial port with the following
// behavior depending on data arrival:
//
// 1) stores arriving data in order inside the dataIn array
// 2) goes out if data is not consistent: if the characters
//    in the line are not '0' or '1'
// 3) goes out when reaching MAXDATA characters in the message
// 4) goes out if nothing happens in 10 seconds
//
// the function answers 0 if things went fine, 1 if there was bad data
// and 2 if there was a timeout
int readSerialString() {
  int cont = 0;
  int errcode = 0;
  long timer = millis();
  while (1) {
    if(Serial.available()) {
      dataIn[cont] = Serial.read();
      //delayMicroseconds(3);
      if (dataIn[cont] != '0' && dataIn[cont] != '1') {
        errcode = 1;
        break;
      }
      cont++;
      if (cont >=MAXDATA) break;
      timer = millis();
    }
    if (millis() - timer > TIMEOUT) {
      errcode = 2;
      break;
    }
  }
return errcode;
}

// END FUNCTIONS

void setup() {
  //set pins to otutput because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  //configure the serial port
  Serial.begin (9600);

  //reset the array containing the data to zeroes
  resetDataIn();
}

void loop() {
  if(Serial.available()) {
    int serin = Serial.read();
    // we check out if the communication package
    // starts with the predefined marker
    if(serin == MARKER) {
      int serialData = readSerialString();
      if (!serialData) {
        sendOut();
        if (DEBUG) {
          Serial.println("** data arrived safe:");
        }
      }
      else {
        if (DEBUG) {
          Serial.print("** data didnt make it: ");
          if (serialData == 1) {
            Serial.println("bad data");
          } 
          else {
            Serial.println("timeout");
          }
        }
      }
    }
  }
}