Bar
SpaceWire UK
Specialist providers of VHDL Intellectual Property & Design Services
BarBarBarBar
Tutorial
Missing Image!
Part 14 - Enable Petalinux webserver & create basic website to serve

Introduction

This tutorial details the steps required to enable the PetaLinux webserver and create an application to install the files required to form a static & dynamic website.

Aims

The aims of this tutorial are as follows :-
  1. Setup environment
  2. Change present working directory
  3. Enable webserver
  4. Create installer application
  5. Create static website
  6. Modify BitBake recipe
  7. Build, package & deploy project on Zedboard
  8. Check static website is working
  9. Create dynamic (server side) website
  10. Modify BitBake recipe
  11. Build, package & deploy project on Zedboard
  12. Check dynamic website is working
  13. Create dynamic (client side) website
  14. Modify BitBake recipe
  15. Build, package & deploy project on Zedboard
  16. Check dynamic (client side) website is working

1. Setup environment

Setup Xilinx design environment for the 2021.2 toolset.
steve@Linux-Steve:/home/steve$ source xilinx.sh
Xilinx tools available tools at /opt/Xilinx :-
1) 2021.2 - Vivado - SDK - Vitis - PetaLinux
0) Exit
Please select tools required or exit : 1

Tools are as follows :-
vivado @ /opt/Xilinx/Vivado/2021.2/bin/vivado
vitis @ /opt/Xilinx/Vitis/2021.2/bin/vitis
petalinux-build @ /opt/Xilinx/PetaLinux/2021.2/tool/tools/common/petalinux/bin/petalinux-build

2. Change present working directory

Change the present working directory to be the project directory.
steve@Linux-Steve:/home/steve$ cd /home/steve/projects/petalinux

3. Enable webserver

Launch the PetaLinux configuration tool.
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-config -c rootfs
Navigate the menu selecting Filesystem Packages » base » busybox, enable busybox-httpd and then save the configuration and exit the tool. Missing Image!

4. Create installer application

Create a new auto-enabled installer application.
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-create --type apps --template install --name website --enable
Examine the file structure of the newly created installer application.
steve@Linux-Steve:/home/steve/projects/petalinux$ tree project-spec/meta-user/recipes-apps/website
project-spec/meta-user/recipes-apps/website
├── files
│   └── website
├── README
└── website.bb

1 directory, 3 files

website

  1. #!/bin/sh

  2. echo "Hello PetaLinux World"


website.bb

  1. #
  2. # This file is the website recipe.
  3. #

  4. SUMMARY = "Simple website application"
  5. SECTION = "PETALINUX/apps"
  6. LICENSE = "MIT"
  7. LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

  8. SRC_URI = "file://website \
  9. "

  10. S = "${WORKDIR}"

  11. do_install() {
  12.      install -d ${D}/${bindir}
  13.      install -m 0755 ${S}/website ${D}/${bindir}
  14. }

5. Create static website

The website will consist of an index page that displays an image of the Zedboard hardware.

Download the ZedBoard image file from Digilent into /home/steve/Downloads. Rename & move this file into the website application area.
steve@Linux-Steve:/home/steve/projects/petalinux$ mv /home/steve/Downloads/zedboard-2.png project-spec/meta-user/recipes-apps/website/files/zedboard.png
Create a simple HTML index page and save this in the website application area.
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/website/files/index.html

index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  5. <title>Zedboard webserver</title>
  6. </head>
  7. <body>
  8. Hello from your Zedboard webserver...
  9. <br>
  10. <img src="zedboard.png" alt="Missing Image!">
  11. </body>
  12. </html>

6. Modify BitBake recipe

Edit the BitBake recipe to remove the webserver entries that would allow installation of this application into /usr/bin. Add the entries for index.html & zedboard.jpg to allow installation of these into /srv/www.
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/website/website.bb

website.bb

  1. #
  2. # This file is the website recipe.
  3. #

  4. SUMMARY = "Simple website application"
  5. SECTION = "PETALINUX/apps"
  6. LICENSE = "MIT"
  7. LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

  8. SRC_URI = "file://index.html"
  9. SRC_URI += "file://zedboard.png"

  10. FILES_${PN} += "/srv/www"

  11. S = "${WORKDIR}"

  12. do_install() {
  13.      install -d ${D}/srv/www
  14.      install -m 0644 ${S}/index.html ${D}/srv/www
  15.      install -d ${D}/srv/www
  16.      install -m 0644 ${S}/zedboard.png ${D}/srv/www
  17. }

Remove the now unused webserver application.
steve@Linux-Steve:/home/steve/projects/petalinux$ rm project-spec/meta-user/recipes-apps/website/files/website

7. Build, package & deploy project on Zedboard

Rebuild the project to include the enabled webserver and new installer application, package up the project ready for deployment, power cycle the Zedboard and deploy the project via JTAG.
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-build
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-package --prebuilt --force
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-boot --jtag --prebuilt 3

8. Check static website is working

Access the webserver running on the Zedboard using a browser pointing at the Zedboard's IP address. All being well the following static webpage should be displayed. Missing Image!

9. Create dynamic (server side) website

The dynamic (server side) website will contain the same elements as the static website plus some extra system information that will be provided live when the page loads or is reloaded.

Create a shell script like the one shown below that outputs what the previous index.html provided directly along with the additional information. This shell script will be called index.cgi and ultimately reside in /srv/www/cgi-bin.
steve@Linux-Steve:/home/steve/projects/petalinux$ mkdir project-spec/meta-user/recipes-apps/website/files/cgi-bin
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.cgi

index.cgi

  1. #!/bin/sh

  2. # Output Header
  3. printf "Content-type: text/html\r\n\r\n"

  4. # Get information
  5. sys_host=$(hostname)
  6. sys_time=$(date)
  7. sys_load=$(awk '{print $1}' /proc/loadavg)
  8. sys_up=$(awk '{print $1}' /proc/uptime)
  9. cpu_model=$(grep model /proc/cpuinfo | cut -d : -f2 | tail -1 | sed 's/\s//')
  10. cpu_cores=$(grep -c ^processor /proc/cpuinfo)
  11. mem_total=$(free -m | awk 'NR==2{print $2}')
  12. mem_used=$(free -m | awk 'NR==2{print $3}')
  13. mem_free=$(free -m | awk 'NR==2{print $4}')
  14. net_mac=$(cat /sys/class/net/eth0/address)
  15. net_ip_loc=$(ip a | grep inet | grep -vw lo | grep -v inet6 | cut -d \/ -f1 | sed 's/[^0-9\.]*//g')
  16. net_ip_ext=$(wget -q -O- http://ipecho.net/plain)

  17. # Output HTML
  18. printf '<!DOCTYPE html>'
  19. printf '<html lang="en">'
  20. printf '<head>'
  21. printf '<meta http-equiv="content-type" content="text/html; charset=UTF-8">'
  22. printf '<title>Zedboard webserver</title>'
  23. printf '</head>'
  24. printf '<body>'
  25. printf 'Hello from your Zedboard webserver...'
  26. printf '<br>'
  27. printf '<img src="../zedboard.png" alt="Missing Image!">'

  28. printf '<br>System<br>'
  29. printf 'Honstname: %s<br>' "${sys_host}"
  30. printf 'Time: %s<br>' "${sys_time}"
  31. printf 'Uptime: %.2f seconds<br>' ${sys_up}

  32. printf '<br>CPU<br>'
  33. printf 'Model: %s<br>' "${cpu_model}"
  34. printf 'Cores: %d<br>' ${cpu_cores}
  35. printf 'Load: %.2f<br>' ${sys_load}

  36. printf '<br>Memory<br>'
  37. printf 'Total: %d Mb<br>' ${mem_total}
  38. printf 'Used: %d Mb<br>' ${mem_used}
  39. printf 'Free: %d Mb<br>' ${mem_free}

  40. printf '<br>Network<br>'
  41. printf 'MAC Address: %s<br>' "${net_mac}"
  42. printf 'Local IP: %s<br>' "${net_ip_loc}"
  43. printf 'External IP: %s<br>' "${net_ip_ext}"

  44. printf '</body>'
  45. printf '</html>'

10. Modify BitBake recipe

Modify the BitBake recipe to reflect the addition of the cgi-bin directory and index.cgi script, ensure the script entry sets the execution bit of the file. The webserver looks for the index file in /srv/www before looking in /srv/www/cgi-bin so the original index.html is temporarily renamed to take this out of the equation.
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/website/website.bb

website.bb

  1. #
  2. # This file is the website recipe.
  3. #

  4. SUMMARY = "Simple website application"
  5. SECTION = "PETALINUX/apps"
  6. LICENSE = "MIT"
  7. LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

  8. SRC_URI = "file://index.html"
  9. SRC_URI += "file://zedboard.png"
  10. SRC_URI += "file://cgi-bin/index.cgi"

  11. FILES_${PN} += "/srv/www"

  12. S = "${WORKDIR}"

  13. do_install() {
  14.      install -d ${D}/srv/www
  15.      install -m 0644 ${S}/index.html ${D}/srv/www/index_original.html
  16.      install -d ${D}/srv/www
  17.      install -m 0644 ${S}/zedboard.png ${D}/srv/www
  18.      install -d ${D}/srv/www/cgi-bin
  19.      install -m 0755 ${S}/cgi-bin/index.cgi ${D}/srv/www/cgi-bin
  20. }

11. Build, package & deploy project on Zedboard

Rebuild the project to include the updated webserver, package up the project ready for deployment, power cycle the Zedboard and deploy the project via JTAG.
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-build
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-package --prebuilt --force
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-boot --jtag --prebuilt 3

12. Check dynamic website is working

Access the webserver running on the Zedboard using a browser pointing at the Zedboard's IP address. All being well something akin to the following webpage should be displayed. Missing Image! Reload the page to refresh all the information displayed, most of which is static except for elements such as time, uptime, load & memory. The index.cgi page can be accessed directly via [Zedboard IP]/cgi-bin/index.cgi and the original index.html via [Zedboard IP]/index_original.html.

13. Create dynamic (client side) website

The dynamic (client side) website will contain the same elements as the previous dynamic (server side) website along with the ability to refresh the uptime element without reloading the whole page.

Create a shell script that returns the uptime in seconds.
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/website/files/cgi-bin/uptime.cgi

uptime.cgi

  1. #!/bin/sh

  2. # Output Header
  3. printf "Content-type: text/html\r\n\r\n"

  4. # Output Command
  5. awk '{print $1}' /proc/uptime

Create a Javascript file that contains the functions required to send & receive data to & from the webserver. Also add a function to enable & disable a timer.
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/website/files/uptime.js

uptime.js

  1. // Requests
  2. var uptime_req;
  3. var timer_req;

  4. // Receive data & update webpage accordingly
  5. function GotUptime() {
  6.   if (uptime_req.readyState == 4 && uptime_req.status == 200) {
  7.     txtObj = document.getElementById("uptime_text");
  8.     if (txtObj !== null) {
  9.       txtObj.innerHTML = uptime_req.responseText;
  10.     }
  11.   }
  12. }

  13. // Setup request and ask for data return
  14. function GetUpTime() {
  15.   if (window.XMLHttpRequest) {
  16.     uptime_req = new XMLHttpRequest();
  17.     uptime_req.abort();
  18.     uptime_req.onreadystatechange = GotUptime;
  19.     uptime_req.open("POST", "/cgi-bin/uptime.cgi", true);
  20.     uptime_req.send(null);
  21.   }
  22. }

  23. // Setup/Cancel timer request
  24. function SetTimeout(obj) {
  25.   clearInterval(timer_req);
  26.   var interval = obj.value;
  27.   if (interval > 0) {
  28.     timer_req = setInterval("GetUpTime()", 1000 * interval);
  29.   }
  30. }

Modify the index.cgi webpage as follows :-
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.cgi

index.cgi

  1. #!/bin/sh

  2. # Output Header
  3. printf "Content-type: text/html\r\n\r\n"

  4. # Get information
  5. sys_host=$(hostname)
  6. sys_time=$(date)
  7. sys_load=$(awk '{print $1}' /proc/loadavg)
  8. sys_up=$(awk '{print $1}' /proc/uptime)
  9. cpu_model=$(grep model /proc/cpuinfo | cut -d : -f2 | tail -1 | sed 's/\s//')
  10. cpu_cores=$(grep -c ^processor /proc/cpuinfo)
  11. mem_total=$(free -m | awk 'NR==2{print $2}')
  12. mem_used=$(free -m | awk 'NR==2{print $3}')
  13. mem_free=$(free -m | awk 'NR==2{print $4}')
  14. net_mac=$(cat /sys/class/net/eth0/address)
  15. net_ip_loc=$(ip a | grep inet | grep -vw lo | grep -v inet6 | cut -d \/ -f1 | sed 's/[^0-9\.]*//g')
  16. net_ip_ext=$(wget -q -O- http://ipecho.net/plain)

  17. # Output HTML
  18. printf '<!DOCTYPE html>'
  19. printf '<html lang="en">'
  20. printf '<head>'
  21. printf '<meta http-equiv="content-type" content="text/html; charset=UTF-8">'
  22. printf '<script src="../uptime.js"></script>';
  23. printf '<title>Zedboard webserver</title>'
  24. printf '</head>'
  25. printf '<body>'
  26. printf 'Hello from your Zedboard webserver...'
  27. printf '<br>'
  28. printf '<img src="../zedboard.png" alt="Missing Image!">'

  29. printf '<br>System<br>'
  30. printf 'Honstname: %s<br>' "${sys_host}"
  31. printf 'Time: %s<br>' "${sys_time}"
  32. printf 'Uptime: <span id="uptime_text">%.2f</span> seconds ' ${sys_up}
  33. printf '​<button onclick="GetUpTime()">Refresh</button>'
  34. printf '​ Auto : <select onchange="SetTimeout(this)">'
  35. printf '​<option value="0">Off</option>'
  36. printf '​<option value="1">1s</option>'
  37. printf '​<option value="5">5s</option>'
  38. printf '​</select><br>'

  39. printf '<br>CPU<br>'
  40. printf 'Model: %s<br>' "${cpu_model}"
  41. printf 'Cores: %d<br>' ${cpu_cores}
  42. printf 'Load: %.2f<br>' ${sys_load}

  43. printf '<br>Memory<br>'
  44. printf 'Total: %d Mb<br>' ${mem_total}
  45. printf 'Used: %d Mb<br>' ${mem_used}
  46. printf 'Free: %d Mb<br>' ${mem_free}

  47. printf '<br>Network<br>'
  48. printf 'MAC Address: %s<br>' "${net_mac}"
  49. printf 'Local IP: %s<br>' "${net_ip_loc}"
  50. printf 'External IP: %s<br>' "${net_ip_ext}"

  51. printf '</body>'
  52. printf '</html>'

14. Modify BitBake recipe

Modify the BitBake recipe to reflect the addition of the uptime.js include and uptime.cgi script, ensure the script entry sets the execution bit of the file.
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/website/website.bb

website.bb

  1. #
  2. # This file is the website recipe.
  3. #

  4. SUMMARY = "Simple website application"
  5. SECTION = "PETALINUX/apps"
  6. LICENSE = "MIT"
  7. LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

  8. SRC_URI = "file://index.html"
  9. SRC_URI += "file://uptime.js"
  10. SRC_URI += "file://zedboard.png"
  11. SRC_URI += "file://cgi-bin/index.cgi"
  12. SRC_URI += "file://cgi-bin/uptime.cgi"

  13. FILES_${PN} += "/srv/www"

  14. S = "${WORKDIR}"

  15. do_install() {
  16.      install -d ${D}/srv/www
  17.      install -m 0644 ${S}/index.html ${D}/srv/www/index_original.html
  18.      install -d ${D}/srv/www
  19.      install -m 0644 ${S}/uptime.js ${D}/srv/www
  20.      install -d ${D}/srv/www
  21.      install -m 0644 ${S}/zedboard.png ${D}/srv/www
  22.      install -d ${D}/srv/www/cgi-bin
  23.      install -m 0755 ${S}/cgi-bin/index.cgi ${D}/srv/www/cgi-bin
  24.      install -d ${D}/srv/www/cgi-bin
  25.      install -m 0755 ${S}/cgi-bin/uptime.cgi ${D}/srv/www/cgi-bin
  26. }

15. Build, package & deploy project on Zedboard

Rebuild the project to include the updated files, package it up ready for deployment, power cycle the Zedboard and deploy via JTAG.
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-build
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-package --prebuilt --force
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-boot --jtag --prebuilt 3

16. Check dynamic (client side) website is working

Access the webserver running on the Zedboard using a browser pointing at the Zedboard's IP address. All being well something akin to the following webpage should be displayed. Missing Image! Reload the page to refresh all the information displayed or click on the Refresh button to refresh only the uptime. Use the Auto dropdown to select the interval of an automatic uptime refresh.