Tuesday, January 26, 2010

Breath-over-IP for Arduino

This is the code for breath-over-IP for an Arduino. This code uses the NewSoftSerial library, and assumes the use of a Lantronix Xport / Xport Direct (perhaps with a LadyAda Ethernet Shield).

#include <NewSoftSerial.h>

// breath-over-IP for Arduino

unsigned long time = 0; // time of last edge
int minTime = 25; // minimum time for edge
int good = 0; // number of consecutive good (fast) edges
int minGoods = 20; // minimum number of consecutive good (fast) edges to indicate breath

int ledPin = 13; // on-board LED pin
int irLedPin = 10; // IR LED attached to pin 12 with 220 ohm resistor
int irDetPin = 0; // IR phototransistor attached to analog 0 with 5V and 10K
int relayPin = 11; // solid-state relay pin

unsigned long onTime = 0; // relay on time'

int i=0; // counts up received breath packets for diagnostics
int light=0; // whether IR detector sees light or dark
int lastLight=0; // what IR detector saw last time
int state=0; // current state of state machine for reading HTTP

char c=0;

unsigned long sendTime=0; // last time breath packet was sent out

NewSoftSerial xport(3,2);

void setup()
{
pinMode(relayPin,OUTPUT);
digitalWrite(relayPin, LOW);

Serial.begin(57600);
xport.begin(9600);
xport.print("GET /update?d=B2&s=0 HTTP/1.1\r\nHost: phy-to-phy.appspot.com\r\n\r\n");
pinMode(ledPin, OUTPUT);
pinMode(irLedPin, OUTPUT);
digitalWrite(irLedPin, HIGH);
//Serial.print("Starting up");
}

void loop()
{
//Serial.println(analogRead(irDetPin));
if(analogRead(irDetPin)>850){
light=0; // impeller blade blocking IR
}
else{
light=1; // impeller blade not blocking IR
}

if(light != lastLight){
// edge
if(millis()-time<minTime){
// fast edge
good++;
}
else{
// not fast edge
good=0;
}
time=millis();
lastLight=light;
}

if(good>minGoods) {
// enough good (fast) edges
digitalWrite(ledPin,HIGH);
if(millis()-sendTime>100){
// send a breath, not too fast though
//Serial.print("I'm sending a breath\n");
xport.print("GET /update?d=B2&s=1 HTTP/1.1\r\nHost: phy-to-phy.appspot.com\r\n\r\n");
sendTime = millis();
}
}
else{
// not enough good (fast) edges
digitalWrite(ledPin,LOW);
if(millis()-sendTime>500){
// send a non-breath, not too fast though
//Serial.print("I'm sending a non-breath...\n");
xport.print("GET /update?d=B2&s=0&q=B1 HTTP/1.1\r\nHost: mylameapp.appspot.com\r\n\r\n");
sendTime = millis();

}
}
if(millis() - onTime > 5000){ // timeout after 5 seconds
digitalWrite(relayPin,LOW);
}

while(xport.available()){
c=(char)xport.read();
//Serial.print(c);
if((c=='B') && (state==0)){state=1;}
else if((c=='1') && (state==1)){state=2;}
else if((c==':') && (state==2)){state=3;}
else if((c=='1') && (state==3)){
digitalWrite(relayPin,HIGH);
onTime = millis();
//Serial.print("REMOTE BREATH!!!\n");
state=0;
}
else if((c=='0') && (state==3)){
digitalWrite(relayPin,LOW);
//Serial.print("No remote breath\n");
}
else state=0;
}
}