Pages

New Arduino ENC28J60 Ethershield library

After combining the original ENC28J60 Ethernet shield library from the www.nuelectronics.com Ethernet shield with the Tuxgraphics.org TCP/IP stack. The end result is a library that is much easier to use. The examples provided show:

  • Simple webserver that can be used to control or read values
  • Simple Twitter client that can post messages on receipt of a trigger – currently a pushbutton between digital input 0 and ground.

These simple demos can run on the 168 Arduino, although anything that is going to use more complex web pages and actions will require the 328 Arduino in order to provide the extra program and data memory.

The library and examples are available at te end of this article. They are installed by unzipping to your arduino-0016/hardware/libraries directory (This assumes you are using Arduino software version 0016). If you already have the EtherShield library installed then this should be removed as this library replaces it.

In the file hardware/libraries/etherShield/ip_config.h you need to define which parts you wan to use, whether it is the webserver client, server, ntp or wol code. To save space you undef the options you dont want.

Once configured, load up one of the examples, set your IP address, gateway IP address and mac address. Then set the authentication string if using the twitter client. Once loaded to your board, point your web browser at your Arduinos IP address and you should see a simple web page.

The code may not be the best as its been hacked around from a number of sources. I also wanted to get something out there that is going to be useful to other people.

Code
Updated EtherShield library

This is a slightly updated version that I have used in my later pachube.com client. The difference here is that you are now able to specify the method to use when posting the data, this could be the default POST or PUT.

Bookmark this post: bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark

28 comments to New Arduino ENC28J60 Ethershield library

  • Pavel Ruzicka

    Hi Andy,

    I’m using currently your Ethershield library and trying to receive data from a webpage form by method “POST”. Can you advise how to do it ? Especially how to receive encoded data which are not in URL address…

    Many thanks
    Pavel Ruzicka, Prague, Czech Republic

  • Administrator

    Hi Pavel,

    I see what you are trying to do, it should be possible, but this is something I havn’t yet tried. The data should be in a URL encoded format similar to the GET data but in a different place in the packet. One thing to watch out for is that the packet buffer is only about 500 bytes, so with headers, you can POST a lot of data to the arduino. Once you exceed the buffer strange things start happening or it just stops working!

    On way to cut down on the size it to use short, even single letter field names, e.g. a=123&b=456&c=789 instead of field1=123&field2=456&field3=789

    There is a problem in the library when using pachube.com, it was there with the original tuxgraphics code I used, in that if you want to use the POST data to a remote server, it was using the HTTP POST method, but pachube.com require it to be the PUT method instead. I’m looking to update the library to handle both cases, probably with an updated post method. I’m also looking to be able to post xml data to pachube.com to perform some environment monitoring. The basic CSV works now and I’m working on sending XML data but am coming against the memory limitations, especially on the 168 boards.

    Hope this gives you an idea that the updated library is still very much a work in progress with much more to do. I’d like to add in DHCP support.

    Cheers

    Andy

  • Pavel Ruzicka

    Hi Andy,

    thank you for reply. The reason why I need POST method is to hide the password, because my Arduino is connected to web-controlled aircondition. I use Atmega 328, so I have buffer around 1500 bytes and it works fine. You are right, when I exceed the buffer, realy strange behaviour I saw….

    OK, I will try to manage the POST method somehow and we will see.

    Cheers
    Pavel

  • daniel

    Hi, just downloaded the library on Arduino 0017, but it seems to not compile on line 102

    if (es.ES_find_key_val(str,kvalstrbuf,10,”mn”)){

    the error is this:

    In function ‘int8_t analyse_get_url(char*)’:
    error: ‘class EtherShield’ has no member named ‘ES_find_key_val’ In function ‘void loop()’:

    and many more

    any idea why?

  • maxlock

    Hi Andy,
    Thanks for posting your ethershield library. I want to modify it to send xAP packets that are very similar to WOL packets defined in your library. The problem I’m having using your WOL function before I modify it, is specifying the destination MAC address. Can you post an example/snippit?

    -Cheers Max (Also based in Thatcham!)

  • Administrator

    Hi Daniel,

    Not sure why this is the case, I’ve used it with Arduino IDA 0017 recently, but ma not have used all the options.

    Cheers

    Andrew

  • Administrator

    Hi Max,

    I’ve not actually used the WOL functionality, its basically as it was from the tuxgraphics.org library that I ported to Arduino ethershield library, hence the reason for no examples. I could have removed it altogether. I may get round to looking at it, but currently got a ton of other stuff on.

    btw, the xAP looks interesting, just got some homeeasy sockets and looking to get hold of some RF modules to try to control them from arduino.

    Cheers

    Andrew

  • maxlock

    Hi Andy,

    Ah ok thanks, I’ll take a look at the tuxgraphics code.

    I’m currently running some X10 modules, but I want to move toward a more intelligent system with 2 way communication and redundancy. The arduino environment is ideal for doing xAP which seems like an elegant solution to me.

    Right now I’m using Misterhouse running on a buffalo linkstation NAS running Debian. It makes a nice low power (~22W) controller.

    -Cheers Max.

  • jimthree

    Hi Andy, Great work on the Ethershield Libs. Do you think there is space on an Arduino 168 to parse a simple RSS feed and extract data that the arduino will react to? Does the library support this? cheers.. Jim

  • Administrator

    Hi Jim,

    The library could support this, its basically what you do with the received packet data. The problem here is that the 168 based arduino only have 1k ram, so this must be used for buffer, stack, variable storage etc. Regular ethernet packets are about 1500 bytes although the tcp data will be less than this you still need the buffer to store all this. Then if the response is split over multiple packets then the library cant handle this. Unless you know that you are going to receive small, say 500 byte rss feeds then the ENC28J60 with the arduino is not going to handle it. However, the official ethernet shield, which has its own inbuilt buffer ram may be able to do it. As I don’t yet have one of these so I cant say much about them.

    I was thinking of having a twitter reader, but thinking I’d need to pre-parse the xml responses via another machine to strip out what I dont need to leave just the data feeds but nothing has progressed on this yet as I may just use the official ethernet shield.

    Hope this helps

    Andy

  • chjunkcy

    Hello Andy,I can use your new library with the twitter client example but I don’t know how to get massage from Twitter. I need twitter massage to control relay like this link http://tuxgraphics.org/electronics/200908/eth-flower-watering.shtml help me please, thank you

  • Administrator

    Hi,

    I’ve had a think about this after looking in more detail at the datasheet for the ENC28J60. It has large internal buffers, so in theory, it should be possible to read and process a stream of bytes by only transferring a small part into the arduino buffer at a time. Instead of at present it loads the whole packet. It is something I’d like to be able to do too as I was looking at reading twitter or facebook news feed xml to change the colour of a rgb LED based on keywords.

    I’ve got a few other things on at the moment so it still in the pipeline to rewrite the library for this shield.

    Cheers

    Andy

  • atmoz

    Hi Andy,

    On the Arduino.cc forum I’ve say it already: I really like the projects on this website!!
    Very nice and fine stuff what you made 🙂

    Also thanks for the library to put data to Pachube!!
    I didn’t know the website, but I used the code to update my own “save.php” file on my remote webserver. At least, it has to do that. It works when I use fixed text. But I want to be able to send a variable (string) to my “save.php” file. I know this is possible, and with your program skills I know that you can help me out with this. Therefore I kindly want to ask you if you can help me with this?

    What do I have to change in this line of code to insert a variable TEST into it?

    es.ES_client_http_post(PSTR(PACHUBEAPIURL +(TEST)),PSTR(PACHUBE_VHOST),PSTR(PACHUBEAPIKEY), PSTR(“PUT “), statusstr ,&browserresult_callback);

    The only thing that I want to do is sending the variable TEST to my “save.php” file.

    In PACHUBEAPIURL = /ethershield_log/save.php?pwd=secret&client=1&status=
    In PACHUBE_VHOST = http://www.luma.nl
    In PACHUBEAPIKEY = 0000 (because my save.php doesn’t need anything extra)

    It works when I use:

    es.ES_client_http_post(PSTR(PACHUBEAPIURL”hello”),PSTR(PACHUBE_VHOST),PSTR(PACHUBEAPIKEY), PSTR(“PUT “), statusstr ,&browserresult_callback);

    But instead of the fixed word “hello” I want to be able to send a string.

    Many thanks in advance for any help!!

    Keep up the good work.

    It’s VERY nice to control your environment with a (standalone) Arduino!!!! Wooohooo!!!

  • ill_switch

    Hi Andy,

    Digging this up from the dead in the hopes that you can provide some assistance. I have a project with an Arduino and an ENC28J60 Ethernet interface that I’d like to post to a twitter account with, hence your work here is very exciting.

    I downloaded the zip you posted above, unpacked it, and loaded it into my arduino-018 environment (on winXP). The webserver example compiles, but the twitter example fails. I’m getting the same error as Daniel mentions above on sept. 6 2009:

    In function ‘int8_t analyse_get_url(char*)’:
    error: ‘class EtherShield’ has no member named ‘ES_find_key_val’ In function ‘void loop()’:

    Any thoughts?

  • Administrator

    Hi,

    Have a look in the sketchbook/libraries/etherShield/ip_config.h file. This contains a number of defines used to include/exclude parts of the library that you are using. For example if you dont need NTP, dont include it.

    Down the bottom there should be a line:

    #define FROMDECODE_websrv_help

    if it says #undef instead of #define then change to #define, this includes the piece of code that handles the url processing.

    I’m thinking the library needs a big update to address a number of issues, documentation being one and linux/unix case sensitivity being another.

    thanks

    Andy

  • mkalten

    Hello Andy, many thanks for your updated etherShield library. This comes quite handy!
    I am currently playing with a simplified patch for sending Tweets, but unfortunately I am having troubles with the ES_client_http_post method, which never succeeds to post any data and which doesn’t call the according callback method neither. My IP configuration is just fine, I am able to ping the etherShield and also can access port 80 on the board properly. Instead of the twitter server I also tested accessing a local machine, but no luck … Maybe you could have a quick look at my patch in order to see what could be wrong? I am using the nuelectronics etherShield on an Arduino Duemillanove. Could it be a memory problem?

    http://tuio.org/files/TwitterTest.pde

    many thanks in advance,
    Martin

  • Administrator

    Hi,

    Problems with memory buffers overwriting other data is common when using the etherShield. You need to set up a big a buffer as you can spare. I use 750 to 950 bytes usually.

    Andy

  • mkalten

    Hi Andy, many thanks for your feedback. I had already tried larger buffer sizes as well, but still no luck with the ES_client_http_post method nor with ES_client_browse_url.
    any other idea what the problem could be here?

  • Andy, your library is 10x better than the original library. Thanks for cleaning it up. I’m in the process of cleaning it up some more, and making it more arduino user friendly. I’m curious if you’d be interested in collaborating on the next version of the library with me? I tried to find your email address but it’s no where to be found.

    https://code.google.com/p/ethershield/

  • Administrator

    Hi Scott,

    Finally got round to catching up on comments. I’ll drop you a mail. I’ve been doing some tweeks to the library recently, mainly to enable it to be used with modified shields that have the CS line on a different pin so that it can be used with other SPI devices, as well as adding a tri-state buffer instead of the AND gates for level shifing on some of the SPI pins.

    I’m wanting to get some DHCP setup too for minimum configuration.

    Cheers

    Andy

  • Ruwan

    Dear Andy,
    Thank you for the your great site and great info. They are very helpful for me.
    I have used your old eithernet library and modified one of your web client example.
    Then i have used that to send simply variable value which is incremented by one at each second. Then it monitored using c# web server written by me. But the problem is when count reaches to 123 (ASCII value) eithernet client is freeze. Then it need hardware reset to continue. [ I have implemented softreset( i have no idea weather it is 100% correct) and when count reaches 100, i did softreset-> initialize eithernet shield again, but it fails. count runs only up to 123 times ]

    Since this probluem, i have downloaded and installed your new client library. then i have tried to compile your old eithernetShiel_client1, but it fails. Can you please provide me some info about how to compile that? or
    how to implement that client in new library? . I beleive your new library will work for my task.

    Thank you,
    Ruwan.

  • arduinocarblackbox

    Hello, I just received my ethernet 28j60 and im finding it quite difficult to find the easiest example ever to implement in my proyect.
    I just need for the ethernet to call a certain URL that contains parameters i want a php to GET and put in mysql database.
    something like

    http://www.mywebsite/power/upload.php?P=1023&V=230&I=4.8

    just that, call that url every 10 seconds with the new values.

    is there a super simplified example using your library to do this?
    thanks a lot for everthing.

  • Paulware

    I share the viewpoint of many others that I can’t get these libraries to work. Could you make a simple client example that GETs http://www.yahoo.com or http://www.google.com thanks

  • I’ve decided to discontinue EtherShield and am in the proces of converting my example code to use the newer EtherCard library. This is easier to use.

    i am putting together a migration post to give tips on how to update your sketches to move from EtherShield to EtherCard.

    Thanks

    Andy

  • tao13

    Hello.
    I’m Mke from Romania.
    I have an arduino mega 2560 , an enc28j60 and some sensors.I modified your example but it doesn’t works for many function/procedures wrote sepratly.Can you help me and tell me why?This is my example:

    #include
    #include
    #include
    #include
    #include “etherShield.h”

    #define LED_PIN 13
    byte on_off = 1;

    int intensitateSenzorLumina;
    #define pinSenzorLumina A8

    int valoareSenzorGaz;
    #define pinSenzorGaz A11

    static uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x24};
    static uint8_t myip[4] = {192,168,1,15};
    static char baseurl[]=”http://192.168.1.15/”;
    static uint16_t mywwwport =80; // listen port for tcp/www (max range 1-254)
    #define BUFFER_SIZE 500
    static uint8_t buf[BUFFER_SIZE+1];
    #define STR_BUFFER_SIZE 22
    static char strbuf[STR_BUFFER_SIZE+1];
    EtherShield es=EtherShield();
    uint16_t print_webpage(uint8_t *buf, byte on_off);
    int8_t analyse_cmd(char *str);
    char numStr[10];
    uint16_t plen;

    void setup()
    {
    Serial.begin(115200);

    pinMode(pinSenzorGaz , INPUT);

    pinMode(pinSenzorLumina , INPUT);

    es.ES_enc28j60Init(mymac);
    es.ES_enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
    delay(10);

    /* Magjack leds configuration, see enc28j60 datasheet, page 11 */
    // LEDA=greed LEDB=yellow
    // 0x880 is PHLCON LEDB=on, LEDA=on
    // enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
    es.ES_enc28j60PhyWrite(PHLCON,0x880);
    delay(500);
    //
    // 0x990 is PHLCON LEDB=off, LEDA=off
    // enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
    es.ES_enc28j60PhyWrite(PHLCON,0x990);
    delay(500);
    // 0x880 is PHLCON LEDB=on, LEDA=on
    // enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00);
    es.ES_enc28j60PhyWrite(PHLCON,0x880);
    delay(500);

    // 0x990 is PHLCON LEDB=off, LEDA=off
    // enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00);
    es.ES_enc28j60PhyWrite(PHLCON,0x990);
    delay(500);

    // 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
    // enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
    es.ES_enc28j60PhyWrite(PHLCON,0x476);
    delay(100);

    //init the ethernet/ip layer:
    es.ES_init_ip_arp_udp_tcp(mymac,myip,80);

    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, LOW); // switch on LED

    }

    void loop()
    {
    ethernetShield_LOOP();
    }

    void citireSenzorGaz()
    {

    valoareSenzorGaz = analogRead(pinSenzorGaz);
    valoareSenzorGaz = map(valoareSenzorGaz , 0, 1024 , 1 , 255) ;
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(” VALOARE C02 “));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    formatNum(valoareSenzorGaz , false , numStr);
    plen=es.ES_fill_tcp_data(buf,plen,numStr);
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));

    if(valoareSenzorGaz > 120)
    {
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“NIVEL CO2 CRESCUT”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    }
    else
    {
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“NIVEL CO2 NORMAL”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    }

    }

    void aprindereBec()
    {
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(” Stare BEC “));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));

    if(on_off)
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“Stins”));
    else
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“Aprins”));

    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(” “));

    if(on_off)
    {
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    }
    else
    {
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“”));
    }
    }

    void ethernetShield_LOOP()
    {
    int8_t cmd;
    uint16_t plen_loop, dat_p_loop;

    plen_loop = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);

    /*plen will ne unequal to zero if there is a valid packet (without crc error) */
    if(plen_loop!=0)
    {
    // arp is broadcast if unknown but a host may also verify the mac address by sending it to a unicast address.
    if(es.ES_eth_type_is_arp_and_my_ip(buf,plen_loop))
    {
    es.ES_make_arp_answer_from_request(buf);
    return;
    }

    // check if ip packets are for us:
    if(es.ES_eth_type_is_ip_and_my_ip(buf,plen_loop)==0)
    {
    return;
    }

    if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V)
    {
    es.ES_make_echo_reply_from_request(buf,plen_loop);
    return;
    }

    // tcp port www start, compare only the lower byte
    if (buf[IP_PROTO_P]==IP_PROTO_TCP_V&&buf[TCP_DST_PORT_H_P]==0&&buf[TCP_DST_PORT_L_P]==mywwwport)
    {
    if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V)
    {
    es.ES_make_tcp_synack_from_syn(buf); // make_tcp_synack_from_syn does already send the syn,ack
    return;
    }
    if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)
    {
    es.ES_init_len_info(buf); // init some data structures
    dat_p_loop=es.ES_get_tcp_data_pointer();
    if (dat_p_loop==0) // we can possibly have no data, just ack:
    {
    if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V)
    {
    es.ES_make_tcp_ack_from_any(buf);
    }
    return;
    }

    if (strncmp(“GET “,(char *)&(buf[dat_p_loop]),4)!=0)
    {
    // head, post and other methods for possible status codes see:
    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
    plen_loop=es.ES_fill_tcp_data_p(buf,0,PSTR(“HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n200 OK”));
    goto SENDTCP;
    }

    if (strncmp(“/ “,(char *)&(buf[dat_p_loop+4]),2)==0)
    {
    plen_loop=print_webpage(buf, on_off);
    goto SENDTCP;
    }
    cmd=analyse_cmd((char *)&(buf[dat_p_loop+5]));

    if (cmd == 2)
    {
    on_off=1;
    digitalWrite(LED_PIN, LOW); // switch on LED
    }

    if (cmd == 3)
    {
    on_off=0;
    digitalWrite(LED_PIN, HIGH); // switch off LED
    }

    plen_loop=print_webpage(buf , on_off);
    plen_loop=print_webpage(buf , on_off);

    SENDTCP: es.ES_make_tcp_ack_from_any(buf); // send ack for http get
    es.ES_make_tcp_ack_with_data(buf,plen_loop); // send data
    }
    }
    }

    }

    // The returned value is stored in the global var strbuf
    uint8_t find_key_val(char *str,char *key)
    {
    uint8_t found=0;
    uint8_t i=0;
    char *kp;
    kp=key;
    while(*str && *str!=’ ‘ && found==0)
    {
    if (*str == *kp)
    {
    kp++;
    if (*kp == ”)
    {
    str++;
    kp=key;
    if (*str == ‘=’)
    {
    found=1;
    }
    }
    }
    else
    {
    kp=key;
    }

    str++;
    }

    if (found==1)
    {
    // copy the value to a buffer and terminate it with ”
    while(*str && *str!=’ ‘ && *str!=’&’ && i<STR_BUFFER_SIZE)
    {
    strbuf[i]=*str;
    i++;
    str++;
    }
    strbuf[i]='';
    }
    return(found);
    }

    int8_t analyse_cmd(char *str)
    {
    int8_t r=-1;

    if (find_key_val(str,"cmd"))
    {
    if (*strbuf 0x2f)
    {
    // is a ASCII number, return it
    r=(*strbuf-0x30);
    }
    }
    return r;
    }

    void formatNum( int num, boolean multiply, char *numStrPtr )
    {
    boolean neg = (num < 0 );
    char *strPtr = numStrPtr;

    for(int i=0; i 10 ) {
    itoa( decimal, strPtr, 10 );
    } else {
    *strPtr++ = ‘0’;
    itoa( decimal, strPtr, 10 );
    }
    } else {
    itoa(num, strPtr, 10 );
    }
    }

    uint16_t print_webpage(uint8_t *buf , byte on_offf)
    {
    int i=0;
    plen = 0;

    plen=es.ES_fill_tcp_data_p(buf,0,PSTR(“HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n”));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR(“SYSTEM PAGE “));

    aprindereBec();

    citireSenzorGaz();

    return(plen);
    }

    Thanks you very much.

  • greywolf

    Great library I have just started using the new version of arduino IDE and have found most of the custom libraries I have for hardware are now incompatible, using your webserver example I get undeclared identifiers for LOW, HIGH, INPUT and OUTPUT on several lines, would it be possible please to get an update for this library to work with arduino 1.0 IDE, I unfortunately am unsure where they need to be defined and if there are any other lines which will require changing once these errors are rectified (ie. methods such as serial.print() have been updated and may cause errors).

  • The last version of EtherShield available from github is Arduino 1.0 IDE compatible and works well with it, however this library is no longer supported or developed by me. Please use EtherCard at https://github.com/jcw/ethercard if you want an easier library that is being actively developed and maintained.

    Regards

    Andy

  • tobyasz

    Hi!
    I want to do a web client. An RFID reader by the GET method data should pass through a php script. What function could this be? Maybe someone could show a working example code.
    Thank you.