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) != '