I was at a Gumbo Labs meeting recently and one of the members, Mark, showed us the router that he had been working on. He had flashed it with OpenWRT, added an SD card, and a serial GPS module. He used it to collect geospatial network information on the way to the meeting for the demonstration. What interested me the most was the expansive abilities of OpenWRT, as well as the relative cheapness of some of the routers that could host it. According to Mark’s logic, why buy an Arduino when you can spend a little more and have linux, wireless, and a higher level programming language? I still think the Arduino has it’s place in my life, mostly considering you can go from the Arduino to a real, sell-able, AVR prototype easily and for extremely cheap. For certain situations though, using a hacked router is a great idea. So I decided to do some research and I came across the Asus WL-520GU.
You can pretty much ignore the specs you see online because they aren’t really important. Here are the real specs to this device:
- It is extremely small, can run off 5 Volts, and doesn’t consume much current. You can easily run it on a battery.
- You can easily find builds of OpenWRT for the Broadcom chip found in the Asus. Flashing it is simple. OpenWRT is among the more hackable and useful of the WRT firmwares. You can SSH, telnet, or log in over serial.
- Asus left a 3.3V serial port right on the board, just solder in a 4 pin header and you got serial communications. You can log into the board from there or you can have your programs access it and send the info out to the world.
- There is a USB port. You can use some cross-compiled linux packages to access that serial port. This opens up a lot of room for creativity. The most important thing about it is that it gives you more space to store cool stuff, like a python interpreter!
- That leads us to the thing I was most excited about, you can run python scripts on the router. And you can use pySerial to access the serial port!
So, how do we go about hacking this? Well, there are a few initial steps. I figured all of this out by reading these two articles
- http://lizard43.blogspot.com/2009/03/tweet-we-using-asus-wl-520gu-and-xbee.html
- http://www.mightyohm.com/blog/2008/10/building-a-wifi-radio-part-1-introduction/
but I am going to go through all the steps here so I can clarify some things. You should read those and then reference them when I am not making sense. I copied a lot verbatim.
First off, we must take apart the router.
BTW, sorry for the crummy pics, I had to use my phone. Anyway, to take this thing off, unscrew the two visible screws then flip out the corner of the rubber feet on the top-left and bottom-right. There are two hidden screws there. After we remove the casing, you can pull out the board.
Now we need to locate the convenient 3.3V serial port that the Asus designers left on the board. It is pretty easy to spot. It is this empty space for a 4 pin jumper. The pin-outs from top to bottom in this picture are 3.3V – RX – TX – GND.
Now you need to desolder this port so you can get access to it. I found this more difficult than it usually is. To keep you from going through the same, I recommend the following steps:
- Desolder from the bottom of the board. There are some delicate traces on the top and you don’t want to cause a short.
- You may need to use a little solder to get the old solder to flow.
- Don’t heat the board too long, you could damage nearby components or traces.
- Use some good wick, not a sucker. This is one of the few times I will recommend you head over to Radio Shack. Their solder wick is great! Unfortunately, I used this bulk Chinese crap.
Here is what happens when you use bad wick:
Not the worst desoldering ever done, I have heard of people bricking routers this way, but certainly not as clean and easy as it should have been.
Next we need to connect this to our computer. Since this is just basically a serial port, you can use a variety of old hardware. Just remember, this doesn’t follow the standard RS-232 specification of 12 Volts! It is only 3.3. Most people have used the FTDI TTL serial to usb cable for this. I happened to have a few extra FTDI chips lying around for such hacking occasions.
I couldn’t find any female headers in the lab so I just grabbed a breadboard and some wires. I soldered the wires directly into the board. You normally want to solder on headers but I didn’t have a need for this at the time b/c once you get OpenWRT on this thing, you can SSH in. The mapping is simple. Cross RX and TX, makes sense if you think about it, and connect grounds to each other. No need to connect the 3.3V on either side.
Once I plugged it in, I checked to see if the FTDI drivers were working and the port was recognized. You also need to know the unique name of the device. I opened up the terminal and checked my /dev folder for descriptors starting with tty.usb.
Now that I know the port is working and where it is, I wanted to see if I could listen in on the Asus firmware as it starts up. I opened up ZTerm, set it to /dev/tty/usbserial-A3000RBH, set the baud rate to 1152oo, and set the protocol to the standard ASCII 8N1 (8 bits, No parity, 1 stop bit). Then I did a hard restart on the router [turning my surge protector off then on], and saw the boot log stream into my ZTerm window.
Now we need to install openWRT. You can build it yourself, but I recommend getting this pre-built version from mightyOhm. Next you need tftp. I know OS X has it, not sure about other OSs. After you have all this gathered, you need to configure your LAN network interface to use a static ip and connect directly to your router. We are going to tftp the openWRT firmware over to the router. The process for this is different for all OSs, but you basically need these settings
- ip: 192.168.1.XXX #just make up something for XXX that isn’t used, like 180
- subnet mask: 255.255.255.0
- router: 192.168.1.1 #this is the default ip of the router
After you are set up, connect up an ethernet cable from your computer to LAN port 1 on your router.
Unplug your router, hold down the black restore button, and plug back in. After a few seconds, you will see the router trying to read a tftp connection in your ZTerm window. It will be saying
Failed.: Timeout occurred
Reading:: TFTP Server.
Over and over again. What you need to do is connect to the router over tftp and upload the openwrt firmware you downloaded earlier.
I opened up a terminal and ran these commands. Your process may slightly differ
$ cd ~/Downloads/ #this is where my trx file was
$ tftp
$ trace
$ timeout 1
$ mode binary
$ connect 192.168.1.1
$ put openwrt-brcm-2.4-squashfs.trx
Once you run the last command, you should see the router accept and start to upload. Don’t touch anything at this point!
Wait for it to say done. XXXX bytes written as seen above. It may take a few minutes, be patient. After this, you can restart the router and watch ZTerm and if all goes well, hit enter when asked and you should see openWRT start up!
OpenWRT comes with busybox so you have most of the normal linux commands like ls:
Now, we want to set up our network interface. I wanted to turn the wireless router into a wireless client. All we have as a text editor is vi so you may need to brush up on it’s use.
First we must set up the wireless interface:
root@OpenWrt:~# vi /etc/config/wireless
edit it to look like this with your own settings:
config wifi-device wl0 option type broadcom option channel 2 # the channel your wireless network is on # REMOVE THIS LINE TO ENABLE WIFI: # option disabled 1 (comment out or remove this line entirely) config wifi-iface option device wl0 option network lan option mode sta # configures the router to connect to your network option ssid MyNetwork # the SSID of your network option encryption wep # the encryption mode of your network option key XXXXXXXXXX # add this line with your WEP key
Then set up DHCP:
root@OpenWrt:~# vi /etc/config/network
Edit it to look like this commenting out last 2 lines:
#### LAN configuration
config interface lan
option type bridge
option ifname "eth0.0"
option proto dhcp
#option ipaddr 192.168.1.1
#option netmask 255.255.255.0
Check your resolve.conf file:
root@OpenWrt:~# cat /etc/resolv.conf
It should say this, if not, make it so:
nameserver 127.0.0.1
Now we can restart the network interface:
root@OpenWrt:/# /etc/init.d/network restart
And we should be able to ping something!
After this, we now have a functioning linux machine! Not bad for 25 bucks. Now I desoldered the serial port hack job [unplug first], and I can SSH or telnet into the router:
If I remember correctly, the username and password were both root.
I have had a few ideas about what to do with this. I think the one I am going with is a home power monitoring system similar to this one :
http://www.picobay.com/projects/2009/01/real-time-web-based-power-charting.html
The basic architecture would be AC clamps in my breaker box -> arduino -> serial port on asus -> python script running off usb -> pachube over wireless connection. I originally thought python would be perfect for this, and it probably is, but I ran into some issues getting USB to work. It was a pain in the ass. Then I realized, do I actually need to write a program to get the info from the serial port to the web? Hello no! I got linux to work with, and linux people have been doing this since the beginning of networks. Fortunately, I found this page that had exactly what I was looking for. Here is the bash script he uses:
#!/bin/sh
while [ 1 ]
do
temp=$(grep -m 1 “temp” /dev/ttyS0|cut -d “=” -f 2)
curl –request PUT –header “X-PachubeApiKey: your-key-here” –data “$temp” “http://www.pachube.com/api/1931.csv”
sleep 300
done
He is basically just listening in on the serial port and parsing the incoming string then piping it to curl [which can be obtained on the Asus via the package manager opkg]. He is using it for temperature but it can easily be adapted for my purposes.
I am waiting to get an AC clamp in and when I do, I will write a part 2 with the rest of the project.
















Parallax RFID Reader <--> Arduino
A while back, I purchased a Parallax RFID reader and used it for authentication for my house door. It was kind of a hack job and wasn’t as stable as I would have liked so I never documented it and put it on the backburner. I recently decided to revisit the device for a project for Gumbo Labs.
The Parallax reader
BTW, you can now get this at your local Radioshack?!?. Maybe they are starting to move in the right direction again? Who knows.
Anyway, this device was initially easy to get running but it was not as stable as I hoped it would be. The example code online did not fully account for the quirks of this reader. I had to closely read the manual to make it work as expected. I am going to briefly describe how to get the best out of this reader and properly integrate it with your Arduino.
First you want to get them connected. The quickest way to do this is with a breadboard and some wires like this guy does:
Connecting Arduino to RFID reader
The mapping should be similar to this:
Keep in mind that when you upload your binary to the Arduino, you may need to disconnect the Parallax TX connection, just a warning.
Now to the Arduino code…
I will explain each piece in detail and give the whole code at the end. If you are impatient and hate learning, go there.
First let’s deal with this /ENABLE pin. Here is what the documentation says about it:
So, when the pin is HIGH, the reader is inactive and in a low current consumption mode. When the pin is LOW, the reader is active and can read tags. To utilize this pin, I created two functions:
The usage of this functionality depends on your application. If you (and by you here I mean the Arduino) know when you will need to read a tag, keep the reader inactive until then to conserve current. This situation is not as likely as you usually want the Arduino to just know when a tag is next to it at any time. In this case, we will use it to briefly deactivate the reader after a tag is read. This will keep the Arduino from getting duplicate or junk/half reads and it will reset the reader for the next tag.
Reading a Tag’s Unique ID
As the documentation describes, when the reader is in active mode and a tag is placed near the antenna, a 12 byte message will come across the Parallax TX serial line. The documentation says this about the serial configuration:
8N1 is the standard for your Arduino, you just have to tell it to start up the UART at 2400 baud in your setup() function:
The designer of the RFID reader, KingPin if I am not mistaken, designed a custom protocol so we can determine where the tag starts and ends. Once again, we refer to the documentation (click to get a larger view of the picture):
RFID tag message protocol
In other words, you should read the incoming serial bytes until you find the start byte [hex 0x0A || decimal 10 || line feed]. You should then read the next 10 bytes as the tag’s unique ID and hope that the stop byte [hex 0x0D || decimal 13 || carriage return] shows up last. BTW, if you ever need to know something like the hex and decimal values of line feed, check here.
Now let’s take a look at the piece of code which reads the tag. I am going to litter it with comments, it looks huge but it is actually pretty concise:
Dealing with radio interference
Let’s say you implement the getRFIDTag() function like this:
So, you have this running and you are using the Arduino’s serial listener in the IDE, and you notice that every once in a while, you get a random tag for no reason. This kind of bug can be a problem and it is one of the things that made my door authentication device so unstable. I wish I would have RTFM a little closer:
I originally thought I was the lone genius who came up with this solution until I read that paragraph
Oh well.
Let’s look at a way we can implement this idea. I noticed when you hold a tag to the reader, considering you don’t deactivate after a read, it just continues to spit out the number until you pull the tag away. So, what we need is a function that is called immediately after getRFIDTag() that reads the code again and validates that it is the same. Most of this function is the same as getRFIDTag(), and I hate to break DRY principles, but we are going for simplicity here and I don’t want this to turn into tutorial on pointers!:
So, this is all good right? No, not really. If you were able to see a problem with this line:
you are very perceptive. This will work for real tags but will make things complicated when noise occurs. Consider the believable case in which we get a junk tag from noise every 30 minutes. When we get that junk tag, we will be stuck on that line. One way to get around it is to apply a timeout. Here is a pretty ghetto way to implement that, just change the above line to this [UPDATE, there is a bug with this, see end of page]:
We define VALIDATE_LENGTH to be the number of milliseconds, roughly, that the isCodeValid() function will wait until it realizes the tag you are asking to validate is just noise.
#define VALIDATE_LENGTH 200 //wait 200 msSo, now you should be good to go. If you are looking to storing and comparing keys in non-volatile memory, I suggest looking at the EEPROM library. I already wrote some code to do this so if you are curious let me know in the comments. As promised, here is all the code for this article:
I have tested this as well as I can. I have yet to catch any noise events ‘in the wild’ so to speak, which concerns me [read Updates, lol]. But I have tested each case in the isCodeValid() function. I have caused a false validation by timeout and by differing keys [repetitive noise]. But I have also broken it by causing it to read “half” of a key. If it still doesn’t work for you, get creative, there are many ways around the interference issue.
Please let me know if you find faults or improvements and Enjoy
Updates
02/07/2010 – For those of you who have been using this code and still getting some noise, I apologize because I just found a bug with the isCodeValid function. For some reason, I was not getting past the line:
I ran this code right before that line:
And this came on the port:
Now, ignore the line a0r10. It is not a bug, it is just that it takes so long to print to the serial port at 2400 baud. Anyway, what is obvious is that my whole function was breaking b/c the STOP_BYTE (13), was still in the buffer. I tried to do a flush before the function but that didn’t work for whatever reason. So what I did is change the while loop to this:
and then after the while loop breaks, throw that 13 away:
Sorry this took so long for me to figure out, I was on hiatus, I hope it didn’t mess anyone up. This change is reflected in the whole piece of code.