Hi,
I did a small web configuration sketch (network and API) that saves settings to EEPROM.
Give it a try.
#include <EtherCard.h>
//#include <Ports.h>
#include <avr/eeprom.h>
#define DEBUG 1 // set to 1 to display free RAM on web page
#define SERIAL 1 // set to 1 to show incoming requests on serial port
#define CONFIG_EEPROM_ADDR ((byte*) 0x10)
// configuration, as stored in EEPROM
struct Config {
// ethernet interface mac address - must be unique on your network
byte usedhcp;
byte mymac[6] ;
byte ip[4];
byte mask[4];
byte gateway[4];
byte dns[4];
char domain[32];
char api[64];
byte valid; // keep this as last byte
} config
= {
// The default values
1,
{ 0x74,0x69,0x69,0x2D,0x30,0x31 },
{192,168,2,2},
{255,255,255,0},
{192,168,2,1},
{192,168,2,1},
"yourdomain.com",
"/~hariabql/sql_datalog.php?action=insert&uid=777&",
253
};
static BufferFiller bfill; // used as cursor while filling the buffer
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[1000]; // tcp/ip send and receive buffer
static void loadConfig() {
for (byte i = 0; i < sizeof config; ++i)
((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i);
if (config.valid != 253) {
config.valid = 253;
config.mymac[1] = 0x74; //{ 0x74,0x69,0x69,0x2D,0x30,0x31 };
config.mymac[2] = 0x69;
}
}
static void saveConfig() {
for (byte i = 0; i < sizeof config; ++i)
eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]);
}
#if DEBUG
static int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
#endif
static void gotPinged(byte* ptr) {
ether.printIp(">>> ping from: ",ptr);
}
void setup(){
#if SERIAL
Serial.begin(9600);
Serial.println("\n[etherNode]");
#endif
loadConfig();
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
if (false) {
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
}
else
if (!ether.staticSetup(config.ip,config.gateway,config.dns))
Serial.println("Static IP failed");
#if SERIAL
ether.printIp("My IP: ", ether.myip);
// ether.printIp("Netmask: ", ether.mymask);
ether.printIp("GW IP: ", ether.gwip);
ether.printIp("DNS IP: ", ether.dnsip);
#endif
/*
if (!ether.dnsLookup(config.domain))
Serial.println("DNS lookup of host failed");
#if SERIAL
ether.printIp("Server IP: ", ether.hisip);
#endif
//ether.parseIp(ether.hisip,"192.168.1.200"
*/
ether.registerPingCallback(gotPinged);
}
char okHeader[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n"
;
static void homePage(BufferFiller& buf) {
buf.emit_p(PSTR("$F\r\n"
"<meta http-equiv='refresh' content='5'/>"
"<title>Nanode home page</title>"
"naNode configuration page "
"- <a href='c'>network</a> - <a href='a'>API</a>"), okHeader);
long t = millis() / 1000;
word h = t / 3600;
byte m = (t / 60) % 60;
byte s = t % 60;
buf.emit_p(PSTR(
"</pre>"
"<br>Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10);
#if DEBUG
buf.emit_p(PSTR(" ($D bytes free)"), freeRam());
#endif
}
static int getIntArg(const char* data, const char* key, int value =-1) {
char temp[10];
if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0)
value = atoi(temp);
return value;
}
static char* getArg(const char* data, const char* key, int value =-1) {
char temp[64];
if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0)
return temp;
}
static void configPage(const char* data, BufferFiller& buf) {
// pick up submitted data, if present
if (data[6] == '?') {
//IP
byte i1 = getIntArg(data, "i1");
byte i2 = getIntArg(data, "i2");
byte i3 = getIntArg(data, "i3");
byte i4 = getIntArg(data, "i4");
//Gateway
byte g1 = getIntArg(data, "g1");
byte g2 = getIntArg(data, "g2");
byte g3 = getIntArg(data, "g3");
byte g4 = getIntArg(data, "g4");
//DNS
byte d1 = getIntArg(data, "d1");
byte d2 = getIntArg(data, "d2");
byte d3 = getIntArg(data, "d3");
byte d4 = getIntArg(data, "d4");
if ((i1 >= 0 && i1 <= 255 && i2 >= 0 && i2 <= 255 && i3 >= 0 && i3 <= 255 && i4 >= 0 && i4 <= 255)
&& (g1 >= 0 && g1 <= 255 && g2 >= 0 && g2 <= 255 && g3 >= 0 && g3 <= 255 && g4 >= 0 && g4 <= 255)
&& (d1 >= 0 && d1 <= 255 && d2 >= 0 && d2 <= 255 && d3 >= 0 && d3 <= 255 && d4 >= 0 && d4 <= 255))
{
// store values as new settings
config.ip[0]=i1; config.ip[1]=i2; config.ip[2]=i3; config.ip[3]=i4;
config.gateway[0]=g1; config.gateway[1]=g2; config.gateway[2]=g3; config.gateway[3]=g4;
config.dns[0]=d1; config.dns[1]=d2; config.dns[2]=d3; config.dns[3]=d4;
saveConfig();
loadConfig();
// redirect to the home page
buf.emit_p(PSTR(
"HTTP/1.0 302 found\r\n"
"Location: /\r\n"
"\r\n"));
return;
}
}
// else show a configuration form
buf.emit_p(PSTR("$F\r\n"
"<h3>naNode network settings</h3>"
"<form>"
"<p>"
"IP <input type=text name=i1 value='$D' size=3>.<input type=text name=i2 value='$D' size=3>.<input type=text name=i3 value='$D' size=3>.<input type=text name=i4 value='$D' size=3> <br>"
"GW <input type=text name=g1 value='$D' size=3>.<input type=text name=g2 value='$D' size=3>.<input type=text name=g3 value='$D' size=3>.<input type=text name=g4 value='$D' size=3> <br>"
"DNS <input type=text name=d1 value='$D' size=3>.<input type=text name=d2 value='$D' size=3>.<input type=text name=d3 value='$D' size=3>.<input type=text name=d4 value='$D' size=3> <br>"
"</p>"
"<input type=submit value=Set> <input type=button value=Back onclick='history.go(-1)'>"
"</form>"),okHeader,
config.ip[0],config.ip[1],config.ip[2],config.ip[3],
config.gateway[0],config.gateway[1],config.gateway[2],config.gateway[3],
config.dns[0],config.dns[1],config.dns[2],config.dns[3] );
}
static void apiPage(const char* data, BufferFiller& buf) {
// pick up submitted data, if present
if (data[6] == '?') {
char* temp=getArg(data, "domain");
for(int i=0;i<sizeof(config.domain);i++) {
config.domain[i]=temp[i] ;
}
temp=getArg(data, "api");
ether.urlDecode(temp);
for(int i=0;i<sizeof(config.api);i++) {
config.api[i]=temp[i] ;
}
saveConfig();
loadConfig();
// redirect to the home page
buf.emit_p(PSTR(
"HTTP/1.0 302 found\r\n"
"Location: /\r\n"
"\r\n"));
return;
}
// else show a configuration form
buf.emit_p(PSTR("$F\r\n"
"<h3>naNode API settings</h3>"
"<form>"
"<p>"
"Domain <input type=text name=domain value='$S' size=32><br>"
"API <input type=text name=api value='$S' size=64><br>"
"</p>"
"<input type=submit value=Set> <input type=button value=Back onclick='history.go(-1)'>"
"</form>"),okHeader,
config.domain, config.api );
}
void loop(){
word len = ether.packetReceive();
word pos = ether.packetLoop(len);
// check if valid tcp data is received
if (pos) {
bfill = ether.tcpOffset();
char* data = (char *) Ethernet::buffer + pos;
#if SERIAL
// Serial.println(data);
#endif
// receive buf hasn't been clobbered by reply yet
if (strncmp("GET / ", data, 6) == 0)
homePage(bfill);
else if (strncmp("GET /c", data, 6) == 0)
configPage(data, bfill);
else if (strncmp("GET /a", data, 6) == 0)
apiPage(data, bfill);
else
bfill.emit_p(PSTR(
"HTTP/1.0 401 Unauthorized\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<h1>401 Unauthorized</h1>"));
ether.httpServerReply(bfill.position()); // send web page data
}
}
Re: naNode web configuration sketch
Awesome, thanks mharizanov, looks great