Client TCP et ENC28J60

Bonjour a tous,
J'ai récemment acheté un module ethernet a base d'ENC28J60, et j'ai testé plusieurs bibliothèques dessus : Ethernet_ENC28J60 et Ethercard toutes les deux basées sur Ethershield. J'aimerais faire un client qui envoie des requetes TCP par differents protocoles ASCII (POP, IMAP, SMTP, HTTP, ...). Dans la librairie Ethernet_ENC28J60, cela est théoriquement possible, mais je n'arrive pas a emettre des données, la reception se passe sans problemes, je peut afficher les données par le port serie, mais rien ne ressort du module ... Et pour la librairie Ethercard, une fonction est présente pour émettre des requetes HTTP, ou y répondre, mais rien pour émettre des chaines ASCII.
En esperant que j'ai été compréhensible
Merci d'avance.

Tout à fait compréhensible. Hélas, je viens moi-même de recevoir mon module Ethernet 28j60 (en fait un DINo avec 4 relais et 4 optocoupleurs sur rail DIN), donc mon expérience est encore zéro ... mais je compte y travailler très vite. Ma première priorité est de vérifier et utiliser mes relais (12V/230V). En second, l'Ethernet.

J'ai lu des posts disant que le Wiznet était "mieux mais plus cher", la librairie Ethernet "officielle" est WizNet, il y a des posts nombreux un peu dans tous les sens, donc ... du boulot en perspective.
Si on partage les expériences, çà avancera plus vite...

Vous utilisez Arduino 1.0 ou 0022 ? Je suis resté à la 0022 pour des raisons de compatibilité (p.ex. avec Wiring). La librairie Ethernet du DINo est un EtherShield adapté pour v1.0 (cherche un Arduino.h), et apparemment le support est arrêté, je vais probablement essayer l'etherCard pour 0022 de jeelabs...

Bonjour,

Je suis passé a la version 1.0, comme je n'avais pas trop de projets en cours sur arduino en ce moment. Mais normalement, Arduino.h est inclus dans arduino 1.0, j'ai eu des librairies qui ont eu un problème par rapport à ça, mais il suffisait juste de remplacer Whprograms.h par Arduino.h

J'essaye plusieurs librairies, une adaptation de la librairie officielle, qui ne peut que répondre a une requete d'un client, et pas se comporter en client, et puis ethercard, qui marche nickel, mais seulement pour du HTTP, je vais essayer de la modifier (si j'en ai le temps et l'envie ... :cold_sweat: ) pour mon usage, c'est a dire effectuer des requêtes POP, IMAP ou SMTP.

J'a vu circuler la même chose a propos du Wiznet, malheureusement ...

Bonjour

J'ai perdu de vue et délaissé le circuit enc28j60 depuis plusieurs mois ...
En passant sur le site Jeelabs je viens de voir que Jean-Claude Wippler (jcw) va reprendre le travail sur la librairie Ethercard pour 'tirer' encore un peu plus de cette puce.
Explication (11 avril) en anglais pour ceux que ça peut intéresser :
http://jeelabs.org/2012/04/11/ethercard-improvements/

Effectivement, ça serait vraiment une bonne amélioration, mais a propos de TcpSend(), j'ai essayé d'utiliser cette fonction, mais je ne suis parvenu a rien, je vais essayer de voir comment elle marche, et d'utiliser l'objet Stash, qui a l'air de lui être lié.

D'ailleurs, j'ai essayé de trouver une doc pour cette librairie, mais je n'ai rien trouvé :0 si quelqu'un a lien, il serait le bienvenu

Bon, j'ai analysé les paquets qui sortent avec les codes d’exemple (celui intitulé pachube), et rien ne se voit ... aucune donnée, des paquets qui ne semblent être que des headers, ...

@konfiot,

des nouvelles ?

J'ai acheté un DINo chez KM tronic, avec un ENC28J60 à bord, et je compte le connecter à Pachube, mais EtherCard ne semble pas démarrer. Cà compile OK, et j'ai vérifié les branchements sur le schéma, çà a l'air standard (SPI sur 10-13).

la librairie EtherShield fournie par KMtronic fonctionne, mais pas de Pachube (uniquement en ... lecture ???)

Suite à des infos recues sur un autre forum, j'ai réussi à mettre en route le ENC28J60 avec les démos (web serveur local) fournies.

La librarie EtherCard de jcw estencore à tester, mais apparemment, il faut spécifier la sortie 10 pour le SPI CE parce que c'est 8 par défaut ...

D'autres nouvelles/expériences ?

Bonjour,

tochinet:
D'autres nouvelles/expériences ?

Moi j'utilise EtherCard avec le module ENC28J60 d'ebay (la breakout verte).
La librairie est très complète, voir trop complète ... et trop peu documenté à mon gout ...
J'avais prévu de faire un article dessus mais j'ai encore pas mal de fonctions dont je ne connais pas l'utilité :~

Désolé pour mon retard, j'ai un peu oublié ce post.
@skywodd : J'ai la même carte que toi, pareil, j'ai trouvé aucune doc sur la Ethercard, j'essaye de comprendre en analysant les sources.
Mais pour l'instant, je fait un serveur domotique, en partant des codes d'exemple, ca marche bien, une fois que j'aurais fini ça, je me reconcentrerais sur le client TCP.
J'ai vu je ne sais plus ou que ethershield n'était plus soutenue, donc ethercard me semble être la seul lib valable pour l'ENC28J60, sinon, il y a aussi un portage de la lib officielle sur l'ENC28J60 (GitHub - turicas/Ethernet_ENC28J60: [NOT MAINTAINED, NOT COMPLETED] Implementation of an Arduino-compatible socket layer library that uses Microchip ENC28J60 Ethernet controller.), mais sa semble plus ou moins abandonné, et ça marche pas super...
@tochinet : Pas tout compris, Sur la lib ethercard, les pins pour le UNO sont 10-13, donc ca devrait marcher sur le DINo, si l'ethernet est relié aux pins 10 - 13.

Bonjour à tous,
Je tente de me "dépatouiller" avec la libraire ethercard pour faire tourner mon "ENC28J60 ethernet shield mega" de Ekitszone.com mais c'est laborieux...
Je n'arrive pas à trouver véritablement de tuto au sens propre du terme. les exemples sont à profusion, mais pas toujours en état de fonctionnement ni très explicites.
En fait je suis à la recherche d'explication sur les différentes fonctions, de cette libraire qui me parait performante au demeurant.
Qui saurait me mettre sur une piste.. Merci

Salut,

pinkyfag:
Je tente de me "dépatouiller" avec la libraire ethercard pour faire tourner mon "ENC28J60 ethernet shield mega" de Ekitszone.com mais c'est laborieux...
Je n'arrive pas à trouver véritablement de tuto au sens propre du terme. les exemples sont à profusion, mais pas toujours en état de fonctionnement ni très explicites.
En fait je suis à la recherche d'explication sur les différentes fonctions, de cette libraire qui me parait performante au demeurant.
Qui saurait me mettre sur une piste.. Merci

On est tous sur le même bateau à ce que je vois :grin:

Voici quelques notes que j'ai pu prendre en me basant sur les différents exemples fourni avec la librairie.
Attention : je ne peut pas garantir la véracité des ces notes (seul le dév d'Ethercard le pourrait).

// Variables partagées
static uint8_t mymac[6]; 
Contient l'adresse mac du module.

uint8_t myip[4];
Contient l'adresse IP du module.

uint8_t mymask[4];
Contient le masque de sous-réseau du réseau.

uint8_t gwip[4];
Contient l'adresse Ip du routeur / passerelle réseau utilisé.

uint8_t dhcpip[4];
Contient l'adresse Ip du serveur DHCP utilisé.

uint8_t dnsip[4];
Contient l'adresse Ip du serveur DNS utilisé.

uint8_t hisip[4];
Contient l'adresse Ip du domaine, obtenu aprés une requête DNS effectué via dnsLookup().

uint16_t hisport;
Port TCP utilisé pour les connexions TCP.

uint8_t *Ethernet::buffer;
Mémoire tampon qui sert au stockage des données envoyé/recu.
Il faut impérativement déclarer le tableau dans son code et donner sa taille dans begin().
Exemple: uint8_t Ethernet::buffer[500]; // Buffer de 500 octets


// API EtherCard
uint8_t begin (const uint16_t size, const uint8_t* macaddr, uint8_t csPin = 8);
Initialise la librairie EtherCard avec un buffer de taille "size", en utilisant l'adresse mac "macaddr" pour s'identifier sur le réseau.
Peut aussi être spécifié la broche utilisé en tant que CS (Chip Enable) pour les communications SPI (au choix D8 (par défaut), D9, ou D10).

bool staticSetup (const uint8_t* my_ip = 0, const uint8_t* gw_ip = 0, const uint8_t* dns_ip = 0);
Cette fonction permet de définir l'adresse Ip du module, celle du routeur et celle du serveur DNS dans le cadre d'un paramétrage Ip statique.

// API TCP/IP
void initIp (uint8_t *myip, uint16_t wwwp);
-> TODO

void makeUdpReply (char *data, uint8_t len, uint16_t port);
-> TODO

uint16_t packetLoop (uint16_t plen);
Parse "plen" octets depuis le buffer et extrait le paquet tcp reçu (si il y en a un)

void httpServerReply (uint16_t dlen);
-> TODO (retourne le code d'erreur HTTP ?)

void setGwIp (const uint8_t *gwipaddr);
-> TODO (Retourne l'ip du routeur depuis sa MAC ? Reverse ARP ?)

uint8_t clientWaitingGw ();
-> TODO (attente de la gateway = routeur ??)

uint8_t clientTcpReq (uint8_t (*r)(uint8_t, uint8_t, uint16_t, uint16_t), uint16_t (*d)(uint8_t), uint16_t port);
-> TODO (création d'une requête TCP ? "r" et "d" sont des callback sur fonction, port = numéro de port cible ?) 

void browseUrl (prog_char *urlbuf, const char *urlbuf_varpart, prog_char *hoststr, void (*cb)(uint8_t,uint16_t,uint16_t));
-> TODO (génère une requête HTTP ? urlbuf_varpart = url relative de la ressource désiré, hoststr = nom d'hôte cible, cb = callback sur fonction ?)

void httpPost (prog_char *urlbuf, prog_char *hoststr, prog_char *header, const char *postval, void (*cb)(uint8_t,uint16_t,uint16_t));
-> TODO (envoi un POST HTTP, urlbuf = url cible, hoststr = nom d'hôte cible, header = entête HTTP, postval = donnée du POST, cb = callback sur fonction ?)

void ntpRequest (uint8_t *ntpip, uint8_t srcport);
-> TODO (génére une requête NTP (network time protocol) au serveur d'ip "ntpip" via le port "srcport")

uint8_t ntpProcessAnswer (uint32_t *time, uint8_t dstport_l);
-> TODO (parse la réponse du serveur NTP, extrait le timestamp recu dans time, dstport_l = port de destination ?)

void udpPrepare (uint16_t sport, uint8_t *dip, uint16_t dport);
-> TODO (prépare un paquet UDP ? sport = source port, dip = destination IP, dport = destination port)

void udpTransmit (uint16_t len);
-> TODO (envoi les données UDP ? de longueur "len" ??)

void sendUdp (char *data, uint8_t len, uint16_t sport, uint8_t *dip, uint16_t dport);
-> TODO (envoi un paquet UDP de données data, sport = source port, dip = destination IP, dport = destination port ?)

void registerPingCallback (void (*cb)(uint8_t*));
Associe la fonction "cb" de prototype : void xxxxx(uint8_t*) comme fonction de callback lors de la réception d'un paquet de ping.
L'argument de type uint8_t* contient l'adresse Ip de l'auteur du ping.

void clientIcmpRequest (const uint8_t *destip);
Envoi une requête de ping vers l'adresse Ip "destip".

uint8_t packetLoopIcmpCheckReply (const uint8_t *ip_mh);
Retourne 1 si l'adresse Ip "ip_mh" a répondu à la requête ping, 0 sinon.

void sendWol (uint8_t *wolmac);
Envoi un "magic packet" sur l'adresse de broadcast afin de réveiller un périphérique réseau d'adresse mac "wolmac" compatible WakeOnLan.

bool isLinkUp ();
Retourne 1 si la connexion ethernet est établi, 0 sinon.
  
void packetSend (uint16_t len);
Envoi un paquet de taille "len" stocké dans le buffer.

uint16_t packetReceive ();
Reçois un paquet, le stock dans le buffer, et retourne la taille du paquet.

void powerDown();
Place le ENC28J60 en mode veille.

void powerUp();
Sort le ENC28J60 du mode veille.
  
void enableBroadcast();
Active la réception des paquets depuis l'adresse de broadcast.

void disableBroadcast();
Désactive la réception des paquets depuis l'adresse de broadcast.


// stash-based API
uint8_t tcpSend ();
Envoi le paquet Tcp en mémoire.


// API DHCP
bool dhcpSetup ();
Permet d'obtenir une Ip et les paramètres réseau automatiquement en utilisant le protocole DHCP.
Retourne 1 si le paramétrage DHCP à réussi, 0 en cas d'échec.

bool dhcpExpired ();
Retourne 1 si la session DHCP a expiré, dans ce cas il faudra rappeler dhcpSetup() avant de pourvoir envoyer / recevoir de nouveau paquets.


// API DNS
bool dnsLookup (prog_char* name);
Utilise le serveur DNS du réseau pour obtenir l'addresse Ip correspondant au nom de domaine "name" (PROGMEM char).
Si tout va bien, l'adresse Ip correspondante au nom de domaine est placé dans hisip[] et la fonction retourne 1.
En cas d'erreur la fonction retourne 0 (serveur DNS indisponible, nom de domaine inconnu, etc ...)


// API WebUtil
void copyIp (uint8_t *dst, const uint8_t *src);
Copie une adresse Ip "src" vers le tableau pointé par "dst".
Les deux tableaux "dst" et "src" doivent avoir la taille adéquate (4 octets).

void copyMac (uint8_t *dst, const uint8_t *src);
Copie une adresse mac "src" vers le tableau pointé par "dst".
Les deux tableaux "dst" et "src" doivent avoir la taille adéquate (4 octets).

void printIp (const char* msg, const uint8_t *buf);
Affiche sur le port série (hardware) le message "msg" suivit de l'adresse Ip désigné par "buf" sous la forme "habituelle" nnn.nnn.nnn.nnn

uint8_t findKeyVal (const char *str, char *strbuf, uint8_t maxlen, const char *key);
Permet de parser une chaine du type truc.php?xyz=abc&uvw=defgh et d'extraire la valeur d'une "clef" (clef=valeur).
Cherche la valeur correspondant à la clef "key" dans la string "str" et place le résultat dans "strbuf" avec une limite de "maxlen" caractéres.
L'allocation de "strbuf" est à la charge de l'utilisateur, la taille de "strbuf" doit être passé en argument "maxlen" à la fonction afin d'éviter un possible buffer overflow.
Retourne le nombre de caractéres placé dans "strbuf" ou 0 si la clef n'as pas était trouvé dans "str".

void urlDecode (char *urlbuf);
Décode les caractéres hexa HTTP présent dans "urlbuf" en caractéres ascii classique.
Exemple: Hello%20World (ou Hello+World) -> Hello World

void urlEncode (char *str, char *urlbuf);
Encode les caractéres ascii spéciaux présent dans "urlbuf" en caractéres hexa HTTP dans "str".
Dans le pire des cas (cas qu'il faut toujours prévoir) la string "str" peut être 3x plus longue que "urlbuf".
Il faut donc allouer "str" avec une taille 3x supérieur à "urlbuf" pour éviter tout probléme.
Exemple: Hello World -> Hello%20World

uint8_t parseIp (uint8_t *bytestr, char *str);
Parse une string du style nnn.nnn.nnn.nnn (adresse Ip) et la converti en un tableau de 4 bytes pouvant être utilisé par la suite.
L'allocation de bytestr[4] est à la charge du dev.
Retourne 0 en cas d'erreur, 1 sinon.

Tout ce qui est avec TODO n'est qu'une interprétation personnelle du code et/ou du nom de la fonction dans son contexte.
Si vous avez des info merci de les partager pour consolider cette liste :wink:

(Ps: ce sont des notes prise sur le vif, désolé pour l'orthographe déplorable)

Bonjour, moi j'ai plusieurs enc28j60 en fonction. Mes boards sont montés avec des pic18f2520. J'ai eu beaucoup de misère à faire fonctionner le enc28j60.
Une fois sur dix, il fonctionnait bien. Je coupais l'alimentation et il ne fonctionne pas. J'ai trouvé une façon de le faire fonctionner sans problème et ça dort depuis ce temps. J'ai rajouté un reset software dans mon programme.

paquet_erreur=SPI_Ethernet_doPacket() ;
if (paquet_erreur==1)
{
asm { reset; }
}

Donc, il peut se resetter plusieurs fois par lui-même, mais une fois qu'il fonctionne ,ça fonctionne très très bien. J'ai quatre pic18f2520 qui se transmettent des informations en eux.

Super, tes notes sur Ethercard, skywodd !!

Quelquechose me dit que Jean Claude Wippler ("jcw" de Jeelabs) développeur de cette librairie saurait apprécier tes notes, compléter, corriger.....Il est aussi francophone... . ça vaudrait le coup de poster tes notes sur un des forums de Jeelabs pour lui demander un 'examen' :
http://forum.jeelabs.net/forum/general-discussion
http://forum.jeelabs.net/forum/questions-and-support

al1fch:
Super, tes notes sur Ethercard, skywodd !!

Quelquechose me dit que Jean Claude Wippler ("jcw" de Jeelabs) développeur de cette librairie saurait apprécier tes notes, compléter, corriger.....Il est aussi francophone... . ça vaudrait le coup de poster tes notes sur un des forums de Jeelabs pour lui demander un 'examen' :
http://forum.jeelabs.net/forum/general-discussion
http://forum.jeelabs.net/forum/questions-and-support

J'ai son adresse mail (trouvé sur la page "about" du site jeelabs)
Je vais reprendre mes notes et essayer de pousser un peu plus loin l'analyse, ensuite je lui demanderai ce qu'il en pense :wink:

Merci merci merci skywodd. jcw était en vacances en Juillet-Août je crois, pas de posts.

@konfiot au sujet des pins : la librairie standard SPI utilise les pins 10-13 par défaut.
MAIS D10=(CS) doit être géré par l'applicatif. Cà doit être une OUTPUT sinon la lib SPI passerait (pas vérifié) automatiquement
en mode SPI esclave.
Petit problème, le nanode et autres utilisent la pin 8 comme CS, et c'est ausssi le défaut pour EtherCard. Dans les examples, on voit

  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) 
    Serial.println( "Failed to access Ethernet controller");

et çà, çà implique CS=8. Pour fonctionner avec CS=10, il faut rajouter le paramètre à la fin.

  if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0) 
    Serial.println( "Failed to access Ethernet controller");

Je n'en suis pas plus loin en ce moment, avec un peu de chance je teste tout çà ce soir...

Et je viens de voir dans une issue sur le github d'etherard qu'il n'était pas pour l'instant de gerer les connexions tcp avec plusieures réponses...

J'ai aussi écrémé les forums pour essayer d'en apprendre un peu plus. Pas facile du tout.

Des nouvelles du front ? Rien vu de récent sur les forums de jeelabs (ou ailleurs).

tochinet:
Des nouvelles du front ? Rien vu de récent sur les forums de jeelabs (ou ailleurs).

Pas grand chose de mon côté, j'ai commencé à (re)lire l'API de etherCard pour documenter un peu mieux la chose.
J'ai découvert toute une série d'héritage qui font que telle classe possède en plus les fonctions de telle autre classe, etc etc du coup c'est un méli-mélo indéchiffrable ...
La seul solution que je vois ce serait de commenter les fonctions une par une avec doxygen et de générer un doxydoc à la fin :zipper_mouth_face:

Oops, jusqu'à la réponse de Frankradio, je n'avais même pas capté que j'avais écrit en anglais dans ce forum. Désolé. Traduction :

Je n'ai pas d'expérience avec Doxygen. En fait, j'ai même bousillé des commentaires Doxygen dans des sketchs Arduino récemment, ils avaient des remarques formattées avec "/**" :frowning:

Ce qui est chouette avec EtherCard c'est qu'on dirait qu'il y a plein de fonctions pour faire des trucs (DHCP/DNS/UDPreply etc). Mais le hic, c'est "comment l'uiliser", c'est beaucoup plus compliqué qu'un catalogue, ou de l'inheritance (objet). Et il y a aussi des techniques "standard" (ou extérieures) qui sont empruntées de quelque part et que je ne comprends pas (comme le "PSTR("))

Pouvez-vous expliquer le lien entre bufferfiller et stach par exemple ?

-- Original post
No experience with Doxygen. Actually, it even looks like I just destroyed doxygen friendly comments from some sketches recently, as they had /** remarks :frowning:

What's neat with Ethercard is that it looks like there are many functions to do many things (DHCP/DNS/UDPreply etc). But the real nut to break is the "how to use it", much more complex than just a catalog or inheritance stuff. And there are some "standard" (or exterior) techniques that are borrowed from somewhere and I don't get either (like the "PSTR(" stuff).

Do you understand how the bufferfiller relates to stash for example ?
-- end of original post

@FrankRadio, maybe it's best to move your query to the International forum... :wink: