/************** Tick Tock Tock **************/ /* Processing code for the Comnputer portion of the Tick Tock Tock project written by Steven Lehrburger 25 June 2008 for the Sociable Objects class at ITP taught by Rob Faludi */ import processing.serial.*; int deviceID = '2'; // Allows the radios in broadcast mode to identify each other int WATCH = '0'; int LCD = '1'; int COMP = '2'; int STARTBYTE = '*'; // a unifrom startbyte int CONFBYTE = 'R'; // and confirmation byte int NUM_TIME_UNITS = 7; // centruy, year, month, day, hours, minutes, Serial xbeePort; // unlike Arduino, we need to epxlicitly set up the Serial port for processing int senderID; int[] currentDateTimeData; // dateTimeData in ccyymmddHHMMSS format void setup() { println(Serial.list()); // so we can see all the serial ports - you may have to change the array index to get the right one xbeePort = new Serial(this, Serial.list()[1], 9600); configureXBee(); currentDateTimeData = new int[NUM_TIME_UNITS]; GetInitialTime(); BroadcastTimeAndWaitForConfirmations(); delay(2000); // broadcast the initial starting time to the other devices so that they are all in sync loop(); while (xbeePort.available() > 0) { println(xbeePort.read());// delay based on the number of bytes left in the array - this helped fix a synchronization bug for some reason delay(20); } println("done"); } // The looping draw function waits until it receives a time from the watch, and then is supposed to set itself void draw() { println("looping"); delay(200); if (CheckBufferForTime(WATCH)) { println("watch signal received"); // SetSystemTime(); // I wasn't actually able to get it to set the computer system time println("watch signal processed"); while (xbeePort.available() > 0) { println(xbeePort.read()); delay(20); } } } // Check's the buffer for a series of bytes that corresponds to a time. // It looks for a Time from a specific sender, depending on if it is being set initially or is running. boolean CheckBufferForTime(int senderID) { if (xbeePort.available() > 0) { int inByte = xbeePort.read(); // first make sure there is a valid startbyte - this will allow us to read junk out of the buffer until a string starts if (inByte == STARTBYTE) { int recSenderID = xbeePort.read(); if(recSenderID == senderID) { int firstDataByte = xbeePort.read(); if(firstDataByte == CONFBYTE) { return(false); } else { currentDateTimeData[0] = firstDataByte; for (int i = 1; i < NUM_TIME_UNITS; i++) { currentDateTimeData[i] = xbeePort.read(); } // store each byte in the proper array return(true); // let the calling function know we stored a string } } } } return(false); } //The received bytes lose their leading zero, and this function assa that zero when necessary String GetTwoDigitValue(int index) { String returnVal = ""; if (currentDateTimeData[index] <= 9) { returnVal += "0"; } if ((index == 2) || (index == 3)) { returnVal += (currentDateTimeData[index] + 1); } else { returnVal += currentDateTimeData[index]; } return(new String(returnVal)); } // This was intended to set the system tiume based on the received time from the watch, but I could not // get it working in time. It uses the date command in the Mac OS X Terminal ( //http://www.ss64.com/osx/ ) // but actually setting the command did not work as expected. I was able to read the date but not write to it, // even with sudo and the temporary password of 'password'. The code was passed on to me by Rob Faludi. // It was convenient for demonstration, however, to have the Computer clock continue to show the correct time for // comparison to the Watch and the Serial LCD. void SetSystemTime() { try { String temp = new String(GetTwoDigitValue(2) + GetTwoDigitValue(3) + GetTwoDigitValue(4) + GetTwoDigitValue(5) + GetTwoDigitValue(0) + GetTwoDigitValue(1) + "." + GetTwoDigitValue(6)); //sudo date Process p1 = Runtime.getRuntime().exec("sudo date 062510452008.04");//" + GetTwoDigitValue(2) + GetTwoDigitValue(3) + GetTwoDigitValue(4) + GetTwoDigitValue(5) + GetTwoDigitValue(0) + GetTwoDigitValue(1) + "." + GetTwoDigitValue(6)); Runtime.getRuntime().exec("password"); BufferedReader in1 = new BufferedReader(new InputStreamReader(p1.getInputStream())); String str = null; while ((str = in1.readLine()) != null) { System.out.println(str); } } catch (Exception e) { println("error1"); e.printStackTrace(); } } // Broadcasts the initial time repeatedly until it receives a confirmation byte from both other devices that it was received void BroadcastTimeAndWaitForConfirmations() { boolean watchConfirmed = false; boolean lcdConfirmed = false; xbeePort.clear(); while (!watchConfirmed || !lcdConfirmed) { broadcastTime(); if (xbeePort.available() > 0) { int possibleStartByte = xbeePort.read(); if (possibleStartByte == STARTBYTE) { int idByte = xbeePort.read(); if (idByte == LCD) { int confByte = xbeePort.read(); lcdConfirmed = (confByte == CONFBYTE); println("LCD confirmed"); } else if (idByte == WATCH) { int confByte = xbeePort.read(); watchConfirmed = (confByte == CONFBYTE); println("Watch confirmed"); } } } } } // Gets the initial time based on the current system time and stores it // The system time can be set in System Preferences for debugging purposes // NOTE // The -1's in the month and day are crucial. For seconds, minutes, hours, and years the counts start at // zero an carry over when they reach their maximum (i.e. 60 for seconds, etc). DAYS AND MONTHS DO NOT DO THIS. // Instead, they start at 1 and count all the way through their maximum before resetting. void GetInitialTime() { currentDateTimeData[0] = year() / 100; // use truncating integer math to separate centuries from years currentDateTimeData[1] = year() - (currentDateTimeData[0] * 100); currentDateTimeData[2] = month() - 1; currentDateTimeData[3] = day() - 1; currentDateTimeData[4] = hour(); currentDateTimeData[5] = minute(); currentDateTimeData[6] = second() + 7; // this offset is a somewhat sloppy way to account for send/receive delays println("printing currentDateTimeData:"); println(currentDateTimeData[0]); println(currentDateTimeData[1]); println(currentDateTimeData[2]); println(currentDateTimeData[3]); println(currentDateTimeData[4]); println(currentDateTimeData[5]); println(currentDateTimeData[6]); } // Sends out a series of bytes representing the current time void broadcastTime() { xbeePort.write(STARTBYTE); xbeePort.write(deviceID); for(int i = 0; i < NUM_TIME_UNITS; i++) { xbeePort.write(currentDateTimeData[i]); } delay(100); } /************** XBee configuration **************/ // Configure's the XBee with the proper addresses void configureXBee() { xbeePort.clear(); delay(1010); xbeePort.write("+++"); delay(1010); CheckFor("OK/r", 10); // everyone is broadcasting! xbeePort.write("ATRE, DH0, DLFFFF\r"); CheckFor("OK/r", 10); // but deviceID's determine sender and behavior xbeePort.write("ATMY"); xbeePort.write(deviceID); xbeePort.write("\r"); CheckFor("OK/r", 10); xbeePort.write("ATIDBCDE\r"); CheckFor("OK/r", 10); xbeePort.write("ATCN\r"); CheckFor("OK/r", 10); delay(1000); } // Checks the receive port from the XBee for the target string until it gets it or times out boolean CheckFor(String target, int timeout) { long timeoutCheck = millis(); String bufferStorage = ""; while (xbeePort.available() > 0) { bufferStorage += xbeePort.read(); if (bufferStorage.indexOf(target) != -1) { return(true); } if ((timeoutCheck + timeout) > millis()) { return(false); } } return(false); }