In Part-3 of this project series where we controlled the onboard LEDs on the router through the command line and a couple of C programs. If you haven't read the previous projects, I would highly recommend you check out those before starting out with this project. The links to the previous projects are listed below.
Exploring the humble Internet Router - Part 1
Exploring the humble Internet Router - Part 2
Exploring the humble Internet Router - Part 3
Before we begin, let's look back to the problem we had while working with the GPIOS using the sysfs filesystem on Linux. Every time we wanted to work with the LEDs, we had to manually export the pin number as follows.
root@OpenWrt:# echo 6 >/sys/class/gpio/export
root@OpenWrt:# ls
export gpio6 gpiochip0 unexport
Once we were done using the LEDs, we had to unexport the GPIO file so that it can be used again later as follows.
root@OpenWrt:# echo 6 >/sys/class/gpio/unexport
root@OpenWrt:# ls
export gpiochip0 unexport
This was kind of painful to do every time we wanted to blink an LED. Therefore we fixed that issue by automating this process in the C program. However, we can fix this problem in another way where the exporting is done at boot time. This way, the pins we need will be ready as soon as the system is booted up. This will be required for the webserver LED control that we will cover here.
We achieve this through the init.d Linux service management. The init.d system provides a way where we can start our custom programs or scripts at boot time through the etc/init.d folder. As we can see below, the /etc/init.d folder has a few files. The init service will start all these services at boot time one after the other based on the order provided in the /etc/rc.d folder. We will get into the details of this soon.
root@OpenWrt:~# ls /etc/init.d/
boot done gpio_switch network rpcd sysfixtime ucitrack urandom_seed wpad cron export_gpio led nvram sshd sysntpd uhttpd urngd dnsmasq firewall log odhcpd sysctl system umount wmacfixup
As an example, let us consider network, sshd, and the uhhtpd files in the /etc/init.d folder. These services will be started at boot time by the init system. The following snippet shows the kernel log at the time of boot up. You can see from the first line that the init process is started. In fact, the init process is the first process to run in userspace. This process then starts the remaining processes. as you can see in the next few lines, the watchdog timer is started after which the urandom process is run, and then the network process is started.
[ 1.362297] Run /sbin/init as init process
[ 2.442560] init: Console is alive
[ 2.446760] init: - watchdog -
[ 2.819911] kmodloader: loading kernel modules from /etc/modules-boot.d/*
[ 3.022939] kmodloader: done loading kernel modules from /etc/modules-boot.d/*
[ 3.041371] init: - preinit -
[ 6.641786] random: jshn: uninitialized urandom read (4 bytes read)
[ 6.923204] random: jshn: uninitialized urandom read (4 bytes read)
[ 7.102083] random: jshn: uninitialized urandom read (4 bytes read)
[ 7.422163] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[ 7.437920] IPv6: ADDRCONF(NETDEV_CHANGE): eth0.1: link becomes ready
So how exactly is this start order determined? The /etc/rc.d folder takes care of this order. The image below shows the same.
The files that start with S** indicate the start order and the ones with K** indicate the kill order. The two numbers following the S or K indicate the run levels. A process having a smaller number starts first. For example, a process starting with S00 runs before S10. Now back to our boot order. You can see that the S00sysfixtime has the lowest number - "00". This is our watchdog process that started first. S00urngd is the urandom process that started after.
Now, we need to add another service here that would export our GPIO pin at boot time. So let's get started on doing that. The first thing we need to do is add a script whose job is to export the GPIO pin, to the init.d folder. As you can see below, I have added the export_gpio file (the code for this script is in the Github repo named export_gpio.sh). The contents of that file are shown here.
As you can see, all it does is export our LED pin (GPIO pin 6) and then set the direction value to out, indicating it as an output pin. The next step is to create the file in the /etc/rc.d folder with a start sequence number. I have created the S93export_gpio file as shown below. We can choose any available number. I chose 93 as it was available and not taken by any other file.
Just creating this file, doesn't exactly do anything. We have to create a symbolic link to the actual script file that we created in the /etc/init.d folder. We do that as follows.
root@OpenWrt:/etc/rc.d# ln -s S93export_gpio ../init.d/export_gpio
The "ln" command creates a link specified by the following two arguments. In this case, it has created a link between S93export_gpio and export_gpio in the init.d folder. The -s flag indicates a symbolic link creation. We can see whether this was done by listing the files and as we can see, it was successful.
Now, the GPIO pin export should automatically take place at boot time. We will now move on to creating a webpage for controlling our LED.
We would first need a web server in order to do that. The router already has a web server running. We can check this by running the ps command. The uhttpd process is our web server. In the following arguments, you can see that the /www is the one that hosts all the web pages.
Now, let us check out the /www folder. The index.html page is our router configuration page that loads up when we go to 192.168.1.1. The cgi-bin folder (common gateway interface) contains all the scripts that interact with the web browser. We will be using that for our LED control scripts.
root@OpenWrt:/www# ls
button.html cgi-bin index.html luci-static mypage.html test.html
Once we visit the 192.168.1.1/index.html page on our browser, we get redirected to the OpenWRT login page. This is a result of a script being run. The address indicates this (192.168.1.1/cgi-bin/luci). The luci script has run when the index.html page was loaded.
Let us now create a page that can control our LEDs. We go to the /www folder and create a file named button.html (all code is in the Github repo). This file would contain simple HTML to create buttons. Upon, clicking the buttons, the page would run scripts that turn the LED on and off.
You can see from the snippet below that the page runs on.sh and off.sh scripts that turn on and turn off the LED respectively.
root@OpenWrt:/www# cat button.html
<!DOCTYPE html>
<html>
<body>
<h1>LED CONTROL</h1>
<form action="cgi-bin/on.sh" method="post">
<input type="submit" value="LED ON">
</form>
<form action="cgi-bin/off.sh" method="post">
<input type="submit" value="LED OFF">
</form>
</body>
</html>
Now, we need to create those scripts in the cgi-bin folder (remember this is where the scripts need to be located as it has executable permissions). The script shown below turns the LED on and indicates the status on the webpage. The off.sh script is similar except, it turns the LED off.
root@OpenWrt:/www/cgi-bin# ls
cgi-backup cgi-download cgi-exec cgi-upload luci off.sh on.sh test_script.sh
root@OpenWrt:/www/cgi-bin# cat on.sh
#!/bin/ash
echo "Switching LED on ..." > /dev/console
echo 0 > /sys/class/gpio/gpio6/value
echo "Content-type: text/html"
echo ""
echo "<html><head><title>LED STATUS</title></head><body>"
echo "<h1>LED ON</h1>"
echo "</body></html>"
Let us now try it. The LED turns on after clicking the LED ON button and the status is shown. At this point, the webpage has to be reloaded manually by pressing the back button in the browser. This will be improved later on.
That would be all for this project! In the next project, we will be building our custom OpenWRT operating system and will also configure our Linux kernel. Stay tuned!
Comments
Please log in or sign up to comment.