// delai
prog_char site[] PROGMEM = "wolpobox.logsm.net";
prog_char url[100] PROGMEM = "/index.php" ;
#include <Time.h>
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <Arduino.h>
#include <EtherCard.h>
#include <MemoryFree.h>
//#define VERSION "WOWlanCloud 20140107-0600"
prog_char VERSION[] PROGMEM= "WOWlanCloud 20140107-0600" ;
//prog_char VERSION[] PROGMEM= "WOWlanCloud 20140106-1500" ;
#define PERIODEMS 10000
#define WAIT 0
#define WOLLISTENPORT 9
#define WOLTARGETPORT 9
#define WOLOUTPORT 100
// EEPROM map
#define eRESET 0 // compte les 4 off/on poufl100r hard reset
#define eDEBUG 1
#define eTRACE 2
#define ePROXY 3
#define eSERVER 4
#define eCLOUD 5
#define DEBUG EEPROM.read(eDEBUG)
#define TRACE 1==EEPROM.read(eTRACE)
#define SERVER true // EEPROM.read(eSERVER)
#define PROXY 1==EEPROM.read(ePROXY)
#define CLOUD 1==EEPROM.read(eCLOUD)
#define PHYBINAEEPROM 10 // fixe 6
#define eIP PHYBINAEEPROM+6 // fixe 4
#define eGW PHYBINAEEPROM+10 // fixe 4
#define eDNS PHYBINAEEPROM+14 // fixe 4
#define eMASK PHYBINAEEPROM+18 // fixe 4
#define NAMEEEPROM eMASK+4 // variable, max 20, null terminatef
#define LONNAMEEEPROM 21
#define MAILTOEEPROM NAMEEEPROM+LONNAMEEEPROM // variable, null terminated, max 60
#define LONMAILTO 61
#define URLEEPROM MAILTOEEPROM+LONMAILTO
#define LONURLEEPROM 60
#define SITEEEPROM URLEEPROM+LONURLEEPROM
#define LONSITEEEPROM 60
#define EEPROMUSED SITEEEPROM+LONSITEEEPROM
//
#define true 1
#define false 0
// ethernet interface mac address, must be unique on the LAN
static byte mybinarymac[] = { 0,1,2,3,4,5 }; // if not in EEPROM
#define LBUF 600
static byte unb ; // for ucase
static uint32_t timer;
static byte broadcast[4] = {255,255,255,255} ; //{255,255,255,255};
static int n=0; // count http requests over cloud
static int ok=true; // global abandon
static int lenquoi;
static int termine; // 1 when found , 1 when magic created
static int eq; // progress in getvalue
static int iii; // common use for loop
static int ipv;
static int lon; // divers copies GAFFE souvent aussi nom d'un argument
// byte mac[6] ;
const char alphabet[17] ="0123456789ABCDEF";
#define LHEXA 102 // taille du paquet magique!
char sandbox[LHEXA]="";
byte Ethernet::buffer[LBUF]; //??????
BufferFiller bfill; //???????
static int udpon=0; // protect reentrance
int write_str_eeprom( char* source ,int address, int allowed){
if (strlen(source)>allowed) {
Serial.println("bug1");
return false;
}
for (iii=0;iii<1+strlen(source);iii=iii+1) EEPROM.write(address+iii,(byte)source[iii]);
return true;
}
void write_binary_eeprom(int lon, int address, int allowed){
if (lon>allowed) {
Serial.println("bug2");
return;
}
for (iii=0;iii<lon;iii=iii+1) EEPROM.write(address+iii,(byte)sandbox[iii]);
}
int read_str_eeprom(char* target,int address, int allowed,int appel){
// Serial.print(address);
// Serial.println("<-ad");
// int lonread=0;
lon=0;
iii=0;
target[0]=0;
if (EEPROM.read(address)==255) {
Serial.println("##255 ");
return false;
}
while (lon==0) {
if (iii>allowed) {
Serial.println("out");
return false;
}
target[iii]=(char)EEPROM.read(address+iii);
if (target[iii]==0) lon=iii;
iii=iii+1;
}
return true;
}
void prtoptions(){
//Serial.print("Options: Debug, Trace, Cloud, Server, Proxy:");
Serial.print("D T C S P ");
Serial.print (DEBUG);
Serial.print (TRACE);
Serial.print (CLOUD);
Serial.print (SERVER);
Serial.println (PROXY);
Serial.print("free=");
Serial.println(freeMemory());
}
void prttime(int call ){
time_t t=now();
Serial.println("");
Serial.print (call);
Serial.print(":");
Serial.print(t);
Serial.print (" now>>");
Serial.print(year(t));
Serial.print("/");
Serial.print(month(t)); // The month now (1-12)
Serial.print("/");
Serial.print(day(t)); // The day now (1-31)
Serial.print("-");
Serial.print(hour(t)); // The hour now (0-23)
Serial.print(":");
Serial.print(minute(t)); // The minute now (0-59)
Serial.print(":");
Serial.print(second(t)); // The second now (0-59)
Serial.println("");
}
void blink(int led, int secondes, int on, int off){
iii=secondes*1000;
while (iii>0){
Serial.print(".");
digitalWrite(led, 0); // turn the LED on (HIGH is the voltage level)
delay(on); // wait for a second
digitalWrite(led, 1); // turn the LED off by making the voltage LOW
delay(off); // wait for a second
iii=iii-on-off;
}
}
void raz(){
Serial.println("Reeseted!");
//
for (iii=0;iii<EEPROMUSED;iii=iii+1) EEPROM.write(iii,255);
// server
EEPROM.write(eRESET,0);
EEPROM.write(eSERVER,true);
blink(13,20,500,500);
}
void chkhardreset(int s){
int rc;
rc=1+EEPROM.read(eRESET);
EEPROM.write(eRESET,rc);
if (rc>=4) raz();
else {
blink(13,s,100,900);
EEPROM.write(eRESET,0);
}
}
void prtx2(int n){
Serial.print(alphabet[n/16]);
Serial.print(alphabet[n%16]);
}
void setup () {
Serial.begin(9600);
// write_str_eeprom("ZORGLUB",NAMEEEPROM,LONNAMEEEPROM);
EEPROM.write(eSERVER,1);
Serial.print(EEPROM.read(eRESET));
Serial.print(" waitting ");
Serial.print(WAIT);
Serial.println("\" !");
chkhardreset(WAIT);
prttime(1);
// check EEprom for mc address
termine=false;
for (iii=1;iii<6;iii=iii+1) if (EEPROM.read(PHYBINAEEPROM+iii)!=255) termine=true;
if (!termine){
Serial.println("no previous PHY in EEPROM, added");
for (iii=0;iii<6;iii=iii+1) EEPROM.write(PHYBINAEEPROM+iii, mybinarymac[iii]);
}
for (iii=0;iii<6;iii=iii+1) {
prtx2((byte)mybinarymac[iii]);
Serial.print(":");
}
Serial.println(" <---- MAC used");
// Serial.println(VERSION);
prtprog(VERSION);
prtoptions();
Serial.print("Ethernet Controller: ");
if (ether.begin(sizeof Ethernet::buffer, mybinarymac,10) == 0) {
ok=false;
Serial.println( "Access Failed.");
} else Serial.println("Ok.");
// ether.staticSetup(myip);
if (ok) {
if (EEPROM.read(eIP)!=255 ){
Serial.println("Using fixed Ip from EEPROM");
for (iii=0;iii<4;iii=iii+1) {
ether.myip[iii]=EEPROM.read(eIP+iii);
ether.gwip[iii]=EEPROM.read(eGW+iii);
ether.dnsip[iii]=EEPROM.read(eDNS+iii);
}
} else{
Serial.print("Trying Dhcp: ");
if (!ether.dhcpSetup()) {
Serial.println("failed.");
// setting fixed ip
Serial.println("Using emergency address.");
ether.myip[0]=192;
ether.myip[1]=168;
ether.myip[2]=0;
ether.myip[3]=100;
ether.mymask[0]=255 ;
ether.mymask[1]=255;
ether.mymask[2]=255;
ether.mymask[3]=0;
} else Serial.println("Ok.");
}
}
if (ok){
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("MASK:", ether.mymask);
ether.printIp("DHCP:", ether.dhcpip);
ether.printIp("DNS: ", ether.dnsip);
if (CLOUD){
if (!ether.dnsLookup(site )) {
Serial.println(" failed test ");
//ok=false;
}
if (ok) {
ether.printIp(" ", ether.hisip);
}
if (ok) {
ether.printIp(" ", ether.hisip);
}
}
}
//register udpSerialPrint() to port 1337
if (ok && PROXY) {
ether.udpServerListenOnPort(&udpReceivedCallback, WOLLISTENPORT);
Serial.print("listen wol on UDP port: ");
Serial.println(WOLLISTENPORT);
}
Serial.println("Andiamo!");
}
// return used part
word getvalue(word off,word len,char retour[],int lenret,char pin[]){
lenquoi=strlen(pin);
termine=false; // true whenpin found
iii=off-1;
while (!termine) {
eq=0;
iii=iii+1;
if (iii==len) {
//termine=true;
// start pin not found
// Serial.println("pas trouve initiale en bour");
retour[0]=0;
return len;
}
while (!termine && Ethernet::buffer [iii+eq]==pin[eq]){
// Serial.print (pin[eq]);
// Serial.println("trouve une ettre");
eq=eq+1;
if (eq>=lenquoi ) termine=true;
// pin not found
if (iii+eq>len) {
retour[0]=0;
return len;
}
}
}
// Serial.println("");
// get value
termine=false;
ipv=0;
// Serial.println("trouve pin ");
//Serial.print("reponse=");
while (!termine && iii+eq+1+ipv<len && ipv<lenret ) {
retour[ipv]=Ethernet::buffer [iii+eq+ipv];
if (retour[ipv]==';') {
// Serial.println("ok ; final ");
retour[ipv]=0;
termine=true;
}
ipv=ipv+1;
}
if (!termine) {
// Serial.println ("no colon found");
// ok=false;
retour[0]=0;
return len;
}
return iii+eq+ipv;
}
void setune(int v,char* mot,int ad){
if (0==strcmp(sandbox,mot)){
EEPROM.write(ad,v);
Serial.print(mot);
Serial.print(" ad=");
Serial.print(ad);
Serial.print(" mis a ");
Serial.println(EEPROM.read(ad));
}
}
void option(int v){
setune(v,"DEBUG",eDEBUG);
setune(v,"TRACE",eTRACE);
setune(v,"CLOUD",eCLOUD);
setune(v,"PROXY" ,ePROXY);
setune(v,"SERVER",eSERVER);
if (TRACE) prtoptions();
}
void ucase(word off,word len){
// search for pin:
for (iii=off;iii<len;iii=iii+1){
unb= Ethernet::buffer [iii];
if (unb>96 && unb <=96+26) Ethernet::buffer [iii]=unb-32;
}
}
int doip4(int offstart,int offend , char* sandbox, int e, char*verbe){
getvalue(offstart,offend,sandbox,100,verbe);
if (strlen(sandbox)>0) {
addstrtosandbox(".");
int ifin=-1;
for (int i4=0;i4<4;i4=i4+1){
int ideb=ifin+1;
int ii=0;
int i1=0;
while (sandbox[ideb+ii]!='.') {
i1=10*i1+(int)sandbox[ideb+ii]-48;
ii=ii+1;
}
ifin=ideb+ii;
EEPROM.write(e+i4,i1);
}
}
}
void domax(int offstart,int offend,const char* qui){
// off et len pointent debur et fin de zone utils
if (DEBUG) {
Serial.println(qui);
Serial.println("[[[[[[");
for (iii=offstart;iii<offend;iii=iii+1) Serial.print((char ) Ethernet::buffer[iii]);
Serial.println("]]]]]]");
}
// check print full packet
ucase(offstart,offend);
//Serial.println("up");
// keep options
// --------------------------- repetable commands
word start;
sandbox[0]='.';
sandbox[1]=0;
start=offstart;
while (strlen(sandbox)>0) {
start=getvalue(start,offend,sandbox,100,"SET:");
if (strlen(sandbox)>0) option(true) ; // optionis in sandbox
}
sandbox[0]='.';
sandbox[1]=0;
start=offstart;
while (strlen(sandbox)>0) {
start=getvalue(start,offend,sandbox,100,"CLR:");
if (strlen(sandbox)!=0) option(false) ; // optionis in sandbox
}
sandbox[0]='.';
sandbox[1]=0;
start=offstart;
while (strlen(sandbox)>0) {
start=getvalue(start,offend,sandbox,100,"PIN:");
if (strlen(sandbox)>0) {
if (TRACE) Serial.println(sandbox);
char* sep=strchr(sandbox,':');
if (TRACE) {
Serial.print("arg:");
Serial.print (sep-sandbox);
}
sandbox[sep-sandbox]=0;
if (TRACE) {
Serial.print("pin:");
Serial.print (sep-sandbox);
}
if (TRACE) {
Serial.print("val:");
Serial.println (sep);
}
}
}
// simple commands
start=getvalue(offstart,offend,sandbox,100,"RAZ:");
if (start<offend) {
Serial.print ("raz:!");
Serial.println("");
raz();
}
start=getvalue(offstart,offend,sandbox,100,"MAILTO:");
if (strlen(sandbox)>0) {
write_str_eeprom(sandbox,MAILTOEEPROM,LONMAILTO);
Serial.print ("mailto:");
Serial.println(sandbox);
}
start=getvalue(offstart,offend,sandbox,100,"TIME:");
if (strlen(sandbox)>0) {
uint32_t tt= atol(sandbox);
setTime(tt);
// Serial.println(tt);
// Serial.println(now());
if (TRACE) {
Serial.println("");
prttime(2);
}
}
getvalue(offstart,offend,sandbox,100,"PHY:");
if (strlen(sandbox)>0){
if (strlen(sandbox)!=12) Serial.println("wrong mac");else {
// 12 to 6
if (h2d(sandbox[1])%2==1) {
Serial.println("rejected");
} else {
for (iii=0;iii<6;iii=iii+1) EEPROM.write(PHYBINAEEPROM+iii, h2d(sandbox[2*iii])*16+h2d(sandbox[2*iii+1]) );
}
}
}
doip4(offstart,offend,sandbox,eIP,"IP:");
doip4(offstart,offend,sandbox,eGW,"GW:");
doip4(offstart,offend,sandbox,eDNS,"DNS:");
doip4(offstart,offend,sandbox,eMASK,"MASK:");
getvalue(offstart,offend,sandbox,100,"ID:");
getvalue(offstart,offend,sandbox,100,"NAME:");
if (strlen(sandbox)>0) {
write_str_eeprom(sandbox,NAMEEEPROM,LONNAMEEEPROM );
}
/*
getvalue(offstart,offend,sandbox,100,"URL:");
if (strlen(sandbox)>0) {
write_str_eeprom(sandbox,SITEEEPROM,LONSITEEEPROM );
Serial.println("site stored");
}
*/
getvalue(offstart,offend,sandbox,100,"TOKEN:");
getvalue(offstart,offend,sandbox,100,"MAC:");
buildmagic(); // will check sandbox! and set termine
// if (termine) sendmagic(magic,102) later
}
// called when the client request is complete
static void cloud_callback (byte status, word offstart, word lenpacket) {
if (TRACE||DEBUG){
Serial.print(offstart);
Serial.print(" ");
Serial.print(lenpacket);
Serial.println("<-- off lren");
}
domax(offstart,offstart+lenpacket,"cloud");
if (termine) sendmagic();
}
//callback that echo received packet (magic!)
void udpReceivedCallback(word port, byte ip[4], const char *data, word len) {
if (!udpon) { // protect again re-entrance'
udpon=true;
if (TRACE) ether.printIp("From: ", ip);
if (DEBUG){
Serial.println(" Raw: ");
Serial.println(data);
}
memcpy(sandbox,data,102);
sendmagic();
udpon=false;
}
}
static word homePage(int off,int len,int ok) {
n=n+1; // compte les appels à homePage
uint32_t t;
t=now();
bfill = ether.tcpOffset();
bfill.emit_p(PSTR( //???????
"HTTP/1.0 200 OK\r\n"
// "Content-Type: text/html\r\n"
// "Pragma: no-cache\r\n"
"\r\n"
// "<meta http-equiv='refresh' content='1'/>"
"<title>Po server</title>"
"<h1>$D:$D:$D $D/$D/$D</h1> n= $D ok=$D time=$D "),
hour(t), minute(t), second(t) ,day(t),month(t),year(t), n,ok); //???????
return bfill.position();
ok=0;
}
int h2d(char h){
char* ih= strchr(alphabet,h);
char* i0= strchr(alphabet,'0');
int ici=ih-i0;
if (ici>15) ici=ici-6;
return ici;
}
void buildmagic (){
termine=false;
if (strlen(sandbox)!=12) return;
if (DEBUG) Serial.println(" build magic mac:");
termine=true;
for (iii=0;iii<12;iii++) {
char unc=sandbox[iii];
Serial.print(unc);
if (unc<'0' || unc>'F' || (unc>'9' && unc<'A')) termine=false;
}
if (!termine) return;
// 12 bytes contain hexa PHY
// creat 6 binary byteaddress à 12
for (iii=0;iii<6;iii=iii+1){
sandbox[12+iii]=h2d(sandbox[2*iii])*16+h2d(sandbox[2*iii+1]);
// repeat
for (int repe=1;repe<16;repe=repe+1) sandbox[6*repe+iii]=sandbox[12+iii];
// ethernet braodcast
for (int repe=0;repe<6;repe=repe+1) sandbox[repe]=255;
}
}
void sendmagic(){
ether.sendUdp(sandbox, 102, WOLOUTPORT, broadcast, WOLTARGETPORT);
}
int addstrtosandbox(char* quoi){
int lon=strlen(quoi);
int lonmac=strlen(sandbox);
if (lon+lonmac>=LHEXA) return false;
for (iii=0;iii<1+lon;iii=iii+1) sandbox[lonmac+iii]=quoi[iii];
return true;
}
int addeepromtosandbox(int ad){
int lon=0;
int lonmac=strlen(sandbox);
iii=ad;
while (lon==0 && (iii-ad)<(LHEXA-lonmac)) {
if (EEPROM.read(iii)==0) lon=iii-ad;
iii=iii+1;
}
if (lon+lonmac>=LHEXA) {
Serial.println("deborde");
return false;
}
for (iii=0;iii<1+lon;iii=iii+1) sandbox[lonmac+iii]=EEPROM.read(ad+iii);
return true;
}
void prtprog(char* t){
iii=0;
while (pgm_read_byte_near(t + iii)!=0) {
Serial.print((char) pgm_read_byte_near(t + iii));
iii=iii+1;
}
Serial.println("");
}
void loop () {
iii=ether.packetReceive();
ether.packetLoop(iii);
if (!ok) return;
if (PROXY) {
// nothing
}
if (CLOUD && ( millis() > timer) ) {
timer = millis() + PERIODEMS;
sandbox[0]=0;
addstrtosandbox("?action=get&id=");
addeepromtosandbox(NAMEEEPROM);
Serial.print("<<<<");Serial.print(sandbox);Serial.println(">>>>");
ether.browseUrl(url , sandbox,site , cloud_callback);
ok=false;
Serial.println("ok false");
} // end cloud
if (SERVER){
word len = ether.packetReceive();
word pos = ether.packetLoop(len);
if (pos>0) {// check if valid tcp data is received
domax(pos,pos+len,"http");
ether.httpServerReply(homePage(pos,pos+len,termine)); // send web page data
if (termine) sendmagic();
}
}
}