So the other night I suddenly woke up in the middle of the night. I was fumbling through my extremely messy desk, which was next to my pillow, to find my phone so that I could see the time. Alas my desk was far too messy to find my phone in the dark. I was far too lazy to take the effort of turning on the lights just to see the time. That was when my eyes glanced upon the ominous green blinking LEDs blinking fervently on my router docked on my wall. I wished I had an LED clock instead and boom it hit me! I have a linux-based DD-WRT router, that means I have full control over it :P. So that was how I began my quest on converting a piece of network equipment to a digital clock!
The next day, I set upon my quest to find out how I could control the blinking LEDs on my router. I noticed that my router had a total of 9 LEDs , and I figured that was more than sufficient to display the time in binary to a sufficient degree. My plan was originally to use 4 LEDs to display the hours (0-11) and 4 more to display the minutes (0-60) with a 5 minute granularity. And use one LED in between as a separator. I never really cared much for the actual LED indicators , since they never really told me much. I mean the most frequent connectivity issue I have, is that of a loose Ethernet cable and not once have I actually glanced to find out if the LED was on or not while troubleshooting it. I simply jammed both ends of the cable in till it eventually connected my laptop :P
The first thing to do was to somehow figure out how to turn on/off some of the LEDs. After a bit of googling and research, I came to know that these LEDs are usually controlled through an interface called the GPIO. And it seems DD-WRT uses this very Hardware interface to provide control over LEDs as well as other I/O such as buttons on the router which could be used for input. For e.g on my TP-LINK WR-740N router , I have a QSS switch , which I never use (nor should you), which can be used as an input device accessible using GPIO.
So how do we actually use this GPIO to control our LEDs? Well there appear to be two simple methods. Before that you need to ensure that your router’s kernel has the GPIO module enabled. First lets ssh to the router so that we can start playing with the LED controls. You can check that the GPIO module has been added by heading over to /proc/gpio . There you will find several nodes corresponding to control points of several GPIO pins. GPIO has several “output” pins which we can use to control the LEDs. We can directly use these files to control the LEDs, however a simpler command line tool called “gpio” exists to simplify the process.
$ gpio
gpio <poll | enable | disable> <pin>
$ gpio enable 27
$g pio disable 27
Basically “gpio enable/disable pin” enables/disables the output pin specified. The next question would be to figure out which pin number corresponds to which LED on the router. This page provides several example scripts which control LEDs, along with several GPIO pin mappings to LEDs for several devices. Unfortunately my device wasn’t among them :( . So I had to resort to figuring out which pin mapped to which LED manually. Eventually though it ended up being fun :P , I managed to write short shell scripts , which would flash a set of pins on off repeatedly so that , I could test several subset of pins at once, and observe the corresponding effects on the LEDs in order to finally identify the mapping for my device. After some effort I obtained the mapping for my router:
26 : QSS Input Button
LED s From Left-to-Right
? : Power LED: I couldn't find this one, I suspect it is hardwired and can't be controlled
27 : Some led with a gear symbol. (No idea what its for)
0 : Wifi Indicator
14 : LAN1 Indicator
15 : LAN2 Indicator
16 : LAN3 Indicator
17 : LAN4 Indicator
13 : Internet Indicator
1 : Lock Symbol : Again not sure , Guesing WPS/QSS indicator
Some of these had inverted effects such as 27,17 which would turn off when enabled with gpio instead of turning on like other pins.
After obtaining the mappings, I set about writing a script in bash, keeping these mappings in an array for easy use. But alas , I realised a bit later that the router does not use bash, but uses busybox’s ash. And ash does not support arrays in scripts.
This put me in a bit of a dilemma and I was considering writing a C-program compiled for the MIPS architecture of my Atheros router. I was trying to avoid a an inefficently written shell script to avoid overloading my router’s CPU. But cross-compiling for MIPS to run on my router was no easy task. I took great efforts to compile gcc and binutils for mips but that didn’t work very well either. Firstly I failed to compile even the hello world program for mips using gcc. And worse a blank binary I generated by compiling “main()” in C , did not even run on my router.
Eventually I gave up on the cross-compilation and much later sat down to write it in pure shell. After a few minutes of quick hacking I had a simple short script , which although inefficient ought to get the job done. Some debugging later, I ran the script, and was trying to make sense of the time. I had used a “usleep 5000” , i.e a refresh rate of 5000 micro-seconds as the optimal refresh rate. I didn’t figure out how to disable the LED indicators of their normal use, and so decided to over-ride it with a higher refresh rate. Unfortunately the script was soo slow and inefficient that even without a usleep to slow it, it ran at too slow a rate, that I couldn’t make sense of the time.
After some brainstorming, I decided that I could just make do with a single LED , displaying the time in a morse code like encoding! I figured it would be a reasonable compromise, and would be a much more efficient solution in terms of reducing the CPU load! So I finally managed to write the shell script and lo and behold , I now have my router reading out the time for me 😀:D
#!/bin/ash
# Script by Phinfinity
# This script displays the time through two segments of 4 short/long blinks to
# convey the current hour and minutes.
pin=1 # Using the QSS LED for displaying time
flash() { # Rapidly flash 10 times , to act as separator between hours/minutes readings
#echo "."
i=10
while [[ $i != 0 ]]
do
gpio enable $pin
usleep 1000
gpio disable $pin
usleep 1000
i=$((i-1))
done
}
pause() { # Puase between blinks
gpio disable $pin
usleep 500000
}
short() { # Short blink - used as a binary "1"
#echo 1
gpio enable $pin
usleep 250000
gpio disable $pin
}
long() { # Long blink - used as a binary "0"
#echo 0
gpio enable $pin
usleep 700000
gpio disable $pin
}
while true
do
min=$(( ($(date +1%M) - 100)/5)) #4bits
# The "+1%M" & "-100" : hack for removing the zero pad to prevent octal interpretation
# busybox date doesn't support format flags like _,- etc. to disable padding
hr=$(date +%l) #4bits
# minute is in the range {0..11}*5 and hr is in the range {0..11}
#Flash longer before begining time
flash
flash
flash
pause
pause
# Blink the Hour
[[ $(( hr&8 )) != 0 ]] && short || long
pause
[[ $(( hr&4 )) != 0 ]] && short || long
pause
[[ $(( hr&2 )) != 0 ]] && short || long
pause
[[ $(( hr&1 )) != 0 ]] && short || long
pause
pause
flash
pause
pause
# Blink the Minute
[[ $(( min&8 )) != 0 ]] && short || long
pause
[[ $(( min&4 )) != 0 ]] && short || long
pause
[[ $(( min&2 )) != 0 ]] && short || long
pause
[[ $(( min&1 )) != 0 ]] && short || long
pause
pause
done
A single LED is used. First the LED flashes rapidly to indicate start. 4 blinks with read out the hour and rapid flashing indicates starting the minute. 4 more blinks read out the minute.You could set this up inside the startup script to autostart every time. Some other considerations are to make sure that you have an NTP server setup on your router to make sure that the correct time is used each time.
Now all that remains , is to see if this actually helps :P, after a few times, I can read the time in a single attempt, the real question is can I do it from my bed when I am half-asleep ;)
Let me know if you have a better idea to implement this, or any suggestions/comments below in the comments!
|
The first thing to do was to somehow figure out how to turn on/off some of the LEDs. After a bit of googling and research, I came to know that these LEDs are usually controlled through an interface called the GPIO. And it seems DD-WRT uses this very Hardware interface to provide control over LEDs as well as other I/O such as buttons on the router which could be used for input. For e.g on my TP-LINK WR-740N router , I have a QSS switch , which I never use (nor should you), which can be used as an input device accessible using GPIO.
So how do we actually use this GPIO to control our LEDs? Well there appear to be two simple methods. Before that you need to ensure that your router’s kernel has the GPIO module enabled. First lets ssh to the router so that we can start playing with the LED controls. You can check that the GPIO module has been added by heading over to /proc/gpio . There you will find several nodes corresponding to control points of several GPIO pins. GPIO has several “output” pins which we can use to control the LEDs. We can directly use these files to control the LEDs, however a simpler command line tool called “gpio” exists to simplify the process.
$ gpio
gpio <poll | enable | disable> <pin>
$ gpio enable 27
$g pio disable 27
Basically “gpio enable/disable pin” enables/disables the output pin specified. The next question would be to figure out which pin number corresponds to which LED on the router. This page provides several example scripts which control LEDs, along with several GPIO pin mappings to LEDs for several devices. Unfortunately my device wasn’t among them :( . So I had to resort to figuring out which pin mapped to which LED manually. Eventually though it ended up being fun :P , I managed to write short shell scripts , which would flash a set of pins on off repeatedly so that , I could test several subset of pins at once, and observe the corresponding effects on the LEDs in order to finally identify the mapping for my device. After some effort I obtained the mapping for my router:
26 : QSS Input Button
LED s From Left-to-Right
? : Power LED: I couldn't find this one, I suspect it is hardwired and can't be controlled
27 : Some led with a gear symbol. (No idea what its for)
0 : Wifi Indicator
14 : LAN1 Indicator
15 : LAN2 Indicator
16 : LAN3 Indicator
17 : LAN4 Indicator
13 : Internet Indicator
1 : Lock Symbol : Again not sure , Guesing WPS/QSS indicator
Some of these had inverted effects such as 27,17 which would turn off when enabled with gpio instead of turning on like other pins.
After obtaining the mappings, I set about writing a script in bash, keeping these mappings in an array for easy use. But alas , I realised a bit later that the router does not use bash, but uses busybox’s ash. And ash does not support arrays in scripts.
This put me in a bit of a dilemma and I was considering writing a C-program compiled for the MIPS architecture of my Atheros router. I was trying to avoid a an inefficently written shell script to avoid overloading my router’s CPU. But cross-compiling for MIPS to run on my router was no easy task. I took great efforts to compile gcc and binutils for mips but that didn’t work very well either. Firstly I failed to compile even the hello world program for mips using gcc. And worse a blank binary I generated by compiling “main()” in C , did not even run on my router.
Eventually I gave up on the cross-compilation and much later sat down to write it in pure shell. After a few minutes of quick hacking I had a simple short script , which although inefficient ought to get the job done. Some debugging later, I ran the script, and was trying to make sense of the time. I had used a “usleep 5000” , i.e a refresh rate of 5000 micro-seconds as the optimal refresh rate. I didn’t figure out how to disable the LED indicators of their normal use, and so decided to over-ride it with a higher refresh rate. Unfortunately the script was soo slow and inefficient that even without a usleep to slow it, it ran at too slow a rate, that I couldn’t make sense of the time.
After some brainstorming, I decided that I could just make do with a single LED , displaying the time in a morse code like encoding! I figured it would be a reasonable compromise, and would be a much more efficient solution in terms of reducing the CPU load! So I finally managed to write the shell script and lo and behold , I now have my router reading out the time for me 😀:D
#!/bin/ash
# Script by Phinfinity
# This script displays the time through two segments of 4 short/long blinks to
# convey the current hour and minutes.
pin=1 # Using the QSS LED for displaying time
flash() { # Rapidly flash 10 times , to act as separator between hours/minutes readings
#echo "."
i=10
while [[ $i != 0 ]]
do
gpio enable $pin
usleep 1000
gpio disable $pin
usleep 1000
i=$((i-1))
done
}
pause() { # Puase between blinks
gpio disable $pin
usleep 500000
}
short() { # Short blink - used as a binary "1"
#echo 1
gpio enable $pin
usleep 250000
gpio disable $pin
}
long() { # Long blink - used as a binary "0"
#echo 0
gpio enable $pin
usleep 700000
gpio disable $pin
}
while true
do
min=$(( ($(date +1%M) - 100)/5)) #4bits
# The "+1%M" & "-100" : hack for removing the zero pad to prevent octal interpretation
# busybox date doesn't support format flags like _,- etc. to disable padding
hr=$(date +%l) #4bits
# minute is in the range {0..11}*5 and hr is in the range {0..11}
#Flash longer before begining time
flash
flash
flash
pause
pause
# Blink the Hour
[[ $(( hr&8 )) != 0 ]] && short || long
pause
[[ $(( hr&4 )) != 0 ]] && short || long
pause
[[ $(( hr&2 )) != 0 ]] && short || long
pause
[[ $(( hr&1 )) != 0 ]] && short || long
pause
pause
flash
pause
pause
# Blink the Minute
[[ $(( min&8 )) != 0 ]] && short || long
pause
[[ $(( min&4 )) != 0 ]] && short || long
pause
[[ $(( min&2 )) != 0 ]] && short || long
pause
[[ $(( min&1 )) != 0 ]] && short || long
pause
pause
done
A single LED is used. First the LED flashes rapidly to indicate start. 4 blinks with read out the hour and rapid flashing indicates starting the minute. 4 more blinks read out the minute.You could set this up inside the startup script to autostart every time. Some other considerations are to make sure that you have an NTP server setup on your router to make sure that the correct time is used each time.
Now all that remains , is to see if this actually helps :P, after a few times, I can read the time in a single attempt, the real question is can I do it from my bed when I am half-asleep ;)
Let me know if you have a better idea to implement this, or any suggestions/comments below in the comments!
Has anyone sampled the various product mentioned here, and can they tell which one is the best???
ReplyDelete