/* * ArduInboxMeter.pde (Mauro Brunato, april 2009) * * Checks your mailboxes, shows your backlog lengths on an analog VU meter, * lets your friends offer you some coffee and allows you to tell your mood * to the world with 10-bit precision. * */ #include // Pin definitions int vuPin = 3; // PWM-driven analog VU-meter int tenPin = 4; // (X10) x10 LED int newmailPin = 5; // (NEW) New mail LED int checkPin = 6; // (CHK) Checking mail LED int errorPin = 9; // (ERR) Error in last mail check int coffeePin = 8; // (COF) Invited for coffee int rxPin = 7; // (RX) Somebody's sending bytes via TCP int moodMeter = 5; // Input pin for mood potentiometer int allmail = 0; // Total number of items in my inbox int newmail = 0; // Unread mail in my inbox long checkPeriod = 60000; // Approx delay between checks (1min) long lastCheck = -checkPeriod; // Time of last check boolean messagePrinted = false; // Has the telnet help message been sent lately // Look-up table: PWM vaues to vuPin for 0-10 and >10 marks of VU-meter int levels[] = {0, 7, 14, 20, 27, 37, 48, 55, 65, 75, 90, 120}; // Ethernet shield's MAC address byte mac[] = { 0x6E, 0x8D, 0xB7, 0xE3, 0x7E, 0xE3 }; // IP address byte ip[] = { 192, 168, 122, 71 }; // Web server address byte server[] = { 192, 168. 123, 123 }; // Web port int port = 8080; // Buffer for telnet input messages char instring[100]; int stringSize = 0; // Has coffee been offered? boolean coffeeOffered = false; // What is my current mood (0-1023)? int currentMood; // TCP client for mail checks Client client(server, port); // Telnet server for coffee invitations Server listener (23); /* * Show the number of messages and if there's new mail. * If more than 10 messages, use the x10 multiplier. */ void display (int number, boolean type) { int level, remainder; boolean ten; if ( number > 10 ) { remainder = number % 10; number /= 10; if ( number > 10 ) level = levels[11]; else level = levels[number] + (levels[number+1]-levels[number]) * remainder / 10; ten = true; } else { level = levels[number]; ten = false; } analogWrite (vuPin, level); digitalWrite (tenPin, ten); digitalWrite (newmailPin, type); } /* * Check the mail. Conection goes to a PHP page which should output a line as * |aaa|bbb| * where aaa is the number of messages in the inbox and bbb is the number of unread messages. * The page can optionally accept the "mood" parameter. */ boolean checkMail (int mood) { boolean allright = false; digitalWrite (checkPin, HIGH); if (client.connect()) { client.print("GET /myInbox.php?mood="); client.print(mood); client.println(" HTTP/1.0"); client.println(); int state = 0; int count = 0; int currentmail = 0; int currentnew = 0; do { if ( !client.available() ) continue; char c = client.read(); switch ( state ) { case 0: if ( c == '|' ) state = 1; break; case 1: if ( c == '|' ) state = 2; else currentmail = currentmail * 10 + c - '0'; break; case 2: if ( c == '|' ) state = 3; else currentnew = currentnew * 10 + c - '0'; break; } } while ( client.connected() && state < 3 ); if ( state >= 3 ) { allmail = currentmail; newmail = currentnew; allright = true; } client.flush(); delay(100); client.stop(); } digitalWrite (checkPin, LOW); digitalWrite (errorPin, !allright); return allright; } /* * A coffee invitation has been issued. */ void startCoffeeProtocol () { coffeeOffered = true; currentMood = analogRead(moodMeter); digitalWrite (coffeePin, HIGH); listener.println ("***** Your offer has been notified. Please stand by."); //raiseFlag(); } /* * I have turned the knob to answer to the invitation. */ void stopCoffeeProtocol (boolean accept) { coffeeOffered = false; digitalWrite (coffeePin, LOW); if ( accept ) listener.print ("*********\r\nYour offer has been accepted\r\nand Mauro is running to the vending machine area.\r\n********\r\n> "); else listener.print ("***** Sorry, your offer has been declined.\r\n> "); } /* * Print help message to the connected telnet client */ void clientHelp (Client c) { c.print ("\r\n*****************\r\nThis is ArduInboxMeter v1.0.\r\n\r\nMauro's current mood is "); c.print (analogRead(moodMeter)); c.print ("/1023.\r\nIf you wish to invite Mauro to take a coffee,\r\n don't be shy and enter \"coffee\".\r\nType \"quit\" to quit.\r\n> "); messagePrinted = true; } /* * Initialization: set in and out pins, set Ethernet */ void setup() { pinMode(vuPin, OUTPUT); pinMode(tenPin, OUTPUT); pinMode(newmailPin, OUTPUT); pinMode(checkPin, OUTPUT); pinMode(errorPin, OUTPUT); pinMode(coffeePin, OUTPUT); pinMode(rxPin, OUTPUT); Ethernet.begin(mac, ip); delay (1000); } /* * Loop for managing coffee, telnet and mail check protocols. */ void loop() { if ( coffeeOffered ) { int val = analogRead (moodMeter); if ( val > currentMood+10 || val > 1018 ) stopCoffeeProtocol(true); else if ( val < currentMood-10 || val < 5 ) stopCoffeeProtocol(false); } Client cl = listener.available(); if ( cl ) { digitalWrite (rxPin, HIGH); char c = cl.read() & ~' '; if ( c == '\n' ) { instring[stringSize] = '\0'; messagePrinted = false; if ( !strcmp(instring,"COFFEE") ) startCoffeeProtocol(); else if ( !strcmp(instring,"QUIT") ) { delay(100); cl.flush(); cl.println ("Bye!"); cl.stop(); lastCheck = -checkPeriod; } else clientHelp (cl); stringSize = 0; } else if ( c >= 'A' && c <= 'Z' && stringSize < 90 ) instring[stringSize++] = c; else if ( !messagePrinted ) { clientHelp (cl); messagePrinted = true; } digitalWrite (rxPin, LOW); } else { long time = millis(); if ( time - lastCheck >= checkPeriod ) { lastCheck = time; if ( checkMail(analogRead(moodMeter)) ) display (allmail, newmail); else lastCheck = time - (3 * checkPeriod / 4); } } }