Pages

New EtherShield Library available

The long awaited update to the EtherShield library is now available, the changes in this release include:

  • DHCP support – Now your project can find its own IP address, dns server and gateway addresses
  • Fixed length problems in main ip code where packet lengths were being passed as bytes not words so as a result incorrect packet lengths were being seen
  • New examples added for DHCP test and Pachube RGB LED demo using DHCP

Find it on Github at https://github.com/thiseldo/EtherShield

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

45 comments to New EtherShield Library available

  • Jross

    Hey Andy,

    You obviously have the skills and are pretty much the only support for the ENC28J60.

    I’ve been racking my brains to use your old library, this library, jeelabs library, etc… just to do a “simple” Arduino to PHP to MySQL.

    I’ve tried your examples with PHP and hacking away at your twitter example to do this, but I get compile errors all the time, and when i don’t…the bloody thing just never connects. I can use the Arduino + ENC28J60 as a server (that part is relatively straightforward), but I can find any good examples that are for newbies that give the bare bones instructions to understand the bits and pieces in your examples.

    Pretty much right now, I just want to do GET myhost.com/ethernet_to_db.php?value=STATIC just to know i can push things in, without all the hoopla of anything else.

    The error I get with your examples & the code are below:

    Error:
    sketch_may27a.cpp: In function ‘void loop()’:
    sketch_may27a:116: error: no matching function for call to ‘EtherShield::ES_client_browse_url(char*, char [50], char*, NULL, void (*)(uint8_t, uint16_t))’
    /home/jonathan/DeviceToWeb/arduino-0022/libraries/etherShieldold/etherShield.h:201: note: candidates are: void EtherShield::ES_client_browse_url(prog_char*, char*, prog_char*, void (*)(uint8_t, uint16_t, uint16_t))

    Here is one of my hacks of your PHP example.

    #include

    // ** Local Network Setup **
    // Please modify the following lines. mac and ip have to be unique
    // in your local area network. You can not have the same numbers in
    // two devices:
    static uint8_t mymac[6] = {
    0x54,0x55,0x58,0x10,0x00,0x27};

    // how did I get the mac addr? Translate the first 3 numbers into ascii is: TUX
    // The IP address of the arduino.
    static uint8_t myip[4] = {
    192,168,1,203};

    // Default gateway. The ip address of your DSL/Cable router.
    static uint8_t gwip[4] = {
    192,168,1,254};

    // IP address of the host running php script (IP of the first portion of the URL):
    static uint8_t webip[4] = {
    192,168,1,66};

    // The name of the virtual host which you want to contact at webip (hostname of the first portion of the URL):
    #define WEB_VHOST "192.168.1.66"
    #define WEBURL "/ethernet_to_db.php"

    // End of configuration

    // listen port for tcp/www:
    #define MYWWWPORT 80

    static volatile uint8_t start_web_client=0; // 0=off but enabled, 1=send update, 2=sending initiated, 3=update was sent OK, 4=diable updates
    static uint8_t web_client_attempts=0;
    static uint8_t web_client_sendok=0;
    static uint8_t resend=0;

    int temp = 22;

    #define STATUS_BUFFER_SIZE 50

    #define BUFFER_SIZE 650
    static uint8_t buf[BUFFER_SIZE+1];

    // global string buffer for message
    static char statusstr[STATUS_BUFFER_SIZE];

    // Instantiate the EtherShield class
    EtherShield es=EtherShield();

    // prepare the webpage by writing the data to the tcp send buffer
    uint16_t print_webpage(uint8_t *buf)
    {
    uint16_t plen;

    plen = es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("WebServer Works!/h1>\n"));

    return(plen);
    }

    // Browser callback, where we get to after receiving a reply to an update, should really
    // do somthing here to check all was OK.
    void browserresult_callback(uint8_t statuscode,uint16_t datapos){
    if (statuscode==0){
    web_client_sendok++;
    }
    // clear pending state at sucessful contact with the
    // web server even if account is expired:
    if (start_web_client==2) start_web_client=3;
    }

    // Perform setup on ethernet and oneWire
    void setup(){
    // Serial.begin(19200);

    // initialize enc28j60
    es.ES_enc28j60Init(mymac);
    //init the ethernet/ip layer:
    es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
    // init the web client:
    es.ES_client_set_gwip(gwip); // e.g internal IP of dsl router
    }

    // The business end of things
    void loop(){
    uint16_t dat_p;
    int8_t cmd;
    start_web_client=1;
    unsigned long lastSend = millis();
    unsigned long time;

    while(1){
    // handle ping and wait for a tcp packet
    dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
    if(dat_p==0){
    // Nothing received, jus see if there is anythng to do
    // update every 10s
    time = millis();
    if( time > (lastSend + 10000) ) {
    resend=1; // resend once if it failed
    start_web_client=1;
    lastSend = time;
    }

    if (start_web_client==1) {
    // Read values from the sensor
    temp = 22;

    sprintf( statusstr, "?value=%s", temp);
    es.ES_client_set_wwwip(webip);
    es.ES_client_browse_url(PSTR(WEBURL),statusstr,PSTR(WEB_VHOST),NULL, &browserresult_callback);
    start_web_client=2;
    web_client_attempts++;
    }

    continue;
    }

    dat_p=print_webpage(buf);
    es.ES_www_server_reply(buf,dat_p); // send data
    }
    }

    // Thats all folks!!

    Cheers Mate, I hope you can help us less than stellar programmers on our way to getting as much as we can from your library.

    If you want me to write up any tutorials after this, I gladly will, after all, you’ll need to get some documentation around all of your hard work!!!!

  • kenboak

    Jross,

    Many of the problems in the Arduino library are caused by not deleting the old library completely from the libraries folder. The Arduino IDE is kinda quirky like that.

    I upgraded to Andy’s latest EtherShield library yesterday and was confronted by a whole bunch of intangible errors – just like the ones you got.

    Delete the old library and these problems should go away.

    Good luck with your project – can I interest you in Nanode http://hackerspaces.org/wiki/Nanode

    Ken

  • Telek

    Hi Andy,

    Great library, thanks for the work you have put into this. I am using it now with a MEGA2560 and a nuelectronics-style ENC28J60 board (made by ekitszone). However I think I found a bug and a couple of enhancements needed to make it work.

    The file enc28j60.c uses #ifdef USE_RF12 in several places (in particular for the read/write commands) however it does not include ip_config.h where that define is made. Adding a #include “ip_config.h” to the top of this file fixed the problem.

    I also modified the en28j60.h header as such to support the mega2560 board difference in pinout:


    #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

    #define DEFAULT_ENC28J60_CONTROL_CS 53
    #define SPI_SS 53
    #define SPI_MOSI 51
    #define SPI_MISO 50
    #define SPI_SCK 52

    #else

    // Default CS pin is 10, for the unmodified shield.
    // Can be changed in init function to use another pin
    // But SPI_SS needs to be setup correctly too
    #define DEFAULT_ENC28J60_CONTROL_CS 10
    #define SPI_SS 10
    #define SPI_MOSI 11
    #define SPI_MISO 12
    #define SPI_SCK 13

    #endif

    Finally before anything else is done in the demo the following lines are needed to disable the microsd card (even if it isn’t present) – I put them in the top of setup():


    void setup()
    {
    /* Disable SD card */
    pinMode(4, OUTPUT);
    digitalWrite(4, HIGH);

    ...

    After those 3 mods it works like a charm!

  • jcw

    Hello Andy – great work on getting DHCP in there. I was wondering what I’m doing wrong – while trying your EtherShield_DHCPTest.pde sketch, I changed two things: disabled some pin 8 calls in setup(), and added a second “8” arg to es.ES_enc28j60Init(), since that’s the pin used by the EtherCard.

    It then goes into a loop doing “Sending DHCP Discover”. Are some routers stricter than others w.r.t. DHCP? I’m using a Linksys 320N.

    Cheers, jcw

  • Hi JCW,

    I have had reports that there are problems with the code when using it with some routers, Netgear and Linksys seem to be the usual problem types. I’ve not been able to track down the problem due to not owning these routers. The latest code in github from 06/06/2011 had a couple of changes in dhcp.c to remove a spurious 00 from the end of the hostname option that wireshark reported as ‘padding’ this may affect some routers and cut down the options and parameters to what I think is the bare minimum to get it working. If this still doesnt work could you try capturing some dhcp packets using wireshark to compare allocating an address from a pc and the ethershield code. Without having any output to work with I cant tell if its the Discover being ignored by the router or the Offer being ignored by the library. An other option is to add in my Packed dump library (from github) to see if you receive the offer from the router. The packet dump library is large due to all the text output messages that go into flash so sometimes it may not run properly at all.

    btw, great work with the Jeenodes and the RFM12 library, I have a number of V4 Jeenodes here plus a RFM12 to ethernet bridge that I put together to interface with a linux server.

    Cheers

    Andy

  • jcw

    More details: discover goes out, offer comes in, request goes out, but I never see an ack.

    Ah, wait, solved – don’t fill in yiaddr, i.e. use: dhcpPtr->yiaddr[i] = 0;

    Also, better to add an “end option”, a single 255 byte at the end.

    Now it works 🙂

  • jcw

    @Scurvyrat – FYI, the above fix is not JeeNode-related, it addresses an issue with Linksys routers (and perhaps others). Andy’s code on GitHub already works with JeeNodes and Ether Cards (simply specify the chip select as 8 during init).

  • tdouez

    I have the same problem with my netgear router. I try your EtherShield_DHCPTest.pde sketch. And the program go into a loop with “Sending DHCP Discover” message. I try it the same program with a cisco router and it’s ok.

  • Hi,

    Have you tried the very latest code from github, this was changed on 7th June to hopefully fix the issues, it did fix issues with Linysys routers.

    Hope this helps

    Andy

  • tdouez

    Unfortunately yes, I tried the latest version and still have the problem. I made another test on a Sagem router and it doesn’t exist. This problem occurs only on a netgear router. I don’t know how to capture the trame between the ethernets shield and router, and send it to you.

  • tdouez

    Hello Andy, I’m reading the dhcp.c source and i have a question about “dhcp_send” function. What’is the signifaction of the “magic number” 400 in “memset(buf, 0, 400); //XXX OUCH!” line ? Why not use the define BUFFER_SIZE ?

    Tristan

  • exigent99

    Hi Andy, just a some more info, I checked out latest from github today and tried it. I have the same loop problem with the DHCP test sketch. In wireshark I can see it do a DHCP discover, then the router does a ‘Who has’ ARP, followed by a DHCP Offer from the router. However the arduino never seems to accept the address. I am testing with a linksys router

  • tdouez

    Andy, I have a pcap file from wireshark between my pc and my netgear router. But i need you email in order to send it.

    Tristan

  • tdouez

    Andy, just for your information the problem is also visible with the software dhcp server “Tftpd32”.

    After reading the dhcp.c file, there is a little error in dhcp_send function. the option client identifier length is bad. the good value is 6 and not 7. This update does not fix the problem, of course.

  • orengo

    Dear,
    Where is the file : ethernet_to_db.php for this example ?

    When I compile occurs a error : error: no matching function for call to ‘EtherShield::ES_client_browse_url(char*, char [50], char*, NULL, void (*)(uint8_t, uint16_t))’

    best regards,

    JORGE ORENGO

  • monkeyfun17

    Andy, could you by any chance make an example for your EtherShield library like the UDPSendReceiveString example from the Ethernet library? I’m trying to do a project that receives a UDP packet, dose something based on the contents of that packet and then sends a UDP packet back. If I had an example that was close to what I need, then I could probably figure it out.

  • hello, you have a tutorial that features used to build something simple? The examples are somewhat complex and not know where to begin to build a webserver.

    hola, tienes un tutorial, de que funciones usar para armar algo simple? Los ejemplos son algo complejos y no se por donde empezar para armar un webserver

  • […] side effect is that the official library does not work. After doing some googling, I’ve found this absolutely perfect library. For example, it fully supports DNS, DHCP while the official does not. The library does not work de […]

  • Brian

    Been using this without major issues with my Mega. However, when I change DEFAULT_ENC28J60_CONTROL_CS and SPI_SS to 10, the code hangs during the call to ES_enc28j60Init
    This happens using the webserver example application. Everything works fine if I leave the CS pin as 53

    I need to change the CS pin, due to conflict with an SD Card reader / TFT display combo. If I build and run my app with the SD Card code enabled, it initializes, but then won’t work.

    Any thoughts on the issue?

  • suvenk

    Hi Andy,
    Have been playing around with your library and it is terrific!
    Kudos on making such a useful piece of code.
    I have been trying to serve fully functional web pages from an SD card via the arduino and ethershield but have been hitting roadblocks all along.
    The idea is to read characters from a file on the (micro)SD card and send them over ethernet.
    This works fine for small files.
    The problem is that the library allows only one packet to be sent per request. Is it possible to send more than one packet before closing the connection and send entire(large) files including jpg/gif/png’s?
    I am a total newbie to both networking and arduino programming. Could you point me in the right direction?

    Thanks!

  • Brian

    Hello again,
    I found the answer to my question regarding using an SS pin other that 53 on the Arduino Mega.
    Needed to add these two lines of code to my setup().

    pinMode(53, OUTPUT);
    digitalWrite(53, HIGH);

    This is needed to get the internal SPI processing working correctly;

    Your library works great !!!!

  • john@jstockton.com

    I got your great library working and it handles small web pages just fine (surprisingly good performance for such a small device). I’m interested in serving a page that is about 4.5kB in size and wanted to know if there is an easy way to deal with that, since the current TX buffer looks like it is limited to 500 bytes. Can I do something like send the page in 500 byte chunks and then close the connection to have the client render the page?

    Thx,

    John Stockton

  • ldutra

    hi all, o would like to use this feature packetloop_icmp_checkreply

    i want to ping a host from arduino and print in my serial port,

    []’s

    Leonardo Dutra

  • poliveira1978

    Hi all.
    My subject hasn’t to do with been unable to put the library to work, the DHCPtest sketch works flawlessly, my doubt is how can i cast the myip var to a string, i’d like to print that info on an lcd.

    Thanks in advance,

    Pedro

  • epam

    Hello Andy,
    thanks for the library, nice work!

    First of all, I would like to confirm the use of the library with Arduino Mega2560 and an ENC28J60 board, with exactly the same modifications as Telek (June 3, 2011 at 04:03) suggests, with the only difference that I have been using MHV AVR Tools instead of WinAVR. It would be convenient if these additions are included in the code.

    While experimenting with your DHCP code, a Linksys (DD-WRT) router, Tftpd32 and WireShark, I have faced the following problems:

    1. My DHCP server uses broadcast packets so I had to set the Broadcast Filter Enable bit in the ERXFCON ENC28J60 register for the packets to be read into the buffer. In the file enc28j60.c, in fuction enc28j60InitWithCs

    enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);

    had to be changed to

    enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN);

    2. Function enc28j60PacketReceive in enc28j60.c reported received packet length incorrectly due to a possible mistake in function enc28j60ReadBuffer

    void enc28j60ReadBuffer(uint16_t len, uint8_t* data)
    {
    .
    .
    *data='';
    }

    Last line was unnesessary because the data pointer does not refer to a null terminated string.

    Having made these corrections, DHCP client functions run without any other problem and Arduino aquires ip,gw and dns automatically which are further assigned by calling ES_init_ip_arp_udp_tcp, ES_client_set_gwip and ES_client_set_dnsip, respectively.

    Keep up the good work!!!

  • Thanks for the updates. Any help producing fixes for other makes of router is much appreciated.

    Cheers

    Andy

  • epam

    Dear Andy,
    excuse me if my 2nd point was not clear but I believe this is a general library bug and not specific to my router.

    uint8_t* data is a pointer to an array of bytes which is not null terminated, as a string would be. So *data=’\’; writes 0x00 to the next memory byte replacing useful data, in my case causing received packet length value 340(0x0154)-4 = 336 to evaluate to 256(0x0100)-4 = 252.


    void enc28j60ReadBuffer(uint16_t len, uint8_t* data)
    {
    enableChip();
    sendSPI(ENC28J60_READ_BUF_MEM);
    while (len--) {
    sendSPI(0x00);
    *data++ = SPDR;
    }
    disableChip();
    *data='\';
    }

    should be edited to

    void enc28j60ReadBuffer(uint16_t len, uint8_t* data)
    {
    enableChip();
    sendSPI(ENC28J60_READ_BUF_MEM);
    while (len--) {
    sendSPI(0x00);
    *data++ = SPDR;
    }
    disableChip();
    }

    The problem arises when the function is called by enc28j60ReadBufferWord

    static word enc28j60ReadBufferWord() {
    word result;
    enc28j60ReadBuffer(2, (byte*) &result);
    return result;
    }

    which is called by enc28j60PacketSend

    ...
    len = enc28j60ReadBufferWord() - 4;
    ...

    Further more one could replace byte and word data types by uint8_t and uint16_t respectively, in accordance to the rest variables in library.

    Thanks again,
    epam

  • marcus

    Hi Andy, I am a newbie of nanode and EtherShield.

    I am testing the EthershieldSimpleClient.pde.

    I have a issue to get a web page that is 2100 bytes.

    My question is, if the BUFFER_SIZE is 500, then I have to get the whole web page in 5 replies from the web server. Any idea how to do it?

    I can only get the 1st packet use the simpleclient at this moment. How to get the others?

    Regards, Marcus

  • Hi Marcus,

    the library as it is now has a limitation in that it can only send or receive a single packet in a tcp session. I have used this with a buffer upto about 950 bytes but any more than that and it doesnt work.
    Its something i’d like to fix but not had the time to look at it.

    Andy

  • marcus

    Hi Andy,
    Thanks for your reply regarding the single packet issue.
    Surely u are busy and many issues are already on your to-do list.

    Instead of fixing all issues just bu yourself, could u share some information / materials for us to fix some of the issues for u?

    For example, while coding in php, I know how to get the following packets, but I have no idea how to do it in C and Ethershield.

    Regards, Marcus

  • ldutra

    Hi Andy,

    Thanks for your library, i’m trying to make a test scheme with arduino what ping hosts, we can configure ip address, and have many features, the idea is to share de source code.

    Can u like send me an example using a arduino pinging a host and printing in a serial port?

    Sds
    Leonardo Dutra

  • elsni

    Hi Andy,

    Thanks for your library. I just want to send tcp packets with one line of text each to a specific server (known by ip) on a specific port (say 18042). The server answers ACK (for ok), NACK (for error) or not at all (timeout).
    I have no idea how to implement this using your library, can you give an example?

    Thank you very much!

    Kind regards, Stephan

  • Andy,

    I can confirm @epam’s suggested changes (July 26, 2011 at 07:23) resolve my problem (Linksys WRT160N router). I was so thrilled to see the DHCP offer actually come through with the broadcast filter change! Still not totally out of the woods, as the Nanode doesn’t realize it has been granted an address yet, but I’m well on my way to solving it now! Big thanks @epam!

    Regards,
    Vic

  • Hi Vic,

    I’m adding this and your other suggestions to th library.

    Thanks for confirming this.

    Cheers

    Andy

  • dirkx

    Below a diff with a few small tweaks to 1) be careful about not overpadding DHCP and deal with broadcast; 2) lets us sent UDP by exposing a few more functions through C++ and 3) allows us to then do rendezvous. So that we can make our presence known without a-priori work.

    Bit confused still as to why the DHCp completion does not call itself the es.ES_init_ip_arp_udp_tcp, es.ES_client_set_gwip(gwip) et.al. And need to see how we can let the DHCP drop into adhoc 192.168.*.* if no DHCP is available – as works so wonderfully with Bonjour/zeroconf/rendesvous.

    Puzzling now as to why UDP hangs the loop() after exactly 32 packets.

    (sorry for the weird formatting of the patch – but wordpress seems to not like special chars.

    dirkx(at)webweaving(punto)org.

    eeb-2:EtherShield dirkx$ git diff
    diff –git a/EtherShield.cpp b/EtherShield.cpp
    index 227c0fe..ac1ab83 100644

  • ldutra

    Hi all,

    Is there a way to implement this code to our library?

    /*
    Ping Example

    This example repeatedly sends ICMP pings and sends the result over the serial port.

    Circuit:
    * Ethernet shield attached to pins 10, 11, 12, 13

    created 30 Sep 2010
    by Blake Foster

    */

    #include
    #include
    #include

    byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // max address for ethernet shield
    byte ip[] = {192,168,2,177}; // ip address for ethernet shield
    byte pingAddr[] = {192,168,2,1}; // ip address to ping

    SOCKET pingSocket = 0;

    char buffer [256];

    void setup()
    {
    // start Ethernet
    Ethernet.begin(mac, ip);
    Serial.begin(9600);
    }

    void loop()
    {
    ICMPPing ping(pingSocket);
    ping(4, pingAddr, buffer);
    Serial.println(buffer);
    delay(500);
    }

  • ozdenmir

    HI Andy,
    Thank you for your library. May i have a newbie request: I am quite good at building hardware but I have nearly no experience in programming. I have built this arduino “http://www.instructables.com/id/A-credit-card-sized-Ethernet-Arduino-compatable-co/” and the webserver example works successfully with the latest “EtherShield Library” you prepared. Now I want to try a simple led switch and a temperature sensor (analog or digital). The switch and sensor sketches in the nuelectronics library doesn’t work for me. Could you put switch and sensor sample sketches to this latest library so I and other enthusiasts can play on it?
    Thank you in advance.
    Ozden

  • michaelword

    hi,
    im pretty new with your Library,
    my question is , how i can i read received UDP packet?
    thank you!

  • […] library is now available from the same author http://blog.thiseldo.co.uk/?p=570. I have not yet uesed […]

  • arduinoenc

    Andy,
    Great library. When using this function though.

    void browserresult_callback(uint8_t statuscode,uint16_t datapos){
    if (datapos != 0)
    {
    // now search for the csv data – it follows the first blank line
    // I’m sure that there is an easier way to search for a blank line – but I threw this together quickly
    // and it works for me.
    uint16_t pos = datapos;
    while (buf[pos]) // loop until end of buffer (or we break out having found what we wanted)
    {
    while (buf[pos]) if (buf[pos++] == ‘\n’) break; // find the first line feed
    if (buf[pos] == 0) break; // run out of buffer
    if (buf[pos++] == ‘\r’) break; // if it is followed by a carriage return then it is a blank line (\r\n\r\n)
    }
    if (buf[pos]) // we didn’t run out of buffer
    {
    pos++; //skip over the ‘\n’ remaining
    Serial.println((char*)&buf[pos]);
    }
    }
    }
    I don’t get anything out of the Serial.println((char*)&buf[pos]);
    I have tried changing the line to Serial.println((char*)&buf[datapos]);
    Then I get all the headers but not body. I have tried to check the server with telnet
    and all seems ok. Using a browser I also get the body returned. Any suggestions?

  • arduinoenc

    Andy,

    More info. Works fine with Apache. Problem is with Cherokee.

  • mzaa

    Hello.
    I have a arduino 1280 and ethernet shield with ENC28J60 (I bought here – http://www.ebay.com/itm/ws/eBayISAPI.dll?ViewItem&item=170680334466#ht_637wt_1110).
    When I use your library, any of the examples did not work.
    Works only this library – http://www.ekitszone.com/download/EKitsZoneEtherShield(MEGA).zip
    Could you please help me. How do I get to work with the library?
    Thanks.

  • poloman

    Hi – is it possible to give a quick example of pinging another machine and waiting for the results? I’ve tried writing the code for it but am not having much luck (I’ve enabled the relevant section in the config file, and have the brief code snippet below, but no luck:

    Serial.println(“Sending Ping”);
    es.ES_client_icmp_request(buf8, checkip);

    while(1) {
    dat_p = es.ES_packetloop_icmp_checkreply(buf8, checkip);
    if (iLast != dat_p){
    Serial.println(“REPLY RECEIVED”);
    }
    etc

  • Omnimusha

    help