Salve a tutti..
Come da titolo pensavo di realizzare una sorta di "network scanner"..l'idea è quella di utilizzare una shield ethernet per collegare l'arduino al router ed avere in out su un display 20x4 gli hosts collegati alla rete, con rispettivi ip\mac..
In giro per la rete non ho trovato tanto a riguardo,o almeno...per quanto riguarda gli ip è una cosa abbastanza semplice, visto che in realtà basta pingarli tutti e vedere chi risponde..ma per il mac address si va incontro ad un problema...
Oltre a qualcuno che faceva riferimento alle richieste ARP, che contengono il mac e vengono trasmesse in broadcast sulla rete locale, se non ricordo male, non ho trovato nessun altro riferimento..
Qualche alternativa? o dite che c'è bisogno di lavorare su queste richieste ARP? in tal caso in che modo gestisco le richieste in broadcast?
In realtà non è così difficile, se osservi la libreria w5100
l'istruzione W5100.readSnDHAR(socket, addr); restituisce il MAC remoto del client connesso a quel determinato socket
l'istruzione W5100.readSnDIPR(socket, addr); restituisce l'IP remoto del client connesso a quel determinato socket
ho fatto un test per verificare quanto detto
Socket#0:0x14 - Porta 80 IP Client:192.168.2.114 - MAC xx:xx:xx:3E:22:AC: Porta (64179) - Status Socket :0x0
Socket#1:0x17 - Porta 9990 IP Client:192.168.2.100 - MAC xx:xx:xx:28:F0:A2: Porta (50368) - Status Socket :0x5
Socket#2:0x17 - Porta 9990 IP Client:192.168.2.114 - MAC xx:xx:xx:xx:22:AC: Porta (64184) - Status Socket :0x5
Socket#3:0x22 - Porta 8888 IP Client:132.163.4.101 - MAC 54:E6:FC:CE:75:A4: Porta (123) - Status Socket :0x4
Close frame received. Closing in answer.
Disconnecting
Ho verificato sulle macchine e sono corretti (il sock_3 è connesso al server NTP della INRIM non è il mio)
Quindi fai un ping verso l'ip che ti interessa dentro la rete o fuori con ICMPPing.h e leggi i registri del chip W5100
ciao
Perfetto..ti ringrazio per la dritta..quindi il tutto è fattibile..più che altro non ho capito come richiamare quelle funzioni...mi basta includere la libreria "w5100.h" e richiamarle?
Se così fosse, potrei ipoteticamente includere all'interno di un ciclo for (che pinga tutti gli ip nella sottorete), e leggere volta per volta il registro del w5100 per recuperare l'ip?
o non è il modo corretto per recuperare i mac address?
esatto.
x iscrizione
Grazie all'aiuto di @pablos sono riuscito a tirare su uno sketck che va a pingare un range di indirizzi indirizzi ip in rete locale, determinati dai due valori di range impostabili, che stampa su serial monitor le informazione sul ping fatto e nel caso riceva risposta stampa le informazioni e il mac address dell'host collegato..(a breve posterò lo sketck!)
Ora il problema..decido di ampliare il lavoro, includendo una lista di mac address, letti da file .txt su sd, e caricati su un array di stringhe char, giusto per eseguire un confronto e assocciare un nome ad un determinato host..
Il problema lo riscontro quando devo eseguire il confronto..da una parte ho un array di uint8_t quindi di byte, e dall'altra una stringa char..da una parte(byte array) quando stampo il valore me lo ritrovo in HEX, dall'altra(stringa char) mi ritrovo i valori scritti in decimale(sempre che io non definisca il formato di stampa)..questo comporta che nel confronto avrò una differenza tra le due stringhe..che soluzione??ho provato eseguendo dei cast ma non ho ottenuto nulla..
Ringrazio in anticipo tutti per l'aiuto!
p.s. @pablos Perchè hai modificato il post dove avevi messo l'esempio cancellandolo completamente??scusa ma non ne ho capito il senso..
Converti in decimale quello che leggi da sd e lo confronti. Ho abbreviato lo scan 0-255 da 4 minuti a 30 secondi. Riguardo al post che dire .... se tu non avessi avuto un altro problema (dopo una settimana) non saresti passato nemmeno a dire ciao... però il post l'hai letto dopo 12 minuti, mentre io mi sono studiato il datasheet, scritto il prog, testato e pubblicato. Tranquillo sono io che sbaglio a sbattermi troppo XD XD XD
Ciao
Avevo già pensato di risolverlo in questo modo..ma non sono riuscito a cavarne piedi..anche provando a convertire quello letto dal registro del wiznet..
Comunque per quanto riguarda la mia risposta..sono riuscito due giorni fa ad implementare quello che tu avevi scritto, proprio per il fatto che lavoro per 12 ore ogni giorno, e non sempre ho la possibilità di dedicarmi ai miei hobby..Avrei avuto modo di postare una risposta e il risultato ottenuto appena possibile....a prescindere il tuo lavoro non sarebbe servito solo a me, ma a chiunque avrebbe cercato in riferimento a questo argomento, visto la scarsa quantità e qualità di materiale reperibile.
Come giusto che sia, allego quello che sono riuscito (nella mia modestità di programmatore) a portar su, facendo riferimento al codice originario postato da 'pablos':
#include <SPI.h>
#include <Ethernet.h>
#include <ICMPPing.h>
#include "utility/socket.h"
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte ip[] = {192,168,1,16}; // IP scelto per la scheda ethernet
byte pingAddrS[] = {192,168,1,1}; // Ip di partenza ping range
byte pingAddrE[] = {192,168,1,254}; //Ip finale ping range
SOCKET pingSocket = 0;
char buffer [256];
ICMPPing ping(pingSocket, (uint16_t)random(0, 255));
byte sock=0;
void setup()
{
Ethernet.begin(mac, ip);
Serial.begin(9600);
}
void loop()
{
for (byte i=pingAddrS[3]; i<=pingAddrE[3]; i++)
{
byte pingAddrTemp[]= { 0, 0, 0, 0,};
for (int x=0; x<3; x++)
{
pingAddrTemp[x]=pingAddrS[x];
}
pingAddrTemp[3]=i;
ICMPEchoReply echoReply = ping(pingAddrTemp, 1);
if (echoReply.status == SUCCESS)
{
sprintf(buffer,
"Reply[%d] from: %d.%d.%d.%d: bytes=%d time=%ldms TTL=%d",
echoReply.data.seq,
echoReply.addr[0],
echoReply.addr[1],
echoReply.addr[2],
echoReply.addr[3],
REQ_DATASIZE,
millis() - echoReply.data.time,
echoReply.ttl);
Serial.print(buffer);
Serial.print(" MAC: ");
uint8_t har[6];
W5100.readSnDHAR(sock, har);
for (byte j=0; j<6; j++)
{
if (har[j]<10)
{
Serial.print("0");
Serial.print(har[j],16);
}
else {
Serial.print(har[j],16);
}
if (j<5)
{
Serial.print(":");
}
}
}
else {
for (byte v=0; v<4; v++)
{
Serial.print(pingAddrTemp[v]);
if (v<3)
{
Serial.print(".");
}
}
Serial.print(" ");
sprintf(buffer, "Echo request failed; %d ", echoReply.status);
Serial.print(buffer);
}
Serial.println();
}
}
Ringrazio tutti quanti per l'aiuto!
Dovresti indicare anche dove hai preso la lib ICMPPing.h a me da un sacco di errori in compilazione, probabilmente sono versioni diverse.
Avevo già pensato di risolverlo in questo modo..ma non sono riuscito a cavarne piedi..anche provando a convertire quello letto dal registro del wiznet..
non ho capito cosa non sei riuscito a fare, non c'è nulla sulla parte SD nel tuo sketch
Tu hai una lista di mac su un file txt che ci metti tu a mano? e poi devi confrontare questi mac con quelli che leggi durante lo scan?
oppure vuoi salvare su SD i mac che trova connessi? dovrei capire lo scopo del confronto mac per darti una risposta.
Ho utilizzato la versione 2.0 dal playground sul sito arduino (Arduino Playground - ICMP Ping Library)..
Anche quando io cercavo di compilare il tuo codice con altre versioni della libreria mi dava problemi.
Nel codice che ho postato, ho rimosso tutte le cose superflue al semplice compito di pingare e stampare le informazioni a schermo, anche nell'eventualità che possa servire a qualcuno.
Comunque, io carico da un file di testo, gli indirizzi mac e la rispettive informazioni(Nome Identificativo), per poter definire, appunto con un confronto, quali siano gli apparecchi connessi alla rete.
Gli indirizzi mac che carico da file vengono salvati su un stringa char. Quindi, almeno per come l'ho vista io, mi ritrovo nel dover convertire o la stringa di char a stringa di byte, o trasformare la stringa di byte contenente il mac letto dal registro del w5100 in char.
Ma in entrambi i casi ho problemi nell'avere due stringhe identiche, o addirittura problemi di compilazione perchè da errori di conversione tra valori non possibili.
skull6m:
Il problema lo riscontro quando devo eseguire il confronto..da una parte ho un array di uint8_t quindi di byte, e dall'altra una stringa char..da una parte(byte array) quando stampo il valore me lo ritrovo in HEX, dall'altra(stringa char) mi ritrovo i valori scritti in decimale(sempre che io non definisca il formato di stampa)..questo comporta che nel confronto avrò una differenza tra le due stringhe..che soluzione??ho provato eseguendo dei cast ma non ho ottenuto nulla..
Non ho seguito tutto il thread, ma da quanto ho capito, il tuo problema ora è confrontare un MAC address che hai in formato numerico (immagino un array di 6 uint8_t) con il classico MAC address in formato stringa "xx-xx-xx-xx-xx-xx" ... giusto ?
Se è così ... non ci sono cast che tengano, devi prima creare una stringa partendo dai tuoi sei bytes numerici, e poi confrontare le due stringhe.
Per questo genere di operazioni, è fondamentale l'uso della ARV libc (che è automaticamente inclusa del IDE di Arduino) e delle sue funzioni per le conversioni e la manipolazione delle stringe che trovi in : <stdlib.h> e in <string.h>.
In particolare, della <stdlib.h> potrai usare la itoa() per convertire i tuoi bytes in char array; e della <string.h> ti serviranno la strcpy(), la strcat() per la creazione della stringa con cui fare il confronto,e la strcmp() per fare veramente il confronto.
Ripeto ... spero di aver capito la tua domanda e di averti quindi messo sulla strada giusta, in caso contrario ... mi scuso per l'inutile post XD
Guglielmo
Nemmeno io ho chiarissimo quello che vuoi fare, ma che la libreria ICMPPing.h restituisce un int e invece sulla SD hai degli hex quello l'ho capito.
Dunque se vuoi leggere un MAC da un file su SD di inizializzazione ad fatto ad esempio così:
file di testo config.ini
[Setup NETWORK]
(ip) = 192.168.2.177
(gateway) = 192.168.2.1
(subnet) = 255.255.255.0
(mac) = 90:A2:DA:A1:7E:24
puoi estrarre dalla stringa del file ogni singolo byte del MAC in un modo simile
...
...
...
void setup() {
delay(1000);
Serial.begin(9600);//debug
...
...
...
String ReadLine;
char charBuf[40];
file.open(&root, "config.ini", O_READ);
int16_t c;
while ((c = file.read())>0){
ReadLine += (char)c;
if((char)c=='\n') {
String newString;
byte strlung = ReadLine.length();
byte parz1 = ReadLine.indexOf("=");
//byte parz2 = ReadLine.indexOf(")"); //ti serve se usi (mac1). (mac2), (mac3) ... (mac10), (mac11)
newString = ReadLine.substring(parz1, strlung);
newString.toCharArray(charBuf, 40);
if((byte)ReadLine.indexOf("(mac)")< 255){
Serial.print("MAC scritto su SD ");//debug
Serial.print(ReadLine);//debug
get_mac(charBuf);
}
ReadLine="";
}
}
delay(5);
file.close();
Ethernet.begin(mac, ip);
Serial.print("valore mac in decimale ");//debug
Serial.println((String)mac[0] + " " + (String)mac[1] + " " + (String)mac[2] + " " + (String)mac[3] + " " + (String)mac[4] + " " + (String)mac[5]);// debug
}
void get_mac(char *charBuffer){
byte i = 0;
char *p = charBuffer;
memset(mac, 0, 6);
while (*p != '\0') {
if (*p == ':') {
++i;
++p;
continue;
}
if (isdigit(*p)) {
mac[i] *= 16; // in hex
mac[i] += (*p - '0');
}
else {
if (isxdigit(*p)) {
mac[i] *= 16; // in hex
mac[i] += (toupper(*p) - 55); // converte A in 0xA ...BCDE... F in 0xF
}
}
++p;
}
}
void loop() {}
uscita sul serial e in oltre viene realmente assegnato alla ethernet
MAC scritto su SD (mac) = 90:A2:DA:A1:7E:24
valore mac in decimale 144 162 218 161 126 36
non è proprio quello che chiedi, ma il metodo può funzionare
Probabilmente alcune di queste funzioni come ti dice gpb01 sono dentro alle lib <stdlib.h> e in <string.h>.