Category Archives: Ethernet

Configuring the TP-LINK TL-WR702N nano router for Arduino

2015-02-07 Update: Added default WiFi password.

The two most-viewed pages on this site are often the following to Arduino articles:

The first one deals with a bug (?) I found in in the Arduino Ethernet library that prevented it from properly handling multiple incoming connections to the same port. The second was sharing my discovery of the $20 TP-LINK TL-WR702N nano router. It seems I am not the only one not happy that Arduino WiFi shields can be as much as $90, while cheap ethernet shields can be found for around $10.

The TP-LINK can be configured to connect to a WiFi network and then plug in to an Ethernet-only device and link it to the WiFi. Folks use them to get Ethernet printers on WiFi (such as the Lexmark printer I have — the official Ethernet module for it is $50, but I can use this TP-Link and be wireless printing for $20). I use one to get my Arduino on WiFi. Note that the Arduino will not have any control over the WiFi connection and won’t be able to select WiFi

This article is a quick guide to getting the TP-LINK set up for use with the Arduino.

TP-LINK TL-WR702N nano router box.

TP-LINK TL-WR702N nano router box, pictured next to a pen for scale.

1. Buy the TP-LINK WR702N. I got mine from Amazon for $19.99. It comes in a tiny box and is packed almost as nicely as an Apple product.

Inside the box you will find the tiny router (about 2″x2″x.5″), a micro USB cable, an Ethernet cable, and a USB power supply. There is also a mini-CD and a few small quick start guides. The guides are put together very well and have plenty of photos.

On the back of the TP-LINK unit will be the MAC address, but unless you have multiple units, you won’t need to know this.

2. Power up the TP-LINK by either plugging it up with the USB micro cable to a USB port (on your computer or a hub), or via the power supply.

3. The unit will boot up and after a few moments a new wireless network will appear that starts with “TP-LINK_xxxxxx” with the last part being the end of the MAC address of the router. Connect your computer to it. You will be prompted for a WiFi password, which you will find under the tiny barcode on the back of the unit. (It will be the last 8 HEX digits of the Mac address.) Give it a few more moments to connect and get an IP address. (Make sure you aren’t getting an internet connection some other way, like Ethernet. There are also ways to configure this router via Ethernet, but you’ll have to check TL-LINK guides for that.)

4. Open a web browser and go to: tplinklogin.net  It should prompt you for a username and password. You will find these on the back of the router, but they should be admin and admin.

TP-LINK WR702N login

Enter “admin” for the username and “admin” for the password.

5. You should see an admin webpage that is coming from your router. The first thing we need to do is configure the router to connect to your WiFi access point and connect to the internet. Click on Quick Setup under Basic Settings and click Next.

TP-LINK WR702N quick setup

Select Quick Setup.

6. The first screen is to select the Working Mode. We want Client, so choose it then click Next.

TP-LINK WR702N working mode

Select Client mode.

6. Next we will do Wireless Client setup and choose which WiFi network this nano should connect to. You can manually type it all in, but it’s easier to just click the Survey button so it scans for networks that are available. From that list, select your own WiFi network and then you will have an easy spot to enter your WiFi network password.

TP-LINK WR702N wireless client

Click the Survey button to obtain a list of available WiFi networks.

TP-LINK WR702N survey

Select your WiFi network from the list.

TP-LINK WR702N wifi password

Enter the password to your WiFi network.

7. The unit will then reboot and attempt to connect to your WiFi network. When it does, it will begin passing the WiFi connection out to the Ethernet port. To test this, turn off WiFi on your computer, and plug it up to the TP-LINK nano router via the included Ethernet cable. You will need to configure your computer’s Ethernet connection for DHCP. If it is working, after a few moments you will get an IP address assigned to your computer by the nano. Once the connection is made, you can test by going to Google.com or a known-working site.

8. Once you know it’s working, you should update the firmware on the nano to the latest. You can download the firmware here:

http://www.tp-link.us/support/download/?model=TL-WR702N&version=V1

Look for the latest version. It should look something like this:

TP-LINK WR702N firmware

Look for the latest version of the firmware for the TP-LINK TL-WR702N on the TP-LINK website.

Download this .zip file, then extract it somewhere you will be able to find it. It will create a folder with a few files inside, including a “.bin” which is the actual firmware update.

Log back in to tplinklogin.net and go to System Tools and Firmware then browse to the .bin file you just downloaded.

TP-LINK WR702N update

Browse to the .bin file you downloaded and update the firmware.

After it updates, the nano will reboot once again. On mine, this reset all the router settings, and I had to log back in and set it up again. There is probably a better set of steps to do this, but this is how I went through it and took screen shots so that is what I am sharing.

Once this is done, you can unplug and switch your computer back to normal internet connection. Now the TP-LINK can be plugged to power and the Arduino Ethernet shield and you can use the Ethernet library to make connections via your WiFi network.

NOTE: Since the nano requires using a computer and web browser to select which WiFi it connects to, this is not a portable solution. You cannot choose what WiFi to connect with (or the password or anything) from the Arduino. If you wanted to take your Arduino somewhere else and get it online, you would have to have a computer available to connect to the TP-LINK nano and reprogram which WiFi network it connects to. If you have a real WiFi shield for the Arduino, you can do this in software.

I hope these quick notes help…

Cheap Arduino Wiznet 5100 ethernet shield

e-Bay seller kbellenterprises has a Wiznet 5100 ethernet shield for the Arduino for just $11.49 with free shipping. And, it ships from Missouri (fast). I have not used this shield, but it’s a great price if it works:

http://www.ebay.com/itm/Wiznet-W5100-Ethernet-Shield-for-Arduino-MicroSD-UNO-MEGA2560-FAST-US-SHIP-/171264625782?pt=LH_DefaultDomain_0&hash=item27e02acc76

This seller also has various Arduino clones (a Leonardo clone for $12.75 and a Leonardo mini for $9.99) with free shipping as well.

Arduino ethernet for $10

Here is a heck of a deal. This Arduino Ethernet Shield uses the WizPro 5100 like the official Arduino shield:

http://www.icstation.com/product_info.php?products_id=1494#.UxXX3TK9KSM

If this $10 shield works the same, it is a very cheap way to get internet connectivity out of an Arduino. If you get one, let me know how it works for you.

The shield I used for my Ethernet experiments was made by Sainsmart and it runs about $20:

http://www.sainsmart.com/sainsmart-ethernet-shield-w5100-for-arduino.html

And for those who don’t want to wait for mail order (from China?), you can get a $20 Seeed ethernet shield at your local Radio Shack:

http://www.radioshack.com/product/index.jsp?productId=13356964

Pretty cool.

A cheap way to get an Arduino on WiFi

Update 3/8/2014: There is an Arduino WiFi shield for around $40 now sold by Adafruit Industries (but you have to solder on the connectors). That shield costs about as much as the TP-Link router I mention in this article, and a $20 Ethernet shield. However, with clone Ethernet shields now around $9 from China, it’s still cheaper to hack something together. (Another advantage of the TP-Link device is you can have it set up to connect and publish the connection via Ethernet, and plug it in to anything that needs it — an Arduino, an OUYA, TiVo, etc.)

To test my Arduino Ethernet code, I needed a way to get my Arduino on my home network. Unfortunately, my router is somewhere else, and I was not able to run a long ethernet cable to it. I initially experimented with making my old MacBook act as a gateway using Apple’s Internet Sharing. I was going to have it share my home WiFi internet out the ethernet port, and hook that port up to the Arduino. Unfortunately, again, it seems there is some problem with the current version of Mac OS X and Internet Sharing and I was unable to get it to work. So, I turned to a free bit of software called Ice Floor which is a GUI front end for the Unix firewall running on Mac OS X. With a bit of Googling I was able to configure Ice Floor to let my Arduino hook to the MacBook, then reach out to the Internet.

I won’t be writing about that. It was easy, once I figured it out, but I spent all night trying.

What I really wanted was a way to get my Arduino on my home WiFi.

With Arduino ethernet interfaces being real cheap if your order from China, or slightly less cheap if your order from the USA, it puzzled me that WiFi shields were so much more. Well, if you don’t need everything to fit inside a small Arduino case, you can just get one of the cheap Ethernet shields and then use one of these things:

http://www.amazon.com/TP-LINK-TL-WR702N-Wireless-Repeater-150Mpbs/dp/B007PTCFFW/

This $23 TP-LINK WR702N WiFi router is really teeny tiny (about 2″x2″ and .5″ tall), and comes with a short ethernet cable, USB cable, and USB power supply. It has several modes of operation, including the one you would expect — plugging up to an Ethernet jack and broadcasting it as a WiFi signal. But, it also has a Client mode, so you can plug it up via Ethernet to the Arduino and then use it as a WiFi card.

Configuration was a bit tricky because I didn’t know what I was doing, but basically, you plug it up to power (USB or power adapter), and configure it via your computer and an Ethernet cable. If your computer is already on a network that is 192.186.0.x (like mine was, from my home DSL router), you will need to disable that from your computer (turn off WiFi, or unplug the Ethernet cable). The instructions (on the website) tell you to change your computer’s IP address to 192.168.0.10, and then in your web browser you go to 192.168.0.254 (which is the router’s default IP address). Up loads an admin web page.

Type in the password (admin/admin), then click the easy setup button and select Client. It will then give you a screen where you can browse to the WiFi network you wish to join, and enter the password (if it’s a protected network) and encryption method used (again, if it’s a protected network).

Once you do that, the little box will reboot and then try to connect to that WiFi hotspot, and then get an IP address from it and link the Ethernet port to the WiFi… So, configure it, then unplug it from the computer and plug it to the Arduino and… your Arduino’s Ethernet code now talks out WiFi.

So, if you ever try to telnet in to my home Arduino, that is how the connection will be getting there.

Just passing information along. Hope it helps someone.

A real Arduino Telnet server?

  • 2014/03/16 Update: The source code to this is now on GitHub. Check the Arduino link at the top of each page of this site.
This sketch tries to process Telnet protocol mesages.

This sketch tries to process Telnet protocol mesages.

The example code for the Ethernet library has some things that try to act like Telnet servers, but really all they do is open up a port and listen for data. When someone connects with a Telnet client, that client will send Telnet protocol messages trying to negotiate the connection. The Arduino examples I have found posted around do not deal with this, which means whatever “garbage” comes in could have unexpected results if the program isn’t properly ignoring invalid data.

Tonight, I began working on a more complete Telnet server for the Arduino. I am sure many of them exist, but what better way to learn than to reinvent the wheel?

I am doing a “fuller” version that would support many of the Telnet protocol options, then a dumber one that would just get rid of the protocol from the stream and ignore pretty much everything.

And, I will wrap that with a simple to use bit of code for making connections without all the tedious setup.

Comment if this project is of interest, as I have several others I may work on first.

Arduino Ethernet and multiple socket server connections

Greetings! If you are finding this writeup useful, please leave a comment. I originally shared these modifications in April 8, 2013. In February 2015, I went through them again using the current Arduino 1.6.0. They still work, but I did tweak the source code notes a bit to be clearer. – Allen

  • 2014/04/03: I just started using GitHub and found all the Arduino sources there, including this bug report which seems to discuss and address this issue. I will be reviewing it when I have time to see if those fixes take care of this bug.
  • 2014/04/08: This is, by far, the most viewed article on this site. I suppose I should do more posts about Arduino Ethernet.
  • 2013/04/09: I have done some more tweaks to the code listed in this article, and will try to update them when I have a chance. I will probably spin it off in to a whole new article on an easy “drop in” telnet server I am working on.
  • 2014/04/14: Fixed some HTML escape codes in the source code. (Thanks, Matt!)
  • 2014/04/16: You can now get an Ethernet shield shipped from the US for $11.49.
  • 2014/04/19: In the comments, Petr Stehlík pointed out that it doesn’t look like a check against incoming IP address is done, meaning that if any packet was received with the same port, it would just be accepted. I will need to investigate the rest of the code and see if it does that check. If not, you could blast a packet to an Arduino and as long as you match the port, it would accept it. That seems real bad, but should be very easy to fix, if needed.
  • 2015/02/15: I just checked these updates against the Arduino 1.6.0 release, and they still work. I am updating the notes on this page to note where the libraries folder is found on Mac OS X, and to clarify where one of the changes goes. I have zipped up my changed and places them here: EthernetMultiServer.zip This may allow a clean 1.6.0 install to “Import Library” and work, but I have not tested that yet. Also, Arduino forum user SurferTim has contributed another way to accomplish this without fixing the library. He has posted a Telnet example in the Playground that talks directly to the Wiznet 5100 chip to keep the incoming connections straight. Very clever (and similar to what I had to do in the library to track the remote ports and keep them separated). Cool
  • 2015/05/22: Similar to the SurferTim approach, a comment by Gene provides another standalone way to do this in code without having to modify the library. He includes a full example in his comment.

NOTE: The links and prices given below may be out of date. Since then. I discovered this seller (kbellenterprises) on e-Bay. They offer some low-cost Arduino clone items. They have always been responsive, and ship very fast. They currently have an UNO clone for $8.49, and a Wiznet 5100 Ethernet shield for $11.49.

The Arduino Ethernet shield (or the $17.99 workalike made by SainSmart) adds internet support to the Arduino. The limited memory of the Arduino does not have to run a full TCP/IP stack. Instead, the Ethernet shield uses a Wizpro chip that handles Ethernet, TCP, UDP and IP protocols. This particular chip, Wizpro W5100, supports four simultaneous connections. This means you could have an Arduino sketch that opens four different websites at the same time, or you could run a server that allows up to four simultaneous users to connect.

At least, you could if the Ethernet library worked right. The way it was designed (I call it a bug or at least an oversight), the existing library would only allow four incoming connections if each one was listening on a different port. For example, if you have port 23 set up to monitor incoming TELNET connections, and one user was connected, any other attempts to connect would be refused until the first connection was closed. I wanted to use the “up to four connections” part to still allow other users to connect, and then tell them “The system is busy. Go away.”

My first attempt to do this was to just create two server instances:

EthernetServer server1(23);
EthernetServer server2(23);

I then modified the WebServer example and trimmed everything out except what I wanted. My main addition was this second server instance, and a check for connections to it while processing the primary connection. It looks like this (see notes afterwards):

// MultiServer Demo

#include <SPI.h>
#include <Ethernet.h>

byte      mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 100);

EthernetServer server1(23);
EthernetServer server2(23);

void setup()
{
Serial.begin(9600);
while (!Serial);

// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server1.begin();
server2.begin();
Serial.print("\nServer is listening at ");
Serial.println(Ethernet.localIP());
}

void loop()
{
EthernetClient client2;

// listen for incoming clients
EthernetClient client1 = server1.available();
if (client1) {
Serial.println("Client A connected.");
client1.println("Greetings, program!");

while(client1.available()>0) client1.read(); // Gobble

// Loop while client is connected.
while (client1.connected())
{
client2 = server2.available();
if (client2.connected()) {
Serial.println("Client B connected. Getting rid of them...");
client2.println("\nThe system is busy. Try back later.\n");
delay(1);
client2.stop();
Serial.println("Client B disconnected.");
}
// Then handle the actual client.

// If data is available, just read it and write it back to the user.
if (client1.available())
{
char c = client1.read();
if (c>0) Serial.write(c);
}
} // end of while... go back and do it again.

// If here, we must no longer be connected.
delay(1);
// close the connection:
client1.stop();
Serial.println("Client A disconnected.");
}
}

My plans was to wait for a connection. Once I had one, I would sit in a loop (as long as they remained connected) and check a second server instance to see if an additional connection attempt was made. If a second attempt was made, I’d send them a quick status message, then shut them down and go back to monitoring the main connection.

This should work, but doesn’t. It produced unexpected results:

Server Output:

Serving at 10.0.0.42
Server is listening at 10.0.0.42
Client 1 connected.
Client 2 connected. Getting rid of them…
Client 2 disconnected.
Client 1 disconnected.

Client (telent) Output:

alsmb:~ allenh$ telnet 10.0.0.42
Trying 10.0.0.42…
Connected to 10.0.0.42.
Escape character is ‘^]’.
Greetings, program!
The system is busy. Try back later.
Connection closed by foreign host.
alsmb:~ allenh$

It seemed the Ethernet could not distinguish between the two connections. I altered the server config to use different ports:

EthernetServer server1(23);
EthernetServer server2(2323);

Perhaps I could let 23 (telnet) be the main port, and 2323 be the status port. This provided much better results.

Server Output:

Server is listening at 10.0.0.42
Client 1 connected.
hello (I typed this from telnet)
(then, I made a second connection from another terminal, to port 2323)
Client 2 connected. Getting rid of them…
Client 2 disconnected.

On the first terminal, I was able to type “hello” and continue my connection, while the second terminal connected, then received the “Go away” message (after pressing some keys to generate some data to wake up the Ethernet code).

So it could work, but not with the same port.

Thanks to a forum post I found earlier explaining how to obtain the remote connection’s IP address, I was aware that the source code to the Ethernet libraries was part of the Arduino IDE, and that it was easy to make changes.

I decided to take a look and see if I could figure out how this Wiznet chip works.

Wiznet W5100

The Wiznet chip is an independent device. The Arduino sends it commands via the SPI bus (like sending byte commands to it) and then data can be read and written back, similarly to talking to a serial port. The Wiznet chip can be programmed to listen to up to four different socket connections, and then it takes care of the rest. The Ardunio basically says “Hey, Wiznet… Listen for connections on Port 23 of Socket 0” and then the Arduino code will query the Wiznet chip saying “Is anyone there?” and if so, handle accordingly.

Inside the Ethernet library code, I saw that it had an array to hold the ports the user was configuring. When you do EthernetServer begin(23), it puts a 23 in the first available slot then programs the Wiznet chip accordingly. These slots are how the Arduino knows which socket of the Wiznet to query. And that is where the problem is.

If you do “EthernetServer server1(23)” followed by “server1.being()”, slot 0 is set up with 23 and Wiznet socket 0 is programmed to listen for port 23 connections. If you then do “EthernetServer server2(23)” followed by “server2.begin()”, then slot 1 is set up with 23 and Wiznet socket 1 is programed to listen to port 23 connections. The Wiznet hardware is fine even with all four of it’s sockets listening to the same port. It tracks the actual connection internally.

But the Arduino code ONLY tracks the port number. So, if someone connects to the first socket 0 port, and is using it, then someone tries to connect to port 23 again, the Wiznet will hook them up to socket 1. The Arduino code makes a mistake, and when it checks for data, it grabs the first slot that matches the desired port. So, it keeps reading and writing data to slot 0 (socket 0) and never sees the second port 23 connection.

To resolve this, I made a few minor changes to the Arduino ethernet library code. First, I added secondary storage to track four remote ports (the ports used on the connecting client), and then added a bit of code that walked through all the available sockets trying to match up local server port number AND remote client port…

And it worked the first time, much to my amazement!

Here are my notes and modifications. There are a few things I did which I am not certain are correct, but they worked so I am sharing them. I will make a note of the parts I am unclear on.

Ethernet Library Modifications:

/*--------------------------------------------------------------------------*/
// 2015-02-15: Verified against Arduino 1.6.0.
//
// To fix the Ethernet library so it correctly allows multiple connections
// to the same port, the following files will need to be modified:
//
// libraries/Ethernet/src/Ethernet.h
// libraries/Ethernet/src/Ethernet.cpp
//
// libraries/Ethernet/src/EthernetClient.cpp
// libraries/Ethernet/src/EthernetClient.h
//
// libraries/Ethernet/src/EthernetServer.cpp
//
// On Mac OS X, these are embedded inside the Arduino.app package. Browse
// to that in the Finder, then right-click and select "Show Package
// Contents" and then you can go to:
//
// Contents/Resources/Java/libraries
//
// Is there a better way?
/*

Modify the following files:

1) Ethernet.h: The Ethernet object currently only tracks which Port the
socket is listening to. Add the following array to hold the remote Port.

Add this after static "uint16_t _server_port[MAX_SOCK_NUM];"

// ACH - added
static uint16_t _client_port[MAX_SOCK_NUM]; // ACH

2) Ethernet.cpp: Add the declaraction of the new array.

Add this after "uint16_t EthernetClass::_server_port[MAX_SOCK_NUM]"

// ACH - added
uint16_t EthernetClass::_client_port[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; // ACH

3) EthernetClient.h: Add prototypes for the new functions, and declare a
new local variable that will track the destination port of this client.

Add this in the private: section

// ACH - added
uint16_t _dstport; // ACH

// ACH - added
uint8_t *getRemoteIP(uint8_t remoteIP[]); // ACH
uint16_t getRemotePort(); // ACH

4)  EthernetClient.cpp: When the Client object is stopped, it resets the
_server_port to zero. We should probably do this for the new _client_port.
In void EthernetClient::stop():

Add after this: EthernetClass::_server_port[_sock] = 0;

// ACH - added
EthernetClass::_client_port[_sock] = 0; // ACH

Add these two functions at the bottom of the file:

// ACH - added
uint8_t *EthernetClient::getRemoteIP(uint8_t remoteIP[]) // ACH
{
W5100.readSnDIPR(_sock, remoteIP);
return remoteIP;
}

uint16_t EthernetClient::getRemotePort() // ACH
{
return W5100.readSnDPORT(_sock);
}

5) EthernetServer.cpp: This code has to be modified so when it checks for
a connection, it checks both the Port (existing code) AND the remote
client's port (new code). If the connection has never been made, it will
initialize the remote port varaible correctly.

Add the following code to available()

EthernetClient EthernetServer::available()
{
accept();

for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);
if (EthernetClass::_server_port[sock] == _port &&
(client.status() == SnSR::ESTABLISHED ||
client.status() == SnSR::CLOSE_WAIT)) {

// ACH - added
// See if we have identified this one before
if (EthernetClass::_client_port[sock] == 0 ) {
client._dstport = client.getRemotePort();
EthernetClass::_client_port[sock] = client._dstport;
return client;
}
if (EthernetClass::_client_port[sock] != client._dstport) {
// Not us!
continue;
}
// ACH - end of additions
//if (client.available()) { // ACH - comment out
// XXX: don't always pick the lowest numbered socket.
return client;
//} // ACH - comment out
}
}

return EthernetClient(MAX_SOCK_NUM);
}

...and code to write():

size_t EthernetServer::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;

accept();

for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);

if (EthernetClass::_server_port[sock] == _port &&
// ACH - added
EthernetClass::_client_port[sock] == client._srcport && // ACH
client.status() == SnSR::ESTABLISHED) {
n += client.write(buffer, size);
}
}

return n;
}

*/
/*--------------------------------------------------------------------------*/

During this research, I also found this part to be bothersome:

if (client.available()) {
// XXX: don't always pick the lowest numbered socket.
return client;
}

Unlike the EthernetClient.available(), the one for EthernetServer really shouldn’t be checking for data. It’s checking to see if a brand new connection has been made, then the code will be checking for data available elsewhere. For this to not just always return client would mean you would get a connection, but never see it until there is data. You couldn’t use this code to write a server that someone telnets to and it just spits out something (like a status or a time). It looks like it would force the remote user to send data first before the Arduino code even knows the connection is there.

I commented out the if so it always returns client, since it will bypass that if it finds no matching socket. It seems to work.

Bug?

Coming soon… Multi user BBS for Arduino!