In questo articolo parliamo di come l’Arduino configura l’Ethernet Shield leggendo i parametri da un file in SD.
Con il codice seguente verrà mostrato come poter configurare l’Ethernet Shield leggendo i parametri in un file di testo salvato nell’SD.

Le caratteristiche principali dello shield sono:
- Tensione di alimentazione 5V (erogati da Arduino)
- Ethernet Controller: W5100 con 16K di buffer interno
- Velocità della connessione: 10/100Mb
- Connessione con l’Arduino su porta SPI
L’Ethernet Shield che è stato preso in considerazione integra uno slot per l’inserimento della SD com’è ben visibile nell’immagine.
Lo sketch allegato di seguito è compatibile con l’IDE 0022.
/*
* Ethernet shield attached to pins 10, 11, 12, 13
* SD pin 4
*
* pin 2 digit output
* pin 3 digit pwm
*/
#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
byte *mac = NULL;
byte *ip = NULL;
int port;
byte *gateway = NULL;
byte *subnet = NULL;
Server server = NULL;
#define ASCII_HEX_START_CHAR 65 //Index of ascii char 'A'
/************ SDCARD STUFF ************/
#define SERVER_CONFIG_FILE_NAME "CONFIG.TXT" //Server config file name
#define SRV_MAC_TOKEN "srv_mac" //Mac token in the config file
#define SRV_IP_TOKEN "srv_ip" //Ip token in the config file
#define SRV_PORT_TOKEN "srv_port" //Port token in the config file
#define SRV_GATEWAY_TOKEN "gateway" //Gateway token in the config file
#define SRV_SUBNET_TOKEN "subnet" //Subnet token in the config file
#define DFN_TIPOPORTDIGIT "portD" //Define delle porte digitali tipo input o output
#define SRV_NUMBER_TOKEN 5 //Tokens number
Sd2Card card; //Sd card objcet
SdVolume volume; //Sd card volume object
SdFile root, //Root dir of sd card
serverCfgFile; //Server config file in sd card
//Store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))
String readString;
void error_P(const char* str) {
PgmPrint("Error: ");
SerialPrintln_P(str);
if (card.errorCode()) {
PgmPrint("SD error: ");
Serial.print(card.errorCode(), HEX);
Serial.print(',');
Serial.println(card.errorData(), HEX);
}
while(1);
}
boolean initValue(String info, String value){
if(info.equals(SRV_MAC_TOKEN)){ //value si riferisce al mac
free(mac); //libera la memoria in caso di inizializzazioni precedenti
mac = strMac2byteVect(value);
if (mac == NULL)
return false;
return true;
}
if(info.equals(SRV_IP_TOKEN)){ //value si riferisce ad un ip
free(ip); //libera la memoria in caso di inizializzazioni precedenti
ip = strIp2byteVect(value);
if (ip == NULL)
return false;
return true;
}
if(info.equals(SRV_PORT_TOKEN)){
port = value.toInt();
if (port <= 1)
return false;
return true;
}
if(info.equals(SRV_GATEWAY_TOKEN)){
free(gateway);
gateway = strIp2byteVect(value);
if (gateway == NULL)
return false;
return true;
}
if(info.equals(SRV_SUBNET_TOKEN)){
free(subnet);
subnet = strIp2byteVect(value);
if (subnet == NULL)
return false;
return true;
}
return false;
}
void setup() {
Serial.begin(9600);
PgmPrint("Free RAM: ");
Serial.println(FreeRam());
pinMode(10, OUTPUT); // set the SS pin as an output (necessary!)
digitalWrite(10, HIGH); // but turn off the W5100 chip!
if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed");
// initialize a FAT volume
if (!volume.init(&card)) error("vol.init failed");
PgmPrint("Volume is FAT");
Serial.println(volume.fatType(),DEC);
if (!root.openRoot(&volume)) error("openRoot failed");
// list file in root with date and size
PgmPrintln("Files found in root:");
root.ls(LS_DATE | LS_SIZE);
Serial.print("Server parameters initializations...");
if (!serverCfgFile.open(root, SERVER_CONFIG_FILE_NAME, O_RDONLY)) error("open file failed");
char *tmpChr;
String valueStr,
infoStr;
boolean isValue;
for (boolean endof = false; !endof;){ //Ciclo sui token (righe)
isValue = false;
for(endof = (serverCfgFile.read(tmpChr, sizeof(char)) != 1); !endof && *tmpChr != 'n'; endof = (serverCfgFile.read(tmpChr, sizeof(char)) != 1)){ //Ciclo sui caratteri
if (*tmpChr == '#'){ //La riga contiene un commento
for(endof = (serverCfgFile.read(tmpChr, sizeof(char)) != 1); !endof && *tmpChr != 'n'; endof = (serverCfgFile.read(tmpChr, sizeof(char)) != 1));
break;
}
if (*tmpChr == 't' || *tmpChr == ' ') //E' stato letto il nome del tag
isValue = true;
if(isValue){ //Se è stato letto il tag viene letto il valore
if (*tmpChr != 't' && *tmpChr != ' ')
valueStr += *tmpChr;
}
else
infoStr += *tmpChr;
free(tmpChr);
}
initValue(infoStr, valueStr); //Inizializza il valore delle variabili globali
valueStr= "";
infoStr = "";
}
if (((int)gateway[0])==0 && ((int)subnet[0])==0)
Ethernet.begin(mac, ip);
else
Ethernet.begin(mac, ip, gateway, subnet);
server = Server(port);
server.begin();
PgmPrint("Free RAM: ");
Serial.println(FreeRam());
}
void loop()
{
while(1);
}
String getMACString(byte b[]){
String macStr,
tmpStr;
int length = 6;
for (int i = 0; i < length; ++i){
tmpStr = String((long)b[i],HEX);
if (tmpStr.length() == 1)
macStr += "0";
if (i < length-1)
tmpStr += ":";
macStr += tmpStr;
}
return macStr;
}
/*
* Convert the vector "b" of 4 bytes (an IP address)
* into a well formatted String.
*/
String getIPString(byte b[]){
String ipStr = "";
int length = 4;
for (int i = 0; i < length; ++i)
if (i < length-1)
ipStr += String((long)b[i]) + ".";
else
ipStr += String((long)b[i]);
return ipStr;
}
/*
* Ritorna la conversione decimale del codice
* esadecimale contenuto in str.
* Nel caso in cui str non e' un codice esadecimale ritorna -1.
*
* TODO: verifica se e' possibile rappresentare
* il codice esadecimale str con un int.
*/
int hexString2dec(String str){
int strLen = str.length(), //numero di caratteri esadecimali
tmpNumber; //intero temporaneo per l'i-esimo carattere
double result = 0; //risultato complessivo della conversione
char tmpChar; //carattere temporaneo per l'i-esimo elemento di str
str = str.toUpperCase(); //converte i caratteri in maiuscoli per il codice ascii
for (int i = 0; i < strLen; ++i){ //ciclo sui caratteri di str
tmpChar = str.charAt(i);
//conversione dell'i-esimo carattere o numero di str in intero
if (isDigit(tmpChar)) //numero
tmpNumber = atoi(&tmpChar);
else
if (isHexadecimalDigit(tmpChar)) //carattere
tmpNumber = tmpChar - ASCII_HEX_START_CHAR + 10;
else
return -1; //se il carattere non e' riconosciuto come esadecimale ritorna -1
result += pow(16, strLen - i - 1) * tmpNumber; //aggiornamento risultato
}
//per la conversione in int del risultato senza perdita di precisione
if ((result*10-((int)result*10)) >= 5)
return result+1;
else
return result;
}
/*
* Ritorna un vettore di 6 byte ottenuto dalla stringa str
* rappresentante un mac address.
* Ritorna null nel caso in cui str non rappresenta un mac address.
*/
byte *strMac2byteVect(String str){
byte *macVect = (byte *) malloc(6);
str = str.replace(':', ""); //elimina i separatori
for (int i = 0; i < 12; i += 2){ //Ciclo sulle coppie di caratteri
macVect[i/2] = hexString2dec(str.substring(i, i+2)); //Inizializza l'i-esimo byte del mac
if (macVect[i/2] == -1){
free(macVect);
return NULL;
}
}
return macVect;
}
/*
* Ritorna un vettore di 4 byte ottenuto dalla stringa str
* rappresentante un indirizzo ip.
* Ritorna null nel caso in cui str non rappresenta un indirizzo ip.
*/
byte *strIp2byteVect(String str){
String tmpStr;
int bytesCount, //contatore per il num di byte
i; //contatore per il ciclo sulla stringa
byte *ipVect = (byte *) malloc(4);
i = 0;
for (bytesCount = 0; bytesCount < 4; bytesCount++){ //Ciclo sui byte
for ( ; (str.charAt(i) != '.') && (str.charAt(i) != '