Arduino Ethernet Shield

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) != '\0'); i++)  //Ciclo sulla stringa
			tmpStr += str.charAt(i);
		ipVect[bytesCount] = tmpStr.toInt();
		tmpStr = "";
		++i;
	}

	if (bytesCount != 4){
		free(ipVect);
		return NULL;
	}
	return ipVect;
}

Nella Secure Digital create un file con il nome CONFIG.TXT ed incollate il testo seguente

##################################
# Config file for Arduino #
##################################
#Server MAC address
srv_mac 90:A2:DA:00:38:5A

#Server IP address 10.0.0.208
srv_ip 192.168.1.177

#Server Port
srv_port 80

#Gateway IP address 10.0.0.8 192.168.1.0
gateway 192.168.0.1

#Subnet IP address 255.255.255.0
subnet 255.255.255.0