// Ethernet connect christmas light controller // Written by Brian Schulteis, Creative Commons License, 2011 // For use on an ENC28J60 ethernet chip with thiseldo's Ethershield library // Written for use on a Teensy++ 2.0, using Arduino 1.0 #include "EtherShield.h" static byte mymac[6] = { 0x54,0x55,0x58,0x10,0x00,0x25}; static byte myip[4] = { 192,168,1,1}; // This will be the IP address of the Arduino static byte mynetmask[4] = { 255,255,255,0}; // Netmask used on my network static byte gwip[4] = { 192,168,1,2}; // IP Address of my firewall on my LAN #define MYNETPORT 6058 // I picked some random port number for this to answer on. Not exactly sure why. #define BUFFER_SIZE 550 // default setting in the example sketch I grabbed for the ethershield static byte buf[BUFFER_SIZE+1]; const int speeds[8] = { 64,96,128,192,256,320,400,512 }; // Array containing the speed settings. byte currentMode = 1; // Start in mode 1 int currentSpeed = 64; // default to slow speed byte lightVariable = 1; // initialize the counters byte tempVariable = 1; EtherShield es=EtherShield(); // Object oriented programming FTW.. I love libraries. void changeMode(char* modeRequested) { currentMode = atoi(modeRequested); if ((currentMode > 8) or (currentMode < 1)) { currentMode=1; } for (int i=9; i < 20; i++) { digitalWrite(i, LOW); // It's best to turn all the lights off before starting a different mode. } lightVariable = 1; tempVariable = 1; tone(7, (100 * currentMode), 200); // Give a beep when the mode is changed, vary frequency based on requested mode. } void changeSpeed(char* speedRequested) { if ((atoi(speedRequested) > 0) and (atoi(speedRequested) < 9)) { currentSpeed = speeds[(atoi(speedRequested)-1)]; tone(7, (1200 * atoi(speedRequested)), 200); // Same deal, beep for speed changes, varied based on requested speed. } } boolean checkEthernet() { int plen, dat_p; // read packet, handle ping and wait for a tcp packet: dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf)); /* dat_p will be unequal to zero if there is a valid * http get */ if (dat_p) { if (buf[dat_p+5] == 'm') { char temp = buf[dat_p+6]; changeMode(((char *)&temp)); dat_p=es.ES_fill_tcp_data_p(buf,0,PSTR("")); es.ES_www_server_reply(buf,dat_p); // send web page data dat_p=0; return(true); // True meaning "yes, there was a mode change" } if (buf[dat_p+5] == 's') { char temp = buf[dat_p+6]; changeSpeed(((char *)&temp)); dat_p=es.ES_fill_tcp_data_p(buf,0,PSTR("")); es.ES_www_server_reply(buf,dat_p); // send web page data dat_p=0; return(false); // False, no mode change, speed change will get automatically rolled in to the main delay loop. } } return(false); // False, nothing received from the ethernet chip. } void modeOne() { // This is a simple chasing pattern. digitalWrite((lightVariable + 9), HIGH); if (lightVariable < 10) { // there are actually two on at any one time, if we're at the end, we need to go back to the beginning. digitalWrite((lightVariable + 10), HIGH); } else { // Pin 10 being the beginning. digitalWrite(10, HIGH); } if (lightVariable == 1) { // Same kind of deal with turning them off, if we're at 1, the last light may still be on digitalWrite(19, LOW); // so turn it off. } else { digitalWrite((lightVariable + 8), LOW); } if (lightVariable == 10) { lightVariable= 1; } else { lightVariable++; } } void modeTwo() { // Start at ends, light up towards middle, then start in middle and turn off towards ends. if (lightVariable < 6) { // 1 - 5 turns them on digitalWrite(lightVariable + 9, HIGH); digitalWrite(20 - lightVariable, HIGH); } else { // 6 through 10 turns them off, like ships passing in the night. digitalWrite(lightVariable + 9, LOW); digitalWrite(20 - lightVariable, LOW); } if (lightVariable == 10) { lightVariable= 1; } else { lightVariable++; } } void modeThree() { // The ever popular Knight Rider if (lightVariable > 10) { // Go left if (lightVariable == 11) { tempVariable = 10; // I think this will get rewritten and not use tempVariable. } else { tempVariable--; } if (tempVariable > 1) { digitalWrite(tempVariable + 8, HIGH); digitalWrite(tempVariable + 9, LOW); } else { digitalWrite(tempVariable + 8, LOW); } if (tempVariable == 10) { digitalWrite(tempVariable + 9, LOW); } } else { // Go right digitalWrite(lightVariable +9, HIGH); if (lightVariable > 1) digitalWrite(lightVariable + 8, LOW); } if (lightVariable == 20) { lightVariable= 2; } else { lightVariable++; } } void modeFour() { // Police light bar style if (lightVariable < 6) { if (lightVariable == 1) { for (int h = 15; h < 20; h++) { digitalWrite(h, LOW); } } if ((lightVariable % 2) == 0) { for (int h = 9; h < 15; h++) { digitalWrite(h, HIGH); } } else { for (int h = 9; h < 15; h++) { digitalWrite(h, LOW); } } } else { if ((lightVariable % 2) == 0) { for (int h = 15; h < 20; h++) { digitalWrite(h, HIGH); } } else { for (int h = 15; h < 20; h++) { digitalWrite(h, LOW); } } } if (lightVariable == 10) { lightVariable= 1; } else { lightVariable++; } } void modeFive() { // All on, then all back off in a VU meter kind of way if (lightVariable < 11) { // Turning them on digitalWrite(lightVariable + 9, HIGH); } else { // Turn them back off digitalWrite(30 - lightVariable, LOW); } if (lightVariable == 20) { lightVariable= 1; } else { lightVariable++; } } void modeSix() { // double chaser mode if (tempVariable == lightVariable) { // This can only happen when this mode is first engaged. tempVariable = 5; } digitalWrite(lightVariable + 9, HIGH); digitalWrite(tempVariable + 9, HIGH); if (lightVariable > 1) { digitalWrite(lightVariable + 8, LOW); } else { digitalWrite(19, LOW); } if (tempVariable > 1) { digitalWrite(tempVariable + 8, LOW); } else { digitalWrite(19, LOW); } if (lightVariable == 10) { lightVariable= 1; } else { lightVariable++; } if (tempVariable == 10) { tempVariable= 1; } else { tempVariable++; } } void modeSeven() { // Start at ends, light up towards middle, then start at ends and turn off towards middle if (lightVariable < 6) { // 1 - 5 turns them on digitalWrite(lightVariable + 9, HIGH); digitalWrite(20 - lightVariable, HIGH); } else { // 6 through 10 turns them off, like ships passing in the night. tempVariable=lightVariable-5; digitalWrite(tempVariable + 9, LOW); digitalWrite(20 - tempVariable, LOW); } if (lightVariable == 10) { lightVariable= 1; } else { lightVariable++; } } void modeSevenb() { // Odd man out mode - No longer used digitalWrite(lightVariable + 9, HIGH); if (lightVariable<10) { digitalWrite(lightVariable + 10, LOW); } if (lightVariable == 2) { digitalWrite(lightVariable + 8, LOW); // When we're starting the evens, we need to make sure to turn the first one off. } if ((lightVariable==9) or (lightVariable==10)) { if (lightVariable==9) { // We're either doing all odd lightVariable = 2; } if (lightVariable==10) { // or all even lightVariable = 1; // Do the opposite the next time around. } } else { lightVariable += 2; } } void modeEight() { // binary mode 10 bit, 2047 total if (!lightVariable) { // See what I did there? -- if we've come back around to 0 if (digitalRead(18)) { // if bit 9 is already on if (digitalRead(19)) { // and if bit 10 is already on digitalWrite(18, LOW); // we got here because they're both on. We've gone all the way around digitalWrite(19, LOW); } else { digitalWrite(19, HIGH); // we got here because only 18 was on, this is the first lap digitalWrite(18, LOW); } } else { digitalWrite(18, HIGH); // if 9 wasn't on, it's time to turn it on, we're at 511 or 1535, doesn't really matter } PORTC = lightVariable; // this turns off all the other bits (1-8) lightVariable++; } else { PORTC = lightVariable; lightVariable++; // lightVariable is a byte, so it goes 0-255, with automatic rollover.. } } void setup(){ for (int i=9; i < 20; i++) { pinMode(i, OUTPUT); } es.ES_enc28j60SpiInit(); // initialize enc28j60 es.ES_enc28j60Init(mymac,20 ); // init the ethernet/ip layer: es.ES_init_ip_arp_udp_tcp(mymac,myip, MYNETPORT); // Serial.begin(9600); } void loop(){ unsigned long currentTime = millis(); while ((!checkEthernet()) and ((millis()-currentTime) < currentSpeed)) { /* I think this is an elegant way to delay, while checking for incoming commands over ethernet. any speed changes automatically get rolled it, a mode change will break it out of this delay automatically without any more delay. After the appropriate delay has elapsed, or it otherwise breaks out of this delay loop, it calls the proper routine which makes one step forward along it's pattern's progression. It then returns to this delay. Totally elegant. */ } switch (currentMode) { case 1: modeOne(); break; case 2: modeTwo(); break; case 3: modeThree(); break; case 4: modeFour(); break; case 5: modeFive(); break; case 6: modeSix(); break; case 7: modeSeven(); break; case 8: modeEight(); break; } }